cosplay: Touhou/Houjuu Nue #4
16
nhf/build.py
16
nhf/build.py
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
@ -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,
|
|
@ -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()
|
|
@ -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)
|
|
||||||
)
|
|
61
nhf/test.py
61
nhf/test.py
|
@ -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__':
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue