cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
3 changed files with 81 additions and 40 deletions
Showing only changes of commit c12ccf3495 - Show all commits

View File

@ -46,15 +46,23 @@ class Parameters(Model):
Defines dimensions for the Houjuu Nue cosplay Defines dimensions for the Houjuu Nue cosplay
""" """
# Harness
harness: MH.Harness = field(default_factory=lambda: MH.Harness()) harness: MH.Harness = field(default_factory=lambda: MH.Harness())
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(name="r1")) wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(name="r2")) name="r1",
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(name="r3")) shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(
name="r2",
))
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(
name="r3",
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
))
wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL( wing_l1: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l1", name="l1",
wrist_angle=-45.0, wrist_angle=-45.0,
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
)) ))
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL( wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l2", name="l2",
@ -63,6 +71,7 @@ class Parameters(Model):
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL( wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l3", name="l3",
wrist_angle=0.0, wrist_angle=0.0,
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
)) ))
trident: MT.Trident = field(default_factory=lambda: MT.Trident()) trident: MT.Trident = field(default_factory=lambda: MT.Trident())

View File

@ -14,7 +14,7 @@ TOL = 1e-6
@dataclass @dataclass
class ShoulderJoint(Model): class ShoulderJoint(Model):
height: float = 100.0 height: float = 60.0
torsion_joint: TorsionJoint = field(default_factory=lambda: TorsionJoint( torsion_joint: TorsionJoint = field(default_factory=lambda: TorsionJoint(
radius_track=18, radius_track=18,
radius_rider=18, radius_rider=18,
@ -30,19 +30,23 @@ class ShoulderJoint(Model):
thickness=1.3, thickness=1.3,
height=7.5, height=7.5,
), ),
rider_slot_begin=0,
rider_n_slots=2,
rider_slot_span=15,
)) ))
# On the parent side, drill vertical holes # On the parent side, drill vertical holes
parent_conn_hole_diam: float = 6.0 parent_conn_hole_diam: float = 4.0
# Position of the holes relative # Position of the holes relative
parent_conn_hole_pos: list[float] = field(default_factory=lambda: [20, 30]) parent_conn_hole_pos: list[float] = field(default_factory=lambda: [15])
parent_lip_length: float = 40.0 parent_lip_length: float = 25.0
parent_lip_width: float = 20.0 parent_lip_width: float = 30.0
parent_lip_thickness: float = 8.0 parent_lip_thickness: float = 5.0
parent_lip_ext: float = 40.0 parent_lip_ext: float = 40.0
parent_lip_guard_height: float = 10.0 parent_lip_guard_height: float = 8.0
parent_root_wall_thickness: float = 25.4 / 16
# Measured from centre of axle # Measured from centre of axle
child_lip_length: float = 45.0 child_lip_length: float = 45.0
@ -52,13 +56,19 @@ class ShoulderJoint(Model):
child_conn_hole_pos: list[float] = field(default_factory=lambda: [25, 35]) child_conn_hole_pos: list[float] = field(default_factory=lambda: [25, 35])
child_core_thickness: float = 3.0 child_core_thickness: float = 3.0
# Rotates the torsion joint to avoid collisions or for some other purpose
axis_rotate_bot: float = 225.0
axis_rotate_top: float = -225.0
@target(name="shoulder-joint/parent") directrix_id: int = 0
def parent(self,
root_wall_thickness: float = 25.4 / 16) -> Cq.Assembly: def __post_init__(self):
assert self.parent_lip_length * 2 < self.height
def parent(self, top: bool = False) -> Cq.Assembly:
joint = self.torsion_joint joint = self.torsion_joint
# Thickness of the lip connecting this joint to the wing root # Thickness of the lip connecting this joint to the wing root
dz = root_wall_thickness dz = self.parent_root_wall_thickness
assert self.parent_lip_width <= joint.radius_track * 2 assert self.parent_lip_width <= joint.radius_track * 2
assert self.parent_lip_ext > joint.radius_track assert self.parent_lip_ext > joint.radius_track
@ -86,14 +96,24 @@ class ShoulderJoint(Model):
loc_dir = Cq.Location((0,0,0), (0, 0, 1), 180) loc_dir = Cq.Location((0,0,0), (0, 0, 1), 180)
loc_pos = Cq.Location((self.parent_lip_ext - self.parent_lip_thickness, 0, dz)) loc_pos = Cq.Location((self.parent_lip_ext - self.parent_lip_thickness, 0, dz))
rot = -self.axis_rotate_top if top else self.axis_rotate_bot
result = ( result = (
Cq.Assembly() Cq.Assembly()
.add(joint.track(), name="track") .add(joint.track(), name="track",
loc=Cq.Location((0, 0, 0), (0, 0, 1), rot))
.add(lip_guard, name="lip_guard") .add(lip_guard, name="lip_guard")
.add(lip, name="lip", loc=loc_pos * loc_dir * loc_axis) .add(lip, name="lip", loc=loc_pos * loc_dir * loc_axis)
) )
return result return result
@target(name="parent-bot")
def parent_bot(self) -> Cq.Assembly:
return self.parent(top=False)
@target(name="parent-top")
def parent_top(self) -> Cq.Assembly:
return self.parent(top=True)
@property @property
def child_height(self) -> float: def child_height(self) -> float:
""" """
@ -103,7 +123,7 @@ class ShoulderJoint(Model):
joint = self.torsion_joint joint = self.torsion_joint
return self.height - 2 * joint.total_height + 2 * joint.rider_disk_height return self.height - 2 * joint.total_height + 2 * joint.rider_disk_height
@target(name="shoulder-joint/child") @target(name="child")
def child(self) -> Cq.Assembly: def child(self) -> Cq.Assembly:
""" """
Creates the top/bottom shoulder child joint Creates the top/bottom shoulder child joint
@ -165,14 +185,17 @@ class ShoulderJoint(Model):
centered=(True, True, False), centered=(True, True, False),
combine='cut') combine='cut')
) )
theta = self.torsion_joint.spring.angle_neutral - self.torsion_joint.rider_slot_span
loc_rotate = Cq.Location((0, 0, 0), (1, 0, 0), 180) loc_rotate = Cq.Location((0, 0, 0), (1, 0, 0), 180)
loc_axis_rotate_bot = Cq.Location((0, 0, 0), (0, 0, 1), self.axis_rotate_bot)
loc_axis_rotate_top = Cq.Location((0, 0, 0), (0, 0, 1), self.axis_rotate_top)
result = ( result = (
Cq.Assembly() Cq.Assembly()
.add(core, name="core", loc=Cq.Location()) .add(core, name="core", loc=Cq.Location())
.add(joint.rider(rider_slot_begin=-90, reverse_directrix_label=True), name="rider_top", .add(joint.rider(rider_slot_begin=-90, reverse_directrix_label=True), name="rider_top",
loc=Cq.Location((0, 0, dh), (0, 0, 1), -90)) loc=loc_axis_rotate_top * Cq.Location((0, 0, dh), (0, 0, 1), -90) * Cq.Location((0, 0, 0), (0, 0, 1), theta))
.add(joint.rider(rider_slot_begin=180), name="rider_bot", .add(joint.rider(rider_slot_begin=180), name="rider_bot",
loc=Cq.Location((0, 0, -dh), (0, 0, 1), -90) * loc_rotate) loc=loc_axis_rotate_bot * Cq.Location((0, 0, -dh), (0, 0, 1), -90) * loc_rotate)
.add(lip, name="lip_top", .add(lip, name="lip_top",
loc=Cq.Location((0, 0, dh))) loc=Cq.Location((0, 0, dh)))
.add(lip, name="lip_bot", .add(lip, name="lip_bot",
@ -181,10 +204,8 @@ class ShoulderJoint(Model):
return result return result
@assembly() @assembly()
def assembly(self, def assembly(self, deflection: float = 0) -> Cq.Assembly:
wing_root_wall_thickness: float = 25.4/16, directrix = self.directrix_id
) -> Cq.Assembly:
directrix = 0
mat = Material.RESIN_TRANSPERENT mat = Material.RESIN_TRANSPERENT
mat_spring = Material.STEEL_SPRING mat_spring = Material.STEEL_SPRING
result = ( result = (
@ -192,23 +213,25 @@ class ShoulderJoint(Model):
.addS(self.child(), name="child", .addS(self.child(), name="child",
role=Role.CHILD, material=mat) role=Role.CHILD, material=mat)
.constrain("child/core", "Fixed") .constrain("child/core", "Fixed")
.addS(self.torsion_joint.spring.generate(), name="spring_top", .addS(self.torsion_joint.spring.generate(deflection=-deflection), name="spring_top",
role=Role.DAMPING, material=mat_spring) role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness), .addS(self.parent_top(),
name="parent_top", name="parent_top",
role=Role.PARENT, material=mat) role=Role.PARENT, material=mat)
.addS(self.torsion_joint.spring.generate(), name="spring_bot", .addS(self.torsion_joint.spring.generate(deflection=deflection), name="spring_bot",
role=Role.DAMPING, material=mat_spring) role=Role.DAMPING, material=mat_spring)
.addS(self.parent(wing_root_wall_thickness), .addS(self.parent_bot(),
name="parent_bot", name="parent_bot",
role=Role.PARENT, material=mat) role=Role.PARENT, material=mat)
) )
TorsionJoint.add_constraints(result, TorsionJoint.add_constraints(
result,
rider="child/rider_top", rider="child/rider_top",
track="parent_top/track", track="parent_top/track",
spring="spring_top", spring="spring_top",
directrix=directrix) directrix=directrix)
TorsionJoint.add_constraints(result, TorsionJoint.add_constraints(
result,
rider="child/rider_bot", rider="child/rider_bot",
track="parent_bot/track", track="parent_bot/track",
spring="spring_bot", spring="spring_bot",

View File

@ -37,7 +37,6 @@ class WingProfile(Model):
spacer_thickness: float = 25.4 / 8 spacer_thickness: float = 25.4 / 8
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint( shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
height=60.0,
)) ))
shoulder_width: float = 30.0 shoulder_width: float = 30.0
shoulder_tip_x: float = -200.0 shoulder_tip_x: float = -200.0
@ -94,6 +93,16 @@ class WingProfile(Model):
self.wrist_s = math.sin(self.wrist_theta) self.wrist_s = math.sin(self.wrist_theta)
self.wrist_top_x, self.wrist_top_y = self.wrist_to_abs(0, self.wrist_height) self.wrist_top_x, self.wrist_top_y = self.wrist_to_abs(0, self.wrist_height)
@submodel(name="shoulder-joint")
def submodel_shoulder_joint(self) -> Model:
return self.shoulder_joint
@submodel(name="elbow-joint")
def submodel_elbow_joint(self) -> Model:
return self.elbow_joint
@submodel(name="wrist-joint")
def submodel_wrist_joint(self) -> Model:
return self.wrist_joint
@property @property
def root_height(self) -> float: def root_height(self) -> float:
return self.shoulder_joint.height return self.shoulder_joint.height
@ -634,9 +643,9 @@ class WingProfile(Model):
( (
result result
.constrain("s0/shoulder?conn_top0", "shoulder/parent_top/lip?conn0", "Plane") .constrain("s0/shoulder?conn_top0", "shoulder/parent_top/lip?conn0", "Plane")
.constrain("s0/shoulder?conn_top1", "shoulder/parent_top/lip?conn1", "Plane") #.constrain("s0/shoulder?conn_top1", "shoulder/parent_top/lip?conn1", "Plane")
.constrain("s0/shoulder?conn_bot0", "shoulder/parent_bot/lip?conn0", "Plane") .constrain("s0/shoulder?conn_bot0", "shoulder/parent_bot/lip?conn0", "Plane")
.constrain("s0/shoulder?conn_bot1", "shoulder/parent_bot/lip?conn1", "Plane") #.constrain("s0/shoulder?conn_bot1", "shoulder/parent_bot/lip?conn1", "Plane")
) )
if "s1" in parts: if "s1" in parts:
result.add(self.assembly_s1(), name="s1") result.add(self.assembly_s1(), name="s1")