Mesh has degenerate double precision vertex locations

I’m creating a mesh in C# using Rhino8 sdk.

My code looks something like this:
mesh = new Mesh();
mesh.Vertices.AddVertices([Point3f]);
mesh.Faces.AddFaces([Face]);

Im getting the issue that:
Mesh was invalid: ON_Mesh.m_F[331] has degenerate double precision vertex locations.

How is this possible? I have not created any double precision vertices…

I also sometimes get: ON_Mesh.m_dV and m_V are not synchronized. But this does not make sense either. I’m not creating any double precision verts :frowning:

You really are, as this:

mesh.Vertices.AddVertices([Point3f]);

ends up calling ON_Mesh:SetVertex.

I don’t believe there is a way to create a mesh with only float vertices.

– Dale

Interesting. The API is misleading because Mesh.Vertices.ToList() returns a list of 32 bit vertices. and Mesh.Vertices[0] returns a Point3f. This makes it feel like vertices are point3f.

This makes it very confusing that adding a vertex adds a double precision vertex.

Also, after looking at the ON_Mesh header, it seems like floating precision is the “default” and if you add double precision, it creates the extra responsibility that the user ensures these two vertex arrays are synchronized. Also, needing to keep two different precision vertex buffers synchronized??? What kind of API is this.

Can we agree that this is a bit strange?

It makes for many foot guns. And I’m not sure how to make things work without, at the very least, wasteful compute.

Enough rant, any recommendations for dealing with these bugs?

Hi @Nick_Drian,

If you need double precision vertices, use Mesh.Point3dAt or Mesh.ToPoint3dArray.

ON_Mesh will automatically synchronizes single and double precision vertices if you use the interface - ON_Mesh::SetVertex. If you access the low-level arrays directly - ON_Mesh::m_V and ON_Mesh::m_dV - you’ll need to synchronize the arrays yourself using ON_Mesh::UpdateSinglePrecisionVertices or ON_Mesh::UpdateDoublePrecisionVertices.

RhinoCommon uses the ON_Mesh interface, so arrays should always be in-sync.

In the early days of Rhino, mesh vertices were floats. Rhino did not have many meshing tools and since meshes are just approximations, the potential loss of some precision wasn’t a big deal.

Also, modern display technologies, such as OpenGL, use single-precision vertices. So floats made sense.

As time went on, we added some more meshing tools to Rhino; thus the need for double-precision vertices. They were also needed to solve “far-from-origin” issues.

Rather than maintain two different meshes classes, we chose to support both vertex types in one class.

What are the bugs? Do you have code that I can use to repeat?

– Dale

Thanks for your thoughtful response.

Here is some code for you to replicate one of my issues. I’m trying to create a clean mesh of the following geometry.
MeshBug.3dm (18.6 MB)
“ON_Mesh.m_F[558536] has degenerate double precision vertex locations.”

Here is the code I’m using to mesh the brep:

foreach (var face in m_Brep.Faces) face.RebuildEdges(0.001, true, true);
MeshingParameters mp = MeshingParameters.QualityRenderMesh;
mp.GridAspectRatio = 6.0;
Mesh[] meshPieces = Mesh.CreateFromBrep(m_Brep, mp);
foreach (var meshPiece in meshPieces.Skip(1))
{
    meshPieces.First().Append(meshPiece);
}
Mesh mesh = meshPieces[0];
mesh.HealNakedEdges(0.1);
mesh.Weld(double.PositiveInfinity);
mesh.Faces.ConvertQuadsToTriangles();
if (!mesh.IsValidWithLog(out var log))
{
    RhinoApp.WriteLine(log);
}

I really wish there was a way to turn a Brep into a Mesh that just worked… feature request. Like if someone at Rhino who understands this stuff better than me would just create an optimize an easy to use Brep Mesher, that would be great. It is quite a pain point to have to chain together many obscure mesh functions to get a good Mesh.

If you know any code bases that have solved this problem of meshing breps, I would love to know about them.

[EDIT]:
It seems Heal naked edges is the issues. Here, without it I get a good mesh. The trouble is, with other breps, I need heal naked edges or I get holes. It kinda feels like there is no one solution that will just work on any brep. And that is the struggle I face.

Hi @Nick_Drian,

This is causing the degenerate point:

mp.GridAspectRatio = 6.0;

TestNick.cs (2.4 KB)

– Dale

Without that aspect ratio constraint, there are other problems.
This is what the small fillet looks like when I don’t constrain the aspect ratio. Fixing one problem always seems to create another.

Hi @Nick_Drian,

You might consider using RhinoObject.MeshObjects, rather than the lower-level Mesh.CreateFromBrep method.

– Dale