engeom 0.2.7__tar.gz → 0.2.9__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.
- {engeom-0.2.7 → engeom-0.2.9}/Cargo.lock +16 -15
- {engeom-0.2.7 → engeom-0.2.9}/Cargo.toml +3 -3
- {engeom-0.2.7 → engeom-0.2.9}/PKG-INFO +1 -1
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil/camber.rs +6 -3
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/edges.rs +3 -3
- engeom-0.2.9/engeom/src/geom3/mesh/outline.rs +281 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/patches.rs +5 -5
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh.rs +47 -7
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology.rs +2 -3
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/raster3.rs +58 -60
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/_plot/matplotlib.py +50 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/_plot/pyvista.py +34 -5
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/geom3.pyi +45 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/plot.py +1 -1
- {engeom-0.2.7 → engeom-0.2.9}/src/conversions.rs +10 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/lib.rs +4 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/mesh.rs +77 -1
- engeom-0.2.9/src/ray_casting.rs +113 -0
- {engeom-0.2.7 → engeom-0.2.9}/.github/workflows/CI.yml +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/.gitignore +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/.gitmodules +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/README.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/airfoils/intro.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/airfoil.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/engeom.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/geom2.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/geom3.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/metrology.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/api/plot.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/bounding_volumes.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/curves.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/images/surface_point_meas.svg +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/index.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/isometries.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/meshes.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/metrology.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/numpy.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/planes_circles_lines.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/points_vectors.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/surf_points.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/docs/svd_basis.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/.gitignore +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/Cargo.lock +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/Cargo.toml +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/README.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/airfoils/camber.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/airfoils/overview.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/common/angles.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/common/core_space.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/common/discrete_domain.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/common/images/surface_point_meas.svg +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/common/svd_basis.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/geom2/alignment.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/geom2/curve.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/geom2/point_collections.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/geom2/shapes.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/index.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/javascripts/mathjax.js +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/docs/python_rust.md +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/mkdocs.yml +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil/edges.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil/helpers.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil/inscribed_circle.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil/orientation.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/airfoil.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/align.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/angles.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/convert_2d_3d.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/discrete_domain.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/indices.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/interval.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/kd_tree.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/points.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/poisson_disk.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/surface_point.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/svd_basis.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common/vec_f64.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/common.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/errors.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/func1/common_functions.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/func1/polynomial.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/func1/series1.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/func1.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/aabb2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/align2/jacobian.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/align2/points_to_curve.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/align2/rc_params2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/align2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/angles2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/circle2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/curve2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/hull.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/line2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2/polyline2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom2.rs +1 -1
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/align3/jacobian.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/align3/multi_param.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/align3/points_to_mesh.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/align3/rotations.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/align3.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/curve3.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/conformal.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/faces.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/filtering.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/measurement.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/queries.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/sampling.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/mesh/uv_mapping.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/plane3.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3/point_cloud.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/geom3.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/io.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/lib.rs +1 -1
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology/dimension.rs +1 -1
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology/line_profiles.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology/surface_deviation.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology/tolerance.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/metrology/tolerance_map.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/stats.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/engeom/src/utility.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/mkdocs.yml +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/pyproject.toml +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/_plot/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/_plot/common.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/airfoil/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/airfoil.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/align/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/align.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/engeom.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/geom2/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/geom2.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/geom3/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/metrology/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/metrology.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/raster3/__init__.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/engeom/raster3.pyi +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/tests/test_all.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/tests/test_geom2_simple.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/python/tests/test_geom3_simple.py +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/airfoil.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/alignments.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/bounding.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/common.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/geom2.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/geom3.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/metrology.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/raster.rs +0 -0
- {engeom-0.2.7 → engeom-0.2.9}/src/svd_basis.rs +0 -0
@@ -831,9 +831,9 @@ dependencies = [
|
|
831
831
|
|
832
832
|
[[package]]
|
833
833
|
name = "numpy"
|
834
|
-
version = "0.
|
834
|
+
version = "0.24.0"
|
835
835
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
836
|
-
checksum = "
|
836
|
+
checksum = "a7cfbf3f0feededcaa4d289fe3079b03659e85c5b5a177f4ba6fb01ab4fb3e39"
|
837
837
|
dependencies = [
|
838
838
|
"libc",
|
839
839
|
"ndarray",
|
@@ -841,6 +841,7 @@ dependencies = [
|
|
841
841
|
"num-integer",
|
842
842
|
"num-traits",
|
843
843
|
"pyo3",
|
844
|
+
"pyo3-build-config",
|
844
845
|
"rustc-hash",
|
845
846
|
]
|
846
847
|
|
@@ -1024,7 +1025,7 @@ dependencies = [
|
|
1024
1025
|
|
1025
1026
|
[[package]]
|
1026
1027
|
name = "py-engeom"
|
1027
|
-
version = "0.2.
|
1028
|
+
version = "0.2.9"
|
1028
1029
|
dependencies = [
|
1029
1030
|
"engeom",
|
1030
1031
|
"numpy",
|
@@ -1049,9 +1050,9 @@ dependencies = [
|
|
1049
1050
|
|
1050
1051
|
[[package]]
|
1051
1052
|
name = "pyo3"
|
1052
|
-
version = "0.
|
1053
|
+
version = "0.24.1"
|
1053
1054
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1054
|
-
checksum = "
|
1055
|
+
checksum = "17da310086b068fbdcefbba30aeb3721d5bb9af8db4987d6735b2183ca567229"
|
1055
1056
|
dependencies = [
|
1056
1057
|
"cfg-if",
|
1057
1058
|
"indoc",
|
@@ -1067,9 +1068,9 @@ dependencies = [
|
|
1067
1068
|
|
1068
1069
|
[[package]]
|
1069
1070
|
name = "pyo3-build-config"
|
1070
|
-
version = "0.
|
1071
|
+
version = "0.24.1"
|
1071
1072
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1072
|
-
checksum = "
|
1073
|
+
checksum = "e27165889bd793000a098bb966adc4300c312497ea25cf7a690a9f0ac5aa5fc1"
|
1073
1074
|
dependencies = [
|
1074
1075
|
"once_cell",
|
1075
1076
|
"target-lexicon",
|
@@ -1077,9 +1078,9 @@ dependencies = [
|
|
1077
1078
|
|
1078
1079
|
[[package]]
|
1079
1080
|
name = "pyo3-ffi"
|
1080
|
-
version = "0.
|
1081
|
+
version = "0.24.1"
|
1081
1082
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1082
|
-
checksum = "
|
1083
|
+
checksum = "05280526e1dbf6b420062f3ef228b78c0c54ba94e157f5cb724a609d0f2faabc"
|
1083
1084
|
dependencies = [
|
1084
1085
|
"libc",
|
1085
1086
|
"pyo3-build-config",
|
@@ -1087,9 +1088,9 @@ dependencies = [
|
|
1087
1088
|
|
1088
1089
|
[[package]]
|
1089
1090
|
name = "pyo3-macros"
|
1090
|
-
version = "0.
|
1091
|
+
version = "0.24.1"
|
1091
1092
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1092
|
-
checksum = "
|
1093
|
+
checksum = "5c3ce5686aa4d3f63359a5100c62a127c9f15e8398e5fdeb5deef1fed5cd5f44"
|
1093
1094
|
dependencies = [
|
1094
1095
|
"proc-macro2",
|
1095
1096
|
"pyo3-macros-backend",
|
@@ -1099,9 +1100,9 @@ dependencies = [
|
|
1099
1100
|
|
1100
1101
|
[[package]]
|
1101
1102
|
name = "pyo3-macros-backend"
|
1102
|
-
version = "0.
|
1103
|
+
version = "0.24.1"
|
1103
1104
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1104
|
-
checksum = "
|
1105
|
+
checksum = "f4cf6faa0cbfb0ed08e89beb8103ae9724eb4750e3a78084ba4017cbe94f3855"
|
1105
1106
|
dependencies = [
|
1106
1107
|
"heck",
|
1107
1108
|
"proc-macro2",
|
@@ -1446,9 +1447,9 @@ dependencies = [
|
|
1446
1447
|
|
1447
1448
|
[[package]]
|
1448
1449
|
name = "target-lexicon"
|
1449
|
-
version = "0.
|
1450
|
+
version = "0.13.2"
|
1450
1451
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
1451
|
-
checksum = "
|
1452
|
+
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
1452
1453
|
|
1453
1454
|
[[package]]
|
1454
1455
|
name = "thiserror"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[package]
|
2
2
|
name = "py-engeom"
|
3
|
-
version = "0.2.
|
3
|
+
version = "0.2.9"
|
4
4
|
edition = "2021"
|
5
5
|
|
6
6
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
@@ -9,10 +9,10 @@ name = "engeom"
|
|
9
9
|
crate-type = ["cdylib"]
|
10
10
|
|
11
11
|
[dependencies]
|
12
|
-
pyo3 = { version= "0.
|
12
|
+
pyo3 = { version= "0.24.1", features=["abi3-py38", "extension-module"]}
|
13
13
|
engeom = { path = "./engeom", features = ["stl"]}
|
14
14
|
parry3d-f64 = {version= "0.18.0", features=["serde-serialize"]}
|
15
15
|
parry2d-f64 = {version= "0.18.0", features=["serde-serialize"]}
|
16
|
-
numpy = "0.
|
16
|
+
numpy = "0.24.0"
|
17
17
|
rand = "0.9.0"
|
18
18
|
|
@@ -10,8 +10,8 @@ use crate::geom2::hull::farthest_pair_indices;
|
|
10
10
|
use crate::geom2::polyline2::SpanningRay;
|
11
11
|
use crate::geom2::{rot90, Line2, Segment2};
|
12
12
|
use crate::AngleDir::{Ccw, Cw};
|
13
|
-
use crate::{Curve2, UnitVec2};
|
14
13
|
use crate::Result;
|
14
|
+
use crate::{Curve2, UnitVec2};
|
15
15
|
use parry2d_f64::query::Ray;
|
16
16
|
use parry2d_f64::shape::ConvexPolygon;
|
17
17
|
|
@@ -23,8 +23,11 @@ use parry2d_f64::shape::ConvexPolygon;
|
|
23
23
|
///
|
24
24
|
/// returns: Result<Unit<Matrix<f64, Const<2>, Const<1>, ArrayStorage<f64, 2, 1>>>, Box<dyn Error, Global>>
|
25
25
|
pub fn camber_detect_upper_dir(camber_line: &Curve2) -> Result<UnitVec2> {
|
26
|
-
let check = Segment2::try_new(
|
27
|
-
.
|
26
|
+
let check = Segment2::try_new(
|
27
|
+
camber_line.at_front().point(),
|
28
|
+
camber_line.at_back().point(),
|
29
|
+
)
|
30
|
+
.map_err(|_| "Failed to create segment from camber line while detecting face orientation")?;
|
28
31
|
|
29
32
|
let resampled = camber_line.resample(ByCount(50))?;
|
30
33
|
|
@@ -100,7 +100,7 @@ impl<'a> MeshEdges<'a> {
|
|
100
100
|
|
101
101
|
/// Given an edge, return a key that can be used to identify the vertices that are connected by the
|
102
102
|
/// edge without regard to the order of the vertices.
|
103
|
-
fn edge_key(edge: &[u32; 2]) -> [u32; 2] {
|
103
|
+
pub fn edge_key(edge: &[u32; 2]) -> [u32; 2] {
|
104
104
|
let x = edge[0].min(edge[1]);
|
105
105
|
let y = edge[0].max(edge[1]);
|
106
106
|
[x, y]
|
@@ -110,7 +110,7 @@ fn edge_key(edge: &[u32; 2]) -> [u32; 2] {
|
|
110
110
|
/// the faces are presented. The edges are not deduplicated nor their direction normalized. The
|
111
111
|
/// resulting list will be 3x the length of the original faces. Elements 0-2 will be from face 0,
|
112
112
|
/// elements 3-5 will be from face 1, and so on.
|
113
|
-
fn naive_edges(faces: &[[u32; 3]]) -> Vec<[u32; 2]> {
|
113
|
+
pub fn naive_edges(faces: &[[u32; 3]]) -> Vec<[u32; 2]> {
|
114
114
|
let mut edges = Vec::new();
|
115
115
|
for face in faces {
|
116
116
|
edges.push([face[1], face[2]]);
|
@@ -122,7 +122,7 @@ fn naive_edges(faces: &[[u32; 3]]) -> Vec<[u32; 2]> {
|
|
122
122
|
|
123
123
|
/// Given a reference list of all edges, return a sorted list of unique edges and the number of
|
124
124
|
/// times each edge appeared in the original list.
|
125
|
-
fn unique_edges(all_edges: &[[u32; 2]]) -> Vec<([u32; 2], usize)> {
|
125
|
+
pub fn unique_edges(all_edges: &[[u32; 2]]) -> Vec<([u32; 2], usize)> {
|
126
126
|
let mut unique = HashMap::new();
|
127
127
|
for edge in all_edges {
|
128
128
|
let key = edge_key(edge);
|
@@ -0,0 +1,281 @@
|
|
1
|
+
//! This module exists to help generate a visual outline of a mesh
|
2
|
+
|
3
|
+
use super::Mesh;
|
4
|
+
use crate::common::points::{fill_gaps, mid_point};
|
5
|
+
use crate::geom3::mesh::edges::{edge_key, naive_edges, unique_edges};
|
6
|
+
use crate::{Point3, UnitVec3};
|
7
|
+
use parry3d_f64::query::{Ray, RayCast};
|
8
|
+
use std::collections::{HashMap, HashSet};
|
9
|
+
use std::f64::consts::PI;
|
10
|
+
|
11
|
+
// struct KeyChainer {
|
12
|
+
// forward: HashMap<u32, HashSet<u32>>,
|
13
|
+
// reverse: HashMap<u32, HashSet<u32>>,
|
14
|
+
// }
|
15
|
+
//
|
16
|
+
// fn first_single(map: &mut HashMap<u32, HashSet<u32>>) -> Option<(u32, u32)> {
|
17
|
+
// for (k, v) in map.iter_mut() {
|
18
|
+
// if v.len() == 1 {
|
19
|
+
// let k0 = *k;
|
20
|
+
// let k1 = *v.iter().next().unwrap();
|
21
|
+
// return Some((k0, k1));
|
22
|
+
// }
|
23
|
+
// }
|
24
|
+
// None
|
25
|
+
// }
|
26
|
+
//
|
27
|
+
// impl KeyChainer {
|
28
|
+
// pub fn new() -> Self {
|
29
|
+
// KeyChainer {
|
30
|
+
// forward: HashMap::new(),
|
31
|
+
// reverse: HashMap::new(),
|
32
|
+
// }
|
33
|
+
// }
|
34
|
+
//
|
35
|
+
// pub fn push(&mut self, key: &[u32; 2]) {
|
36
|
+
// let k_min = key[0].min(key[1]);
|
37
|
+
// let k_max = key[0].max(key[1]);
|
38
|
+
// self.forward.entry(k_min).or_default().insert(k_max);
|
39
|
+
// self.reverse.entry(k_max).or_default().insert(k_min);
|
40
|
+
// }
|
41
|
+
//
|
42
|
+
// pub fn remove_pair(&mut self, k0: u32, k1: u32) {
|
43
|
+
// let k_min = k0.min(k1);
|
44
|
+
// let k_max = k0.max(k1);
|
45
|
+
//
|
46
|
+
// if let Some(v) = self.forward.get_mut(&k_min) {
|
47
|
+
// v.remove(&k_max);
|
48
|
+
// if v.is_empty() {
|
49
|
+
// self.forward.remove(&k_min);
|
50
|
+
// }
|
51
|
+
// }
|
52
|
+
//
|
53
|
+
// if let Some(v) = self.reverse.get_mut(&k_max) {
|
54
|
+
// v.remove(&k_min);
|
55
|
+
// if v.is_empty() {
|
56
|
+
// self.reverse.remove(&k_max);
|
57
|
+
// }
|
58
|
+
// }
|
59
|
+
// }
|
60
|
+
//
|
61
|
+
// pub fn pop_new(&mut self) -> Option<(u32, u32)> {
|
62
|
+
// if let Some((k0, k1)) = first_single(&mut self.forward) {
|
63
|
+
// self.remove_pair(k0, k1);
|
64
|
+
// Some((k0, k1))
|
65
|
+
// } else if let Some((k0, k1)) = first_single(&mut self.reverse) {
|
66
|
+
// self.remove_pair(k0, k1);
|
67
|
+
// Some((k0, k1))
|
68
|
+
// } else {
|
69
|
+
// // Find the lowest count from forward
|
70
|
+
// if let Some(n) = self
|
71
|
+
// .forward
|
72
|
+
// .iter()
|
73
|
+
// .min_by(|a, b| a.1.len().cmp(&b.1.len()))
|
74
|
+
// .clone()
|
75
|
+
// {
|
76
|
+
// let k0 = *n.0;
|
77
|
+
// let k1 = *n.1.iter().next().unwrap();
|
78
|
+
// self.remove_pair(k0, k1);
|
79
|
+
// Some((k0, k1))
|
80
|
+
// } else {
|
81
|
+
// None
|
82
|
+
// }
|
83
|
+
// }
|
84
|
+
// }
|
85
|
+
//
|
86
|
+
// pub fn find_next(&mut self, k0: u32) -> Option<u32> {
|
87
|
+
// if let Some(v) = self.forward.get_mut(&k0) {
|
88
|
+
// if v.len() == 1 {
|
89
|
+
// let k1 = *v.iter().next().unwrap();
|
90
|
+
// self.remove_pair(k0, k1);
|
91
|
+
// return Some(k1);
|
92
|
+
// }
|
93
|
+
// }
|
94
|
+
// if let Some(v) = self.reverse.get_mut(&k0) {
|
95
|
+
// if v.len() == 1 {
|
96
|
+
// let k1 = *v.iter().next().unwrap();
|
97
|
+
// self.remove_pair(k0, k1);
|
98
|
+
// return Some(k1);
|
99
|
+
// }
|
100
|
+
// }
|
101
|
+
// None
|
102
|
+
// }
|
103
|
+
//
|
104
|
+
// pub fn sequences(&mut self) -> Vec<Vec<u32>> {
|
105
|
+
// let mut chains = Vec::new();
|
106
|
+
// let mut working = Vec::new();
|
107
|
+
//
|
108
|
+
// // Find first
|
109
|
+
// while !self.forward.is_empty() {
|
110
|
+
// if working.is_empty() {
|
111
|
+
// if let Some((k0, k1)) = self.pop_new() {
|
112
|
+
// working.push(k0);
|
113
|
+
// working.push(k1);
|
114
|
+
// } else {
|
115
|
+
// for (a, b) in self.forward.iter() {
|
116
|
+
// println!("{} -> {:?}", a, b);
|
117
|
+
// }
|
118
|
+
// for (a, b) in self.reverse.iter() {
|
119
|
+
// println!("{} <- {:?}", a, b);
|
120
|
+
// }
|
121
|
+
// panic!("This should not happen");
|
122
|
+
// }
|
123
|
+
// }
|
124
|
+
//
|
125
|
+
// // Now we have a working chain
|
126
|
+
// let last = *working.last().unwrap();
|
127
|
+
// if let Some(next) = self.find_next(last) {
|
128
|
+
// self.remove_pair(last, next);
|
129
|
+
// working.push(next);
|
130
|
+
// } else {
|
131
|
+
// // We are done with this chain
|
132
|
+
// chains.push(working.clone());
|
133
|
+
// working.clear();
|
134
|
+
// }
|
135
|
+
// }
|
136
|
+
//
|
137
|
+
// chains
|
138
|
+
// }
|
139
|
+
// }
|
140
|
+
|
141
|
+
impl Mesh {
|
142
|
+
pub fn visual_outline(
|
143
|
+
&self,
|
144
|
+
facing: UnitVec3,
|
145
|
+
max_edge_length: f64,
|
146
|
+
corner_angle: Option<f64>,
|
147
|
+
) -> Vec<(Point3, Point3, u8)> {
|
148
|
+
let corner_angle = corner_angle.unwrap_or(PI / 4.0 - 1e-2);
|
149
|
+
let (boundaries, mut corners) = self.classified_edge_types();
|
150
|
+
// let mut working = KeyChainer::new();
|
151
|
+
let mut working = Vec::new();
|
152
|
+
|
153
|
+
for (i, indices) in self.shape.indices().iter().enumerate() {
|
154
|
+
for (i0, i1) in [(0, 1), (1, 2), (2, 0)] {
|
155
|
+
let k = edge_key(&[indices[i0], indices[i1]]);
|
156
|
+
|
157
|
+
if boundaries.contains(&k) {
|
158
|
+
working.push(k);
|
159
|
+
} else if let Some(corner) = corners.get_mut(&k) {
|
160
|
+
if corner[0] == u32::MAX {
|
161
|
+
corner[0] = i as u32;
|
162
|
+
} else {
|
163
|
+
corner[1] = i as u32;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
// At this point, working contains boundary edges and corners contains corner face pairs
|
170
|
+
// Now we need to process the corners
|
171
|
+
for (key, corner) in corners.iter() {
|
172
|
+
if corner[0] == u32::MAX || corner[1] == u32::MAX {
|
173
|
+
continue;
|
174
|
+
}
|
175
|
+
|
176
|
+
let n0u = self.shape.triangle(corner[0]).normal();
|
177
|
+
let n1u = self.shape.triangle(corner[1]).normal();
|
178
|
+
|
179
|
+
if let (Some(n0), Some(n1)) = (n0u, n1u) {
|
180
|
+
if n0.angle(&n1) > corner_angle {
|
181
|
+
// Is this a corner?
|
182
|
+
working.push(*key);
|
183
|
+
} else {
|
184
|
+
let f0 = facing.dot(&n0);
|
185
|
+
let f1 = facing.dot(&n1);
|
186
|
+
let f_max = f0.max(f1);
|
187
|
+
let f_min = f0.min(f1);
|
188
|
+
|
189
|
+
if f_max >= 0.0 && f_min < 0.0 {
|
190
|
+
// Is this a silhouette?
|
191
|
+
working.push(*key);
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
let vert_normals = self.get_vertex_normals();
|
198
|
+
let mut edges = Vec::new();
|
199
|
+
for k in working {
|
200
|
+
let k0 = k[0];
|
201
|
+
let k1 = k[1];
|
202
|
+
|
203
|
+
let p0: Point3 =
|
204
|
+
self.shape.vertices()[k0 as usize].clone() + vert_normals[k0 as usize] * 1e-2;
|
205
|
+
let p1: Point3 =
|
206
|
+
self.shape.vertices()[k1 as usize].clone() + vert_normals[k1 as usize] * 1e-2;
|
207
|
+
|
208
|
+
let points = fill_gaps(&[p0, p1], max_edge_length);
|
209
|
+
|
210
|
+
for (p0, p1) in points.iter().zip(points.iter().skip(1)) {
|
211
|
+
let p = mid_point(p0, p1) + facing.into_inner() * 1e-2;
|
212
|
+
|
213
|
+
let ray = Ray::new(p, facing.into_inner());
|
214
|
+
|
215
|
+
if self.shape.intersects_local_ray(&ray, f64::MAX) {
|
216
|
+
edges.push((*p0, *p1, 1))
|
217
|
+
} else {
|
218
|
+
edges.push((*p0, *p1, 0))
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
// // We want to chain vertices together
|
224
|
+
// let sequences = working
|
225
|
+
// .sequences()
|
226
|
+
// .into_iter()
|
227
|
+
// .map(|indices| {
|
228
|
+
// indices
|
229
|
+
// .iter()
|
230
|
+
// .map(|i| self.shape.vertices()[*i as usize])
|
231
|
+
// .collect::<Vec<_>>()
|
232
|
+
// })
|
233
|
+
// .collect::<Vec<_>>();
|
234
|
+
//
|
235
|
+
// let mut edges = Vec::new();
|
236
|
+
// let shift = -facing.into_inner();
|
237
|
+
// for c in sequences.iter() {
|
238
|
+
// if let Ok(chain) = Curve3::from_points(c, 1e-3) {
|
239
|
+
// if chain.count() < 3 || chain.length() < max_edge_length * 2.0 {
|
240
|
+
// continue;
|
241
|
+
// }
|
242
|
+
//
|
243
|
+
// // println!("before l={} n={}", chain.length(), chain.count());
|
244
|
+
// let chain = chain.resample(Resample::ByMaxSpacing(max_edge_length));
|
245
|
+
// // println!("after");
|
246
|
+
//
|
247
|
+
// for (p0, p1) in chain.points().iter().zip(chain.points().iter().skip(1)) {
|
248
|
+
// let p = mid_point(p0, p1) + shift * 1e-2;
|
249
|
+
//
|
250
|
+
// let ray = Ray::new(p, shift);
|
251
|
+
//
|
252
|
+
// if self.shape.intersects_local_ray(&ray, f64::MAX) {
|
253
|
+
// edges.push((*p0, *p1, 1))
|
254
|
+
// } else {
|
255
|
+
// edges.push((*p0, *p1, 0))
|
256
|
+
// }
|
257
|
+
// }
|
258
|
+
// }
|
259
|
+
// }
|
260
|
+
|
261
|
+
edges
|
262
|
+
}
|
263
|
+
|
264
|
+
fn classified_edge_types(&self) -> (HashSet<[u32; 2]>, HashMap<[u32; 2], [u32; 2]>) {
|
265
|
+
let naive = naive_edges(&self.shape.indices());
|
266
|
+
let unique = unique_edges(&naive);
|
267
|
+
|
268
|
+
let mut boundaries = HashSet::new();
|
269
|
+
let mut corners = HashMap::new();
|
270
|
+
|
271
|
+
for (key, count) in unique {
|
272
|
+
if count == 1 {
|
273
|
+
boundaries.insert(key);
|
274
|
+
} else if count == 2 {
|
275
|
+
corners.insert(key, [u32::MAX, u32::MAX]);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
|
279
|
+
(boundaries, corners)
|
280
|
+
}
|
281
|
+
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
use crate::geom3::Mesh;
|
2
|
-
use crate::Point3;
|
2
|
+
use crate::{Point3, Result};
|
3
3
|
use std::collections::{HashMap, HashSet};
|
4
4
|
|
5
5
|
fn edge_key(i: usize, f: &[u32; 3]) -> (u32, u32) {
|
@@ -50,7 +50,7 @@ fn take_one_boundary(order: &mut HashMap<u32, u32>) -> Option<Vec<u32>> {
|
|
50
50
|
Some(sequence)
|
51
51
|
}
|
52
52
|
|
53
|
-
pub fn compute_boundary_points(mesh: &Mesh, patch: &[usize]) -> Vec<Vec<Point3
|
53
|
+
pub fn compute_boundary_points(mesh: &Mesh, patch: &[usize]) -> Result<Vec<Vec<Point3>>> {
|
54
54
|
let mut order = HashMap::new();
|
55
55
|
let mut remaining = HashSet::new();
|
56
56
|
let edges = compute_boundary_edges(mesh, patch);
|
@@ -58,7 +58,7 @@ pub fn compute_boundary_points(mesh: &Mesh, patch: &[usize]) -> Vec<Vec<Point3>>
|
|
58
58
|
if let std::collections::hash_map::Entry::Vacant(e) = order.entry(v0) {
|
59
59
|
e.insert(v1);
|
60
60
|
} else {
|
61
|
-
|
61
|
+
return Err("Duplicate boundary point found!".into());
|
62
62
|
}
|
63
63
|
remaining.insert(v0);
|
64
64
|
}
|
@@ -68,14 +68,14 @@ pub fn compute_boundary_points(mesh: &Mesh, patch: &[usize]) -> Vec<Vec<Point3>>
|
|
68
68
|
sequences.push(sequence);
|
69
69
|
}
|
70
70
|
|
71
|
-
sequences
|
71
|
+
Ok(sequences
|
72
72
|
.into_iter()
|
73
73
|
.map(|seq| {
|
74
74
|
seq.into_iter()
|
75
75
|
.map(|v| mesh.vertices()[v as usize])
|
76
76
|
.collect()
|
77
77
|
})
|
78
|
-
.collect()
|
78
|
+
.collect())
|
79
79
|
}
|
80
80
|
|
81
81
|
/// Uses the adjacency information of the mesh to compute a list of patches of connected faces. This
|
@@ -7,6 +7,7 @@ mod edges;
|
|
7
7
|
mod faces;
|
8
8
|
pub mod filtering;
|
9
9
|
mod measurement;
|
10
|
+
mod outline;
|
10
11
|
mod patches;
|
11
12
|
mod queries;
|
12
13
|
mod sampling;
|
@@ -14,7 +15,7 @@ mod uv_mapping;
|
|
14
15
|
|
15
16
|
pub use self::uv_mapping::UvMapping;
|
16
17
|
use crate::geom3::Aabb3;
|
17
|
-
use crate::{Iso3, Point2, Point3, Result, SurfacePoint3};
|
18
|
+
use crate::{Iso3, Point2, Point3, Result, SurfacePoint3, UnitVec3, Vector3};
|
18
19
|
pub use edges::MeshEdges;
|
19
20
|
use parry3d_f64::shape::{TriMesh, TriMeshFlags};
|
20
21
|
|
@@ -207,13 +208,52 @@ impl Mesh {
|
|
207
208
|
/// lists of points, where each list of points is the boundary of a patch. Note that this
|
208
209
|
/// function will not work on non-manifold meshes.
|
209
210
|
///
|
210
|
-
/// returns: Vec<Vec<usize, Global>, Global
|
211
|
-
pub fn get_patch_boundary_points(&self) -> Vec<Vec<Point3
|
211
|
+
/// returns: Result<Vec<Vec<usize, Global>, Global>>
|
212
|
+
pub fn get_patch_boundary_points(&self) -> Result<Vec<Vec<Point3>>> {
|
212
213
|
let patches = self.get_patches();
|
213
|
-
|
214
|
-
|
215
|
-
.
|
216
|
-
|
214
|
+
let mut result = Vec::new();
|
215
|
+
for patch in patches.iter() {
|
216
|
+
result.extend(patches::compute_boundary_points(self, patch)?);
|
217
|
+
}
|
218
|
+
|
219
|
+
Ok(result)
|
220
|
+
}
|
221
|
+
|
222
|
+
pub fn get_face_normals(&self) -> Result<Vec<UnitVec3>> {
|
223
|
+
let mut result = Vec::new();
|
224
|
+
for t in self.shape.triangles() {
|
225
|
+
if let Some(n) = t.normal() {
|
226
|
+
result.push(n.clone());
|
227
|
+
} else {
|
228
|
+
return Err("Failed to get normal".into());
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
Ok(result)
|
233
|
+
}
|
234
|
+
|
235
|
+
pub fn get_vertex_normals(&self) -> Vec<Vector3> {
|
236
|
+
let mut sums: Vec<Vector3> = vec![Vector3::new(0.0, 0.0, 0.0); self.shape.vertices().len()];
|
237
|
+
let mut counts = vec![0; self.shape.vertices().len()];
|
238
|
+
|
239
|
+
for (indices, tri) in self.shape.indices().iter().zip(self.shape.triangles()) {
|
240
|
+
if let Some(n) = tri.normal() {
|
241
|
+
for i in indices {
|
242
|
+
sums[*i as usize] += n.into_inner();
|
243
|
+
counts[*i as usize] += 1;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
// Normalize the normals
|
249
|
+
for i in 0..sums.len() {
|
250
|
+
if counts[i] > 0 {
|
251
|
+
let v = sums[i] / counts[i] as f64;
|
252
|
+
sums[i] = v.normalize();
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
sums
|
217
257
|
}
|
218
258
|
}
|
219
259
|
|
@@ -7,8 +7,8 @@ mod tolerance_map;
|
|
7
7
|
pub use tolerance::Tolerance;
|
8
8
|
pub use tolerance_map::{ConstantTolMap, DiscreteDomainTolMap, ToleranceMap};
|
9
9
|
|
10
|
-
pub use dimension::Measurement;
|
11
10
|
use crate::{Iso3, To2D, To3D};
|
11
|
+
pub use dimension::Measurement;
|
12
12
|
|
13
13
|
pub type SurfaceDeviation2 = surface_deviation::SurfaceDeviation<2>;
|
14
14
|
pub type SurfaceDeviationSet2 = surface_deviation::SurfaceDeviationSet<2>;
|
@@ -18,7 +18,6 @@ pub type SurfaceDeviationSet3 = surface_deviation::SurfaceDeviationSet<3>;
|
|
18
18
|
pub type Distance2 = dimension::Distance<2>;
|
19
19
|
pub type Distance3 = dimension::Distance<3>;
|
20
20
|
|
21
|
-
|
22
21
|
// Conversions between 2D and 3D distances
|
23
22
|
impl Distance2 {
|
24
23
|
/// Convert a 2D distance to a 3D distance using an isometry transformation. The 2D distance
|
@@ -55,4 +54,4 @@ impl Distance3 {
|
|
55
54
|
let direction = (iso * self.direction).to_2d();
|
56
55
|
Distance2::new(a, b, Some(direction))
|
57
56
|
}
|
58
|
-
}
|
57
|
+
}
|