Methods to export an STL file using rhinoinside?

Using rhinoinside, I read .3dm file, obtain object’s geometry, cull meshes and breps, convert breps to meshes, and then, based on their names and IDs I’d gotten from their respective objects I fill Rhino.FileIO.File3dm() or Rhino.RhinoDoc.CreateHeadless(None) and re-assign these attributes.

Is there a way to export objects from memory or iterate through objects in generated Rhino.FileIO.File3dm() and export each .STL separately without creating a document for each of them? Because otherwise it seems a bit redundant…

Something like:
for What in meshIDs:
Rhino.FileIO.File3dm.Export(where, What, attributes)

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

Thank you, the first solution shall work for the current project of mine.

Nevertheless, the second solution is not less useful, and I’ll keep it in mind.