feat: Cut polygons to remove joint conflict
This commit is contained in:
parent
f5b048d0b9
commit
d3a6f1e1c5
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue