Skip to content

Remeshing

Original Remeshed
finely_triangulated_spot coarsely_triangulated_spot

These routines try to improve mesh quality using repeated rounds of vertex position smoothing, edge flipping, and edge splits/collapses.

void remesh(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& geom, RemeshOptions options = defaultRemeshOptions);

Remesh a mesh using vertex smoothing along with edge splits, collapses, and flips. Options are passed as a RemeshOptions object.

void remesh(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& geom, MutationManager& mm, RemeshOptions options = defaultRemeshOptions);

Remesh a mesh using vertex smoothing along with edge splits, collapses, and flips. Options are passed as a RemeshOptions object. All mesh mutations are performed through a MutationManager object, which can e.g. keep special vertices fixed or run callback functions when certain mesh mutations occur.

Tangential Vertex Smoothing

Vertex smoothing moves each vertex towards the average of its neighborhood. This average can be computed in two ways: in circumentric smoothing, every vertex is moved towards the area-weighted average of the circumcenters of its neighboring faces (as in [Chen & Holst 2011]), whereas in Laplacian smoothing, every vertex is moved towards the average of the positions of its neighboring vertices.

In either case we perform tangential smoothing, meaning that we only move vertices tangentially along the surface.

double smoothByCircumcenter(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);

Move each vertex tangentially towards the area-weighted average of its neighboring face circumcenters. Returns the average amount that each vertex was moved by.

double smoothByCircumcenter(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);

Move each vertex tangentially towards the area-weighted average of its neighboring face circumcenters , using the provided MutationManager to move the vertices Returns the average amount that each vertex was moved by.

double smoothByLaplacian(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);
double smoothByLaplacian(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);

Move each vertex tangentially towards the average of its neighbors, using the provided MutationManager to move the vertices Returns the average amount that each vertex was moved by.

Boundary Conditions

The boundary conditions for smoothing can be set to RemeshBoundaryCondition::Tangential, RemeshBoundaryCondition::Fixed, or RemeshBoundaryCondition::Free. Tangential smoothing allows boundary vertices to move along the tangent direction to the boundary curve, fixed smoothing fixes the boundary vertices, and free smoothing allows boundary vertices to move along any direction in the surface’s tangent plane. Leaving boundary vertices free allows the mesh to degenerate, so it is not recommended unless you impose additional constraints.

Extrinsic Delaunay Flipping

Delaunay flipping performs edge flips to improve triangle quality.

No guarantees

Unlike the intrinsic Delaunay flipping routines, extrinsic flipping algorithms are not guaranteed to produce a Delaunay mesh. Nonetheless, these edge flips generally improve triangle quality in practice.

size_t fixDelaunay(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom);

Try to make all triangles Delaunay using extrinsic edge flips. Returns the number of flips performed.

size_t fixDelaunay(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm);

Try to make all triangles Delaunay using extrinsic edge flips, using the provided MutationManager to flip edges. Returns the number of flips performed.

Edge Length Adjustment

These routines perform edge splits and collapses to drive mesh edge lengths towards a target value. If curvature adaptation is enabled, this target length is made shorter in high-curvature areas, leading to more resolution there.

bool adjustEdgeLengths(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, RemeshOptions options = defaultRemeshOptions);

Apply splits and collapses to adjust edge lengths.

Reads the following options from options, with the following default values and meanings:

  • double options.targetEdgeLength = -1: the target edge length in flat regions. If targetEdgeLength is negative, the target length is set relative to the input mesh’s mean length.
  • double options.curvatureAdaptation = 0: how much target edge length should vary due to curvature. Set curvatureAdaptation to zero if you want edge lengths to be approximately targetEdgeLength everywhere.
  • double options.minRelativeLength = 0.05: the minimum possible edge length in the output mesh. Defined relative to targetEdgeLength.
bool adjustEdgeLengths(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, RemeshOptions options = defaultRemeshOptions);

Apply splits and collapses to adjust edge lengths. All splits and collapses are performed using the provided MutationManager.

Reads the following options from options, with the following default values and meanings:

  • double options.targetEdgeLength = -1: the target edge length in flat regions. If targetEdgeLength is negative, the target length is set relative to the input mesh’s mean length.
  • double options.curvatureAdaptation = 0: how much target edge length should vary due to curvature. Set curvatureAdaptation to zero if you want edge lengths to be approximately targetEdgeLength everywhere.
  • double options.minRelativeLength = 0.05: the minimum possible edge length in the output mesh. Defined relative to targetEdgeLength.

Helper Types

Options

Options are passed in to remesh via a RemeshOptions object.

Field Default value Meaning
double targetEdgeLength -1 the target edge length in flat regions. If targetEdgeLength is negative, the target edge length is set to relative the input mesh’s mean edge length
size_t maxIterations 10 the maximum number of iterations to run for
double curvatureAdaptation 0 how much target length should vary due to curvature. Set curvatureAdaptation to 0 if you want edge lengths to be approximately targetEdgeLength everywhere
double minRelativeLength 0.05 the minimum possible edge length allowed in the output mesh. Defined relative to targetEdgeLength
RemeshSmoothStyle smoothStyle RemeshSmoothStyle::Circumcentric the type of vertex smoothing to use (either RemeshSmoothStyle::Circumcentric or RemeshSmoothStyle::Laplacian)
RemeshBoundaryCondition boundaryCondition RemeshBoundaryCondition::Tangential the type of motions allowed for boundary vertices (either RemeshBoundaryCondition::Fixed, RemeshBoundaryCondition::Tangential or RemeshBoundaryCondition::Free)

‘Fixed’ boundary may still move slightly

Setting boundaryCondition to RemeshBoundaryCondition::Fixed only fixes boundary vertices during vertex smoothing. Boundary edges may still be split or collapsed during edge length adjustment, which can also cause the boundary to move slightly. To stop all motion of the boundary, you can pass in a MutationManager which marks all boundary edges as not splittable or collapsible.