Meshing works through UI _Mesh, bad results from Mesh.CreateFromBrep

gen5.3dm (1.7 MB)

tl;dr: I can create a mesh that meets my requirements (closed, if not “good”) with _Mesh in the UI, but trying to do the same thing programmatically through RhinoCommon via Python gives an open mesh at best. A file is enclosed, and I think this will be an easy one to reproduce. I am blocked on forward progress because later steps require a closed mesh.

See attached file, which contains a single closed polysurface.

When running _Mesh from the UI, I get a well-formed, closed mesh as a result, regardless of the settings in the dialog – for example using “Smooth and slower” works fine… maybe not great, since _MeshRepair says:

Here is what is wrong with this mesh:
Mesh has 47 non manifold edges.
Skipping face direction check because of positive non manifold edge count.
Mesh has 139 pairs of faces that intersect each other.
This can cause problems if you’re doing mesh boolean operations with it.

Important things to consider with this mesh:
Mesh has 10 naked edges. Although this does not necessarily mean that the mesh is bad,
naked edges can cause problems if the ultimate goal is STL output.
Mesh has 94 faces where the face normal differs substantially from the vertex normals.
Although this does not necessarily mean that the mesh is bad,
these normals can cause problems if the ultimate goal is for rendering or boolean purposes.

(Side note – how can a mesh be closed when it has 10 naked edges?)

_What says:

Geometry:
Valid mesh.
Closed double precision polygon mesh: 35587 vertices, 39642 faces
Bounding box: (-335.143,-83.077,-32.741) to (335.143,373.007,159.890)

However, when I run Geometry.Mesh.CreateFromBrep() on this same object (that was created entirely programmatically; before adding it to the document), regardless of meshing parameters (for example Geometry.MeshingParameters.Smooth, which I know is deprecated but allows most direct comparison; I’ve tried many others with similar results), I always get a much worse result… and I always get a mesh that both the UI and _What agree is open. _MeshRepair says:

Here is what is wrong with this mesh:
Mesh has 506 extremely short edges.
Mesh has 3 non manifold edges.
Mesh has 3 duplicate faces.
Skipping face direction check because of positive non manifold edge count.
Mesh has 429 pairs of faces that intersect each other.
This can cause problems if you’re doing mesh boolean operations with it.

Important things to consider with this mesh:
Mesh has 46 naked edges. Although this does not necessarily mean that the mesh is bad,
naked edges can cause problems if the ultimate goal is STL output.
Mesh has 36 faces where the face normal differs substantially from the vertex normals.
Although this does not necessarily mean that the mesh is bad,
these normals can cause problems if the ultimate goal is for rendering or boolean purposes.

And _What says:

Geometry:
Valid mesh.
Open polygon mesh: 37501 vertices, 42463 faces with normals
Bounding box: (-335.143,-83.077,-32.741) to (335.143,373.007,159.890)
Quality meshing parameters.
Adaptive SubD meshing density = 256 mesh quads per SubD quad.

For clarity, my code calls Geometry.Mesh.CreateFromBrep(that_object, Geometry.MeshingParameters.Smooth), which returns 129 different meshes; which I then glue together into a new empty mesh created with Geo.Mesh() with Geometry.Append.Overloads[System.Collections.Generic.IEnumerable[Geo.Mesh]](). I’m well aware that there’s a good chance that this merging process is the source of the problem, but from what I can tell Append is the only documented standard way to join meshes…

It does stand out that the _Mesh mesh is identified as double precision… apologies for the digression, but since I just noticed this live while writing this post, I modified my MeshParameters to explicitly set .DoublePrecision = True, and _What reflects that (which does point to different settings between the UI “Smooth and slower” and the programmatic .Smooth), but _MeshRepair gets even worse:

Here is what is wrong with this mesh:
Mesh has 523 extremely short edges.
Mesh has 3 non manifold edges.
Mesh has 3 duplicate faces.
Skipping face direction check because of positive non manifold edge count.
Mesh has 95 pairs of faces that intersect each other.
This can cause problems if you’re doing mesh boolean operations with it.

Important things to consider with this mesh:
Mesh has 288 naked edges. Although this does not necessarily mean that the mesh is bad,
naked edges can cause problems if the ultimate goal is STL output.
Mesh has 32 faces where the face normal differs substantially from the vertex normals.
Although this does not necessarily mean that the mesh is bad,
these normals can cause problems if the ultimate goal is for rendering or boolean purposes.

Valid mesh.
Open double precision polygon mesh: 37502 vertices, 42477 faces with normals
  Bounding box: (-335.143,-83.077,-32.741) to (335.143,373.007,159.890)
  Quality meshing parameters.
  Adaptive SubD meshing density = 256 mesh quads per SubD quad.
  DoublePrecision = true

The next step would be to set .ClosedObjectPostProcess = True; but no matter what I do here, while creating the mesh creates the usual 129 pieces that all look good individually, the call to Geometry.Mesh.Append() to glue them all together always results in a mesh where .IsValid = False (which never happens without .ClosedObjectPostProcess = True).

And of course the fact that Rhino thinks that this mesh is open restricts follow-up operations.

I need to find a workaround for this to move forward. My mental model right now is that _Mesh performs the Geometry.Mesh.CreateFromBrep() operation, and then some additional cleanup / repair… if that’s true, I see two ways forward:

  1. Replicate the repair procedure programmatically, if anyone can shed light on what works.
  2. Invoke _Mesh programmatically… I’ve avoided hopping between the lovely RhinoCommon API and running commands that require objects to already be in docs so far, but might have to break down over this one.

Suggestions? Observations? Paths forward?

[Rhino for Mac Version 8 (8.19.25132.01002, 2025-05-12)]

Pass the results of Mesh.CreateFromBrep to this:

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.mesh/healnakededges

— Dale

That worked. Thanks for the incredibly quick response!

Any hints as to what I can do to create Breps that mesh better in the future?

For this model, I don’t have any suggestion.

The Mesh command uses the function, I linked to above, to clean up edges.

– Dale