Warning: New mesh is not valid. ON_Mesh.m_F.vi has invalid vertex indices

I’m developing a Rhino plugin. A command of the plugin takes an input mesh and then generates an output mesh. I receive the following warning for an output mesh, when it’s being added to Rhino document:

Warning: New mesh is not valid.
ON_Mesh.m_F[9203].vi[] has invalid vertex indices.

However, the output mesh is saved as STL and it’s opened without any problem on MeshLab and other 3D software.

I studied this post and made sure that my output mesh has its local coordinate system origin i.e. (0, 0, 0) located at its bounding-box center. But the warning persists:

I have attached the input mesh mesh.stl and the output mesh mesh-hollowed.stl saved as STL:

mesh.stl (460.9 KB)

mesh-hollowed.stl (4.9 MB)

I’d appreciate any hints.

Moved to Developer category.

When I import the output mesh saved as STL, i.e. mesh-hollowed.stl, into the Rhino again, I observe that Rhino considers it as two separate meshes, rather than a single one. It’s a hollowed mesh, so it has an outer surface and an inner surface. But both external and internal surfaces are part of the same mesh, not separate.

I’m not sure why Rhino considers them two separate meshes, but not other software like MeshLab. Maybe this observation is related to the warning I’m receiving.

2023-05-03 21_11_59-

2023-05-03 21_12_52-

Just a side note, the outer surface has normal vectors pointing outward. And the inner surface has normal vectors pointing inward.

Maybe related:

Hi @Megidd, you’ll get 19 seperate meshes if you check below option on the STL import dialog:

grafik

If it is unchecked, you’ll get a single mesh.

Well, its not the best mesh, run the _Check command on it…

No, do not confuse Breps with Meshes. This topic is about something different.

_
c.

1 Like

Thanks :slight_smile: You’re right, without that checkmark, the imported STL is just a single mesh:

2023-05-06 02_57_37-STL Import Options

2023-05-06 02_55_56-

_Check command

Now, I’m going to try your suggested _Check command on my mesh before adding it to the Rhino document. Let’s see if the warning gets resolved by _Check command…

I tried the Check method of C# Mesh class and enabled all of its checks:

                        // Run the CheckValidity method on the mesh.
                        MeshCheckParameters parameters = new MeshCheckParameters();

                        // Enable all the checks:
                        parameters.CheckForBadNormals = true;
                        parameters.CheckForDegenerateFaces = true;
                        parameters.CheckForDisjointMeshes = true;
                        parameters.CheckForDuplicateFaces = true;
                        parameters.CheckForExtremelyShortEdges = true;
                        parameters.CheckForInvalidNgons = true;
                        parameters.CheckForNakedEdges = true;
                        parameters.CheckForNonManifoldEdges = true;
                        parameters.CheckForRandomFaceNormals = true;
                        parameters.CheckForSelfIntersection = true;
                        parameters.CheckForUnusedVertices = true;

                        // Create TextLog object
                        Rhino.FileIO.TextLog log = new Rhino.FileIO.TextLog("log--mesh-checks--hollowing.txt");

                        bool isValid = meshOut.Check(log, ref parameters);

                        RhinoApp.WriteLine("Is output mesh valid? {0}", isValid);

Surprisingly, this is the prompt message:

2023-05-06 04_20_42-

And this is the content of the mesh check log file:

2023-05-06 04_27_54-Nano3D-log--mesh-checks--hollowing.txt - Notepad

Implication

The bool isValid = meshOut.Check(log, ref parameters); statement returns true. It means there is nothing critical wrong with the output mesh. But the same warning is thrown:

Warning: New mesh is not valid.
ON_Mesh.m_F[9203].vi has invalid vertex indices.

And after the output mesh is added to the Rhino document, as soon as I zoom in or out, the mesh disappears.

I’m confused and I don’t know why.

Maybe a reasonable thing to do is to implement a custom logic for detecting the issue with the vertex indices. I mean a method that is designed to check for this specific type of issue. A separate validation mechanism that is able to detect the issue with the vertex indices.

I’m going to try…

I added this separate validation mechanism that is able to detect the issue with the vertex indices:

        public static bool HasInvalidVertexIndices(Mesh mesh)
        {
            // Check each face in the mesh
            for (int i = 0; i < mesh.Faces.Count; i++)
            {
                MeshFace face = mesh.Faces[i];

                // Check each vertex index in the face
                if (face.A < 0 || face.A >= mesh.Vertices.Count ||
                    face.B < 0 || face.B >= mesh.Vertices.Count ||
                    face.C < 0 || face.C >= mesh.Vertices.Count)
                {
                    // If any vertex index is invalid, return true
                    return true;
                }
            }

            // If all face vertex indices are valid, return false
            return false;
        }

I’m calling the new method like this:

bool hasInvalidVertexIndices = MeshHelper.HasInvalidVertexIndices(meshOut);

RhinoApp.WriteLine("Does output mesh have invalid vertex indices? {0}", hasInvalidVertexIndices);

Surprisingly, my code prints this message on the prompt:

2023-05-06 06_24_21-

So, what is wrong with the mesh? It’s confusing :confused:

Hi @Megidd, print out F[9203] and see if it references 3 unique vertex indices which you have in your mesh vertex list.

Btw. Check just give you the log of errors, it does not repair anything. You’ll need to do this on your own using eg. CullDegenerateFaces, RemoveZeroAreaFaces and get rid of non manifold edges. The display problem you see after adding the mesh to the doc is related to the errors in the mesh. Either try to avoid generating a bad mesh or repair it.

_
c.

1 Like

Btw, most of the errors are already present in the input mesh:

Mesh has 21 pairs of faces that intersect each other.
This can cause problems if you’re doing mesh boolean operations with it.

Mesh has 6 faces where the face normal differs substantially from the vertex normals.
These normals can cause problems if the ultimate goal is for rendering or boolean purposes.

The intersecting 21 pairs of faces intersecting each other can be found using MeshFaceList.GetClashingFacePairs Method.

The problematic face you get printed out for the offsetted part seems to be this one, it is located at the bottom of the inside shell:

There are also a bunch of floating vertices not creating any face directly below it. Maybe using MeshVertexList.CullUnused method gets rid of this mess. Don’t be confused by the
face numbers, i’ve splitted the whole mesh into disjoint pieces so the numers are different.

1 Like

Right @clement :+1:

I printed the vertices for the face with 9203 index. Looks like there are 3 different indices but 3 vertices have the same coordinate:

2023-05-06 06_56_51-

Is there is any available Rhino tool to automatically fix it? Just curious :roll_eyes:

The input mesh is this one: https://upload.wikimedia.org/wikipedia/commons/9/93/Utah_teapot_(solid).stl

Hi @Megidd,

this creates a zero area mesh face which you should be able to get rid of using MeshFaceList.GetZeroAreaFaces.

Yes, there are multiple built in commands which you can run, but they potentially can create a bigger mess if not used with caution:

MeshRepair
ExtractNonManifoldMeshEdges
CullDegenerateMeshFaces
CollapseMeshFacesByEdgeLength
CollapseMeshFacesByArea
ExtractDuplicateMeshFaces
...

_
c.

1 Like

I implemented this method to remove triangles with zero area:

        public static int[] RemoveZeroAreaTriangles(int[] indexBuffer, float[] vertexBuffer)
        {
            // Remove the zero-area triangles from the index buffer
            List<int> newIndexBuffer = new List<int>();
            for (int i = 0; i < indexBuffer.Length; i += 3)
            {
                // Get the vertex positions for the three vertices of the triangle
                int indexA = indexBuffer[i];
                int indexB = indexBuffer[i + 1];
                int indexC = indexBuffer[i + 2];
                Vector3d vertexA = new Vector3d(vertexBuffer[indexA * 3], vertexBuffer[indexA * 3 + 1], vertexBuffer[indexA * 3 + 2]);
                Vector3d vertexB = new Vector3d(vertexBuffer[indexB * 3], vertexBuffer[indexB * 3 + 1], vertexBuffer[indexB * 3 + 2]);
                Vector3d vertexC = new Vector3d(vertexBuffer[indexC * 3], vertexBuffer[indexC * 3 + 1], vertexBuffer[indexC * 3 + 2]);

                // Compute the cross product of two edges of the triangle
                Vector3d edge1 = vertexB - vertexA;
                Vector3d edge2 = vertexC - vertexA;
                Vector3d crossProduct = Vector3d.CrossProduct(edge1, edge2);

                // Check if the cross product has zero length
                if (crossProduct.Length < RhinoMath.ZeroTolerance)
                {
                    // If the cross product has zero length, skip this triangle
                    continue;
                }

                // Add the indices of the non-zero-area triangle to the new index buffer
                newIndexBuffer.Add(indexA);
                newIndexBuffer.Add(indexB);
                newIndexBuffer.Add(indexC);
            }

            // Convert the new index buffer to an array and return it
            return newIndexBuffer.ToArray();
        }

Now, the output mesh is added to the scene just fine:

2023-05-06 07_38_07-

Showing the cross section by ClippingPlane command:

2023-05-06 07_38_36-

1 Like