Manifold 1.0
Robust computational geometry
 
Loading...
Searching...
No Matches
Manifold::Impl Struct Reference

Classes

struct  BaryIndices
 
struct  MeshRelationD
 
struct  Relation
 

Public Types

enum class  Shape { Tetrahedron , Cube , Octahedron }
 

Public Member Functions

 Impl (Shape, const glm::mat4x3=glm::mat4x3(1))
 
 Impl (const MeshGL &, std::vector< float > propertyTolerance={})
 
 Impl (const Mesh &, const MeshRelationD &relation, const std::vector< float > &propertyTolerance={}, bool hasFaceIDs=false)
 
void ForVert (int halfedge, std::function< void(int halfedge)> func)
 
template<typename T >
void ForVert (int halfedge, std::function< T(int halfedge)> transform, std::function< void(int halfedge, const T &here, const T &next)> binaryOp)
 
void CreateFaces (const std::vector< float > &propertyTolerance={})
 
void RemoveUnreferencedVerts (Vec< glm::ivec3 > &triVerts)
 
void InitializeOriginal ()
 
void CreateHalfedges (const Vec< glm::ivec3 > &triVerts)
 
void CalculateNormals ()
 
void IncrementMeshIDs ()
 
void Update ()
 
void MarkFailure (Error status)
 
void Warp (std::function< void(glm::vec3 &)> warpFunc)
 
void WarpBatch (std::function< void(VecView< glm::vec3 >)> warpFunc)
 
Impl Transform (const glm::mat4x3 &transform) const
 
SparseIndices EdgeCollisions (const Impl &B, bool inverted=false) const
 
SparseIndices VertexCollisionsZ (VecView< const glm::vec3 > vertsIn, bool inverted=false) const
 
bool IsEmpty () const
 
int NumVert () const
 
int NumEdge () const
 
int NumTri () const
 
int NumProp () const
 
int NumPropVert () const
 
Properties GetProperties () const
 
void CalculateCurvature (int gaussianIdx, int meanIdx)
 
void CalculateBBox ()
 
bool IsFinite () const
 
bool IsIndexInBounds (VecView< const glm::ivec3 > triVerts) const
 
void SetPrecision (float minPrecision=-1)
 
bool IsManifold () const
 
bool Is2Manifold () const
 
bool MatchesTriNormals () const
 
int NumDegenerateTris () const
 
float MinGap (const Impl &other, float searchLength) const
 
void Finish ()
 
void SortVerts ()
 
void ReindexVerts (const Vec< int > &vertNew2Old, int numOldVert)
 
void CompactProps ()
 
void GetFaceBoxMorton (Vec< Box > &faceBox, Vec< uint32_t > &faceMorton) const
 
void SortFaces (Vec< Box > &faceBox, Vec< uint32_t > &faceMorton)
 
void GatherFaces (const Vec< int > &faceNew2Old)
 
void GatherFaces (const Impl &old, const Vec< int > &faceNew2Old)
 
void Face2Tri (const Vec< int > &faceEdge, const Vec< TriRef > &halfedgeRef)
 
PolygonsIdx Face2Polygons (VecView< Halfedge >::IterC start, VecView< Halfedge >::IterC end, glm::mat3x2 projection) const
 
CrossSection Slice (float height) const
 
CrossSection Project () const
 
void SimplifyTopology ()
 
void DedupeEdge (int edge)
 
void CollapseEdge (int edge, std::vector< int > &edges)
 
void RecursiveEdgeSwap (int edge, int &tag, std::vector< int > &visited, std::vector< int > &edgeSwapStack, std::vector< int > &edges)
 
void RemoveIfFolded (int edge)
 
void PairUp (int edge0, int edge1)
 
void UpdateVert (int vert, int startEdge, int endEdge)
 
void FormLoop (int current, int end)
 
void CollapseTri (const glm::ivec3 &triEdge)
 
void SplitPinchedVerts ()
 
int GetNeighbor (int tri) const
 
glm::ivec4 GetHalfedges (int tri) const
 
BaryIndices GetIndices (int halfedge) const
 
void FillRetainedVerts (Vec< Barycentric > &vertBary) const
 
Vec< BarycentricSubdivide (std::function< int(glm::vec3)>)
 
bool IsInsideQuad (int halfedge) const
 
bool IsMarkedInsideQuad (int halfedge) const
 
glm::vec3 GetNormal (int halfedge, int normalIdx) const
 
std::vector< SmoothnessUpdateSharpenedEdges (const std::vector< Smoothness > &) const
 
Vec< boolFlatFaces () const
 
Vec< intVertFlatFace (const Vec< bool > &) const
 
std::vector< SmoothnessSharpenEdges (float minSharpAngle, float minSmoothness) const
 
void SharpenTangent (int halfedge, float smoothness)
 
void SetNormals (int normalIdx, float minSharpAngle)
 
void LinearizeFlatTangents ()
 
void CreateTangents (int normalIdx)
 
void CreateTangents (std::vector< Smoothness >)
 
void Refine (std::function< int(glm::vec3)>)
 

Static Public Member Functions

static uint32_t ReserveIDs (uint32_t)
 

Public Attributes

Box bBox_
 
float precision_ = -1
 
Error status_ = Error::NoError
 
Vec< glm::vec3 > vertPos_
 
Vec< Halfedgehalfedge_
 
Vec< glm::vec3 > vertNormal_
 
Vec< glm::vec3 > faceNormal_
 
Vec< glm::vec4 > halfedgeTangent_
 
MeshRelationD meshRelation_
 
Collider collider_
 

Static Public Attributes

static std::atomic< uint32_tmeshIDCounter_
 

Class Documentation

◆ manifold::Manifold::Impl::BaryIndices

struct manifold::Manifold::Impl::BaryIndices
Class Members
int tri
int start4
int end4

◆ manifold::Manifold::Impl::MeshRelationD

struct manifold::Manifold::Impl::MeshRelationD
Class Members
int originalID = -1 The originalID of this Manifold if it is an original; -1 otherwise.
int numProp = 0
Vec< float > properties
map< int, Relation > meshIDtransform
Vec< TriRef > triRef
Vec< ivec3 > triProperties

◆ manifold::Manifold::Impl::Relation

struct manifold::Manifold::Impl::Relation
Class Members
int originalID = -1
mat4x3 transform = glm::mat4x3(1)
bool backSide = false

Constructor & Destructor Documentation

◆ Impl() [1/2]

Impl ( Shape  shape,
const glm::mat4x3  m = glm::mat4x3(1) 
)

Create either a unit tetrahedron, cube or octahedron. The cube is in the first octant, while the others are symmetric about the origin.

◆ Impl() [2/2]

Impl ( const Mesh mesh,
const MeshRelationD relation,
const std::vector< float > &  propertyTolerance = {},
bool  hasFaceIDs = false 
)

Create a manifold from an input triangle Mesh. Will return an empty Manifold and set an Error Status if the Mesh is not manifold or otherwise invalid. TODO: update halfedgeTangent during SimplifyTopology.

Member Function Documentation

◆ CreateHalfedges()

void CreateHalfedges ( const Vec< glm::ivec3 > &  triVerts)

Create the halfedge_ data structure from an input triVerts array like Mesh.

◆ CalculateNormals()

void CalculateNormals ( )

If face normals are already present, this function uses them to compute vertex normals (angle-weighted pseudo-normals); otherwise it also computes the face normals. Face normals are only calculated when needed because nearly degenerate faces will accrue rounding error, while the Boolean can retain their original normal, which is more accurate and can help with merging coplanar faces.

If the face normals have been invalidated by an operation like Warp(), ensure you do faceNormal_.resize(0) before calling this function to force recalculation.

◆ IncrementMeshIDs()

void IncrementMeshIDs ( )

Remaps all the contained meshIDs to new unique values to represent new instances of these meshes.

◆ Update()

void Update ( )

Does a full recalculation of the face bounding boxes, including updating the collider, but does not resort the faces.

◆ EdgeCollisions()

SparseIndices EdgeCollisions ( const Impl Q,
bool  inverted = false 
) const

Returns a sparse array of the bounding box overlaps between the edges of the input manifold, Q and the faces of this manifold. Returned indices only point to forward halfedges.

◆ VertexCollisionsZ()

SparseIndices VertexCollisionsZ ( VecView< const glm::vec3 >  vertsIn,
bool  inverted = false 
) const

Returns a sparse array of the input vertices that project inside the XY bounding boxes of the faces of this manifold.

◆ CalculateBBox()

void CalculateBBox ( )

Calculates the bounding box of the entire manifold, which is stored internally to short-cut Boolean operations and to serve as the precision range for Morton code calculation. Ignores NaNs.

◆ IsFinite()

bool IsFinite ( ) const

Determines if all verts are finite. Checking just the bounding box dimensions is insufficient as it ignores NaNs.

◆ IsIndexInBounds()

bool IsIndexInBounds ( VecView< const glm::ivec3 >  triVerts) const

Checks that the input triVerts array has all indices inside bounds of the vertPos_ array.

◆ SetPrecision()

void SetPrecision ( float  minPrecision = -1)

Sets the precision based on the bounding box, and limits its minimum value by the optional input.

◆ IsManifold()

bool IsManifold ( ) const

Returns true if this manifold is in fact an oriented even manifold and all of the data structures are consistent.

◆ Is2Manifold()

bool Is2Manifold ( ) const

Returns true if this manifold is in fact an oriented 2-manifold and all of the data structures are consistent.

◆ MatchesTriNormals()

bool MatchesTriNormals ( ) const

Returns true if all triangles are CCW relative to their triNormals_.

◆ NumDegenerateTris()

int NumDegenerateTris ( ) const

Returns the number of triangles that are colinear within precision_.

◆ Finish()

void Finish ( )

Once halfedge_ has been filled in, this function can be called to create the rest of the internal data structures. This function also removes the verts and halfedges flagged for removal (NaN verts and -1 halfedges).

◆ SortVerts()

void SortVerts ( )

Sorts the vertices according to their Morton code.

◆ ReindexVerts()

void ReindexVerts ( const Vec< int > &  vertNew2Old,
int  oldNumVert 
)

Updates the halfedges to point to new vert indices based on a mapping, vertNew2Old. This may be a subset, so the total number of original verts is also given.

◆ CompactProps()

void CompactProps ( )

Removes unreferenced property verts and reindexes triProperties.

◆ GetFaceBoxMorton()

void GetFaceBoxMorton ( Vec< Box > &  faceBox,
Vec< uint32_t > &  faceMorton 
) const

Fills the faceBox and faceMorton input with the bounding boxes and Morton codes of the faces, respectively. The Morton code is based on the center of the bounding box.

◆ SortFaces()

void SortFaces ( Vec< Box > &  faceBox,
Vec< uint32_t > &  faceMorton 
)

Sorts the faces of this manifold according to their input Morton code. The bounding box and Morton code arrays are also sorted accordingly.

◆ GatherFaces()

void GatherFaces ( const Vec< int > &  faceNew2Old)

Creates the halfedge_ vector for this manifold by copying a set of faces from another manifold, given by oldHalfedge. Input faceNew2Old defines the old faces to gather into this.

◆ Face2Tri()

void Face2Tri ( const Vec< int > &  faceEdge,
const Vec< TriRef > &  halfedgeRef 
)

Triangulates the faces. In this case, the halfedge_ vector is not yet a set of triangles as required by this data structure, but is instead a set of general faces with the input faceEdge vector having length of the number of faces + 1. The values are indicies into the halfedge_ vector for the first edge of each face, with the final value being the length of the halfedge_ vector itself. Upon return, halfedge_ has been lengthened and properly represents the mesh as a set of triangles as usual. In this process the faceNormal_ values are retained, repeated as necessary.

◆ Face2Polygons()

PolygonsIdx Face2Polygons ( VecView< Halfedge >::IterC  start,
VecView< Halfedge >::IterC  end,
glm::mat3x2  projection 
) const

Returns a set of 2D polygons formed by the input projection of the vertices of the list of Halfedges, which must be an even-manifold, meaning each vert must be referenced the same number of times as a startVert and endVert.

◆ SimplifyTopology()

void SimplifyTopology ( )

Collapses degenerate triangles by removing edges shorter than precision_ and any edge that is preceeded by an edge that joins the same two face relations. It also performs edge swaps on the long edges of degenerate triangles, though there are some configurations of degenerates that cannot be removed this way.

Before collapsing edges, the mesh is checked for duplicate edges (more than one pair of triangles sharing the same edge), which are removed by duplicating one vert and adding two triangles. These degenerate triangles are likely to be collapsed again in the subsequent simplification.

Note when an edge collapse would result in something non-manifold, the vertices are duplicated in such a way as to remove handles or separate meshes, thus decreasing the Genus(). It only increases when meshes that have collapsed to just a pair of triangles are removed entirely.

Rather than actually removing the edges, this step merely marks them for removal, by setting vertPos to NaN and halfedge to {-1, -1, -1, -1}.

◆ GetNeighbor()

int GetNeighbor ( int  tri) const

Returns the tri side index (0-2) connected to the other side of this quad if this tri is part of a quad, or -1 otherwise.

◆ GetHalfedges()

glm::ivec4 GetHalfedges ( int  tri) const

For the given triangle index, returns either the three halfedge indices of that triangle and halfedges[3] = -1, or if the triangle is part of a quad, it returns those four indices. If the triangle is part of a quad and is not the lower of the two triangle indices, it returns all -1s.

◆ GetIndices()

Manifold::Impl::BaryIndices GetIndices ( int  halfedge) const

Returns the BaryIndices, which gives the tri and indices (0-3), such that GetHalfedges(val.tri)[val.start4] points back to this halfedge, and val.end4 will point to the next one. This function handles this for both triangles and quads. Returns {-1, -1, -1} if the edge is the interior of a quad.

◆ FillRetainedVerts()

void FillRetainedVerts ( Vec< Barycentric > &  vertBary) const

Retained verts are part of several triangles, and it doesn't matter which one the vertBary refers to. Here, whichever is last will win and it's done on the CPU for simplicity for now. Using AtomicCAS on .tri should work for a GPU version if desired.

◆ Subdivide()

Vec< Barycentric > Subdivide ( std::function< int(glm::vec3)>  edgeDivisions)

Split each edge into n pieces as defined by calling the edgeDivisions function, and sub-triangulate each triangle accordingly. This function doesn't run Finish(), as that is expensive and it'll need to be run after the new vertices have moved, which is a likely scenario after refinement (smoothing).

◆ IsInsideQuad()

bool IsInsideQuad ( int  halfedge) const

Returns true if this halfedge should be marked as the interior of a quad, as defined by its two triangles referring to the same face, and those triangles having no further face neighbors beyond.

◆ IsMarkedInsideQuad()

bool IsMarkedInsideQuad ( int  halfedge) const

Returns true if this halfedge is an interior of a quad, as defined by its halfedge tangent having negative weight.

◆ GetNormal()

glm::vec3 GetNormal ( int  halfedge,
int  normalIdx 
) const

Get the property normal associated with the startVert of this halfedge, where normalIdx shows the beginning of where normals are stored in the properties.

◆ SharpenTangent()

void SharpenTangent ( int  halfedge,
float  smoothness 
)

Sharpen tangents that intersect an edge to sharpen that edge. The weight is unchanged, as this has a squared effect on radius of curvature, except in the case of zero radius, which is marked with weight = 0.

◆ SetNormals()

void SetNormals ( int  normalIdx,
float  minSharpAngle 
)

Instead of calculating the internal shared normals like CalculateNormals does, this method fills in vertex properties, unshared across edges that are bent more than minSharpAngle.

◆ LinearizeFlatTangents()

void LinearizeFlatTangents ( )

Tangents get flattened to create sharp edges by setting their weight to zero. This is the natural limit of reducing the weight to increase the sharpness smoothly. This limit gives a decent shape, but it causes the parameterization to be stretched and compresses it near the edges, which is good for resolving tight curvature, but bad for property interpolation. This function fixes the parameter stretch at the limit for sharp edges, since there is no curvature to resolve. Note this also changes the overall shape - making it more evenly curved.

◆ CreateTangents() [1/2]

void CreateTangents ( int  normalIdx)

Calculates halfedgeTangent_, allowing the manifold to be refined and smoothed. The tangents form weighted cubic Beziers along each edge. This function creates circular arcs where possible (minimizing maximum curvature), constrained to the indicated property normals. Across edges that form discontinuities in the normals, the tangent vectors are zero-length, allowing the shape to form a sharp corner with minimal oscillation.

◆ CreateTangents() [2/2]

void CreateTangents ( std::vector< Smoothness sharpenedEdges)

Calculates halfedgeTangent_, allowing the manifold to be refined and smoothed. The tangents form weighted cubic Beziers along each edge. This function creates circular arcs where possible (minimizing maximum curvature), constrained to the vertex normals. Where sharpenedEdges are specified, the tangents are shortened that intersect the sharpened edge, concentrating the curvature there, while the tangents of the sharp edges themselves are aligned for continuity.