cosplay: Touhou/Houjuu Nue #4

Open
aniva wants to merge 189 commits from touhou/houjuu-nue into main
2 changed files with 38 additions and 34 deletions
Showing only changes of commit 7e7b9e1f64 - Show all commits

View File

@ -634,12 +634,15 @@ class ElbowJoint(Model):
axle is at position 0, and parent direction is -X axle is at position 0, and parent direction is -X
""" """
return Cq.Location.from2d(-self.parent_arm_radius, 0, 0) return Cq.Location.from2d(-self.parent_arm_radius, 0, 0)
def child_arm_loc(self) -> Cq.Location: def child_arm_loc(self, flip: bool = False) -> Cq.Location:
""" """
2d Location of the centre of the arm surface on the child side, assuming 2d Location of the centre of the arm surface on the child side, assuming
axle is at position 0, and parent direction is -X axle is at position 0, and parent direction is -X
Set `flip=True` to indicate that the joint is supposed to be installed upside down
""" """
return Cq.Location.rot2d(self.angle_neutral) * Cq.Location.from2d(self.child_arm_radius, 0, 180) result = Cq.Location.rot2d(self.angle_neutral) * Cq.Location.from2d(self.child_arm_radius, 0, 180)
return result.flip_y() if flip else result
def lip(self) -> Cq.Workplane: def lip(self) -> Cq.Workplane:
holes = [ holes = [

View File

@ -62,7 +62,7 @@ class WingProfile(Model):
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint( wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
disk_joint=DiskJoint( disk_joint=DiskJoint(
movement_angle=45, movement_angle=30,
radius_disk=13.0, radius_disk=13.0,
radius_housing=15.0, radius_housing=15.0,
), ),
@ -91,6 +91,7 @@ class WingProfile(Model):
elbow_rotate: float = -5.0 elbow_rotate: float = -5.0
wrist_rotate: float = 30.0 wrist_rotate: float = 30.0
# False for the right side, True for the left side
flip: bool = False flip: bool = False
def __post_init__(self): def __post_init__(self):
@ -447,9 +448,9 @@ class WingProfile(Model):
h = self.elbow_height / 2 h = self.elbow_height / 2
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.parent_arm_loc() loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.parent_arm_loc()
tags_elbow = [ tags_elbow = [
("elbow_bot", self.elbow_axle_loc * loc_elbow *\ ("elbow_bot", self.elbow_axle_loc * loc_elbow *
Cq.Location.from2d(0, -self.elbow_h2)), Cq.Location.from2d(0, -self.elbow_h2)),
("elbow_top", self.elbow_axle_loc * loc_elbow *\ ("elbow_top", self.elbow_axle_loc * loc_elbow *
Cq.Location.from2d(0, self.elbow_h2)), Cq.Location.from2d(0, self.elbow_h2)),
] ]
profile = self.profile_s1() profile = self.profile_s1()
@ -512,19 +513,19 @@ class WingProfile(Model):
return profile return profile
def surface_s2(self, front: bool = True) -> Cq.Workplane: def surface_s2(self, front: bool = True) -> Cq.Workplane:
h = self.elbow_height / 2 h = self.elbow_height / 2
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc() loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc(flip=self.flip)
tags_elbow = [ tags_elbow = [
("elbow_bot", self.elbow_axle_loc * loc_elbow *\ ("elbow_bot", self.elbow_axle_loc * loc_elbow *
Cq.Location.from2d(0, self.elbow_h2)), Cq.Location.from2d(0, self.elbow_h2)),
("elbow_top", self.elbow_axle_loc * loc_elbow *\ ("elbow_top", self.elbow_axle_loc * loc_elbow *
Cq.Location.from2d(0, -self.elbow_h2)), Cq.Location.from2d(0, -self.elbow_h2)),
] ]
h = self.wrist_height / 2 h = self.wrist_height / 2
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.parent_arm_loc().flip_y() loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.parent_arm_loc()
tags_wrist = [ tags_wrist = [
("wrist_bot", self.wrist_axle_loc * loc_wrist *\ ("wrist_bot", self.wrist_axle_loc * loc_wrist *
Cq.Location.from2d(0, -self.wrist_h2)), Cq.Location.from2d(0, -self.wrist_h2)),
("wrist_top", self.wrist_axle_loc * loc_wrist *\ ("wrist_top", self.wrist_axle_loc * loc_wrist *
Cq.Location.from2d(0, self.wrist_h2)), Cq.Location.from2d(0, self.wrist_h2)),
] ]
profile = self.profile_s2() profile = self.profile_s2()
@ -580,11 +581,11 @@ class WingProfile(Model):
def surface_s3(self, def surface_s3(self,
front: bool = True) -> Cq.Workplane: front: bool = True) -> Cq.Workplane:
h = self.wrist_height / 2 h = self.wrist_height / 2
loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc().flip_y() loc_wrist = Cq.Location.rot2d(self.wrist_rotate) * self.wrist_joint.child_arm_loc(flip=not self.flip)
tags = [ tags = [
("wrist_bot", self.wrist_axle_loc * loc_wrist *\ ("wrist_bot", self.wrist_axle_loc * loc_wrist *
Cq.Location.from2d(0, self.wrist_h2)), Cq.Location.from2d(0, self.wrist_h2)),
("wrist_top", self.wrist_axle_loc * loc_wrist *\ ("wrist_top", self.wrist_axle_loc * loc_wrist *
Cq.Location.from2d(0, -self.wrist_h2)), Cq.Location.from2d(0, -self.wrist_h2)),
] ]
profile = self.profile_s3() profile = self.profile_s3()
@ -662,42 +663,42 @@ class WingProfile(Model):
if "s1" in parts and "elbow" in parts: if "s1" in parts and "elbow" in parts:
( (
result result
.constrain("s1/elbow_top?conn0", "elbow/parent_upper/lip?conn_top0", "Plane") .constrain("s1/elbow_top?conn0", f"elbow/parent_upper/lip?conn_{tag_top}0", "Plane")
.constrain("s1/elbow_top?conn1", "elbow/parent_upper/lip?conn_top1", "Plane") .constrain("s1/elbow_top?conn1", f"elbow/parent_upper/lip?conn_{tag_top}1", "Plane")
.constrain("s1/elbow_bot?conn0", "elbow/parent_upper/lip?conn_bot0", "Plane") .constrain("s1/elbow_bot?conn0", f"elbow/parent_upper/lip?conn_{tag_bot}0", "Plane")
.constrain("s1/elbow_bot?conn1", "elbow/parent_upper/lip?conn_bot1", "Plane") .constrain("s1/elbow_bot?conn1", f"elbow/parent_upper/lip?conn_{tag_bot}1", "Plane")
) )
if "s2" in parts: if "s2" in parts:
result.add(self.assembly_s2(), name="s2") result.add(self.assembly_s2(), name="s2")
if "s2" in parts and "elbow" in parts: if "s2" in parts and "elbow" in parts:
( (
result result
.constrain("s2/elbow_top?conn0", "elbow/child/lip?conn_top0", "Plane") .constrain("s2/elbow_top?conn0", f"elbow/child/lip?conn_{tag_top}0", "Plane")
.constrain("s2/elbow_top?conn1", "elbow/child/lip?conn_top1", "Plane") .constrain("s2/elbow_top?conn1", f"elbow/child/lip?conn_{tag_top}1", "Plane")
.constrain("s2/elbow_bot?conn0", "elbow/child/lip?conn_bot0", "Plane") .constrain("s2/elbow_bot?conn0", f"elbow/child/lip?conn_{tag_bot}0", "Plane")
.constrain("s2/elbow_bot?conn1", "elbow/child/lip?conn_bot1", "Plane") .constrain("s2/elbow_bot?conn1", f"elbow/child/lip?conn_{tag_bot}1", "Plane")
) )
if "wrist" in parts: if "wrist" in parts:
angle = self.wrist_joint.disk_joint.movement_angle * elbow_wrist_deflection angle = self.wrist_joint.disk_joint.movement_angle * elbow_wrist_deflection
result.add(self.wrist_joint.assembly(angle=elbow_wrist_deflection), name="wrist") result.add(self.wrist_joint.assembly(angle=angle), name="wrist")
if "s2" in parts and "wrist" in parts: if "s2" in parts and "wrist" in parts:
# Mounted backwards to bend in other direction # Mounted backwards to bend in other direction
( (
result result
.constrain("s2/wrist_top?conn0", "wrist/parent_upper/lip?conn_bot0", "Plane") .constrain("s2/wrist_top?conn0", f"wrist/parent_upper/lip?conn_{tag_bot}0", "Plane")
.constrain("s2/wrist_top?conn1", "wrist/parent_upper/lip?conn_bot1", "Plane") .constrain("s2/wrist_top?conn1", f"wrist/parent_upper/lip?conn_{tag_bot}1", "Plane")
.constrain("s2/wrist_bot?conn0", "wrist/parent_upper/lip?conn_top0", "Plane") .constrain("s2/wrist_bot?conn0", f"wrist/parent_upper/lip?conn_{tag_top}0", "Plane")
.constrain("s2/wrist_bot?conn1", "wrist/parent_upper/lip?conn_top1", "Plane") .constrain("s2/wrist_bot?conn1", f"wrist/parent_upper/lip?conn_{tag_top}1", "Plane")
) )
if "s3" in parts: if "s3" in parts:
result.add(self.assembly_s3(), name="s3") result.add(self.assembly_s3(), name="s3")
if "s3" in parts and "wrist" in parts: if "s3" in parts and "wrist" in parts:
( (
result result
.constrain("s3/wrist_top?conn0", "wrist/child/lip?conn_bot0", "Plane") .constrain("s3/wrist_top?conn0", f"wrist/child/lip?conn_{tag_bot}0", "Plane")
.constrain("s3/wrist_top?conn1", "wrist/child/lip?conn_bot1", "Plane") .constrain("s3/wrist_top?conn1", f"wrist/child/lip?conn_{tag_bot}1", "Plane")
.constrain("s3/wrist_bot?conn0", "wrist/child/lip?conn_top0", "Plane") .constrain("s3/wrist_bot?conn0", f"wrist/child/lip?conn_{tag_top}0", "Plane")
.constrain("s3/wrist_bot?conn1", "wrist/child/lip?conn_top1", "Plane") .constrain("s3/wrist_bot?conn1", f"wrist/child/lip?conn_{tag_top}1", "Plane")
) )
if len(parts) > 1: if len(parts) > 1:
result.solve() result.solve()
@ -845,10 +846,10 @@ class WingL(WingProfile):
def __post_init__(self): def __post_init__(self):
assert self.wrist_height <= self.shoulder_joint.height assert self.wrist_height <= self.shoulder_joint.height
self.wrist_bot_loc = self.wrist_bot_loc.with_angle_2d(self.wrist_angle) self.wrist_bot_loc = self.wrist_bot_loc.with_angle_2d(self.wrist_angle)
self.elbow_joint.angle_neutral = -15.0 self.elbow_joint.angle_neutral = 15.0
self.elbow_rotate = 5.0 self.elbow_rotate = 5.0
self.wrist_joint.angle_neutral = -self.wrist_bot_loc.to2d_rot() - 30.0 self.wrist_joint.angle_neutral = self.wrist_bot_loc.to2d_rot() + 30.0
self.wrist_rotate = self.wrist_joint.angle_neutral self.wrist_rotate = -self.wrist_joint.angle_neutral
super().__post_init__() super().__post_init__()