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
|
2024-07-06 16:41:13 -07:00
|
|
|
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
|
2024-07-12 23:16:04 -07:00
|
|
|
import nhf.touhou.houjuu_nue.joints as MJ
|
2024-07-14 23:58:42 -07:00
|
|
|
import nhf.touhou.houjuu_nue.harness as MH
|
2024-07-06 16:41:13 -07:00
|
|
|
import nhf.utils
|
2024-06-19 15:54:09 -07:00
|
|
|
|
2024-06-28 20:07:37 -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
|
2024-07-14 23:58:42 -07:00
|
|
|
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(
|
2024-06-28 20:07:37 -07:00
|
|
|
radius=30,
|
|
|
|
radius_inner=20,
|
|
|
|
tooth_height=10,
|
2024-07-14 23:58:42 -07:00
|
|
|
base_height=5,
|
|
|
|
n_tooth=24
|
2024-07-03 18:45:16 -07:00
|
|
|
))
|
2024-06-28 20:07:37 -07:00
|
|
|
|
2024-07-09 19:57:54 -07:00
|
|
|
wing_profile: MW.WingProfile = field(default_factory=lambda: MW.WingProfile(
|
2024-07-15 22:57:38 -07:00
|
|
|
shoulder_joint=MJ.ShoulderJoint(
|
|
|
|
height=100.0,
|
|
|
|
),
|
|
|
|
elbow_joint=MJ.ElbowJoint(),
|
|
|
|
wrist_joint=MJ.ElbowJoint(),
|
2024-07-12 23:16:04 -07:00
|
|
|
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
|
2024-06-28 20:07:37 -07:00
|
|
|
wing_root_radius: float = 40
|
2024-07-06 16:41:13 -07:00
|
|
|
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
|
2024-07-08 21:46:35 -07:00
|
|
|
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")
|
2024-07-14 23:58:42 -07:00
|
|
|
self.harness.hs_hirth_joint = self.hs_hirth_joint
|
2024-07-15 22:57:38 -07:00
|
|
|
self.wing_profile.base_joint = self.hs_hirth_joint
|
2024-07-14 23:58:42 -07:00
|
|
|
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"
|
2024-07-08 21:46:35 -07:00
|
|
|
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()
|
2024-07-09 22:22:48 -07:00
|
|
|
@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)
|
2024-07-14 23:58:42 -07:00
|
|
|
def harness_profile(self) -> Cq.Sketch:
|
|
|
|
return self.harness.profile()
|
2024-06-23 22:27:15 -07:00
|
|
|
|
2024-07-14 23:58:42 -07:00
|
|
|
def harness_surface(self) -> Cq.Workplane:
|
|
|
|
return self.harness.surface()
|
2024-07-04 12:03:38 -07:00
|
|
|
|
2024-07-14 23:58:42 -07:00
|
|
|
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:
|
2024-07-14 23:58:42 -07:00
|
|
|
return self.harness.assembly()
|
2024-07-07 21:45:10 -07:00
|
|
|
|
2024-07-09 22:22:48 -07:00
|
|
|
@target(name="wing/proto-shoulder-joint-parent", prototype=True)
|
|
|
|
def proto_shoulder_joint_parent(self):
|
2024-07-15 22:57:38 -07:00
|
|
|
return self.wing_profile.shoulder_joint.torsion_joint.track()
|
2024-07-09 22:22:48 -07:00
|
|
|
@target(name="wing/proto-shoulder-joint-child", prototype=True)
|
|
|
|
def proto_shoulder_joint_child(self):
|
2024-07-15 22:57:38 -07:00
|
|
|
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-06 16:41:13 -07:00
|
|
|
|
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:
|
2024-07-04 12:03:38 -07:00
|
|
|
"""
|
|
|
|
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-04 12:03:38 -07:00
|
|
|
)
|
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)
|
2024-07-15 22:57:38 -07:00
|
|
|
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()
|