engeom 0.2.9__tar.gz → 0.2.11__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.9 → engeom-0.2.11}/Cargo.lock +2 -2
- {engeom-0.2.9 → engeom-0.2.11}/Cargo.toml +1 -1
- {engeom-0.2.9 → engeom-0.2.11}/PKG-INFO +1 -1
- {engeom-0.2.9 → engeom-0.2.11}/engeom/Cargo.lock +1 -1
- {engeom-0.2.9 → engeom-0.2.11}/engeom/Cargo.toml +1 -1
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/surface_point.rs +27 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/curve3.rs +1 -0
- engeom-0.2.11/engeom/src/geom3/iso3.rs +375 -0
- engeom-0.2.11/engeom/src/geom3/mesh/collisions.rs +194 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh.rs +82 -3
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/plane3.rs +11 -0
- engeom-0.2.11/engeom/src/geom3/xyzwpr.rs +141 -0
- engeom-0.2.11/engeom/src/geom3.rs +72 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/lib.rs +5 -0
- engeom-0.2.11/engeom/src/sensor.rs +156 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/_plot/matplotlib.py +62 -15
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/_plot/pyvista.py +26 -5
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/geom2.pyi +40 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/geom3.pyi +385 -0
- engeom-0.2.11/python/engeom/sensor/__init__.py +6 -0
- engeom-0.2.11/python/engeom/sensor.pyi +58 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/geom2.rs +17 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/geom3.rs +213 -6
- {engeom-0.2.9 → engeom-0.2.11}/src/lib.rs +14 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/mesh.rs +139 -6
- {engeom-0.2.9 → engeom-0.2.11}/src/ray_casting.rs +0 -3
- engeom-0.2.11/src/sensor.rs +117 -0
- engeom-0.2.9/engeom/src/geom3.rs +0 -142
- {engeom-0.2.9 → engeom-0.2.11}/.github/workflows/CI.yml +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/.gitignore +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/.gitmodules +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/README.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/airfoils/intro.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/airfoil.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/engeom.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/geom2.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/geom3.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/metrology.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/api/plot.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/bounding_volumes.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/curves.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/images/surface_point_meas.svg +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/index.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/isometries.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/meshes.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/metrology.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/numpy.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/planes_circles_lines.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/points_vectors.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/surf_points.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/docs/svd_basis.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/.gitignore +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/README.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/airfoils/camber.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/airfoils/overview.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/common/angles.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/common/core_space.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/common/discrete_domain.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/common/images/surface_point_meas.svg +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/common/svd_basis.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/geom2/alignment.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/geom2/curve.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/geom2/point_collections.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/geom2/shapes.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/index.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/javascripts/mathjax.js +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/docs/python_rust.md +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/mkdocs.yml +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil/camber.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil/edges.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil/helpers.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil/inscribed_circle.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil/orientation.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/airfoil.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/align.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/angles.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/convert_2d_3d.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/discrete_domain.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/indices.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/interval.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/kd_tree.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/points.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/poisson_disk.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/svd_basis.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common/vec_f64.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/common.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/errors.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/func1/common_functions.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/func1/polynomial.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/func1/series1.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/func1.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/aabb2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/align2/jacobian.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/align2/points_to_curve.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/align2/rc_params2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/align2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/angles2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/circle2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/curve2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/hull.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/line2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2/polyline2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom2.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/align3/jacobian.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/align3/multi_param.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/align3/points_to_mesh.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/align3/rotations.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/align3.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/conformal.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/edges.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/faces.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/filtering.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/measurement.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/outline.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/patches.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/queries.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/sampling.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/mesh/uv_mapping.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/geom3/point_cloud.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/io.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology/dimension.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology/line_profiles.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology/surface_deviation.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology/tolerance.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology/tolerance_map.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/metrology.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/raster3.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/stats.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/engeom/src/utility.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/mkdocs.yml +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/pyproject.toml +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/_plot/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/_plot/common.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/airfoil/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/airfoil.pyi +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/align/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/align.pyi +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/engeom.pyi +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/geom2/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/geom3/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/metrology/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/metrology.pyi +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/plot.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/raster3/__init__.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/engeom/raster3.pyi +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/tests/test_all.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/tests/test_geom2_simple.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/python/tests/test_geom3_simple.py +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/airfoil.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/alignments.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/bounding.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/common.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/conversions.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/metrology.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/raster.rs +0 -0
- {engeom-0.2.9 → engeom-0.2.11}/src/svd_basis.rs +0 -0
@@ -231,7 +231,7 @@ dependencies = [
|
|
231
231
|
|
232
232
|
[[package]]
|
233
233
|
name = "engeom"
|
234
|
-
version = "0.2.
|
234
|
+
version = "0.2.1"
|
235
235
|
dependencies = [
|
236
236
|
"faer",
|
237
237
|
"itertools 0.14.0",
|
@@ -1025,7 +1025,7 @@ dependencies = [
|
|
1025
1025
|
|
1026
1026
|
[[package]]
|
1027
1027
|
name = "py-engeom"
|
1028
|
-
version = "0.2.
|
1028
|
+
version = "0.2.11"
|
1029
1029
|
dependencies = [
|
1030
1030
|
"engeom",
|
1031
1031
|
"numpy",
|
@@ -80,6 +80,33 @@ impl<const D: usize> SurfacePoint<D> {
|
|
80
80
|
let projection = self.projection(other);
|
81
81
|
(projection - other).norm()
|
82
82
|
}
|
83
|
+
|
84
|
+
/// Returns a new surface point shifted from the original surface point by the given distance
|
85
|
+
/// along the normal. This is useful for creating a new surface point that is a certain distance
|
86
|
+
/// away from the original surface point, in the direction of the normal.
|
87
|
+
///
|
88
|
+
/// # Arguments
|
89
|
+
///
|
90
|
+
/// * `shift`: the distance to offset the surface point along the normal
|
91
|
+
///
|
92
|
+
/// returns: SurfacePoint<{ D }>
|
93
|
+
///
|
94
|
+
/// # Examples
|
95
|
+
///
|
96
|
+
/// ```
|
97
|
+
/// use engeom::{Point2, SurfacePoint2, Vector2};
|
98
|
+
/// use approx::assert_relative_eq;
|
99
|
+
///
|
100
|
+
/// let sp = SurfacePoint2::new_normalize(Point2::new(0.0, 0.0), Vector2::new(0.0, 1.0));
|
101
|
+
///
|
102
|
+
/// let shifted = sp.shift(2.0);
|
103
|
+
/// assert_relative_eq!(shifted.point, Point2::new(0.0, 2.0), epsilon = 1e-6);
|
104
|
+
/// assert_relative_eq!(shifted.normal.into_inner(), Vector2::new(0.0, 1.0), epsilon = 1e-6);
|
105
|
+
/// ```
|
106
|
+
pub fn shift(&self, offset: f64) -> Self {
|
107
|
+
let new_point = self.point + self.normal.as_ref() * offset;
|
108
|
+
Self::new(new_point, self.normal)
|
109
|
+
}
|
83
110
|
}
|
84
111
|
|
85
112
|
/// Created a vector of `SurfacePoint` instances from a vector of points and a vector of normals.
|
@@ -0,0 +1,375 @@
|
|
1
|
+
//! This module has additional tools and functions for working with 3D isometries
|
2
|
+
|
3
|
+
use crate::{Iso3, Point3, Result, UnitVec3, Vector3};
|
4
|
+
use parry3d_f64::na::{try_convert, Matrix4, UnitQuaternion};
|
5
|
+
use parry3d_f64::na::{Matrix3, Translation3};
|
6
|
+
|
7
|
+
pub trait IsoExtensions3 {
|
8
|
+
fn flip_around_x(&self) -> Iso3;
|
9
|
+
fn flip_around_y(&self) -> Iso3;
|
10
|
+
fn flip_around_z(&self) -> Iso3;
|
11
|
+
fn try_from_array(array: &[f64; 16]) -> Result<Iso3>;
|
12
|
+
|
13
|
+
fn try_from_basis_xy(e0: &Vector3, e1: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
14
|
+
fn try_from_basis_xz(e0: &Vector3, e2: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
15
|
+
fn try_from_basis_yz(e1: &Vector3, e2: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
16
|
+
fn try_from_basis_yx(e1: &Vector3, e0: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
17
|
+
fn try_from_basis_zx(e2: &Vector3, e0: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
18
|
+
fn try_from_basis_zy(e2: &Vector3, e1: &Vector3, origin: Option<Point3>) -> Result<Iso3>;
|
19
|
+
|
20
|
+
fn from_rx(angle: f64) -> Iso3;
|
21
|
+
fn from_ry(angle: f64) -> Iso3;
|
22
|
+
fn from_rz(angle: f64) -> Iso3;
|
23
|
+
}
|
24
|
+
|
25
|
+
impl IsoExtensions3 for Iso3 {
|
26
|
+
/// Rotate the isometry in place by 180 degrees around the x-axis. The location of the origin
|
27
|
+
/// is not changed, but the y and z directions are reversed.
|
28
|
+
fn flip_around_x(&self) -> Self {
|
29
|
+
let r = Iso3::rotation(Vector3::x() * std::f64::consts::PI);
|
30
|
+
self.translation * r * self.rotation
|
31
|
+
}
|
32
|
+
|
33
|
+
/// Rotate the isometry in place by 180 degrees around the y-axis. The location of the origin
|
34
|
+
/// is not changed, but the x and z directions are reversed.
|
35
|
+
fn flip_around_y(&self) -> Self {
|
36
|
+
let r = Iso3::rotation(Vector3::y() * std::f64::consts::PI);
|
37
|
+
self.translation * r * self.rotation
|
38
|
+
}
|
39
|
+
|
40
|
+
/// Rotate the isometry in place by 180 degrees around the z-axis. The location of the origin
|
41
|
+
/// is not changed, but the x and y directions are reversed.
|
42
|
+
fn flip_around_z(&self) -> Self {
|
43
|
+
let r = Iso3::rotation(Vector3::z() * std::f64::consts::PI);
|
44
|
+
self.translation * r * self.rotation
|
45
|
+
}
|
46
|
+
|
47
|
+
/// Try to convert a 16 element array into an Iso3. The array is expected to be in row-major
|
48
|
+
/// order.
|
49
|
+
fn try_from_array(array: &[f64; 16]) -> Result<Self> {
|
50
|
+
try_convert(Matrix4::from_row_slice(array)).ok_or("Could not convert to Iso3".into())
|
51
|
+
}
|
52
|
+
|
53
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
54
|
+
/// vector will become the x-axis in the isometry, the secondary basis vector will be projected
|
55
|
+
/// onto the primary and the remaining component will be the y-axis. The final axis will be
|
56
|
+
/// computed by cross product for a right-handed coordinate system.
|
57
|
+
///
|
58
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
59
|
+
/// where it would be located in the world coordinate system.
|
60
|
+
///
|
61
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
62
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
63
|
+
///
|
64
|
+
/// # Arguments
|
65
|
+
///
|
66
|
+
/// * `e0`: A vector in the world coordinate system that will become the x-axis in the basis
|
67
|
+
/// coordinate system, will be normalized to unit length automatically.
|
68
|
+
/// * `e1`: A vector in the world coordinate system whose component linearly independent of `e0`
|
69
|
+
/// will become the y-axis in the basis coordinate system, will be normalized to unit length.
|
70
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
71
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
72
|
+
/// be coincident with the origin of the world coordinate system.
|
73
|
+
///
|
74
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
75
|
+
fn try_from_basis_xy(e0: &Vector3, e1: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
76
|
+
let e0 = e0.try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
77
|
+
let e2 = e0.cross(e1).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
78
|
+
let e1 = e2.cross(&e0).try_normalize(1e-10).ok_or("Could not normalize e1")?;
|
79
|
+
|
80
|
+
from_bases(e0, e1, e2, origin)
|
81
|
+
}
|
82
|
+
|
83
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
84
|
+
/// vector will become the x-axis in the isometry, the secondary basis vector will be projected
|
85
|
+
/// onto the primary and the remaining component will be the z-axis. The final axis will be
|
86
|
+
/// computed by cross product for a right-handed coordinate system.
|
87
|
+
///
|
88
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
89
|
+
/// where it would be located in the world coordinate system.
|
90
|
+
///
|
91
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
92
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
93
|
+
///
|
94
|
+
/// # Arguments
|
95
|
+
///
|
96
|
+
/// * `e0`: A vector in the world coordinate system that will become the x-axis in the basis
|
97
|
+
/// coordinate system, will be normalized to unit length automatically.
|
98
|
+
/// * `e2`: A vector in the world coordinate system whose component linearly independent of `e0`
|
99
|
+
/// will become the z-axis in the basis coordinate system, will be normalized to unit length.
|
100
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
101
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
102
|
+
/// be coincident with the origin of the world coordinate system.
|
103
|
+
///
|
104
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
105
|
+
fn try_from_basis_xz(e0: &Vector3, e2: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
106
|
+
let e0 = e0.try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
107
|
+
let e1 = e2.cross(&e0).try_normalize(1e-10).ok_or("Could not normalize e1")?;
|
108
|
+
let e2 = e0.cross(&e1).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
109
|
+
from_bases(e0, e1, e2, origin)
|
110
|
+
}
|
111
|
+
|
112
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
113
|
+
/// vector will become the y-axis in the isometry, the secondary basis vector will be projected
|
114
|
+
/// onto the primary and the remaining component will be the z-axis. The final axis will be
|
115
|
+
/// computed by cross product for a right-handed coordinate system.
|
116
|
+
///
|
117
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
118
|
+
/// where it would be located in the world coordinate system.
|
119
|
+
///
|
120
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
121
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
122
|
+
///
|
123
|
+
/// # Arguments
|
124
|
+
///
|
125
|
+
/// * `e1`: A vector in the world coordinate system that will become the y-axis in the basis
|
126
|
+
/// coordinate system, will be normalized to unit length automatically.
|
127
|
+
/// * `e2`: A vector in the world coordinate system whose component linearly independent of `e1`
|
128
|
+
/// will become the z-axis in the basis coordinate system, will be normalized to unit length.
|
129
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
130
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
131
|
+
/// be coincident with the origin of the world coordinate system.
|
132
|
+
///
|
133
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
134
|
+
fn try_from_basis_yz(e1: &Vector3, e2: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
135
|
+
let e1 = e1.try_normalize(1e-10).ok_or("Could not normalize e1")?;
|
136
|
+
let e0 = e1.cross(&e2).try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
137
|
+
let e2 = e0.cross(&e1).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
138
|
+
from_bases(e0, e1, e2, origin)
|
139
|
+
}
|
140
|
+
|
141
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
142
|
+
/// vector will become the y-axis in the isometry, the secondary basis vector will be projected
|
143
|
+
/// onto the primary and the remaining component will be the x-axis. The final axis will be
|
144
|
+
/// computed by cross product for a right-handed coordinate system.
|
145
|
+
///
|
146
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
147
|
+
/// where it would be located in the world coordinate system.
|
148
|
+
///
|
149
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
150
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
151
|
+
///
|
152
|
+
/// # Arguments
|
153
|
+
///
|
154
|
+
/// * `e1`: A vector in the world coordinate system that will become the y-axis in the basis
|
155
|
+
/// coordinate system, will be normalized to unit length automatically.
|
156
|
+
/// * `e0`: A vector in the world coordinate system whose component linearly independent of `e1`
|
157
|
+
/// will become the x-axis in the basis coordinate system, will be normalized to unit length.
|
158
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
159
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
160
|
+
/// be coincident with the origin of the world coordinate system.
|
161
|
+
///
|
162
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
163
|
+
fn try_from_basis_yx(e1: &Vector3, e0: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
164
|
+
let e1 = e1.try_normalize(1e-10).ok_or("Could not normalize e1")?;
|
165
|
+
let e2 = e0.cross(&e1).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
166
|
+
let e0 = e1.cross(&e2).try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
167
|
+
from_bases(e0, e1, e2, origin)
|
168
|
+
}
|
169
|
+
|
170
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
171
|
+
/// vector will become the z-axis in the isometry, the secondary basis vector will be projected
|
172
|
+
/// onto the primary and the remaining component will be the x-axis. The final axis will be
|
173
|
+
/// computed by cross product for a right-handed coordinate system.
|
174
|
+
///
|
175
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
176
|
+
/// where it would be located in the world coordinate system.
|
177
|
+
///
|
178
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
179
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
180
|
+
///
|
181
|
+
/// # Arguments
|
182
|
+
///
|
183
|
+
/// * `e2`: A vector in the world coordinate system that will become the z-axis in the basis
|
184
|
+
/// coordinate system, will be normalized to unit length automatically.
|
185
|
+
/// * `e0`: A vector in the world coordinate system whose component linearly independent of `e2`
|
186
|
+
/// will become the x-axis in the basis coordinate system, will be normalized to unit length.
|
187
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
188
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
189
|
+
/// be coincident with the origin of the world coordinate system.
|
190
|
+
///
|
191
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
192
|
+
fn try_from_basis_zx(e2: &Vector3, e0: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
193
|
+
let e2 = e2.try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
194
|
+
let e1 = e2.cross(&e0).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
195
|
+
let e0 = e1.cross(&e2).try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
196
|
+
from_bases(e0, e1, e2, origin)
|
197
|
+
}
|
198
|
+
|
199
|
+
/// Try to create an isometry from two basis vectors and an optional origin. The primary basis
|
200
|
+
/// vector will become the z-axis in the isometry, the secondary basis vector will be projected
|
201
|
+
/// onto the primary and the remaining component will be the y-axis. The final axis will be
|
202
|
+
/// computed by cross product for a right-handed coordinate system.
|
203
|
+
///
|
204
|
+
/// The isometry produced by this method will move a point in the basis coordinate system to
|
205
|
+
/// where it would be located in the world coordinate system.
|
206
|
+
///
|
207
|
+
/// If you want to take features in the world coordinate system and move them into the basis
|
208
|
+
/// coordinate system, you need to use the inverse of the isometry.
|
209
|
+
///
|
210
|
+
/// # Arguments
|
211
|
+
///
|
212
|
+
/// * `e2`: A vector in the world coordinate system that will become the z-axis in the basis
|
213
|
+
/// coordinate system, will be normalized to unit length automatically.
|
214
|
+
/// * `e1`: A vector in the world coordinate system whose component linearly independent of `e2`
|
215
|
+
/// will become the y-axis in the basis coordinate system, will be normalized to unit length.
|
216
|
+
/// * `origin`: An optional point in the world coordinate system that will be the origin of the
|
217
|
+
/// basis coordinate system. If not provided, the origin of the basis coordinate system will
|
218
|
+
/// be coincident with the origin of the world coordinate system.
|
219
|
+
///
|
220
|
+
/// returns: Result<Isometry<f64, Unit<Quaternion<f64>>, 3>, Box<dyn Error, Global>>
|
221
|
+
fn try_from_basis_zy(e2: &Vector3, e1: &Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
222
|
+
let e2 = e2.try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
223
|
+
let e0 = e1.cross(&e2).try_normalize(1e-10).ok_or("Could not normalize e0")?;
|
224
|
+
let e1 = e2.cross(&e0).try_normalize(1e-10).ok_or("Could not normalize e2")?;
|
225
|
+
from_bases(e0, e1, e2, origin)
|
226
|
+
}
|
227
|
+
|
228
|
+
fn from_rx(angle: f64) -> Iso3 {
|
229
|
+
Iso3::rotation(Vector3::x() * angle)
|
230
|
+
}
|
231
|
+
|
232
|
+
fn from_ry(angle: f64) -> Iso3 {
|
233
|
+
Iso3::rotation(Vector3::y() * angle)
|
234
|
+
}
|
235
|
+
|
236
|
+
fn from_rz(angle: f64) -> Iso3 {
|
237
|
+
Iso3::rotation(Vector3::z() * angle)
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
fn from_bases(e0: Vector3, e1: Vector3, e2: Vector3, origin: Option<Point3>) -> Result<Iso3> {
|
242
|
+
let rot_m = Matrix3::from_columns(&[e0, e1, e2]);
|
243
|
+
let r = UnitQuaternion::from_matrix(&rot_m);
|
244
|
+
let t = if let Some(o) = origin {
|
245
|
+
Translation3::from(o.coords)
|
246
|
+
} else {
|
247
|
+
Translation3::identity()
|
248
|
+
};
|
249
|
+
|
250
|
+
Ok(Iso3::from_parts(t, r))
|
251
|
+
}
|
252
|
+
|
253
|
+
#[cfg(test)]
|
254
|
+
mod tests {
|
255
|
+
use std::f64::consts::PI;
|
256
|
+
use super::*;
|
257
|
+
use crate::Point3;
|
258
|
+
use approx::assert_relative_eq;
|
259
|
+
|
260
|
+
struct BasisCheck {
|
261
|
+
o: Point3,
|
262
|
+
e0: Vector3,
|
263
|
+
e1: Vector3,
|
264
|
+
e2: Vector3,
|
265
|
+
fwd: Iso3,
|
266
|
+
}
|
267
|
+
|
268
|
+
impl BasisCheck {
|
269
|
+
fn new() -> Self {
|
270
|
+
let o = Point3::new(1.0, 2.0, 3.0);
|
271
|
+
let angle = UnitVec3::new_normalize(Vector3::new(1.0, 1.0, 1.0));
|
272
|
+
let fwd = Iso3::from_parts(
|
273
|
+
Translation3::from(o.coords),
|
274
|
+
UnitQuaternion::new(PI / 4.0 * angle.into_inner()),
|
275
|
+
);
|
276
|
+
let e0 = fwd * Vector3::x();
|
277
|
+
let e1 = fwd * Vector3::y();
|
278
|
+
let e2 = fwd * Vector3::z();
|
279
|
+
|
280
|
+
Self { o, e0, e1, e2, fwd }
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
#[test]
|
285
|
+
fn iso3_try_from_basis_xy() -> Result<()> {
|
286
|
+
let check = BasisCheck::new();
|
287
|
+
let iso = Iso3::try_from_basis_xy(&check.e0, &check.e1, Some(check.o))?;
|
288
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
289
|
+
Ok(())
|
290
|
+
}
|
291
|
+
|
292
|
+
#[test]
|
293
|
+
fn iso3_try_from_basis_xz() -> Result<()> {
|
294
|
+
let check = BasisCheck::new();
|
295
|
+
let iso = Iso3::try_from_basis_xz(&check.e0, &check.e2, Some(check.o))?;
|
296
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
297
|
+
Ok(())
|
298
|
+
}
|
299
|
+
|
300
|
+
#[test]
|
301
|
+
fn iso3_try_from_basis_yx() -> Result<()> {
|
302
|
+
let check = BasisCheck::new();
|
303
|
+
let iso = Iso3::try_from_basis_yx(&check.e1, &check.e0, Some(check.o))?;
|
304
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
305
|
+
Ok(())
|
306
|
+
}
|
307
|
+
|
308
|
+
#[test]
|
309
|
+
fn iso3_try_from_basis_yz() -> Result<()> {
|
310
|
+
let check = BasisCheck::new();
|
311
|
+
let iso = Iso3::try_from_basis_yz(&check.e1, &check.e2, Some(check.o))?;
|
312
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
313
|
+
Ok(())
|
314
|
+
}
|
315
|
+
|
316
|
+
#[test]
|
317
|
+
fn iso3_try_from_basis_zx() -> Result<()> {
|
318
|
+
let check = BasisCheck::new();
|
319
|
+
let iso = Iso3::try_from_basis_zx(&check.e2, &check.e0, Some(check.o))?;
|
320
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
321
|
+
Ok(())
|
322
|
+
}
|
323
|
+
|
324
|
+
#[test]
|
325
|
+
fn iso3_try_from_basis_zy() -> Result<()> {
|
326
|
+
let check = BasisCheck::new();
|
327
|
+
let iso = Iso3::try_from_basis_zy(&check.e2, &check.e1, Some(check.o))?;
|
328
|
+
assert_relative_eq!(iso, check.fwd, epsilon = 1e-6);
|
329
|
+
Ok(())
|
330
|
+
}
|
331
|
+
|
332
|
+
#[test]
|
333
|
+
fn iso3_try_from_basis_xy_manual() {
|
334
|
+
let o = Point3::new(1.0, 2.0, 3.0);
|
335
|
+
let e0 = UnitVec3::new_normalize(Vector3::new(1.0, 1.0, 0.0));
|
336
|
+
let e1 = Vector3::new(0.0, 1.0, 1.0);
|
337
|
+
|
338
|
+
let iso = Iso3::try_from_basis_xy(&e0.into_inner(), &e1, Some(o)).unwrap();
|
339
|
+
|
340
|
+
assert_relative_eq!(iso * Point3::origin(), o, epsilon = 1e-6);
|
341
|
+
assert_relative_eq!(
|
342
|
+
iso * Point3::new(1.0, 0.0, 0.0),
|
343
|
+
o + e0.into_inner() * 1.0,
|
344
|
+
epsilon = 1e-6
|
345
|
+
);
|
346
|
+
}
|
347
|
+
|
348
|
+
#[test]
|
349
|
+
fn iso3_try_from_array_simple() {
|
350
|
+
let array = [
|
351
|
+
1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 2.0, 0.0, 0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 1.0,
|
352
|
+
];
|
353
|
+
let iso = Iso3::try_from_array(&array).unwrap();
|
354
|
+
let m = iso.to_matrix();
|
355
|
+
let expected = Matrix4::new(
|
356
|
+
1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 2.0, 0.0, 0.0, 1.0, 3.0, 0.0, 0.0, 0.0, 1.0,
|
357
|
+
);
|
358
|
+
assert_relative_eq!(m, expected);
|
359
|
+
}
|
360
|
+
|
361
|
+
#[test]
|
362
|
+
fn iso3_flip_x() {
|
363
|
+
let iso = Iso3::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 0.0));
|
364
|
+
let flipped = iso.flip_around_x();
|
365
|
+
|
366
|
+
let p = Point3::new(0.0, 0.0, 0.0);
|
367
|
+
assert_relative_eq!(flipped * p, Point3::new(1.0, 2.0, 3.0));
|
368
|
+
|
369
|
+
let p1 = Point3::new(1.0, 0.0, 0.0);
|
370
|
+
assert_relative_eq!(flipped * p1, Point3::new(2.0, 2.0, 3.0));
|
371
|
+
|
372
|
+
let p2 = Point3::new(0.0, 1.0, 0.0);
|
373
|
+
assert_relative_eq!(flipped * p2, Point3::new(1.0, 1.0, 3.0));
|
374
|
+
}
|
375
|
+
}
|
@@ -0,0 +1,194 @@
|
|
1
|
+
//! Mesh collision detection and distance checks
|
2
|
+
|
3
|
+
use std::cmp::PartialEq;
|
4
|
+
use crate::{Iso3, Mesh, Result};
|
5
|
+
use std::collections::{HashMap, HashSet};
|
6
|
+
use parry3d_f64::query::intersection_test;
|
7
|
+
|
8
|
+
#[derive(Debug, Clone, PartialEq)]
|
9
|
+
enum MeshType {
|
10
|
+
Stationary,
|
11
|
+
Moving,
|
12
|
+
}
|
13
|
+
|
14
|
+
struct MeshItem {
|
15
|
+
mesh: Mesh,
|
16
|
+
mesh_type: MeshType,
|
17
|
+
}
|
18
|
+
|
19
|
+
pub struct MeshCollisionSet {
|
20
|
+
meshes: HashMap<usize, MeshItem>,
|
21
|
+
exceptions: HashSet<(usize, usize)>,
|
22
|
+
}
|
23
|
+
|
24
|
+
impl MeshCollisionSet {
|
25
|
+
pub fn new() -> Self {
|
26
|
+
Self {
|
27
|
+
meshes: HashMap::new(),
|
28
|
+
exceptions: HashSet::new(),
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
pub fn add_exception(&mut self, id1: usize, id2: usize) {
|
33
|
+
let lower = id1.min(id2);
|
34
|
+
let upper = id1.max(id2);
|
35
|
+
self.exceptions.insert((lower, upper));
|
36
|
+
}
|
37
|
+
|
38
|
+
fn skip_collision(&self, id1: usize, id2: usize) -> bool {
|
39
|
+
let lower = id1.min(id2);
|
40
|
+
let upper = id1.max(id2);
|
41
|
+
self.exceptions.contains(&(lower, upper))
|
42
|
+
}
|
43
|
+
|
44
|
+
fn add_mesh(&mut self, mesh: Mesh, mesh_type: MeshType) -> usize {
|
45
|
+
let id = self.meshes.len();
|
46
|
+
self.meshes.insert(id, MeshItem { mesh, mesh_type });
|
47
|
+
|
48
|
+
id
|
49
|
+
}
|
50
|
+
|
51
|
+
pub fn add_stationary(&mut self, mesh: Mesh) -> usize {
|
52
|
+
self.add_mesh(mesh, MeshType::Stationary)
|
53
|
+
}
|
54
|
+
|
55
|
+
pub fn add_moving(&mut self, mesh: Mesh) -> usize {
|
56
|
+
self.add_mesh(mesh, MeshType::Moving)
|
57
|
+
}
|
58
|
+
|
59
|
+
/// This function will check for all collisions between the meshes in the set, according to the
|
60
|
+
/// following rules:
|
61
|
+
///
|
62
|
+
/// - Moving meshes will be checked against all meshes that don't contain an exception,
|
63
|
+
/// including both stationary and other moving meshes
|
64
|
+
/// - Stationary meshes will not be checked against any other meshes, and so a collision will
|
65
|
+
/// only be reported if it is with a stationary mesh
|
66
|
+
///
|
67
|
+
/// # Arguments
|
68
|
+
///
|
69
|
+
/// * `transforms`: transforms for the moving meshes
|
70
|
+
/// * `stop_at_first`: If true, the function will stop at the first collision found for each
|
71
|
+
/// moving mesh. If false, it will check all collisions.
|
72
|
+
///
|
73
|
+
/// returns: Vec<(usize, usize), Global>
|
74
|
+
///
|
75
|
+
/// # Examples
|
76
|
+
///
|
77
|
+
/// ```
|
78
|
+
///
|
79
|
+
/// ```
|
80
|
+
pub fn check_all(
|
81
|
+
&self,
|
82
|
+
transforms: &[(usize, Iso3)],
|
83
|
+
stop_at_first: bool,
|
84
|
+
) -> Result<Vec<(usize, usize)>> {
|
85
|
+
// Create the fast isometry lookup:
|
86
|
+
let lookups = self.quick_lookups(transforms)?;
|
87
|
+
|
88
|
+
// We'll iterate through all the moving meshes (this can be parallelized later).
|
89
|
+
// For each moving mesh, we'll iterate through all stationary meshes and then all moving
|
90
|
+
// meshes. Whether a collision check occurs depends on the following:
|
91
|
+
// - Is the current mesh id lower than the other mesh id?
|
92
|
+
// - Is there an exception for the current pair of meshes?
|
93
|
+
let mut pairs = Vec::new();
|
94
|
+
|
95
|
+
for (&id1, mesh1) in self.meshes.iter() {
|
96
|
+
if mesh1.mesh_type == MeshType::Stationary {
|
97
|
+
continue;
|
98
|
+
}
|
99
|
+
|
100
|
+
let iso1 = &lookups[id1];
|
101
|
+
|
102
|
+
for (&id2, mesh2) in self.meshes.iter() {
|
103
|
+
if mesh2.mesh_type == MeshType::Moving && id1 >= id2 {
|
104
|
+
continue;
|
105
|
+
}
|
106
|
+
|
107
|
+
if self.skip_collision(id1, id2) {
|
108
|
+
continue;
|
109
|
+
}
|
110
|
+
|
111
|
+
let iso2 = &lookups[id2];
|
112
|
+
|
113
|
+
// Check for collision
|
114
|
+
if let Ok(check) = intersection_test(iso1, mesh1.mesh.tri_mesh(), iso2, mesh2.mesh.tri_mesh()) {
|
115
|
+
if check {
|
116
|
+
pairs.push((id1, id2));
|
117
|
+
if stop_at_first {
|
118
|
+
break;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
Ok(pairs)
|
126
|
+
}
|
127
|
+
|
128
|
+
fn quick_lookups(&self, transforms: &[(usize, Iso3)]) -> Result<Vec<Iso3>> {
|
129
|
+
let mut lookups = vec![Iso3::identity(); self.meshes.len()];
|
130
|
+
for &(id, iso) in transforms.iter() {
|
131
|
+
if id >= self.meshes.len() {
|
132
|
+
return Err(format!("Transform id {} out of bounds", id).into());
|
133
|
+
}
|
134
|
+
|
135
|
+
lookups[id] = iso.clone();
|
136
|
+
}
|
137
|
+
|
138
|
+
Ok(lookups)
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
|
143
|
+
#[cfg(test)]
|
144
|
+
mod tests {
|
145
|
+
use super::*;
|
146
|
+
use crate::geom3::Mesh;
|
147
|
+
use crate::Iso3;
|
148
|
+
|
149
|
+
#[test]
|
150
|
+
fn collision_set() {
|
151
|
+
let mut set = MeshCollisionSet::new();
|
152
|
+
let mesh1 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
153
|
+
let mesh2 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
154
|
+
|
155
|
+
let id1 = set.add_stationary(mesh1);
|
156
|
+
let id2 = set.add_moving(mesh2);
|
157
|
+
|
158
|
+
let transforms = vec![(id2, Iso3::translation(0.5, 0.5, 0.5))];
|
159
|
+
|
160
|
+
let pairs = set.check_all(&transforms, false).unwrap();
|
161
|
+
assert_eq!(pairs.len(), 1);
|
162
|
+
}
|
163
|
+
|
164
|
+
#[test]
|
165
|
+
fn collision_set_exception_skips() {
|
166
|
+
let mut set = MeshCollisionSet::new();
|
167
|
+
let mesh1 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
168
|
+
let mesh2 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
169
|
+
|
170
|
+
let id1 = set.add_stationary(mesh1);
|
171
|
+
let id2 = set.add_moving(mesh2);
|
172
|
+
set.add_exception(id2, id1);
|
173
|
+
|
174
|
+
let transforms = vec![(id2, Iso3::translation(0.5, 0.5, 0.5))];
|
175
|
+
|
176
|
+
let pairs = set.check_all(&transforms, false).unwrap();
|
177
|
+
assert_eq!(pairs.len(), 0);
|
178
|
+
}
|
179
|
+
|
180
|
+
#[test]
|
181
|
+
fn collision_set_misses() {
|
182
|
+
let mut set = MeshCollisionSet::new();
|
183
|
+
let mesh1 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
184
|
+
let mesh2 = Mesh::create_box(1.0, 1.0, 1.0, true);
|
185
|
+
|
186
|
+
let id1 = set.add_stationary(mesh1);
|
187
|
+
let id2 = set.add_moving(mesh2);
|
188
|
+
|
189
|
+
let transforms = vec![(id2, Iso3::translation(2.5, 0.5, 0.5))];
|
190
|
+
|
191
|
+
let pairs = set.check_all(&transforms, false).unwrap();
|
192
|
+
assert_eq!(pairs.len(), 0);
|
193
|
+
}
|
194
|
+
}
|