Code Library
Rhino & GrasshopperPythonRhino 6–8 · built-in Python (rhinoscriptsyntax)MIT licenseIntermediate

Export Rhino curves to DXF, one file per layer

CAM software that wants each operation as a separate import turns "export the drawing to DXF" into "export the drawing N times, once per operation, hiding everything else first." This script does that automatically: it groups every curve in the document by its current layer, then runs Rhino's own Export command once per layer, so a model with roughing/finishing/engraving on separate layers comes out as three clean DXF files instead of one that needs re-splitting downstream.

Before you run it

  • Rhino 6, 7, or 8 (script uses rhinoscriptsyntax plus the -Export command line)
  • Curves organized onto layers that already match your intended DXF split (one layer per operation, typically)
  • Run once interactively first and check the exact Export prompts your Rhino version shows — the script assumes the default prompt accepts a single Enter

The code

GitHub
"""Export every curve on each layer to its own DXF file - one file per
layer, useful for CAM software that wants each operation on a separate import.

Rhino 6/7: Tools > PythonScript > Edit, paste, run.
Rhino 8:   ScriptEditor.
"""

import os
import rhinoscriptsyntax as rs

OUT_FOLDER = "C:\\DXF\\"   # must end with a backslash


def main():
    if not os.path.isdir(OUT_FOLDER):
        print("Folder not found: {}".format(OUT_FOLDER))
        return

    curves = rs.ObjectsByType(4, select=False)  # 4 = curve objects
    if not curves:
        print("No curves in the document.")
        return

    by_layer = {}
    for obj in curves:
        layer = rs.ObjectLayer(obj)
        by_layer.setdefault(layer, []).append(obj)

    exported = 0
    for layer, ids in by_layer.items():
        rs.UnselectAllObjects()
        rs.SelectObjects(ids)

        safe_name = layer.replace("::", "_").replace(" ", "_")
        path = os.path.join(OUT_FOLDER, "{}.dxf".format(safe_name))

        rs.Command('_-Export "{}" _Enter'.format(path), False)
        exported += 1
        print("{}: {} curve(s) -> {}".format(layer, len(ids), path))

    rs.UnselectAllObjects()
    print("{} layer(s) exported to {}".format(exported, OUT_FOLDER))


main()

What you get

What you get

C:\DXF\
├── Roughing.dxf
├── Finishing.dxf
├── Engraving.dxf
└── ...

Roughing: 12 curve(s) -> C:\DXF\Roughing.dxf
Finishing: 8 curve(s) -> C:\DXF\Finishing.dxf
Engraving: 3 curve(s) -> C:\DXF\Engraving.dxf
3 layer(s) exported to C:\DXF\

How it works

  • rs.ObjectsByType(4, select=False) grabs every curve in the document by its object-type code (4 = curves) — no manual selection needed, unlike the curvature-finder script's rs.GetObject.
  • Grouping into a {layer: [ids]} dictionary first, then looping over the groups, is what turns "all curves" into "one DXF per layer" — the export step only ever sees one layer's curves selected at a time.
  • rs.Command('_-Export "..." _Enter', False) is the standard way to script a command that would otherwise open a dialog: the leading - suppresses the modal UI, and _Enter accepts the follow-up prompt's default.
  • Layer names are sanitized (:: and spaces replaced) before becoming filenames — Rhino allows characters in layer names, especially nested-layer separators, that most filesystems don't.

Gotchas & honest limits

  • Test the `-Export` prompt sequence interactively once before trusting this unattended — depending on your Rhino version and DXF export settings, there can be more than one follow-up prompt (units, ACAD version), and this script only sends one _Enter.
  • Curves on a locked or hidden layer are still returned by ObjectsByType but can't be selected or exported — a hidden layer will silently produce an empty or missing DXF for that layer.
  • Nested layers (Parent::Child) are flattened into one filename per full layer path, not one file per parent — usually what you want for a CAM-operation split, but check it matches your layer structure.
  • This exports curves only — surfaces, meshes, and annotations on the same layers are ignored, by design, since DXF/CAM handoff is almost always curve geometry.

Goes deeper

Want this adapted to your shop — or built into a real tool?

Samples are the free 80%. The last 20% is the part I do for a living.

Get in touch
Home
Blog
Tools
Code
Email
LinkedIn
Résumé