cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
3 changed files with 56 additions and 7 deletions
Showing only changes of commit e23cb5cc47 - Show all commits

View File

@ -31,7 +31,7 @@ class Item:
def role(self) -> Optional[Role]: def role(self) -> Optional[Role]:
return None return None
def generate(self, **kwargs) -> Union[Cq.Assembly, Cq.Workplane]: def generate(self, **kwargs) -> Union[Cq.Solid, Cq.Assembly, Cq.Workplane]:
""" """
Creates an assembly for this item. Subclass should implement this Creates an assembly for this item. Subclass should implement this
""" """
@ -42,7 +42,7 @@ class Item:
Interface for creating assembly with the necessary metadata Interface for creating assembly with the necessary metadata
""" """
a = self.generate(**kwargs) a = self.generate(**kwargs)
if isinstance(a, Cq.Workplane): if isinstance(a, Cq.Workplane) or isinstance(a, Cq.Solid):
a = Cq.Assembly(a) a = Cq.Assembly(a)
if role := self.role: if role := self.role:
a.metadata[KEY_ROLE] = role a.metadata[KEY_ROLE] = role

View File

@ -1,9 +1,11 @@
""" """
Unit tests for tooling Unit tests for tooling
""" """
from dataclasses import dataclass
import unittest import unittest
import cadquery as Cq import cadquery as Cq
from nhf.build import Model, target from nhf.build import Model, target
from nhf.parts.item import Item
import nhf.checks import nhf.checks
import nhf.utils import nhf.utils
@ -17,6 +19,20 @@ def makeSphere(r: float) -> Cq.Solid:
""" """
return Cq.Solid.makeSphere(r, angleDegrees1=-90) return Cq.Solid.makeSphere(r, angleDegrees1=-90)
@dataclass(frozen=True)
class MassBall(Item):
"""
A ball with fixed mass
"""
radius: float = 0.2
@property
def name(self) -> str:
return f"MassBall {self.mass}"
def generate(self) -> Cq.Solid:
return makeSphere(self.radius)
class BuildScaffold(Model): class BuildScaffold(Model):
def __init__(self): def __init__(self):
@ -180,5 +196,16 @@ class TestUtils(unittest.TestCase):
self.assertAlmostEqual(ry, 1) self.assertAlmostEqual(ry, 1)
self.assertAlmostEqual(rz, 0) self.assertAlmostEqual(rz, 0)
def test_centre_of_mass(self):
assembly = (
Cq.Assembly()
.add(MassBall(mass=3).assembly(), name="s1", loc=Cq.Location((0, 0, 0)))
.add(MassBall(mass=7).assembly(), name="s2", loc=Cq.Location((0, 0, 10)))
)
com = assembly.centre_of_mass()
self.assertAlmostEqual(com.x, 0)
self.assertAlmostEqual(com.y, 0)
self.assertAlmostEqual(com.z, 7)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -3,6 +3,7 @@ Utility functions for cadquery objects
""" """
import functools import functools
import math import math
from typing import Optional
import cadquery as Cq import cadquery as Cq
from cadquery.occ_impl.solver import ConstraintSpec from cadquery.occ_impl.solver import ConstraintSpec
from nhf import Role from nhf import Role
@ -236,16 +237,37 @@ Cq.Assembly.get_abs_direction = get_abs_direction
# Tallying functions # Tallying functions
def assembly_this_mass(self: Cq.Assembly) -> Optional[float]:
"""
Gets the mass of an assembly, without considering its components.
"""
if item := self.metadata.get(KEY_ITEM):
return item.mass
elif material := self.metadata.get(KEY_MATERIAL):
vol = self.toCompound().Volume()
return (vol / 1000) * material.density
else:
return None
def total_mass(self: Cq.Assembly) -> float: def total_mass(self: Cq.Assembly) -> float:
""" """
Calculates the total mass in units of g Calculates the total mass in units of g
""" """
total = 0.0 total = 0.0
for _, a in self.traverse(): for _, a in self.traverse():
if item := a.metadata.get(KEY_ITEM): if m := assembly_this_mass(a):
total += item.mass total += m
elif material := a.metadata.get(KEY_MATERIAL):
vol = a.toCompound().Volume()
total += (vol / 1000) * material.density
return total return total
Cq.Assembly.total_mass = total_mass Cq.Assembly.total_mass = total_mass
def centre_of_mass(self: Cq.Assembly) -> Optional[float]:
moment = Cq.Vector()
total = 0.0
for n, a in self.traverse():
if m := assembly_this_mass(a):
moment += m * a.toCompound().Center()
total += m
if total == 0.0:
return None
return moment / total
Cq.Assembly.centre_of_mass = centre_of_mass