cosplay: Touhou/Houjuu Nue #4
|
@ -0,0 +1,156 @@
|
|||
"""
|
||||
This schematics file contains all designs related to tool handles
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
import cadquery as Cq
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Handle:
|
||||
"""
|
||||
Characteristic of a tool handle
|
||||
"""
|
||||
|
||||
# Outer radius for the handle
|
||||
radius: float = 38 / 2
|
||||
|
||||
# Inner radius
|
||||
radius_inner: float = 33 / 2
|
||||
|
||||
# Wall thickness for the connector
|
||||
insertion_thickness: float = 4
|
||||
|
||||
# The connector goes in the insertion
|
||||
connector_thickness: float = 4
|
||||
|
||||
# Length for the rim on the female connector
|
||||
rim_length: float = 5
|
||||
|
||||
insertion_length: float = 60
|
||||
|
||||
connector_length: float = 60
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.radius > self.radius_inner
|
||||
assert self.radius_inner > self.insertion_thickness + self.connector_thickness
|
||||
assert self.insertion_length > self.rim_length
|
||||
|
||||
@property
|
||||
def _r1(self):
|
||||
"""
|
||||
Radius of inside of insertion
|
||||
"""
|
||||
return self.radius_inner - self.insertion_thickness
|
||||
@property
|
||||
def _r2(self):
|
||||
"""
|
||||
Radius of inside of connector
|
||||
"""
|
||||
return self._r1 - self.connector_thickness
|
||||
|
||||
def segment(self, length: float):
|
||||
result = (
|
||||
Cq.Workplane()
|
||||
.cylinder(radius=self.radius, height=length)
|
||||
)
|
||||
result.faces("<Z").tag("mate1")
|
||||
result.faces(">Z").tag("mate2")
|
||||
return result
|
||||
|
||||
def insertion(self):
|
||||
"""
|
||||
This type of joint is used to connect two handlebar pieces. Each handlebar
|
||||
piece is a tube which cannot be machined, so the joint connects to the
|
||||
handle by glue.
|
||||
|
||||
Tags:
|
||||
* lip: Co-planar Mates to the rod
|
||||
* mate: Mates to the connector
|
||||
"""
|
||||
result = (
|
||||
Cq.Workplane('XY')
|
||||
.cylinder(
|
||||
radius=self.radius_inner,
|
||||
height=self.insertion_length - self.rim_length,
|
||||
centered=[True, True, False])
|
||||
)
|
||||
result.faces(">Z").tag("lip")
|
||||
result = (
|
||||
result.faces(">Z")
|
||||
.workplane()
|
||||
.circle(self.radius)
|
||||
.extrude(self.rim_length)
|
||||
.faces(">Z")
|
||||
.hole(2 * self._r1)
|
||||
)
|
||||
result.faces(">Z").tag("mate")
|
||||
return result
|
||||
|
||||
def connector(self, solid: bool = False):
|
||||
"""
|
||||
Tags:
|
||||
* mate{1,2}: Mates to the connector
|
||||
"""
|
||||
result = (
|
||||
Cq.Workplane('XY')
|
||||
.cylinder(
|
||||
radius=self.radius,
|
||||
height=self.connector_length,
|
||||
)
|
||||
)
|
||||
for (tag, selector) in [("mate1", "<Z"), ("mate2", ">Z")]:
|
||||
result.faces(selector).tag(tag)
|
||||
r1 = self.radius_inner
|
||||
result = (
|
||||
result
|
||||
.faces(selector)
|
||||
.workplane()
|
||||
.circle(self._r1)
|
||||
.extrude(self.insertion_length)
|
||||
)
|
||||
if not solid:
|
||||
result = result.faces(">Z").hole(2 * self._r2)
|
||||
return result
|
||||
|
||||
def one_side_connector(self):
|
||||
result = (
|
||||
Cq.Workplane('XY')
|
||||
.cylinder(
|
||||
radius=self.radius,
|
||||
height=self.rim_length,
|
||||
)
|
||||
)
|
||||
result.faces("<Z").tag("mate")
|
||||
result.faces(">Z").tag("base")
|
||||
result = (
|
||||
result
|
||||
.faces("<Z")
|
||||
.workplane()
|
||||
.circle(self._r1)
|
||||
.extrude(self.insertion_length)
|
||||
)
|
||||
return result
|
||||
|
||||
def connector_insertion_assembly(self):
|
||||
connector_color = Cq.Color(0.8,0.8,0.5,0.3)
|
||||
insertion_color = Cq.Color(0.7,0.7,0.7,0.3)
|
||||
result = (
|
||||
Cq.Assembly()
|
||||
.add(self.connector(), name="c", color=connector_color)
|
||||
.add(self.insertion(), name="i1", color=insertion_color)
|
||||
.add(self.insertion(), name="i2", color=insertion_color)
|
||||
.constrain("c?mate1", "i1?mate", "Plane")
|
||||
.constrain("c?mate2", "i2?mate", "Plane")
|
||||
.solve()
|
||||
)
|
||||
return result
|
||||
def connector_one_side_insertion_assembly(self):
|
||||
connector_color = Cq.Color(0.8,0.8,0.5,0.3)
|
||||
insertion_color = Cq.Color(0.7,0.7,0.7,0.3)
|
||||
result = (
|
||||
Cq.Assembly()
|
||||
.add(self.insertion(), name="i", color=connector_color)
|
||||
.add(self.one_side_connector(), name="c", color=insertion_color)
|
||||
.constrain("i?mate", "c?mate", "Plane")
|
||||
.solve()
|
||||
)
|
||||
return result
|
|
@ -12,6 +12,7 @@ class Material(Enum):
|
|||
|
||||
WOOD_BIRCH = 0.8, _color('bisque', 0.9)
|
||||
PLASTIC_PLA = 0.5, _color('azure3', 0.6)
|
||||
ACRYLIC_BLACK = 0.5, _color('gray50', 0.6)
|
||||
|
||||
def __init__(self, density: float, color: Cq.Color):
|
||||
self.density = density
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import unittest
|
||||
import cadquery as Cq
|
||||
import nhf.joints
|
||||
import nhf.handle
|
||||
|
||||
class TestJoints(unittest.TestCase):
|
||||
|
||||
|
@ -13,5 +14,13 @@ class TestJoints(unittest.TestCase):
|
|||
def test_joints_comma_assembly(self):
|
||||
nhf.joints.comma_assembly()
|
||||
|
||||
|
||||
class TestHandle(unittest.TestCase):
|
||||
|
||||
def test_handle_assembly(self):
|
||||
h = nhf.handle.Handle()
|
||||
h.connector_insertion_assembly()
|
||||
h.connector_one_side_insertion_assembly()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -20,15 +20,18 @@ the wing which demands transluscency are created from 1/16" acrylic panels.
|
|||
These panels serve double duty as the exoskeleton.
|
||||
|
||||
The wings are labeled r1,r2,r3,l1,l2,l3. The segments of the wings are labeled
|
||||
from root to tip s0 (root), s1, s2, s3. The joints are named (from root to tip)
|
||||
from root to tip s0 (root),
|
||||
s1, s2, s3. The joints are named (from root to tip)
|
||||
shoulder, elbow, wrist in analogy with human anatomy.
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
import unittest
|
||||
import cadquery as Cq
|
||||
import nhf.joints
|
||||
import nhf.handle
|
||||
from nhf import Material
|
||||
import nhf.touhou.houjuu_nue.wing as MW
|
||||
import nhf.touhou.houjuu_nue.trident as MT
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Parameters:
|
||||
|
@ -86,6 +89,8 @@ class Parameters:
|
|||
wing_r2_height = 100
|
||||
wing_r3_height = 100
|
||||
|
||||
trident_handle: nhf.handle.Handle = nhf.handle.Handle()
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.wing_root_radius > self.hs_joint_radius,\
|
||||
"Wing root must be large enough to accomodate joint"
|
||||
|
@ -301,3 +306,6 @@ class Parameters:
|
|||
result.constrain(f"harness?{name}_{i}", f"hs_{name}p?h{i}", "Point")
|
||||
result.solve()
|
||||
return result
|
||||
|
||||
def trident_assembly(self):
|
||||
return MT.trident_assembly(self.trident_handle)
|
||||
|
|
|
@ -18,6 +18,9 @@ class Test(unittest.TestCase):
|
|||
def test_harness(self):
|
||||
p = M.Parameters()
|
||||
p.harness_assembly()
|
||||
def test_trident():
|
||||
p = M.Parameters()
|
||||
p.trident_assembly()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import math
|
||||
import cadquery as Cq
|
||||
from nhf import Material
|
||||
from nhf.handle import Handle
|
||||
|
||||
def trident_assembly(
|
||||
handle: Handle,
|
||||
handle_segment_length: float = 24*25.4):
|
||||
def segment():
|
||||
return handle.segment(handle_segment_length)
|
||||
mat_i = Material.PLASTIC_PLA
|
||||
mat_s = Material.ACRYLIC_BLACK
|
||||
assembly = (
|
||||
Cq.Assembly()
|
||||
.add(handle.insertion(), name="i0", color=mat_i.color)
|
||||
.constrain("i0", "Fixed")
|
||||
.add(segment(), name="s1", color=mat_s.color)
|
||||
.constrain("i0?lip", "s1?mate1", "Plane", param=0)
|
||||
.add(handle.insertion(), name="i1", color=mat_i.color)
|
||||
.add(handle.connector(), name="c1", color=mat_i.color)
|
||||
.add(handle.insertion(), name="i2", color=mat_i.color)
|
||||
.constrain("s1?mate2", "i1?lip", "Plane", param=0)
|
||||
.constrain("i1?mate", "c1?mate1", "Plane")
|
||||
.constrain("i2?mate", "c1?mate2", "Plane")
|
||||
.add(segment(), name="s2", color=mat_s.color)
|
||||
.constrain("i2?lip", "s2?mate1", "Plane", param=0)
|
||||
.add(handle.insertion(), name="i3", color=mat_i.color)
|
||||
.constrain("s2?mate2", "i3?lip", "Plane", param=0)
|
||||
)
|
||||
return assembly.solve()
|
Loading…
Reference in New Issue