Skip to main content

cq-acis

Parse ACIS SAT/SAB data and convert the supported analytic B-rep subset to CadQuery/OpenCascade shapes.

日本語版: README.ja.md

This project is experimental. ACIS SAT versions and producer-specific records vary, so unsupported entities are preserved as raw records and conversion fails explicitly when an exact shape cannot be built.

Features

  • SAT container detection and ASCII record framing
  • Legacy one-line and modern three-line SAT headers
  • Counted @<length> strings used by SAT 7 and later
  • SAB and Autodesk ShapeManager SAB parsing for explicitly admitted profiles
  • Entity-reference graph validation for $n pointers
  • Typed decoding for SAT save versions 105, 400, 600, and 700
  • Typed topology and analytic geometry entities: body, lump, shell, face, loop, coedge, edge, vertex, point, straight-curve, ellipse-curve, plane-surface, cone-surface, and transform
  • Exact CadQuery conversion for line, circular/elliptical edge, plane, cylindrical, and circular-conical geometry
  • Splitting of non-manifold ACIS shells into valid CadQuery solids and compounds
  • Preservation of unsupported records as RawEntity
  • Reusable Rust acis-core models, reference validation, and analytic helpers, with a PyO3 binding and the existing Python dataclass API

Elliptical cones, elliptical cylinders, sheared placements, and unsupported surface/curve types are rejected rather than approximated.

Installation

The CadQuery converter is installed with the default dependencies:

python -m pip install cq-acis

For a source checkout, install Rust (1.83 or newer) and a C linker first. The native extension is built by maturin:

python -m pip install -e .

Quick start

Parse SAT records and resolve topology references:

from cq_acis import BodyEntity, parse_sat_model

with open("model.sat", "rb") as source:
    model = parse_sat_model(source.read())

for body in model.bodies():
    assert isinstance(body, BodyEntity)
    lump = model.resolve(body.lump)
    print(body.index, lump.index if lump else None)

Convert the bodies to a CadQuery Workplane:

from cq_acis import import_sat_file

result = import_sat_file("model.sat")
shape = result.val()
assert shape.isValid()
print(shape.Volume())

Shared model for external decoders

cq_acis.model provides AcisModel, AcisMetadata, and the geometry/entity types independently of SAT framing. External decoders can construct AcisModel(metadata=..., entities=...) directly; a SatHeader, SatEntityGraph, or text SatRecord is not required. The same to_cadquery() and new convert_model() functions accept both this model and the existing SatModel.

For existing SAT callers:

from pathlib import Path
from cq_acis import convert_model, parse_sat_model

sat_model = parse_sat_model(Path("model.sat").read_bytes())
model = sat_model.as_acis_model()
shapes = convert_model(model)

assert model.metadata == sat_model.metadata
assert model.entities is sat_model.entities
# Existing access to sat_model.graph and raw.record still works.

Adapter contracts:

  • Use contiguous, zero-based model indices for EntityRef; -1 is null. Keep source record IDs in RawEntity.entity_id. Construction validates indices and reference closure, not geometry or source-format compatibility.
  • Put length units and tolerances in AcisMetadata: units_mm is millimetres per source unit, resabs uses source length units, and resnor is dimensionless. Missing source values remain None. For compatibility, the converter still defaults missing units to 1 mm and missing absolute tolerance to 1e-6 source units; external decoders should supply known values explicitly.
  • Preserve source encoding, save version, producer and dialect in metadata. The application year and kernel save version are separate values.
  • A RawEntity can omit record and instead retain binary raw_data and a SourceSpan(source_id, start_offset, end_offset). Spans are half-open byte ranges in the named domain, including decompressed streams where applicable.
  • Keep unknown entities as RawEntity and adapter reports in AcisModel.diagnostics (AcisDiagnostic). Unsupported geometry referenced by a converted body raises CadQueryConversionError; an undecoded raw body is also rejected. Other retained records and diagnostics are not proof of complete conversion and should be inspected by callers.

All existing public entity imports and the SatModel(graph, entities) constructor remain available. SAT framing and schema decoding are still Python; SAB/ASM binary decoding now runs in Rust; Inventor CFB/RSe extraction is implemented in the separate inventor-kit project. See binary support.

Rust core and Python boundary

crates/acis-core owns all 14 typed entity variants, raw values, metadata, diagnostics, reference validation/resolution, vector math, ellipse/cone evaluation, and transform calculations. It can be a direct Cargo dependency of an Inventor decoder without Python or CadQuery. See its README for a local dependency example.

crates/cq-acis-py provides the PyO3 boundary. The Python dataclasses preserve constructors, imports, equality, dataclasses.replace, and the identity of existing model entities. Their math and AcisModel validation/resolution call Rust. No Python fallback silently substitutes for a missing extension; build/install it before running from source.

For a model owned entirely by Rust:

native = model.to_native()  # Immutable snapshot; no SAT serialization/reparsing.
assert native.to_model() == model
shapes = convert_model(native)

NativeModel implements the converter's model interface. Its properties and to_model() create Python dataclasses with equal values, without retaining Python entity objects or their identities. The CadQuery adapter materializes this Python view once per converter, avoiding repeated field copies during topology traversal. Conversion copies fields directly, including bytes and arbitrary-precision source integers; it does not use JSON. Model references fit signed 64-bit indices, with -1 for null, while offsets and lengths fit the native address range. Invalid source spans and dangling diagnostic targets are also rejected. Unknown entity classes/values must be represented by RawEntity/bytes instead of being silently dropped.

The maturin build creates a mixed Python/Rust wheel with the CPython stable ABI for Python 3.10+. Wheel installation does not need Rust; source installation does. CadQuery's own platform/Python requirements still apply. An abi3 tag alone does not demonstrate testing on every Python version or operating system.

Example and visual inspection

examples/parse_sat.py parses a SAT file, prints body statistics, and exports STEP, STL, and SVG files.

PYTHONPATH=src python examples/parse_sat.py
PYTHONPATH=src python examples/parse_sat.py path/to/model.sat \
  --output-dir /tmp/cq-acis-output

Open the generated STL or STEP in any 3D CAD viewer. With the optional ocp_vscode viewer installed, try:

PYTHONPATH=src python examples/parse_sat.py --show

Supported entities and conversion scope

The parser currently has typed support for:

body, lump, shell, face, loop, coedge, edge, vertex,
point, straight-curve, ellipse-curve,
plane-surface, cone-surface, transform

Typed support does not imply that every entity can already be converted to a CadQuery shape. Conversion is exact-only and raises CadQueryConversionError for unsupported geometry.

Development corpus

The pinned development corpus is not included in the Python wheel. It is kept in this repository for parser and conversion regression tests. Sources, upstream commits, and SHA-1 values are recorded in corpus/sources.lock.json; downloaded file hashes and SAT metadata are recorded in corpus/manifest.jsonl.

python scripts/fetch_corpus.py
python scripts/fetch_corpus.py --check

Review corpus/README.md and corpus/licenses/ before redistributing third-party files.

Testing

Run the full test suite from a source checkout, with its virtual environment active:

python -m pip install maturin
maturin develop
cargo test -p acis-core --locked
PYTHONPATH=src python -m unittest discover -s tests -v

The pinned corpus currently covers 25 artifacts, including 23 SAT files and 2 SAB files. CadQuery regression tests convert 23 SAT artifacts and 147 bodies. Native tests round-trip all 62,530 entities through Rust and cover SAT-free geometry, source bytes/integers, model validation, and Python API compatibility.

Project status

The package is under active development. The public API and supported SAT subset may change while broader producer/version coverage is added.

License

The project code is licensed under the MIT License. Third-party corpus files have separate notices under corpus/licenses/; consult those notices before redistribution.

SAB / ASM (stage 3)

parse_sab_model(data, source_id="model.sab") decodes the admitted binary profiles directly through Rust. See bounded support and history limitations.

Python release CI

Publishing a GitHub Release tagged v<pyproject version> builds and validates Linux, Windows, macOS ARM64/Intel ABI3 wheels and an sdist, then publishes to PyPI with Trusted Publishing. Manual workflow runs build and verify without uploading. See release setup, versioning, and retry instructions.

Metadata

Release files for cq-acis 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cq-acis 0.2.0
File Size Uploaded
cq_acis-0.2.0.tar.gz 57.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cq-acis 0.2.0
File
cq_acis-0.2.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
cq_acis-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
cq_acis-0.2.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
cq_acis-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 1.5 MB

Release files / cq_acis-0.2.0.tar.gz

Download URL cq_acis-0.2.0.tar.gz
Size 57.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f24f5d8b0e4176fbb91a37b3a720a03506acbe43c7fe8ce7ebb97477bbb56f9b
BLAKE2b-256 checksum
How to use checksums
f04fede425b82f730242923f7babecfb9051cc08bccdc87bdf272aa3c4f58f56
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / cq_acis-0.2.0-cp310-abi3-win_amd64.whl

Download URL cq_acis-0.2.0-cp310-abi3-win_amd64.whl
Size 276.0 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
1703f95ff05eecb7b1aa34d7ec5822ec597d375ed82b39c25d87c0c25e309b77
BLAKE2b-256 checksum
How to use checksums
b2c45a743675aa9735be83603a0e8f29ba636e573e2d547ebab8ff5f07d05ba9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / cq_acis-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL cq_acis-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 423.6 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
19de905be081a246c6a44b7c369387b2ddf6127698e2f4989073006254fed007
BLAKE2b-256 checksum
How to use checksums
e50f307b5e63c6a30ac587b2d0ffcfc093c619b12085833976ca1ba8e2f6c647
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / cq_acis-0.2.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL cq_acis-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
Size 383.8 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
a1f15d51137937e6c8e45306297349802a5a9144e3bbbe8c7a8b1e20dea85061
BLAKE2b-256 checksum
How to use checksums
4817a3575a9966a84cad9b7544cca3c68fa3c0c683764d59e65772352b1673f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / cq_acis-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL cq_acis-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 380.5 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
b0bb44e701af39d77dced671e9e2670d9862198650bc70d35d375ebc09824914
BLAKE2b-256 checksum
How to use checksums
58bbdb849d440cb35a8df227a7d024b13ca52761a2dd77253fb66bd8ed99c72d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.12

6 release files

0.3.11

6 release files

0.3.10

5 release files

0.3.9

5 release files

0.3.8

5 release files

0.3.7

5 release files

0.3.6

5 release files

0.3.5

5 release files

0.3.4

5 release files

0.3.3

5 release files

0.3.2

5 release files

This release

0.2.0 This release

5 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page