Hi @Ex_John,
You don’t need a document per object. Two options, depending on how much of Rhino you want in the loop.
1. One headless doc, ExportSelected per object
FileStl.Write is whole-document only (it forwards to RhinoDoc.Export), but RhinoDoc.ExportSelected takes the same options dictionary, so you can reuse a single document and just change the selection:
import os
import Rhino
opts = Rhino.FileIO.FileStlWriteOptions()
opts.BinaryFile = True
opts.ExportOpenObjects = True
opts.MeshingParameters = Rhino.Geometry.MeshingParameters.Default
stl_dict = opts.ToDictionary()
for obj in doc.Objects:
doc.Objects.UnselectAll()
doc.Objects.Select(obj.Id, True)
name = obj.Attributes.Name or str(obj.Id)
doc.ExportSelected(os.path.join(folder, name + ".stl"), stl_dict)
Passing a non-empty options dictionary is what suppresses all the export UI, so this is safe headless. Note that the STL exporter will mesh breps for you using MeshingParameters — you don’t have to pre-mesh, and you don’t have to re-apply attributes either, since STL carries no names, layers or materials. The filename is the only place a name survives.
2. Skip the document entirely
Since you already have meshes in memory, binary STL is trivial to write yourself, and this avoids the doc, the export plug-in and the selection round-trip:
import struct
def write_binary_stl(path, meshes):
tris = []
for m in meshes:
d = m.DuplicateMesh()
d.Faces.ConvertQuadsToTriangles()
d.FaceNormals.ComputeFaceNormals()
for i in range(d.Faces.Count):
f, n = d.Faces[i], d.FaceNormals[i]
tris.append((n, d.Vertices[f.A], d.Vertices[f.B], d.Vertices[f.C]))
with open(path, "wb") as fp:
fp.write(b"\0" * 80)
fp.write(struct.pack("<I", len(tris)))
for n, a, b, c in tris:
fp.write(struct.pack("<12fH", n.X, n.Y, n.Z,
a.X, a.Y, a.Z, b.X, b.Y, b.Z, c.X, c.Y, c.Z, 0))
Note: no unit conversion happens on write, so if your model isn’t in the units you expect, scale the geometry first.
– Dale