cosplay: Touhou/Houjuu Nue #1

Closed
aniva wants to merge 37 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():
for name in dir(subject):
if name == 'target_names':
continue
method = getattr(subject, name)
if hasattr(method, 'target'):
yield method.target
if hasattr(method, '_target'):
yield method._target
return {method.name: method for method in g()}
@ -43,7 +45,7 @@ def target(name, **deco_kwargs):
@wraps(method)
def wrapper(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 f
@ -60,12 +62,20 @@ class Model:
Base class for a parametric assembly
"""
@property
def target_names(self) -> list[str]:
"""
List of decorated target functions
"""
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):
"""
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
import cadquery as Cq
import nhf.metric_threads as NMt
import nhf.parts.metric_threads as metric_threads
@dataclass
class Handle:
@ -50,7 +50,7 @@ class Handle:
@property
def diam_insertion_internal(self):
r = NMt.metric_thread_major_radius(
r = metric_threads.metric_thread_major_radius(
self.diam_threading,
self.thread_pitch,
internal=True)
@ -58,7 +58,7 @@ class Handle:
@property
def diam_connector_external(self):
r = NMt.metric_thread_minor_radius(
r = metric_threads.metric_thread_minor_radius(
self.diam_threading,
self.thread_pitch)
return r * 2
@ -77,13 +77,13 @@ class Handle:
def _external_thread(self, length=None):
if length is None:
length = self.insertion_length
return NMt.external_metric_thread(
return metric_threads.external_metric_thread(
self.diam_threading,
self.thread_pitch,
length,
top_lead_in=True)
def _internal_thread(self):
return NMt.internal_metric_thread(
return metric_threads.internal_metric_thread(
self.diam_threading,
self.thread_pitch,
self.insertion_length)

View File

@ -1,7 +1,7 @@
from dataclasses import dataclass
import math
import cadquery as Cq
import nhf.springs as NS
import nhf.parts.springs as springs
from nhf import Role
@dataclass
@ -209,7 +209,7 @@ def comma_joint(radius=30,
def comma_assembly():
joint1 = comma_joint()
joint2 = comma_joint()
spring = NS.torsion_spring()
spring = springs.torsion_spring()
result = (
Cq.Assembly()
.add(joint1, name="joint1", color=Cq.Color(0.8,0.8,0.5,0.3))
@ -298,7 +298,7 @@ class TorsionJoint:
def spring(self):
return NS.torsion_spring(
return springs.torsion_spring(
radius=self.radius_spring,
height=self.spring_height,
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 cadquery as Cq
import nhf.joints
import nhf.handle
import nhf.metric_threads as NMt
from nhf.checks import binary_intersection
from nhf.build import Model, target
class TestJoints(unittest.TestCase):
class BuildScaffold(Model):
def test_joint_hirth(self):
j = nhf.joints.HirthJoint()
obj = j.generate()
self.assertIsInstance(
obj.val().solids(), Cq.Solid,
msg="Hirth joint must be in one piece")
@target(name="obj1")
def o1(self):
return Cq.Solid.makeBox(10, 10, 10)
def test_joints_hirth_assembly(self):
for n_tooth in [16, 20, 24]:
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)
def o2(self):
return Cq.Solid.makeCylinder(10, 20)
class TestBuild(unittest.TestCase):
class TestHandle(unittest.TestCase):
def test_handle_assembly(self):
h = nhf.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 = 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)
def test_build_scaffold(self):
s = BuildScaffold()
names = ["obj1"]
self.assertEqual(s.target_names, names)
self.assertEqual(s.check_all(), len(names))
if __name__ == '__main__':

View File

@ -32,12 +32,10 @@ shoulder, elbow, wrist in analogy with human anatomy.
from dataclasses import dataclass, field
import unittest
import cadquery as Cq
import nhf.joints
import nhf.handle
from nhf import Material
from nhf.joints import HirthJoint
from nhf.handle import Handle
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.trident as MT

View File

@ -1,7 +1,7 @@
import math
import cadquery as Cq
from nhf import Material
from nhf.handle import Handle
from nhf.parts.handle import Handle
def trident_assembly(
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 cadquery as Cq
from nhf.joints import HirthJoint
from nhf.parts.joints import HirthJoint
def wing_root_profiles(
base_sweep=150,