|
| 1 | + |
| 2 | +| Original | Remeshed | |
| 3 | +| - | - | |
| 4 | +|{: style="max-width: 20em; display: block; margin-left: auto; margin-right: auto;"}|{: style="max-width: 20em; display: block; margin-left: auto; margin-right: auto;"} |
| 5 | + |
| 6 | +These routines try to improve mesh quality using repeated rounds of [vertex position smoothing](#tangential-vertex-smoothing), [edge flipping](#extrinsic-delaunay-flipping), and [edge splits/collapses](#edge-length-adjustment). |
| 7 | + |
| 8 | +??? func "`#!cpp void remesh(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& geom, RemeshOptions options = defaultRemeshOptions);`" |
| 9 | + |
| 10 | + Remesh a mesh using vertex smoothing along with edge splits, collapses, and flips. Options are passed as a [RemeshOptions](#options) object. |
| 11 | + |
| 12 | +??? func "`#!cpp void remesh(ManifoldSurfaceMesh& mesh, IntrinsicGeometryInterface& geom, MutationManager& mm, RemeshOptions options = defaultRemeshOptions);`" |
| 13 | + |
| 14 | + Remesh a mesh using vertex smoothing along with edge splits, collapses, and flips. Options are passed as a [RemeshOptions](#options) object. |
| 15 | + 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. |
| 16 | + |
| 17 | +## Tangential Vertex Smoothing |
| 18 | +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]](https://www.sciencedirect.com/science/article/abs/pii/S0045782510003117)), whereas in *Laplacian* smoothing, every vertex is moved towards the average of the positions of its neighboring vertices. |
| 19 | + |
| 20 | +In either case we perform *tangential smoothing*, meaning that we only move vertices tangentially along the surface. |
| 21 | + |
| 22 | +??? func "`#!cpp double smoothByCircumcenter(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);`" |
| 23 | + |
| 24 | + Move each vertex tangentially towards the area-weighted average of its neighboring face circumcenters. |
| 25 | + Returns the average amount that each vertex was moved by. |
| 26 | + |
| 27 | +??? func "`#!cpp double smoothByCircumcenter(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);`" |
| 28 | + |
| 29 | + Move each vertex tangentially towards the area-weighted average of its neighboring face circumcenters |
| 30 | + , using the provided `MutationManager` to move the vertices |
| 31 | + Returns the average amount that each vertex was moved by. |
| 32 | + |
| 33 | +??? func "`#!cpp double smoothByLaplacian(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);`" |
| 34 | + |
| 35 | + Move each vertex tangentially towards the average of its neighbors |
| 36 | + Returns the average amount that each vertex was moved by. |
| 37 | +??? func "`#!cpp double smoothByLaplacian(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, double stepSize = 1, RemeshBoundaryCondition bc = RemeshBoundaryCondition::Tangential);`" |
| 38 | + |
| 39 | + Move each vertex tangentially towards the average of its neighbors, using the provided `MutationManager` to move the vertices |
| 40 | + Returns the average amount that each vertex was moved by. |
| 41 | + |
| 42 | +### Boundary Conditions |
| 43 | +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. |
| 44 | + |
| 45 | +## Extrinsic Delaunay Flipping |
| 46 | +Delaunay flipping performs edge flips to improve triangle quality. |
| 47 | + |
| 48 | +!!! warning "No guarantees" |
| 49 | + |
| 50 | + Unlike the [intrinsic Delaunay flipping routines](/surface/intrinsic_triangulations/basics/#high-level-mutators), extrinsic flipping algorithms are not guaranteed to produce a Delaunay mesh. Nonetheless, these edge flips generally improve triangle quality in practice. |
| 51 | + |
| 52 | +??? func "`#!cpp size_t fixDelaunay(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom);`" |
| 53 | + |
| 54 | + Try to make all triangles Delaunay using extrinsic edge flips. |
| 55 | + Returns the number of flips performed. |
| 56 | + |
| 57 | +??? func "`#!cpp size_t fixDelaunay(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm);`" |
| 58 | + Try to make all triangles Delaunay using extrinsic edge flips, using the provided `MutationManager` to flip edges. |
| 59 | + Returns the number of flips performed. |
| 60 | + |
| 61 | +## Edge Length Adjustment |
| 62 | +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. |
| 63 | + |
| 64 | +??? func "`#!cpp bool adjustEdgeLengths(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, RemeshOptions options = defaultRemeshOptions);`" |
| 65 | + |
| 66 | + Apply splits and collapses to adjust edge lengths. |
| 67 | + |
| 68 | + Reads the following options from `options`, with the following default values and meanings: |
| 69 | + |
| 70 | + * `#!cpp 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. |
| 71 | + * `#!cpp 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. |
| 72 | + * `#!cpp double options.minRelativeLength = 0.05`: the minimum possible edge length in the output mesh. Defined relative to `targetEdgeLength`. |
| 73 | + |
| 74 | +??? func "`#!cpp bool adjustEdgeLengths(ManifoldSurfaceMesh& mesh, VertexPositionGeometry& geom, MutationManager& mm, RemeshOptions options = defaultRemeshOptions);`" |
| 75 | + |
| 76 | + Apply splits and collapses to adjust edge lengths. |
| 77 | + All splits and collapses are performed using the provided `MutationManager`. |
| 78 | + |
| 79 | + Reads the following options from `options`, with the following default values and meanings: |
| 80 | + |
| 81 | + * `#!cpp 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. |
| 82 | + * `#!cpp 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. |
| 83 | + * `#!cpp double options.minRelativeLength = 0.05`: the minimum possible edge length in the output mesh. Defined relative to `targetEdgeLength`. |
| 84 | + |
| 85 | +## Helper Types |
| 86 | +### Options |
| 87 | +Options are passed in to `remesh` via a `RemeshOptions` object. |
| 88 | + |
| 89 | +| Field | Default value | Meaning | |
| 90 | +|----------------------------------------------------|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 91 | +| `#!cpp 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 | |
| 92 | +| `#!cpp size_t maxIterations` | `10` | the maximum number of iterations to run for | |
| 93 | +| `#!cpp 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 | |
| 94 | +| `#!cpp double minRelativeLength` | `0.05` | the minimum possible edge length allowed in the output mesh. Defined relative to targetEdgeLength | |
| 95 | +| `#!cpp RemeshSmoothStyle smoothStyle` | `RemeshSmoothStyle::Circumcentric` | the type of vertex smoothing to use (either `RemeshSmoothStyle::Circumcentric` or `RemeshSmoothStyle::Laplacian`) | |
| 96 | +| `#!cpp RemeshBoundaryCondition boundaryCondition` | `RemeshBoundaryCondition::Tangential` | the type of motions allowed for boundary vertices (either `RemeshBoundaryCondition::Fixed`, `RemeshBoundaryCondition::Tangential` or `RemeshBoundaryCondition::Free`) | |
| 97 | + |
| 98 | +!!! warning "'Fixed' boundary may still move slightly" |
| 99 | + |
| 100 | + 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. |
0 commit comments