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