cosplay: Touhou/Houjuu Nue #4
|
@ -52,8 +52,6 @@ class WingProfile(Model):
|
||||||
# Distance between the two spacers on the elbow, halved
|
# Distance between the two spacers on the elbow, halved
|
||||||
elbow_h2: float = 5.0
|
elbow_h2: float = 5.0
|
||||||
|
|
||||||
s2_thickness: float = 25.0
|
|
||||||
|
|
||||||
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
|
wrist_joint: ElbowJoint = field(default_factory=lambda: ElbowJoint(
|
||||||
disk_joint=DiskJoint(
|
disk_joint=DiskJoint(
|
||||||
movement_angle=30,
|
movement_angle=30,
|
||||||
|
@ -71,8 +69,6 @@ class WingProfile(Model):
|
||||||
# Distance between the two spacers on the elbow, halved
|
# Distance between the two spacers on the elbow, halved
|
||||||
wrist_h2: float = 5.0
|
wrist_h2: float = 5.0
|
||||||
|
|
||||||
s3_thickness: float = 25.0
|
|
||||||
|
|
||||||
mat_panel: Material = Material.ACRYLIC_TRANSLUSCENT
|
mat_panel: Material = Material.ACRYLIC_TRANSLUSCENT
|
||||||
mat_bracket: Material = Material.ACRYLIC_TRANSPARENT
|
mat_bracket: Material = Material.ACRYLIC_TRANSPARENT
|
||||||
mat_hs_joint: Material = Material.PLASTIC_PLA
|
mat_hs_joint: Material = Material.PLASTIC_PLA
|
||||||
|
@ -85,6 +81,8 @@ class WingProfile(Model):
|
||||||
wrist_height: float
|
wrist_height: float
|
||||||
elbow_rotate: float = -5.0
|
elbow_rotate: float = -5.0
|
||||||
wrist_rotate: float = -30.0
|
wrist_rotate: float = -30.0
|
||||||
|
# Position of the elbow axle with 0 being bottom and 1 being top (flipped on the left side)
|
||||||
|
elbow_axle_pos: float = 0.3
|
||||||
|
|
||||||
# False for the right side, True for the left side
|
# False for the right side, True for the left side
|
||||||
flip: bool
|
flip: bool
|
||||||
|
@ -94,7 +92,9 @@ class WingProfile(Model):
|
||||||
|
|
||||||
self.elbow_top_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height)
|
self.elbow_top_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height)
|
||||||
self.wrist_top_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height)
|
self.wrist_top_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height)
|
||||||
self.elbow_axle_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height / 2)
|
if self.flip:
|
||||||
|
self.elbow_axle_pos = 1 - self.elbow_axle_pos
|
||||||
|
self.elbow_axle_loc = self.elbow_bot_loc * Cq.Location.from2d(0, self.elbow_height * self.elbow_axle_pos)
|
||||||
if self.flip:
|
if self.flip:
|
||||||
self.wrist_axle_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height / 2)
|
self.wrist_axle_loc = self.wrist_bot_loc * Cq.Location.from2d(0, self.wrist_height / 2)
|
||||||
else:
|
else:
|
||||||
|
@ -108,6 +108,19 @@ class WingProfile(Model):
|
||||||
self.shoulder_joint.child_guard_width = self.s1_thickness + self.panel_thickness * 2
|
self.shoulder_joint.child_guard_width = self.s1_thickness + self.panel_thickness * 2
|
||||||
assert self.spacer_thickness == self.root_joint.child_mount_thickness
|
assert self.spacer_thickness == self.root_joint.child_mount_thickness
|
||||||
|
|
||||||
|
@property
|
||||||
|
def s2_thickness(self) -> float:
|
||||||
|
"""
|
||||||
|
s2 needs to duck under s1, so its thinner
|
||||||
|
"""
|
||||||
|
return self.s1_thickness - 2 * self.panel_thickness
|
||||||
|
@property
|
||||||
|
def s3_thickness(self) -> float:
|
||||||
|
"""
|
||||||
|
s3 does not need to duck under s2
|
||||||
|
"""
|
||||||
|
return self.s1_thickness - 2 * self.panel_thickness
|
||||||
|
|
||||||
@submodel(name="shoulder-joint")
|
@submodel(name="shoulder-joint")
|
||||||
def submodel_shoulder_joint(self) -> Model:
|
def submodel_shoulder_joint(self) -> Model:
|
||||||
return self.shoulder_joint
|
return self.shoulder_joint
|
||||||
|
@ -343,27 +356,6 @@ class WingProfile(Model):
|
||||||
"""
|
"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
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) -> Optional[Cq.Sketch]:
|
def _wrist_joint_retract_cut_polygon(self, loc: Cq.Location) -> Optional[Cq.Sketch]:
|
||||||
"""
|
"""
|
||||||
Creates a cutting polygon for removing the contraction part of a joint
|
Creates a cutting polygon for removing the contraction part of a joint
|
||||||
|
@ -422,6 +414,44 @@ class WingProfile(Model):
|
||||||
.assemble()
|
.assemble()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _parent_joint_extension_profile(
|
||||||
|
self,
|
||||||
|
loc_axle: Cq.Location,
|
||||||
|
loc_bot: Cq.Location,
|
||||||
|
loc_top: Cq.Location,
|
||||||
|
angle_span: float,
|
||||||
|
bot: bool = True
|
||||||
|
) -> Cq.Sketch:
|
||||||
|
"""
|
||||||
|
Generates a sector-like profile on the child side of a panel to
|
||||||
|
accomodate for joint rotation
|
||||||
|
"""
|
||||||
|
sign = -1 if bot else 1
|
||||||
|
|
||||||
|
loc_tip = loc_top if bot else loc_bot
|
||||||
|
loc_arc_right = loc_bot if bot else loc_top
|
||||||
|
loc_rel_arc_right = loc_axle.inverse * loc_arc_right
|
||||||
|
loc_arc_left = loc_axle * Cq.Location.rot2d(sign * angle_span) * loc_rel_arc_right
|
||||||
|
loc_arc_middle = loc_axle * Cq.Location.rot2d(sign * angle_span / 2) * loc_rel_arc_right
|
||||||
|
|
||||||
|
return (
|
||||||
|
Cq.Sketch()
|
||||||
|
.segment(
|
||||||
|
loc_tip.to2d_pos(),
|
||||||
|
loc_arc_right.to2d_pos(),
|
||||||
|
)
|
||||||
|
.arc(
|
||||||
|
loc_arc_right.to2d_pos(),
|
||||||
|
loc_arc_middle.to2d_pos(),
|
||||||
|
loc_arc_left.to2d_pos(),
|
||||||
|
)
|
||||||
|
.segment(
|
||||||
|
loc_tip.to2d_pos(),
|
||||||
|
loc_arc_left.to2d_pos(),
|
||||||
|
)
|
||||||
|
.assemble()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _assembly_insert_spacer(
|
def _assembly_insert_spacer(
|
||||||
self,
|
self,
|
||||||
|
@ -492,9 +522,6 @@ class WingProfile(Model):
|
||||||
self.profile()
|
self.profile()
|
||||||
.reset()
|
.reset()
|
||||||
.polygon(self._mask_elbow(), mode='i')
|
.polygon(self._mask_elbow(), mode='i')
|
||||||
.reset()
|
|
||||||
.push([self.elbow_axle_loc])
|
|
||||||
.each(self._elbow_joint_retract_cut_polygon, mode='s')
|
|
||||||
)
|
)
|
||||||
return profile
|
return profile
|
||||||
def surface_s1(self, front: bool = True) -> Cq.Workplane:
|
def surface_s1(self, front: bool = True) -> Cq.Workplane:
|
||||||
|
@ -516,35 +543,6 @@ class WingProfile(Model):
|
||||||
tags = tags_shoulder + tags_elbow
|
tags = tags_shoulder + tags_elbow
|
||||||
return extrude_with_markers(
|
return extrude_with_markers(
|
||||||
profile, self.panel_thickness, tags, reverse=front)
|
profile, self.panel_thickness, tags, reverse=front)
|
||||||
@target(name="profile-s1-bridge", kind=TargetKind.DXF)
|
|
||||||
def profile_s1_bridge(self) -> Cq.Workplane:
|
|
||||||
return (
|
|
||||||
self.profile()
|
|
||||||
#.reset()
|
|
||||||
#.polygon(self._mask_elbow(), mode='i')
|
|
||||||
.reset()
|
|
||||||
.push([self.elbow_axle_loc])
|
|
||||||
.each(self._elbow_joint_retract_cut_polygon, mode='i')
|
|
||||||
.reset()
|
|
||||||
.push([self.elbow_axle_loc])
|
|
||||||
.each(lambda loc: self._joint_extension_profile(
|
|
||||||
axle_loc=self.elbow_axle_loc,
|
|
||||||
radius=self.elbow_height / 2,
|
|
||||||
angle_span=self.elbow_joint.motion_span,
|
|
||||||
bot=not self.flip,
|
|
||||||
), mode='a')
|
|
||||||
)
|
|
||||||
def surface_s1_bridge(self, front: bool = True) -> Cq.Workplane:
|
|
||||||
profile = self.profile_s1_bridge()
|
|
||||||
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.parent_arm_loc()
|
|
||||||
tags = [
|
|
||||||
("elbow_bot", self.elbow_axle_loc * loc_elbow *
|
|
||||||
Cq.Location.from2d(0, -self.elbow_h2)),
|
|
||||||
("elbow_top", self.elbow_axle_loc * loc_elbow *
|
|
||||||
Cq.Location.from2d(0, self.elbow_h2)),
|
|
||||||
]
|
|
||||||
return extrude_with_markers(
|
|
||||||
profile, self.panel_thickness, tags, reverse=not front)
|
|
||||||
@submodel(name="spacer-s1-shoulder")
|
@submodel(name="spacer-s1-shoulder")
|
||||||
def spacer_s1_shoulder(self) -> MountingBox:
|
def spacer_s1_shoulder(self) -> MountingBox:
|
||||||
holes = [
|
holes = [
|
||||||
|
@ -576,14 +574,6 @@ class WingProfile(Model):
|
||||||
material=self.mat_panel, role=self.role_panel)
|
material=self.mat_panel, role=self.role_panel)
|
||||||
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
|
.constrain("front@faces@>Z", "back@faces@<Z", "Point",
|
||||||
param=self.s1_thickness)
|
param=self.s1_thickness)
|
||||||
.addS(self.surface_s1_bridge(front=True), name="bridge_front",
|
|
||||||
material=self.mat_panel, role=self.role_panel)
|
|
||||||
.constrain("front?elbow_bot", "bridge_front?elbow_bot", "Plane")
|
|
||||||
.constrain("front?elbow_top", "bridge_front?elbow_top", "Plane")
|
|
||||||
.addS(self.surface_s1_bridge(front=False), name="bridge_back",
|
|
||||||
material=self.mat_panel, role=self.role_panel)
|
|
||||||
.constrain("back?elbow_bot", "bridge_back?elbow_bot", "Plane")
|
|
||||||
.constrain("back?elbow_top", "bridge_back?elbow_top", "Plane")
|
|
||||||
)
|
)
|
||||||
for t in ["shoulder_bot", "shoulder_top", "elbow_bot", "elbow_top"]:
|
for t in ["shoulder_bot", "shoulder_top", "elbow_bot", "elbow_top"]:
|
||||||
is_top = t.endswith("_top")
|
is_top = t.endswith("_top")
|
||||||
|
@ -607,15 +597,14 @@ class WingProfile(Model):
|
||||||
.polygon(self._mask_wrist(), mode='i')
|
.polygon(self._mask_wrist(), mode='i')
|
||||||
.reset()
|
.reset()
|
||||||
.push([self.elbow_axle_loc])
|
.push([self.elbow_axle_loc])
|
||||||
.each(self._elbow_joint_retract_cut_polygon, mode='s')
|
.each(lambda loc: self._parent_joint_extension_profile(
|
||||||
|
loc,
|
||||||
|
self.elbow_bot_loc,
|
||||||
|
self.elbow_top_loc,
|
||||||
|
self.elbow_joint.motion_span,
|
||||||
|
bot=not self.flip,
|
||||||
|
), mode='a')
|
||||||
)
|
)
|
||||||
if self.flip:
|
|
||||||
profile = (
|
|
||||||
profile
|
|
||||||
.reset()
|
|
||||||
.push([self.wrist_axle_loc])
|
|
||||||
.each(self._wrist_joint_retract_cut_polygon, mode='s')
|
|
||||||
)
|
|
||||||
return profile
|
return profile
|
||||||
def surface_s2(self, front: bool = True) -> Cq.Workplane:
|
def surface_s2(self, front: bool = True) -> Cq.Workplane:
|
||||||
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc(flip=self.flip)
|
loc_elbow = Cq.Location.rot2d(self.elbow_rotate) * self.elbow_joint.child_arm_loc(flip=self.flip)
|
||||||
|
|
Loading…
Reference in New Issue