pub struct Plane<T: Number, const N: usize> { /* private fields */ }Expand description
A plane in 3D space, defined by a normal vector and a distance from the origin
Implementations§
Source§impl<T, const N: usize> Plane<T, N>where
T: Number,
impl<T, const N: usize> Plane<T, N>where
T: Number,
pub fn new(normal: SVector<T, N>, distance: T) -> Self
pub fn normal(&self) -> SVector<T, N>
pub fn with_normal(self, normal: SVector<T, N>) -> Self
Sourcepub fn distance(&self) -> T
pub fn distance(&self) -> T
Returns the signed distance from the origin to the plane along the normal.
Sourcepub fn roughly_eq(&self, other: &Self) -> bool
pub fn roughly_eq(&self, other: &Self) -> bool
Approximate equality check using epsilon tolerance.
Sourcepub fn origin_projection(&self) -> Point<T, N>
pub fn origin_projection(&self) -> Point<T, N>
Returns the point on the plane closest to the origin. Requires the normal to be a unit vector.
pub fn classify_point(&self, point: &Point<T, N>) -> PlaneSide
pub fn has_point(&self, point: &Point<T, N>) -> bool
Sourcepub fn cast<T2: Number>(self) -> Plane<T2, N>where
T: AsPrimitive<T2>,
pub fn cast<T2: Number>(self) -> Plane<T2, N>where
T: AsPrimitive<T2>,
Cast the plane’s numeric type from T to T2.
pub fn flip(self) -> Self
Sourcepub fn classify_polygon(&self, polygon: &Polygon<T, N>) -> PolygonClassification
pub fn classify_polygon(&self, polygon: &Polygon<T, N>) -> PolygonClassification
Classifies a polygon
Computes signed distances for all vertices in a single pass, tracking min/max to derive the classification without per-vertex branching.
Source§impl<T: Number, const N: usize> Plane<T, N>
impl<T: Number, const N: usize> Plane<T, N>
pub fn split_edge( &self, a: &Point<T, N>, b: &Point<T, N>, ) -> Result<(Point<T, N>, Point<T, N>, Point<T, N>), PlaneSide>
Sourcepub fn split_polygon(
&self,
polygon: Polygon<T, N>,
) -> (Polygon<T, N>, Polygon<T, N>)
pub fn split_polygon( &self, polygon: Polygon<T, N>, ) -> (Polygon<T, N>, Polygon<T, N>)
Split a spanning polygon into a front fragment and a back fragment.
Algorithm:
- Classify each vertex with
classify_point. - For each consecutive edge (a, b):
- If
aisFront, addato the front list. - If
aisBack, addato the back list. - If
aisOn, addato both lists. - If edge (a, b) crosses the plane (a and b have opposite Front/Back classification):
compute the intersection point
p = a + t*(b-a)wheret = (d - n·a) / (n·(b-a)), then addpto both lists.
- If
- Build two new
Polygons from the front and back vertex lists, keeping the original plane.
Metadata is preserved: both fragments inherit the source polygon’s metadata.
Source§impl<T> Plane<T, 3>
impl<T> Plane<T, 3>
Sourcepub fn from_points(p1: Point3<T>, p2: Point3<T>, p3: Point3<T>) -> Self
pub fn from_points(p1: Point3<T>, p2: Point3<T>, p3: Point3<T>) -> Self
Construct a plane from three non-collinear points. The normal is oriented by the right-hand rule: (p2 - p1) × (p3 - p1).
Sourcepub fn rotation_to(&self, other: Plane<T, 3>) -> Matrix3<T>where
T: Signed,
pub fn rotation_to(&self, other: Plane<T, 3>) -> Matrix3<T>where
T: Signed,
Compute the 3×3 rotation matrix R such that R * self.normal() == other.normal().
In other words, given a point p that lies in the plane described by self, the product
R * p will lie in the plane described by other. This is the unique shortest-arc rotation
(minimum rotation angle) that carries one normal onto the other, computed via the
Rodrigues rotation formula in its trigonometry-free form.
§Mathematical derivation
Let a = self.normal() and b = other.normal() (both assumed to be unit vectors).
The angle θ between them satisfies:
cos θ = a · b (dot product)
sin θ = ‖a × b‖ (magnitude of cross product)The rotation axis is v = a × b (unnormalized; its magnitude is sin θ).
The skew-symmetric cross-product matrix [v]× encodes the “cross with v” operation:
⎡ 0 −v₃ v₂ ⎤
[v]× = ⎢ v₃ 0 −v₁ ⎥
⎣ −v₂ v₁ 0 ⎦Rodrigues’ formula then gives:
R = I + [v]× + [v]ײ · 1/(1 + cos θ)This avoids calling acos/sin/cos and is numerically stable for all θ except
θ = 180° (anti-parallel normals), which is handled separately below.
§Special case: anti-parallel normals (θ ≈ 180°)
When a · b ≈ −1 the denominator (1 + cos θ) approaches zero, so the formula above
is undefined. Geometrically, any 180° rotation whose axis is perpendicular to a is a
valid solution; we break the degeneracy by choosing the world axis that is least aligned
with a (found with iamin() — the index of the smallest absolute component) as a
helper to build a perpendicular rotation axis:
rot_axis = (a × world_axis).normalize()
R = −I + 2 · rot_axis · rot_axisᵀ(This is Rodrigues with θ = π: cos π = −1, sin π = 0.)
Trait Implementations§
Source§impl<T: PartialEq + Number, const N: usize> PartialEq for Plane<T, N>
impl<T: PartialEq + Number, const N: usize> PartialEq for Plane<T, N>
Source§impl<T: PartialOrd + Number, const N: usize> PartialOrd for Plane<T, N>
impl<T: PartialOrd + Number, const N: usize> PartialOrd for Plane<T, N>
impl<T: Copy + Number, const N: usize> Copy for Plane<T, N>
impl<T: Number, const N: usize> StructuralPartialEq for Plane<T, N>
Auto Trait Implementations§
impl<T, const N: usize> Freeze for Plane<T, N>where
T: Freeze,
impl<T, const N: usize> RefUnwindSafe for Plane<T, N>where
T: RefUnwindSafe,
impl<T, const N: usize> Send for Plane<T, N>
impl<T, const N: usize> Sync for Plane<T, N>
impl<T, const N: usize> Unpin for Plane<T, N>where
T: Unpin,
impl<T, const N: usize> UnsafeUnpin for Plane<T, N>where
T: UnsafeUnpin,
impl<T, const N: usize> UnwindSafe for Plane<T, N>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSend for T
impl<T> DowncastSend for T
§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
§impl<T> Pointable for T
impl<T> Pointable for T
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.