engeom 0.2.15__tar.gz → 0.2.16__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 (220) hide show
  1. {engeom-0.2.15 → engeom-0.2.16}/Cargo.lock +13 -85
  2. {engeom-0.2.15 → engeom-0.2.16}/Cargo.toml +1 -1
  3. {engeom-0.2.15 → engeom-0.2.16}/PKG-INFO +1 -1
  4. {engeom-0.2.15 → engeom-0.2.16}/engeom/Cargo.toml +1 -1
  5. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil/helpers.rs +12 -12
  6. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/discrete_domain.rs +64 -0
  7. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/domain_window.rs +1 -1
  8. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/index_mask.rs +7 -1
  9. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/kd_tree.rs +59 -39
  10. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/points.rs +20 -4
  11. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/poisson_disk.rs +3 -2
  12. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/svd_basis.rs +10 -6
  13. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/func1/series1.rs +4 -7
  14. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/circle2.rs +1 -1
  15. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/curve2.rs +16 -16
  16. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/hull.rs +11 -2
  17. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/polyline2.rs +4 -4
  18. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/mesh.rs +49 -6
  19. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/multi_mesh.rs +47 -19
  20. engeom-0.2.16/engeom/src/geom3/align3/point_stability.rs +251 -0
  21. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3.rs +10 -1
  22. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/curve3.rs +14 -14
  23. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/collisions.rs +4 -5
  24. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/edges.rs +0 -1
  25. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/filtering.rs +89 -2
  26. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/half_edge/smoothing.rs +4 -1
  27. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/nav_structure.rs +390 -337
  28. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/sampling.rs +3 -3
  29. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/uv_mapping.rs +2 -2
  30. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh.rs +5 -13
  31. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/plane3.rs +1 -1
  32. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/point_cloud/normal_estimation.rs +1 -1
  33. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/point_cloud.rs +45 -16
  34. engeom-0.2.16/engeom/src/io/lptf3/comprehensive.rs +151 -0
  35. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io/lptf3/downsample.rs +1 -1
  36. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io/lptf3/loader.rs +14 -10
  37. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io/lptf3.rs +39 -1
  38. engeom-0.2.16/engeom/src/io/point_cloud.rs +148 -0
  39. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io.rs +3 -1
  40. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/lib.rs +1 -0
  41. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology/line_profiles.rs +4 -4
  42. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/kernel.rs +9 -4
  43. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/mapping.rs +1 -2
  44. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/raster_mask.rs +21 -12
  45. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/region_labeling.rs +2 -2
  46. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/roi.rs +3 -3
  47. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/roi_mask.rs +1 -1
  48. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/scalar_raster.rs +28 -5
  49. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/sensors/laser_profile.rs +20 -3
  50. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/sensors.rs +56 -56
  51. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/stats.rs +1 -1
  52. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/td/simple_viewer.rs +1 -2
  53. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/utility.rs +2 -2
  54. {engeom-0.2.15 → engeom-0.2.16/py-engeom}/python/engeom/geom3.pyi +31 -0
  55. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/geom3.rs +6 -0
  56. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/mesh.rs +9 -1
  57. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/point_cloud.rs +8 -2
  58. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/svd_basis.rs +18 -2
  59. {engeom-0.2.15/py-engeom → engeom-0.2.16}/python/engeom/geom3.pyi +31 -0
  60. {engeom-0.2.15 → engeom-0.2.16}/engeom/benches/convolution.rs +0 -0
  61. {engeom-0.2.15 → engeom-0.2.16}/engeom/benches/down_sample.rs +0 -0
  62. {engeom-0.2.15 → engeom-0.2.16}/engeom/benches/index_mask.rs +0 -0
  63. {engeom-0.2.15 → engeom-0.2.16}/engeom/benches/raster_ball_rolling.rs +0 -0
  64. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/airfoils/camber.md +0 -0
  65. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/airfoils/overview.md +0 -0
  66. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/common/angles.md +0 -0
  67. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/common/core_space.md +0 -0
  68. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/common/discrete_domain.md +0 -0
  69. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/common/images/surface_point_meas.svg +0 -0
  70. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/common/svd_basis.md +0 -0
  71. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/geom2/alignment.md +0 -0
  72. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/geom2/curve.md +0 -0
  73. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/geom2/point_collections.md +0 -0
  74. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/geom2/shapes.md +0 -0
  75. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/index.md +0 -0
  76. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/javascripts/mathjax.js +0 -0
  77. {engeom-0.2.15 → engeom-0.2.16}/engeom/docs/python_rust.md +0 -0
  78. {engeom-0.2.15 → engeom-0.2.16}/engeom/mkdocs.yml +0 -0
  79. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil/camber.rs +0 -0
  80. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil/edges.rs +0 -0
  81. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil/inscribed_circle.rs +0 -0
  82. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil/orientation.rs +0 -0
  83. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/airfoil.rs +0 -0
  84. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/align.rs +0 -0
  85. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/angles.rs +1 -1
  86. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/average.rs +0 -0
  87. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/convert_2d_3d.rs +0 -0
  88. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/domain_map.rs +0 -0
  89. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/indices.rs +0 -0
  90. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/interval.rs +0 -0
  91. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/surface_point.rs +0 -0
  92. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/triangulation/parallel_row2.rs +0 -0
  93. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/triangulation.rs +0 -0
  94. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/vec_f64.rs +0 -0
  95. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common/voxel_downsample.rs +0 -0
  96. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/common.rs +1 -1
  97. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/errors.rs +0 -0
  98. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/func1/common_functions.rs +0 -0
  99. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/func1/polynomial.rs +0 -0
  100. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/func1.rs +0 -0
  101. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/aabb2.rs +0 -0
  102. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/align2/jacobian.rs +0 -0
  103. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/align2/points_to_curve.rs +0 -0
  104. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/align2/rc_params2.rs +0 -0
  105. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/align2.rs +0 -0
  106. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/angles2.rs +0 -0
  107. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2/line2.rs +0 -0
  108. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom2.rs +0 -0
  109. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/jacobian.rs +0 -0
  110. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/mesh_overlap.rs +0 -0
  111. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/mesh_to_mesh.rs +0 -0
  112. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/multi_param.rs +0 -0
  113. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/points_to_cloud.rs +0 -0
  114. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/points_to_mesh.rs +0 -0
  115. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/align3/rotations.rs +0 -0
  116. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/iso3.rs +0 -0
  117. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/conformal.rs +0 -0
  118. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/faces.rs +0 -0
  119. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/half_edge.rs +0 -0
  120. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/measurement.rs +0 -0
  121. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/outline.rs +0 -0
  122. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/mesh/queries.rs +0 -0
  123. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3/xyzwpr.rs +0 -0
  124. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/geom3.rs +0 -0
  125. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io/lptf3/mesh.rs +0 -0
  126. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/io/lptf3/uncertainty.rs +0 -0
  127. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology/dimension.rs +0 -0
  128. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology/surface_deviation.rs +0 -0
  129. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology/tolerance.rs +0 -0
  130. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology/tolerance_map.rs +0 -0
  131. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/metrology.rs +0 -0
  132. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/area_average.rs +0 -0
  133. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/ball_rolling.rs +0 -0
  134. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/index_iter.rs +0 -0
  135. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/inpaint.rs +0 -0
  136. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/mask_ops.rs +0 -0
  137. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/visualize.rs +0 -0
  138. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2/zhang_suen.rs +0 -0
  139. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster2.rs +0 -0
  140. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/raster3.rs +0 -0
  141. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/td/common.rs +0 -0
  142. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/td/control.rs +0 -0
  143. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/td/conversion.rs +0 -0
  144. {engeom-0.2.15 → engeom-0.2.16}/engeom/src/td.rs +0 -0
  145. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/Cargo.toml +0 -0
  146. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/airfoils/intro.md +0 -0
  147. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/airfoil.md +0 -0
  148. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/engeom.md +0 -0
  149. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/geom2.md +0 -0
  150. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/geom3.md +0 -0
  151. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/metrology.md +0 -0
  152. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/api/plot.md +0 -0
  153. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/bounding_volumes.md +0 -0
  154. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/curves.md +0 -0
  155. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/images/surface_point_meas.svg +0 -0
  156. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/index.md +0 -0
  157. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/isometries.md +0 -0
  158. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/meshes.md +0 -0
  159. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/metrology.md +0 -0
  160. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/numpy.md +0 -0
  161. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/planes_circles_lines.md +0 -0
  162. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/points_vectors.md +0 -0
  163. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/surf_points.md +0 -0
  164. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/docs/svd_basis.md +0 -0
  165. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/mkdocs.yml +0 -0
  166. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/__init__.py +0 -0
  167. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/_plot/__init__.py +0 -0
  168. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/_plot/common.py +0 -0
  169. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/_plot/matplotlib.py +0 -0
  170. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/_plot/pyvista.py +0 -0
  171. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/airfoil/__init__.py +0 -0
  172. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/airfoil.pyi +0 -0
  173. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/align/__init__.py +0 -0
  174. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/align.pyi +0 -0
  175. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/engeom.pyi +0 -0
  176. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/geom2/__init__.py +0 -0
  177. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/geom2.pyi +0 -0
  178. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/geom3/__init__.py +0 -0
  179. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/metrology/__init__.py +0 -0
  180. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/metrology.pyi +0 -0
  181. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/plot.py +0 -0
  182. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/raster3/__init__.py +0 -0
  183. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/raster3.pyi +0 -0
  184. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/sensors/__init__.py +0 -0
  185. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/engeom/sensors.pyi +0 -0
  186. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/tests/test_all.py +0 -0
  187. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/tests/test_geom2_simple.py +0 -0
  188. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/python/tests/test_geom3_simple.py +0 -0
  189. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/airfoil.rs +0 -0
  190. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/alignments.rs +0 -0
  191. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/bounding.rs +0 -0
  192. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/common.rs +0 -0
  193. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/conversions.rs +0 -0
  194. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/geom2.rs +0 -0
  195. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/lib.rs +0 -0
  196. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/metrology.rs +0 -0
  197. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/raster.rs +0 -0
  198. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/ray_casting.rs +0 -0
  199. {engeom-0.2.15 → engeom-0.2.16}/py-engeom/src/sensors.rs +0 -0
  200. {engeom-0.2.15 → engeom-0.2.16}/pyproject.toml +0 -0
  201. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/__init__.py +0 -0
  202. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/_plot/__init__.py +0 -0
  203. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/_plot/common.py +0 -0
  204. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/_plot/matplotlib.py +0 -0
  205. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/_plot/pyvista.py +0 -0
  206. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/airfoil/__init__.py +0 -0
  207. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/airfoil.pyi +0 -0
  208. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/align/__init__.py +0 -0
  209. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/align.pyi +0 -0
  210. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/engeom.pyi +0 -0
  211. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/geom2/__init__.py +0 -0
  212. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/geom2.pyi +0 -0
  213. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/geom3/__init__.py +0 -0
  214. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/metrology/__init__.py +0 -0
  215. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/metrology.pyi +0 -0
  216. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/plot.py +0 -0
  217. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/raster3/__init__.py +0 -0
  218. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/raster3.pyi +0 -0
  219. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/sensors/__init__.py +0 -0
  220. {engeom-0.2.15 → engeom-0.2.16}/python/engeom/sensors.pyi +0 -0
@@ -147,12 +147,6 @@ dependencies = [
147
147
  "syn 2.0.104",
148
148
  ]
149
149
 
150
- [[package]]
151
- name = "array-init"
152
- version = "2.1.0"
153
- source = "registry+https://github.com/rust-lang/crates.io-index"
154
- checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc"
155
-
156
150
  [[package]]
157
151
  name = "arrayref"
158
152
  version = "0.3.9"
@@ -207,12 +201,6 @@ dependencies = [
207
201
  "arrayvec",
208
202
  ]
209
203
 
210
- [[package]]
211
- name = "az"
212
- version = "1.2.1"
213
- source = "registry+https://github.com/rust-lang/crates.io-index"
214
- checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
215
-
216
204
  [[package]]
217
205
  name = "bit_field"
218
206
  version = "0.10.2"
@@ -449,12 +437,6 @@ version = "0.7.5"
449
437
  source = "registry+https://github.com/rust-lang/crates.io-index"
450
438
  checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
451
439
 
452
- [[package]]
453
- name = "cmov"
454
- version = "0.3.1"
455
- source = "registry+https://github.com/rust-lang/crates.io-index"
456
- checksum = "1b1dc960ba75d543267db9254da8ec1cb318a037beb3f8d2497520e410096fab"
457
-
458
440
  [[package]]
459
441
  name = "color_quant"
460
442
  version = "1.1.0"
@@ -664,12 +646,6 @@ version = "0.2.0"
664
646
  source = "registry+https://github.com/rust-lang/crates.io-index"
665
647
  checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
666
648
 
667
- [[package]]
668
- name = "divrem"
669
- version = "1.0.0"
670
- source = "registry+https://github.com/rust-lang/crates.io-index"
671
- checksum = "69dde51e8fef5e12c1d65e0929b03d66e4c0c18282bc30ed2ca050ad6f44dd82"
672
-
673
649
  [[package]]
674
650
  name = "dlib"
675
651
  version = "0.5.2"
@@ -679,12 +655,6 @@ dependencies = [
679
655
  "libloading 0.8.8",
680
656
  ]
681
657
 
682
- [[package]]
683
- name = "doc-comment"
684
- version = "0.3.3"
685
- source = "registry+https://github.com/rust-lang/crates.io-index"
686
- checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
687
-
688
658
  [[package]]
689
659
  name = "downcast-rs"
690
660
  version = "1.2.1"
@@ -723,7 +693,7 @@ dependencies = [
723
693
 
724
694
  [[package]]
725
695
  name = "engeom"
726
- version = "0.2.15"
696
+ version = "0.2.16"
727
697
  dependencies = [
728
698
  "alum",
729
699
  "approx 0.5.1",
@@ -733,7 +703,7 @@ dependencies = [
733
703
  "faer",
734
704
  "imageproc",
735
705
  "itertools 0.14.0",
736
- "kiddo",
706
+ "kdtree",
737
707
  "levenberg-marquardt",
738
708
  "num-traits",
739
709
  "parry2d-f64",
@@ -885,19 +855,6 @@ dependencies = [
885
855
  "simd-adler32",
886
856
  ]
887
857
 
888
- [[package]]
889
- name = "fixed"
890
- version = "1.29.0"
891
- source = "registry+https://github.com/rust-lang/crates.io-index"
892
- checksum = "707070ccf8c4173548210893a0186e29c266901b71ed20cd9e2ca0193dfe95c3"
893
- dependencies = [
894
- "az",
895
- "bytemuck",
896
- "half",
897
- "num-traits",
898
- "typenum",
899
- ]
900
-
901
858
  [[package]]
902
859
  name = "flate2"
903
860
  version = "1.1.2"
@@ -1441,32 +1398,21 @@ dependencies = [
1441
1398
  ]
1442
1399
 
1443
1400
  [[package]]
1444
- name = "khronos_api"
1445
- version = "3.1.0"
1446
- source = "registry+https://github.com/rust-lang/crates.io-index"
1447
- checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
1448
-
1449
- [[package]]
1450
- name = "kiddo"
1451
- version = "5.2.1"
1401
+ name = "kdtree"
1402
+ version = "0.7.0"
1452
1403
  source = "registry+https://github.com/rust-lang/crates.io-index"
1453
- checksum = "52d0b22e8069fa029e15b7b0bf5bccc6d10c6abd26c3447970f708e2ee543afb"
1404
+ checksum = "0f0a0e9f770b65bac9aad00f97a67ab5c5319effed07f6da385da3c2115e47ba"
1454
1405
  dependencies = [
1455
- "aligned-vec",
1456
- "array-init",
1457
- "az",
1458
- "cmov",
1459
- "divrem",
1460
- "doc-comment",
1461
- "fixed",
1462
- "generator",
1463
1406
  "num-traits",
1464
- "ordered-float",
1465
- "sorted-vec",
1466
- "tracing",
1467
- "tracing-subscriber",
1407
+ "thiserror 1.0.69",
1468
1408
  ]
1469
1409
 
1410
+ [[package]]
1411
+ name = "khronos_api"
1412
+ version = "3.1.0"
1413
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1414
+ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
1415
+
1470
1416
  [[package]]
1471
1417
  name = "lazy_static"
1472
1418
  version = "1.5.0"
@@ -2417,7 +2363,7 @@ dependencies = [
2417
2363
 
2418
2364
  [[package]]
2419
2365
  name = "py-engeom"
2420
- version = "0.2.15"
2366
+ version = "0.2.16"
2421
2367
  dependencies = [
2422
2368
  "engeom",
2423
2369
  "numpy",
@@ -3065,12 +3011,6 @@ dependencies = [
3065
3011
  "wayland-protocols",
3066
3012
  ]
3067
3013
 
3068
- [[package]]
3069
- name = "sorted-vec"
3070
- version = "0.8.6"
3071
- source = "registry+https://github.com/rust-lang/crates.io-index"
3072
- checksum = "d372029cb5195f9ab4e4b9aef550787dce78b124fcaee8d82519925defcd6f0d"
3073
-
3074
3014
  [[package]]
3075
3015
  name = "spade"
3076
3016
  version = "2.14.0"
@@ -3408,21 +3348,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
3408
3348
  checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
3409
3349
  dependencies = [
3410
3350
  "pin-project-lite",
3411
- "tracing-attributes",
3412
3351
  "tracing-core",
3413
3352
  ]
3414
3353
 
3415
- [[package]]
3416
- name = "tracing-attributes"
3417
- version = "0.1.30"
3418
- source = "registry+https://github.com/rust-lang/crates.io-index"
3419
- checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
3420
- dependencies = [
3421
- "proc-macro2",
3422
- "quote",
3423
- "syn 2.0.104",
3424
- ]
3425
-
3426
3354
  [[package]]
3427
3355
  name = "tracing-core"
3428
3356
  version = "0.1.34"
@@ -3,7 +3,7 @@ resolver = "3"
3
3
  members = ["engeom", "py-engeom"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.2.15"
6
+ version = "0.2.16"
7
7
  edition = "2024"
8
8
 
9
9
  [workspace.dependencies]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engeom
3
- Version: 0.2.15
3
+ Version: 0.2.16
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -22,10 +22,10 @@ bitvec = {version = "1.0.1", features = ["serde"]}
22
22
  serde_json = "1.0.140"
23
23
  itertools = "0.14.0"
24
24
  levenberg-marquardt = "0.14.0"
25
- kiddo = "5.2.1"
26
25
  stl_io = { version = "0.8.5", optional = true }
27
26
  num-traits = "0.2.19"
28
27
  faer = "0.22.6"
28
+ kdtree = "0.7.0"
29
29
 
30
30
  imageproc = "0.25.0"
31
31
  colorgrad = "0.7.2"
@@ -244,16 +244,16 @@ pub fn extract_edge_sub_curve(
244
244
 
245
245
  let perimeter = section.length();
246
246
 
247
- if let Some(p0) = portion0 {
248
- if p0.length() < perimeter * frac {
249
- return Some(p0);
250
- }
247
+ if let Some(p0) = portion0
248
+ && p0.length() < perimeter * frac
249
+ {
250
+ return Some(p0);
251
251
  }
252
252
 
253
- if let Some(p1) = portion1 {
254
- if p1.length() < perimeter * frac {
255
- return Some(p1);
256
- }
253
+ if let Some(p1) = portion1
254
+ && p1.length() < perimeter * frac
255
+ {
256
+ return Some(p1);
257
257
  }
258
258
 
259
259
  None
@@ -357,10 +357,10 @@ impl OrientedCircles {
357
357
  pub fn push(&mut self, circle: InscribedCircle) {
358
358
  let mut c = circle;
359
359
 
360
- if let Some(last) = self.last() {
361
- if last.spanning_ray.dir().dot(&c.spanning_ray.dir()) < 0.0 {
362
- c.reverse_in_place();
363
- }
360
+ if let Some(last) = self.last()
361
+ && last.spanning_ray.dir().dot(&c.spanning_ray.dir()) < 0.0
362
+ {
363
+ c.reverse_in_place();
364
364
  }
365
365
 
366
366
  if self.reversed {
@@ -177,6 +177,35 @@ impl DiscreteDomain {
177
177
  pub fn bounds_unchecked(&self) -> Interval {
178
178
  Interval::new(self.values[0], self.values[self.values.len() - 1])
179
179
  }
180
+
181
+ pub fn closest_index(&self, value: f64) -> Option<usize> {
182
+ if self.is_empty() {
183
+ return None;
184
+ }
185
+ if self.len() == 1 {
186
+ return Some(0);
187
+ }
188
+ if value >= self.values[self.len() - 1] {
189
+ return Some(self.len() - 1);
190
+ }
191
+ if value <= self.values[0] {
192
+ return Some(0);
193
+ }
194
+
195
+ let index = self.index_of(value)?;
196
+ if index == self.len() - 1 {
197
+ return Some(self.len() - 1);
198
+ }
199
+
200
+ let lower_value = self.values[index];
201
+ let upper_value = self.values[index + 1];
202
+
203
+ if (value - lower_value).abs() < (value - upper_value).abs() {
204
+ Some(index)
205
+ } else {
206
+ Some(index + 1)
207
+ }
208
+ }
180
209
  }
181
210
 
182
211
  impl Deref for DiscreteDomain {
@@ -210,6 +239,7 @@ impl TryFrom<Vec<f64>> for DiscreteDomain {
210
239
  #[cfg(test)]
211
240
  mod tests {
212
241
  use super::*;
242
+ use rand::Rng;
213
243
  use test_case::test_case;
214
244
 
215
245
  #[test]
@@ -272,4 +302,38 @@ mod tests {
272
302
  let domain = DiscreteDomain::try_from(vec![1.0, 2.0, 3.0]).unwrap();
273
303
  assert_eq!(domain.index_of(x), expected);
274
304
  }
305
+
306
+ fn brute_force_closest_index(domain: &DiscreteDomain, value: f64) -> Option<usize> {
307
+ if domain.is_empty() {
308
+ return None;
309
+ }
310
+ let mut closest_index = 0;
311
+ let mut closest_distance = (value - domain.values[0]).abs();
312
+ for (i, &v) in domain.values.iter().enumerate() {
313
+ let distance = (value - v).abs();
314
+ if distance < closest_distance {
315
+ closest_distance = distance;
316
+ closest_index = i;
317
+ }
318
+ }
319
+ Some(closest_index)
320
+ }
321
+
322
+ #[test]
323
+ fn stress_test_closest() {
324
+ let n = 1000;
325
+ let mut rng = rand::rng();
326
+ let domain = DiscreteDomain::linear(-10.0, 10.0, 100);
327
+ for _ in 0..n {
328
+ let test_val = rng.random_range(-12.0..12.0);
329
+ let closest_index = domain.closest_index(test_val);
330
+ let expected = brute_force_closest_index(&domain, test_val);
331
+
332
+ assert_eq!(
333
+ closest_index, expected,
334
+ "Failed for test value: {}",
335
+ test_val
336
+ );
337
+ }
338
+ }
275
339
  }
@@ -16,7 +16,7 @@
16
16
  /// ```
17
17
  ///
18
18
  /// ```
19
- pub fn iter_domain_window(domain: &[f64], window_size: f64) -> DomainWindowIter {
19
+ pub fn iter_domain_window(domain: &[f64], window_size: f64) -> DomainWindowIter<'_> {
20
20
  DomainWindowIter::new(domain, window_size)
21
21
  }
22
22
 
@@ -64,7 +64,7 @@ impl IndexMask {
64
64
  self.mask.len()
65
65
  }
66
66
 
67
- pub fn iter_true(&self) -> MaskTrueIterator {
67
+ pub fn iter_true(&self) -> MaskTrueIterator<'_> {
68
68
  MaskTrueIterator {
69
69
  mask: self,
70
70
  current: 0,
@@ -279,6 +279,12 @@ impl IndexMask {
279
279
  }
280
280
  Ok(())
281
281
  }
282
+
283
+ pub fn fill(&mut self, value: bool) {
284
+ for u in self.mask.as_raw_mut_slice() {
285
+ *u = if value { !0 } else { 0 };
286
+ }
287
+ }
282
288
  }
283
289
 
284
290
  pub struct MaskTrueIterator<'a> {
@@ -1,9 +1,24 @@
1
+ use crate::Result;
1
2
  use crate::common::{IndexMask, PCoords};
2
- use kiddo::SquaredEuclidean;
3
- use kiddo::immutable::float::kdtree;
4
- use std::num::NonZero;
3
+ use kdtree::KdTree as KdTreeInner;
4
+ use kdtree::distance::squared_euclidean;
5
5
  use uuid::Uuid;
6
6
 
7
+ // fn check_tree() {
8
+ // let a: ([f64; 2], usize) = ([0f64, 0f64], 0);
9
+ // let b: ([f64; 2], usize) = ([1f64, 1f64], 1);
10
+ // let c: ([f64; 2], usize) = ([2f64, 2f64], 2);
11
+ // let d: ([f64; 2], usize) = ([3f64, 3f64], 3);
12
+ //
13
+ // let dimensions = 2;
14
+ // let mut kdtree = KdTreeInner::new(dimensions);
15
+ //
16
+ // kdtree.add(&a.0, a.1).unwrap();
17
+ // kdtree.add(&b.0, b.1).unwrap();
18
+ // kdtree.add(&c.0, c.1).unwrap();
19
+ // kdtree.add(&d.0, d.1).unwrap();
20
+ // }
21
+
7
22
  /// A KD tree associated with a unique UUID, such that it can be checked to be matched against a
8
23
  /// specific entity. The idea is that the UUID of the associated object will change if the object
9
24
  /// points are modified, and thus the matched tree can be validated before use.
@@ -28,7 +43,7 @@ impl<const D: usize> MatchedTree<D> {
28
43
 
29
44
  pub trait KdTreeSearch<const D: usize> {
30
45
  fn nearest_one(&self, point: &impl PCoords<D>) -> (usize, f64);
31
- fn nearest(&self, point: &impl PCoords<D>, count: NonZero<usize>) -> Vec<(usize, f64)>;
46
+ fn nearest(&self, point: &impl PCoords<D>, count: usize) -> Vec<(usize, f64)>;
32
47
  fn within(&self, point: &impl PCoords<D>, radius: f64) -> Vec<(usize, f64)>;
33
48
 
34
49
  fn len(&self) -> usize;
@@ -39,7 +54,7 @@ pub trait KdTreeSearch<const D: usize> {
39
54
 
40
55
  /// An immutable k-dimensional tree for fast searches on points in D dimensions
41
56
  pub struct KdTree<const D: usize> {
42
- tree: kdtree::ImmutableKdTree<f64, usize, D, 32>,
57
+ tree: KdTreeInner<f64, usize, [f64; D]>,
43
58
  }
44
59
 
45
60
  impl<const D: usize> KdTree<D> {
@@ -50,20 +65,16 @@ impl<const D: usize> KdTree<D> {
50
65
  /// * `points`: A slice of points.
51
66
  ///
52
67
  /// returns: KdTree<{ D }>
53
- pub fn new(points: &[impl PCoords<D>]) -> Self {
68
+ pub fn new(points: &[impl PCoords<D>]) -> Result<Self> {
54
69
  let mut entries: Vec<[f64; D]> = Vec::with_capacity(points.len());
55
70
  for p in points {
56
71
  entries.push(p.coords().into());
57
72
  }
58
- Self {
59
- tree: kdtree::ImmutableKdTree::new_from_slice(&entries),
60
- }
61
- }
62
-
63
- pub fn from_slice(s: &[[f64; D]]) -> Self {
64
- Self {
65
- tree: kdtree::ImmutableKdTree::new_from_slice(s),
73
+ let mut tree = KdTreeInner::new(D);
74
+ for (i, e) in entries.iter().enumerate() {
75
+ tree.add(*e, i)?;
66
76
  }
77
+ Ok(Self { tree })
67
78
  }
68
79
  }
69
80
 
@@ -84,10 +95,15 @@ impl<const D: usize> KdTreeSearch<D> for KdTree<D> {
84
95
  ///
85
96
  /// ```
86
97
  fn nearest_one(&self, point: &impl PCoords<D>) -> (usize, f64) {
87
- let result = self
98
+ if let Ok(item) = self
88
99
  .tree
89
- .nearest_one::<SquaredEuclidean>(&point.coords().into());
90
- (result.item, result.distance.sqrt())
100
+ .nearest(point.coords().as_slice(), 1, &squared_euclidean)
101
+ {
102
+ let (d, u) = &item[0];
103
+ (**u, d.sqrt())
104
+ } else {
105
+ (usize::MAX, f64::INFINITY)
106
+ }
91
107
  }
92
108
 
93
109
  /// Find the nearest `count` points in the kd-tree to a given point.
@@ -104,14 +120,16 @@ impl<const D: usize> KdTreeSearch<D> for KdTree<D> {
104
120
  /// ```
105
121
  ///
106
122
  /// ```
107
- fn nearest(&self, point: &impl PCoords<D>, count: NonZero<usize>) -> Vec<(usize, f64)> {
123
+ fn nearest(&self, point: &impl PCoords<D>, count: usize) -> Vec<(usize, f64)> {
108
124
  let result = self
109
125
  .tree
110
- .nearest_n::<SquaredEuclidean>(&point.coords().into(), count);
111
- result
112
- .iter()
113
- .map(|r| (r.item, r.distance.sqrt()))
114
- .collect::<Vec<_>>()
126
+ .nearest(point.coords().as_slice(), count, &squared_euclidean);
127
+
128
+ if let Ok(neighbors) = result {
129
+ neighbors.iter().map(|(d, u)| (**u, d.sqrt())).collect()
130
+ } else {
131
+ Vec::new()
132
+ }
115
133
  }
116
134
 
117
135
  /// Find all points within a given radius of a point.
@@ -129,13 +147,15 @@ impl<const D: usize> KdTreeSearch<D> for KdTree<D> {
129
147
  ///
130
148
  /// ```
131
149
  fn within(&self, point: &impl PCoords<D>, radius: f64) -> Vec<(usize, f64)> {
132
- let result = self
133
- .tree
134
- .within::<SquaredEuclidean>(&point.coords().into(), radius * radius);
135
- result
136
- .iter()
137
- .map(|r| (r.item, r.distance.sqrt()))
138
- .collect::<Vec<_>>()
150
+ if let Ok(result) = self.tree.within(
151
+ point.coords().as_slice(),
152
+ radius * radius,
153
+ &squared_euclidean,
154
+ ) {
155
+ result.iter().map(|(d, u)| (**u, d.sqrt())).collect()
156
+ } else {
157
+ Vec::new()
158
+ }
139
159
  }
140
160
 
141
161
  /// Get the number of points in the kd-tree.
@@ -171,7 +191,7 @@ impl<const D: usize> PartialKdTree<D> {
171
191
  /// ```
172
192
  ///
173
193
  /// ```
174
- pub fn new(all_points: &[impl PCoords<D>], mask: &IndexMask) -> Self {
194
+ pub fn new(all_points: &[impl PCoords<D>], mask: &IndexMask) -> Result<Self> {
175
195
  if mask.len() != all_points.len() {
176
196
  panic!("Mask length must match the length of all_points");
177
197
  }
@@ -182,8 +202,8 @@ impl<const D: usize> PartialKdTree<D> {
182
202
  points.push(all_points[i].coords());
183
203
  index_map.push(i);
184
204
  }
185
- let tree = KdTree::new(&points);
186
- Self { tree, index_map }
205
+ let tree = KdTree::new(&points)?;
206
+ Ok(Self { tree, index_map })
187
207
  }
188
208
  }
189
209
 
@@ -193,7 +213,7 @@ impl<const D: usize> KdTreeSearch<D> for PartialKdTree<D> {
193
213
  (self.index_map[i], d)
194
214
  }
195
215
 
196
- fn nearest(&self, point: &impl PCoords<D>, count: NonZero<usize>) -> Vec<(usize, f64)> {
216
+ fn nearest(&self, point: &impl PCoords<D>, count: usize) -> Vec<(usize, f64)> {
197
217
  let result = self.tree.nearest(point, count);
198
218
  result
199
219
  .iter()
@@ -230,7 +250,7 @@ mod tests {
230
250
  Point2::new(1.0, 1.0),
231
251
  Point2::new(2.0, 2.0),
232
252
  ];
233
- let tree = KdTree::new(&points);
253
+ let tree = KdTree::new(&points).expect("KD tree creation failed");
234
254
  assert_eq!(tree.len(), 3);
235
255
  }
236
256
 
@@ -241,7 +261,7 @@ mod tests {
241
261
  Point2::new(1.0, 1.0),
242
262
  Point2::new(2.0, 2.0),
243
263
  ];
244
- let tree = KdTree::new(&points);
264
+ let tree = KdTree::new(&points).expect("KD tree creation failed");
245
265
  let (i, d) = tree.nearest_one(&Point2::new(1.25, 1.25));
246
266
  assert_eq!(i, 1);
247
267
  assert_relative_eq!(d, (0.25 * 0.25 * 2.0_f64).sqrt(), epsilon = 1e-6);
@@ -254,7 +274,7 @@ mod tests {
254
274
  Point2::new(1.0, 0.0),
255
275
  Point2::new(2.0, 0.0),
256
276
  ];
257
- let tree = KdTree::new(&points);
277
+ let tree = KdTree::new(&points).expect("KD tree creation failed");
258
278
  let within = tree.within(&Point2::new(3.5, 0.0), 2.0);
259
279
  assert_eq!(within.len(), 1);
260
280
  assert_eq!(within[0].0, 2);
@@ -267,7 +287,7 @@ mod tests {
267
287
  .flat_map(|i| (0..20).map(move |j| Point2::new(i as f64, j as f64)))
268
288
  .collect::<Vec<_>>();
269
289
 
270
- let fixed_tree = KdTree::new(&points);
290
+ let fixed_tree = KdTree::new(&points).expect("KD tree creation failed");
271
291
 
272
292
  for _ in 0..1000 {
273
293
  let mut test_select = index_vec(None, points.len());
@@ -280,7 +300,7 @@ mod tests {
280
300
  }
281
301
  let indices = mask.to_indices();
282
302
 
283
- let partial_tree = PartialKdTree::new(&points, &mask);
303
+ let partial_tree = PartialKdTree::new(&points, &mask).expect("KD tree creation failed");
284
304
 
285
305
  for &i in indices.iter() {
286
306
  let p = &points[i];
@@ -1,9 +1,26 @@
1
1
  //! Common operations on f64 points in D-dimensional space.
2
2
 
3
3
  use crate::common::PCoords;
4
+ use crate::common::kd_tree::{KdTree, KdTreeSearch};
4
5
  use crate::common::surface_point::SurfacePoint;
5
6
  use parry3d_f64::na::{AbstractRotation, Isometry, Point, SVector};
6
- use crate::common::kd_tree::{KdTree, KdTreeSearch};
7
+
8
+ pub fn area<const D: usize>(
9
+ pa: &impl PCoords<D>,
10
+ pb: &impl PCoords<D>,
11
+ pc: &impl PCoords<D>,
12
+ ) -> f64 {
13
+ let ab = pb.coords() - pa.coords();
14
+ let ac = pc.coords() - pa.coords();
15
+
16
+ if D == 2 {
17
+ 0.5 * (ab[0] * ac[1] - ab[1] * ac[0]).abs()
18
+ } else if D == 3 {
19
+ 0.5 * ab.cross(&ac).norm()
20
+ } else {
21
+ panic!("Area calculation is only implemented for 2D and 3D points");
22
+ }
23
+ }
7
24
 
8
25
  /// Calculate the barycentric coordinates of a point `p` with respect to the triangle defined by
9
26
  /// points `a`, `b`, and `c` in D-dimensional space. The barycentric coordinates are a way of
@@ -510,7 +527,6 @@ where
510
527
  points.iter().map(|p| transform * p).collect()
511
528
  }
512
529
 
513
-
514
530
  /// Clusters a set of points by distance tolerance, where all points reachable by a series of hops
515
531
  /// less than or equal to the specified tolerance are grouped together into a single cluster.
516
532
  ///
@@ -534,7 +550,8 @@ pub fn cluster_points_by_tol<const D: usize>(
534
550
  while !working.is_empty() {
535
551
  let mut group = vec![working.pop().unwrap()];
536
552
  loop {
537
- let tree = KdTree::new(&group);
553
+ let tree =
554
+ KdTree::new(&group).expect("KD tree construction failed. Are there enough points?");
538
555
  let mut to_add = Vec::new();
539
556
  for (i, p) in working.iter().enumerate() {
540
557
  // let (d, _) = tree.nearest_one(&to_slice(p), &squared_euclidean);
@@ -566,7 +583,6 @@ pub fn merge_points_by_tol<const D: usize>(
566
583
  clusters.iter().map(|c| mean_point(c)).collect()
567
584
  }
568
585
 
569
-
570
586
  #[cfg(test)]
571
587
  mod tests {
572
588
  use super::*;
@@ -24,7 +24,8 @@ pub fn sample_poisson_disk_all<const D: usize>(
24
24
  radius: f64,
25
25
  ) -> IndexMask {
26
26
  let pre_mask = voxel_downsample(points, radius * 0.25);
27
- let partial_tree = PartialKdTree::new(points, &pre_mask);
27
+ let partial_tree = PartialKdTree::new(points, &pre_mask)
28
+ .expect("KD tree construction failed. Are there enough points?");
28
29
 
29
30
  let mut skip_mask = pre_mask.clone();
30
31
  let mut final_mask = IndexMask::new(points.len(), false);
@@ -71,7 +72,7 @@ mod tests {
71
72
 
72
73
  // Brute force check that each point only has one point (itself) within the radius
73
74
  let kept = keep.clone_indices_of(&points).unwrap();
74
- let tree = KdTree::new(&kept);
75
+ let tree = KdTree::new(&kept).expect("Tree construction failed");
75
76
  for (i, &p) in kept.iter().enumerate() {
76
77
  let within = tree.within(&p, r);
77
78
  assert_eq!(within.len(), 1);