Cosplay/nhf/touhou/houjuu_nue/__init__.py

185 lines
6.4 KiB
Python
Raw Normal View History

2024-06-24 16:13:15 -07:00
"""
2024-07-03 23:15:39 -07:00
To build, execute
```
python3 nhf/touhou/houjuu_nue/__init__.py
```
2024-06-24 16:13:15 -07:00
This cosplay consists of 3 components:
## Trident
The trident is composed of individual segments, made of acrylic, and a 3D
printed head (convention rule prohibits metal) with a metallic paint. To ease
transportation, the trident handle has individual segments with threads and can
be assembled on site.
## Snake
A 3D printed snake with a soft material so it can wrap around and bend
## Wings
This is the crux of the cosplay and the most complex component. The wings mount
on a wearable harness. Each wing consists of 4 segments with 3 joints. Parts of
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
2024-06-25 06:11:48 -07:00
from root to tip s0 (root),
s1, s2, s3. The joints are named (from root to tip)
2024-06-24 16:13:15 -07:00
shoulder, elbow, wrist in analogy with human anatomy.
"""
2024-07-03 18:45:16 -07:00
from dataclasses import dataclass, field
2024-07-16 12:03:51 -07:00
from typing import Optional
2024-06-20 23:29:18 -07:00
import cadquery as Cq
2024-07-07 21:45:10 -07:00
from nhf.build import Model, TargetKind, target, assembly
from nhf.parts.joints import HirthJoint, TorsionJoint
2024-07-09 22:09:16 -07:00
from nhf.parts.handle import Handle, BayonetMount
2024-06-24 16:13:15 -07:00
import nhf.touhou.houjuu_nue.wing as MW
2024-06-25 06:11:48 -07:00
import nhf.touhou.houjuu_nue.trident as MT
import nhf.touhou.houjuu_nue.joints as MJ
import nhf.touhou.houjuu_nue.harness as MH
import nhf.utils
2024-06-19 15:54:09 -07:00
@dataclass
2024-07-03 23:15:39 -07:00
class Parameters(Model):
2024-06-19 21:23:41 -07:00
"""
2024-06-24 16:13:15 -07:00
Defines dimensions for the Houjuu Nue cosplay
2024-06-19 21:23:41 -07:00
"""
2024-06-24 16:13:15 -07:00
# Thickness of the exoskeleton panel in millimetres
2024-06-19 21:23:41 -07:00
panel_thickness: float = 25.4 / 16
2024-06-23 22:27:15 -07:00
# Harness
harness: MH.Harness = field(default_factory=lambda: MH.Harness())
2024-06-23 22:27:15 -07:00
2024-07-03 18:45:16 -07:00
hs_hirth_joint: HirthJoint = field(default_factory=lambda: HirthJoint(
radius=30,
radius_inner=20,
tooth_height=10,
base_height=5,
n_tooth=24
2024-07-03 18:45:16 -07:00
))
2024-07-09 19:57:54 -07:00
wing_profile: MW.WingProfile = field(default_factory=lambda: MW.WingProfile(
shoulder_joint=MJ.ShoulderJoint(
height=100.0,
),
elbow_joint=MJ.ElbowJoint(),
wrist_joint=MJ.ElbowJoint(),
elbow_height=110.0,
2024-07-09 19:57:54 -07:00
))
2024-06-24 16:13:15 -07:00
# Exterior radius of the wing root assembly
wing_root_radius: float = 40
wing_root_wall_thickness: float = 8
2024-06-20 23:29:18 -07:00
"""
2024-07-07 21:01:40 -07:00
Heights for various wing joints, where the numbers start from the first
joint.
2024-06-20 23:29:18 -07:00
"""
2024-07-07 12:15:47 -07:00
wing_s0_thickness: float = 40
2024-07-07 21:01:40 -07:00
# Length of the spacer
wing_s1_thickness: float = 20
wing_s1_spacer_thickness: float = 25.4 / 8
wing_s1_spacer_width: float = 20
wing_s1_spacer_hole_diam: float = 8
wing_s1_shoulder_spacer_hole_dist: float = 20
wing_s1_shoulder_spacer_width: float = 60
2024-06-20 23:29:18 -07:00
2024-07-03 18:45:16 -07:00
trident_handle: Handle = field(default_factory=lambda: Handle(
2024-06-26 08:28:25 -07:00
diam=38,
2024-07-01 17:59:42 -07:00
diam_inner=38-2 * 25.4/8,
2024-06-26 08:28:25 -07:00
diam_connector_internal=18,
simplify_geometry=False,
2024-07-09 22:09:16 -07:00
mount=BayonetMount(n_pin=3),
2024-07-03 18:45:16 -07:00
))
2024-07-10 16:20:33 -07:00
trident_terminal_height: float = 80
trident_terminal_hole_diam: float = 24
trident_terminal_bottom_thickness: float = 10
2024-06-25 06:11:48 -07:00
2024-06-24 16:13:15 -07:00
def __post_init__(self):
2024-07-04 10:02:58 -07:00
super().__init__(name="houjuu-nue")
self.harness.hs_hirth_joint = self.hs_hirth_joint
self.wing_profile.base_joint = self.hs_hirth_joint
assert self.wing_root_radius > self.hs_hirth_joint.radius, \
2024-06-24 16:13:15 -07:00
"Wing root must be large enough to accomodate joint"
assert self.wing_s1_shoulder_spacer_hole_dist > self.wing_s1_spacer_hole_diam, \
"Spacer holes are too close to each other"
2024-06-24 16:13:15 -07:00
2024-07-04 01:13:22 -07:00
@target(name="trident/handle-connector")
def handle_connector(self):
return self.trident_handle.connector()
@target(name="trident/handle-insertion")
def handle_insertion(self):
return self.trident_handle.insertion()
@target(name="trident/proto-handle-connector", prototype=True)
def proto_handle_connector(self):
2024-07-09 22:09:16 -07:00
return self.trident_handle.one_side_connector(height=15)
@target(name="trident/handle-terminal-connector")
def handle_terminal_connector(self):
2024-07-10 16:20:33 -07:00
result = self.trident_handle.one_side_connector(height=self.trident_terminal_height)
#result.faces("<Z").circle(radius=25/2).cutThruAll()
h = self.trident_terminal_height + self.trident_handle.insertion_length - self.trident_terminal_bottom_thickness
result = result.faces(">Z").hole(self.trident_terminal_hole_diam, depth=h)
return result
2024-07-04 01:13:22 -07:00
2024-07-04 01:11:16 -07:00
@target(name="harness", kind=TargetKind.DXF)
def harness_profile(self) -> Cq.Sketch:
return self.harness.profile()
2024-06-23 22:27:15 -07:00
def harness_surface(self) -> Cq.Workplane:
return self.harness.surface()
def hs_joint_parent(self) -> Cq.Workplane:
return self.harness.hs_joint_parent()
2024-06-22 13:40:06 -07:00
2024-07-07 21:45:10 -07:00
@assembly()
def harness_assembly(self) -> Cq.Assembly:
return self.harness.assembly()
2024-07-07 21:45:10 -07:00
@target(name="wing/proto-shoulder-joint-parent", prototype=True)
def proto_shoulder_joint_parent(self):
return self.wing_profile.shoulder_joint.torsion_joint.track()
@target(name="wing/proto-shoulder-joint-child", prototype=True)
def proto_shoulder_joint_child(self):
return self.wing_profile.shoulder_joint.torsion_joint.rider()
2024-07-07 21:01:40 -07:00
2024-07-07 21:45:10 -07:00
@assembly()
2024-07-16 12:03:51 -07:00
def wing_r1_assembly(self, parts: Optional[list[str]] = None) -> Cq.Assembly:
return self.wing_profile.assembly(parts)
2024-07-07 21:45:10 -07:00
@assembly()
2024-07-16 12:03:51 -07:00
def wings_harness_assembly(self, parts: Optional[list[str]] = None) -> Cq.Assembly:
"""
Assembly of harness with all the wings
"""
a_tooth = self.hs_hirth_joint.tooth_angle
result = (
Cq.Assembly()
.add(self.harness_assembly(), name="harness", loc=Cq.Location((0, 0, 0)))
2024-07-16 12:03:51 -07:00
.add(self.wing_r1_assembly(parts), name="wing_r1")
.add(self.wing_r1_assembly(parts), name="wing_r2")
.add(self.wing_r1_assembly(parts), name="wing_r3")
)
2024-07-16 12:03:51 -07:00
self.hs_hirth_joint.add_constraints(result, "harness/r1", "wing_r1/s0/hs", offset=9)
self.hs_hirth_joint.add_constraints(result, "harness/r2", "wing_r2/s0/hs", offset=8)
self.hs_hirth_joint.add_constraints(result, "harness/r3", "wing_r3/s0/hs", offset=7)
return result.solve()
2024-07-03 23:15:39 -07:00
2024-07-07 21:45:10 -07:00
@assembly(collision_check=False)
def trident_assembly(self) -> Cq.Assembly:
"""
Disable collision check since the threads may not align.
"""
return MT.trident_assembly(self.trident_handle)
2024-07-03 23:15:39 -07:00
if __name__ == '__main__':
p = Parameters()
p.build_all()