11from __future__ import annotations
22
3- from typing import TYPE_CHECKING , ClassVar
3+ from typing import TYPE_CHECKING
44import euklid
55import logging
6+ import pyfoil
67
78from openglider .airfoil import Profile3D
89from openglider .utils .dataclass import dataclass , Field
910from openglider .mesh import Mesh , triangulate
1011from openglider .vector .unit import Length , Percentage
12+ from openglider .glider .rib .crossports import polygon
1113
1214if TYPE_CHECKING :
1315 from openglider .glider .cell import Cell
@@ -26,9 +28,10 @@ class MiniRib:
2628 trailing_edge_cut : Length = Length ("20mm" )
2729 mrib_num : int = 0
2830 function : euklid .vector .Interpolation = Field (default_factory = lambda : euklid .vector .Interpolation ([]))
29- hole_num : int = 4
30- hole_border_side :float = 0.2
31- hole_border_front_back : float = 0.15
31+ hole_num : int = 0
32+ hole_border_side : Length | Percentage = Length ("2cm" )
33+ hole_border_panel : Length | Percentage = Length ("2cm" )
34+ hole_curve_factor : float = 0.5
3235
3336
3437 class Config :
@@ -63,11 +66,14 @@ def get_multiplier(self, x: float) -> float:
6366 else :
6467 return 1.
6568
66- def convert_to_percentage (self , value : Percentage | Length ) -> Percentage :
69+ def rib_chord (self , cell : Cell ) -> float :
70+ return cell .rib1 .chord * (1 - self .yvalue ) + cell .rib2 .chord * self .yvalue
71+
72+ def convert_to_percentage (self , value : Percentage | Length , cell : Cell ) -> Percentage :
6773 if isinstance (value , Percentage ):
6874 return value
6975
70- return Percentage (value .si / self .chord )
76+ return Percentage (value .si / self .rib_chord ( cell ) )
7177
7278 def get_offset_outline (self , cell :Cell , margin : Percentage | Length ) -> pyfoil .Airfoil :
7379 profile_3d = self .get_profile_3d (cell )
@@ -91,21 +97,11 @@ def get_profile_3d(self, cell: Cell) -> Profile3D:
9197
9298 return cell .rib_profiles_3d [self .mrib_num + 1 ]
9399
94-
95-
96- def convert_to_percentage (self , value : Percentage | Length , cell :Cell ) -> Percentage :
97- if isinstance (value , Percentage ):
98- return value
99- chord = cell .rib1 .chord * (1 - self .yvalue ) + cell .rib2 .chord * self .yvalue
100- return Percentage (value .si / chord )
101-
102100 def convert_to_chordlength (self , value : Percentage | Length , cell :Cell ) -> Length :
103101 if isinstance (value , Length ):
104102 return value
105103
106- chord = cell .rib1 .chord * (1 - self .yvalue ) + cell .rib2 .chord * self .yvalue
107-
108- return Length (value .si * chord )
104+ return Length (value .si * self .rib_chord (cell ))
109105
110106 def _get_lengths (self , cell : Cell ) -> tuple [float , float ]:
111107 flattened_cell = cell .get_flattened_cell ()
@@ -184,8 +180,6 @@ def get_mesh(self, cell:Cell, filled: bool=True, max_area: float=None, hole_res:
184180 vertices += hole_vertices
185181 boundary .append ([start_index + i for i in hole_indices ])
186182
187-
188-
189183 if not filled :
190184 segments = []
191185 for lst in boundary :
@@ -213,72 +207,70 @@ def get_mesh(self, cell:Cell, filled: bool=True, max_area: float=None, hole_res:
213207 return minirib_mesh
214208
215209
216- def get_holes (self , cell : Cell , points : int = 40 ) -> tuple [list [euklid .vector .PolyLine2D ], list [euklid .vector .Vector2D ]]:
217-
210+ def get_holes (self , cell : Cell , num_points : int = 140 ) -> tuple [list [euklid .vector .PolyLine2D ], list [euklid .vector .Vector2D ]]:
211+ if self .hole_num < 1 :
212+ return [], []
218213 nodes_top , nodes_bottom = self .get_nodes (cell )
219214
220- len_top = nodes_top .get_length ()
221- len_bot = nodes_bottom .get_length ()
215+ # add border on top / bottom
216+ offset = self .convert_to_chordlength (self .hole_border_panel , cell )
217+ top_curve = nodes_top .reverse ().offset (offset )
218+ bottom_curve = nodes_bottom .offset (- offset )
219+
220+ # check for intersection between offset lines
221+ try :
222+ cut = top_curve .cut (bottom_curve , len (top_curve .nodes )- 1 )
223+ top_curve = top_curve .get (0 , cut [0 ])
224+ bottom_curve = bottom_curve .get (0 , cut [1 ])
225+ except RuntimeError :
226+ pass
222227
223- def get_point ( x : float , y : float ) -> euklid . vector . Vector2D :
224- p1 = nodes_top . get ( nodes_top . walk ( 0 , len_top * x ) )
225- p2 = nodes_bottom . get ( nodes_bottom . walk ( 0 , len_bot * ( 1 - x )) )
228+ # helper functions to get points on minirib
229+ len_top = top_curve . get_length ( )
230+ len_bot = bottom_curve . get_length ( )
226231
227- return p1 + (p2 - p1 )* y
232+ def to_percentage (length : Length | Percentage ):
233+ if isinstance (length , Percentage ):
234+ return length
235+
236+ return Percentage (length .si / len_top )
237+
238+ def get_top (x : float ) -> euklid .vector .Vector2D :
239+ return top_curve .get (top_curve .walk (0 , len_top * x ))
228240
241+ def get_bottom (x : float ) -> euklid .vector .Vector2D :
242+ return bottom_curve .get (bottom_curve .walk (0 , len_bot * x ))
243+
229244 holes = []
230245 centers = []
246+
247+ end = self .back_cut if self .back_cut is not None else 1.
231248
232- if self .hole_num == 4 :
233- holes = [
234- euklid .spline .BSplineCurve ([
235- get_point (0.9 ,0.9 ),
236- get_point (0.85 ,0.9 ),
237- get_point (0.85 ,0.1 ),
238- get_point (0.95 ,0.1 ),
239- get_point (0.95 ,0.9 ),
240- get_point (0.9 ,0.9 ),
241- ]).get_sequence (points ),
242-
243- euklid .spline .BSplineCurve ([
244- get_point (0.75 ,0.9 ),
245- get_point (0.7 ,0.9 ),
246- get_point (0.7 ,0.1 ),
247- get_point (0.8 ,0.1 ),
248- get_point (0.8 ,0.9 ),
249- get_point (0.75 ,0.9 ),
250- ]).get_sequence (points ),
251-
252- euklid .spline .BSplineCurve ([
253- get_point (0.625 ,0.9 ),
254- get_point (0.575 ,0.9 ),
255- get_point (0.575 ,0.1 ),
256- get_point (0.65 ,0.1 ),
257- get_point (0.65 ,0.9 ),
258- get_point (0.625 ,0.9 ),
259- ]).get_sequence (points ),
260-
261- euklid .spline .BSplineCurve ([
262- get_point (0.5 ,0.9 ),
263- get_point (0.475 ,0.9 ),
264- get_point (0.475 ,0.1 ),
265- get_point (0.525 ,0.1 ),
266- get_point (0.525 ,0.9 ),
267- get_point (0.5 ,0.9 ),
268- ]).get_sequence (points ),
269-
270-
271-
249+ if self .trailing_edge_cut is not None :
250+ end -= to_percentage (self .trailing_edge_cut ).si
272251
273- ]
252+ border_holes = to_percentage ( self . hole_border_side ). si
274253
275- centers = [
254+ total_border = (self .hole_num + 1 ) * border_holes
255+ hole_width = (1 - total_border ) / self .hole_num
276256
277- get_point (0.9 , 0.5 ),
278- get_point (0.75 , 0.5 ),
279- get_point (0.625 , 0.5 ),
280- get_point (0.5 , 0.5 ),
257+ x_left = border_holes
258+
259+ # draw holes
260+ for _ in range (self .hole_num ):
261+ x_right = x_left + hole_width
262+ x_center = (x_left + x_right )/ 2
263+
264+ points = [
265+ get_bottom (x_left ),
266+ get_bottom (x_right ),
267+ get_top (x_right ),
268+ get_top (x_left )
281269 ]
282270
283- return holes , centers
271+ holes .append (polygon (points , self .hole_curve_factor , num_points ))
272+ centers .append ((get_top (x_center ) + get_bottom (x_center ))* 0.5 )
284273
274+ x_left = x_right + border_holes
275+
276+ return holes , centers
0 commit comments