cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
12 changed files with 97 additions and 77 deletions
Showing only changes of commit 5bceb6180e - Show all commits

View File

@ -29,9 +29,11 @@ class Target:
""" """
def g(): def g():
for name in dir(subject): for name in dir(subject):
if name == 'target_names':
continue
method = getattr(subject, name) method = getattr(subject, name)
if hasattr(method, 'target'): if hasattr(method, '_target'):
yield method.target yield method._target
return {method.name: method for method in g()} return {method.name: method for method in g()}
@ -43,7 +45,7 @@ def target(name, **deco_kwargs):
@wraps(method) @wraps(method)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
return method(self, *args, **kwargs) return method(self, *args, **kwargs)
wrapper.target = Target(method, name, **deco_kwargs) wrapper._target = Target(method, name, **deco_kwargs)
return wrapper return wrapper
return f return f
@ -60,12 +62,20 @@ class Model:
Base class for a parametric assembly Base class for a parametric assembly
""" """
@property
def target_names(self) -> list[str]: def target_names(self) -> list[str]:
""" """
List of decorated target functions List of decorated target functions
""" """
return list(Target.methods(self).keys()) return list(Target.methods(self).keys())
def check_all(self) -> int:
total = 0
for k, f in Target.methods(self).items():
f(self)
total += 1
return total
def build_all(self, output_dir: Union[Path, str] ="build", verbose=1): def build_all(self, output_dir: Union[Path, str] ="build", verbose=1):
""" """
Build all targets in this model Build all targets in this model

0
nhf/parts/__init__.py Normal file
View File

View File

@ -3,7 +3,7 @@ This schematics file contains all designs related to tool handles
""" """
from dataclasses import dataclass from dataclasses import dataclass
import cadquery as Cq import cadquery as Cq
import nhf.metric_threads as NMt import nhf.parts.metric_threads as metric_threads
@dataclass @dataclass
class Handle: class Handle:
@ -50,7 +50,7 @@ class Handle:
@property @property
def diam_insertion_internal(self): def diam_insertion_internal(self):
r = NMt.metric_thread_major_radius( r = metric_threads.metric_thread_major_radius(
self.diam_threading, self.diam_threading,
self.thread_pitch, self.thread_pitch,
internal=True) internal=True)
@ -58,7 +58,7 @@ class Handle:
@property @property
def diam_connector_external(self): def diam_connector_external(self):
r = NMt.metric_thread_minor_radius( r = metric_threads.metric_thread_minor_radius(
self.diam_threading, self.diam_threading,
self.thread_pitch) self.thread_pitch)
return r * 2 return r * 2
@ -77,13 +77,13 @@ class Handle:
def _external_thread(self, length=None): def _external_thread(self, length=None):
if length is None: if length is None:
length = self.insertion_length length = self.insertion_length
return NMt.external_metric_thread( return metric_threads.external_metric_thread(
self.diam_threading, self.diam_threading,
self.thread_pitch, self.thread_pitch,
length, length,
top_lead_in=True) top_lead_in=True)
def _internal_thread(self): def _internal_thread(self):
return NMt.internal_metric_thread( return metric_threads.internal_metric_thread(
self.diam_threading, self.diam_threading,
self.thread_pitch, self.thread_pitch,
self.insertion_length) self.insertion_length)

View File

@ -1,7 +1,7 @@
from dataclasses import dataclass from dataclasses import dataclass
import math import math
import cadquery as Cq import cadquery as Cq
import nhf.springs as NS import nhf.parts.springs as springs
from nhf import Role from nhf import Role
@dataclass @dataclass
@ -209,7 +209,7 @@ def comma_joint(radius=30,
def comma_assembly(): def comma_assembly():
joint1 = comma_joint() joint1 = comma_joint()
joint2 = comma_joint() joint2 = comma_joint()
spring = NS.torsion_spring() spring = springs.torsion_spring()
result = ( result = (
Cq.Assembly() Cq.Assembly()
.add(joint1, name="joint1", color=Cq.Color(0.8,0.8,0.5,0.3)) .add(joint1, name="joint1", color=Cq.Color(0.8,0.8,0.5,0.3))
@ -298,7 +298,7 @@ class TorsionJoint:
def spring(self): def spring(self):
return NS.torsion_spring( return springs.torsion_spring(
radius=self.radius_spring, radius=self.radius_spring,
height=self.spring_height, height=self.spring_height,
thickness=self.spring_thickness, thickness=self.spring_thickness,

59
nhf/parts/test.py Normal file
View File

@ -0,0 +1,59 @@
import unittest
import cadquery as Cq
from nhf.checks import binary_intersection
import nhf.parts.joints as joints
import nhf.parts.handle as handle
import nhf.parts.metric_threads as metric_threads
class TestJoints(unittest.TestCase):
def test_joint_hirth(self):
j = joints.HirthJoint()
obj = j.generate()
self.assertIsInstance(
obj.val().solids(), Cq.Solid,
msg="Hirth joint must be in one piece")
def test_joints_hirth_assembly(self):
for n_tooth in [16, 20, 24]:
with self.subTest(n_tooth=n_tooth):
j = joints.HirthJoint()
assembly = j.assembly()
isect = binary_intersection(assembly)
self.assertLess(isect.Volume(), 1e-6,
"Hirth joint assembly must not have intersection")
def test_joints_comma_assembly(self):
joints.comma_assembly()
def test_torsion_joint(self):
j = joints.TorsionJoint()
assembly = j.rider_track_assembly()
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.zlen, j.total_height)
class TestHandle(unittest.TestCase):
def test_handle_assembly(self):
h = handle.Handle()
assembly = h.connector_insertion_assembly()
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.xlen, h.diam)
self.assertAlmostEqual(bbox.ylen, h.diam)
assembly = h.connector_one_side_insertion_assembly()
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.xlen, h.diam)
self.assertAlmostEqual(bbox.ylen, h.diam)
class TestMetricThreads(unittest.TestCase):
def test_major_radius(self):
major = 3.0
t = metric_threads.external_metric_thread(major, 0.5, 4.0, z_start= -0.85, top_lead_in=True)
bbox = t.val().BoundingBox()
self.assertAlmostEqual(bbox.xlen, major, places=3)
self.assertAlmostEqual(bbox.ylen, major, places=3)
if __name__ == '__main__':
unittest.main()

View File

@ -1,12 +0,0 @@
import cadquery as Cq
def mystery():
return (
Cq.Workplane("XY")
.box(10, 5, 5)
.faces(">Z")
.workplane()
.hole(1)
.edges("|Z")
.fillet(2)
)

View File

@ -1,58 +1,23 @@
import unittest import unittest
import cadquery as Cq import cadquery as Cq
import nhf.joints from nhf.build import Model, target
import nhf.handle
import nhf.metric_threads as NMt
from nhf.checks import binary_intersection
class TestJoints(unittest.TestCase): class BuildScaffold(Model):
def test_joint_hirth(self): @target(name="obj1")
j = nhf.joints.HirthJoint() def o1(self):
obj = j.generate() return Cq.Solid.makeBox(10, 10, 10)
self.assertIsInstance(
obj.val().solids(), Cq.Solid,
msg="Hirth joint must be in one piece")
def test_joints_hirth_assembly(self): def o2(self):
for n_tooth in [16, 20, 24]: return Cq.Solid.makeCylinder(10, 20)
with self.subTest(n_tooth=n_tooth):
j = nhf.joints.HirthJoint()
assembly = j.assembly()
isect = binary_intersection(assembly)
self.assertLess(isect.Volume(), 1e-6,
"Hirth joint assembly must not have intersection")
def test_joints_comma_assembly(self):
nhf.joints.comma_assembly()
def test_torsion_joint(self):
j = nhf.joints.TorsionJoint()
assembly = j.rider_track_assembly()
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.zlen, j.total_height)
class TestBuild(unittest.TestCase):
class TestHandle(unittest.TestCase): def test_build_scaffold(self):
s = BuildScaffold()
def test_handle_assembly(self): names = ["obj1"]
h = nhf.handle.Handle() self.assertEqual(s.target_names, names)
assembly = h.connector_insertion_assembly() self.assertEqual(s.check_all(), len(names))
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.xlen, h.diam)
self.assertAlmostEqual(bbox.ylen, h.diam)
assembly = h.connector_one_side_insertion_assembly()
bbox = assembly.toCompound().BoundingBox()
self.assertAlmostEqual(bbox.xlen, h.diam)
self.assertAlmostEqual(bbox.ylen, h.diam)
class TestMetricThreads(unittest.TestCase):
def test_major_radius(self):
major = 3.0
t = NMt.external_metric_thread(major, 0.5, 4.0, z_start= -0.85, top_lead_in=True)
bbox = t.val().BoundingBox()
self.assertAlmostEqual(bbox.xlen, major, places=3)
self.assertAlmostEqual(bbox.ylen, major, places=3)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -32,12 +32,10 @@ shoulder, elbow, wrist in analogy with human anatomy.
from dataclasses import dataclass, field from dataclasses import dataclass, field
import unittest import unittest
import cadquery as Cq import cadquery as Cq
import nhf.joints
import nhf.handle
from nhf import Material from nhf import Material
from nhf.joints import HirthJoint
from nhf.handle import Handle
from nhf.build import Model, target from nhf.build import Model, target
from nhf.parts.joints import HirthJoint
from nhf.parts.handle import Handle
import nhf.touhou.houjuu_nue.wing as MW import nhf.touhou.houjuu_nue.wing as MW
import nhf.touhou.houjuu_nue.trident as MT import nhf.touhou.houjuu_nue.trident as MT

View File

@ -1,7 +1,7 @@
import math import math
import cadquery as Cq import cadquery as Cq
from nhf import Material from nhf import Material
from nhf.handle import Handle from nhf.parts.handle import Handle
def trident_assembly( def trident_assembly(
handle: Handle, handle: Handle,

View File

@ -4,7 +4,7 @@ This file describes the shapes of the wing shells. The joints are defined in
""" """
import math import math
import cadquery as Cq import cadquery as Cq
from nhf.joints import HirthJoint from nhf.parts.joints import HirthJoint
def wing_root_profiles( def wing_root_profiles(
base_sweep=150, base_sweep=150,