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/_plot/__init__.py +1 -0
- engeom/_plot/common.py +17 -0
- engeom/{matplotlib.py → _plot/matplotlib.py} +88 -45
- engeom/_plot/pyvista.py +256 -0
- engeom/airfoil/__init__.py +4 -0
- engeom/airfoil.pyi +202 -51
- engeom/engeom.pyd +0 -0
- engeom/engeom.pyi +35 -2
- engeom/geom2/__init__.py +5 -0
- engeom/geom2.pyi +456 -80
- engeom/geom3/__init__.py +5 -0
- engeom/geom3.pyi +530 -148
- engeom/metrology/__init__.py +4 -0
- engeom/metrology.pyi +85 -12
- engeom/plot.py +26 -0
- {engeom-0.2.4.dist-info → engeom-0.2.6.dist-info}/METADATA +7 -1
- engeom-0.2.6.dist-info/RECORD +21 -0
- engeom/pyvista.py +0 -178
- engeom-0.2.4.dist-info/RECORD +0 -18
- {engeom-0.2.4.dist-info → engeom-0.2.6.dist-info}/WHEEL +0 -0
engeom/geom2.pyi
CHANGED
@@ -1,128 +1,262 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
import numpy
|
3
|
-
from typing import Iterable, Tuple, Type, TypeVar
|
4
2
|
|
5
|
-
from
|
3
|
+
from typing import Iterable, Tuple, TypeVar, Iterator, Any
|
4
|
+
|
5
|
+
from numpy.typing import NDArray
|
6
|
+
from engeom.engeom import ResampleEnum
|
7
|
+
|
8
|
+
from engeom import geom3
|
6
9
|
|
7
10
|
Transformable2 = TypeVar("Transformable2", Vector2, Point2, Iso2, SurfacePoint2)
|
8
11
|
PointOrVec2 = TypeVar("PointOrVec2", Point2, Vector2)
|
9
12
|
|
10
13
|
|
11
14
|
class Vector2(Iterable[float]):
|
15
|
+
"""
|
16
|
+
A class representing a vector in 2D space. The vector contains an x and y component. It is iterable and will
|
17
|
+
yield the x and y components in order, allowing the Python unpacking operator `*` to be used to compensate for the
|
18
|
+
lack of function overloading through some other parts of the library.
|
19
|
+
|
20
|
+
A vector has different semantics than a point when it comes to transformations and some mathematical operations.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __iter__(self) -> Iterator[float]:
|
24
|
+
pass
|
25
|
+
|
12
26
|
def __init__(self, x: float, y: float):
|
13
27
|
"""
|
14
|
-
|
15
|
-
:param x:
|
16
|
-
:param y:
|
28
|
+
Create a 2D vector from the given x and y components.
|
29
|
+
:param x: the x component of the vector.
|
30
|
+
:param y: the y component of the vector.
|
17
31
|
"""
|
18
32
|
...
|
19
33
|
|
20
34
|
@property
|
21
35
|
def x(self) -> float:
|
36
|
+
"""
|
37
|
+
Access the x component of the vector as a floating point value.
|
38
|
+
"""
|
22
39
|
...
|
23
40
|
|
24
41
|
@property
|
25
42
|
def y(self) -> float:
|
43
|
+
"""
|
44
|
+
Access the y component of the vector as a floating point value.
|
45
|
+
"""
|
26
46
|
...
|
27
47
|
|
28
48
|
def __rmul__(self, other: float) -> Vector2:
|
49
|
+
"""
|
50
|
+
Multiply the vector by a scalar value. This allows the scalar to be on the left side of the multiplication
|
51
|
+
operator.
|
52
|
+
:param other: a scalar value to multiply the vector by.
|
53
|
+
:return: a new vector that is the result of the multiplication.
|
54
|
+
"""
|
55
|
+
...
|
56
|
+
|
57
|
+
def __mul__(self, other: float) -> Vector2:
|
58
|
+
"""
|
59
|
+
Multiply the vector by a scalar value.
|
60
|
+
:param other: a scalar value to multiply the vector by.
|
61
|
+
:return: a new vector that is the result of the multiplication.
|
62
|
+
"""
|
29
63
|
...
|
30
64
|
|
31
65
|
def __add__(self, other: PointOrVec2) -> PointOrVec2:
|
66
|
+
"""
|
67
|
+
Add a vector to a point or another vector. Adding a vector to a point will return a new point, while
|
68
|
+
adding a vector to a vector will return a new vector.
|
69
|
+
:param other: a point or vector to add to the vector.
|
70
|
+
:return: a new point or vector that is the result of the addition.
|
71
|
+
"""
|
32
72
|
...
|
33
73
|
|
34
74
|
def __sub__(self, other: Vector2) -> Vector2:
|
75
|
+
"""
|
76
|
+
Subtract a vector from this vector.
|
77
|
+
:param other: the vector to subtract from this vector.
|
78
|
+
:return: a new vector that is the result of the subtraction.
|
79
|
+
"""
|
35
80
|
...
|
36
81
|
|
37
82
|
def __neg__(self) -> Vector2:
|
83
|
+
"""
|
84
|
+
Invert the vector by negating the x and y components.
|
85
|
+
:return: a new vector in which the x and y components are negated.
|
86
|
+
"""
|
38
87
|
...
|
39
88
|
|
40
|
-
def
|
89
|
+
def __truediv__(self, other: float) -> Vector2:
|
90
|
+
"""
|
91
|
+
Divide the vector by a scalar value.
|
92
|
+
:param other: a scalar value to divide the vector by.
|
93
|
+
:return: a new vector that is the result of the division.
|
94
|
+
"""
|
41
95
|
...
|
42
96
|
|
43
|
-
def as_numpy(self) ->
|
97
|
+
def as_numpy(self) -> NDArray[float]:
|
44
98
|
"""
|
45
|
-
Create a numpy array of shape (2,) from the vector.
|
99
|
+
Create a numpy array of shape (2, ) from the vector.
|
46
100
|
"""
|
47
101
|
...
|
48
102
|
|
49
103
|
def dot(self, other: Vector2) -> float:
|
50
104
|
"""
|
51
|
-
Compute the dot product of two vectors.
|
105
|
+
Compute the dot product of two vectors. The result is a scalar value.
|
106
|
+
:param other: the vector to compute the dot product with.
|
107
|
+
:return: the scalar dot product of the two vectors.
|
52
108
|
"""
|
53
109
|
...
|
54
110
|
|
55
111
|
def cross(self, other: Vector2) -> float:
|
56
112
|
"""
|
57
113
|
Compute the cross product of two vectors.
|
114
|
+
:param other: the vector to compute the cross product with.
|
115
|
+
:return: the scalar cross product of the two vectors.
|
58
116
|
"""
|
59
117
|
...
|
60
118
|
|
61
119
|
def norm(self) -> float:
|
62
120
|
"""
|
63
|
-
Compute the norm of the vector.
|
121
|
+
Compute the Euclidian norm (aka magnitude, length) of the vector.
|
64
122
|
"""
|
65
123
|
...
|
66
124
|
|
67
125
|
def normalized(self) -> Vector2:
|
68
126
|
"""
|
69
|
-
Return a normalized version of the vector.
|
127
|
+
Return a normalized version of the vector. The normalized vector will have the same direction as the original
|
128
|
+
vector, but with a magnitude of 1.
|
70
129
|
"""
|
71
130
|
...
|
72
131
|
|
73
132
|
def angle_to(self, other: Vector2) -> float:
|
74
133
|
"""
|
75
134
|
Compute the smallest angle between two vectors and return it in radians.
|
135
|
+
|
136
|
+
:param other: the vector to compute the angle to.
|
137
|
+
:return: the angle between the two vectors in radians.
|
76
138
|
"""
|
77
139
|
...
|
78
140
|
|
79
141
|
|
80
142
|
class Point2(Iterable[float]):
|
143
|
+
"""
|
144
|
+
A class representing a point in 2D space. The point contains an x and y component. It is iterable and will yield
|
145
|
+
the x and y components in order, allowing the Python unpacking operator `*` to be used to compensate for the lack
|
146
|
+
of function overloading through some other parts of the library.
|
147
|
+
|
148
|
+
A point has different semantics than a vector when it comes to transformations and some mathematical operations.
|
149
|
+
"""
|
150
|
+
|
151
|
+
def __iter__(self) -> Iterator[float]:
|
152
|
+
pass
|
153
|
+
|
81
154
|
def __init__(self, x: float, y: float):
|
82
155
|
"""
|
83
|
-
|
84
|
-
:param x:
|
85
|
-
:param y:
|
156
|
+
Create a 2D point from the given x and y components.
|
157
|
+
:param x: the x component of the point.
|
158
|
+
:param y: the y component of the point.
|
86
159
|
"""
|
87
160
|
...
|
88
161
|
|
89
162
|
@property
|
90
163
|
def x(self) -> float:
|
164
|
+
"""
|
165
|
+
Access the x component of the point as a floating point value.
|
166
|
+
"""
|
91
167
|
...
|
92
168
|
|
93
169
|
@property
|
94
170
|
def y(self) -> float:
|
171
|
+
"""
|
172
|
+
Access the y component of the point as a floating point value.
|
173
|
+
"""
|
95
174
|
...
|
96
175
|
|
97
176
|
@property
|
98
177
|
def coords(self) -> Vector2:
|
99
178
|
"""
|
100
|
-
Get the coordinates of the point as a Vector2 object.
|
101
|
-
:return: a Vector2 object
|
179
|
+
Get the coordinates of the point as a `Vector2` object.
|
180
|
+
:return: a `Vector2` object with the same x and y components as the point.
|
102
181
|
"""
|
103
182
|
...
|
104
183
|
|
105
184
|
def __sub__(self, other: PointOrVec2) -> PointOrVec2:
|
185
|
+
"""
|
186
|
+
Subtract a point or vector from this point. Subtracting a point from a point will return a new vector, while
|
187
|
+
subtracting a vector from a point will return a new point.
|
188
|
+
:param other: a point or vector to subtract from the point.
|
189
|
+
:return: a new point or vector that is the result of the subtraction.
|
190
|
+
"""
|
106
191
|
...
|
107
192
|
|
108
193
|
def __add__(self, other: Vector2) -> Vector2:
|
194
|
+
"""
|
195
|
+
Add a vector to this point.
|
196
|
+
:param other: the vector to add to the point.
|
197
|
+
:return: a new point that is the result of the addition.
|
198
|
+
"""
|
109
199
|
...
|
110
200
|
|
111
|
-
def
|
201
|
+
def __mul__(self, other: float) -> Point2:
|
112
202
|
"""
|
113
|
-
|
203
|
+
Multiply the point's x and y components by a scalar value, returning a new point.
|
204
|
+
:param other: the scalar value to multiply the point by.
|
205
|
+
:return: a new point that is the result of the multiplication.
|
206
|
+
"""
|
207
|
+
...
|
208
|
+
|
209
|
+
def __truediv__(self, other) -> Point2:
|
210
|
+
"""
|
211
|
+
Divide the point's x and y components by a scalar value, returning a new point.
|
212
|
+
:param other: the scalar value to divide the point by.
|
213
|
+
:return: a new point that is the result of the division.
|
214
|
+
"""
|
215
|
+
...
|
216
|
+
|
217
|
+
def __rmul__(self, other) -> Point2:
|
218
|
+
"""
|
219
|
+
Multiply the point's x and y components by a scalar value, returning a new point. This allows the scalar to be
|
220
|
+
on the left side of the multiplication.
|
221
|
+
:param other: the scalar value to multiply the point by.
|
222
|
+
:return: a new point that is the result of the multiplication.
|
223
|
+
"""
|
224
|
+
...
|
225
|
+
|
226
|
+
def __neg__(self) -> Point2:
|
227
|
+
"""
|
228
|
+
Invert the point by negating the x and y components.
|
229
|
+
:return: a new point in which the x and y components are negated.
|
230
|
+
"""
|
231
|
+
...
|
232
|
+
|
233
|
+
def as_numpy(self) -> NDArray[float]:
|
234
|
+
"""
|
235
|
+
Create a numpy array of shape (2, ) from the point.
|
114
236
|
"""
|
115
237
|
...
|
116
238
|
|
117
239
|
|
118
240
|
class SurfacePoint2:
|
241
|
+
"""
|
242
|
+
This class is used to represent a surface point in 2D space.
|
243
|
+
|
244
|
+
Surface points are a composite structure that consist of a point in space and a normal direction. Conceptually, they
|
245
|
+
come from metrology as a means of representing a point on the surface of an object along with the normal direction
|
246
|
+
of the surface at that point. However, they are also isomorphic with the concept of a ray or a parameterized line
|
247
|
+
with a direction of unit length, and can be used in that way as well.
|
248
|
+
"""
|
249
|
+
|
119
250
|
def __init__(self, x: float, y: float, nx: float, ny: float):
|
120
251
|
"""
|
252
|
+
Create a surface point from the given x and y components and the normal vector components. The normal vector
|
253
|
+
components will be normalized automatically upon creation. If the normal vector is the zero vector, an
|
254
|
+
exception will be thrown.
|
121
255
|
|
122
|
-
:param x:
|
123
|
-
:param y:
|
124
|
-
:param nx:
|
125
|
-
:param ny:
|
256
|
+
:param x: the x component of the point.
|
257
|
+
:param y: the y component of the point.
|
258
|
+
:param nx: the x component of the normal vector.
|
259
|
+
:param ny: the y component of the normal vector.
|
126
260
|
"""
|
127
261
|
...
|
128
262
|
|
@@ -200,14 +334,72 @@ class SurfacePoint2:
|
|
200
334
|
"""
|
201
335
|
...
|
202
336
|
|
337
|
+
def rot_normal(self, angle: float) -> SurfacePoint2:
|
338
|
+
"""
|
339
|
+
Rotate the normal vector of the surface point by a given angle in radians and return a new surface point. The
|
340
|
+
position of the surface point is not affected. The angle is positive for counter-clockwise rotation and negative
|
341
|
+
for clockwise rotation.
|
342
|
+
|
343
|
+
:param angle: the angle to rotate the normal vector by.
|
344
|
+
:return: a new surface point with the rotated normal vector.
|
345
|
+
"""
|
346
|
+
|
347
|
+
def __mul__(self, other: float) -> SurfacePoint2:
|
348
|
+
"""
|
349
|
+
Multiply the position of the surface point by a scalar value. The normal vector is not affected unless the
|
350
|
+
scalar is negative, in which case the normal vector is inverted.
|
351
|
+
:param other: the scalar value to multiply the position by.
|
352
|
+
:return: a new surface point with the position multiplied by the scalar.
|
353
|
+
"""
|
354
|
+
...
|
355
|
+
|
356
|
+
def __rmul__(self, other: float) -> SurfacePoint2:
|
357
|
+
"""
|
358
|
+
Multiply the position of the surface point by a scalar value. The normal vector is not affected unless the
|
359
|
+
scalar is negative, in which case the normal vector is inverted.
|
360
|
+
:param other: the scalar value to multiply the position by.
|
361
|
+
:return: a new surface point with the position multiplied by the scalar.
|
362
|
+
"""
|
363
|
+
...
|
364
|
+
|
365
|
+
def __truediv__(self, other: float) -> SurfacePoint2:
|
366
|
+
"""
|
367
|
+
Divide the position of the surface point by a scalar value. The normal vector is not affected unless the
|
368
|
+
scalar is negative, in which case the normal vector is inverted.
|
369
|
+
:param other: the scalar value to divide the position by.
|
370
|
+
:return: a new surface point with the position divided by the scalar.
|
371
|
+
"""
|
372
|
+
...
|
373
|
+
|
374
|
+
def __neg__(self) -> SurfacePoint2:
|
375
|
+
"""
|
376
|
+
Invert both the position AND the normal vector of the surface point.
|
377
|
+
"""
|
378
|
+
...
|
379
|
+
|
203
380
|
|
204
381
|
class Iso2:
|
382
|
+
"""
|
383
|
+
A class representing an isometry in 2D space. An isometry is a transformation that preserves distances and angles,
|
384
|
+
also sometimes known as a rigid body transformation. It is composed of a translation and a rotation.
|
385
|
+
|
386
|
+
`Iso2` objects can be used to transform points, vectors, surface points, other isometries, and a number of other
|
387
|
+
2D geometric constructs.
|
388
|
+
"""
|
389
|
+
|
205
390
|
def __init__(self, tx: float, ty: float, r: float):
|
206
391
|
"""
|
392
|
+
Create an isometry from a translation and a rotation. The translation is represented by the x and y components
|
393
|
+
of the translation vector. The rotation is represented by the angle in radians, and will be a rotation around
|
394
|
+
the origin of the coordinate system.
|
395
|
+
|
396
|
+
In convention with typical transformation matrices, transforming by an isometry constructed this way is the
|
397
|
+
equivalent of first rotating by the angle `r` and then translating by the vector `(tx, ty)`.
|
207
398
|
|
208
|
-
:param tx:
|
209
|
-
:param ty:
|
210
|
-
:param r:
|
399
|
+
:param tx: the x component of the translation vector.
|
400
|
+
:param ty: the y component of the translation vector.
|
401
|
+
:param r: the angle of rotation in radians around the origin, where a positive value is a counter-clockwise
|
402
|
+
rotation.
|
211
403
|
"""
|
212
404
|
...
|
213
405
|
|
@@ -219,109 +411,240 @@ class Iso2:
|
|
219
411
|
...
|
220
412
|
|
221
413
|
def __matmul__(self, other: Transformable2) -> Transformable2:
|
414
|
+
"""
|
415
|
+
Transform a point, vector, or other transformable object by the isometry using the matrix multiplication
|
416
|
+
operator. The transform must be on the right side of the operator, and the object being transformed must be on
|
417
|
+
the left side. This is the equivalent of multiplying the object by the isometry matrix.
|
418
|
+
|
419
|
+
When composing multiple isometries together, remember that the order of operations is reversed. For example, if
|
420
|
+
you have isometries A, B, and C, and you want to compose them together such that they are the equivalent of
|
421
|
+
first applying A, then B, then C, you would write `D = C @ B @ A`.
|
422
|
+
|
423
|
+
:param other: the object to transform.
|
424
|
+
:return: an object of the same type as the input, transformed by the isometry.
|
425
|
+
"""
|
222
426
|
...
|
223
427
|
|
224
428
|
def inverse(self) -> Iso2:
|
225
429
|
"""
|
226
|
-
Get the inverse of the isometry
|
430
|
+
Get the inverse of the isometry, which is the isometry that undoes the transformation of the original isometry,
|
431
|
+
or the isometry that when composed with the original isometry produces the identity isometry.
|
227
432
|
"""
|
228
433
|
...
|
229
434
|
|
230
|
-
def as_numpy(self) ->
|
435
|
+
def as_numpy(self) -> NDArray[float]:
|
231
436
|
"""
|
232
437
|
Create a numpy array of shape (3, 3) from the isometry.
|
233
438
|
"""
|
234
439
|
...
|
235
440
|
|
236
|
-
def transform_points(self, points:
|
441
|
+
def transform_points(self, points: NDArray[float]) -> NDArray[float]:
|
237
442
|
"""
|
238
|
-
Transform an array of points using the isometry.
|
443
|
+
Transform an array of points using the isometry. The semantics of transforming points are such that the full
|
444
|
+
matrix is applied, first rotating the point around the origin and then translating it by the translation vector.
|
445
|
+
|
446
|
+
To transform vectors, use the `transform_vectors` method instead.
|
447
|
+
|
448
|
+
This is an efficient way to transform a large number of points at once, rather than using the `@` operator
|
449
|
+
individually on a large number of `Point2` objects.
|
450
|
+
|
239
451
|
:param points: a numpy array of shape (N, 2)
|
240
|
-
:return: a numpy array of shape (N, 2)
|
452
|
+
:return: a numpy array of shape (N, 2) containing the transformed points in the same order as the input.
|
241
453
|
"""
|
242
454
|
...
|
243
455
|
|
244
|
-
def transform_vectors(self, vectors:
|
456
|
+
def transform_vectors(self, vectors: NDArray[float]) -> NDArray[float]:
|
245
457
|
"""
|
246
|
-
Transform an array of vectors using the isometry. The
|
247
|
-
|
248
|
-
|
458
|
+
Transform an array of vectors using the isometry. The semantics of transforming vectors are such that only the
|
459
|
+
rotation matrix is applied, and the translation vector is not used. The vectors retain their original
|
460
|
+
magnitude, but their direction is rotated by the isometry.
|
461
|
+
|
462
|
+
To transform points, use the `transform_points` method instead.
|
463
|
+
|
464
|
+
This is an efficient way to transform a large number of vectors at once, rather than using the `@` operator
|
465
|
+
individually on a large number of `Vector2` objects.
|
466
|
+
|
467
|
+
:param vectors: a numpy array of shape (N, 2)
|
468
|
+
:return: a numpy array of shape (N, 2) containing the transformed vectors in the same order as the input.
|
249
469
|
"""
|
250
470
|
...
|
251
471
|
|
252
472
|
|
253
473
|
class SvdBasis2:
|
474
|
+
"""
|
475
|
+
A class which creates a set of orthonormal basis vectors from a set of points in 2D space. The basis is created
|
476
|
+
using a singular value decomposition of the points, and is very similar to the statistical concept of principal
|
477
|
+
component analysis.
|
478
|
+
|
479
|
+
The basis can be used to determine the rank of the point set, the variance of the points along the basis vectors,
|
480
|
+
and to extract an isometry that will transform points from the world space to the basis space. It is useful for
|
481
|
+
orienting unknown point sets in a consistent way, for finding best-fit lines or planes, and for other similar
|
482
|
+
tasks.
|
483
|
+
"""
|
254
484
|
|
255
485
|
def __init__(
|
256
486
|
self,
|
257
|
-
points:
|
258
|
-
weights:
|
487
|
+
points: NDArray[float],
|
488
|
+
weights: NDArray[float] | None = None
|
259
489
|
):
|
260
490
|
"""
|
491
|
+
Create a basis from a set of points. The basis will be calculated using a singular value decomposition of the
|
492
|
+
points.
|
493
|
+
|
494
|
+
:param points: a numpy array of shape (n, 2) containing the points to calculate the basis from.
|
495
|
+
:param weights: a numpy array of shape (n,) containing the weights of the points. If None, all points will be
|
496
|
+
weighted equally.
|
497
|
+
"""
|
498
|
+
...
|
499
|
+
|
500
|
+
def rank(self, tol: float) -> int:
|
501
|
+
"""
|
502
|
+
Retrieve the rank of the decomposition by counting the number of singular values that are
|
503
|
+
greater than the provided tolerance. A rank of 0 indicates that all singular values are
|
504
|
+
less than the tolerance, and thus the point set is essentially a single point. A rank of 1
|
505
|
+
indicates that the point set is essentially a line. A rank of 2 indicates that the point
|
506
|
+
set exists roughly in a plane.
|
507
|
+
|
508
|
+
The singular values do not directly have a clear physical meaning. They are square roots of
|
509
|
+
the variance multiplied by the number of points used to compute the basis. Thus, they can
|
510
|
+
be interpreted in relation to each other, and when they are very small.
|
511
|
+
|
512
|
+
This method should be used either when you know roughly what a cutoff tolerance for the
|
513
|
+
problem you're working on should be, or when you know the cutoff value should be very
|
514
|
+
small. Otherwise, consider examining the standard deviations of the basis vectors
|
515
|
+
instead, as they will be easier to interpret (`basis_stdevs()`).
|
516
|
+
:param tol: the tolerance to use when determining the rank.
|
517
|
+
:return: the rank of the decomposition.
|
518
|
+
"""
|
519
|
+
...
|
520
|
+
|
521
|
+
def largest(self) -> Vector2:
|
522
|
+
"""
|
523
|
+
Get the largest singular vector of the basis.
|
524
|
+
:return: the largest singular vector.
|
525
|
+
"""
|
526
|
+
...
|
527
|
+
|
528
|
+
def smallest(self) -> Vector2:
|
529
|
+
"""
|
530
|
+
Get the smallest singular vector of the basis.
|
531
|
+
:return: the smallest singular vector.
|
532
|
+
"""
|
533
|
+
...
|
534
|
+
|
535
|
+
def basis_variances(self) -> NDArray[float]:
|
536
|
+
"""
|
537
|
+
Get the variance of the points along the singular vectors.
|
538
|
+
:return: a numpy array of the variance of the points along the singular vectors.
|
539
|
+
"""
|
540
|
+
...
|
541
|
+
|
542
|
+
def basis_stdevs(self) -> NDArray[float]:
|
543
|
+
"""
|
544
|
+
Get the standard deviation of the points along the singular vectors.
|
545
|
+
:return: a numpy array of the standard deviation of the points along the singular vectors.
|
546
|
+
"""
|
547
|
+
...
|
548
|
+
|
549
|
+
def to_iso2(self) -> Iso2:
|
550
|
+
"""
|
551
|
+
Produce an isometry which will transform from the world space to the basis space.
|
261
552
|
|
262
|
-
|
263
|
-
|
553
|
+
For example, if the basis is created from a set of points that lie roughly on an arbitrary line, multiplying
|
554
|
+
original points by this isometry will move the points such that all points are aligned with the x-axis.
|
555
|
+
:return: the isometry that transforms from the world space to the basis space.
|
264
556
|
"""
|
265
557
|
...
|
266
558
|
|
267
559
|
|
268
560
|
class CurveStation2:
|
269
561
|
"""
|
270
|
-
A class representing a station along a curve in
|
562
|
+
A class representing a station along a curve in 2D space. The station is represented by a point on the curve, a
|
271
563
|
tangent (direction) vector, and a length along the curve.
|
564
|
+
|
565
|
+
These are created as the result of position finding operations on `Curve2` objects.
|
272
566
|
"""
|
273
567
|
|
274
568
|
@property
|
275
569
|
def point(self) -> Point2:
|
276
|
-
"""
|
570
|
+
"""
|
571
|
+
Get the point in 2D world space where the station is located.
|
572
|
+
:return: the point in 2D world space.
|
573
|
+
"""
|
277
574
|
...
|
278
575
|
|
279
576
|
@property
|
280
577
|
def direction(self) -> Vector2:
|
281
|
-
"""
|
578
|
+
"""
|
579
|
+
Get the direction vector of the curve at the location of the station. This is the tangent vector of the curve,
|
580
|
+
and is typically the direction from the previous vertex to the next vertex.
|
581
|
+
:return: the direction vector of the curve at the station.
|
582
|
+
"""
|
282
583
|
...
|
283
584
|
|
284
585
|
@property
|
285
586
|
def normal(self) -> Vector2:
|
286
|
-
"""
|
587
|
+
"""
|
588
|
+
Get the normal vector of the curve at the location of the station. This is the vector that is orthogonal to the
|
589
|
+
direction vector, and is the direction vector at the station rotated by -90 degrees. When the curve represents
|
590
|
+
a manifold surface, this vector represents the direction of the surface normal.
|
591
|
+
:return: the surface normal vector of the curve at the station.
|
592
|
+
"""
|
287
593
|
...
|
288
594
|
|
289
595
|
@property
|
290
596
|
def direction_point(self) -> SurfacePoint2:
|
291
597
|
"""
|
292
|
-
|
598
|
+
Get the combined point and direction vector of the curve at the location of the station, returned as a
|
599
|
+
`SurfacePoint2` object.
|
600
|
+
:return: the combined point and direction vector of the curve at the station.
|
293
601
|
"""
|
294
602
|
...
|
295
603
|
|
296
604
|
@property
|
297
605
|
def surface_point(self) -> SurfacePoint2:
|
298
606
|
"""
|
299
|
-
|
607
|
+
Get the combined point and normal vector of the curve at the location of the station, returned as a
|
608
|
+
`SurfacePoint2` object.
|
609
|
+
:return: the combined point and normal vector of the curve at the station.
|
300
610
|
"""
|
301
611
|
...
|
302
612
|
|
303
613
|
@property
|
304
614
|
def index(self) -> int:
|
305
|
-
"""
|
615
|
+
"""
|
616
|
+
Get the index of the previous vertex on the curve, at or before the station.
|
617
|
+
:return: the index of the previous vertex on the curve.
|
618
|
+
"""
|
306
619
|
...
|
307
620
|
|
308
621
|
@property
|
309
622
|
def length_along(self) -> float:
|
310
|
-
"""
|
623
|
+
"""
|
624
|
+
Get the length along the curve to the station, starting at the first vertex of the curve.
|
625
|
+
:return: the length along the curve to the station.
|
626
|
+
"""
|
311
627
|
...
|
312
628
|
|
313
629
|
|
314
630
|
class Curve2:
|
315
631
|
"""
|
316
632
|
A class representing a curve in 2D space. The curve is defined by a set of vertices and the line segments between
|
317
|
-
them
|
633
|
+
them (also known as a polyline).
|
318
634
|
|
635
|
+
Because the curve is in 2D space, it also has a concept of a surface normal direction, which is orthogonal to the
|
636
|
+
tangent direction of the curve at any point. This normal direction allows a `Curve2` to represent a 2D manifold
|
637
|
+
surface boundary, defining the concepts of inside and outside. It is commonly used to represent the surface of a
|
638
|
+
solid body in a 2D cross-section.
|
639
|
+
|
640
|
+
Additionally, the `Curve2` object can be used to represent closed regions by connecting the first and last vertices
|
641
|
+
and allowing the curve to be treated as a closed loop. This lets the `Curve2` also represent closed polygons.
|
319
642
|
"""
|
320
643
|
|
321
644
|
def __init__(
|
322
645
|
self,
|
323
|
-
vertices:
|
324
|
-
normals:
|
646
|
+
vertices: NDArray[float],
|
647
|
+
normals: NDArray[float] | None = None,
|
325
648
|
tol: float = 1e-6,
|
326
649
|
force_closed: bool = False,
|
327
650
|
hull_ccw: bool = False,
|
@@ -334,11 +657,14 @@ class Curve2:
|
|
334
657
|
to model a manifold surface.
|
335
658
|
|
336
659
|
There are three ways to specify the winding order of the vertices:
|
660
|
+
|
337
661
|
1. Control it manually by passing the vertices array with the rows already organized so that an exterior surface
|
338
662
|
is counter-clockwise.
|
663
|
+
|
339
664
|
2. If the vertices represent an exterior shape, pass `hull_ccw=True` to have the constructor automatically
|
340
665
|
check the winding order and reverse it if point ordering in the convex hull does not match ordering in the
|
341
666
|
original array.
|
667
|
+
|
342
668
|
3. Pass a `normals` array the same size as the `vertices` array, where the normals are non-zero vectors pointed
|
343
669
|
in the "outside" direction at each point. The constructor will reverse the winding if the majority of normals
|
344
670
|
do not point in the same direction as the winding.
|
@@ -358,7 +684,7 @@ class Curve2:
|
|
358
684
|
|
359
685
|
def length(self) -> float:
|
360
686
|
"""
|
361
|
-
Get the length of the curve.
|
687
|
+
Get the total length of the curve as a scalar value.
|
362
688
|
:return: the length of the curve.
|
363
689
|
"""
|
364
690
|
...
|
@@ -462,7 +788,7 @@ class Curve2:
|
|
462
788
|
"""
|
463
789
|
...
|
464
790
|
|
465
|
-
def make_hull(self) ->
|
791
|
+
def make_hull(self) -> NDArray[int]:
|
466
792
|
"""
|
467
793
|
Get the vertices of a convex hull of the curve, in counter-clockwise order.
|
468
794
|
:return: a numpy array of shape (N, 2) representing the convex hull of the curve.
|
@@ -486,7 +812,7 @@ class Curve2:
|
|
486
812
|
...
|
487
813
|
|
488
814
|
@property
|
489
|
-
def points(self) ->
|
815
|
+
def points(self) -> NDArray[float]:
|
490
816
|
"""
|
491
817
|
Get the points of the curve.
|
492
818
|
:return: a numpy array of shape (N, 2) representing the points of the curve.
|
@@ -501,7 +827,7 @@ class Curve2:
|
|
501
827
|
"""
|
502
828
|
...
|
503
829
|
|
504
|
-
def resample(self, resample:
|
830
|
+
def resample(self, resample: ResampleEnum) -> Curve2:
|
505
831
|
"""
|
506
832
|
Resample the curve using the given resampling method. The resampling method can be one of the following:
|
507
833
|
|
@@ -522,22 +848,32 @@ class Curve2:
|
|
522
848
|
"""
|
523
849
|
...
|
524
850
|
|
851
|
+
def to_3d(self) -> geom3.Curve3:
|
852
|
+
"""
|
853
|
+
Convert the curve to a 3D curve by adding a z-coordinate of 0 to all points.
|
854
|
+
:return: a new `Curve3` object representing the curve in 3D space.
|
855
|
+
"""
|
856
|
+
...
|
857
|
+
|
525
858
|
|
526
859
|
class Circle2:
|
860
|
+
"""
|
861
|
+
A class representing a circle in 2D space. The circle is defined by a center point and a radius.
|
862
|
+
"""
|
863
|
+
|
527
864
|
def __init__(self, x: float, y: float, r: float):
|
528
865
|
"""
|
529
|
-
|
530
|
-
:param x:
|
531
|
-
:param y:
|
532
|
-
:param r:
|
866
|
+
Create a circle from the given center point and radius.
|
867
|
+
:param x: the x-coordinate of the center of the circle.
|
868
|
+
:param y: the y-coordinate of the center of the circle.
|
869
|
+
:param r: the radius of the circle.
|
533
870
|
"""
|
534
871
|
...
|
535
872
|
|
536
|
-
|
537
873
|
@property
|
538
874
|
def center(self) -> Point2:
|
539
875
|
"""
|
540
|
-
Get the center of the circle.
|
876
|
+
Get the `Point2` at the center of the circle.
|
541
877
|
:return: the center of the circle.
|
542
878
|
"""
|
543
879
|
...
|
@@ -576,20 +912,36 @@ class Circle2:
|
|
576
912
|
|
577
913
|
|
578
914
|
class Arc2:
|
915
|
+
"""
|
916
|
+
An arc in 2D space. The arc is defined by a center point, a radius, a start angle, and a sweep angle.
|
917
|
+
|
918
|
+
* The center point and the radius define the circle of which the arc is part.
|
919
|
+
|
920
|
+
* The start angle is the angle in radians from the positive x-axis to the point where the arc begins. A positive
|
921
|
+
value is a counter-clockwise rotation, so a start angle of $\\pi / 2$ would start the arc at the top $y=r$ of the
|
922
|
+
circle.
|
923
|
+
|
924
|
+
* The sweep angle is the angle in radians that the arc covers, beginning at the starting point. A positive value is
|
925
|
+
a counter-clockwise rotation, a negative value is clockwise.
|
926
|
+
"""
|
927
|
+
|
579
928
|
def __init__(self, x: float, y: float, r: float, start_radians: float, sweep_radians: float):
|
580
929
|
"""
|
930
|
+
Create an arc from the given center point, radius, start angle, and sweep angle.
|
581
931
|
|
582
|
-
:param x:
|
583
|
-
:param y:
|
584
|
-
:param r:
|
585
|
-
:param start_radians:
|
586
|
-
|
932
|
+
:param x: the x-coordinate of the center of the arc.
|
933
|
+
:param y: the y-coordinate of the center of the arc.
|
934
|
+
:param r: the radius of the arc.
|
935
|
+
:param start_radians: the start angle of the arc in radians, which is the angle from the positive x-axis to the
|
936
|
+
starting point of the arc. A positive value is a counter-clockwise rotation.
|
937
|
+
:param sweep_radians: the sweep angle of the arc in radians, which is the angle that the arc covers, beginning
|
938
|
+
at the starting point. A positive value is a counter-clockwise rotation, a negative value is clockwise.
|
587
939
|
"""
|
588
940
|
|
589
941
|
@property
|
590
942
|
def center(self) -> Point2:
|
591
943
|
"""
|
592
|
-
Get the center of the arc.
|
944
|
+
Get the center point of the arc.
|
593
945
|
:return: the center of the arc.
|
594
946
|
"""
|
595
947
|
...
|
@@ -597,31 +949,31 @@ class Arc2:
|
|
597
949
|
@property
|
598
950
|
def x(self) -> float:
|
599
951
|
"""
|
600
|
-
Get the x-coordinate of the arc.
|
601
|
-
:return: the x-coordinate of the arc.
|
952
|
+
Get the x-coordinate of the center of the arc.
|
953
|
+
:return: the x-coordinate of the arc center.
|
602
954
|
"""
|
603
955
|
...
|
604
956
|
|
605
957
|
@property
|
606
958
|
def y(self) -> float:
|
607
959
|
"""
|
608
|
-
Get the y-coordinate of the arc.
|
609
|
-
:return: the y-coordinate of the arc
|
960
|
+
Get the y-coordinate of the center of the arc.
|
961
|
+
:return: the y-coordinate of the arc center
|
610
962
|
"""
|
611
963
|
...
|
612
964
|
|
613
965
|
@property
|
614
966
|
def r(self) -> float:
|
615
967
|
"""
|
616
|
-
Get the radius of the arc
|
617
|
-
:return: the radius of the arc
|
968
|
+
Get the radius of the arc
|
969
|
+
:return: the radius of the arc
|
618
970
|
"""
|
619
971
|
...
|
620
972
|
|
621
973
|
@property
|
622
974
|
def start(self) -> float:
|
623
975
|
"""
|
624
|
-
Get the start angle of the arc in radians.
|
976
|
+
Get the start angle of the arc, in radians.
|
625
977
|
:return: the start angle of the arc in radians.
|
626
978
|
"""
|
627
979
|
...
|
@@ -629,7 +981,7 @@ class Arc2:
|
|
629
981
|
@property
|
630
982
|
def sweep(self) -> float:
|
631
983
|
"""
|
632
|
-
Get the sweep angle of the arc in radians.
|
984
|
+
Get the sweep angle of the arc, in radians.
|
633
985
|
:return: the sweep angle of the arc in radians.
|
634
986
|
"""
|
635
987
|
...
|
@@ -658,14 +1010,28 @@ class Arc2:
|
|
658
1010
|
"""
|
659
1011
|
...
|
660
1012
|
|
1013
|
+
|
661
1014
|
class Aabb2:
|
662
|
-
|
1015
|
+
"""
|
1016
|
+
A class representing an axis-aligned bounding box in 2D space. The bounding box is defined by a minimum point and a
|
1017
|
+
maximum point, which are the lower-left and upper-right corners of the box, respectively.
|
1018
|
+
|
1019
|
+
Bounding boxes are typically used for accelerating intersection and distance queries and are used internally inside
|
1020
|
+
the Rust language `engeom` library for this purpose. However, they have other useful applications and so are
|
1021
|
+
exposed here in the Python API.
|
1022
|
+
|
1023
|
+
Typically, `Aabb2` objects will be retrieved from other `engeom` objects which use them internally, such as curves,
|
1024
|
+
circles, arcs, etc. However, they can also be created and manipulated directly.
|
1025
|
+
"""
|
1026
|
+
|
1027
|
+
def __init__(self, x_min: float, y_min: float, x_max: float, y_max: float):
|
663
1028
|
"""
|
1029
|
+
Create an axis-aligned bounding box from the minimum and maximum coordinates.
|
664
1030
|
|
665
|
-
:param x_min:
|
666
|
-
:param
|
667
|
-
:param
|
668
|
-
:param y_max:
|
1031
|
+
:param x_min: the minimum x-coordinate of the AABB
|
1032
|
+
:param y_min: the minimum y-coordinate of the AABB
|
1033
|
+
:param x_max: the maximum x-coordinate of the AABB
|
1034
|
+
:param y_max: the maximum y-coordinate of the AABB
|
669
1035
|
"""
|
670
1036
|
...
|
671
1037
|
|
@@ -681,6 +1047,16 @@ class Aabb2:
|
|
681
1047
|
"""
|
682
1048
|
...
|
683
1049
|
|
1050
|
+
@staticmethod
|
1051
|
+
def from_points(points: NDArray[float]) -> Aabb2:
|
1052
|
+
"""
|
1053
|
+
Create an AABB that bounds a set of points. If the point array is empty or the wrong shape, an error will be
|
1054
|
+
thrown.
|
1055
|
+
:param points: a numpy array of shape (N, 2) containing the points to bound
|
1056
|
+
:return: a new AABB object
|
1057
|
+
"""
|
1058
|
+
...
|
1059
|
+
|
684
1060
|
@property
|
685
1061
|
def min(self) -> Point2:
|
686
1062
|
"""
|
@@ -731,4 +1107,4 @@ class Aabb2:
|
|
731
1107
|
:param d: the distance to shrink the AABB by.
|
732
1108
|
:return: a new AABB object with the shrunk bounds.
|
733
1109
|
"""
|
734
|
-
...
|
1110
|
+
...
|