engeom 0.2.4__cp38-abi3-win_amd64.whl → 0.2.6__cp38-abi3-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
engeom/airfoil.pyi CHANGED
@@ -1,45 +1,67 @@
1
1
  from typing import List
2
2
 
3
- import numpy
3
+ from numpy.typing import NDArray
4
4
  from enum import Enum
5
-
6
- from .geom2 import Circle2, Curve2, Point2, SurfacePoint2, Arc2
7
- from .metrology import Length2
5
+ import geom2
8
6
 
9
7
  type MclOrientEnum = MclOrient.TmaxFwd | MclOrient.DirFwd
10
8
  type FaceOrientEnum = FaceOrient.Detect | FaceOrient.UpperDir
11
9
  type EdgeFindEnum = EdgeFind.Open | EdgeFind.OpenIntersect | EdgeFind.Intersect | EdgeFind.RansacRadius
12
- type EdgeTypeEnum = EdgeType | Arc2
13
10
  type AfGageEnum = AfGage.OnCamber | AfGage.Radius
14
11
 
12
+
15
13
  class EdgeType(Enum):
16
- Open=0
17
- Closed=1
14
+ """
15
+ An enumeration of the possible non-geometric types of edges that can be detected on an airfoil cross-section as the
16
+ result of an edge finding operation. When one of these types is returned, it means that the edge finding algorithm
17
+ could not provide more detailed geometric information about the edge.
18
+ """
19
+
20
+ Open = 0
21
+ """ Represents an open edge, where the airfoil cross-section is incomplete and/or not closed. """
22
+
23
+ Closed = 1
24
+ """ Represents an edge that is closed, where the airfoil cross-section has contiguous vertices through the edge. """
25
+
18
26
 
19
27
  class AfGage:
20
28
  """
21
- A class representing a measurement for locating a position on an airfoil cross-section.
29
+ An enumeration class used to specify a method for locating a gage points on an airfoil cross-section.
22
30
  """
31
+
23
32
  class OnCamber:
33
+ """
34
+ A gaging method that measures a distance along the mean camber line. A positive distance will be from the
35
+ leading edge towards the trailing edge, and a negative distance will be from the trailing edge towards the
36
+ leading edge.
37
+ """
38
+
24
39
  def __init__(self, d: float):
25
40
  """
26
- A gaging method that measures a distance along the mean camber line. A positive distance will be from the
27
- leading edge towards the trailing edge, and a negative distance will be from the trailing edge towards the
28
- leading edge.
41
+ Create a specification for a gage point that is a distance `d` along the mean camber line. A positive
42
+ distance will be from the leading edge towards the trailing edge, and a negative distance will be from the
43
+ trailing edge towards the leading edge.
29
44
  :param d: the distance along the mean camber line to find the position
30
45
  """
31
46
  ...
32
47
 
33
48
  class Radius:
49
+ """
50
+ A gaging method that measures by intersection with a circle of a given radius centered on either the
51
+ leading or trailing edge point. A positive radius indicates that the circle is located on the leading edge
52
+ while a negative radius indicates that the circle is located on the trailing edge.
53
+ """
54
+
34
55
  def __init__(self, r: float):
35
56
  """
36
- A gaging method that measures by intersection with a circle of a given radius centered on either the
37
- leading or trailing edge point. A positive radius indicates that the circle is located on the leading edge
38
- while a negative radius indicates that the circle is located on the trailing edge.
57
+ Create a specification for a gage point that is located at the intersection of a circle of radius `r` with
58
+ the airfoil cross-section. A positive radius indicates that the circle is located on the leading edge while
59
+ a negative radius indicates that the circle is located on the trailing edge.
39
60
  :param r: the radius of the circle to find the position
40
61
  """
41
62
  ...
42
63
 
64
+
43
65
  class FaceOrient:
44
66
  """
45
67
  An enumeration of the possible ways to orient the upper/lower (suction/pressure, convex/concave) faces of an
@@ -51,7 +73,13 @@ class FaceOrient:
51
73
  In an airfoil with an MCL that exhibits curvature, this will attempt to detect which direction the camber line
52
74
  curves and thus identify convex/concave. This will fail if the MCL is straight.
53
75
  """
54
- ...
76
+
77
+ def __init__(self):
78
+ """
79
+ Create a new face orientation parameter that will attempt to detect the orientation of the faces based on
80
+ the curvature of the mean camber line.
81
+ """
82
+ ...
55
83
 
56
84
  class UpperDir:
57
85
  """
@@ -83,7 +111,14 @@ class MclOrient:
83
111
  This method will take advantage of the fact that for most typical subsonic airfoils the maximum thickness point
84
112
  is closer to the leading edge than the trailing edge.
85
113
  """
86
- ...
114
+
115
+ def __init__(self):
116
+ """
117
+ Create a specification for orienting the mean camber line based on which side the maximum thickness point is
118
+ closer to. This method will assume that the maximum thickness point is closer to the leading edge than the
119
+ trailing edge.
120
+ """
121
+ ...
87
122
 
88
123
  class DirFwd:
89
124
  """
@@ -116,9 +151,25 @@ class EdgeFind:
116
151
  as they are. Use this if you know that the airfoil cross-section is open/incomplete on this side, and you don't
117
152
  care to extend the MCL any further.
118
153
  """
119
- ...
154
+
155
+ def __init__(self):
156
+ """
157
+ Create a specification which assumes that the airfoil cross-section is open/incomplete on this side, and
158
+ makes no attempt to find the edge geometry beyond the unambiguous inscribed circles.
159
+ """
160
+ ...
120
161
 
121
162
  class OpenIntersect:
163
+ """
164
+ This algorithm is also for an open edge, but unlike `Open` it will attempt to refine the end of the MCL and
165
+ extend it to intersect the line segment which spans the open gap where the edge should be. This is useful on
166
+ partial cross-sections where you would still like to extend the MCL as much as possible.
167
+
168
+ It works by intersecting the end of the inscribed circles camber curve with the open gap in the airfoil
169
+ cross-section, filling and refining more inscribed circles between the last circle and the intersection point,
170
+ and repeating until the location of the end converges to within 1/100th of the general refinement tolerance.
171
+ """
172
+
122
173
  def __init__(self, max_iter: int):
123
174
  """
124
175
  This algorithm will attempt to find the edge geometry by intersecting the end of the inscribed circles
@@ -137,21 +188,37 @@ class EdgeFind:
137
188
  This algorithm will simply intersect the end of the inscribed circles camber curve with the airfoil
138
189
  cross-section. This is the fastest method with the least amount of assumptions, and makes sense for airfoil
139
190
  edges where you know the mean camber line has very low curvature in the vicinity of the edge.
191
+
192
+ Do not use this method if you know that the airfoil cross-section is open/incomplete on this side, as it will
193
+ throw an error if the MCL does not intersect the cross-section.
140
194
  """
141
- ...
142
195
 
143
- class RansacRadius:
144
- def __init__(self, in_tol: float, n: int = 500):
196
+ def __init__(self):
145
197
  """
146
- This algorithm uses RANSAC (Random Sample Consensus) to find a constant radius leading edge circle that
147
- fits the greatest number of points leftover at the edge within the tolerance `in_tol`.
198
+ Create a specification which will attempt to find the edge geometry by intersecting the end of the inscribed
199
+ circles camber curve with the airfoil cross-section. Use on known closed airfoil cross-sections with low
200
+ curvature near the edge.
201
+ """
202
+ ...
148
203
 
149
- The method will try `n` different combinations of three points picked at random from the remaining points
150
- at the edge, construct a circle, and then count the number of points within `in_tol` distance of the circle
151
- perimeter. The circle with the most points within tolerance will be considered the last inscribed circle.
204
+ class RansacRadius:
205
+ """
206
+ This technique uses RANSAC (Random Sample Consensus) to find a constant radius leading/trailing edge circle
207
+ that fits the greatest number of points leftover at the edge within the tolerance `in_tol`.
208
+
209
+ The method will try `n` different combinations of three points picked at random from the remaining points
210
+ at the edge, construct a circle, and then count the number of points within `in_tol` distance of the circle
211
+ perimeter. The circle with the most points within tolerance will be considered the last inscribed circle.
212
+
213
+ The MCL will be extended to this final circle, and then intersected with the airfoil cross-section to find
214
+ the final edge point.
215
+ """
152
216
 
153
- The MCL will be extended to this final circle, and then intersected with the airfoil cross-section to find
154
- the final edge point.
217
+ def __init__(self, in_tol: float, n: int = 500):
218
+ """
219
+ Create a specification which will attempt to find the edge geometry by Random Sample Consensus of a constant
220
+ radius at the edge of the airfoil cross-section. This is useful for airfoils known to have a constant radius
221
+ edge and on section data which is relatively clean and has low noise.
155
222
 
156
223
  :param in_tol: the max distance from the circle perimeter for a point to be considered a RANSAC inlier
157
224
  :param n: The number of RANSAC iterations to perform
@@ -160,50 +227,94 @@ class EdgeFind:
160
227
 
161
228
 
162
229
  class InscribedCircle:
230
+ """
231
+ Represents an inscribed circle in an airfoil cross-section. The circle is contained within the airfoil cross-section
232
+ and is tangent to the airfoil section at two points.
233
+ """
234
+
235
+ from .geom2 import Circle2, Point2
236
+
163
237
  @property
164
- def circle(self) -> Circle2: ...
238
+ def circle(self) -> Circle2:
239
+ """
240
+ Gets the circle object associated with this inscribed circle.
241
+ :return: The circle entity for the inscribed circle
242
+ """
243
+ ...
165
244
 
166
245
  @property
167
246
  def contact_a(self) -> Point2:
168
247
  """
169
- A contact point of the inscribed circle with one side of the airfoil cross-section. Inscribed circles computed
170
- together will have a consistent meaning of `a` and `b` sides, but which is the upper or lower surface will
171
- depend on the ordering of the circles and the coordinate system of the airfoil.
248
+ Get a contact point of the inscribed circle with one side of the airfoil cross-section. Inscribed circles
249
+ computed together will have a consistent meaning of `a` and `b` sides, but which is the upper or lower surface
250
+ will depend on the ordering of the circles and the coordinate system of the airfoil.
251
+
252
+ :return: The first contact point of the inscribed circle with the airfoil cross-section
172
253
  """
173
254
  ...
174
255
 
175
256
  @property
176
257
  def contact_b(self) -> Point2:
177
258
  """
178
- The other contact point of the inscribed circle with the airfoil cross-section. Inscribed circles computed
259
+ Get the other contact point of the inscribed circle with the airfoil cross-section. Inscribed circles computed
179
260
  together will have a consistent meaning of `a` and `b` sides, but which is the upper or lower surface will
180
261
  depend on the ordering of the circles and the coordinate system of the airfoil.
262
+
263
+ :return: The second contact point of the inscribed circle with the airfoil cross-section
181
264
  """
182
265
  ...
183
266
 
184
267
 
185
268
  class EdgeResult:
186
269
  """
187
- Represents the results of an edge detection algorithm
270
+ Represents the results of an airfoil edge detection operation, containing both a point on the airfoil cross-section
271
+ that was detected as the edge, and optional geometric information about the edge depending on the method used.
188
272
  """
273
+ from .geom2 import Arc2, Point2
189
274
 
190
275
  @property
191
276
  def point(self) -> Point2:
192
277
  """
193
- The point on the airfoil cross-section that was detected as the edge.
278
+ Gets the point on the airfoil cross-section that was detected as the edge.
279
+ :return: The point on the airfoil cross-section that was detected as the edge
194
280
  """
195
281
  ...
196
282
 
197
283
  @property
198
- def geometry(self):
284
+ def geometry(self) -> EdgeType | Arc2:
285
+ """
286
+ Gets the geometric information about the edge that was detected.
287
+
288
+ * This will be an instance of `EdgeType` if the algorithm could not provide more detailed geometric information
289
+ about the edge beyond open/closed.
290
+
291
+ * This will be an instance of `Arc2` in the case of constant radius edge detection.
292
+
293
+ :return: The geometric information about the edge that was detected
294
+ """
199
295
  ...
200
296
 
201
297
 
202
298
  class AirfoilGeometry:
203
299
  """
204
- The result of an airfoil geometry computation.
300
+ This class produces and contains the result of the geometric analysis of an airfoil cross-section. It contains:
301
+
302
+ 1. The mean camber line
303
+
304
+ 2. The segregated geometry of the upper (suction, convex) and lower (pressure, concave) faces
305
+
306
+ 3. The detected position and geometry of the leading and trailing edges
307
+
308
+ 4. The array of inscribed circles identified during the analysis
309
+
310
+ From this information, thicknesses and other measurements can be made on the airfoil.
311
+
312
+ See the `from_analyze` method for how to perform the analysis creating an instance of this class.
205
313
  """
206
314
 
315
+ from .geom2 import Curve2, Circle2
316
+ from .metrology import Distance2
317
+
207
318
  @staticmethod
208
319
  def from_analyze(
209
320
  section: Curve2,
@@ -213,28 +324,65 @@ class AirfoilGeometry:
213
324
  trailing: EdgeFindEnum,
214
325
  face_orient: FaceOrientEnum,
215
326
  ) -> AirfoilGeometry:
327
+ """
328
+ This method attempts to extract the airfoil geometry from the given airfoil cross-section using only the
329
+ geometric information embedded in the section. It is suitable for airfoil cross-sections with clean, low-noise
330
+ or noise-free data, such as those which come from nominal CAD data or from very clean scans/samples of airfoils
331
+ with smooth, continuous surfaces with little to no defects.
332
+
333
+ The cross-section data must also be *only* the outer surface of the airfoil, with no internal features or
334
+ points. The vertices should be ordered in a counter-clockwise direction, but the section may be open on one
335
+ side and no particular orientation or position in the XY plane is required.
336
+
337
+ Internally, this operation will attempt to:
338
+
339
+ 1. Extract the unambiguous inscribed circles from the cross-section using an iterative stepping/refinement
340
+ method (see `compute_inscribed_circles` for more detail).
341
+
342
+ 2. Orient the mean camber line (determine which side is the leading edge and which side is the trailing edge)
343
+ based on the method specified in `camber_orient`.
344
+
345
+ 3. Extract the exact position (and optionally, the geometry) of the leading and trailing edges based on the
346
+ methods specified in `leading` and `trailing`, respectively.
347
+
348
+ 4. Identify and extract the upper (suction, convex) and lower (pressure, concave) faces of the airfoil based on
349
+ the method specified in `face_orient`.
350
+
351
+ If successful in all of these steps, the method will return an instance of `AirfoilGeometry` containing the
352
+ results of the analysis. If any of the steps fail, the method will raise an error.
353
+
354
+ :param section: The curve representing the airfoil cross-section
355
+ :param refine_tol: A general tolerance used in the analysis, typically used to refine results until the error
356
+ or difference between two values is less than this value. It is also used in certain methods as a common
357
+ reference tolerance, where the method will use a fraction of this value as a threshold for convergence or error.
358
+ :param camber_orient: The method to use to orient the mean camber line of the airfoil.
359
+ :param leading: The method to use to detect the leading edge of the airfoil.
360
+ :param trailing: The method to use to detect the trailing edge of the airfoil.
361
+ :param face_orient: The method to identify the upper and lower faces of the airfoil.
362
+ :return: An instance of `AirfoilGeometry` containing the results of the analysis.
363
+ """
216
364
  ...
217
365
 
218
366
  @property
219
367
  def leading(self) -> EdgeResult | None:
220
368
  """
221
- The result of the leading edge detection algorithm.
369
+ Gets the result of the leading edge detection algorithm.
222
370
  """
223
371
  ...
224
372
 
225
373
  @property
226
374
  def trailing(self) -> EdgeResult | None:
227
375
  """
228
- The result of the trailing edge detection algorithm.
376
+ Gets the result of the trailing edge detection algorithm.
229
377
  """
230
378
  ...
231
379
 
232
380
  @property
233
381
  def camber(self) -> Curve2:
234
382
  """
235
- The mean camber line of the airfoil cross-section. The curve will be oriented so that the first point is at
383
+ Gets the mean camber line of the airfoil cross-section. The curve will be oriented so that the first point is at
236
384
  the leading edge of the airfoil and the last point is at the trailing edge.
237
- :return:
385
+ :return: The mean camber line of the airfoil cross-section as a `Curve2` object.
238
386
  """
239
387
  ...
240
388
 
@@ -245,7 +393,7 @@ class AirfoilGeometry:
245
393
  in the same winding direction as the original section, so the first point may be at either the leading or
246
394
  trailing edge based on the airfoil geometry and the coordinate system.
247
395
 
248
- :return: A Curve2, or None if there was an issue detecting the leading or trailing edge.
396
+ :return: A `Curve2`, or None if there was an issue detecting the leading or trailing edge.
249
397
  """
250
398
  ...
251
399
 
@@ -256,43 +404,46 @@ class AirfoilGeometry:
256
404
  oriented in the same winding direction as the original section, so the first point may be at either the leading
257
405
  or trailing edge based on the airfoil geometry and the coordinate system.
258
406
 
259
- :return: A Curve2, or None if there was an issue detecting the leading or trailing edge.
407
+ :return: A `Curve2`, or None if there was an issue detecting the leading or trailing edge.
260
408
  """
261
409
  ...
262
410
 
263
411
  @property
264
- def circle_array(self) -> numpy.ndarray[float]:
412
+ def circle_array(self) -> NDArray[float]:
265
413
  """
266
414
  Returns the list of inscribed circles as a numpy array of shape (N, 3) where N is the number of inscribed
267
415
  circles. The first two columns are the x and y coordinates of the circle center, and the third column is the
268
416
  radius of the circle.
417
+ :return: A numpy array of shape (N, 3) containing the inscribed circles
269
418
  """
270
419
  ...
271
420
 
272
- def get_thickness(self, gage: AfGageEnum) -> Length2:
421
+ def get_thickness(self, gage: AfGageEnum) -> Distance2:
273
422
  """
274
- Get the thickness dimension of the airfoil cross-section.
423
+ Get the thickness dimension of the airfoil cross-section. The 'a' point of the distance will be on the lower
424
+ surface of the airfoil, and the 'b' point will be on the upper surface.
275
425
  :param gage: the gaging method to use
276
- :return:
426
+ :return: a `Distance2` object representing the thickness dimension at the specified gage points
277
427
  """
278
428
  ...
279
429
 
280
- def get_tmax(self) -> Length2:
430
+ def get_tmax(self) -> Distance2:
281
431
  """
282
- Get the maximum thickness dimension of the airfoil cross-section.
283
- :return:
432
+ Get the maximum thickness dimension of the airfoil cross-section. The 'a' point of the distance will be on the
433
+ lower surface of the airfoil, and the 'b' point will be on the upper surface.
434
+ :return: a `Distance2` object representing the maximum thickness dimension
284
435
  """
285
436
  ...
286
437
 
287
438
  def get_tmax_circle(self) -> Circle2:
288
439
  """
289
440
  Get the circle representing the maximum thickness dimension of the airfoil cross-section.
290
- :return:
441
+ :return: a `Circle2` object representing the maximum thickness circle
291
442
  """
292
443
  ...
293
444
 
294
445
 
295
- def compute_inscribed_circles(section: Curve2, refine_tol: float) -> List[InscribedCircle]:
446
+ def compute_inscribed_circles(section: geom2.Curve2, refine_tol: float) -> List[InscribedCircle]:
296
447
  """
297
448
  Compute the unambiguous inscribed circles of an airfoil cross-section.
298
449
 
engeom/engeom.pyd CHANGED
Binary file
engeom/engeom.pyi CHANGED
@@ -1,13 +1,46 @@
1
1
  from __future__ import annotations
2
2
  from enum import Enum
3
3
 
4
- type Resample = Resample_Count | Resample_Spacing | Resample_MaxSpacing
4
+ type ResampleEnum = Resample_Count | Resample_Spacing | Resample_MaxSpacing
5
5
 
6
6
  class DeviationMode(Enum):
7
+ """
8
+ Represents the different methods of calculating deviation between a point and another geometry.
9
+ """
7
10
  Point = 0
8
11
  Plane = 1
9
12
 
10
13
  class SelectOp(Enum):
14
+ """
15
+ A common enum to describe different types of selection operations.
16
+ """
11
17
  Add=0
12
18
  Remove=1
13
- Keep=2
19
+ Keep=2
20
+
21
+ class Resample:
22
+ """
23
+ A common enum to describe different methods of resampling a point based geometry.
24
+ """
25
+
26
+ class Count:
27
+ """ A resampling method that specifies a fixed number of entities. """
28
+ def __init__(self, count: int):
29
+ self.count = count
30
+
31
+ class Spacing:
32
+ """
33
+ A resampling method that specifies a fixed spacing between entities. For some types of resampling operations,
34
+ this may result in dead space near edges. Check with the specific operation documentation for details.
35
+ """
36
+ def __init__(self, spacing: float):
37
+ self.spacing = spacing
38
+
39
+ class MaxSpacing:
40
+ """
41
+ A resampling method which specifies a maximum permissible spacing between entities. Unlike `Spacing`, this will
42
+ allow the operation to adjust spacing to remove potential dead space near edges, while also placing a limit on
43
+ how far apart entities can be as a result.
44
+ """
45
+ def __init__(self, max_spacing: float):
46
+ self.max_spacing = max_spacing
engeom/geom2/__init__.py CHANGED
@@ -1,3 +1,8 @@
1
+ """
2
+ This module contains a number of classes and functions for working with 2D geometry. These range from fundamental
3
+ primitives like points and vectors up to complex items like polylines.
4
+ """
5
+
1
6
  from ..engeom import _geom2
2
7
 
3
8
  # Global import of all functions