engeom 0.2.8__tar.gz → 0.2.10__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.8 → engeom-0.2.10}/Cargo.lock +2 -2
- {engeom-0.2.8 → engeom-0.2.10}/Cargo.toml +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/PKG-INFO +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/Cargo.lock +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/Cargo.toml +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil/camber.rs +6 -3
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/surface_point.rs +27 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/curve3.rs +1 -0
- engeom-0.2.10/engeom/src/geom3/iso3.rs +375 -0
- engeom-0.2.10/engeom/src/geom3/mesh/collisions.rs +194 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/edges.rs +3 -3
- engeom-0.2.10/engeom/src/geom3/mesh/outline.rs +281 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/patches.rs +5 -5
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh.rs +79 -7
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/plane3.rs +11 -0
- engeom-0.2.10/engeom/src/geom3.rs +70 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/lib.rs +2 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology.rs +2 -3
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/raster3.rs +58 -60
- engeom-0.2.10/engeom/src/sensor.rs +156 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/_plot/matplotlib.py +112 -15
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/_plot/pyvista.py +26 -5
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/geom2.pyi +40 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/geom3.pyi +295 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/plot.py +1 -1
- engeom-0.2.10/python/engeom/sensor/__init__.py +6 -0
- engeom-0.2.10/python/engeom/sensor.pyi +58 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/conversions.rs +10 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/geom2.rs +17 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/geom3.rs +124 -6
- {engeom-0.2.8 → engeom-0.2.10}/src/lib.rs +15 -1
- {engeom-0.2.8 → engeom-0.2.10}/src/mesh.rs +151 -2
- {engeom-0.2.8 → engeom-0.2.10}/src/ray_casting.rs +0 -3
- engeom-0.2.10/src/sensor.rs +117 -0
- engeom-0.2.8/engeom/src/geom3.rs +0 -142
- {engeom-0.2.8 → engeom-0.2.10}/.github/workflows/CI.yml +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/.gitignore +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/.gitmodules +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/README.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/airfoils/intro.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/airfoil.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/engeom.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/geom2.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/geom3.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/metrology.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/api/plot.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/bounding_volumes.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/curves.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/images/surface_point_meas.svg +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/index.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/isometries.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/meshes.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/metrology.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/numpy.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/planes_circles_lines.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/points_vectors.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/surf_points.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/docs/svd_basis.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/.gitignore +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/README.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/airfoils/camber.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/airfoils/overview.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/common/angles.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/common/core_space.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/common/discrete_domain.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/common/images/surface_point_meas.svg +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/common/svd_basis.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/geom2/alignment.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/geom2/curve.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/geom2/point_collections.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/geom2/shapes.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/index.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/javascripts/mathjax.js +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/docs/python_rust.md +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/mkdocs.yml +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil/edges.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil/helpers.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil/inscribed_circle.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil/orientation.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/airfoil.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/align.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/angles.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/convert_2d_3d.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/discrete_domain.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/indices.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/interval.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/kd_tree.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/points.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/poisson_disk.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/svd_basis.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common/vec_f64.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/common.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/errors.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/func1/common_functions.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/func1/polynomial.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/func1/series1.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/func1.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/aabb2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/align2/jacobian.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/align2/points_to_curve.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/align2/rc_params2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/align2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/angles2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/circle2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/curve2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/hull.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/line2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2/polyline2.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom2.rs +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/align3/jacobian.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/align3/multi_param.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/align3/points_to_mesh.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/align3/rotations.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/align3.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/conformal.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/faces.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/filtering.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/measurement.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/queries.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/sampling.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/mesh/uv_mapping.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/geom3/point_cloud.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/io.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology/dimension.rs +1 -1
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology/line_profiles.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology/surface_deviation.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology/tolerance.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/metrology/tolerance_map.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/stats.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/engeom/src/utility.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/mkdocs.yml +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/pyproject.toml +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/_plot/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/_plot/common.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/airfoil/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/airfoil.pyi +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/align/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/align.pyi +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/engeom.pyi +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/geom2/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/geom3/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/metrology/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/metrology.pyi +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/raster3/__init__.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/engeom/raster3.pyi +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/tests/test_all.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/tests/test_geom2_simple.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/python/tests/test_geom3_simple.py +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/airfoil.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/alignments.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/bounding.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/common.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/metrology.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/src/raster.rs +0 -0
- {engeom-0.2.8 → engeom-0.2.10}/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.10"
|
1029
1029
|
dependencies = [
|
1030
1030
|
"engeom",
|
1031
1031
|
"numpy",
|
@@ -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
|
|
@@ -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
|
+
}
|