cosplay: Touhou/Houjuu Nue #4

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

View File

@ -95,7 +95,7 @@ class RootJoint(Model):
child_height: float = 60.0
child_width: float = 50.0
child_mount_thickness: float = 25.4 / 8
child_mount_thickness: float = 25.4 / 4
def corner_pos(self) -> list[tuple[int, int]]:
"""
@ -888,6 +888,10 @@ class ElbowJoint(Model):
def total_thickness(self):
return self.disk_joint.total_thickness
@property
def motion_span(self) -> float:
return self.disk_joint.movement_angle
def parent_arm_loc(self) -> Cq.Location:
"""
2d Location of the centre of the arm surface on the parent side, assuming

View File

@ -24,7 +24,9 @@ class WingProfile(Model):
root_joint: RootJoint = field(default_factory=lambda: RootJoint())
panel_thickness: float = 25.4 / 16
spacer_thickness: float = 25.4 / 8
# 1/4" acrylic for the spacer. Anything thinner would threathen structural
# strength
spacer_thickness: float = 25.4 / 4
shoulder_joint: ShoulderJoint = field(default_factory=lambda: ShoulderJoint(
))
@ -325,9 +327,52 @@ class WingProfile(Model):
### s1, s2, s3 ###
def profile(self) -> Cq.Sketch:
"""
Generates profile from shoulder and above
Generates profile from shoulder and above. Subclass should implement
"""
def _elbow_joint_retract_cut_polygon(self, loc: Cq.Location) -> Cq.Sketch:
"""
Creates a cutting polygon for removing the contraction part of a joint
"""
theta = math.radians(self.elbow_joint.motion_span)
h = self.elbow_height
dx = h * math.tan(theta / 2)
dy = h
sign = -1 if self.flip else 1
points = [
(0, 0),
(dx, sign * dy),
(-dx, sign * dy),
]
return (
Cq.Sketch()
.polygon([
(loc * Cq.Location.from2d(*p)).to2d_pos()
for p in points
])
)
def _wrist_joint_retract_cut_polygon(self, loc: Cq.Location) -> Cq.Sketch:
"""
Creates a cutting polygon for removing the contraction part of a joint
"""
theta = math.radians(self.wrist_joint.motion_span)
dx = self.wrist_height * math.tan(theta)
dy = self.wrist_height
sign = -1 if self.flip else 1
points = [
(0, 0),
(0, -sign * dy),
(-dx, -sign * dy),
]
return (
Cq.Sketch()
.polygon([
(loc * Cq.Location.from2d(*p)).to2d_pos()
for p in points
])
)
def _assembly_insert_spacer(
self,
a: Cq.Assembly,
@ -374,8 +419,7 @@ class WingProfile(Model):
self,
joint: ElbowJoint,
segment_thickness: float,
dx: float,
bot=False) -> MountingBox:
dx: float) -> MountingBox:
length = joint.lip_length / 2 - dx
holes = [
Hole(x - dx)
@ -398,6 +442,9 @@ class WingProfile(Model):
self.profile()
.reset()
.polygon(self._mask_elbow(), mode='i')
.reset()
.push([self.elbow_axle_loc])
.each(self._elbow_joint_retract_cut_polygon, mode='s')
)
return profile
def surface_s1(self, front: bool = True) -> Cq.Workplane:
@ -471,6 +518,12 @@ class WingProfile(Model):
.polygon(self._mask_elbow(), mode='s')
.reset()
.polygon(self._mask_wrist(), mode='i')
.reset()
.push([self.elbow_axle_loc])
.each(self._elbow_joint_retract_cut_polygon, mode='s')
.reset()
.push([self.wrist_axle_loc])
.each(self._wrist_joint_retract_cut_polygon, mode='s')
)
return profile
def surface_s2(self, front: bool = True) -> Cq.Workplane:
@ -638,7 +691,7 @@ class WingProfile(Model):
.constrain("s1/shoulder_bot?conn1", f"shoulder/child/lip_{tag_bot}?conn1", "Plane")
)
if "elbow" in parts:
angle = self.elbow_joint.disk_joint.movement_angle * elbow_wrist_deflection
angle = self.elbow_joint.motion_span * elbow_wrist_deflection
result.add(self.elbow_joint.assembly(angle=angle), name="elbow")
if "s1" in parts and "elbow" in parts:
(
@ -659,7 +712,7 @@ class WingProfile(Model):
.constrain("s2/elbow_bot?conn1", f"elbow/child/lip?conn_{tag_bot}1", "Plane")
)
if "wrist" in parts:
angle = self.wrist_joint.disk_joint.movement_angle * elbow_wrist_deflection
angle = self.wrist_joint.motion_span * elbow_wrist_deflection
result.add(self.wrist_joint.assembly(angle=angle), name="wrist")
if "s2" in parts and "wrist" in parts:
# Mounted backwards to bend in other direction