Skip to main content

Triangulation

Struct Triangulation 

Source
pub struct Triangulation {
    pub positions: Vec<Point>,
    pub normals: Vec<Vector>,
    pub parameters: Vec<(f64, f64)>,
    pub triangles: Vec<[u32; 3]>,
    pub deflection_met: bool,
}
Expand description

A triangulated surface.

Vertices carry their parameters as well as their positions, so a caller can ask the exact surface about a triangulated point rather than only the approximation.

Fields§

§positions: Vec<Point>

Vertex positions.

§normals: Vec<Vector>

Outward unit normals, one per vertex.

§parameters: Vec<(f64, f64)>

The surface parameters each vertex came from.

§triangles: Vec<[u32; 3]>

Triangles, as indices into the vertex arrays, wound counter-clockwise about the outward normal.

§deflection_met: bool

Whether every face met its requested deflection.

Implementations§

Source§

impl Triangulation

Source

pub fn new() -> Self

An empty mesh.

Source

pub fn vertex_count(&self) -> usize

Number of vertices.

Source

pub fn triangle_count(&self) -> usize

Number of triangles.

Source

pub fn is_empty(&self) -> bool

Whether the mesh holds no triangles.

Source

pub fn bounds(&self) -> Aabb

The bounding box of the vertices.

Source

pub fn area(&self) -> f64

The total area of the triangles.

An underestimate of the surface’s own area for a convex patch, since a triangle chord-cuts the surface it spans. It converges from below as the deflection tightens.

Source

pub fn volume(&self) -> f64

The signed volume enclosed, by the divergence theorem.

Meaningful only for a mesh that is closed and consistently wound outward: each triangle contributes the signed volume of the tetrahedron it forms with the origin, and the contributions cancel except over the enclosed region. An open mesh gives a number with no meaning, and a mesh wound inward gives the negative, which is why Triangulation::is_closed exists to be asked first.

Source

pub fn is_closed(&self) -> bool

Whether every triangle edge is crossed as often one way as the other.

The mesh equivalent of a closed shell, and the precondition for Triangulation::volume meaning anything. It is exactly what the divergence theorem needs: the surface has no boundary, and it is wound consistently, so each triangle’s contribution cancels against its neighbours’ except over the region enclosed.

Counting directed edges rather than undirected ones is what makes this the right question, and it is stricter and looser than the obvious test in the two different ways that matter.

Stricter: two triangles sharing an edge and winding the same way round it traverse it twice in the same direction. The edge is used twice, so a count of uses calls it closed, and the volume that comes out is wrong because one of the two faces is inside out.

Looser: an edge may legitimately carry four triangles. Where two faces meet along a short edge that discretizes into several segments, each can fill the sliver between the polyline and its own chord, and the chord then belongs to both: four triangles round one edge, two crossing each way. There is no hole there and the volume is right; demanding exactly two refuses a mesh for being non-manifold when nothing was asked about manifoldness. Sixty-four bodies of one real assembly were refused that way, forty-four of them for this alone.

This also agrees with the topology side at last: is_shell_closed counts an edge’s uses and accepts any even number, and the two halves of the kernel should not mean different things by the same word.

Source

pub fn border_welded(&self, reach: f64) -> Self

Weld only the mesh’s border vertices, within reach.

The second pass after Triangulation::welded: interior edges are already manifold, and touching them at a widened tolerance would eat real features. Borders are where imported slop lives (an edge’s curve and its neighbour’s disagree by the file’s own tolerance, which the model records on the edge), so only vertices on unmatched triangle edges are candidates, merged to their nearest counterpart within reach.

Source

pub fn border_stitched(&self, reach: f64) -> Self

Split border segments at border vertices that lie on them.

The T-junction repair that follows Triangulation::border_welded: after welding, two faces’ border chains share their vertices but may subdivide the same stretch differently: one face’s segment spans two of its neighbour’s. Splitting the long segment at the neighbour’s own vertex index makes the chains segment-for-segment identical, which is what closure counts. No positions move and none are added.

Source

pub fn sealed(&self, width: f64) -> Self

This mesh with its folds cancelled and its cracks sealed: the last pass over a mesh welded from faces that each met their edges.

A fold is two triangles on the same three vertices facing opposite ways, left where a sliver face collapses in the weld; they enclose nothing, and both go. A crack is a loop of border edges whose mean width (twice its area over its perimeter) is within width: two faces sampling a shared corner differently leave one, narrower than the chord they were drawn to. It is fanned shut from one of its corners, each new triangle crossing a border edge the other way from the triangle already on it. A loop wider than that, or a border vertex with more than one way on, is a real opening and stays.

Source

pub fn append(&mut self, other: &Self)

Append another mesh, shifting its indices.

Source

pub fn welded(&self, tol: Tolerances) -> Self

Merge vertices that coincide within tol, rewiring the triangles.

Faces are triangulated independently, so a shared edge produces two copies of every boundary vertex, at identical positions, since both came from the same edge discretization, but as separate entries. Merging them is what turns a pile of face meshes into one closed surface, and what lets Triangulation::is_closed answer truthfully.

Trait Implementations§

Source§

impl Clone for Triangulation

Source§

fn clone(&self) -> Triangulation

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Triangulation

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Triangulation

Source§

fn default() -> Triangulation

Returns the “default value” for a type. Read more
Source§

impl PartialEq for Triangulation

Source§

fn eq(&self, other: &Triangulation) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for Triangulation

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Scalar for T
where T: 'static + Clone + PartialEq + Debug,

§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.