Welding mesh vertices by distance

Hi,

If I have a mesh that has vertices disconnected and apart by tiny tiny distance, that I want to weld.
More simply: vertices in those cases are not coincident.

These methods wont help:
mesh.Weld(0.01);
mesh.Vertices.CombineIdentical(true, true);

Is there any approach in rhino-common that could help merge vertices by some distance?

In rhino I was using macro:
__AlignMeshVertices _SelectNakedEdges _All _Pause 0.1 Enter

What would be a translation to C# ? Is AlignMeshVertices exposed to SDK?
https://mcneel.myjetbrains.com/youtrack/issue/RH-29113

This mesh was created from bunch of polylines, and I think a floating point error produced a tiny tiny gap.

From RhinoCommon this is not so easy, I think. What you can do is get all naked edge vertices using mesh.GetNakedEdgePointStatus (see below), then try to see if two naked edge vertices are within a certain tolerance. If so, set one of them to the location of the other. Afterwards, call mesh.Vertices.CombineIdentical(true,true)

http://developer.rhino3d.com/api/RhinoCommonWin/html/M_Rhino_Geometry_Mesh_GetNakedEdgePointStatus.htm

For large meshes, the searching can be speeded up using an R-tree.

1 Like

RTree seems to be a nice approach thanks:)

Maybe there is smarter way, but I used as your suggested method:

//Store naked mesh vertices and their ids
List<Point3f> pts = new List<Point3f>();
bool[] flag = M.GetNakedEdgePointStatus();

allPointsFound = new List<List<int>>();

//History is need to stop searching rtee
//When all point groups are found
history.Clear();

//Create Rtree
RTree tree = new RTree();

for(int i = 0; i < flag.Length; i++){
  if(flag[i]){
    tree.Insert(M.Vertices[i], i);
    pts.Add(M.Vertices[i]);
  }
}

//Search RTree
for(int i = 0; i < pts.Count; i++){
  tempIDList = new List<int>();
  tree.Search(new Sphere(pts[i], radius), method);

  if(tempIDList.Count > 1)
    allPointsFound.Add(tempIDList);

  if(history.Count == M.Vertices.Count)
    break;
}

//Now move found vertices to one of firs vertex position
foreach(List<int> i in allPointsFound)
  for(int j = 1; j < i.Count; j++)
    M.Vertices[i[0]] = M.Vertices[i[j]];

M.Vertices.CombineIdentical(false, false);


A = M;

}

// <Custom additional code> 

  //Rtree collections
  List<int> history = new List<int>();
  List<List<int>> allPointsFound;
  List<int> tempIDList;

  private void method(object sender, RTreeEventArgs e){
    if(!history.Contains(e.Id)){
     tempIDList.Add(e.Id);
      history.Add(e.Id);
    }
  }

15_RTree_WeldMesh.gh (7.6 KB)

First I tested the rtee method with bunch of points:

It seems to do what I needed.

3 Likes

Look good! The only thing is that you use a fixed search radius, and that this may cause collapsing of faces if chosen too large. An alternative would be to enumerate all vertices that radiate from the one you are looking at, calculate the minimum distance, and use a small fraction of that to search.

Shouldn’t it be
M.Vertices[i[j]] = M.Vertices[i[0]];
instead?

Yes, in NGon plugin I am using the correct version:

Four years for this post…

This post just solve my problem. Thanks a lot for sharing !