Retrieve mesh settings entered in the "-_Mesh" GUI

Hello everyone,

A part of the plug-in I am developing uses successive meshing steps for several surfaces, and for user-friendliness, I show up the Mesh interface to the user (the Preview option is just perfect), using rs.Command("-_Mesh _DetailedOptions ").
mesh_interface

However, I would like to retrieve the user-defined parameters entered in this menu for later use of the tolerances, but it does not seem possible in Rhino Python… This is strange, knowing that between two executions of the Mesh interface, the GUI remembers the values, so they should be accessible somehow. Any idea?

FYI, I know that starting v6 we can access the mesh parameters of the document (RenderMeshMaxDistEdgeToSurf), but this is not what I’m looking for, unless of course there is a way to automatically apply the user-defined parameters entered in the Mesh GUI into the Mesh Document Properties…

Best regards,
Nathan

Hi @Nathan_Clero,

You can mesh object and show Rhino’s mesh UI using one of the RhinoObject.MeshObjects overrides.

– Dale

Hi @dale,

Thanks for your answer!
I’ve been trying to implement what you suggested but I’m struggling with RhinoCommon (I’m used to Python only, my bad). As far as I understand, this one RhinoObject.MeshObjects Method would allow me to pass a Rhino.Geometry.MeshingParameters object, that will then be updated with user parameters. Am I correct?

While implementing it, I’m struggling with passing the RhinoObject iterable as input.
So I’m here:

  1. Initializing a MeshingParameters class
mpo = Rhino.Geometry.MeshingParameters()
print mpo
print mpo.Tolerance
print mpo.ComputeCurvature
print mpo.MaximumEdgeLength
print mpo.MinimumEdgeLength
print mpo.MinimumTolerance
  1. Modify on of the parameters
mpo.Tolerance = 0.0015
print mpo.Tolerance
  1. Run the MeshObjects method
meshes = []
attributes = []

iter = [HERE I DO NOT KNOW]

mpo_mod = Rhino.DocObjects.MeshObject.MeshObjects(iter, mpo, False, meshes, attributes)
print mpo_mod

I don’t manage to set this iter variable in my Python environment… I have tried several things (setting a IEnumerable object, using rs.coercerhinoobject, …) using documentation links but still can’t figure it out… Sorry to ask but do you have any idea?

Best regards,
Nathan

Hi @Nathan_Clero,

I guess I was thinking of something like this.

import System
import Rhino
import scriptcontext as sc

def test_mesh_objects():
    # Select some objects to mesh
    filter = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter
    rc, objrefs = Rhino.Input.RhinoGet.GetMultipleObjects("Select surface and polysurfaces to mesh", False, filter)
    if rc != Rhino.Commands.Result.Success: return
    
    # Build a list of objects to mesh
    in_objects = []
    for objref in objrefs:
        in_objects.append(objref.Object())
    
    # See if we have any saved meshing parmeters
    # If not, just use the factory defaults
    mp = Rhino.Geometry.MeshingParameters.Default
    if sc.sticky.has_key('test_mesh_objects'):
        mp = sc.sticky['test_mesh_objects']
    
    # Prompt the user to twesk the meshing parameters
    ui_style = 1 # detail
    rc, mp, ui_style, = Rhino.Input.RhinoGet.GetMeshParameters(sc.doc, mp, ui_style)
    if rc != Rhino.Commands.Result.Success: return
    
    # Mesh the objects and add the meshes to the document
    rc, meshes, attributes = Rhino.DocObjects.RhinoObject.MeshObjects(in_objects, mp)
    if rc == Rhino.Commands.Result.Success:
        for i in range(0, len(meshes)):
            id = sc.doc.Objects.AddMesh(meshes[i], attributes[i])
            if id != System.Guid.Empty:
                sc.doc.Objects.Select(id, True, True, True)
                
    # Save our meshing parmeters for use later
    sc.sticky['test_mesh_objects'] = mp
    
if __name__ == "__main__":
    test_mesh_objects()

– Dale

Hi @dale,

Thanks a lot! Very helpful, I think I was missing objref.Object() for the ObjRef to RhinoObject translation, thanks I will use that whenever the user handpicks the surface, and rs.coercerhinoobject when the surfaces are programatically selected by GUIDs.

One small remark is that Rhino.Input.RhinoGet.GetMeshParameters is Rhino 7 only. For Rhino 5/6 compatiblity I am using the “second method” of Rhino.DocObjects.RhinoObject.MeshObjects (described HERE) to be able to access simpleDialog set to False (to have the GUI appearing).

Best regards,
Nathan

Hi @dale

Now I’m facing an issue that rs.Command("-_Mesh _DetailedOptions ") and Rhino.DocObjects.RhinoObject.MeshObjects(in_objects, mp, False) don’t behave the same …

  • rs.Command("-_Mesh _DetailedOptions ") creates all meshes successfully
  • Rhino.DocObjects.RhinoObject.MeshObjects(in_objects, mp, False) generates some Empty GUID
    Any idea what could be the difference between the 2?

Piece of code:

# rs.Command("_Mesh ", echo=self.DEBUG)
rc, mp, ui_style, meshes, attributes = Rhino.DocObjects.RhinoObject.MeshObjects(in_objects, mp, False)
if rc == Rhino.Commands.Result.Success:
    for i in range(0, len(meshes)):
        id = sc.doc.Objects.AddMesh(meshes[i], attributes[i])
        if id != System.Guid.Empty:
            sc.doc.Objects.Select(id, True, True, True)
            out_mesh.append(id)

In addition, I have no way to know which surfaces have failed to produce a mesh, so I cannot fix them by applying rs.Command("-_Mesh _DetailedOptions "). Unless you know how?

Best regards,
Nathan

Edit: I attach a test file, the group of surfaces belonging to each layer can reproduce the issue.
test_meshing.py (2.2 KB)
test_geom.3dm (887.1 KB)

Hi @Nathan_Clero,

Set test_method = 0 then run your script. Then run SelMesh - you’ll should see that 86 meshes were selected, which is the same number of surface. Now, unselect everything and run SelBadObjects - you’ll see 7 meshes were selected. These are the 7 meshes that were not added to the document when your script called RhinoObject.MeshObjects.

Now you get to figure out why your surfaces are generating invalid meshes.

– Dale

Hi @dale,

Oooooh I see… So the mesh generated from a seemingly healthy surface (not so healthy in the end) results in a bad mesh, which is NOT added to the document if generated with RhinoObject.MeshObjects, but added if generated with rs.Command("_Mesh ").

I need to wrap my head around this to find the best solution, but a few thinking out loud:

  • the "_Mesh " command is definitely super powerful as it manages to create the meshes anyway (not sure if they can be used correctly later by our tool through the STL format) …
  • … but using it I cannot retrieve the meshing parameters entered by the user
  • there is no way to detect in advance that those surfaces will produce bad meshes as they are not detected as bad objects themselves, and they can produce a seemingly healthy polysurface when joined together…

Thanks again a lot for the help Dale!

Best regards,
Nathan

Hi @Nathan_Clero,

One the one bad mesh I looked at, the What command complains about the normal - that surface has two neighboring edges that are tangent - U and V parallel/colinear. Looks like rebuilding the normals fixes this, in your case.

import Rhino
import scriptcontext as sc

def __custom_meshing_parameters():
    mp = Rhino.Geometry.MeshingParameters.Default
    mp.Tolerance = 0.005  # Max distance edge to surface
    mp.RelativeTolerance = 0.5  # Density
    mp.GridAspectRatio = 4  # Aspect ratio
    mp.MaximumEdgeLength = 0.0
    mp.MinimumEdgeLength = 0.005
    mp.RefineAngle = 0.0  #Angle (rad)
    mp.GridMinCount = 100  #Minimum number of initial quads
    return mp

def test_mesh_objects():
    filter = Rhino.DocObjects.ObjectType.Surface | Rhino.DocObjects.ObjectType.PolysrfFilter
    rc, objrefs = Rhino.Input.RhinoGet.GetMultipleObjects("Select surface and polysurfaces to mesh", False, filter)
    if rc != Rhino.Commands.Result.Success:
        return
    
    in_objects = []
    for objref in objrefs:
        in_objects.append(objref.Object())
    
    mp = __custom_meshing_parameters()
    rc, mp, ui_style, meshes, attributes = Rhino.DocObjects.RhinoObject.MeshObjects(in_objects, mp, False)
    if rc == Rhino.Commands.Result.Success:
        for i in range(0, len(meshes)):
            mesh = meshes[i]
            if not mesh.IsValid:
                mesh.RebuildNormals()
            if not mesh.IsValid:
                continue
            sc.doc.Objects.AddMesh(mesh, attributes[i])
    
    sc.doc.Views.Redraw()
    
if __name__ == "__main__":
    test_mesh_objects()

– Dale