engeom 0.2.1__cp38-abi3-win_amd64.whl → 0.2.4__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/engeom.pyd CHANGED
Binary file
engeom/engeom.pyi CHANGED
@@ -6,3 +6,8 @@ type Resample = Resample_Count | Resample_Spacing | Resample_MaxSpacing
6
6
  class DeviationMode(Enum):
7
7
  Point = 0
8
8
  Plane = 1
9
+
10
+ class SelectOp(Enum):
11
+ Add=0
12
+ Remove=1
13
+ Keep=2
engeom/geom3.pyi CHANGED
@@ -4,7 +4,8 @@ from pathlib import Path
4
4
  from typing import Tuple, Iterable, List, TypeVar
5
5
 
6
6
  import numpy
7
- from engeom import DeviationMode, Resample
7
+ from engeom import DeviationMode, Resample, SelectOp
8
+ from .metrology import Length3
8
9
 
9
10
  Transformable3 = TypeVar("Transformable3", Vector3, Point3, Plane3, Iso3, SurfacePoint3)
10
11
  PointOrVector3 = TypeVar("PointOrVector3", Vector3, Point3)
@@ -434,7 +435,7 @@ class Mesh:
434
435
  def __init__(
435
436
  self,
436
437
  vertices: numpy.ndarray[float],
437
- triangles: numpy.ndarray[numpy.uint32],
438
+ faces: numpy.ndarray[numpy.uint32],
438
439
  merge_duplicates: bool = False,
439
440
  delete_degenerate: bool = False
440
441
  ):
@@ -445,7 +446,7 @@ class Mesh:
445
446
  front/outside.
446
447
 
447
448
  :param vertices: a numpy array of shape (n, 3) containing the vertices of the mesh.
448
- :param triangles: a numpy array of shape (m, 3) containing the triangles of the mesh, should be uint.
449
+ :param faces: a numpy array of shape (m, 3) containing the triangles of the mesh, should be uint.
449
450
  :param merge_duplicates: merge duplicate vertices and triangles
450
451
  :param delete_degenerate: delete degenerate triangles
451
452
  """
@@ -506,7 +507,7 @@ class Mesh:
506
507
  ...
507
508
 
508
509
  @property
509
- def points(self) -> numpy.ndarray[float]:
510
+ def vertices(self) -> numpy.ndarray[float]:
510
511
  """
511
512
  Will return an immutable view of the vertices of the mesh as a numpy array of shape (n, 3).
512
513
  :return: a numpy array of shape (n, 3) containing the vertices of the mesh.
@@ -514,7 +515,7 @@ class Mesh:
514
515
  ...
515
516
 
516
517
  @property
517
- def triangles(self) -> numpy.ndarray[numpy.uint32]:
518
+ def faces(self) -> numpy.ndarray[numpy.uint32]:
518
519
  """
519
520
  Will return an immutable view of the triangles of the mesh as a numpy array of shape (m, 3).
520
521
  :return: a numpy array of shape (m, 3) containing the triangles of the mesh.
@@ -573,6 +574,142 @@ class Mesh:
573
574
  """
574
575
  ...
575
576
 
577
+ def face_select_none(self) -> MeshTriangleFilter:
578
+ """
579
+ Start a filter operation on the faces of the mesh beginning with no faces selected. This will return a filter
580
+ object that can be used to further add or remove faces from the selection.
581
+
582
+ :return: a filter object for the triangles of the mesh.
583
+ """
584
+ ...
585
+
586
+ def face_select_all(self) -> MeshTriangleFilter:
587
+ """
588
+ Start a filter operation on the faces of the mesh beginning with all faces selected. This will return a filter
589
+ object that can be used to further add or remove faces from the selection.
590
+
591
+ :return: a filter object for the triangles of the mesh.
592
+ """
593
+ ...
594
+
595
+ def separate_patches(self) -> List[Mesh]:
596
+ """
597
+ Separate the mesh into connected patches. This will return a list of new mesh objects, each containing one
598
+ connected patch of the original mesh. These objects will be clones of the original mesh, so modifying them will
599
+ have no effect on the original mesh.
600
+ :return:
601
+ """
602
+
603
+ def create_from_indices(self, indices: List[int]) -> Mesh:
604
+ """
605
+ Create a new mesh from a list of triangle indices. This will build a new mesh object containing only the
606
+ triangles (and their respective vertices) identified by the given list of indices. Do not allow duplicate
607
+ indices in the list.
608
+ :param indices: the triangle indices to include in the new mesh
609
+ :return:
610
+ """
611
+ ...
612
+
613
+ def measure_point_deviation(self, x: float, y: float, z: float, dist_mode: DeviationMode) -> Length3:
614
+ """
615
+ Compute the deviation of a point from this mesh's surface and return it as a measurement object.
616
+
617
+ The deviation is the distance from the point to its closest projection onto the mesh using
618
+ the specified distance mode. The direction of the measurement is the direction between the
619
+ point and the projection, flipped into the positive half-space of the mesh surface at the
620
+ projection point.
621
+
622
+ If the distance is less than a very small floating point epsilon, the direction will be
623
+ taken directly from the mesh surface normal.
624
+
625
+ The first point `.a` of the measurement is the reference point, and the second point `.b`
626
+ is the test point.
627
+
628
+ :param x: the x component of the point to measure
629
+ :param y: the y component of the point to measure
630
+ :param z: the z component of the point to measure
631
+ :param dist_mode: the deviation mode to use
632
+ :return:
633
+ """
634
+
635
+ def boundary_first_flatten(self) -> numpy.ndarray[float]:
636
+ """
637
+
638
+ :return:
639
+ """
640
+
641
+ def surface_closest_to(self, x: float, y: float, z: float) -> SurfacePoint3:
642
+ """
643
+ Find the closest point on the surface of the mesh to a given point in space, returning the point and normal
644
+ in the form of a `SurfacePoint3` object.
645
+ :param x: the x coordinate of the point to find the closest point to
646
+ :param y: the y coordinate of the point to find the closest point to
647
+ :param z: the z coordinate of the point to find the closest point to
648
+ :return: a `SurfacePoint3` object containing the closest point and normal
649
+ """
650
+ ...
651
+
652
+
653
+ class MeshTriangleFilter:
654
+ def collect(self) -> List[int]:
655
+ """
656
+ Collect the final indices of the triangles that passed the filter.
657
+ :return:
658
+ """
659
+ ...
660
+
661
+ def create_mesh(self) -> Mesh:
662
+ """
663
+ Create a new mesh from the filtered triangles. This will build a new mesh object containing only the triangles
664
+ (and their respective vertices) that are still retained in the filter.
665
+ :return:
666
+ """
667
+ ...
668
+
669
+ def facing(self, x: float, y: float, z: float, angle: float, mode: SelectOp) -> MeshTriangleFilter:
670
+ """
671
+
672
+ :param x:
673
+ :param y:
674
+ :param z:
675
+ :param angle:
676
+ :param mode:
677
+ :return:
678
+ """
679
+ ...
680
+
681
+ def near_mesh(
682
+ self,
683
+ other: Mesh,
684
+ all_points: bool,
685
+ distance_tol: float,
686
+ mode: SelectOp,
687
+ planar_tol: float | None = None,
688
+ angle_tol: float | None = None,
689
+ ) -> MeshTriangleFilter:
690
+ """
691
+ Reduce the list of indices to only include triangles that are within a certain distance of
692
+ their closest projection onto another mesh. The distance can require that all points of the
693
+ triangle are within the tolerance, or just one.
694
+
695
+ There are two additional optional tolerances that can be applied.
696
+
697
+ 1. A planar tolerance, which checks the distance of the vertex projected onto the plane of
698
+ the reference mesh triangle and looks at how far it is from the projection point. This
699
+ is useful to filter out triangles that go past the edge of the reference mesh.
700
+ 2. An angle tolerance, which checks the angle between the normal of the current triangle
701
+ and the normal of the reference triangle. This is useful to filter out triangles that
702
+ are not facing the same direction as the reference mesh.
703
+
704
+ :param other: the mesh to use as a reference
705
+ :param all_points: if True, all points of the triangle must be within the tolerance, if False, only one point
706
+ :param distance_tol: the maximum distance between the triangle and its projection onto the reference mesh
707
+ :param mode:
708
+ :param planar_tol: the maximum in-plane distance between the triangle and its projection onto the reference mesh
709
+ :param angle_tol: the maximum angle between the normals of the triangle and the reference mesh
710
+ """
711
+ ...
712
+
576
713
 
577
714
  class CurveStation3:
578
715
  """
@@ -762,4 +899,4 @@ class Aabb3:
762
899
  @property
763
900
  def extent(self) -> Vector3:
764
901
  """ The extent of the box. """
765
- ...
902
+ ...
engeom/matplotlib.py CHANGED
@@ -125,20 +125,12 @@ else:
125
125
  self,
126
126
  length: Length2,
127
127
  side_shift: float = 0,
128
- format: str = "{value:.3f}",
128
+ template: str = "{value:.3f}",
129
129
  fontsize: int = 10,
130
130
  label_place: LabelPlace = LabelPlace.Outside,
131
131
  label_offset: float | None = None,
132
132
  fontname: str | None = None,
133
133
  ):
134
- """
135
- Plot a Length2 object on a Matplotlib Axes object.
136
- :param side_shift:
137
- :param length: a Length2 object
138
- :return: None
139
- """
140
- from matplotlib.pyplot import Line2D
141
-
142
134
  pad_scale = self._font_height(12) * 1.5
143
135
  center = length.center.shift_orthogonal(side_shift)
144
136
  leader_a = center.projection(length.a)
@@ -169,7 +161,7 @@ else:
169
161
  kwargs["fontname"] = fontname
170
162
 
171
163
  result = self.annotate_text_only(
172
- format.format(value=length.value),
164
+ template.format(value=length.value),
173
165
  label_coords,
174
166
  bbox=dict(boxstyle="round,pad=0.3", ec="black", fc="white"),
175
167
  **kwargs,
@@ -232,9 +224,9 @@ else:
232
224
 
233
225
  return min(x_scale, y_scale)
234
226
 
235
- def _tuplefy(item: PlotCoords) -> Tuple[float, float]:
236
- if isinstance(item, (Point2, Vector2)):
237
- return item.x, item.y
238
- else:
239
- x, y, *_ = item
240
- return x, y
227
+ def _tuplefy(item: PlotCoords) -> Tuple[float, float]:
228
+ if isinstance(item, (Point2, Vector2)):
229
+ return item.x, item.y
230
+ else:
231
+ x, y, *_ = item
232
+ return x, y
engeom/metrology.pyi CHANGED
@@ -1,4 +1,5 @@
1
1
  from .geom2 import Point2, Vector2, SurfacePoint2
2
+ from .geom3 import Point3, Vector3, SurfacePoint3
2
3
 
3
4
 
4
5
  class Length2:
@@ -30,3 +31,34 @@ class Length2:
30
31
  @property
31
32
  def center(self) -> SurfacePoint2:
32
33
  ...
34
+
35
+
36
+ class Length3:
37
+ def __init__(self, a: Point3, b: Point3, direction: Vector3 | None = None):
38
+ """
39
+
40
+ :param a:
41
+ :param b:
42
+ :param direction:
43
+ """
44
+ ...
45
+
46
+ @property
47
+ def a(self) -> Point3:
48
+ ...
49
+
50
+ @property
51
+ def b(self) -> Point3:
52
+ ...
53
+
54
+ @property
55
+ def direction(self) -> Vector3:
56
+ ...
57
+
58
+ @property
59
+ def value(self) -> float:
60
+ ...
61
+
62
+ @property
63
+ def center(self) -> SurfacePoint3:
64
+ ...
engeom/pyvista.py CHANGED
@@ -4,12 +4,16 @@ This module contains helper functions for working with PyVista.
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from typing import List
7
+ from typing import List, Any, Dict, Union, Iterable, Tuple
8
8
 
9
9
  import numpy
10
10
  from pyvista import ColorLike
11
11
 
12
- from .geom3 import Mesh, Curve3
12
+ from .geom3 import Mesh, Curve3, Vector3, Point3, Iso3
13
+ from .metrology import Length3
14
+ from .matplotlib import LabelPlace
15
+
16
+ PlotCoords = Union[Point3, Vector3, Iterable[float]]
13
17
 
14
18
  try:
15
19
  import pyvista
@@ -22,12 +26,12 @@ else:
22
26
  self.plotter = plotter
23
27
 
24
28
  def add_curves(
25
- self,
26
- *curves: Curve3,
27
- color: ColorLike = "w",
28
- width: float = 5.0,
29
- label: str | None = None,
30
- name: str | None = None,
29
+ self,
30
+ *curves: Curve3,
31
+ color: ColorLike = "w",
32
+ width: float = 5.0,
33
+ label: str | None = None,
34
+ name: str | None = None,
31
35
  ) -> List[pyvista.vtkActor]:
32
36
  """
33
37
 
@@ -58,7 +62,117 @@ else:
58
62
  :param mesh:
59
63
  :return:
60
64
  """
61
- prefix = numpy.ones((mesh.triangles.shape[0], 1), dtype=mesh.triangles.dtype)
62
- faces = numpy.hstack((prefix * 3, mesh.triangles))
63
- data = pyvista.PolyData(mesh.points, faces)
65
+ if "cmap" in kwargs:
66
+ cmap_extremes = _cmap_extremes(kwargs["cmap"])
67
+ kwargs.update(cmap_extremes)
68
+
69
+ prefix = numpy.ones((mesh.faces.shape[0], 1), dtype=mesh.faces.dtype)
70
+ faces = numpy.hstack((prefix * 3, mesh.faces))
71
+ data = pyvista.PolyData(mesh.vertices, faces)
64
72
  return self.plotter.add_mesh(data, **kwargs)
73
+
74
+ def dimension(
75
+ self,
76
+ length: Length3,
77
+ template: str = "{value:.3f}",
78
+ label_place: LabelPlace = LabelPlace.Outside,
79
+ label_offset: float | None = None,
80
+ text_size: int = 16,
81
+ scale_value: float = 1.0,
82
+ ):
83
+ label_offset = label_offset or max(abs(length.value), 1.0) * 3
84
+
85
+ t_a = length.center.scalar_projection(length.a)
86
+ t_b = length.center.scalar_projection(length.b)
87
+
88
+ outside = length.center.at_distance(max(t_a, t_b))
89
+ inside = length.center.at_distance(min(t_a, t_b))
90
+
91
+ circles = []
92
+ builder = LineBuilder()
93
+
94
+ builder.add(inside - length.direction * label_offset * 0.25)
95
+ builder.add(inside)
96
+ circles.append(inside)
97
+ builder.skip()
98
+
99
+ circles.append(outside)
100
+ builder.add(outside)
101
+ builder.add(outside + length.direction * label_offset)
102
+
103
+ points = numpy.array([_tuplefy(p) for p in circles], dtype=numpy.float64)
104
+ self.plotter.add_points(points, color="black", point_size=4, render_points_as_spheres=True)
105
+
106
+ lines = builder.build()
107
+ self.plotter.add_lines(lines, color="black", width=1.5)
108
+
109
+ value = length.value * scale_value
110
+ label = pyvista.Label(text=template.format(value=value), position=lines[-1], size=text_size)
111
+ self.plotter.add_actor(label)
112
+
113
+ def coordinate_frame(self, iso: Iso3, size: float = 1.0):
114
+ points = numpy.array([[0, 0, 0], [size, 0, 0], [0, size, 0], [0, 0, size]], dtype=numpy.float64)
115
+ points = iso.transform_points(points)
116
+
117
+ self.plotter.add_lines(points[[0, 1]], color="red", width=5.0)
118
+ self.plotter.add_lines(points[[0, 2]], color="green", width=5.0)
119
+ self.plotter.add_lines(points[[0, 3]], color="blue", width=5.0)
120
+
121
+ def label(self, point: PlotCoords, text: str, **kwargs):
122
+ label = pyvista.Label(text=text, position=_tuplefy(point), **kwargs)
123
+ self.plotter.add_actor(label)
124
+
125
+ def arrow(self, start: PlotCoords, direction: PlotCoords,
126
+ tip_length: float = 0.25,
127
+ tip_radius: float = 0.1,
128
+ shaft_radius: float = 0.05,
129
+ **kwargs):
130
+ pd = pyvista.Arrow(_tuplefy(start), _tuplefy(direction), tip_length=tip_length, tip_radius=tip_radius,
131
+ shaft_radius=shaft_radius)
132
+ self.plotter.add_mesh(pd, **kwargs, color="black")
133
+
134
+
135
+ def _cmap_extremes(item: Any) -> Dict[str, ColorLike]:
136
+ working = {}
137
+ try:
138
+ from matplotlib.colors import Colormap
139
+ except ImportError:
140
+ return working
141
+ else:
142
+ if isinstance(item, Colormap):
143
+ over = getattr(item, "_rgba_over", None)
144
+ under = getattr(item, "_rgba_under", None)
145
+ if over is not None:
146
+ working["above_color"] = over
147
+ if under is not None:
148
+ working["below_color"] = under
149
+ return working
150
+
151
+
152
+ class LineBuilder:
153
+ def __init__(self):
154
+ self.vertices = []
155
+ self._skip = 1
156
+
157
+ def add(self, points: PlotCoords):
158
+ if self.vertices:
159
+ if self._skip > 0:
160
+ self._skip -= 1
161
+ else:
162
+ self.vertices.append(self.vertices[-1])
163
+
164
+ self.vertices.append(_tuplefy(points))
165
+
166
+ def skip(self):
167
+ self._skip = 2
168
+
169
+ def build(self) -> numpy.ndarray:
170
+ return numpy.array(self.vertices, dtype=numpy.float64)
171
+
172
+
173
+ def _tuplefy(item: PlotCoords) -> Tuple[float, float, float]:
174
+ if isinstance(item, (Point3, Vector3)):
175
+ return item.x, item.y, item.z
176
+ else:
177
+ x, y, z, *_ = item
178
+ return x, y, z
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engeom
3
- Version: 0.2.1
3
+ Version: 0.2.4
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,18 +1,18 @@
1
- engeom-0.2.1.dist-info/METADATA,sha256=8MGvMlNyJjmeSSKaFGTM71uhryuOUrx9K_BpDPwVAfQ,339
2
- engeom-0.2.1.dist-info/WHEEL,sha256=mYDPFrpmO1_UhonyEoMo2i0zHOwqc92hj_Q3CYuEBdM,94
1
+ engeom-0.2.4.dist-info/METADATA,sha256=ihtRy0gEfQ1gc10xbpncuk_Uc_-ocxIR2HyZEejVXto,339
2
+ engeom-0.2.4.dist-info/WHEEL,sha256=_g1M2QM3kt1Ssm_sHOg_3TUY7GxNE2Ueyslb9ZDtPwk,94
3
3
  engeom/airfoil/__init__.py,sha256=G6m7JEvHVk3sM2JooJPOg8JNA3VuEp0EIqczSEbC_PY,180
4
4
  engeom/airfoil.pyi,sha256=0TVpXkolFUXbBqJp93FenA_XqvU7FD1DnbncAF0ubow,14654
5
5
  engeom/align/__init__.py,sha256=SEeMqeqLKqJC73Mg8GwPwd9NwWnl-dcCqJ4rPdh8yyc,196
6
6
  engeom/align.pyi,sha256=QCSKrTLkCoaIubcrPU9J-wDZe1lRP0GbPgWZmonXjo0,997
7
- engeom/engeom.pyi,sha256=Il7TIk8Z5QgZENLVBgb2Pj11MIHCRbQCdDvgMh9LRgk,194
7
+ engeom/engeom.pyi,sha256=Jia11rU8ZnMKdlXgfGeBPlSmsYPEfALM-_ufNwR0ibQ,254
8
8
  engeom/geom2/__init__.py,sha256=mRu8Zh6DE-EQyhxScoxszPqDjGVzGWVJEQO6RIAtS4A,174
9
9
  engeom/geom2.pyi,sha256=Jh0ES-Gvkl7sFQV7VG6KdwgDbCPhmiETG_YOObYazhU,22741
10
10
  engeom/geom3/__init__.py,sha256=DG5jt2xgS9WRNb58ZkkrcKQQO6bIG-irg-uV_BkHEj4,174
11
- engeom/geom3.pyi,sha256=np6QjaeAS1Ms0Y4xNj4IoLRgI-rd9oh2sAH9TJem8Gw,28230
12
- engeom/matplotlib.py,sha256=3B2gRowUT5UDy-d46i9yANfoxoCa_BBuRo4HHb7NFYU,9275
11
+ engeom/geom3.pyi,sha256=UUUg3OHobF_MfSDJZXD0PEZGSak2XQpiGAkne3lY7fI,34163
12
+ engeom/matplotlib.py,sha256=A0gdQshzE3G7joNHna4viYnioQtA8LVXfSuZ_X6AHeo,9001
13
13
  engeom/metrology/__init__.py,sha256=cpsB0-hJGitzW79Coxwf7r_mpNaeI6yG3myDEVdBJgk,186
14
- engeom/metrology.pyi,sha256=dEPRtvc8us6rMLwg3wIWUa92Udew_QN_Y71NV9zGf2s,572
15
- engeom/pyvista.py,sha256=g3wwolj-F0kDSVuDl03CN-DbbR2R71dz-hzqard3bQs,1703
14
+ engeom/metrology.pyi,sha256=P_2pkoLUAOB0-RKppj0FN01XGY0jx1lGw9H1eKXrW8s,1144
15
+ engeom/pyvista.py,sha256=WVjaMG1hhd6hkknfxgkgCH8rZRXaM2AweG39T0UQkGc,6044
16
16
  engeom/__init__.py,sha256=kYgFq3jq1quDfV013wEYQMlUBz4QNSpP6u8lFiuTHvc,115
17
- engeom/engeom.pyd,sha256=UtK_xCx3NZB_wyw6AtsXZrODS-dRgTDvYYVaANM4Moc,1592832
18
- engeom-0.2.1.dist-info/RECORD,,
17
+ engeom/engeom.pyd,sha256=7G9m_LBBIJkK7bVNkiV0Z6rQ0VA1R-KuVkZcB_w4rPE,2317312
18
+ engeom-0.2.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.8.1)
2
+ Generator: maturin (1.8.2)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp38-abi3-win_amd64