Files
OneCAD/vendor/truck-geometry/src/specifieds/plane.rs
T

257 lines
7.7 KiB
Rust

use super::*;
impl Plane {
/// Creates a new plane from three points.
#[inline(always)]
pub const fn new(origin: Point3, one: Point3, another: Point3) -> Plane {
Plane {
o: origin,
p: one,
q: another,
}
}
/// Returns the origin
#[inline(always)]
pub const fn origin(&self) -> Point3 { self.o }
/// Returns the u-axis
#[inline(always)]
pub fn u_axis(&self) -> Vector3 { self.p - self.o }
/// Returns the v-axis
#[inline(always)]
pub fn v_axis(&self) -> Vector3 { self.q - self.o }
/// Returns the normal
/// # Examples
/// ```
/// use truck_geometry::prelude::*;
/// let plane = Plane::new(
/// Point3::new(0.0, 0.0, 0.0),
/// Point3::new(1.0, 0.0, 0.0),
/// Point3::new(0.0, 1.0, 0.0),
/// );
/// assert_near!(plane.normal(), Vector3::unit_z());
/// ```
#[inline(always)]
pub fn normal(&self) -> Vector3 { self.u_axis().cross(self.v_axis()).normalize() }
/// Gets the parameter of `pt` in plane's matrix.
/// # Examples
/// ```
/// use truck_geometry::prelude::*;
/// let plane = Plane::new(
/// Point3::new(1.0, 2.0, 3.0),
/// Point3::new(2.0, 1.0, 3.0),
/// Point3::new(3.0, 4.0, -1.0),
/// );
///
/// let pt = Point3::new(2.1, -6.5, 4.7);
/// let prm = plane.get_parameter(pt);
/// let rev = plane.origin()
/// + prm[0] * plane.u_axis()
/// + prm[1] * plane.v_axis()
/// + prm[2] * plane.normal();
/// assert_near!(pt, rev);
/// ```
#[inline(always)]
pub fn get_parameter(&self, pt: Point3) -> Vector3 {
let a = self.u_axis();
let b = self.v_axis();
let c = self.normal();
let mat = Matrix3::from_cols(a, b, c).invert().unwrap();
mat * (pt - self.o)
}
/// into B-spline surface
/// # Examples
/// ```
/// use truck_geometry::prelude::*;
/// let pt0 = Point3::new(0.0, 1.0, 2.0);
/// let pt1 = Point3::new(1.0, 1.0, 3.0);
/// let pt2 = Point3::new(0.0, 2.0, 3.0);
/// let plane: Plane = Plane::new(pt0, pt1, pt2);
/// let surface: BSplineSurface<Point3> = plane.into_bspline();
/// assert_eq!(surface.range_tuple(), ((0.0, 1.0), (0.0, 1.0)));
///
/// const N: usize = 100;
/// for i in 0..=N {
/// for j in 0..=N {
/// let u = i as f64 / N as f64;
/// let v = j as f64 / N as f64;
/// let res = surface.subs(u, v);
/// let ans = plane.subs(u, v);
/// assert_near!(ans, res);
/// }
/// }
/// ```
#[inline(always)]
pub fn into_bspline(&self) -> BSplineSurface<Point3> {
let o = self.o;
let p = self.p;
let q = self.q;
BSplineSurface::debug_new(
(KnotVec::bezier_knot(1), KnotVec::bezier_knot(1)),
vec![vec![o, q], vec![p, p + (q - o)]],
)
}
/// into NURBS surface
/// # Examples
/// ```
/// use truck_geometry::prelude::*;
/// let pt0 = Point3::new(0.0, 1.0, 2.0);
/// let pt1 = Point3::new(1.0, 1.0, 3.0);
/// let pt2 = Point3::new(0.0, 2.0, 3.0);
/// let plane: Plane = Plane::new(pt0, pt1, pt2);
/// let surface: NurbsSurface<Vector4> = plane.into_nurbs();
/// assert_eq!(surface.range_tuple(), ((0.0, 1.0), (0.0, 1.0)));
///
/// const N: usize = 100;
/// for i in 0..=N {
/// for j in 0..=N {
/// let u = i as f64 / N as f64;
/// let v = j as f64 / N as f64;
/// let res = surface.subs(u, v);
/// let ans = plane.subs(u, v);
/// assert_near!(ans, res);
/// }
/// }
/// ```
#[inline(always)]
pub fn into_nurbs(&self) -> NurbsSurface<Vector4> {
let o = self.o.to_homogeneous();
let p = self.p.to_homogeneous();
let q = self.q.to_homogeneous();
NurbsSurface::new(BSplineSurface::debug_new(
(KnotVec::bezier_knot(1), KnotVec::bezier_knot(1)),
vec![vec![o, q], vec![p, p + q - o]],
))
}
}
impl ParametricSurface for Plane {
type Point = Point3;
type Vector = Vector3;
#[inline(always)]
fn subs(&self, u: f64, v: f64) -> Point3 {
self.o + u * (self.p - self.o) + v * (self.q - self.o)
}
#[inline(always)]
fn uder(&self, _: f64, _: f64) -> Vector3 { self.p - self.o }
#[inline(always)]
fn vder(&self, _: f64, _: f64) -> Vector3 { self.q - self.o }
#[inline(always)]
fn uuder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
#[inline(always)]
fn uvder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
#[inline(always)]
fn vvder(&self, _: f64, _: f64) -> Vector3 { Vector3::zero() }
/// as square
#[inline(always)]
fn parameter_range(&self) -> (ParameterRange, ParameterRange) {
let range = (Bound::Included(0.0), Bound::Included(1.0));
(range, range)
}
}
impl ParametricSurface3D for Plane {
#[inline(always)]
fn normal(&self, _: f64, _: f64) -> Vector3 { self.normal() }
}
impl BoundedSurface for Plane {}
impl Invertible for Plane {
#[inline(always)]
fn inverse(&self) -> Self {
Plane {
o: self.o,
p: self.q,
q: self.p,
}
}
#[inline(always)]
fn invert(&mut self) { *self = self.inverse(); }
}
impl IncludeCurve<BSplineCurve<Point3>> for Plane {
#[inline(always)]
fn include(&self, curve: &BSplineCurve<Point3>) -> bool {
let origin = self.origin();
let normal = self.normal();
curve
.control_points()
.iter()
.all(|pt| (pt - origin).dot(normal).so_small())
}
}
impl IncludeCurve<NurbsCurve<Vector4>> for Plane {
fn include(&self, curve: &NurbsCurve<Vector4>) -> bool {
let origin = self.origin();
let normal = self.normal();
let (s, e) = (curve.front(), curve.back());
if !(s - origin).dot(normal).so_small() || !(e - origin).dot(normal).so_small() {
return false;
}
curve.non_rationalized().control_points().iter().all(|pt| {
if pt[3].so_small() {
true
} else {
let pt = Point3::from_homogeneous(*pt);
(pt - origin).dot(normal).so_small()
}
})
}
}
impl ParameterDivision2D for Plane {
#[inline(always)]
fn parameter_division(&self, range: ((f64, f64), (f64, f64)), _: f64) -> (Vec<f64>, Vec<f64>) {
(vec![range.0 .0, range.0 .1], vec![range.1 .0, range.1 .1])
}
}
impl<T: Transform3<Scalar = f64>> Transformed<T> for Plane {
#[inline(always)]
fn transform_by(&mut self, trans: T) {
self.o = trans.transform_point(self.o);
self.p = trans.transform_point(self.p);
self.q = trans.transform_point(self.q);
}
#[inline(always)]
fn transformed(&self, trans: T) -> Self {
Plane {
o: trans.transform_point(self.o),
p: trans.transform_point(self.p),
q: trans.transform_point(self.q),
}
}
}
impl SearchParameter<D2> for Plane {
type Point = Point3;
#[inline(always)]
fn search_parameter<H: Into<SPHint2D>>(
&self,
point: Point3,
_: H,
_: usize,
) -> Option<(f64, f64)> {
let v = self.get_parameter(point);
match v[2].so_small() {
true => Some((v[0], v[1])),
false => None,
}
}
}
impl SearchNearestParameter<D2> for Plane {
type Point = Point3;
#[inline(always)]
fn search_nearest_parameter<H: Into<SPHint2D>>(
&self,
point: Point3,
_: H,
_: usize,
) -> Option<(f64, f64)> {
let v = self.get_parameter(point);
Some((v[0], v[1]))
}
}