I think this is a bug when you want to remove 1) one ngon 2) and then remove previously ngon contained meshes faces (I am not removing vertices just faces)
I believe the mesh becomes invalid because all stored mesh ngons face ids shifted after mesh faces removal. Is it true and is it possible to fix?
Is the only solution to clear all ngons and add new ones?
And this has to be done after each mesh face deletion?
Example:
//Copy mesh
Mesh mesh = M.DuplicateMesh();
//Get ngon mesh faces
uint[] faces = mesh.Ngons[50].FaceIndexList();
int[] facesIntArray = new int[faces.Length];
for(int i = 0; i < faces.Length; i++)
facesIntArray[i] = (int) faces[i];
mesh.Ngons.RemoveNgons(new int[]{50});//Same stuff with RemoveAt
mesh.Faces.DeleteFaces(facesIntArray); //<-------error after this line
A = mesh;
I would guess that you get an index error when deleting the Faces (same problem when deleting Vertices). If so, the solution is to sort the Faces (or Vertices) as OrderByDescending. Otherwise the internal logic in the DeleteFaces method may delete an index that is past the end of the list/array.
if say, you have the following list
[0|1|2|3|4]
and try to delete [3|4], then the first item to delete [3] will succeed, but not the second [4], because by then the list has shrinked so that index [4] no longer exist, like so:
[0|1|2|3|4]
[3] // Delete index 3,
[0|1|2|4] // But when trying to delete index 4 then...
[4] // ... we are out of bounds :)
^!%#3@!!
Just some hours ago I encountered a problem with errors when deleting vertices, which I fixed like so:
var removals = new List<int>();
for (var i = 0; i < mesh.Vertices.Count; i++)
{
if (CullB[i])
removals.Add(i);
}
var ordered = removals.OrderByDescending(x => x); // Fixes errors in
mesh.Vertices.Remove(ordered, false); // remove method
If this is not the problem in your case, then… never mind.
I think that RhinoCommon’s DeleteFaces-method fixes the index shifting. It is only during removal that the method tends to exceed the bounds of the list when a “big” index comes late in the removal loop (deletion from the end towards the beginning of the list removes the problem, by the suggested sorting)
Hm. I’ve never used Ngons so I don’t know how they behave when manipulated. All I know is that when removing Vertices or Faces then Rhino’s Mesh class updates the indices properly (if you survive the removal as discussed above).
It requires some sort of mapping, here is something that helps to remove 1 ngon, ech, now I fixed faces update, I noticed for naked vertices also vertex list is required to be updated uhu… but rhinocommon somehow updates vertices strange that this works… attach the code if somebody else will needRemoveNgonwithFaces.gh (7.2 KB)
.
private void RunScript(Mesh M, ref object A, ref object B)
{
try{
//Copy mesh
Mesh mesh = M.DuplicateMesh();
int removeID = 10;
//Get ngon mesh faces
Tuple<List<int>,List<int>> ngonFacesAndVertices = BoundaryVertexIndexListInt(mesh.Ngons[removeID]);
Print(mesh.Ngons.Count.ToString());
mesh.Ngons.RemoveNgons(new int[]{removeID});//Same stuff with RemoveAt
//Copy face array
int[] faces = Enumerable.Range(0, mesh.Faces.Count).ToArray();
//Remove faces in order
var ordered = ngonFacesAndVertices.Item2.OrderByDescending(x => x);
mesh.Faces.DeleteFaces(ordered);//<-------error after this line
//Copy face array
int[] facesUpdated = Enumerable.Range(0, faces.Length).ToArray();
B = ordered;
int k = 0;
for(int i = 0; i < faces.Length;i++){
if(ordered.Contains(i) ){
facesUpdated[i] = (-1);
}else{
facesUpdated[i] = (k++);
}
//Print( facesUpdated[i].ToString());
}
//Copy all ngon list
List < MeshNgon > ngonlist = new List<MeshNgon>();
mesh = mesh.DuplicateMesh();
foreach(MeshNgon ng in mesh.Ngons)
ngonlist.Add(ng);
//Clear ngons from mesh
Print(mesh.Ngons.Count.ToString());
mesh.Ngons.Clear();
Print(ngonlist.Count.ToString());
for(int i = 0; i < ngonlist.Count;i++){
Tuple<List<int>,List<int>> ngonsInputs = BoundaryVertexIndexListInt(ngonlist[i]);
for(int j = 0; j < ngonsInputs.Item2.Count;j++){
ngonsInputs.Item2[j] = facesUpdated[ngonsInputs.Item2[j]];
Print(ngonsInputs.Item2[j].ToString());
}
mesh.Ngons.AddNgon(MeshNgon.Create(ngonsInputs.Item1, ngonsInputs.Item2));
}
Print("???????? ");
Print(mesh.Ngons.Count.ToString());
// MeshNgon ngonUpdated = MeshNgon.Create(ngonlist[51]);
//mesh.Ngons.AddNgon(ngonlist[51]);
//Print(mesh.Ngons.Count.ToString());
A = mesh;
}catch(Exception e){
Print(e.ToString());
}
}
// <Custom additional code>
public Tuple<List<int>,List<int>>BoundaryVertexIndexListInt(MeshNgon ngon){
uint[] vertices = ngon.BoundaryVertexIndexList();
List<int> vertexIntArray = new List<int>(vertices.Length);
for(int i = 0; i < vertices.Length; i++)
vertexIntArray.Add((int) vertices[i]);
uint[] faces = ngon.FaceIndexList();
List<int> facesIntArray = new List<int>(faces.Length);
for(int i = 0; i < faces.Length; i++)
facesIntArray.Add((int) faces[i]);
return new Tuple<List<int>,List<int>>(vertexIntArray.ToList(), facesIntArray.ToList());
}