engeom 0.2.4__tar.gz → 0.2.6__tar.gz

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.
Files changed (154) hide show
  1. {engeom-0.2.4 → engeom-0.2.6}/Cargo.lock +1 -1
  2. {engeom-0.2.4 → engeom-0.2.6}/Cargo.toml +1 -1
  3. {engeom-0.2.4 → engeom-0.2.6}/PKG-INFO +7 -1
  4. engeom-0.2.6/README.md +3 -0
  5. engeom-0.2.6/docs/airfoils/intro.md +13 -0
  6. engeom-0.2.6/docs/api/airfoil.md +3 -0
  7. engeom-0.2.6/docs/api/engeom.md +5 -0
  8. engeom-0.2.6/docs/api/geom2.md +3 -0
  9. engeom-0.2.6/docs/api/geom3.md +4 -0
  10. engeom-0.2.6/docs/api/metrology.md +9 -0
  11. engeom-0.2.6/docs/api/plot.md +15 -0
  12. engeom-0.2.6/docs/bounding_volumes.md +112 -0
  13. engeom-0.2.6/docs/curves.md +111 -0
  14. engeom-0.2.6/docs/index.md +27 -0
  15. engeom-0.2.6/docs/isometries.md +146 -0
  16. engeom-0.2.6/docs/meshes.md +319 -0
  17. engeom-0.2.6/docs/metrology.md +11 -0
  18. engeom-0.2.6/docs/numpy.md +13 -0
  19. engeom-0.2.6/docs/planes_circles_lines.md +7 -0
  20. engeom-0.2.6/docs/points_vectors.md +175 -0
  21. engeom-0.2.6/docs/surf_points.md +159 -0
  22. engeom-0.2.6/docs/svd_basis.md +103 -0
  23. engeom-0.2.6/engeom/docs/common/images/surface_point_meas.svg +553 -0
  24. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil/camber.rs +26 -17
  25. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil.rs +7 -7
  26. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/func1/series1.rs +1 -1
  27. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2.rs +52 -0
  28. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/measurement.rs +3 -3
  29. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh.rs +0 -1
  30. engeom-0.2.6/engeom/src/metrology/dimension.rs +97 -0
  31. engeom-0.2.6/engeom/src/metrology.rs +58 -0
  32. engeom-0.2.6/mkdocs.yml +54 -0
  33. engeom-0.2.6/python/engeom/_plot/__init__.py +1 -0
  34. engeom-0.2.6/python/engeom/_plot/common.py +17 -0
  35. {engeom-0.2.4/python/engeom → engeom-0.2.6/python/engeom/_plot}/matplotlib.py +88 -45
  36. engeom-0.2.6/python/engeom/_plot/pyvista.py +256 -0
  37. {engeom-0.2.4 → engeom-0.2.6}/python/engeom/airfoil/__init__.py +4 -0
  38. engeom-0.2.6/python/engeom/airfoil.pyi +485 -0
  39. engeom-0.2.6/python/engeom/engeom.pyi +46 -0
  40. engeom-0.2.6/python/engeom/geom2/__init__.py +10 -0
  41. engeom-0.2.6/python/engeom/geom2.pyi +1110 -0
  42. engeom-0.2.6/python/engeom/geom3/__init__.py +10 -0
  43. engeom-0.2.6/python/engeom/geom3.pyi +1284 -0
  44. {engeom-0.2.4 → engeom-0.2.6}/python/engeom/metrology/__init__.py +4 -0
  45. engeom-0.2.6/python/engeom/metrology.pyi +137 -0
  46. engeom-0.2.6/python/engeom/plot.py +26 -0
  47. {engeom-0.2.4 → engeom-0.2.6}/python/tests/test_geom2_simple.py +66 -0
  48. engeom-0.2.6/python/tests/test_geom3_simple.py +171 -0
  49. {engeom-0.2.4 → engeom-0.2.6}/src/airfoil.rs +5 -5
  50. {engeom-0.2.4 → engeom-0.2.6}/src/bounding.rs +98 -7
  51. {engeom-0.2.4 → engeom-0.2.6}/src/geom2.rs +68 -0
  52. {engeom-0.2.4 → engeom-0.2.6}/src/geom3.rs +56 -0
  53. {engeom-0.2.4 → engeom-0.2.6}/src/lib.rs +3 -3
  54. {engeom-0.2.4 → engeom-0.2.6}/src/mesh.rs +10 -10
  55. {engeom-0.2.4 → engeom-0.2.6}/src/metrology.rs +25 -17
  56. {engeom-0.2.4 → engeom-0.2.6}/src/svd_basis.rs +61 -19
  57. engeom-0.2.4/engeom/src/geom3/mesh/serialization.rs +0 -106
  58. engeom-0.2.4/engeom/src/metrology/dimension.rs +0 -45
  59. engeom-0.2.4/engeom/src/metrology.rs +0 -18
  60. engeom-0.2.4/python/engeom/airfoil.pyi +0 -334
  61. engeom-0.2.4/python/engeom/engeom.pyi +0 -13
  62. engeom-0.2.4/python/engeom/geom2/__init__.py +0 -5
  63. engeom-0.2.4/python/engeom/geom2.pyi +0 -734
  64. engeom-0.2.4/python/engeom/geom3/__init__.py +0 -5
  65. engeom-0.2.4/python/engeom/geom3.pyi +0 -902
  66. engeom-0.2.4/python/engeom/metrology.pyi +0 -64
  67. engeom-0.2.4/python/engeom/pyvista.py +0 -178
  68. {engeom-0.2.4 → engeom-0.2.6}/.github/workflows/CI.yml +0 -0
  69. {engeom-0.2.4 → engeom-0.2.6}/.gitignore +0 -0
  70. {engeom-0.2.4 → engeom-0.2.6}/.gitmodules +0 -0
  71. {engeom-0.2.4/engeom/docs/common → engeom-0.2.6/docs}/images/surface_point_meas.svg +0 -0
  72. {engeom-0.2.4 → engeom-0.2.6}/engeom/.gitignore +0 -0
  73. {engeom-0.2.4 → engeom-0.2.6}/engeom/Cargo.lock +0 -0
  74. {engeom-0.2.4 → engeom-0.2.6}/engeom/Cargo.toml +0 -0
  75. {engeom-0.2.4 → engeom-0.2.6}/engeom/README.md +0 -0
  76. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/airfoils/camber.md +0 -0
  77. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/airfoils/overview.md +0 -0
  78. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/common/angles.md +0 -0
  79. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/common/core_space.md +0 -0
  80. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/common/discrete_domain.md +0 -0
  81. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/common/svd_basis.md +0 -0
  82. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/geom2/alignment.md +0 -0
  83. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/geom2/curve.md +0 -0
  84. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/geom2/point_collections.md +0 -0
  85. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/geom2/shapes.md +0 -0
  86. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/index.md +0 -0
  87. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/javascripts/mathjax.js +0 -0
  88. {engeom-0.2.4 → engeom-0.2.6}/engeom/docs/python_rust.md +0 -0
  89. {engeom-0.2.4 → engeom-0.2.6}/engeom/mkdocs.yml +0 -0
  90. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil/edges.rs +0 -0
  91. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil/helpers.rs +0 -0
  92. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil/inscribed_circle.rs +0 -0
  93. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/airfoil/orientation.rs +0 -0
  94. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/align.rs +0 -0
  95. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/angles.rs +0 -0
  96. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/convert_2d_3d.rs +0 -0
  97. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/discrete_domain.rs +0 -0
  98. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/indices.rs +0 -0
  99. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/interval.rs +0 -0
  100. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/kd_tree.rs +0 -0
  101. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/points.rs +0 -0
  102. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/poisson_disk.rs +0 -0
  103. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/surface_point.rs +0 -0
  104. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/svd_basis.rs +0 -0
  105. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common/vec_f64.rs +0 -0
  106. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/common.rs +0 -0
  107. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/errors.rs +0 -0
  108. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/func1/common_functions.rs +0 -0
  109. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/func1/polynomial.rs +0 -0
  110. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/func1.rs +0 -0
  111. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/aabb2.rs +0 -0
  112. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/align2/jacobian.rs +0 -0
  113. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/align2/points_to_curve.rs +0 -0
  114. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/align2/rc_params2.rs +0 -0
  115. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/align2.rs +0 -0
  116. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/angles2.rs +0 -0
  117. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/circle2.rs +0 -0
  118. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/curve2.rs +0 -0
  119. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/hull.rs +0 -0
  120. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/line2.rs +0 -0
  121. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom2/polyline2.rs +0 -0
  122. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/align3/jacobian.rs +0 -0
  123. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/align3/multi_param.rs +0 -0
  124. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/align3/points_to_mesh.rs +0 -0
  125. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/align3/rotations.rs +0 -0
  126. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/align3.rs +0 -0
  127. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/curve3.rs +0 -0
  128. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/conformal.rs +0 -0
  129. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/edges.rs +0 -0
  130. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/faces.rs +0 -0
  131. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/filtering.rs +0 -0
  132. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/patches.rs +0 -0
  133. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/queries.rs +0 -0
  134. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/sampling.rs +0 -0
  135. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/mesh/uv_mapping.rs +0 -0
  136. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/plane3.rs +0 -0
  137. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3/point_cloud.rs +0 -0
  138. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/geom3.rs +0 -0
  139. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/io.rs +0 -0
  140. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/lib.rs +0 -0
  141. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/metrology/line_profiles.rs +0 -0
  142. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/metrology/surface_deviation.rs +0 -0
  143. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/metrology/tolerance.rs +0 -0
  144. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/metrology/tolerance_map.rs +0 -0
  145. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/stats.rs +0 -0
  146. {engeom-0.2.4 → engeom-0.2.6}/engeom/src/utility.rs +0 -0
  147. {engeom-0.2.4 → engeom-0.2.6}/pyproject.toml +0 -0
  148. {engeom-0.2.4 → engeom-0.2.6}/python/engeom/__init__.py +0 -0
  149. {engeom-0.2.4 → engeom-0.2.6}/python/engeom/align/__init__.py +0 -0
  150. {engeom-0.2.4 → engeom-0.2.6}/python/engeom/align.pyi +0 -0
  151. {engeom-0.2.4 → engeom-0.2.6}/python/tests/test_all.py +0 -0
  152. {engeom-0.2.4 → engeom-0.2.6}/src/alignments.rs +0 -0
  153. {engeom-0.2.4 → engeom-0.2.6}/src/common.rs +0 -0
  154. {engeom-0.2.4 → engeom-0.2.6}/src/conversions.rs +0 -0
@@ -1024,7 +1024,7 @@ dependencies = [
1024
1024
 
1025
1025
  [[package]]
1026
1026
  name = "py-engeom"
1027
- version = "0.2.4"
1027
+ version = "0.2.6"
1028
1028
  dependencies = [
1029
1029
  "engeom",
1030
1030
  "numpy",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "py-engeom"
3
- version = "0.2.4"
3
+ version = "0.2.6"
4
4
  edition = "2021"
5
5
 
6
6
  # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engeom
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -8,3 +8,9 @@ Requires-Dist: numpy
8
8
  Requires-Dist: pytest ; extra == 'tests'
9
9
  Provides-Extra: tests
10
10
  Requires-Python: >=3.8
11
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
12
+
13
+ # Engeom Python Bindings
14
+
15
+ Full documentation at https://mattj23.github.io/py-engeom/
16
+
engeom-0.2.6/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Engeom Python Bindings
2
+
3
+ Full documentation at https://mattj23.github.io/py-engeom/
@@ -0,0 +1,13 @@
1
+ # Airfoil Introduction
2
+
3
+ An airfoil is a body designed to produce asymmetrical forces when moving through a fluid. Airfoils are a common subject
4
+ of metrology and engineering analysis in the aerospace and aerospace propulsion industries.
5
+
6
+ The `engeom` library has tools for airfoil analysis centered around the 2D cross-sections of airfoil bodies. This is a
7
+ function of the aerospace industry's historical use of 2D drawings to specify airfoil dimensional requirements and
8
+ performance characteristics.
9
+
10
+ Airfoil analysis is a complicated subject with a lot of specialized tools and terminology based on convention and
11
+ historical precedent. There aren't typically one-size-fits-all algorithms and methods because of the extreme variation
12
+ in airfoil shapes and requirements. Different institutions and organizations even within the same industry will often
13
+ have their own preferred methods, tools, and sometimes even terminology.
@@ -0,0 +1,3 @@
1
+ # Airfoil Module
2
+
3
+ ::: engeom.airfoil
@@ -0,0 +1,5 @@
1
+ # Engeom
2
+
3
+ The `engeom` main module has a handful of common entities shared across other parts of the library.
4
+
5
+ ::: engeom
@@ -0,0 +1,3 @@
1
+ # Geom2 Module
2
+
3
+ ::: engeom.geom2
@@ -0,0 +1,4 @@
1
+ # Geom3 Module
2
+
3
+ ::: engeom.geom3
4
+
@@ -0,0 +1,9 @@
1
+ # Metrology Module
2
+
3
+ !!! warning
4
+ The metrology feature set is still experimental and is under heavy development in the Rust `engeom` library.
5
+ Expect significant changes to the API in the future.
6
+
7
+ ::: engeom.metrology
8
+ options:
9
+ show_source: false
@@ -0,0 +1,15 @@
1
+ # Plot Module
2
+
3
+ !!! warning
4
+ This module's API is still under development and will likely change in the future.
5
+
6
+ ::: engeom.plot
7
+ options:
8
+ show_source: false
9
+ members:
10
+ - LabelPlace
11
+ - PyvistaPlotterHelper
12
+ - GOM_CMAP
13
+ - GomColorMap
14
+ - MatplotlibAxesHelper
15
+
@@ -0,0 +1,112 @@
1
+ # Bounding Volumes
2
+
3
+ There are currently two types of bounding volumes available in the `engeom` library. Both are axis-aligned bounding
4
+ boxes (AABBs), but one is for 2D (`Aabb2`) and the other is for 3D (`Aabb3`).
5
+
6
+ These bounding volumes are primarily used within the Rust language library as an internal mechanism to support data
7
+ structures which accelerate distance queries and intersection checks. However, they also have a number of useful
8
+ features and so are exposed to the Python API.
9
+
10
+ ## Creating Bounding Volumes
11
+
12
+ Most commonly, bounding volumes are created internally by the library for geometries that are part of acceleration
13
+ structures or have clear spatial bounds, and accessed by retrieving them from those entities. However, through the
14
+ Python API, they can also be created directly.
15
+
16
+ ```python
17
+ from engeom.geom2 import Aabb2
18
+ from engeom.geom3 import Aabb3
19
+
20
+ # Create a 2D AABB. The arguments are x_min, y_min, x_max, y_max.
21
+ box2 = Aabb2(-1, -2, 3, 4)
22
+
23
+ # Create a 3D AABB. The arguments are x_min, y_min, z_min, x_max, y_max, z_max.
24
+ box3 = Aabb3(-1, -2, -3, 3, 4, 5)
25
+ ```
26
+
27
+ Two other convenient methods for creating bounding volumes are `from_points` and `at_point`.
28
+
29
+ The `from_points` function creates a bounding volume that contains all the points in the input list. Pass it a list of
30
+ points as a numpy array, and it will determine the bounds.
31
+
32
+ ```python
33
+ import numpy
34
+ from engeom.geom2 import Aabb2
35
+ from engeom.geom3 import Aabb3
36
+
37
+ points = numpy.array([[0, 0, 0],
38
+ [1, 1, 1],
39
+ [2, 2, 2],
40
+ [3, 3, 3]]).astype(numpy.float64)
41
+
42
+ # Create boxes that contain all the points
43
+ box2 = Aabb2.from_points(points[:, :2])
44
+ box3 = Aabb3.from_points(points)
45
+ ```
46
+
47
+ The `at_point` function creates a bounding volume centered at the specified point with the specified dimensions. The
48
+ arguments are the center point and the dimensions of the box. The 2D version takes 4 arguments (x, y, width, height),
49
+ and the 3D version takes 6 arguments (x, y, z, width, height, depth).
50
+
51
+ ```python
52
+ from engeom.geom2 import Aabb2
53
+ from engeom.geom3 import Aabb3
54
+
55
+ # Create a 2D AABB centered at the point (1, 2) that is 3 units wide (x)
56
+ # and 4 units tall (y).
57
+ box2 = Aabb2.at_point(1, 2, 3, 4)
58
+
59
+ # Create a 3D AABB centered at the point (1, 2, 3) that is 4 units wide (x),
60
+ # 5 units tall (y), and 6 units deep (z).
61
+ box3 = Aabb3.at_point(1, 2, 3, 4, 5, 6)
62
+ ```
63
+
64
+ ## Bounding Volume Properties
65
+
66
+ There are four properties of bounding volumes, both 2D and 3D, that can be accessed and yield point and vector values
67
+ related to the geometry of the volume.
68
+
69
+ | Property | Type | Description |
70
+ |-----------|---------------------|------------------------------------------------------------------|
71
+ | `.center` | `Point2`/`Point3` | The center point of the bounding volume |
72
+ | `.min` | `Point2`/`Point3` | The minimum corner point of the bounding volume |
73
+ | `.max` | `Point2`/`Point3` | The maximum corner point of the bounding volume |
74
+ | `.extent` | `Vector2`/`Vector3` | The extents of the bounding volume (equivalent to `.max - .min`) |
75
+
76
+ ```python
77
+ from engeom.geom3 import Aabb3
78
+
79
+ box = Aabb3(-1, -2, -3, 1, 2, 3)
80
+
81
+ # Get the center point of the box
82
+ print(box.center) # Point3(0, 0, 0)
83
+ print(box.min) # Point3(-1, -2, -3)
84
+ print(box.max) # Point3(1, 2, 3)
85
+ print(box.extent) # Vector3(2, 4, 6)
86
+ ```
87
+
88
+ ## Expand and Shrink
89
+
90
+ Bounding volumes can be expanded or shrunk by a specified amount, yielding a new bounding volume. The `expand` and
91
+ `shrink` methods take a single argument, which is the amount to expand or shrink the perimeter of the bounding volume.
92
+
93
+ The overall change in the size of the extents will be twice the amount specified. For example, if you expand a 2D box
94
+ by 1 unit, the width and height will each increase by 2 units.
95
+
96
+ ```python
97
+ from engeom.geom2 import Aabb2
98
+ box = Aabb2(-1, -2, 1, 2)
99
+
100
+ print(box.extent) # Vector2(2, 4)
101
+
102
+ expanded = box.expand(0.5)
103
+ print(expanded.extent) # Vector2(3, 5)
104
+
105
+ shrunk = box.shrink(0.5)
106
+ print(shrunk.extent) # Vector2(1, 3)
107
+ ```
108
+
109
+ ## Intersection and Containment
110
+
111
+ !!! warning
112
+ Intersection and containment options are not yet bound to the Python API. This will be added in a future release.
@@ -0,0 +1,111 @@
1
+ # Curves
2
+
3
+ ## Introduction
4
+
5
+ The `engeom` library has both a 2D and 3D curve type. This type represents a 1-dimensional manifold that consists of
6
+ a sequence of vertices in $\mathbb{R}^n$ space that are connected by line-segment edges, sometimes referred to as a
7
+ polyline.
8
+
9
+ Each curve entity consists of a single contiguous sequence of vertices with a clear start and end point. In the case of
10
+ the 2D `Curve2` type, the curve can also be "closed", meaning that the end point is connected to the start point to
11
+ form a closed loop and so operations on the manifold that cross the end point will wrap around to the start point,
12
+ and vice versa.
13
+
14
+ While the fundamental operations on a curve, such as distance queries and manifold traversal are the same or similar
15
+ for the 2D and 3D curve types, the 2D curve type has many more features that are made possible by the 2D plane.
16
+
17
+ ## 2D Curves
18
+
19
+ The 2D curve type, `Curve2`, is a more feature-rich type than the 3D curve type, because the nature of the 2D plane
20
+ means that a 2D polyline is more conceptually related to a 3D `Mesh` object than it is to a 3D polyline. A `Curve2`
21
+ object can represent a boundary/surface with a clear sense of "inside" and "outside", and if it forms a closed loop
22
+ it can model a partitioning of the $\mathbb{R}^2$ plane into an interior and exterior region.
23
+
24
+ In 2D, a curve has concept of a surface normal direction, which is built from the concept inside/outside defined through
25
+ the winding order of the vertices. By convention, the segment from vertex $i$ to vertex $i+1$ defines the space to
26
+ its "right" as being outside the curve, and the space to its "left" as being inside the curve, resulting in a
27
+ counter-clockwise winding order defining a positive convex shape.
28
+
29
+ ### Creation
30
+
31
+ Creation of a `Curve2` object is done by passing in a list of ordered vertices that define the curve. The vertices
32
+ will be interpreted in sequential order, so that each vertex will be connected to the next vertex in the list.
33
+
34
+ Adjacent vertices that are within a distance tolerance from each other will be de-duplicated, to prevent the curve from
35
+ having zero-length segments. Additionally, if the first and last point are within the distance tolerance, the curve
36
+ will be considered "closed" and algorithms which do manifold traversal will wrap between the first and last points.
37
+
38
+ However, because of the importance of winding order on 2D curves, the `Curve2` type must *also* be constructed with the
39
+ vertices in the specific order that matches the intended definition of "inside" vs "outside" for the curve.
40
+
41
+ While the space occupied by the curve might be exactly the same whether the vertices are constructed in forward or
42
+ reverse order, the inside vs outside will be opposite.
43
+
44
+ There are three ways that winding order can be specified during construction of a `Curve2` object:
45
+
46
+ 1. You can prepare the list of vertices so that they are in the correct order and then pass them into the constructor.
47
+ Counter-clockwise order of vertices for positive convex shapes/regions, and clockwise order for negative convex
48
+ shapes/regions.
49
+
50
+ 2. If you know that the curve is meant to represent a positive (convex) shape overall, you can set the `hull_ccw=True`
51
+ flag. The constructor will build the convex hull of the vertices you provide and reverse their order if the hull
52
+ sequence does not match the input sequence.
53
+
54
+ 3. You may provide the constructor with an array of surface normals that correspond with the vertices. There must be one
55
+ normal per vertex in the input list, and it must be pointing in the direction that you intend to be the "outside" of
56
+ the surface. The constructor will reverse the input order if the majority of normals are not pointing in the same
57
+ direction as the winding order would imply.
58
+
59
+ The input arguments for the constructor are:
60
+
61
+ | Argument | Type | Description |
62
+ |----------------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
63
+ | `vertices` | `numpy.ndarray` | A 2D array of shape `(n, 2)` where `n` is the number of vertices in the curve. The columns are the x and y components of the vertices |
64
+ | `normals` | `numpy.ndarray` **OPTIONAL** | A 2D array of shape `(n, 2)` where `n` is the number of vertices in the curve. The columns are the x and y components of the normals at each vertex. Default is `None`. |
65
+ | `tol` | `float` **OPTIONAL** | A tolerance distance, below which points are considered to be the same and de-duplicated. Default is `1e-6` |
66
+ | `force_closed` | `bool` **OPTIONAL** | If `True`, the curve will be guaranteed to be closed. If the first and last point are more than `tol` distance apart, an additional vertex will be added to the end that overlaps with the beginning. Default is `False` |
67
+ | `hull_ccw` | `bool` **OPTIONAL** | If `True`, the vertices will be re-ordered to match the convex hull of the vertices. Default is `False`. This will be ignored if `normals` is not `None` |
68
+
69
+ ```python
70
+ import numpy
71
+ from engeom.geom2 import Curve2
72
+
73
+ # These are the corners of an open unit square
74
+ vertices = numpy.array([[0.0, 0], [1, 0], [1, 1], [0, 1]])
75
+
76
+ # Create a curve with these vertices and nothing else
77
+ c1 = Curve2(vertices)
78
+ print(c1) # <Curve2 n=4, l=3 (open)>
79
+
80
+ # Force the curve to be closed
81
+ c2 = Curve2(vertices, force_closed=True)
82
+ print(c2) # <Curve2 n=5, l=4 (closed)>
83
+ ```
84
+
85
+ ### Stations
86
+
87
+ Because a `Curve2` object is a 1D manifold, every unique position along the curve can be represented by a single scalar
88
+ value, which is the length from the start of the curve. Each unique position along a 2D curve has several geometric
89
+ properties which are useful. These properties are bundled in a `CurveStation2` object, which is a lightweight data
90
+ object that represents a single position on the manifold.
91
+
92
+ `CurveStation2` objects are not created directly, but are retrieved from a `Curve2` object through one of several different possible queries on the manifold.
93
+
94
+ The `CurveStation2` object has the following properties:
95
+
96
+ | Property | Type | Description |
97
+ |--------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
98
+ | `.point` | `Point2` | The 2D position in space that corresponds with the station on the manifold. |
99
+ | `.direction` | `Vector2` | The vector pointing in the direction of positive distance along the curve. Typically this is the vector from the last vertex to the next vertex. |
100
+ | `.normal` | `Vector2` | The vector pointing in the direction of the surface normal at the station. This is the `direction` vector rotated by $-90°$. |
101
+ | `.direction_point` | `SurfacePoint2` | A convenience surface point that combines the `point` position and `direction` vector. |
102
+ | `.surface_point` | `SurfacePoint2` | A convenience surface point that combines the `point` position and `normal` vector. |
103
+ | `.index` | `int` | The index of the previous vertex on the curve, at or before the station. |
104
+ | `.length_along` | `float` | The distance along the curve from the start to the station. This is the manifold domain. |
105
+
106
+
107
+ ### Querying
108
+
109
+
110
+
111
+
@@ -0,0 +1,27 @@
1
+ # Engeom (Python Bindings)
2
+
3
+ This site has the documentation for the Python bindings of the `engeom` library.
4
+
5
+ The [`engeom` library](https://github.com/mattj23/engeom) is a Rust library for 2D and 3D engineering geometry, with a specific focus on metrology applications. The Python bindings provide a way to use some of the library's functionality in Python, with a reasonably similar interface to the Rust library.
6
+
7
+ The bindings are built using `pyo3` and `maturin` and `engeom` is compiled as a self-contained extension library, so the python module is the only thing which needs to be installed on an interpreter for everything to work. It is available for Python versions `>=3.8`, for Windows/Linux/macOS, and on most common 64-bit architectures.
8
+
9
+ ## Quick Overview
10
+
11
+ The `engeom` Python library has a few general feature sets:
12
+
13
+ - 2D and 3D geometric primitives (points, vectors, planes, circles/arcs, line segments, transformation matrices, etc) which can be used to represent and perform basic geometric operations through a simple and consistent interface.
14
+ - More complicated entities like 3D triangle meshes, 2D and 3D polylines, and 3D point clouds, with common operations like intersections, projections, distance queries, transformations, etc.
15
+ - Some basic fitting and alignment algorithms for 2D and 3D data
16
+ - Helper functions for plotting and visualization to assist in use of the `matplotlib` and `pyvista` libraries.
17
+
18
+ ## Installation
19
+
20
+ The Python bindings can be installed using `pip`:
21
+
22
+ ```bash
23
+ pip install engeom
24
+ ```
25
+
26
+
27
+
@@ -0,0 +1,146 @@
1
+ # Isometries (Rigid-body Transformations)
2
+
3
+ Isometries are a class of transformations that preserve distances between points. They are also known as rigid-body
4
+ transformations, as they preserve the shape of the object being transformed.
5
+
6
+ In the underlying Rust `engeom` library, isometries are aliases for a native `nalgebra` struct. In two dimensions this
7
+ consists of a 2D translation and a unit complex for rotation, and in three dimensions it consists of a 3D translation
8
+ and a unit quaternion for rotation.
9
+
10
+ Isometries can be thought of as equivalent to transformation matrices, but with the limitation that certain matrices
11
+ are not valid isometries because they do not preserve distances. They can be composed together by multiplication
12
+ according to the rules of matrix multiplication, inverted according to the rules of matrix inversion, and they can be
13
+ multiplied against points or vectors to transform them.
14
+
15
+ ## Creating Isometries
16
+
17
+ Two-dimensional isometries can be created directly from three scalar values: the x and y components of the translation,
18
+ and the angle of rotation in radians. Three-dimensional isometries are more complicated, and are easiest to create
19
+ through composition.
20
+
21
+ ### Two-dimensional Isometries
22
+
23
+ ```python
24
+ from math import pi
25
+ from engeom.geom2 import Iso2
26
+
27
+ # Shortcut for the identity transform
28
+ i0 = Iso2.identity()
29
+
30
+ # Create an isometry that translates by (1, 2) and rotates by pi/4 radians
31
+ i1 = Iso2(1, 2, pi / 4)
32
+ ```
33
+
34
+ ### Three-dimensional Isometries
35
+
36
+ ```python
37
+ import numpy
38
+ from math import pi
39
+ from engeom.geom3 import Iso3
40
+
41
+ # Shortcut for the identity transform
42
+ i0 = Iso3.identity()
43
+
44
+ # Try to create an isometry directly from a 4x4 transformation matrix. Will throw
45
+ # an exception if the matrix is not a valid isometry.
46
+ m = numpy.array([[1, 0, 0, 1],
47
+ [0, 1, 0, 2],
48
+ [0, 0, 1, 3],
49
+ [0, 0, 0, 1]])
50
+ i1 = Iso3(m)
51
+
52
+ # Create an isometry that only translates by specifying the translation vector
53
+ i2 = Iso3.from_translation(1, 2, 3)
54
+
55
+ # Create an isometry that rotates by pi/4 radians around the x-axis. See the documentation
56
+ # for `from_rotation` for more information on the arguments.
57
+ i3 = Iso3.from_rotation(pi / 4, 1, 0, 0)
58
+ ```
59
+
60
+ ## Inverting Isometries
61
+
62
+ Isometries can, by definition, be inverted. The inverse of an isometry is an isometry that, when applied to the result
63
+ of the original isometry, returns the original input. An isometry multiplied by its inverse is the identity isometry.
64
+
65
+ ```python
66
+ from math import pi
67
+ from engeom.geom3 import Iso3
68
+
69
+ i = Iso3.from_rotation(pi / 4, 1, 0, 0)
70
+
71
+ # Invert the isometry
72
+ i_inv = i.inverse()
73
+ ```
74
+
75
+
76
+ ## Composition
77
+
78
+ Isometries can be composed together by multiplying them together. The order of multiplication is important, as
79
+ isometries do not commute. The result of multiplying two isometries together is a new isometry that is equivalent to
80
+ apply the right hand isometry first, and then the left hand isometry.
81
+
82
+ The operator for isometry multiplication is the same as the matrix multiplication operator, `@`.
83
+
84
+ ```python
85
+ from math import pi
86
+ from engeom.geom3 import Iso3
87
+
88
+ i1 = Iso3.from_rotation(pi / 4, 1, 0, 0)
89
+ i2 = Iso3.from_translation(1, 2, 3)
90
+
91
+ # Apply the rotation first, then the translation
92
+
93
+ i3 = i2 @ i1
94
+ ```
95
+
96
+ ## Transforming Primitives
97
+
98
+ ### Vectors, Points, Surface Points, etc
99
+
100
+ Isometries can be applied to points, vectors, and other geometric primitives by multiplying them by the isometry using
101
+ the `@` operator.
102
+
103
+ * A point transformed by an isometry is a new point that is at a new position in space.
104
+ * A vector transformed by an isometry has been rotated, but its magnitude has not changed.
105
+ * A surface point transformed by an isometry is the result of transforming the point and the normal vector
106
+ independently, and then re-constituting them into a new surface point. The position has been moved and the normal
107
+ vector rotated but remains of unit magnitude.
108
+
109
+ ```python
110
+ from math import pi
111
+ from engeom.geom2 import Iso2, Vector2, Point2, SurfacePoint2
112
+
113
+ p = Point2(1, 2)
114
+ v = Vector2(1, 2)
115
+ sp = SurfacePoint2(1, 2, 1, 0)
116
+
117
+ i = Iso2(1, 2, pi / 4)
118
+
119
+ p2 = i @ p
120
+ v2 = i @ v
121
+ sp2 = i @ sp
122
+ ```
123
+
124
+ ### Numpy Arrays
125
+
126
+ For efficient transformation of large numbers of points or vectors, both 2D and 3D isometries can be applied to `numpy`
127
+ arrays representing points or vectors according to the rules defined in the previous section.
128
+
129
+ ```python
130
+ import numpy
131
+ from math import pi
132
+ from engeom.geom2 import Iso2
133
+
134
+ values = numpy.array([[1, 2],
135
+ [3, 4],
136
+ [5, 6],
137
+ [7, 8]])
138
+
139
+ i = Iso2(1, 2, pi / 4)
140
+
141
+ # Apply the isometry to the values as if they were points
142
+ new_points = i.transform_points(values)
143
+
144
+ # Apply the isometry to the values as if they were vectors
145
+ new_vectors = i.transform_vectors(values)
146
+ ```