refactor: Use 2d locations for wing tags

This commit is contained in:
Leni Aniva 2024-07-17 21:17:50 -07:00
parent 6d72749c9b
commit 6c6c17ea07
Signed by: aniva
GPG Key ID: 4D9B1C8D10EA4C50
3 changed files with 129 additions and 134 deletions

View File

@ -70,7 +70,7 @@ class Parameters(Model):
))
wing_l3: MW.WingL = field(default_factory=lambda: MW.WingL(
name="l3",
wrist_angle=0.0,
wrist_angle=-0.0,
))
trident: MT.Trident = field(default_factory=lambda: MT.Trident())

View File

@ -81,13 +81,9 @@ class WingProfile(Model):
role_panel: Role = Role.STRUCTURE
# Subclass must populate
elbow_x: float
elbow_y: float
elbow_angle: float
elbow_bot_loc: Cq.Location
elbow_height: float
wrist_x: float
wrist_y: float
wrist_angle: float
wrist_bot_loc: Cq.Location
wrist_height: float
flip: bool = False
@ -95,14 +91,8 @@ class WingProfile(Model):
def __post_init__(self):
super().__init__(name=self.name)
self.elbow_theta = math.radians(self.elbow_angle)
self.elbow_c = math.cos(self.elbow_theta)
self.elbow_s = math.sin(self.elbow_theta)
self.elbow_top_x, self.elbow_top_y = self.elbow_to_abs(0, self.elbow_height)
self.wrist_theta = math.radians(self.wrist_angle)
self.wrist_c = math.cos(self.wrist_theta)
self.wrist_s = math.sin(self.wrist_theta)
self.wrist_top_x, self.wrist_top_y = self.wrist_to_abs(0, self.wrist_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.shoulder_joint.angle_neutral = -self.shoulder_angle_neutral
@ -401,16 +391,6 @@ class WingProfile(Model):
"Axis", param=angle)
)
def elbow_to_abs(self, x: float, y: float) -> Tuple[float, float]:
elbow_x = self.elbow_x + x * self.elbow_c - y * self.elbow_s
elbow_y = self.elbow_y + x * self.elbow_s + y * self.elbow_c
return elbow_x, elbow_y
def wrist_to_abs(self, x: float, y: float) -> Tuple[float, float]:
wrist_x = self.wrist_x + x * self.wrist_c - y * self.wrist_s
wrist_y = self.wrist_y + x * self.wrist_s + y * self.wrist_c
return wrist_x, wrist_y
def _mask_elbow(self) -> list[Tuple[float, float]]:
"""
Polygon shape to mask out parts above the elbow
@ -459,12 +439,12 @@ class WingProfile(Model):
]
h = self.elbow_height / 2
tags_elbow = [
("elbow_bot", Cq.Location.from2d(
*self.elbow_to_abs(-self.elbow_joint.parent_arm_radius, h - self.elbow_h2),
self.elbow_angle + 0)),
("elbow_top", Cq.Location.from2d(
*self.elbow_to_abs(-self.elbow_joint.parent_arm_radius, h + self.elbow_h2),
self.elbow_angle + 0)),
("elbow_bot", self.elbow_bot_loc * Cq.Location.from2d(
-self.elbow_joint.parent_arm_radius,
h - self.elbow_h2)),
("elbow_top", self.elbow_bot_loc * Cq.Location.from2d(
-self.elbow_joint.parent_arm_radius,
h + self.elbow_h2)),
]
profile = self.profile_s1()
tags = tags_shoulder + tags_elbow
@ -527,21 +507,23 @@ class WingProfile(Model):
def surface_s2(self, front: bool = True) -> Cq.Workplane:
h = self.elbow_height / 2
tags_elbow = [
("elbow_bot", Cq.Location.from2d(
*self.elbow_to_abs(self.elbow_joint.child_arm_radius, h - self.elbow_h2),
self.elbow_angle + 180)),
("elbow_top", Cq.Location.from2d(
*self.elbow_to_abs(self.elbow_joint.child_arm_radius, h + self.elbow_h2),
self.elbow_angle + 180)),
("elbow_bot", self.elbow_bot_loc * Cq.Location.from2d(
self.elbow_joint.child_arm_radius,
h - self.elbow_h2,
180)),
("elbow_top", self.elbow_bot_loc * Cq.Location.from2d(
self.elbow_joint.child_arm_radius,
h + self.elbow_h2,
180)),
]
h = self.wrist_height / 2
tags_wrist = [
("wrist_bot", Cq.Location.from2d(
*self.wrist_to_abs(-self.wrist_joint.parent_arm_radius, h - self.wrist_h2),
self.wrist_angle)),
("wrist_top", Cq.Location.from2d(
*self.wrist_to_abs(-self.wrist_joint.parent_arm_radius, h + self.wrist_h2),
self.wrist_angle)),
("wrist_bot", self.wrist_bot_loc * Cq.Location.from2d(
-self.wrist_joint.parent_arm_radius,
h - self.wrist_h2)),
("wrist_top", self.wrist_bot_loc * Cq.Location.from2d(
-self.wrist_joint.parent_arm_radius,
h + self.wrist_h2)),
]
profile = self.profile_s2()
tags = tags_elbow + tags_wrist
@ -597,12 +579,14 @@ class WingProfile(Model):
front: bool = True) -> Cq.Workplane:
h = self.wrist_height / 2
tags = [
("wrist_bot", Cq.Location.from2d(
*self.wrist_to_abs(self.wrist_joint.child_arm_radius, h - self.wrist_h2),
self.wrist_angle + 180)),
("wrist_top", Cq.Location.from2d(
*self.wrist_to_abs(self.wrist_joint.child_arm_radius, h + self.wrist_h2),
self.wrist_angle + 180)),
("wrist_bot", self.wrist_bot_loc * Cq.Location.from2d(
self.wrist_joint.child_arm_radius,
h - self.wrist_h2,
180)),
("wrist_top", self.wrist_bot_loc * Cq.Location.from2d(
self.wrist_joint.child_arm_radius,
h + self.wrist_h2,
180)),
]
profile = self.profile_s3()
return extrude_with_markers(profile, self.panel_thickness, tags, reverse=front)
@ -726,45 +710,34 @@ class WingR(WingProfile):
Right side wings
"""
elbow_bot_loc: Cq.Location = Cq.Location.from2d(285.0, 5.0, 25.0)
elbow_height: float = 111.0
elbow_x: float = 285.0
elbow_y: float = 5.0
# Tilt of elbow w.r.t. shoulder
elbow_angle: float = 25.0
wrist_bot_loc: Cq.Location = Cq.Location.from2d(403.0, 253.0, 40.0)
wrist_height: float = 60.0
# Bottom point of the wrist
wrist_x: float = 403.0
wrist_y: float = 253.0
# Tile of wrist w.r.t. shoulder
wrist_angle: float = 40
# Extends from the wrist to the tip of the arrow
arrow_height: float = 300
arrow_angle: float = 8
arrow_angle: float = -8
# Relative (in wrist coordinate) centre of the ring
ring_x: float = 45
ring_y: float = 25
ring_radius_inner: float = 22
ring_rel_loc: Cq.Location = Cq.Location.from2d(45.0, 25.0)
ring_radius_inner: float = 22.0
def __post_init__(self):
super().__post_init__()
self.arrow_theta = math.radians(self.arrow_angle)
self.arrow_x, self.arrow_y = self.wrist_to_abs(0, -self.arrow_height)
self.arrow_tip_x = self.arrow_x + (self.arrow_height + self.wrist_height) \
* math.sin(self.arrow_theta - self.wrist_theta)
self.arrow_tip_y = self.arrow_y + (self.arrow_height + self.wrist_height) \
* math.cos(self.arrow_theta - self.wrist_theta)
# [[c, s], [-s, c]] * [ring_x, ring_y]
self.ring_abs_x = self.wrist_top_x + self.wrist_c * self.ring_x - self.wrist_s * self.ring_y
self.ring_abs_y = self.wrist_top_y + self.wrist_s * self.ring_x + self.wrist_c * self.ring_y
assert self.arrow_angle < 0, "Arrow angle cannot be positive"
self.arrow_bot_loc = self.wrist_bot_loc \
* Cq.Location.from2d(0, -self.arrow_height)
self.arrow_other_loc = self.arrow_bot_loc \
* Cq.Location.rot2d(self.arrow_angle) \
* Cq.Location.from2d(0, self.arrow_height + self.wrist_height)
self.ring_loc = self.wrist_top_loc * self.ring_rel_loc
assert self.ring_radius > self.ring_radius_inner
@property
def ring_radius(self) -> float:
dx = self.ring_x
dy = self.ring_y
(dx, dy), _ = self.ring_rel_loc.to2d()
return (dx * dx + dy * dy) ** 0.5
def profile(self) -> Cq.Sketch:
@ -779,8 +752,8 @@ class WingR(WingProfile):
tag="shoulder")
.spline([
(0, self.shoulder_joint.height),
(self.elbow_top_x, self.elbow_top_y),
(self.wrist_top_x, self.wrist_top_y),
self.elbow_top_loc.to2d_pos(),
self.wrist_top_loc.to2d_pos(),
],
tag="s1_top")
#.segment(
@ -789,31 +762,31 @@ class WingR(WingProfile):
# tag="wrist")
.spline([
(0, 0),
(self.elbow_x, self.elbow_y),
(self.wrist_x, self.wrist_y),
self.elbow_bot_loc.to2d_pos(),
self.wrist_bot_loc.to2d_pos(),
],
tag="s1_bot")
)
result = (
result
.segment(
(self.wrist_x, self.wrist_y),
(self.arrow_x, self.arrow_y)
self.wrist_bot_loc.to2d_pos(),
self.arrow_bot_loc.to2d_pos(),
)
.segment(
(self.arrow_x, self.arrow_y),
(self.arrow_tip_x, self.arrow_tip_y)
self.arrow_bot_loc.to2d_pos(),
self.arrow_other_loc.to2d_pos(),
)
.segment(
(self.arrow_tip_x, self.arrow_tip_y),
(self.wrist_top_x, self.wrist_top_y)
self.arrow_other_loc.to2d_pos(),
self.wrist_top_loc.to2d_pos(),
)
)
# Carve out the ring
result = result.assemble()
result = (
result
.push([(self.ring_abs_x, self.ring_abs_y)])
.push([self.ring_loc.to2d_pos()])
.circle(self.ring_radius, mode='a')
.circle(self.ring_radius_inner, mode='s')
.clean()
@ -822,38 +795,39 @@ class WingR(WingProfile):
def _mask_elbow(self) -> list[Tuple[float, float]]:
l = 200
elbow_x, _ = self.elbow_bot_loc.to2d_pos()
elbow_top_x, _ = self.elbow_top_loc.to2d_pos()
return [
(0, -l),
(self.elbow_x, -l),
(self.elbow_x, self.elbow_y),
(self.elbow_top_x, self.elbow_top_y),
(self.elbow_top_x, l),
(elbow_x, -l),
self.elbow_bot_loc.to2d_pos(),
self.elbow_top_loc.to2d_pos(),
(elbow_top_x, l),
(0, l)
]
def _mask_wrist(self) -> list[Tuple[float, float]]:
l = 200
wrist_x, _ = self.wrist_bot_loc.to2d_pos()
_, wrist_top_y = self.wrist_top_loc.to2d_pos()
return [
(0, -l),
(self.wrist_x, -l),
(self.wrist_x, self.wrist_y),
(self.wrist_top_x, self.wrist_top_y),
(wrist_x, -l),
self.wrist_bot_loc.to2d_pos(),
self.wrist_top_loc.to2d_pos(),
#(self.wrist_top_x, self.wrist_top_y),
(0, self.wrist_top_y),
(0, wrist_top_y),
]
@dataclass(kw_only=True)
class WingL(WingProfile):
elbow_x: float = 230.0
elbow_y: float = 110.0
elbow_angle: float = -10.0
elbow_bot_loc: Cq.Location = Cq.Location.from2d(230.0, 110.0, -10.0)
elbow_height: float = 80.0
wrist_x: float = 480.0
wrist_y: float = 0.0
wrist_angle: float = -45
wrist_angle: float = -45.0
wrist_bot_loc: Cq.Location = Cq.Location.from2d(480.0, 0.0, -45.0)
wrist_height: float = 43.0
shoulder_bezier_ext: float = 80.0
@ -866,11 +840,14 @@ class WingL(WingProfile):
flip: bool = True
def __post_init__(self):
super().__post_init__()
assert self.wrist_height <= self.shoulder_joint.height
self.wrist_bot_loc = self.wrist_bot_loc.with_angle_2d(self.wrist_angle)
super().__post_init__()
def arrow_to_abs(self, x, y) -> Tuple[float, float]:
return self.wrist_to_abs(x * self.arrow_length, y * self.arrow_height / 2 + self.wrist_height / 2)
rel = Cq.Location.from2d(x * self.arrow_length, y * self.arrow_height / 2 + self.wrist_height / 2)
return (self.wrist_bot_loc * rel).to2d_pos()
def profile(self) -> Cq.Sketch:
result = (
@ -879,39 +856,29 @@ class WingL(WingProfile):
(0,0),
(0, self.shoulder_height)
)
#.spline([
# (0, 0),
# self.elbow_to_abs(0, 0),
# self.wrist_to_abs(0, 0),
#])
#.spline([
# (0, self.shoulder_height),
# self.elbow_to_abs(0, self.elbow_height),
# self.wrist_to_abs(0, self.wrist_height),
#])
.bezier([
(0, 0),
(self.shoulder_bezier_ext, 0),
self.elbow_to_abs(-self.elbow_bezier_ext, 0),
self.elbow_to_abs(0, 0),
(self.elbow_bot_loc * Cq.Location.from2d(-self.elbow_bezier_ext, 0)).to2d_pos(),
self.elbow_bot_loc.to2d_pos(),
])
.bezier([
(0, self.shoulder_joint.height),
(self.shoulder_bezier_ext, self.shoulder_joint.height),
self.elbow_to_abs(-self.elbow_bezier_ext, self.elbow_height),
self.elbow_to_abs(0, self.elbow_height),
(self.elbow_top_loc * Cq.Location.from2d(-self.elbow_bezier_ext, 0)).to2d_pos(),
self.elbow_top_loc.to2d_pos(),
])
.bezier([
self.elbow_to_abs(0, 0),
self.elbow_to_abs(self.elbow_bezier_ext, 0),
self.wrist_to_abs(-self.wrist_bezier_ext, 0),
self.wrist_to_abs(0, 0),
self.elbow_bot_loc.to2d_pos(),
(self.elbow_bot_loc * Cq.Location.from2d(self.elbow_bezier_ext, 0)).to2d_pos(),
(self.wrist_bot_loc * Cq.Location.from2d(-self.wrist_bezier_ext, 0)).to2d_pos(),
self.wrist_bot_loc.to2d_pos(),
])
.bezier([
self.elbow_to_abs(0, self.elbow_height),
self.elbow_to_abs(self.elbow_bezier_ext, self.elbow_height),
self.wrist_to_abs(-self.wrist_bezier_ext, self.wrist_height),
self.wrist_to_abs(0, self.wrist_height),
self.elbow_top_loc.to2d_pos(),
(self.elbow_top_loc * Cq.Location.from2d(self.elbow_bezier_ext, 0)).to2d_pos(),
(self.wrist_top_loc * Cq.Location.from2d(-self.wrist_bezier_ext, 0)).to2d_pos(),
self.wrist_top_loc.to2d_pos(),
])
)
# arrow base positions
@ -919,13 +886,13 @@ class WingL(WingProfile):
result = (
result
.bezier([
self.wrist_to_abs(0, self.wrist_height),
self.wrist_to_abs(self.wrist_bezier_ext, self.wrist_height),
self.wrist_top_loc.to2d_pos(),
(self.wrist_top_loc * Cq.Location.from2d(self.wrist_bezier_ext, 0)).to2d_pos(),
self.arrow_to_abs(base_u, base_v),
])
.bezier([
self.wrist_to_abs(0, 0),
self.wrist_to_abs(self.wrist_bezier_ext, 0),
self.wrist_bot_loc.to2d_pos(),
(self.wrist_bot_loc * Cq.Location.from2d(self.wrist_bezier_ext, 0)).to2d_pos(),
self.arrow_to_abs(base_u, -base_v),
])
)
@ -954,22 +921,27 @@ class WingL(WingProfile):
def _mask_elbow(self) -> list[Tuple[float, float]]:
l = 200
elbow_bot_x, _ = self.elbow_bot_loc.to2d_pos()
elbow_top_x, _ = self.elbow_top_loc.to2d_pos()
return [
(0, -l),
(self.elbow_x, -l),
(self.elbow_x, self.elbow_y),
(self.elbow_top_x, self.elbow_top_y),
(self.elbow_top_x, l),
(elbow_bot_x, -l),
self.elbow_bot_loc.to2d_pos(),
self.elbow_top_loc.to2d_pos(),
(elbow_top_x, l),
(0, l)
]
def _mask_wrist(self) -> list[Tuple[float, float]]:
l = 200
elbow_bot_x, _ = self.elbow_bot_loc.to2d_pos()
_, elbow_top_y = self.elbow_top_loc.to2d_pos()
_, wrist_bot_y = self.wrist_bot_loc.to2d_pos()
return [
(0, -l),
(self.elbow_x, self.wrist_y),
(self.wrist_x, self.wrist_y),
(self.wrist_top_x, self.wrist_top_y),
(self.elbow_x, self.elbow_top_y + l),
(elbow_bot_x, wrist_bot_y),
self.wrist_bot_loc.to2d_pos(),
self.wrist_top_loc.to2d_pos(),
(elbow_bot_x, elbow_top_y + l),
(0, l),
]

View File

@ -43,6 +43,10 @@ def from2d(x: float, y: float, rotate: float=0.0) -> Cq.Location:
return Cq.Location((x, y, 0), (0, 0, 1), rotate)
Cq.Location.from2d = from2d
def rot2d(angle: float) -> Cq.Location:
return Cq.Location((0, 0, 0), (0, 0, 1), angle)
Cq.Location.rot2d = rot2d
def is2d(self: Cq.Location) -> bool:
(_, _, z), (rx, ry, _) = self.toTuple()
return z == 0 and rx == 0 and ry == 0
@ -59,6 +63,25 @@ def to2d(self: Cq.Location) -> Tuple[Tuple[float, float], float]:
return (x, y), rz
Cq.Location.to2d = to2d
def to2d_pos(self: Cq.Location) -> Tuple[float, float]:
"""
Returns position and angle
"""
(x, y, z), (rx, ry, _) = self.toTuple()
assert z == 0
assert rx == 0
assert ry == 0
return (x, y)
Cq.Location.to2d_pos = to2d_pos
def with_angle_2d(self: Cq.Location, angle: float) -> Tuple[float, float]:
"""
Returns position and angle
"""
x, y = self.to2d_pos()
return Cq.Location.from2d(x, y, angle)
Cq.Location.with_angle_2d = with_angle_2d
### Tags
def tagPoint(self, tag: str):