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 ").
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…
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:
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?
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()
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).
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)
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.
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…
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()