""" To build, execute ``` python3 nhf/touhou/houjuu_nue/__init__.py ``` 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 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, field from typing import Optional import cadquery as Cq from nhf.build import Model, TargetKind, target, assembly, submodel import nhf.touhou.houjuu_nue.wing as MW 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.touhou.houjuu_nue.electronics as ME from nhf.parts.item import Item import nhf.utils WING_DEFLECT_ODD = 0.0 WING_DEFLECT_EVEN = 25.0 @dataclass class Parameters(Model): """ Defines dimensions for the Houjuu Nue cosplay """ harness: MH.Harness = field(default_factory=lambda: MH.Harness()) wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR( name="r1", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(0,1,1,1), parent_substrate_cull_edges=(0,0,1,0), ), shoulder_angle_bias=WING_DEFLECT_ODD, s0_top_hole=False, s0_bot_hole=True, arrow_height=350.0 )) wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR( name="r2", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(1,1,1,1), parent_substrate_cull_edges=(0,0,1,0), ), electronic_board=ME.ElectronicBoardControl(), shoulder_angle_bias=WING_DEFLECT_EVEN, s0_top_hole=True, s0_bot_hole=True, )) wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR( name="r3", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(1,1,1,0), parent_substrate_cull_edges=(0,0,1,0), ), shoulder_angle_bias=WING_DEFLECT_ODD, s0_top_hole=True, s0_bot_hole=False, )) wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL( name="l1", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(1,0,1,1), parent_substrate_cull_edges=(1,0,0,0), ), shoulder_angle_bias=WING_DEFLECT_EVEN, wrist_angle=-60.0, s0_top_hole=False, s0_bot_hole=True, )) wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL( name="l2", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(1,1,1,1), parent_substrate_cull_edges=(1,0,0,0), ), wrist_angle=-30.0, shoulder_angle_bias=WING_DEFLECT_ODD, s0_top_hole=True, s0_bot_hole=True, )) wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL( name="l3", root_joint=MJ.RootJoint( parent_substrate_cull_corners=(1,1,0,1), parent_substrate_cull_edges=(1,0,0,0), ), shoulder_angle_bias=WING_DEFLECT_EVEN, wrist_angle=-0.0, s0_top_hole=True, s0_bot_hole=False, )) trident: MT.Trident = field(default_factory=lambda: MT.Trident()) def __post_init__(self): super().__init__(name="houjuu-nue") @submodel(name="harness") def submodel_harness(self) -> Model: return self.harness @submodel(name="wing-r1") def submodel_wing_r1(self) -> Model: return self.wing_r1 @submodel(name="wing-r2") def submodel_wing_r2(self) -> Model: return self.wing_r2 @submodel(name="wing-r3") def submodel_wing_r3(self) -> Model: return self.wing_r3 @submodel(name="wing-l1") def submodel_wing_l1(self) -> Model: return self.wing_l1 @submodel(name="wing-l2") def submodel_wing_l2(self) -> Model: return self.wing_l2 @submodel(name="wing-l3") def submodel_wing_l3(self) -> Model: return self.wing_l3 @assembly() def wings_harness_assembly(self, parts: Optional[list[str]] = None, **kwargs) -> Cq.Assembly: """ Assembly of harness with all the wings """ result = ( Cq.Assembly() .add(self.harness.assembly(), name="harness", loc=Cq.Location((0, 0, 0))) .add(self.wing_r1.assembly(parts, root_offset=9, **kwargs), name="wing_r1") .add(self.wing_r2.assembly(parts, root_offset=7, **kwargs), name="wing_r2") .add(self.wing_r3.assembly(parts, root_offset=6, **kwargs), name="wing_r3") .add(self.wing_l1.assembly(parts, root_offset=19, **kwargs), name="wing_l1") .add(self.wing_l2.assembly(parts, root_offset=20, **kwargs), name="wing_l2") .add(self.wing_l3.assembly(parts, root_offset=21, **kwargs), name="wing_l3") ) for tag in ["r1", "r2", "r3", "l1", "l2", "l3"]: self.harness.add_root_joint_constraint( result, "harness/base", f"wing_{tag}/root", tag ) return result.solve() @submodel(name="trident") def submodel_trident(self) -> Model: return self.trident def stat(self) -> dict[str, float]: a = self.wings_harness_assembly() bbox = a.toCompound().BoundingBox() return { "wing-span": bbox.xlen, "wing-depth": bbox.ylen, "wing-height": bbox.zlen, "wing-mass": a.total_mass(), "wing-centre-of-mass": a.centre_of_mass().toTuple(), "items": Item.count(a), } if __name__ == '__main__': import sys p = Parameters() if len(sys.argv) == 1: p.build_all() sys.exit(0) if sys.argv[1] == 'stat': print(p.stat())