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/geom3.pyi
CHANGED
@@ -1,59 +1,115 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Tuple, Iterable, List, TypeVar
|
4
|
+
from typing import Tuple, Iterable, List, TypeVar, Iterator, Any
|
5
5
|
|
6
6
|
import numpy
|
7
|
-
from
|
8
|
-
|
7
|
+
from numpy.typing import NDArray
|
8
|
+
import engeom
|
9
|
+
import metrology
|
9
10
|
|
10
11
|
Transformable3 = TypeVar("Transformable3", Vector3, Point3, Plane3, Iso3, SurfacePoint3)
|
11
12
|
PointOrVector3 = TypeVar("PointOrVector3", Vector3, Point3)
|
12
13
|
|
13
14
|
|
14
|
-
class Vector3:
|
15
|
+
class Vector3(Iterable[float]):
|
16
|
+
"""
|
17
|
+
A class representing a vector in 3D space. The vector is represented by its x, y, and z components. It is
|
18
|
+
iterable and will yield the x, y, and z components in that order, allowing the Python unpacking operator `*` to be
|
19
|
+
used to compensate for the lack of function overloading in other parts of the library.
|
20
|
+
|
21
|
+
A vector supports a number of mathematical operations, including addition, subtraction, scalar multiplication,
|
22
|
+
dot and cross products, and normalization. It also supports transformation by isometry.
|
23
|
+
|
24
|
+
Vectors have different semantics than points when it comes to transformations and some mathematical operations. Be
|
25
|
+
sure to use the type which matches the conceptual use of the object in your code.
|
26
|
+
"""
|
27
|
+
|
15
28
|
def __init__(self, x: float, y: float, z: float):
|
16
29
|
"""
|
17
|
-
|
18
|
-
:param x:
|
19
|
-
:param y:
|
20
|
-
:param z:
|
30
|
+
Create a vector in 3D space by specifying the x, y, and z components.
|
31
|
+
:param x: the x component of the vector
|
32
|
+
:param y: the y component of the vector
|
33
|
+
:param z: the z component of the vector
|
21
34
|
"""
|
22
35
|
...
|
23
36
|
|
24
37
|
@property
|
25
38
|
def x(self) -> float:
|
39
|
+
"""
|
40
|
+
Get the x component of the vector as a floating point value.
|
41
|
+
"""
|
26
42
|
...
|
27
43
|
|
28
44
|
@property
|
29
45
|
def y(self) -> float:
|
46
|
+
"""
|
47
|
+
Get the y component of the vector as a floating point value.
|
48
|
+
"""
|
30
49
|
...
|
31
50
|
|
32
51
|
@property
|
33
52
|
def z(self) -> float:
|
53
|
+
"""
|
54
|
+
Get the z component of the vector as a floating point value.
|
55
|
+
"""
|
34
56
|
...
|
35
57
|
|
36
|
-
def __iter__(self) ->
|
58
|
+
def __iter__(self) -> Iterator[float]:
|
37
59
|
...
|
38
60
|
|
39
61
|
def __rmul__(self, other: float) -> Vector3:
|
62
|
+
"""
|
63
|
+
Multiply the vector by a scalar value. This allows the scalar to be on the left side of the multiplication
|
64
|
+
operator.
|
65
|
+
:param other: the scalar value to multiply the vector by.
|
66
|
+
:return: a new vector that is the result of the multiplication.
|
67
|
+
"""
|
40
68
|
...
|
41
69
|
|
42
70
|
def __add__(self, other: PointOrVector3) -> PointOrVector3:
|
71
|
+
"""
|
72
|
+
Add a vector to another vector or a point. Adding a vector to a point will return a new point, and adding a
|
73
|
+
vector to a vector will return a new vector.
|
74
|
+
:param other: the other vector or point to add to this vector.
|
75
|
+
:return: a new vector or point that is the result of the addition.
|
76
|
+
"""
|
43
77
|
...
|
44
78
|
|
45
79
|
def __sub__(self, other: Vector3) -> Vector3:
|
80
|
+
"""
|
81
|
+
Subtract another vector from this vector.
|
82
|
+
:param other: the other vector to subtract from this vector.
|
83
|
+
:return: a new vector that is the result of the subtraction.
|
84
|
+
"""
|
46
85
|
...
|
47
86
|
|
48
87
|
def __neg__(self) -> Vector3:
|
88
|
+
"""
|
89
|
+
Invert the vector by negating all of its components.
|
90
|
+
:return: a new vector in which the x, y, and z components are negated.
|
91
|
+
"""
|
49
92
|
...
|
50
93
|
|
51
|
-
def __mul__(self,
|
94
|
+
def __mul__(self, other: float) -> Vector3:
|
95
|
+
"""
|
96
|
+
Multiply the vector by a scalar value.
|
97
|
+
:param other: the scalar value to multiply the vector by.
|
98
|
+
:return: a new vector that is the result of the multiplication.
|
99
|
+
"""
|
52
100
|
...
|
53
101
|
|
54
|
-
def
|
102
|
+
def __truediv__(self, other: float) -> Vector3:
|
55
103
|
"""
|
56
|
-
|
104
|
+
Divide the vector by a scalar value.
|
105
|
+
:param other: the scalar value to divide the vector by.
|
106
|
+
:return: a new vector that is the result of the division.
|
107
|
+
"""
|
108
|
+
...
|
109
|
+
|
110
|
+
def as_numpy(self) -> NDArray[float]:
|
111
|
+
"""
|
112
|
+
Create a numpy array of shape (3, ) from the vector.
|
57
113
|
"""
|
58
114
|
...
|
59
115
|
|
@@ -75,48 +131,71 @@ class Vector3:
|
|
75
131
|
|
76
132
|
def norm(self) -> float:
|
77
133
|
"""
|
78
|
-
Calculate the norm (length) of the vector.
|
79
|
-
:return:
|
134
|
+
Calculate the Euclidian norm (aka magnitude, length) of the vector.
|
135
|
+
:return: the length of the vector as a floating point value.
|
80
136
|
"""
|
81
137
|
|
82
138
|
def normalized(self) -> Vector3:
|
83
139
|
"""
|
84
|
-
Return a normalized version of the vector.
|
140
|
+
Return a normalized version of the vector. The normalized vector will have the same direction as the original
|
141
|
+
vector, but will have a length of 1.
|
85
142
|
:return: a new vector that has unit length
|
86
143
|
"""
|
87
144
|
|
88
145
|
def angle_to(self, other: Vector3) -> float:
|
89
146
|
"""
|
90
|
-
Calculate the smallest angle between this vector and another vector.
|
147
|
+
Calculate the smallest angle between this vector and another vector and return it in radians.
|
91
148
|
:param other: the other vector to calculate the angle to.
|
92
149
|
:return: the angle between the two vectors in radians.
|
93
150
|
"""
|
94
151
|
...
|
95
152
|
|
96
153
|
|
97
|
-
class Point3:
|
154
|
+
class Point3(Iterable[float]):
|
155
|
+
"""
|
156
|
+
A class representing a point in 3D space. The point is represented by its x, y, and z coordinates. It is iterable
|
157
|
+
and will yield the x, y, and z coordinates in that order, allowing the Python unpacking operator `*` to be used to
|
158
|
+
compensate for the lack of function overloading in other parts of the library.
|
159
|
+
|
160
|
+
A point supports a number of mathematical operations, including addition and subtraction with vectors, subtraction
|
161
|
+
with other points, and scaling by a scalar value. It also supports transformation by isometry.
|
162
|
+
|
163
|
+
Points have different semantics than vectors when it comes to transformations and some mathematical operations. Be
|
164
|
+
sure to use the type which matches the conceptual use of the object in your code.
|
165
|
+
"""
|
166
|
+
|
98
167
|
def __init__(self, x: float, y: float, z: float):
|
99
168
|
"""
|
169
|
+
Create a point in 3D space by specifying the x, y, and z coordinates.
|
100
170
|
|
101
|
-
:param x:
|
102
|
-
:param y:
|
103
|
-
:param z:
|
171
|
+
:param x: the x coordinate of the point
|
172
|
+
:param y: the y coordinate of the point
|
173
|
+
:param z: the z coordinate of the point
|
104
174
|
"""
|
105
175
|
...
|
106
176
|
|
107
177
|
@property
|
108
178
|
def x(self) -> float:
|
179
|
+
"""
|
180
|
+
Get the x coordinate of the point as a floating point value.
|
181
|
+
"""
|
109
182
|
...
|
110
183
|
|
111
184
|
@property
|
112
185
|
def y(self) -> float:
|
186
|
+
"""
|
187
|
+
Get the y coordinate of the point as a floating point value.
|
188
|
+
"""
|
113
189
|
...
|
114
190
|
|
115
191
|
@property
|
116
192
|
def z(self) -> float:
|
193
|
+
"""
|
194
|
+
Get the z coordinate of the point as a floating point value.
|
195
|
+
"""
|
117
196
|
...
|
118
197
|
|
119
|
-
def __iter__(self) ->
|
198
|
+
def __iter__(self) -> Iterator[float]:
|
120
199
|
...
|
121
200
|
|
122
201
|
@property
|
@@ -128,28 +207,82 @@ class Point3:
|
|
128
207
|
...
|
129
208
|
|
130
209
|
def __sub__(self, other: PointOrVector3) -> PointOrVector3:
|
210
|
+
"""
|
211
|
+
Subtract a vector from a point to get a new point, or subtract a point from a point to get a new vector.
|
212
|
+
:param other: the other point or vector to subtract from this point.
|
213
|
+
:return: a new point or vector that is the result of the subtraction.
|
214
|
+
"""
|
131
215
|
...
|
132
216
|
|
133
217
|
def __add__(self, other: Vector3) -> Vector3:
|
218
|
+
"""
|
219
|
+
Add a vector to a point to get a new point.
|
220
|
+
:param other: the vector to add to this point.
|
221
|
+
:return: a new point that is the result of the addition.
|
222
|
+
"""
|
134
223
|
...
|
135
224
|
|
136
|
-
def
|
225
|
+
def __neg__(self) -> Point3:
|
137
226
|
"""
|
138
|
-
|
227
|
+
Invert the point by negating all of its components.
|
228
|
+
:return: a new point in which the x, y, and z components are negated
|
229
|
+
"""
|
230
|
+
...
|
231
|
+
|
232
|
+
def __mul__(self, other: float) -> Point3:
|
233
|
+
"""
|
234
|
+
Multiply the coordinates of the point by a scalar value.
|
235
|
+
:param other: the scalar value to multiply the point by.
|
236
|
+
:return: a new point that is the result of the multiplication.
|
237
|
+
"""
|
238
|
+
...
|
239
|
+
|
240
|
+
def __rmul__(self, other: float) -> Point3:
|
241
|
+
"""
|
242
|
+
Multiply the coordinates of the point by a scalar value. This allows the scalar to be on the left side of the
|
243
|
+
multiplication operator.
|
244
|
+
:param other: the scalar value to multiply the point by.
|
245
|
+
:return: a new point that is the result of the multiplication.
|
246
|
+
"""
|
247
|
+
...
|
248
|
+
|
249
|
+
def __truediv__(self, other: float) -> Point3:
|
250
|
+
"""
|
251
|
+
Divide the coordinates of the point by a scalar value.
|
252
|
+
:param other: the scalar value to divide the point by.
|
253
|
+
:return: a new point that is the result of the division.
|
254
|
+
"""
|
255
|
+
...
|
256
|
+
|
257
|
+
def as_numpy(self) -> NDArray[float]:
|
258
|
+
"""
|
259
|
+
Create a numpy array of shape (2, ) from the point.
|
139
260
|
"""
|
140
261
|
...
|
141
262
|
|
142
263
|
|
143
264
|
class SurfacePoint3:
|
265
|
+
"""
|
266
|
+
This class is used to represent a surface point in 3D space.
|
267
|
+
|
268
|
+
Surface points are a composite structure that consist of a point in space and a normal direction. Conceptually, they
|
269
|
+
come from metrology as a means of representing a point on the surface of an object along with the normal direction
|
270
|
+
of the surface at that point. However, they are also isomorphic with the concept of a ray or a parameterized line
|
271
|
+
with a direction of unit length, and can be used in that way as well.
|
272
|
+
"""
|
273
|
+
|
144
274
|
def __init__(self, x: float, y: float, z: float, nx: float, ny: float, nz: float):
|
145
275
|
"""
|
276
|
+
Create a surface point in 3D space by specifying the x, y, and z coordinates of the point, as well as the x, y,
|
277
|
+
and z components of the normal vector. The normal components will be normalized before being stored, so they
|
278
|
+
do not need to be scaled to unit length before being passed to this constructor.
|
146
279
|
|
147
|
-
:param x:
|
148
|
-
:param y:
|
149
|
-
:param z:
|
150
|
-
:param nx:
|
151
|
-
:param ny:
|
152
|
-
:param nz:
|
280
|
+
:param x: the x coordinate of the point
|
281
|
+
:param y: the y coordinate of the point
|
282
|
+
:param z: the z coordinate of the point
|
283
|
+
:param nx: the x component of the normal vector (will be normalized after construction)
|
284
|
+
:param ny: the y component of the normal vector (will be normalized after construction)
|
285
|
+
:param nz: the z component of the normal vector (will be normalized after construction)
|
153
286
|
"""
|
154
287
|
...
|
155
288
|
|
@@ -223,12 +356,60 @@ class SurfacePoint3:
|
|
223
356
|
"""
|
224
357
|
...
|
225
358
|
|
359
|
+
def __mul__(self, other: float) -> SurfacePoint3:
|
360
|
+
"""
|
361
|
+
Multiply the position of the surface point by a scalar value. The normal vector is not affected unless the
|
362
|
+
scalar is negative, in which case the normal vector is inverted.
|
363
|
+
:param other:
|
364
|
+
:return:
|
365
|
+
"""
|
366
|
+
...
|
367
|
+
|
368
|
+
def __rmul__(self, other: float) -> SurfacePoint3:
|
369
|
+
"""
|
370
|
+
Multiply the position of the surface point by a scalar value. The normal vector is not affected unless the
|
371
|
+
scalar is negative, in which case the normal vector is inverted.
|
372
|
+
:param other:
|
373
|
+
:return:
|
374
|
+
"""
|
375
|
+
...
|
376
|
+
|
377
|
+
def __truediv__(self, other: float) -> SurfacePoint3:
|
378
|
+
"""
|
379
|
+
Divide the position of the surface point by a scalar value. The normal vector is not affected unless the
|
380
|
+
scalar is negative, in which case the normal vector is inverted.
|
381
|
+
:param other:
|
382
|
+
:return:
|
383
|
+
"""
|
384
|
+
...
|
385
|
+
|
386
|
+
def __neg__(self) -> SurfacePoint3:
|
387
|
+
"""
|
388
|
+
Invert both the position AND the normal vector of the surface point.
|
389
|
+
"""
|
390
|
+
...
|
391
|
+
|
226
392
|
|
227
393
|
class Iso3:
|
228
|
-
"""
|
394
|
+
"""
|
395
|
+
A class representing an isometry in 3D space. An isometry is a transformation that preserves distances and angles,
|
396
|
+
and is also sometimes known as a rigid body transformation. It is composed of a translation and a rotation, with
|
397
|
+
the rotation part being internally represented by a unit quaternion.
|
229
398
|
|
230
|
-
|
231
|
-
|
399
|
+
`Iso3` objects can be used to transform 3D points, vectors, surface points, other isometries, and a few other types
|
400
|
+
of objects. They can also be inverted and decomposed.
|
401
|
+
"""
|
402
|
+
|
403
|
+
def __init__(self, matrix: NDArray[float]):
|
404
|
+
"""
|
405
|
+
Attempt to create an isometry from a 4x4 matrix in the form of a numpy array. If the matrix is not a valid
|
406
|
+
isometry (it is not orthogonal, it has scale or shear, etc.), an exception will be raised.
|
407
|
+
|
408
|
+
Use this method if you explicitly have a known matrix to convert to an isometry, otherwise consider using a
|
409
|
+
composition of the `from_translation` and `from_rotation` methods.
|
410
|
+
|
411
|
+
:param matrix: a numpy array of shape (4, 4) containing the matrix representation of the isometry.
|
412
|
+
"""
|
232
413
|
...
|
233
414
|
|
234
415
|
@staticmethod
|
@@ -238,18 +419,28 @@ class Iso3:
|
|
238
419
|
|
239
420
|
@staticmethod
|
240
421
|
def from_translation(x: float, y: float, z: float) -> Iso3:
|
241
|
-
"""
|
422
|
+
"""
|
423
|
+
Create an isometry representing a translation by the specified x, y, and z components.
|
424
|
+
:param x: the x component of the translation.
|
425
|
+
:param y: the y component of the translation.
|
426
|
+
:param z: the z component of the translation.
|
427
|
+
:return: an isometry containing only a translation component
|
428
|
+
"""
|
242
429
|
...
|
243
430
|
|
244
431
|
@staticmethod
|
245
|
-
def from_rotation(angle: float,
|
432
|
+
def from_rotation(angle: float, ax: float, ay: float, az: float) -> Iso3:
|
246
433
|
"""
|
247
|
-
Create an isometry representing a rotation around an axis
|
248
|
-
applied.
|
434
|
+
Create an isometry representing a rotation around an axis defined by a vector direction and the origin. The
|
435
|
+
components of the direction will be automatically normalized before the rotation applied.
|
436
|
+
|
437
|
+
When looking down the axis of rotation (the axis is pointing towards the observer), the rotation will be
|
438
|
+
counter-clockwise.
|
439
|
+
|
249
440
|
:param angle: the angle to rotate by in radians.
|
250
|
-
:param
|
251
|
-
:param
|
252
|
-
:param
|
441
|
+
:param ax: the x component of the rotation axis.
|
442
|
+
:param ay: the y component of the rotation axis.
|
443
|
+
:param az: the z component of the rotation axis.
|
253
444
|
:return: the isometry representing the rotation.
|
254
445
|
"""
|
255
446
|
...
|
@@ -263,64 +454,93 @@ class Iso3:
|
|
263
454
|
...
|
264
455
|
|
265
456
|
def inverse(self) -> Iso3:
|
266
|
-
"""
|
457
|
+
"""
|
458
|
+
Get the inverse of the isometry. The inverse is the isometry that will undo the transformation of the original
|
459
|
+
isometry, or the isometry that when applied to the original isometry will return the identity isometry.
|
460
|
+
"""
|
267
461
|
...
|
268
462
|
|
269
|
-
def transform_points(self, points:
|
270
|
-
"""
|
271
|
-
of the isometry.
|
463
|
+
def transform_points(self, points: NDArray[float]) -> NDArray[float]:
|
464
|
+
"""
|
465
|
+
Transform an array of points using the isometry. The semantics of transforming points are such that the full
|
466
|
+
matrix is applied, first rotating the point around the origin and then translating it by the translation vector.
|
467
|
+
|
468
|
+
To transform vectors, use the `transform_vectors` method instead.
|
272
469
|
|
273
|
-
|
274
|
-
|
470
|
+
This is an efficient way to transform a large number of points at once, rather than using the `@` operator
|
471
|
+
individually on a large number of `Point3` objects.
|
472
|
+
|
473
|
+
:param points: a numpy array of shape (N, 3)
|
474
|
+
:return: a numpy array of shape (N, 3) containing the transformed points in the same order as the input.
|
275
475
|
"""
|
276
476
|
...
|
277
477
|
|
278
|
-
def transform_vectors(self,
|
279
|
-
"""
|
280
|
-
|
478
|
+
def transform_vectors(self, vectors: NDArray[float]) -> NDArray[float]:
|
479
|
+
"""
|
480
|
+
Transform an array of vectors using the isometry. The semantics of transforming vectors are such that only the
|
481
|
+
rotation matrix is applied, and the translation vector is not used. The vectors retain their original
|
482
|
+
magnitude, but their direction is rotated by the isometry.
|
483
|
+
|
484
|
+
To transform points, use the `transform_points` method instead.
|
281
485
|
|
282
|
-
|
283
|
-
|
486
|
+
This is an efficient way to transform a large number of vectors at once, rather than using the `@` operator
|
487
|
+
individually on a large number of `Vector3` objects.
|
488
|
+
|
489
|
+
:param vectors: a numpy array of shape (N, 3)
|
490
|
+
:return: a numpy array of shape (N, 3) containing the transformed vectors in the same order as the input.
|
284
491
|
"""
|
285
492
|
...
|
286
493
|
|
287
|
-
def as_numpy(self) ->
|
288
|
-
"""
|
494
|
+
def as_numpy(self) -> NDArray[float]:
|
495
|
+
"""
|
496
|
+
Return a copy of the 4x4 matrix representation of the isometry.
|
497
|
+
"""
|
289
498
|
...
|
290
499
|
|
291
500
|
def flip_around_x(self) -> Iso3:
|
292
|
-
"""
|
293
|
-
|
501
|
+
"""
|
502
|
+
Return a new isometry that flips the isometry 180° around the x-axis. The origin of the isometry will be
|
503
|
+
preserved, but the y and z axes will point in the opposite directions.
|
504
|
+
:return: a new isometry that is the result of the flip.
|
505
|
+
"""
|
294
506
|
...
|
295
507
|
|
296
508
|
def flip_around_y(self) -> Iso3:
|
297
|
-
"""
|
298
|
-
|
509
|
+
"""
|
510
|
+
Return a new isometry that flips the isometry 180° around the y-axis. The origin of the isometry will be
|
511
|
+
preserved, but the x and z axes will point in the opposite directions.
|
512
|
+
:return: a new isometry that is the result of the flip.
|
513
|
+
"""
|
299
514
|
...
|
300
515
|
|
301
516
|
def flip_around_z(self) -> Iso3:
|
302
|
-
"""
|
303
|
-
|
517
|
+
"""
|
518
|
+
Return a new isometry that flips the isometry 180° around the z-axis. The origin of the isometry will be
|
519
|
+
preserved, but the x and y axes will point in the opposite directions.
|
520
|
+
:return: a new isometry that is the result of the flip.
|
521
|
+
"""
|
304
522
|
...
|
305
523
|
|
306
524
|
|
307
525
|
class SvdBasis3:
|
308
526
|
"""
|
309
|
-
A class
|
310
|
-
|
527
|
+
A class which creates a set of orthonormal basis vectors from a set of points in 3D space. The basis is created
|
528
|
+
using a singular value decomposition of the points, and is very similar to the statistical concept of principal
|
529
|
+
component analysis.
|
530
|
+
|
531
|
+
The basis can be used to determine the rank of the point set, the variance of the points along the basis vectors,
|
532
|
+
and to extract an isometry that will transform points from the world space to the basis space. It is useful for
|
533
|
+
orienting unknown point sets in a consistent way, for finding best-fit lines or planes, and for other similar
|
534
|
+
tasks.
|
311
535
|
"""
|
312
536
|
|
313
|
-
def __init__(
|
314
|
-
self,
|
315
|
-
points: numpy.ndarray[float],
|
316
|
-
weights: numpy.ndarray[float] | None = None
|
317
|
-
):
|
537
|
+
def __init__(self, points: NDArray[float], weights: NDArray[float] | None = None):
|
318
538
|
"""
|
319
539
|
Create a basis from a set of points. The basis will be calculated using a singular value decomposition of the
|
320
540
|
points.
|
321
541
|
|
322
542
|
:param points: a numpy array of shape (n, 3) containing the points to calculate the basis from.
|
323
|
-
:param weights: a numpy array of shape (n,) containing the weights of the points. If None, all points will be
|
543
|
+
:param weights: a numpy array of shape (n, ) containing the weights of the points. If None, all points will be
|
324
544
|
weighted equally.
|
325
545
|
"""
|
326
546
|
...
|
@@ -335,31 +555,31 @@ class SvdBasis3:
|
|
335
555
|
"""
|
336
556
|
...
|
337
557
|
|
338
|
-
def largest(self) ->
|
558
|
+
def largest(self) -> Vector3:
|
339
559
|
"""
|
340
560
|
Return the largest normalized basis vector.
|
341
|
-
:return: a
|
561
|
+
:return: a Vector3 object containing the largest basis vector.
|
342
562
|
"""
|
343
563
|
...
|
344
564
|
|
345
|
-
def smallest(self) ->
|
565
|
+
def smallest(self) -> Vector3:
|
346
566
|
"""
|
347
567
|
Return the smallest normalized basis vector.
|
348
|
-
:return: a
|
568
|
+
:return: a Vector3 object containing the smallest basis vector.
|
349
569
|
"""
|
350
570
|
...
|
351
571
|
|
352
|
-
def basis_variances(self) ->
|
572
|
+
def basis_variances(self) -> NDArray[float]:
|
353
573
|
"""
|
354
574
|
Return the variances of the basis vectors.
|
355
|
-
:return: a numpy array of shape (3,) containing the variances of the basis vectors.
|
575
|
+
:return: a numpy array of shape (3, ) containing the variances of the basis vectors.
|
356
576
|
"""
|
357
577
|
...
|
358
578
|
|
359
|
-
def basis_stdevs(self) ->
|
579
|
+
def basis_stdevs(self) -> NDArray[float]:
|
360
580
|
"""
|
361
581
|
Return the standard deviations of the basis vectors.
|
362
|
-
:return: a numpy array of shape (3,) containing the standard deviations of the basis vectors.
|
582
|
+
:return: a numpy array of shape (3, ) containing the standard deviations of the basis vectors.
|
363
583
|
"""
|
364
584
|
...
|
365
585
|
|
@@ -434,8 +654,8 @@ class Mesh:
|
|
434
654
|
|
435
655
|
def __init__(
|
436
656
|
self,
|
437
|
-
vertices:
|
438
|
-
faces:
|
657
|
+
vertices: NDArray[float],
|
658
|
+
faces: NDArray[numpy.uint32],
|
439
659
|
merge_duplicates: bool = False,
|
440
660
|
delete_degenerate: bool = False
|
441
661
|
):
|
@@ -445,6 +665,10 @@ class Mesh:
|
|
445
665
|
triangle. The triangles should be specified in counter-clockwise order when looking at the triangle from the
|
446
666
|
front/outside.
|
447
667
|
|
668
|
+
!!! tip
|
669
|
+
If you get an error `TypeError: argument 'faces': 'ndarray' object cannot be converted to 'PyArray<T, D>'`,
|
670
|
+
make sure to convert the faces array to an unsigned integer type, e.g. `numpy.uint32`.
|
671
|
+
|
448
672
|
:param vertices: a numpy array of shape (n, 3) containing the vertices of the mesh.
|
449
673
|
:param faces: a numpy array of shape (m, 3) containing the triangles of the mesh, should be uint.
|
450
674
|
:param merge_duplicates: merge duplicate vertices and triangles
|
@@ -454,7 +678,7 @@ class Mesh:
|
|
454
678
|
|
455
679
|
@property
|
456
680
|
def aabb(self) -> Aabb3:
|
457
|
-
"""
|
681
|
+
""" Get the axis-aligned bounding box of the mesh. """
|
458
682
|
...
|
459
683
|
|
460
684
|
@staticmethod
|
@@ -464,6 +688,11 @@ class Mesh:
|
|
464
688
|
file. Optional parameters can be used to control the behavior of the loader when handling duplicate vertices/
|
465
689
|
triangles and degenerate triangles.
|
466
690
|
|
691
|
+
!!! note
|
692
|
+
The STL loader will automatically merge duplicate vertices due to the extreme redundancy of the STL format,
|
693
|
+
but the `merge_duplicates` flag will control whether to merge vertices when new meshes are appended to the
|
694
|
+
existing mesh.
|
695
|
+
|
467
696
|
:param path: the path to the STL file to load.
|
468
697
|
:param merge_duplicates: merge duplicate vertices and triangles. If None, the default behavior is to do nothing
|
469
698
|
:param delete_degenerate: delete degenerate triangles. If None, the default behavior is to do nothing
|
@@ -485,7 +714,7 @@ class Mesh:
|
|
485
714
|
Will return a copy of the mesh. This is a copy of the data, so modifying the returned mesh will not modify the
|
486
715
|
original mesh.
|
487
716
|
|
488
|
-
:return:
|
717
|
+
:return: an independent copy of the mesh.
|
489
718
|
"""
|
490
719
|
|
491
720
|
def transform_by(self, iso: Iso3):
|
@@ -493,7 +722,6 @@ class Mesh:
|
|
493
722
|
Transforms the vertices of the mesh by an isometry. This will modify the mesh in place. Any copies made of
|
494
723
|
the vertices will no longer match the mesh after this operation.
|
495
724
|
:param iso: the isometry to transform the mesh by.
|
496
|
-
:return: None
|
497
725
|
"""
|
498
726
|
...
|
499
727
|
|
@@ -502,12 +730,15 @@ class Mesh:
|
|
502
730
|
Append another mesh to this mesh. This will add the vertices and triangles from the other mesh to this mesh,
|
503
731
|
changing this one and leaving the other one unmodified.
|
504
732
|
|
733
|
+
The `merge_duplicates` and `delete_degenerate` flags will control whether to merge duplicate vertices/triangles
|
734
|
+
and delete degenerate triangles when appending the mesh.
|
735
|
+
|
505
736
|
:param other: the mesh to append to this mesh, will not be modified in this operation
|
506
737
|
"""
|
507
738
|
...
|
508
739
|
|
509
740
|
@property
|
510
|
-
def vertices(self) ->
|
741
|
+
def vertices(self) -> NDArray[float]:
|
511
742
|
"""
|
512
743
|
Will return an immutable view of the vertices of the mesh as a numpy array of shape (n, 3).
|
513
744
|
:return: a numpy array of shape (n, 3) containing the vertices of the mesh.
|
@@ -515,7 +746,7 @@ class Mesh:
|
|
515
746
|
...
|
516
747
|
|
517
748
|
@property
|
518
|
-
def faces(self) ->
|
749
|
+
def faces(self) -> NDArray[numpy.uint32]:
|
519
750
|
"""
|
520
751
|
Will return an immutable view of the triangles of the mesh as a numpy array of shape (m, 3).
|
521
752
|
:return: a numpy array of shape (m, 3) containing the triangles of the mesh.
|
@@ -525,30 +756,42 @@ class Mesh:
|
|
525
756
|
def split(self, plane: Plane3) -> Tuple[Mesh | None, Mesh | None]:
|
526
757
|
"""
|
527
758
|
Split the mesh by a plane. The plane will divide the mesh into two possible parts and return them as two new
|
528
|
-
objects. If the part lies entirely on one side of the plane, the other part will be None
|
759
|
+
objects. If the part lies entirely on one side of the plane, the other part will be `None`.
|
529
760
|
|
530
761
|
:param plane: the plane to split the mesh by.
|
531
762
|
|
532
|
-
:return: a tuple of two optional meshes, the first being that on the negative side of the plane, the second
|
533
|
-
that on the positive side of the plane.
|
763
|
+
:return: a tuple of two optional meshes, the first being that on the negative side of the plane, the second
|
764
|
+
being that on the positive side of the plane.
|
534
765
|
"""
|
535
766
|
...
|
536
767
|
|
537
|
-
def deviation(self, points:
|
768
|
+
def deviation(self, points: NDArray[float], mode: engeom.DeviationMode) -> NDArray[float]:
|
538
769
|
"""
|
539
|
-
Calculate the deviation between a set of points and their respective closest points on the mesh surface.
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
770
|
+
Calculate the deviation between a set of points and their respective closest points on the mesh surface.
|
771
|
+
There are two possible modes of computing the distance, specified using the `DeviationMode` enum. The two
|
772
|
+
modes are essentially the same except for how they treat points which are beyond the edge of the closest face.
|
773
|
+
|
774
|
+
- `DeviationMode.Point`: The deviation is calculated as the direct distance from the test point to the closest
|
775
|
+
point on the face.
|
776
|
+
|
777
|
+
- `DeviationMode.Plane`: The deviation is calculated as the distance from the test point to the plane of the
|
778
|
+
face on which the closest point lies. This allows for points that are slightly beyond the edge of the closest
|
779
|
+
face to have a deviation which would be the same as if the edge of the face extended to beyond the test point.
|
780
|
+
|
781
|
+
In both cases, the deviation will be positive if the point is outside the surface and negative if the point is
|
782
|
+
inside the surface.
|
783
|
+
|
784
|
+
This is a means of efficiently calculating the deviation of a large number of points from a mesh surface. For
|
785
|
+
a single point, the `measure_point_deviation` method will provide a `Distance3` result, which is more suitable
|
786
|
+
for visualization and reporting.
|
544
787
|
|
545
788
|
:param points: a numpy array of shape (n, 3) containing the points to calculate the deviation for.
|
546
789
|
:param mode: the mode to calculate the deviation in.
|
547
|
-
:return: a numpy array of shape (n,) containing the deviation for each point.
|
790
|
+
:return: a numpy array of shape (n, ) containing the deviation for each point.
|
548
791
|
"""
|
549
792
|
...
|
550
793
|
|
551
|
-
def sample_poisson(self, radius: float) ->
|
794
|
+
def sample_poisson(self, radius: float) -> NDArray[float]:
|
552
795
|
"""
|
553
796
|
Sample the surface of the mesh using a Poisson disk sampling algorithm. This will return a numpy array of points
|
554
797
|
and their normals that are approximately evenly distributed across the surface of the mesh. The radius parameter
|
@@ -568,13 +811,14 @@ class Mesh:
|
|
568
811
|
"""
|
569
812
|
Calculate and return the intersection curves between the mesh and a plane.
|
570
813
|
|
571
|
-
:param plane:
|
572
|
-
:param tol:
|
573
|
-
|
814
|
+
:param plane: The plane to intersect the mesh with.
|
815
|
+
:param tol: The curve tolerance to use when constructing the intersection curves. See the `Curve3` class
|
816
|
+
initializer for more information on the tolerance parameter.
|
817
|
+
:return: a list of `Curve3` objects representing the intersection curves.
|
574
818
|
"""
|
575
819
|
...
|
576
820
|
|
577
|
-
def face_select_none(self) ->
|
821
|
+
def face_select_none(self) -> FaceFilterHandle:
|
578
822
|
"""
|
579
823
|
Start a filter operation on the faces of the mesh beginning with no faces selected. This will return a filter
|
580
824
|
object that can be used to further add or remove faces from the selection.
|
@@ -583,7 +827,7 @@ class Mesh:
|
|
583
827
|
"""
|
584
828
|
...
|
585
829
|
|
586
|
-
def face_select_all(self) ->
|
830
|
+
def face_select_all(self) -> FaceFilterHandle:
|
587
831
|
"""
|
588
832
|
Start a filter operation on the faces of the mesh beginning with all faces selected. This will return a filter
|
589
833
|
object that can be used to further add or remove faces from the selection.
|
@@ -597,7 +841,7 @@ class Mesh:
|
|
597
841
|
Separate the mesh into connected patches. This will return a list of new mesh objects, each containing one
|
598
842
|
connected patch of the original mesh. These objects will be clones of the original mesh, so modifying them will
|
599
843
|
have no effect on the original mesh.
|
600
|
-
:return:
|
844
|
+
:return: a list of new mesh objects containing the connected patches.
|
601
845
|
"""
|
602
846
|
|
603
847
|
def create_from_indices(self, indices: List[int]) -> Mesh:
|
@@ -606,36 +850,76 @@ class Mesh:
|
|
606
850
|
triangles (and their respective vertices) identified by the given list of indices. Do not allow duplicate
|
607
851
|
indices in the list.
|
608
852
|
:param indices: the triangle indices to include in the new mesh
|
609
|
-
:return:
|
853
|
+
:return: a new mesh object containing only the specified triangles
|
610
854
|
"""
|
611
855
|
...
|
612
856
|
|
613
|
-
def measure_point_deviation(self, x: float, y: float, z: float,
|
857
|
+
def measure_point_deviation(self, x: float, y: float, z: float,
|
858
|
+
dist_mode: engeom.DeviationMode) -> metrology.Distance3:
|
614
859
|
"""
|
615
860
|
Compute the deviation of a point from this mesh's surface and return it as a measurement object.
|
616
861
|
|
617
|
-
The deviation is the distance from the point to its closest projection onto the mesh using
|
618
|
-
|
619
|
-
|
620
|
-
projection point.
|
862
|
+
The deviation is the distance from the point to its closest projection onto the mesh using the specified
|
863
|
+
distance mode. The direction of the measurement is the direction between the point and the projection,
|
864
|
+
flipped so that it points in the same direction as the mesh surface normal.
|
621
865
|
|
622
|
-
If the distance is less than a very small floating point epsilon, the direction will be
|
623
|
-
|
866
|
+
If the distance is less than a very small floating point epsilon, the direction will be taken directly from the
|
867
|
+
mesh surface normal.
|
624
868
|
|
625
|
-
The first point `.a` of the measurement is the
|
626
|
-
|
869
|
+
The first point `.a` of the measurement is the point on the mesh, and the second point `.b` is the test point
|
870
|
+
that was given as an argument.
|
871
|
+
|
872
|
+
There are two possible modes of computing the distance, specified using the `DeviationMode` enum. The two
|
873
|
+
modes are essentially the same except for how they treat points which are beyond the edge of the closest face.
|
874
|
+
|
875
|
+
- `DeviationMode.Point`: The deviation is calculated as the direct distance from the test point to the closest
|
876
|
+
point on the face.
|
877
|
+
|
878
|
+
- `DeviationMode.Plane`: The deviation is calculated as the distance from the test point to the plane of the
|
879
|
+
face on which the closest point lies. This allows for points that are slightly beyond the edge of the closest
|
880
|
+
face to have a deviation which would be the same as if the edge of the face extended to beyond the test point.
|
881
|
+
|
882
|
+
In both cases, the deviation will be positive if the point is outside the surface and negative if the point is
|
883
|
+
inside the surface.
|
884
|
+
|
885
|
+
This method is appropriate for measuring the deviation at a few points of interest, returning a rich object
|
886
|
+
that contains features to aid in visualization or analysis. For bulk measurement of large numbers of points,
|
887
|
+
use the `deviation` method instead.
|
627
888
|
|
628
889
|
:param x: the x component of the point to measure
|
629
890
|
:param y: the y component of the point to measure
|
630
891
|
:param z: the z component of the point to measure
|
631
892
|
:param dist_mode: the deviation mode to use
|
632
|
-
:return:
|
893
|
+
:return: a `Distance3` object containing the deviation measurement
|
633
894
|
"""
|
634
895
|
|
635
|
-
def boundary_first_flatten(self) ->
|
896
|
+
def boundary_first_flatten(self) -> NDArray[float]:
|
636
897
|
"""
|
898
|
+
This method will perform a conformal mapping of the mesh to the XY plane using the boundary-first flattening
|
899
|
+
algorithm developed by Crane et al. This mapping attempts to preserve angles from the original mesh to the
|
900
|
+
flattened mesh, and is useful for applications such as texture mapping or transformation to an image/raster
|
901
|
+
space for analysis.
|
637
902
|
|
638
|
-
:
|
903
|
+
There are a number of limitations to this method based on the implementation:
|
904
|
+
|
905
|
+
* There can be no non-manifold edges in the mesh. Non-manifold edges are edges that have more than two faces
|
906
|
+
connected to them. If there are non-manifold edges, the method will raise an exception.
|
907
|
+
|
908
|
+
* There must be a single patch (sets of faces connected by common edges) in the mesh. If there are multiple
|
909
|
+
patches, the method will raise an exception.
|
910
|
+
|
911
|
+
* There can be only one boundary loop in the mesh, meaning that there can be no holes. If there are holes, the
|
912
|
+
method will raise an exception.
|
913
|
+
|
914
|
+
The method will return a numpy array of shape (n, 2) containing the flattened vertices of the mesh in the XY
|
915
|
+
plane. There is no specific orientation or position guarantee to the output vertices, so they may need to be
|
916
|
+
transformed, scaled, and/or rotated to fit a specific application.
|
917
|
+
|
918
|
+
The 2D vertices in the output will be in the exact same order as those in the mesh and will have a 1:1
|
919
|
+
correspondence by index, meaning that the `faces` array from the mesh also describes the triangles in the
|
920
|
+
flattened output.
|
921
|
+
|
922
|
+
:return: a numpy array of shape (n, 2) containing the flattened vertices of the mesh.
|
639
923
|
"""
|
640
924
|
|
641
925
|
def surface_closest_to(self, x: float, y: float, z: float) -> SurfacePoint3:
|
@@ -650,11 +934,21 @@ class Mesh:
|
|
650
934
|
...
|
651
935
|
|
652
936
|
|
653
|
-
class
|
937
|
+
class FaceFilterHandle:
|
938
|
+
"""
|
939
|
+
A class that acts as a handle to a filtering (selection/deselection) operation of faces on a mesh.
|
940
|
+
|
941
|
+
A filtering operation is started using the `face_select_all` or `face_select_none` methods on a `Mesh` object, and
|
942
|
+
then further filtering operations can be done on the handle to select or deselect faces based on various criteria.
|
943
|
+
|
944
|
+
Once finished, the handle can be finalized into a list of the final indices of the triangles that passed the filter,
|
945
|
+
or used to directly create a new mesh containing only the filtered triangles.
|
946
|
+
"""
|
947
|
+
|
654
948
|
def collect(self) -> List[int]:
|
655
949
|
"""
|
656
|
-
|
657
|
-
:return:
|
950
|
+
Finalize the handle by collecting the final indices of the triangles that passed the filter.
|
951
|
+
:return: a list of the final indices of the triangles that passed the filter.
|
658
952
|
"""
|
659
953
|
...
|
660
954
|
|
@@ -662,19 +956,23 @@ class MeshTriangleFilter:
|
|
662
956
|
"""
|
663
957
|
Create a new mesh from the filtered triangles. This will build a new mesh object containing only the triangles
|
664
958
|
(and their respective vertices) that are still retained in the filter.
|
665
|
-
:return:
|
959
|
+
:return: a new mesh object containing only the filtered triangles.
|
666
960
|
"""
|
667
961
|
...
|
668
962
|
|
669
|
-
def facing(self, x: float, y: float, z: float, angle: float, mode: SelectOp) ->
|
963
|
+
def facing(self, x: float, y: float, z: float, angle: float, mode: engeom.SelectOp) -> FaceFilterHandle:
|
670
964
|
"""
|
965
|
+
Add, remove, or keep only the faces whose normals are facing a given direction within a certain angle tolerance.
|
671
966
|
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
:param
|
676
|
-
:param
|
677
|
-
:
|
967
|
+
This method will alter the filter handle object in place and return `self` to allow for the use of a fluent-like
|
968
|
+
interface if desired.
|
969
|
+
|
970
|
+
:param x: the x component of the direction to check against
|
971
|
+
:param y: the y component of the direction to check against
|
972
|
+
:param z: the z component of the direction to check against
|
973
|
+
:param angle: the maximum angle in radians between the face normal and the filter direction
|
974
|
+
:param mode: the operation to perform on the faces, one of `SelectOp.Add`, `SelectOp.Remove`, or `SelectOp.Keep`
|
975
|
+
:return: the altered filter handle object
|
678
976
|
"""
|
679
977
|
...
|
680
978
|
|
@@ -683,28 +981,28 @@ class MeshTriangleFilter:
|
|
683
981
|
other: Mesh,
|
684
982
|
all_points: bool,
|
685
983
|
distance_tol: float,
|
686
|
-
mode: SelectOp,
|
984
|
+
mode: engeom.SelectOp,
|
687
985
|
planar_tol: float | None = None,
|
688
986
|
angle_tol: float | None = None,
|
689
|
-
) ->
|
987
|
+
) -> FaceFilterHandle:
|
690
988
|
"""
|
691
|
-
|
692
|
-
|
693
|
-
triangle are within the tolerance, or just one.
|
989
|
+
Add, remove, or keep only the faces that are within a certain distance of their closest projection onto another
|
990
|
+
mesh. The distance can require that all three vertices of the triangle are within the tolerance, or just one.
|
694
991
|
|
695
992
|
There are two additional optional tolerances that can be applied.
|
696
993
|
|
697
|
-
1. A planar tolerance, which checks the distance of the vertex projected onto the plane of
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
are not facing the same direction as the
|
994
|
+
1. A planar tolerance, which checks the distance of the vertex projected onto the plane of the reference mesh
|
995
|
+
triangle and looks at how far it is from the projection point. This is useful to filter out triangles
|
996
|
+
that go past the edge of the reference mesh.
|
997
|
+
|
998
|
+
2. An angle tolerance, which checks the angle between the normal of the current triangle and the normal of the
|
999
|
+
reference triangle. This is useful to filter out triangles that are not facing the same direction as the
|
1000
|
+
reference mesh.
|
703
1001
|
|
704
1002
|
:param other: the mesh to use as a reference
|
705
1003
|
:param all_points: if True, all points of the triangle must be within the tolerance, if False, only one point
|
706
1004
|
:param distance_tol: the maximum distance between the triangle and its projection onto the reference mesh
|
707
|
-
:param mode:
|
1005
|
+
:param mode: the operation to perform on the faces, one of `SelectOp.Add`, `SelectOp.Remove`, or `SelectOp.Keep`
|
708
1006
|
:param planar_tol: the maximum in-plane distance between the triangle and its projection onto the reference mesh
|
709
1007
|
:param angle_tol: the maximum angle between the normals of the triangle and the reference mesh
|
710
1008
|
"""
|
@@ -715,16 +1013,25 @@ class CurveStation3:
|
|
715
1013
|
"""
|
716
1014
|
A class representing a station along a curve in 3D space. The station is represented by a point on the curve, a
|
717
1015
|
tangent (direction) vector, and a length along the curve.
|
1016
|
+
|
1017
|
+
These are created as the result of position finding operations on `Curve3` objects.
|
718
1018
|
"""
|
719
1019
|
|
720
1020
|
@property
|
721
1021
|
def point(self) -> Point3:
|
722
|
-
"""
|
1022
|
+
"""
|
1023
|
+
Get the point in 3D world space where the station is located.
|
1024
|
+
:return: the point in 3D world space
|
1025
|
+
"""
|
723
1026
|
...
|
724
1027
|
|
725
1028
|
@property
|
726
1029
|
def direction(self) -> Vector3:
|
727
|
-
"""
|
1030
|
+
"""
|
1031
|
+
Get the direction vector of the curve at the location of the station. This is the tangent vector of the curve,
|
1032
|
+
and is typically the direction from the previous vertex to the next vertex.
|
1033
|
+
:return: the direction vector of the curve at the station.
|
1034
|
+
"""
|
728
1035
|
...
|
729
1036
|
|
730
1037
|
@property
|
@@ -736,22 +1043,33 @@ class CurveStation3:
|
|
736
1043
|
|
737
1044
|
@property
|
738
1045
|
def index(self) -> int:
|
739
|
-
"""
|
1046
|
+
"""
|
1047
|
+
Get the index of the previous vertex on the curve, at or before the station.
|
1048
|
+
:return: the index of the previous vertex on the curve.
|
1049
|
+
"""
|
740
1050
|
...
|
741
1051
|
|
742
1052
|
@property
|
743
1053
|
def length_along(self) -> float:
|
744
|
-
"""
|
1054
|
+
"""
|
1055
|
+
Get the length along the curve to the station, starting at the first vertex of the curve.
|
1056
|
+
:return: the length along the curve to the station.
|
1057
|
+
"""
|
745
1058
|
...
|
746
1059
|
|
747
1060
|
|
748
1061
|
class Curve3:
|
749
1062
|
"""
|
750
|
-
A class representing a polyline in 3D space. The curve is represented by a set of vertices and the segments
|
751
|
-
between them.
|
1063
|
+
A class representing a polyline in 3D space. The curve is represented by a set of vertices and the lien segments
|
1064
|
+
between them (also known as a polyline).
|
1065
|
+
|
1066
|
+
!!! note
|
1067
|
+
Because this curve is a simplicial 1-complex in 3D space it cannot divide space the way a `Curve2` can in 2D
|
1068
|
+
space. As a result, it lacks the concept of left/right or inside/outside, and so does not have all the same
|
1069
|
+
features that exist in the 2D curve class.
|
752
1070
|
"""
|
753
1071
|
|
754
|
-
def __init__(self, vertices:
|
1072
|
+
def __init__(self, vertices: NDArray[float], tol: float = 1.0e-6):
|
755
1073
|
"""
|
756
1074
|
Create a curve from a set of vertices. The vertices should be a numpy array of shape (n, 3).
|
757
1075
|
|
@@ -778,7 +1096,7 @@ class Curve3:
|
|
778
1096
|
...
|
779
1097
|
|
780
1098
|
@property
|
781
|
-
def points(self) ->
|
1099
|
+
def points(self) -> NDArray[float]:
|
782
1100
|
"""
|
783
1101
|
Will return an immutable view of the vertices of the mesh as a numpy array of shape (n, 3).
|
784
1102
|
:return: a numpy array of shape (n, 3) containing the vertices of the mesh.
|
@@ -831,7 +1149,7 @@ class Curve3:
|
|
831
1149
|
"""
|
832
1150
|
...
|
833
1151
|
|
834
|
-
def resample(self, resample:
|
1152
|
+
def resample(self, resample: engeom.ResampleEnum) -> Curve3:
|
835
1153
|
"""
|
836
1154
|
Resample the curve using the given resampling method. The resampling method can be one of the following:
|
837
1155
|
|
@@ -866,7 +1184,15 @@ class Curve3:
|
|
866
1184
|
|
867
1185
|
class Aabb3:
|
868
1186
|
"""
|
869
|
-
A class representing an axis-aligned bounding box in 3D space. The box is defined by
|
1187
|
+
A class representing an axis-aligned bounding box in 3D space. The bounding box is defined by a minimum point and a
|
1188
|
+
maximum point, which are the lower-left and upper-right corners of the box, respectively.
|
1189
|
+
|
1190
|
+
Bounding boxes are typically used for accelerating intersection and distance queries and are used internally inside
|
1191
|
+
the Rust language `engeom` library for this purpose. However, they have other useful applications and so are
|
1192
|
+
exposed here in the Python API.
|
1193
|
+
|
1194
|
+
Typically, `Aabb3` objects will be retrieved from other `engeom` objects which use them internally, such as
|
1195
|
+
`Curve3` and `Mesh` entities. However, they can also be created and manipulated directly.
|
870
1196
|
"""
|
871
1197
|
|
872
1198
|
def __init__(self, x_min: float, y_min: float, z_min: float, x_max: float, y_max: float, z_max: float):
|
@@ -883,20 +1209,76 @@ class Aabb3:
|
|
883
1209
|
|
884
1210
|
@property
|
885
1211
|
def min(self) -> Point3:
|
886
|
-
"""
|
1212
|
+
"""
|
1213
|
+
Get the minimum point of the AABB.
|
1214
|
+
:return: the minimum point of the AABB.
|
1215
|
+
"""
|
887
1216
|
...
|
888
1217
|
|
889
1218
|
@property
|
890
1219
|
def max(self) -> Point3:
|
891
|
-
"""
|
1220
|
+
"""
|
1221
|
+
Get the maximum point of the AABB.
|
1222
|
+
:return: the maximum point of the AABB.
|
1223
|
+
"""
|
892
1224
|
...
|
893
1225
|
|
894
1226
|
@property
|
895
1227
|
def center(self) -> Point3:
|
896
|
-
"""
|
1228
|
+
"""
|
1229
|
+
Get the center point of the AABB.
|
1230
|
+
:return: the center point of the AABB.
|
1231
|
+
"""
|
897
1232
|
...
|
898
1233
|
|
899
1234
|
@property
|
900
1235
|
def extent(self) -> Vector3:
|
901
|
-
"""
|
1236
|
+
"""
|
1237
|
+
The extent of the box (equivalent to `self.max - self.min`).
|
1238
|
+
:return: A vector representing the extent of the box.
|
1239
|
+
"""
|
1240
|
+
...
|
1241
|
+
|
1242
|
+
@staticmethod
|
1243
|
+
def at_point(x: float, y: float, z: float, w: float, h: float | None = None, l: float | None = None) -> Aabb3:
|
1244
|
+
"""
|
1245
|
+
Create an AABB centered at a point with a given width and height.
|
1246
|
+
:param x: The x-coordinate of the center of the AABB.
|
1247
|
+
:param y: The y-coordinate of the center of the AABB.
|
1248
|
+
:param z: The z-coordinate of the center of the AABB.
|
1249
|
+
:param w: The width (x extent) of the AABB.
|
1250
|
+
:param h: The height (y extent) of the AABB. If not provided, it will have the same value as the width.
|
1251
|
+
:param l: The length (z extent) of the AABB. If not provided, it will have the same value as the width.
|
1252
|
+
:return: A new axis aligned bounding box object.
|
1253
|
+
"""
|
1254
|
+
...
|
1255
|
+
|
1256
|
+
@staticmethod
|
1257
|
+
def from_points(points: NDArray[float]) -> Aabb3:
|
1258
|
+
"""
|
1259
|
+
Create an AABB that bounds a set of points. If the point array is empty or the wrong shape, an error will be
|
1260
|
+
thrown.
|
1261
|
+
:param points: a numpy array of shape (N, 2) containing the points to bound
|
1262
|
+
:return: a new AABB object
|
1263
|
+
"""
|
1264
|
+
...
|
1265
|
+
|
1266
|
+
def expand(self, d: float) -> Aabb3:
|
1267
|
+
"""
|
1268
|
+
Expand the AABB by a given distance in all directions. The resulting height and
|
1269
|
+
width will be increased by 2 * d.
|
1270
|
+
|
1271
|
+
:param d: the distance to expand the AABB by.
|
1272
|
+
:return: a new AABB object with the expanded bounds.
|
1273
|
+
"""
|
1274
|
+
...
|
1275
|
+
|
1276
|
+
def shrink(self, d: float) -> Aabb3:
|
1277
|
+
"""
|
1278
|
+
Shrink the AABB by a given distance in all directions. The resulting height and
|
1279
|
+
width will be decreased by 2 * d.
|
1280
|
+
|
1281
|
+
:param d: the distance to shrink the AABB by.
|
1282
|
+
:return: a new AABB object with the shrunk bounds.
|
1283
|
+
"""
|
902
1284
|
...
|