Remove mesh faces bug or not?

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;

Initial mesh

RemoveNgonwithFaces.gh (10.5 KB)

Mesh after removal of 1 ngon and its faces:

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. :slight_smile:

// Rolf

1 Like

Yeah I understand but, it also means that I need to recreate all ngons from scratch and check which one indices shifted.

Which becomes more complex when each ngon is a collection of faces. Ech…

Will try to loop through each ngon and to sort it out thanks for the logic:)

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)

// Rolf

No it does not.

I think this methods remains from Rhino5, and it was not changed in Rhino6.
Since this breaks meshngon indexlist, mesh becomes invalid.

For instance
//First I removed this ngon and then its faces
MeshNgon ngon0 = new MeshNgon(somevertexloop, new int [0,1,5,3] );

//So these guys remains

MeshNgon ngon1 = new MeshNgon(somevertexloop, new int [2,4,6] );
MeshNgon ngon2 = new MeshNgon(somevertexloop, new int [7,8,9,10,11] );

Now lets say I removed ngon0,
What would be the logic to update ngon1 and ngon2 face indexing?
[2,4,6] and [7,8,9,10,11] ?

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).

// Rolf

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());
  }
1 Like