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, sphere-surface, torus-surface, and transform
  • Exact CadQuery conversion for line, circular/elliptical edge, plane, cylindrical (including elliptical), circular-conical and qualified sphere/torus 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

M4 adds an experimental explicit SAT 700 exactsur NURBS surface adapter. It also admits an experimental ASM 22700 / embedded 22601 direct explicit NURBS profile, proved cone-apex degeneracies, circular sphere holes, and elliptical-cone isosections. Other native spline profiles and non-similarity placements remain unsupported. Projected 2D trims are numerically checked against unchanged 3D curves at source precision. See M4 scope and validation. Partial tolerant topology and nested subtype views keep model API 2. The 0.3.3 extension for tolerant boundaries and finite UV trims documents its admitted profiles and remaining conversion limits. From 0.3.2, cq-acis, acis-core, and acis-py-bridge share the workspace version. Python builds bundle the matching core and bridge sources; downstream Rust consumers require those crates to be published to crates.io.

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 using the CPython 3.10 stable ABI. The package requires Python 3.11 or newer because it depends on CadQuery 2.8+. Wheel installation does not need Rust; source installation does. CadQuery's platform 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<workspace.package.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. The Python version is read from Cargo.toml through maturin's dynamic metadata. See release setup, versioning, and retry instructions.

Metadata

Release files for cq-acis 0.3.3

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.3.3
File Size Uploaded
cq_acis-0.3.3.tar.gz 95.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for cq-acis 0.3.3
File
cq_acis-0.3.3-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
cq_acis-0.3.3-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.3.3-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
cq_acis-0.3.3-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 2.0 MB

Release files / cq_acis-0.3.3.tar.gz

Download URL cq_acis-0.3.3.tar.gz
Size 95.6 kB
Tags Source
SHA-256 checksum
How to use checksums
62344a8731d3829931f2c8732475672fecb49af782d64d33778590af7ed20cbe
BLAKE2b-256 checksum
How to use checksums
00ebbf9ab0e73f04b24000d3505d0d9e36c78d2bd588893cb57ecbfa8d74226f
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 12, 2026.

Transparency log

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

Download URL cq_acis-0.3.3-cp310-abi3-win_amd64.whl
Size 402.2 kB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
5cf55c65c6198d6fdb7d111b105c888b3bcc8ef083261ea2c789f6370cbfe7b1
BLAKE2b-256 checksum
How to use checksums
61cd4c5b4dbce03467214d7247939c5763dc6aaa33bc23a319becd29d5a4d6d5
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 12, 2026.

Transparency log

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

Download URL cq_acis-0.3.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 548.9 kB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
0475c96b8f895dfd6cd57a3289d6fa427d2d81bfc1e8eaa4b3cd7ba817a04118
BLAKE2b-256 checksum
How to use checksums
2fd793726c5a68905e8787950c6b724834caccb270c5b372c61aff15a9709934
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 12, 2026.

Transparency log

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

Download URL cq_acis-0.3.3-cp310-abi3-macosx_11_0_arm64.whl
Size 500.8 kB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
f90bfbb4e758f9accfbefd1ee32ac46f6c07e1893058e9c073e1680cdce4c0e2
BLAKE2b-256 checksum
How to use checksums
769d868c74bef9486ed1e05e0ac75fa817d5612edf46d3385434667081954ae4
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 12, 2026.

Transparency log

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

Download URL cq_acis-0.3.3-cp310-abi3-macosx_10_12_x86_64.whl
Size 502.0 kB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
4a86eb41a215ec677f87cb00b9df0136562babc8f9ae192f847a1f2b49d07e09
BLAKE2b-256 checksum
How to use checksums
b053e7a07a496e3cf58498d959133c7086d4e058710dccd24211871bb7e8deff
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 12, 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

This release

0.3.3 This release

5 release files

0.3.2

5 release files

0.2.0

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