cosplay: Touhou/Houjuu Nue #4
|
@ -46,15 +46,23 @@ class Parameters(Model):
|
|||
Defines dimensions for the Houjuu Nue cosplay
|
||||
"""
|
||||
|
||||
# Harness
|
||||
harness: MH.Harness = field(default_factory=lambda: MH.Harness())
|
||||
|
||||
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(name="r1"))
|
||||
wing_r2: MW.WingR = field(default_factory=lambda: MW.WingR(name="r2"))
|
||||
wing_r3: MW.WingR = field(default_factory=lambda: MW.WingR(name="r3"))
|
||||
wing_r1: MW.WingR = field(default_factory=lambda: MW.WingR(
|
||||
name="r1",
|
||||
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(
|
||||
name="l1",
|
||||
wrist_angle=-45.0,
|
||||
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
|
||||
))
|
||||
wing_l2: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||
name="l2",
|
||||
|
@ -63,6 +71,7 @@ class Parameters(Model):
|
|||
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
|
||||
name="l3",
|
||||
wrist_angle=0.0,
|
||||
shoulder_joint=MJ.ShoulderJoint(directrix_id=1),
|
||||
))
|
||||
|
||||
trident: MT.Trident = field(default_factory=lambda: MT.Trident())
|
||||
|
|
|
@ -14,7 +14,7 @@ TOL = 1e-6
|
|||
@dataclass
|
||||
class ShoulderJoint(Model):
|
||||
|
||||
height: float = 100.0
|
||||
height: float = 60.0
|
||||
torsion_joint: TorsionJoint = field(default_factory=lambda: TorsionJoint(
|
||||
radius_track=18,
|
||||
radius_rider=18,
|
||||
|
@ -30,19 +30,23 @@ class ShoulderJoint(Model):
|
|||
thickness=1.3,
|
||||
height=7.5,
|
||||
),
|
||||
rider_slot_begin=0,
|
||||
rider_n_slots=2,
|
||||
rider_slot_span=15,
|
||||
))
|
||||
|
||||
# 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
|
||||
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_width: float = 20.0
|
||||
parent_lip_thickness: float = 8.0
|
||||
parent_lip_length: float = 25.0
|
||||
parent_lip_width: float = 30.0
|
||||
parent_lip_thickness: float = 5.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
|
||||
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_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")
|
||||
def parent(self,
|
||||
root_wall_thickness: float = 25.4 / 16) -> Cq.Assembly:
|
||||
directrix_id: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
assert self.parent_lip_length * 2 < self.height
|
||||
|
||||
def parent(self, top: bool = False) -> Cq.Assembly:
|
||||
joint = self.torsion_joint
|
||||
# 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_ext > joint.radius_track
|
||||
|
||||
|
@ -86,14 +96,24 @@ class ShoulderJoint(Model):
|
|||
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))
|
||||
|
||||
rot = -self.axis_rotate_top if top else self.axis_rotate_bot
|
||||
|
||||
result = (
|
||||
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, name="lip", loc=loc_pos * loc_dir * loc_axis)
|
||||
)
|
||||
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
|
||||
def child_height(self) -> float:
|
||||
"""
|
||||
|
@ -103,7 +123,7 @@ class ShoulderJoint(Model):
|
|||
joint = self.torsion_joint
|
||||
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:
|
||||
"""
|
||||
Creates the top/bottom shoulder child joint
|
||||
|
@ -165,14 +185,17 @@ class ShoulderJoint(Model):
|
|||
centered=(True, True, False),
|
||||
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_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 = (
|
||||
Cq.Assembly()
|
||||
.add(core, name="core", loc=Cq.Location())
|
||||
.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",
|
||||
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",
|
||||
loc=Cq.Location((0, 0, dh)))
|
||||
.add(lip, name="lip_bot",
|
||||
|
@ -181,10 +204,8 @@ class ShoulderJoint(Model):
|
|||
return result
|
||||
|
||||
@assembly()
|
||||
def assembly(self,
|
||||
wing_root_wall_thickness: float = 25.4/16,
|
||||
) -> Cq.Assembly:
|
||||
directrix = 0
|
||||
def assembly(self, deflection: float = 0) -> Cq.Assembly:
|
||||
directrix = self.directrix_id
|
||||
mat = Material.RESIN_TRANSPERENT
|
||||
mat_spring = Material.STEEL_SPRING
|
||||
result = (
|
||||
|
@ -192,23 +213,25 @@ class ShoulderJoint(Model):
|
|||
.addS(self.child(), name="child",
|
||||
role=Role.CHILD, material=mat)
|
||||
.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)
|
||||
.addS(self.parent(wing_root_wall_thickness),
|
||||
.addS(self.parent_top(),
|
||||
name="parent_top",
|
||||
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)
|
||||
.addS(self.parent(wing_root_wall_thickness),
|
||||
.addS(self.parent_bot(),
|
||||
name="parent_bot",
|
||||
role=Role.PARENT, material=mat)
|
||||
)
|
||||
TorsionJoint.add_constraints(result,
|
||||
TorsionJoint.add_constraints(
|
||||
result,
|
||||
rider="child/rider_top",
|
||||
track="parent_top/track",
|
||||
spring="spring_top",
|
||||
directrix=directrix)
|
||||
TorsionJoint.add_constraints(result,
|
||||
TorsionJoint.add_constraints(
|
||||
result,
|
||||
rider="child/rider_bot",
|
||||
track="parent_bot/track",
|
||||
spring="spring_bot",
|
||||
|
|
|
@ -37,7 +37,6 @@ class WingProfile(Model):
|
|||
spacer_thickness: float = 25.4 / 8
|
||||
|
||||
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
|
||||
height=60.0,
|
||||
))
|
||||
shoulder_width: float = 30.0
|
||||
shoulder_tip_x: float = -200.0
|
||||
|
@ -94,6 +93,16 @@ class WingProfile(Model):
|
|||
self.wrist_s = math.sin(self.wrist_theta)
|
||||
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
|
||||
def root_height(self) -> float:
|
||||
return self.shoulder_joint.height
|
||||
|
@ -634,9 +643,9 @@ class WingProfile(Model):
|
|||
(
|
||||
result
|
||||
.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_bot1", "shoulder/parent_bot/lip?conn1", "Plane")
|
||||
#.constrain("s0/shoulder?conn_bot1", "shoulder/parent_bot/lip?conn1", "Plane")
|
||||
)
|
||||
if "s1" in parts:
|
||||
result.add(self.assembly_s1(), name="s1")
|
||||
|
|
Loading…
Reference in New Issue