engeom 0.1.1__cp38-abi3-macosx_10_12_x86_64.whl → 0.1.2__cp38-abi3-macosx_10_12_x86_64.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/engeom.abi3.so CHANGED
Binary file
engeom/engeom.pyi CHANGED
@@ -1,14 +1,8 @@
1
1
  from __future__ import annotations
2
-
3
- from pathlib import Path
4
- from typing import Any, List, Tuple, Union
5
2
  from enum import Enum
6
3
 
7
- import numpy
8
-
4
+ type Resample = Resample_ByCount | Resample_BySpacing | Resample_ByMaxSpacing
9
5
 
10
6
  class DeviationMode(Enum):
11
7
  Absolute = 0
12
8
  Normal = 1
13
-
14
-
engeom/geom2.pyi CHANGED
@@ -1,5 +1,10 @@
1
1
  from __future__ import annotations
2
2
  import numpy
3
+ from typing import Iterable, Tuple
4
+
5
+ from engeom.engeom import Resample
6
+
7
+ type Transformable2 = Vector2 | Point2 | Iso2 | SurfacePoint2
3
8
 
4
9
 
5
10
  class Vector2:
@@ -19,6 +24,9 @@ class Vector2:
19
24
  def y(self) -> float:
20
25
  ...
21
26
 
27
+ def __iter__(self) -> Iterable[float]:
28
+ ...
29
+
22
30
  def __rmul__(self, other: float) -> Vector2:
23
31
  ...
24
32
 
@@ -40,6 +48,36 @@ class Vector2:
40
48
  """
41
49
  ...
42
50
 
51
+ def dot(self, other: Vector2) -> float:
52
+ """
53
+ Compute the dot product of two vectors.
54
+ """
55
+ ...
56
+
57
+ def cross(self, other: Vector2) -> float:
58
+ """
59
+ Compute the cross product of two vectors.
60
+ """
61
+ ...
62
+
63
+ def norm(self) -> float:
64
+ """
65
+ Compute the norm of the vector.
66
+ """
67
+ ...
68
+
69
+ def normalized(self) -> Vector2:
70
+ """
71
+ Return a normalized version of the vector.
72
+ """
73
+ ...
74
+
75
+ def angle_to(self, other: Vector2) -> float:
76
+ """
77
+ Compute the smallest angle between two vectors and return it in radians.
78
+ """
79
+ ...
80
+
43
81
 
44
82
  class Point2:
45
83
  def __init__(self, x: float, y: float):
@@ -58,6 +96,9 @@ class Point2:
58
96
  def y(self) -> float:
59
97
  ...
60
98
 
99
+ def __iter__(self) -> Iterable[float]:
100
+ ...
101
+
61
102
  @property
62
103
  def coords(self) -> Vector2:
63
104
  """
@@ -79,6 +120,81 @@ class Point2:
79
120
  ...
80
121
 
81
122
 
123
+ class SurfacePoint2:
124
+ def __init__(self, x: float, y: float, nx: float, ny: float):
125
+ """
126
+
127
+ :param x:
128
+ :param y:
129
+ :param nx:
130
+ :param ny:
131
+ """
132
+ ...
133
+
134
+ @property
135
+ def point(self) -> Point2:
136
+ """
137
+ Get the coordinates of the point as a Point2 object.
138
+ :return: a Point2 object
139
+ """
140
+ ...
141
+
142
+ @property
143
+ def normal(self) -> Vector2:
144
+ """
145
+ Get the normal of the point as a Vector2 object.
146
+ :return: a Vector2 object
147
+ """
148
+ ...
149
+
150
+ def at_distance(self, distance: float) -> Point2:
151
+ """
152
+ Get the point at a distance along the normal from the surface point.
153
+ :param distance: the distance to move along the normal.
154
+ :return: the point at the distance along the normal.
155
+ """
156
+ ...
157
+
158
+ def scalar_projection(self, point: Point2) -> float:
159
+ """
160
+ Calculate the scalar projection of a point onto the axis defined by the surface point position and direction.
161
+ Positive values indicate that the point is in the normal direction from the surface point, while negative values
162
+ indicate that the point is in the opposite direction.
163
+
164
+ :param point: the point to calculate the projection of.
165
+ :return: the scalar projection of the point onto the normal.
166
+ """
167
+ ...
168
+
169
+ def projection(self, point: Point2) -> Point2:
170
+ """
171
+ Calculate the projection of a point onto the axis defined by the surface point position and direction.
172
+
173
+ :param point: the point to calculate the projection of.
174
+ :return: the projection of the point onto the plane.
175
+ """
176
+ ...
177
+
178
+ def reversed(self) -> SurfacePoint2:
179
+ """
180
+ Return a new surface point with the normal vector inverted, but the position unchanged.
181
+ :return: a new surface point with the inverted normal vector.
182
+ """
183
+ ...
184
+
185
+ def planar_distance(self, point: Point2) -> float:
186
+ """
187
+ Calculate the planar (non-normal) distance between the surface point and a point. This is complementary to the
188
+ scalar projection. A point is projected onto the plane defined by the position and normal of the surface point,
189
+ and the distance between the surface point position and the projected point is returned. The value will always
190
+ be positive.
191
+
192
+ :param point: the point to calculate the distance to.
193
+ :return: the planar distance between the surface point and the point.
194
+ """
195
+ ...
196
+
197
+
82
198
  class Iso2:
83
199
  def __init__(self, tx: float, ty: float, r: float):
84
200
  """
@@ -130,10 +246,271 @@ class Iso2:
130
246
 
131
247
  class SvdBasis2:
132
248
 
133
- def __init__(self, points: numpy.ndarray[float], weights: numpy.ndarray[float] | None):
249
+ def __init__(
250
+ self,
251
+ points: numpy.ndarray[float],
252
+ weights: numpy.ndarray[float] | None = None
253
+ ):
134
254
  """
135
255
 
136
256
  :param points:
137
257
  :param weights:
138
258
  """
139
259
  ...
260
+
261
+
262
+ class CurveStation2:
263
+ """
264
+ A class representing a station along a curve in 3D space. The station is represented by a point on the curve, a
265
+ tangent (direction) vector, and a length along the curve.
266
+ """
267
+
268
+ @property
269
+ def point(self) -> Point2:
270
+ """ The 2d position in space on the curve. """
271
+ ...
272
+
273
+ @property
274
+ def direction(self) -> Vector2:
275
+ """ The tangent (direction) vector of the curve at the station. """
276
+ ...
277
+
278
+ @property
279
+ def normal(self) -> Vector2:
280
+ """ The normal vector of the curve at the station. """
281
+ ...
282
+
283
+ @property
284
+ def direction_point(self) -> SurfacePoint2:
285
+ """
286
+ A `SurfacePoint2` object representing the point on the curve and the curve's tangent/direction vector.
287
+ """
288
+ ...
289
+
290
+ @property
291
+ def surface_point(self) -> SurfacePoint2:
292
+ """
293
+ A `SurfacePoint2` object representing the point on the curve and the curve's normal vector.
294
+ """
295
+ ...
296
+
297
+ @property
298
+ def index(self) -> int:
299
+ """ The index of the previous vertex on the curve, at or before the station. """
300
+ ...
301
+
302
+ @property
303
+ def length_along(self) -> float:
304
+ """ The length along the curve from the start of the curve to the station. """
305
+ ...
306
+
307
+
308
+ class Curve2:
309
+ """
310
+ A class representing a curve in 2D space. The curve is defined by a set of vertices and the line segments between
311
+ them. In two dimensions, the curve also has the concepts of closed/open, surface direction, and hull.
312
+
313
+ """
314
+
315
+ def __init__(
316
+ self,
317
+ vertices: numpy.ndarray,
318
+ normals: numpy.ndarray | None = None,
319
+ tol: float | None = None,
320
+ force_closed: bool = False,
321
+ hull_ccw: bool = False,
322
+ ):
323
+ """
324
+ Create a 2d curve from a set of vertices and some additional options.
325
+
326
+ It's important to note that in 2d, a curve has a concept of a normal direction, built from the concept of
327
+ inside/outside defined through the winding order of the vertices. This extra information can allow a 2d curve
328
+ to model a manifold surface.
329
+
330
+ There are three ways to specify the winding order of the vertices:
331
+ 1. Control it manually by passing the vertices array with the rows already organized so that an exterior surface
332
+ is counter-clockwise.
333
+ 2. If the vertices represent an exterior shape, pass `hull_ccw=True` to have the constructor automatically
334
+ check the winding order and reverse it if point ordering in the convex hull does not match ordering in the
335
+ original array.
336
+ 3. Pass a `normals` array the same size as the `vertices` array, where the normals are non-zero vectors pointed
337
+ in the "outside" direction at each point. The constructor will reverse the winding if the majority of normals
338
+ do not point in the same direction as the winding.
339
+
340
+ :param vertices: a numpy array of shape (N, 2) representing the vertices of the curve.
341
+ :param normals: an optional numpy array of shape (N, 2) representing the normals of the curve associated with
342
+ each vertex.
343
+ :param tol: a tolerance value for the curve. If not provided, a default value of 1e-6 is used. This is the
344
+ distance at which two points are considered to be the same.
345
+ :param force_closed: If True, the curve will be closed even if the first and last points are not the same, which
346
+ will be done by adding a new point at the end of the array that is the same as the first point.
347
+ :param hull_ccw: If True, the constructor will check the winding order of the vertices and reverse it if the
348
+ convex hull of the points is not in the same order as the original array. This will do nothing if the `normals`
349
+ parameter is provided.
350
+ """
351
+ ...
352
+
353
+ def length(self) -> float:
354
+ """
355
+ Get the length of the curve.
356
+ :return: the length of the curve.
357
+ """
358
+ ...
359
+
360
+ def at_front(self) -> CurveStation2:
361
+ """
362
+ Get the station at the front of the curve.
363
+ :return: the station at the front of the curve.
364
+ """
365
+ ...
366
+
367
+ def at_back(self) -> CurveStation2:
368
+ """
369
+ Get the station at the back of the curve.
370
+ :return: the station at the back of the curve.
371
+ """
372
+ ...
373
+
374
+ def at_length(self, length: float) -> CurveStation2:
375
+ """
376
+ Get the station at a given length along the curve. Will throw a ValueError if the length is less than zero or
377
+ greater than the length of the curve.
378
+ :param length: the length along the curve.
379
+ :return: the station at the given length.
380
+ """
381
+ ...
382
+
383
+ def at_fraction(self, fraction: float) -> CurveStation2:
384
+ """
385
+ Get the station at a given fraction of the length of the curve. Will throw a ValueError if the fraction is less
386
+ than zero or greater than one.
387
+ :param fraction: the fraction of the length of the curve.
388
+ :return: the station at the given fraction.
389
+ """
390
+ ...
391
+
392
+ def at_closest_to_point(self, point: Point2) -> CurveStation2:
393
+ """
394
+ Get the station on the curve that is closest to a given point.
395
+ :param point: the point to find the closest station to.
396
+ :return: the station on the curve that is closest to the given point.
397
+ """
398
+ ...
399
+
400
+ @property
401
+ def is_closed(self) -> bool:
402
+ """
403
+ Check if the curve is closed.
404
+ :return: True if the curve is closed, False otherwise.
405
+ """
406
+ ...
407
+
408
+ def trim_front(self, length: float) -> Curve2:
409
+ """
410
+ Remove the front of the curve by a given length and return a new curve.
411
+ :param length: the length to trim from the front of the curve.
412
+ :return: a new curve with the front trimmed by the given length.
413
+ """
414
+ ...
415
+
416
+ def trim_back(self, length: float) -> Curve2:
417
+ """
418
+ Remove the back of the curve by a given length and return a new curve.
419
+ :param length: the length to trim from the back of the curve.
420
+ :return: a new curve with the back trimmed by the given length.
421
+ """
422
+ ...
423
+
424
+ def between_lengths(self, l0: float, l1: float) -> Curve2:
425
+ """
426
+ Attempt to get a new curve cut between two lengths along the curve. If the lengths are not valid, a ValueError
427
+ will be thrown.
428
+
429
+ If the curve is closed, the lengths will be wrapped around the curve. If the curve is not closed, the value
430
+ of `l0` must be less than `l1`. In either case, the lengths must be within the bounds of the curve.
431
+
432
+ :param l0: the start length.
433
+ :param l1: the end length.
434
+ :return: a new curve between the two lengths.
435
+ """
436
+ ...
437
+
438
+ def between_lengths_by_control(self, a: float, b: float, control: float) -> Curve2:
439
+ """
440
+ Attempt to get a new curve cut between two lengths along the curve, with a control point that will be used to
441
+ determine which side of the curve to keep. This is primarily helpful on closed curves when you can find a length
442
+ (usually via use of the `at_closest_to_point` method) that is on the side of the curve you want to keep.
443
+
444
+ If the lengths are not valid, a ValueError will be thrown.
445
+
446
+ :param a: the first length along the curve to cut
447
+ :param b: the second length along the curve to cut
448
+ :param control: a length along the curve that is on a point in the portion of the result that you want to keep
449
+ :return: a new curve between the two lengths
450
+ """
451
+
452
+ def reversed(self) -> Curve2:
453
+ """
454
+ Reverse the curve and return a new curve.
455
+ :return: a new curve with the vertices in reverse order.
456
+ """
457
+ ...
458
+
459
+ def make_hull(self) -> numpy.ndarray[float]:
460
+ """
461
+ Get the vertices of a convex hull of the curve, in counter-clockwise order.
462
+ :return: a numpy array of shape (N, 2) representing the convex hull of the curve.
463
+ """
464
+ ...
465
+
466
+ def max_point_in_direction(self, direction: Vector2) -> Tuple[int, Point2]:
467
+ """
468
+ Find the point on the curve that is furthest in a given direction.
469
+ :param direction: the direction to find the furthest point in.
470
+ :return: a tuple of the index of the point and the point itself.
471
+ """
472
+ ...
473
+
474
+ def max_distance_in_direction(self, surf_point: SurfacePoint2) -> float:
475
+ """
476
+ Find the maximum scalar projection of all vertices of the curve onto a surface point.
477
+ :param surf_point: the direction to find the furthest point in.
478
+ :return: the maximum scalar projection of all vertices of the curve onto a surface point.
479
+ """
480
+ ...
481
+
482
+ def clone_points(self) -> numpy.ndarray[float]:
483
+ """
484
+ Clone the points of the curve.
485
+ :return: a numpy array of shape (N, 2) representing the points of the curve.
486
+ """
487
+ ...
488
+
489
+ def simplify(self, tol: float) -> Curve2:
490
+ """
491
+ Simplify the curve using the Ramer-Douglas-Peucker algorithm.
492
+ :param tol: the tolerance to use for simplification.
493
+ :return: a new curve with the simplified points.
494
+ """
495
+ ...
496
+
497
+ def resample(self, resample: Resample) -> Curve2:
498
+ """
499
+ Resample the curve using the given resampling method. The resampling method can be one of the following:
500
+
501
+ - `Resample.ByCount(count: int)`: resample the curve to have the given number of points.
502
+ - `Resample.BySpacing(distance: float)`: resample the curve to have points spaced by the given distance.
503
+ - `Resample.ByMaxSpacing(distance: float)`: resample the curve to have points spaced by a maximum distance.
504
+
505
+ :param resample: the resampling method to use.
506
+ :return: a new curve object with the resampled vertices.
507
+ """
508
+ ...
509
+
510
+ def transformed_by(self, transform: Iso2) -> Curve2:
511
+ """
512
+ Transform the curve by the given transform and return a new curve.
513
+ :param transform: the transform to apply to the curve.
514
+ :return: a new curve object with the transformed vertices.
515
+ """
516
+ ...
engeom/geom3.pyi CHANGED
@@ -1,13 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
- from typing import Tuple
4
+ from typing import Tuple, Iterable, List
5
5
 
6
6
  import numpy
7
+ from engeom import DeviationMode, Resample
7
8
 
8
- from engeom import DeviationMode
9
-
10
- type Transformable3 = Vector3 | Point3 | Plane3 | Iso3
9
+ type Transformable3 = Vector3 | Point3 | Plane3 | Iso3 | SurfacePoint3
11
10
 
12
11
 
13
12
  class Vector3:
@@ -32,6 +31,9 @@ class Vector3:
32
31
  def z(self) -> float:
33
32
  ...
34
33
 
34
+ def __iter__(self) -> Iterable[float]:
35
+ ...
36
+
35
37
  def __rmul__(self, other: float) -> Vector3:
36
38
  ...
37
39
 
@@ -53,6 +55,42 @@ class Vector3:
53
55
  """
54
56
  ...
55
57
 
58
+ def dot(self, other: Vector3) -> float:
59
+ """
60
+ Calculate the dot product of this vector with another vector.
61
+ :param other: the other vector to calculate the dot product with.
62
+ :return: the dot product of the two vectors.
63
+ """
64
+ ...
65
+
66
+ def cross(self, other: Vector3) -> Vector3:
67
+ """
68
+ Calculate the cross product of this vector with another vector.
69
+ :param other: the other vector to calculate the cross product with.
70
+ :return: the cross product of the two vectors.
71
+ """
72
+ ...
73
+
74
+ def norm(self) -> float:
75
+ """
76
+ Calculate the norm (length) of the vector.
77
+ :return:
78
+ """
79
+
80
+ def normalized(self) -> Vector3:
81
+ """
82
+ Return a normalized version of the vector.
83
+ :return: a new vector that has unit length
84
+ """
85
+
86
+ def angle_to(self, other: Vector3) -> float:
87
+ """
88
+ Calculate the smallest angle between this vector and another vector.
89
+ :param other: the other vector to calculate the angle to.
90
+ :return: the angle between the two vectors in radians.
91
+ """
92
+ ...
93
+
56
94
 
57
95
  class Point3:
58
96
  def __init__(self, x: float, y: float, z: float):
@@ -76,6 +114,9 @@ class Point3:
76
114
  def z(self) -> float:
77
115
  ...
78
116
 
117
+ def __iter__(self) -> Iterable[float]:
118
+ ...
119
+
79
120
  @property
80
121
  def coords(self) -> Vector3:
81
122
  """
@@ -97,6 +138,90 @@ class Point3:
97
138
  ...
98
139
 
99
140
 
141
+ class SurfacePoint3:
142
+ def __init__(self, x: float, y: float, z: float, nx: float, ny: float, nz: float):
143
+ """
144
+
145
+ :param x:
146
+ :param y:
147
+ :param z:
148
+ :param nx:
149
+ :param ny:
150
+ :param nz:
151
+ """
152
+ ...
153
+
154
+ @property
155
+ def point(self) -> Point3:
156
+ """
157
+ Get the coordinates of the point as a Point3 object.
158
+ :return: a Point3 object
159
+ """
160
+ ...
161
+
162
+ @property
163
+ def normal(self) -> Vector3:
164
+ """
165
+ Get the normal of the point as a Vector3 object.
166
+ :return: a Vector3 object
167
+ """
168
+ ...
169
+
170
+ def at_distance(self, distance: float) -> Point3:
171
+ """
172
+ Get the point at a distance along the normal from the surface point.
173
+ :param distance: the distance to move along the normal.
174
+ :return: the point at the distance along the normal.
175
+ """
176
+ ...
177
+
178
+ def scalar_projection(self, point: Point3) -> float:
179
+ """
180
+ Calculate the scalar projection of a point onto the axis defined by the surface point position and direction.
181
+ Positive values indicate that the point is in the normal direction from the surface point, while negative values
182
+ indicate that the point is in the opposite direction.
183
+
184
+ :param point: the point to calculate the projection of.
185
+ :return: the scalar projection of the point onto the normal.
186
+ """
187
+ ...
188
+
189
+ def projection(self, point: Point3) -> Point3:
190
+ """
191
+ Calculate the projection of a point onto the axis defined by the surface point position and direction.
192
+
193
+ :param point: the point to calculate the projection of.
194
+ :return: the projection of the point onto the plane.
195
+ """
196
+ ...
197
+
198
+ def reversed(self) -> SurfacePoint3:
199
+ """
200
+ Return a new surface point with the normal vector inverted, but the position unchanged.
201
+ :return: a new surface point with the inverted normal vector.
202
+ """
203
+ ...
204
+
205
+ def planar_distance(self, point: Point3) -> float:
206
+ """
207
+ Calculate the planar (non-normal) distance between the surface point and a point. This is complementary to the
208
+ scalar projection. A point is projected onto the plane defined by the position and normal of the surface point,
209
+ and the distance between the surface point position and the projected point is returned. The value will always
210
+ be positive.
211
+
212
+ :param point: the point to calculate the distance to.
213
+ :return: the planar distance between the surface point and the point.
214
+ """
215
+ ...
216
+
217
+ def get_plane(self) -> Plane3:
218
+ """
219
+ Get the plane defined by the surface point.
220
+ :return: the plane defined by the surface point.
221
+ """
222
+ ...
223
+
224
+
100
225
  class Iso3:
101
226
  """ An isometry (rigid body transformation) in 3D space. """
102
227
 
@@ -183,7 +308,11 @@ class SvdBasis3:
183
308
  fitting basis for the points using a singular value decomposition.
184
309
  """
185
310
 
186
- def __init__(self, points: numpy.ndarray[float], weights: numpy.ndarray[float] | None):
311
+ def __init__(
312
+ self,
313
+ points: numpy.ndarray[float],
314
+ weights: numpy.ndarray[float] | None = None
315
+ ):
187
316
  """
188
317
  Create a basis from a set of points. The basis will be calculated using a singular value decomposition of the
189
318
  points.
@@ -305,6 +434,8 @@ class Mesh:
305
434
  self,
306
435
  vertices: numpy.ndarray[float],
307
436
  triangles: numpy.ndarray[numpy.uint32],
437
+ merge_duplicates: bool | None = None,
438
+ delete_degenerate: bool | None = None
308
439
  ):
309
440
  """
310
441
  Create an engeom mesh from vertices and triangles. The vertices should be a numpy array of shape (n, 3), while
@@ -314,16 +445,21 @@ class Mesh:
314
445
 
315
446
  :param vertices: a numpy array of shape (n, 3) containing the vertices of the mesh.
316
447
  :param triangles: a numpy array of shape (m, 3) containing the triangles of the mesh, should be uint.
448
+ :param merge_duplicates: merge duplicate vertices and triangles. If None, the default behavior is to do nothing
449
+ :param delete_degenerate: delete degenerate triangles. If None, the default behavior is to do nothing
317
450
  """
318
451
  ...
319
452
 
320
453
  @staticmethod
321
- def load_stl(path: str | Path) -> Mesh:
454
+ def load_stl(path: str | Path, merge_duplicates: bool | None = None, delete_degenerate: bool | None = None) -> Mesh:
322
455
  """
323
456
  Load a mesh from an STL file. This will return a new mesh object containing the vertices and triangles from the
324
- file.
457
+ file. Optional parameters can be used to control the behavior of the loader when handling duplicate vertices/
458
+ triangles and degenerate triangles.
325
459
 
326
460
  :param path: the path to the STL file to load.
461
+ :param merge_duplicates: merge duplicate vertices and triangles. If None, the default behavior is to do nothing
462
+ :param delete_degenerate: delete degenerate triangles. If None, the default behavior is to do nothing
327
463
  :return: the mesh object containing the data from the file.
328
464
  """
329
465
  ...
@@ -423,3 +559,167 @@ class Mesh:
423
559
  :return: a numpy array of shape (n, 6) containing the sampled points.
424
560
  """
425
561
  ...
562
+
563
+ def section(self, plane: Plane3, tol: float | None = None) -> List[Curve3]:
564
+ """
565
+ Calculate and return the intersection curves between the mesh and a plane.
566
+
567
+ :param plane:
568
+ :param tol:
569
+ :return:
570
+ """
571
+ ...
572
+
573
+
574
+ class CurveStation3:
575
+ """
576
+ A class representing a station along a curve in 3D space. The station is represented by a point on the curve, a
577
+ tangent (direction) vector, and a length along the curve.
578
+ """
579
+
580
+ @property
581
+ def point(self) -> Point3:
582
+ """ The 3d position in space on the curve. """
583
+ ...
584
+
585
+ @property
586
+ def direction(self) -> Vector3:
587
+ """ The tangent (direction) vector of the curve at the station. """
588
+ ...
589
+
590
+ @property
591
+ def direction_point(self) -> SurfacePoint3:
592
+ """
593
+ A `SurfacePoint3` object representing the point on the curve and the curve's tangent/direction vector.
594
+ """
595
+ ...
596
+
597
+ @property
598
+ def index(self) -> int:
599
+ """ The index of the previous vertex on the curve, at or before the station. """
600
+ ...
601
+
602
+ @property
603
+ def length_along(self) -> float:
604
+ """ The length along the curve from the start of the curve to the station. """
605
+ ...
606
+
607
+
608
+ class Curve3:
609
+ """
610
+ A class representing a polyline in 3D space. The curve is represented by a set of vertices and the segments
611
+ between them.
612
+ """
613
+
614
+ def __init__(self, vertices: numpy.ndarray):
615
+ """
616
+ Create a curve from a set of vertices. The vertices should be a numpy array of shape (n, 3).
617
+
618
+ :param vertices: a numpy array of shape (n, 3) containing the vertices of the curve.
619
+ """
620
+ ...
621
+
622
+ def clone(self) -> Curve3:
623
+ """
624
+ Will return a copy of the curve. This is a copy of the data, so modifying the returned curve will not modify
625
+ the original curve.
626
+
627
+ :return: a copy of the curve.
628
+ """
629
+ ...
630
+
631
+ def length(self) -> float:
632
+ """
633
+ Return the total length of the curve in the units of the vertices.
634
+
635
+ :return: the length of the curve.
636
+ """
637
+ ...
638
+
639
+ def clone_vertices(self) -> numpy.ndarray[float]:
640
+ """
641
+ Will return a copy of the vertices of the curve as a numpy array. If the curve has not been modified, this will
642
+ be the same as the original vertices. This is a copy of the data, so modifying the returned array will not
643
+ modify the curve.
644
+
645
+ :return: a numpy array of shape (n, 3) containing the vertices of the curve.
646
+ """
647
+ ...
648
+
649
+ def at_length(self, length: float) -> CurveStation3:
650
+ """
651
+ Return a station along the curve at the given length. The length is measured from the start of the curve to the
652
+ station. If the length is greater than the length of the curve or less than 0, an error will be raised.
653
+
654
+ :param length: the length along the curve to return the station at.
655
+ :return: a `CurveStation3` object representing the station along the curve.
656
+ """
657
+ ...
658
+
659
+ def at_fraction(self, fraction: float) -> CurveStation3:
660
+ """
661
+ Return a station along the curve at the given fraction of the length of the curve. If the fraction is greater
662
+ than 1 or less than 0, an error will be raised.
663
+
664
+ :param fraction: the fraction of the length of the curve to return the station at.
665
+ :return: a `CurveStation3` object representing the station along the curve.
666
+ """
667
+ ...
668
+
669
+ def at_closest_to_point(self, point: Point3) -> CurveStation3:
670
+ """
671
+ Return a station along the curve at the closest point to the given point. The station will be the point on the
672
+ curve that is closest to the given point.
673
+
674
+ :param point: the point to find the closest station to.
675
+ :return: a `CurveStation3` object representing the station along the curve.
676
+ """
677
+ ...
678
+
679
+ def at_front(self) -> CurveStation3:
680
+ """
681
+ Return a station at the front of the curve. This is equivalent to calling `at_length(0)`.
682
+
683
+ :return: a `CurveStation3` object representing the station at the front of the curve.
684
+ """
685
+ ...
686
+
687
+ def at_back(self) -> CurveStation3:
688
+ """
689
+ Return a station at the back of the curve. This is equivalent to calling `at_length(length)`.
690
+
691
+ :return: a `CurveStation3` object representing the station at the back of the curve.
692
+ """
693
+ ...
694
+
695
+ def resample(self, resample: Resample) -> Curve3:
696
+ """
697
+ Resample the curve using the given resampling method. The resampling method can be one of the following:
698
+
699
+ - `Resample.ByCount(count: int)`: resample the curve to have the given number of points.
700
+ - `Resample.BySpacing(distance: float)`: resample the curve to have points spaced by the given distance.
701
+ - `Resample.ByMaxSpacing(distance: float)`: resample the curve to have points spaced by a maximum distance.
702
+
703
+ :param resample: the resampling method to use.
704
+ :return: a new curve object with the resampled vertices.
705
+ """
706
+ ...
707
+
708
+ def simplify(self, tolerance: float) -> Curve3:
709
+ """
710
+ Simplify the curve using the Ramer-Douglas-Peucker algorithm. This will remove vertices from the curve that are
711
+ within the given tolerance of the line between the previous and next vertices.
712
+
713
+ :param tolerance: the tolerance to use when simplifying the curve.
714
+ :return: a new curve object with the simplified vertices.
715
+ """
716
+ ...
717
+
718
+ def transformed_by(self, iso: Iso3) -> Curve3:
719
+ """
720
+ Transform the curve by an isometry. This will return a new curve object with the transformed vertices.
721
+
722
+ :param iso: the isometry to transform the curve by.
723
+ :return: a new curve object with the transformed vertices.
724
+ """
725
+ ...
engeom/matplotlib.py CHANGED
@@ -1,10 +1,50 @@
1
+ from typing import List
2
+
3
+ import matplotlib.lines
1
4
  import numpy
5
+ from .geom2 import Curve2
2
6
 
3
7
  try:
4
8
  from matplotlib.pyplot import Axes, Circle
9
+ from matplotlib.colors import ListedColormap
5
10
  except ImportError:
6
11
  pass
7
12
  else:
13
+ class GomColorMap(ListedColormap):
14
+ def __init__(self):
15
+ colors = numpy.array([
16
+ [1, 0, 160],
17
+ [1, 0, 255],
18
+ [0, 254, 255],
19
+ [0, 160, 0],
20
+ [0, 254, 0],
21
+ [255, 255, 0],
22
+ [255, 128, 0],
23
+ [255, 1, 0]
24
+ ], dtype=numpy.float64)
25
+ colors /= 256.0
26
+ colors = numpy.hstack((colors, numpy.ones((len(colors), 1))))
27
+ super().__init__(colors)
28
+ self.set_under("magenta")
29
+ self.set_over("darkred")
30
+
31
+ GOM_CMAP = GomColorMap()
32
+
33
+ def add_curve_plots(ax: Axes, *curves: Curve2, **kwargs) -> List[List[matplotlib.lines.Line2D]]:
34
+ """
35
+ Plot a list of curves on a Matplotlib Axes object.
36
+ :param ax: a Matplotlib Axes object
37
+ :param curves: a list of Curve2 objects
38
+ :param kwargs: keyword arguments to pass to the plot function
39
+ :return: None
40
+ """
41
+ actors = []
42
+ for curve in curves:
43
+ points = curve.clone_points()
44
+ a = ax.plot(points[:, 0], points[:, 1], **kwargs)
45
+ actors.append(a)
46
+ return actors
47
+
8
48
 
9
49
  def set_aspect_fill(ax: Axes):
10
50
  """
@@ -38,7 +78,3 @@ else:
38
78
  x_range = x_scale / y_scale * (x1 - x0)
39
79
  x_mid = (x0 + x1) / 2
40
80
  ax.set_xlim(x_mid - x_range / 2, x_mid + x_range / 2)
41
-
42
-
43
-
44
-
engeom/pyvista.py CHANGED
@@ -1,8 +1,14 @@
1
1
  """
2
2
  This module contains helper functions for working with PyVista.
3
3
  """
4
+ from __future__ import annotations
5
+
6
+ from typing import List
7
+
4
8
  import numpy
5
- from .geom3 import Mesh
9
+ from pyvista import ColorLike
10
+
11
+ from .geom3 import Mesh, Curve3
6
12
 
7
13
  try:
8
14
  import pyvista
@@ -23,4 +29,35 @@ else:
23
29
  vertices = mesh.clone_vertices()
24
30
  faces = mesh.clone_triangles()
25
31
  faces = numpy.hstack((numpy.ones((faces.shape[0], 1), dtype=faces.dtype) * 3, faces))
26
- return pyvista.PolyData(vertices, faces)
32
+ return pyvista.PolyData(vertices, faces)
33
+
34
+
35
+ def add_curves_to_plotter(
36
+ plotter: pyvista.Plotter,
37
+ curves: List[Curve3],
38
+ color: ColorLike = 'w',
39
+ width: float = 5.0,
40
+ label: str | None = None,
41
+ name: str | None = None,
42
+ ) -> List[pyvista.vtkActor]:
43
+ """
44
+ Adds curves to a PyVista plotter.
45
+ :param plotter:
46
+ :param curves:
47
+ :param color:
48
+ :param width:
49
+ :param label:
50
+ :param name:
51
+ :return:
52
+ """
53
+
54
+ if pyvista is None:
55
+ raise ImportError("PyVista is not installed.")
56
+
57
+ result_list = []
58
+ for curve in curves:
59
+ v = curve.clone_vertices()
60
+ added = plotter.add_lines(v, connected=True, color=color, width=width, label=label, name=name)
61
+ result_list.append(added)
62
+
63
+ return result_list
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engeom
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -0,0 +1,14 @@
1
+ engeom-0.1.2.dist-info/METADATA,sha256=ym_mnfPDlcTOzcYgeEZGMCFsgidl30syGoPDLY_B2eA,339
2
+ engeom-0.1.2.dist-info/WHEEL,sha256=ajTxDRk-ooZz0dnA2NZaw_ASzODvtK_6X8l0woIlBl4,104
3
+ engeom/geom2.pyi,sha256=De3YQSGpS4UQ1zawtIsuVR4-7rcFjqmNvL9lbtzN_d4,17117
4
+ engeom/geom3.pyi,sha256=fEFhdFmEJsDP3X0aE_N0heqMyyPnbYjpeB0hTR2xjOI,27295
5
+ engeom/geom3/__init__.py,sha256=DG5jt2xgS9WRNb58ZkkrcKQQO6bIG-irg-uV_BkHEj4,174
6
+ engeom/pyvista.py,sha256=Lyvm0K_rvhR2wZACtfwCPYwEuABqYSTdjvbBaQS9yI4,1721
7
+ engeom/geom2/__init__.py,sha256=mRu8Zh6DE-EQyhxScoxszPqDjGVzGWVJEQO6RIAtS4A,174
8
+ engeom/matplotlib.py,sha256=Y9JZqpEFHm5EVzbr20P-NdxndNZdDH32OhE_KjxG_S4,3025
9
+ engeom/__init__.py,sha256=QN5uETqrN442w41foyrcCPV_x6NP-mrxkPJhdvdey1g,109
10
+ engeom/align/__init__.py,sha256=SEeMqeqLKqJC73Mg8GwPwd9NwWnl-dcCqJ4rPdh8yyc,196
11
+ engeom/engeom.pyi,sha256=pLlD_YazsO0zu3guQZx85btESz0gAwVv79xD0pjd7Nc,196
12
+ engeom/align.pyi,sha256=KBC0nwcyp4YMfY2hRN1gr3DqFah-unqAd_o1KYwJAqc,1022
13
+ engeom/engeom.abi3.so,sha256=pXKp5LBjoNK1-rFdzXxIj3Dyyfc1gWM2zjaLAHvBp28,1735644
14
+ engeom-0.1.2.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- engeom-0.1.1.dist-info/METADATA,sha256=z8XmJMWeTVLOwcvkJvmggeYXlOUJKfEjA4NfrS8GlX0,339
2
- engeom-0.1.1.dist-info/WHEEL,sha256=ajTxDRk-ooZz0dnA2NZaw_ASzODvtK_6X8l0woIlBl4,104
3
- engeom/geom2.pyi,sha256=nwZ8Isy-PdvNIIyZyNuo78Us95CXd1FaWllqnF9MKbE,2978
4
- engeom/geom3.pyi,sha256=PjDbjM3d20PUbP5pmlb8OqpZ7gM0RQL_f7gEVTbr7kE,16198
5
- engeom/geom3/__init__.py,sha256=DG5jt2xgS9WRNb58ZkkrcKQQO6bIG-irg-uV_BkHEj4,174
6
- engeom/pyvista.py,sha256=zJ-FFwbzxVhhhrh4rfn26iaOK95Tw0L2QZsDNK8MXzg,729
7
- engeom/geom2/__init__.py,sha256=mRu8Zh6DE-EQyhxScoxszPqDjGVzGWVJEQO6RIAtS4A,174
8
- engeom/matplotlib.py,sha256=N3CkAtQjh9xZ1hx6_piFGRNzLRLEMh9OVvWDKx5yiL8,1676
9
- engeom/__init__.py,sha256=QN5uETqrN442w41foyrcCPV_x6NP-mrxkPJhdvdey1g,109
10
- engeom/align/__init__.py,sha256=SEeMqeqLKqJC73Mg8GwPwd9NwWnl-dcCqJ4rPdh8yyc,196
11
- engeom/engeom.pyi,sha256=flbU5LWg6szeBLTaxa1eNvN8wBhLCf9qdFNgxOYS1ng,203
12
- engeom/align.pyi,sha256=KBC0nwcyp4YMfY2hRN1gr3DqFah-unqAd_o1KYwJAqc,1022
13
- engeom/engeom.abi3.so,sha256=LDbXTj8ap2KOhAqtW0bdRxQWuKw2Hk4YGiRjRyxTUW4,1393484
14
- engeom-0.1.1.dist-info/RECORD,,
File without changes