Cleaning and repairing meshes
In #353 some cleaning functions were proposed to eliminate vertices of a mesh that are orphan or to "merge" them somehow. Instead of providing this functionality as isolated functions, we should aim for a more composable transform interface.
I propose that we start listing the possible cleaning operations that we would like to implement in this issue, and then we can open separate PRs for each of them. A good list of cleaning operations is available in the MeshLab project as discussed in our Zulip channel.
- [x] 0 = only duplicated vertices and faces are removed
- [x] 1 = remove unreferenced vertices
- [ ] 2 = remove non-manifold faces
- [ ] 3 = remove degenerate faces
- [ ] 4 = remove non-manifold vertices
- [ ] 5 = split non-manifold vertices by threshold
- [ ] 6 = merge close vertices (given a radius)
- [x] 7 = coherently orient faces
I believe MeshLab has the same cleaning operations than the R package Rvcg.
I already implemented 0 (I called it gather(mesh)) and 1. I don't know what is a manifold vertex/face. 6 can be obtained by a minor modification of 0. For 7 I don't know how to do.
I don't know what is a manifold vertex/face
https://sinestesia.co/blog/tutorials/non-manifold-meshes-and-how-to-fix-them/
Basically, a mesh is said to be manifold when it represents a "simple" surface, i.e. when you look at it locally you can imagine a Cartesian plane with two dimensions. When a vertex shares more than 3 edges or when an edge shares more than 2 faces, it means that we have some sort of feature that doesn't belong to the "surface", e.g. a face that is hanging in a T shape.
Thanks.
Regarding the names for these functions, in Rvcg there's a unique function named vcgClean. The wanted operations are given by one or more numbers between 0 and 7. Personally I don't really like.
Yes, I think we can aim for a more composable set of transforms. The naming will be difficult but we can certainly do better.
Hello,
I have a function which removes the unused vertices of a mesh. How should I name it and where should I put it if I want to do a PR? Currently it is named removeUnusedVertices. This function is necessary for the clipping (another function I have).
Let's follow the numbering convention in MeshLab and Rvcg that you shared in https://github.com/JuliaGeometry/Meshes.jl/issues/354#issuecomment-1364685494.
We can create a single transform called Repair{K} that takes a code K as a static parameter and dispatches the correct algorithm. For example:
"""
Repair{K}
Perform repairing operation with code `K`.
## Available operations
- K = 0: duplicated vertices and faces are removed
- K = 1: ...
"""
struct Repair{K} <: StatelessGeometricTransform end
# implement operation K = 0
function apply(transform::Repair{0}, mesh)
# TODO
end
You can save this transform in our transforms folder along with the other available geometric transforms.
Hmm I don't understand this code. Could you show me how to call Repair{0}? I mean if I have a mesh, how to apply Repair{0} to this mesh?
Any transform defined in this package can be applied as a functor, so you can mesh |> Repair{0} |> Repair{1} for example. You can also construct a lazy pipeline to apply to any new mesh you get, this is done with the \to operator:
pipe = Repair{0} → Repair{1}
# pipe syntax
mesh |> pipe
# functor syntax
pipe(mesh)
I've done the job. But I tried mesh |> Repair{1} and that does not work (no method matching).
Should I export Repair{1}? I exported Repair.
Can you share your attempt in a PR so that we can review it together? The transform machinery has many fallback implementations and so you need to implement the correct method to get it dispatched correctly.
@stla I will work on Repair{7}, we already have it implemented because our HalfEdgeTopology constructor reorders the vertices to make the resulting set of faces coherent.
@stla I added Repair{7}. You mentioned that you already have Repair{0} and Repair{6} implemented right? Mind submitting them as PRs? I've created a check list in this issue so that we track the missing ones.
@juliohm I have 0 only for removing the duplicated vertices, not the duplicated faces. Then 6 is very similar, it suffices to replace the equality with the closeness.
@juliohm Now we have everything ready for the clipping. Should we define clip(mesh) as a transform too?
Can you remind what the clip function does exactly? Maybe in a separate issue or Zulip? This issue we are using to track the repairing operations.