Reading 3D Solids with ezdxf Python: Extract ACIS Payloads from DXF Files

To read 3D solids with ezdxf in Python, query 3DSOLID entities from the DXF modelspace and access their embedded ACIS/SAT payload via the .acis property. ezdxf does not reconstruct B-Rep topology, generate meshes, or convert parametric geometry to standard triangle formats — it exposes the raw ACIS string exactly as stored in the DXF file. For production AEC/GIS pipelines, pair this extraction with a dedicated ACIS parser or geometry kernel (python-occ, OpenCASCADE, or cadquery) to convert the payload into usable vertices, faces, or STEP/IGES outputs. For broader entity traversal and memory-efficient DXF processing, see the ezdxf Deep Dive.

How ezdxf Handles 3D Solids in DXF Files

AutoCAD stores parametric 3D geometry as 3DSOLID entities. Unlike basic 3DFACE or MESH objects, 3DSOLID entities encapsulate a complete Boundary Representation (B-Rep) inside a proprietary ACIS/SAT text blob. When you parse a DXF file, ezdxf reads this blob directly from DXF group codes 1 and 3, making it accessible through the .acis property as a list of strings — one string per ACIS line.

The diagram below shows where 3DSOLID fits in a DXF entity pipeline and why ACIS payloads must be routed separately from faceted geometry.

3DSOLID Entity Routing in a DXF Parsing Pipeline Diagram showing DXF modelspace entities split into two routes: 3DFACE and MESH flow directly to polygonal mesh output, while 3DSOLID entities are validated for ACIS headers then routed to a geometry kernel (OpenCASCADE / python-occ) for B-Rep to mesh conversion. DXF Modelspace msp.query() Entity type? 3DFACE / MESH Polygonal Mesh Output 3DSOLID Validate ACIS header encrypted/empty Log & flag for ACIS SDK Geometry Kernel (OCC)

In automated interoperability workflows, treating 3DSOLID as a raw payload — rather than a ready-to-render mesh — prevents topology corruption. DXF files frequently mix faceted approximations (MESH, 3DFACE) with true parametric solids. Routing ACIS payloads to a downstream conversion service preserves precision and avoids silent data loss that occurs when forcing solids into polygonal formats prematurely.

This distinction also matters for Geometry & Mesh Conversion workflows: attempting to pass an unprocessed 3DSOLID entity directly into trimesh or a GeoJSON serializer will silently drop the geometry.

Production-Ready Script

The following script safely extracts ACIS payloads from all 3DSOLID entities in a DXF file, handles multi-line ACIS data, validates the payload header, and writes structured JSON for downstream processing.

# ezdxf>=1.1.0, Python 3.9+
import ezdxf
import json
import sys
from pathlib import Path
from typing import List, Dict, Any

def extract_3dsolid_acis(dxf_path: str, output_json: str) -> None:
    """Extract ACIS/SAT payloads from 3DSOLID entities in a DXF file."""
    try:
        doc = ezdxf.readfile(dxf_path)
        msp = doc.modelspace()
    except ezdxf.DXFError as e:
        sys.exit(f"Failed to load DXF: {e}")

    # The correct DXF entity type string is "3DSOLID" — not "SOLID3D"
    solids = msp.query("3DSOLID")
    if not solids:
        print("No 3DSOLID entities found in modelspace.")
        return

    extracted: List[Dict[str, Any]] = []
    for solid in solids:
        # .acis returns list[str] — one entry per SAT line
        acis_lines: List[str] = solid.acis
        if not acis_lines:
            # Likely encrypted; log the handle for licensed ACIS SDK processing
            print(f"Warning: Handle {solid.dxf.handle} has empty ACIS payload (possibly encrypted).")
            continue

        acis_str = "\n".join(acis_lines)

        # Validate ACIS header: first line must start with "ACIS" or "ASM"
        first_line = acis_lines[0].strip()
        if not (first_line.startswith("ACIS") or first_line.startswith("ASM")):
            print(f"Warning: Handle {solid.dxf.handle} has unrecognized ACIS header: {first_line!r}")
            continue

        extracted.append({
            "entity_handle": solid.dxf.handle,
            "layer": solid.dxf.layer,
            "acis_version": first_line,
            "line_count": len(acis_lines),
            "payload_length_bytes": len(acis_str.encode("utf-8")),
            "raw_acis": acis_str,
        })

    Path(output_json).write_text(json.dumps(extracted, indent=2), encoding="utf-8")
    print(f"Extracted {len(extracted)} 3DSOLID payloads → {output_json}")

if __name__ == "__main__":
    extract_3dsolid_acis("input.dxf", "solids_acis.json")

Key implementation notes:

  • msp.query("3DSOLID") uses the correct DXF type string. The variant SOLID3D does not exist in the DXF specification and will return no results silently.
  • solid.acis returns list[str], one entry per SAT line. Do not attempt solid.dxf.acis_data — that attribute does not exist on the dxf namespace object and will raise DXFAttributeError.
  • Some AutoCAD 2021+ versions store ACIS data as an encrypted binary blob. These payloads will appear as an empty list and must be handled separately (see fallback strategies below).
  • Separating metadata (entity_handle, layer, acis_version) from the raw payload in the output JSON lets downstream batch routers filter and dispatch without loading full ACIS strings unnecessarily.
  • The DXFError guard around ezdxf.readfile() catches malformed headers and version mismatches before any entity iteration begins — especially important when processing bulk DXF exports from DXF entity structure breakdown pipelines.

Compatibility Matrix

Component Supported Range Notes
ezdxf version >=1.0.0 Earlier versions may handle ACIS line joining differently; >=1.1.0 recommended.
Python 3.9+ Uses typing, pathlib, and walrus-free list comprehensions.
DXF format R2000 (AC1015) — R2018 (AC1032) 3DSOLID stabilized in R2000. Newer versions may encrypt ACIS.
ACIS/SAT format v1.0v7.x Proprietary Spatial format. Full parsing requires OpenCASCADE, python-occ, or a licensed ACIS SDK.
OS Cross-platform ACIS parsing binaries from OpenCASCADE often require platform-native builds.
Encrypted payloads AutoCAD 2021+ solid.acis returns []; requires Spatial ACIS SDK or AutoCAD batch export as STEP before processing.
Custom entity types Civil 3D, Plant 3D May use subclass extensions that lack standard ACIS headers; validate before routing.

For the official entity specification, see the Autodesk DXF Reference for 3DSOLID. For geometry kernel integration, consult the OpenCASCADE documentation.

Fallback Strategies When ACIS Extraction Fails

ACIS payloads fail in automated pipelines for three main reasons: encryption (AutoCAD 2021+), ACIS version mismatches, or proprietary subclass extensions from vertical products. Implement these fallbacks in priority order to maintain pipeline continuity.

1. Pre-process to mesh before DXF export

Run a batch AutoLISP or .NET script inside AutoCAD or Civil 3D to convert 3DSOLID entities to MESH entities before the DXF is written. ezdxf then resolves faceted geometry via MESH or 3DFACE queries, bypassing ACIS entirely. This is the most reliable fallback for pipelines where you control the export step.

2. Export as STEP or IGES from the source application

Convert solids to *.step or *.iges using AutoCAD’s export dialog or a command-line batch script. STEP preserves full B-Rep topology and is natively importable by python-occ (pythonOCC) and cadquery. This is the recommended path when parametric accuracy must be preserved for spatial analysis or BIM-to-GIS coordinate transformation — for example, before running CAD local coordinate to EPSG:4326 conversion.

# python-occ STEP import example (pythonOCC>=7.7.0)
from OCC.Core.STEPControl import STEPControl_Reader
from OCC.Core.IFSelect import IFSelect_RetDone

reader = STEPControl_Reader()
status = reader.ReadFile("model.step")
if status == IFSelect_RetDone:
    reader.TransferRoots()
    shape = reader.OneShape()

3. Use trimesh for polygonal approximations

If the DXF contains embedded mesh approximations alongside the solids, extract facets from MESH and 3DFACE entities and pass them to trimesh for lightweight analysis. This bypasses B-Rep reconstruction but sacrifices parametric precision — acceptable for visual validation or GIS footprint extraction but not for engineering tolerances.

4. Handle encrypted payloads explicitly

When solid.acis returns [] or the first line does not start with ACIS/ASM, log the entity handle and skip conversion. Batch-log affected files for manual review or for routing to a licensed Spatial ACIS SDK. Never let a silent empty-list result pass through as valid geometry — this is a common source of corrupt spatial indexes downstream.

5. Validate ACIS headers in CI gates

Add a pre-processing assertion that counts entities where solid.acis is non-empty versus total 3DSOLID count. If more than 20% of solids have empty payloads, fail the pipeline early and raise an alert rather than silently producing an incomplete geometry dataset. This is particularly important in batch DXF processing pipelines that feed into GIS ingestion or BIM coordination workflows.

Does ezdxf reconstruct B-Rep topology from 3DSOLID entities?

No. ezdxf exposes only the raw ACIS/SAT text blob stored in DXF group codes 1 and 3. It does not parse ACIS geometry, generate triangle meshes, or rebuild B-Rep topology. A separate geometry kernel — such as OpenCASCADE via python-occ — is required for any mesh reconstruction or solid analysis.

Why does solid.acis return an empty list?

AutoCAD 2021 and later versions can store ACIS data as an encrypted binary blob when the drawing contains licensed geometry or DRM-protected content. When encryption is applied, ezdxf cannot decode the payload and .acis returns []. Log the entity handle and route the file to a licensed Spatial ACIS SDK or export as STEP from within AutoCAD.

What is the difference between 3DSOLID and MESH in DXF?

3DSOLID stores a parametric Boundary Representation encoded as an ACIS/SAT string — it carries exact topology, curved surfaces, and feature history. MESH and 3DFACE store explicit polygonal facets: a list of vertices and face indices with no parametric information. ezdxf can extract vertex coordinates from MESH and 3DFACE directly; 3DSOLID requires ACIS parsing for full geometry access.

Can I convert a 3DSOLID ACIS payload to STEP without AutoCAD?

Yes. python-occ (pythonOCC) wraps OpenCASCADE and can import ACIS strings via BRepTools then export using STEPControl_Writer. cadquery provides a higher-level interface to the same OpenCASCADE backend. Both approaches preserve B-Rep topology and produce standards-conformant STEP files suitable for downstream GIS or structural analysis.