Skip to content

Commit 2e13621

Browse files
committed
update rigidfoils
1 parent 6dc5dcd commit 2e13621

File tree

5 files changed

+134
-95
lines changed

5 files changed

+134
-95
lines changed

openglider/glider/rib/rib.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,18 @@ def get_offset_outline(self, margin: Percentage | Length) -> pyfoil.Airfoil:
262262

263263
def get_rigidfoils(self) -> list[RigidFoilBase]:
264264
if self.sharknose is not None:
265-
rigidfoils = self.sharknose.update_rigidfoils(self)
266-
for rigid_no, rigid in enumerate(rigidfoils):
265+
result: list[RigidFoilBase] = []
266+
267+
for rigidfoil in self.rigidfoils:
268+
rigidfoils_this = self.sharknose.update_rigidfoil(self, rigidfoil)
269+
if rigidfoils_this is not None:
270+
result += rigidfoils_this
271+
else:
272+
result.append(rigidfoil)
273+
for rigid_no, rigid in enumerate(result):
267274
rigid.name = self.rigid_naming_scheme.format(rigid_no, rib=self)
268275

269-
return rigidfoils
276+
return result
270277

271278
return self.rigidfoils
272279

openglider/glider/rib/rigidfoils.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,24 @@ class RigidFoilBase(ABC, BaseModel):
2626

2727
cap_length: Length = Length("2cm")
2828
tension: Percentage = Percentage("98%")
29+
material: str = "Plastic"
30+
diameter: Length = Length("2mm")
2931

3032
def get_3d(self, rib: Rib) -> euklid.vector.PolyLine3D:
31-
return euklid.vector.PolyLine3D([rib.align(p, scale=False) for p in self.get_flattened(rib)])
33+
return euklid.vector.PolyLine3D([rib.align(p, scale=False) for p in self.get_center_line(rib)])
3234

3335
def get_length(self, rib: Rib) -> float:
34-
return self.get_flattened(rib).get_length() * self.tension.si
36+
return self.get_center_line(rib).get_length() * self.tension.si
3537

36-
def get_flattened(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
37-
return self._get_flattened(rib, glider).fix_errors()
38+
def get_flattened(self, center_line: euklid.vector.PolyLine2D) -> euklid.vector.PolyLine2D:
39+
outer_line = center_line.offset(self.diameter.si/2).fix_errors()
40+
inner_line = center_line.offset(-self.diameter.si/2).fix_errors()
41+
42+
outline = euklid.vector.PolyLine2D(outer_line.nodes + inner_line.nodes[::-1]).close()
43+
44+
return outline
3845

39-
def _get_flattened(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
46+
def get_center_line(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
4047
raise NotImplementedError()
4148

4249
def get_cap_radius(self, start: bool) -> tuple[Length, Percentage]:
@@ -62,7 +69,7 @@ def func(self, pos: float, radius: Percentage) -> float:
6269
def get_cap_radius(self, start: bool) -> tuple[Length, Percentage]:
6370
return -self.circle_radius, Percentage(0.35)
6471

65-
def _get_flattened(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
72+
def get_center_line(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
6673
max_segment = 0.005 # 5mm
6774
profile = rib.get_hull()
6875
profile_normvectors = profile.normvectors
@@ -90,7 +97,7 @@ def _get_flattened(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLin
9097
indices = [profile(x) for x in point_range]
9198

9299
# convert to unitless percentage (everything is scaled later)
93-
distance = rib.convert_to_percentage(self.distance)
100+
distance = rib.convert_to_percentage(self.distance) + rib.convert_to_percentage(self.diameter/2)
94101
radius = rib.convert_to_percentage(self.circle_radius)
95102

96103
nodes = [
@@ -105,13 +112,13 @@ class _RigidFoilCurved(RigidFoilBase):
105112
append_curve: bool = True
106113
straight_part: Length = Length(0)
107114

108-
def _get_flattened(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
115+
def get_center_line(self, rib: Rib, glider: Glider=None) -> euklid.vector.PolyLine2D:
109116
profile = rib.get_hull()
110117

111118
start = profile.get_ik(self.start.si)
112119
end = profile.get_ik(self.end.si)
113120

114-
distance = rib.convert_to_chordlength(self.distance)
121+
distance = rib.convert_to_chordlength(self.distance) + self.diameter/2
115122

116123
rigidfoil_curve = (profile.curve.get(start, end) * rib.chord).offset(-distance.si).fix_errors()
117124
inner_curve = rigidfoil_curve

openglider/glider/rib/sharknose.py

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -88,51 +88,46 @@ def get_tangent(ik: float, from_point: euklid.vector.Vector2D, to_point: euklid.
8888

8989
return openglider.airfoil.Profile2D(data)
9090

91-
def update_rigidfoils(self, rib: Rib) -> list[RigidFoilBase]:
92-
result: list[RigidFoilBase] = []
93-
94-
nearest_position = round(rib.profile_2d.get_ik(self.position))
95-
position = Percentage(rib.profile_2d.curve.get(nearest_position)[0])
96-
97-
for rigidfoil in rib.rigidfoils:
98-
if rigidfoil.start < position and rigidfoil.end > position:
99-
# split rigidfoil
100-
rigid_1 = RigidFoilCurved(
101-
start=rigidfoil.start,
102-
end=position,
103-
distance=rigidfoil.distance,
104-
cap_length=rigidfoil.cap_length,
105-
tension=rigidfoil.tension,
106-
inner_allowance=rigidfoil.inner_allowance
107-
)
108-
if straight_part := getattr(rigidfoil, "straight_part"):
109-
rigid_1.straight_part = straight_part
110-
111-
radius, amount = rigidfoil.get_cap_radius(start=True)
112-
rigid_1.circle_radius_start = radius
113-
rigid_1.circle_amount_start = amount
114-
rigid_1.circle_radius_end = self.rigidfoil_circle_radius
115-
rigid_1.circle_amount_end = self.rigidfoil_circle_amount
116-
117-
rigid_2 = RigidFoilCurved(
118-
start=position,
119-
end=rigidfoil.end,
120-
distance=rigidfoil.distance,
121-
cap_length=rigidfoil.cap_length,
122-
tension=rigidfoil.tension,
123-
inner_allowance=rigidfoil.inner_allowance
124-
)
125-
if straight_part := getattr(rigidfoil, "straight_part"):
126-
rigid_2.straight_part = straight_part
127-
128-
radius, amount = rigidfoil.get_cap_radius(start=False)
129-
rigid_2.circle_radius_end = radius
130-
rigid_2.circle_amount_end = amount
131-
rigid_2.circle_radius_start = self.rigidfoil_circle_radius
132-
rigid_2.circle_amount_start = self.rigidfoil_circle_amount
133-
134-
result += [rigid_1, rigid_2]
135-
else:
136-
result.append(rigidfoil)
137-
138-
return result
91+
def update_rigidfoil(self, rib: Rib, rigidfoil: RigidFoilBase) -> tuple[RigidFoilCurved, RigidFoilCurved] | None:
92+
if rigidfoil.start < self.position and rigidfoil.end > self.position:
93+
nearest_position = round(rib.profile_2d.get_ik(self.position))
94+
position = Percentage(rib.profile_2d.curve.get(nearest_position)[0])
95+
96+
# split rigidfoil
97+
rigid_1 = RigidFoilCurved(
98+
start=rigidfoil.start,
99+
end=position,
100+
distance=rigidfoil.distance,
101+
cap_length=rigidfoil.cap_length,
102+
tension=rigidfoil.tension,
103+
inner_allowance=rigidfoil.inner_allowance
104+
)
105+
if straight_part := getattr(rigidfoil, "straight_part", None):
106+
rigid_1.straight_part = straight_part
107+
108+
radius, amount = rigidfoil.get_cap_radius(start=True)
109+
rigid_1.circle_radius_start = radius
110+
rigid_1.circle_amount_start = amount
111+
rigid_1.circle_radius_end = self.rigidfoil_circle_radius
112+
rigid_1.circle_amount_end = self.rigidfoil_circle_amount
113+
114+
rigid_2 = RigidFoilCurved(
115+
start=position,
116+
end=rigidfoil.end,
117+
distance=rigidfoil.distance,
118+
cap_length=rigidfoil.cap_length,
119+
tension=rigidfoil.tension,
120+
inner_allowance=rigidfoil.inner_allowance
121+
)
122+
if straight_part:
123+
rigid_2.straight_part = straight_part
124+
125+
radius, amount = rigidfoil.get_cap_radius(start=False)
126+
rigid_2.circle_radius_end = radius
127+
rigid_2.circle_amount_end = amount
128+
rigid_2.circle_radius_start = self.rigidfoil_circle_radius
129+
rigid_2.circle_amount_start = self.rigidfoil_circle_amount
130+
131+
return (rigid_1, rigid_2)
132+
133+
return None

openglider/materials/cloth.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ porcher,skytex_32,32,petrol_blue,#01567D
88
porcher,skytex_32,32,deep_blue,#243882
99
porcher,skytex_32,32,lime_green_500,#96C11E
1010
porcher,skytex_32,32,lime_green_530,#BCB21F
11+
porcher,skytex_32,32,green,#00945E
1112
porcher,skytex_32,32,green_551,#9BBB59
1213
porcher,skytex_32,32,dragon_red,#E62E39
1314
porcher,skytex_32,32,sangria,#AE2760

openglider/plots/glider/ribs.py

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import math
4-
from typing import TYPE_CHECKING
4+
from typing import TYPE_CHECKING, Literal
55
from collections.abc import Callable
66

77
import euklid
@@ -33,80 +33,109 @@ class RigidFoilPlot:
3333
rigidfoil: RigidFoilBase
3434
ribplot: RibPlot
3535

36+
drawing: PlotPart
3637
inner_curve: euklid.vector.PolyLine2D | None = None
3738
outer_curve: euklid.vector.PolyLine2D | None = None
39+
center_curve: euklid.vector.PolyLine2D | None = None
3840

3941
def __init__(self, rigidfoil: RigidFoilBase, ribplot: RibPlot) -> None:
4042
self.rigidfoil = rigidfoil
4143
self.ribplot = ribplot
44+
self.drawing = PlotPart()
4245

43-
def add_text(self, plotpart: PlotPart) -> None:
44-
(_, p1), (_, p2) = self.get_cap(-1, True)
46+
def add_text(self) -> None:
47+
(_, p1), (_, p2) = self.get_cap("back")
4548

46-
plotpart.layers[self.ribplot.layer_name_text] += Text(
49+
self.drawing.layers[self.ribplot.layer_name_text] += Text(
4750
self.rigidfoil.name, p1, p2, align="center", valign=0.6
4851
).get_vectors()
4952

50-
def get_cap(self, position: int, rear: bool) -> tuple[tuple[Vector2D, Vector2D], tuple[Vector2D, Vector2D]]:
51-
assert self.inner_curve is not None and self.outer_curve is not None
53+
def get_cap(self, side: Literal["front", "back"], outer_distance: float | None = None) -> tuple[tuple[Vector2D, Vector2D], tuple[Vector2D, Vector2D]]:
54+
if side == "front":
55+
position = 0
56+
angle = math.pi/2
57+
elif side == "back":
58+
position = -1
59+
angle = -math.pi/2
60+
else:
61+
raise ValueError("side must be 'front' or 'back'")
62+
63+
if self.center_curve is None:
64+
raise ValueError("Setup not called")
65+
66+
if outer_distance is None:
67+
outer_distance = self.get_outer_distance().si
68+
inner_distance = self.get_inner_distance().si
5269

70+
center_point = self.center_curve.nodes[position]
71+
normal = self.center_curve.normvectors().nodes[position]
72+
73+
outer_point = center_point + normal * outer_distance
74+
inner_point = center_point - normal * inner_distance
5375
# back cap
54-
p1 = self.inner_curve.nodes[position]
55-
p2 = self.outer_curve.nodes[position]
56-
angle = math.pi/2
57-
if rear:
58-
angle = -angle
59-
diff = euklid.vector.Rotation2D(angle).apply(p1-p2).normalized() * self.rigidfoil.cap_length.si
76+
diff = euklid.vector.Rotation2D(angle).apply(inner_point - outer_point).normalized() * self.rigidfoil.cap_length.si
6077

6178
return (
62-
(p1, p2),
63-
(p1+diff, p2+diff)
79+
(inner_point, outer_point),
80+
(inner_point+diff, outer_point+diff)
6481
)
6582

66-
def _get_inner_outer(self, glider: Glider) -> tuple[euklid.vector.PolyLine2D, euklid.vector.PolyLine2D]:
67-
curve = self.rigidfoil.get_flattened(self.ribplot.rib, glider)
68-
83+
def get_outer_distance(self) -> Length:
6984
distance = self.ribplot.rib.convert_to_chordlength(self.rigidfoil.distance)
70-
d_outer = self.ribplot.rib.seam_allowance.si + distance.si
71-
85+
return self.ribplot.rib.seam_allowance + distance + self.rigidfoil.diameter/2
86+
87+
def get_inner_distance(self) -> Length:
7288
if self.rigidfoil.inner_allowance:
7389
allowance = self.rigidfoil.inner_allowance
7490
else:
7591
allowance = self.ribplot.rib.seam_allowance
7692

77-
inner_curve = curve.offset(-(distance+allowance).si).fix_errors()
78-
outer_curve = curve.offset(d_outer).fix_errors()
93+
return (self.rigidfoil.diameter/2+allowance)
94+
95+
def setup(self, glider: Glider) -> tuple[euklid.vector.PolyLine2D, euklid.vector.PolyLine2D, euklid.vector.PolyLine2D]:
96+
if any([x is None for x in [self.inner_curve, self.outer_curve, self.center_curve]]):
97+
curve = self.rigidfoil.get_center_line(self.ribplot.rib, glider)
98+
99+
d_outer = self.get_outer_distance()
100+
d_inner = self.get_inner_distance()
79101

80-
return inner_curve, outer_curve
102+
103+
self.center_curve = curve
104+
self.inner_curve = curve.offset(-d_inner.si)
105+
self.outer_curve = curve.offset(d_outer.si)
106+
107+
return self.center_curve, self.inner_curve, self.outer_curve # type: ignore
108+
109+
def insert_mark(self) -> None:
110+
assert self.center_curve is not None
111+
112+
rigidfoil_outline = self.rigidfoil.get_flattened(self.center_curve)
113+
114+
self.drawing.layers[self.ribplot.layer_name_marks].append(rigidfoil_outline)
115+
self.ribplot.plotpart.layers[self.ribplot.layer_name_rigidfoils].append(rigidfoil_outline)
81116

82117
def flatten(self, glider: Glider) -> PlotPart:
83-
plotpart = PlotPart()
118+
curve, inner_curve, outer_curve = self.setup(glider)
119+
plotpart = self.drawing
84120

85121
controlpoints: list[tuple[float, list[euklid.vector.PolyLine2D]]] = []
86122
for x in self.ribplot.config.get_controlpoints(self.ribplot.rib):
87123
for mark in self.ribplot.insert_mark(x, self.ribplot.config.marks_controlpoint, insert=False):
88124
controlpoints.append((x, mark))
89125

90-
curve = self.rigidfoil.get_flattened(self.ribplot.rib, glider)
91-
92126
# add marks into the profile
93-
self.ribplot.plotpart.layers[self.ribplot.layer_name_rigidfoils].append(curve)
94127
self.ribplot.plotpart.layers[self.ribplot.layer_name_laser_dots].append(euklid.vector.PolyLine2D([curve.get(0)]))
95128
self.ribplot.plotpart.layers[self.ribplot.layer_name_laser_dots].append(euklid.vector.PolyLine2D([curve.get(len(curve)-1)]))
96129

97-
self.inner_curve, self.outer_curve = self._get_inner_outer(glider)
98-
99-
plotpart.layers[self.ribplot.layer_name_marks].append(curve)
100-
101-
back_cap = self.get_cap(-1, True)
130+
back_cap = self.get_cap("back")
102131
plotpart.layers[self.ribplot.layer_name_marks].append(euklid.vector.PolyLine2D(list(back_cap[0])))
103132

104-
front_cap = self.get_cap(0, False)
133+
front_cap = self.get_cap("front")
105134
plotpart.layers[self.ribplot.layer_name_marks].append(euklid.vector.PolyLine2D(list(front_cap[0])))
106135

107-
outline = self.inner_curve
136+
outline = inner_curve
108137
outline += euklid.vector.PolyLine2D(list(back_cap[1]))
109-
outline += self.outer_curve.reverse()
138+
outline += outer_curve.reverse()
110139
outline += euklid.vector.PolyLine2D(list(front_cap[1])).reverse()
111140

112141
for x, controlpoint in controlpoints:
@@ -117,7 +146,7 @@ def flatten(self, glider: Glider) -> PlotPart:
117146

118147
plotpart.layers[self.ribplot.layer_name_outline].append(outline.fix_errors().close())
119148

120-
self.add_text(plotpart)
149+
self.add_text()
121150

122151
return plotpart
123152

0 commit comments

Comments
 (0)