ACIS Tools

The ezdxf.acis sub-package provides some ACIS data management tools. The main goals of this tools are:

  1. load and parse simple and known ACIS data structures

  2. create and export simple and known ACIS data structures

It is NOT a goal to load and edit arbitrary existing ACIS structures.

Don’t even try it!

These tools cannot replace the official ACIS SDK due to the complexity of the data structures and the absence of an ACIS kernel. Without access to the full documentation it is very cumbersome to reverse-engineer entities and their properties, therefore the analysis of the ACIS data structures is limited to the use as embedded data in DXF and DWG files.

The ezdxf library does not provide an ACIS kernel and there are no plans for implementing one because this is far beyond my capabilities, but it is possible to extract geometries made up only by flat polygonal faces (polyhedron) from ACIS data. Exporting polyhedrons as ACIS data and loading this DXF file by Autodesk products or BricsCAD works for SAT data for DXF R2000-R2010 and for SAB data for DXF R2013-R2018.

Important

Always import from the public interface module ezdxf.acis.api, the internal package and module structure may change in the future and imports from other modules than api will break.

Functions

ezdxf.acis.api.load_dxf(entity: DXFEntity) list[Body]

Load the ACIS bodies from the given DXF entity. This is the recommended way to load ACIS data.

The DXF entity has to be an ACIS based entity and inherit from ezdxf.entities.Body. The entity has to be bound to a valid DXF document and the DXF version of the document has to be DXF R2000 or newer.

Raises:

Warning

Only a limited count of ACIS entities is supported, all unsupported entities are loaded as NONE_ENTITY and their data is lost. Exporting such NONE_ENTITIES will raise an ExportError exception.

To emphasize that again: It is not possible to load and re-export arbitrary ACIS data!

Example:

import ezdxf
from ezdxf.acis import api as acis

doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()

for e in msp.query("3DSOLID"):
    bodies = acis.load_dxf(e)
    ...
ezdxf.acis.api.export_dxf(entity: DXFEntity, bodies: Sequence[Body])

Store the ACIS bodies in the given DXF entity. This is the recommended way to set ACIS data of DXF entities.

The DXF entity has to be an ACIS based entity and inherit from ezdxf.entities.Body. The entity has to be bound to a valid DXF document and the DXF version of the document has to be DXF R2000 or newer.

Raises:

Example:

import ezdxf
from ezdxf.render import forms
from ezdxf.acis import api as acis

doc = ezdxf.new("R2000")
msp = doc.modelspace()

# create an ACIS body from a simple cube-mesh
body = acis.body_from_mesh(forms.cube())
solid3d = msp.add_3dsolid()
acis.export_dxf(solid3d, [body])
doc.saveas("cube.dxf")
ezdxf.acis.api.load(data: str | Sequence[str] | bytes | bytearray) list[Body]

Returns a list of Body entities from SAT or SAB data. Accepts SAT data as a single string or a sequence of strings and SAB data as bytes or bytearray.

ezdxf.acis.api.export_sat(bodies: Sequence[Body], version: int = const.DEFAULT_SAT_VERSION) list[str]

Export one or more Body entities as text based SAT data.

ACIS version 700 is sufficient for DXF versions R2000, R2004, R2007 and R2010, later DXF versions require SAB data.

Raises:
ezdxf.acis.api.export_sab(bodies: Sequence[Body], version: int = const.DEFAULT_SAB_VERSION) bytes

Export one or more Body entities as binary encoded SAB data.

ACIS version 21800 is sufficient for DXF versions R2013 and R2018, earlier DXF versions require SAT data.

Raises:
ezdxf.acis.api.mesh_from_body(body: Body, merge_lumps=True) list[MeshTransformer]

Returns a list of MeshTransformer instances from the given ACIS Body entity. The list contains multiple meshes if merge_lumps is False or just a single mesh if merge_lumps is True.

The ACIS format stores the faces in counter-clockwise orientation where the face-normal points outwards (away) from the solid body (material).

Note

This function returns meshes build up only from flat polygonal Face entities, for a tessellation of more complex ACIS entities (spline surfaces, tori, cones, …) is an ACIS kernel required which ezdxf does not provide.

Parameters:
  • body – ACIS entity of type Body

  • merge_lumps – returns all Lump entities from a body as a single mesh if True otherwise each Lump entity is a separated mesh

Raises:

TypeError – given body entity has invalid type

The following images show the limitations of the mesh_from_body() function. The first image shows the source 3DSOLID entities with subtraction of entities with flat and curved faces:

_images/solids-acis.png

Example script to extracts all flat polygonal faces as meshes:

import ezdxf
from ezdxf.acis import api as acis


doc = ezdxf.readfile("3dsolids.dxf")
msp = doc.modelspace()

doc_out = ezdxf.new()
msp_out = doc_out.modelspace()

for e in msp.query("3DSOLID"):
    for body in acis.load_dxf(data):
        for mesh in acis.mesh_from_body(body):
            mesh.render_mesh(msp_out)
doc_out.saveas("meshes.dxf")

The second image shows the flat faces extracted from the 3DSOLID entities and exported as Mesh entities:

_images/solids-mesh.png

As you can see all faces which do not have straight lines as boundaries are lost.

ezdxf.acis.api.body_from_mesh(mesh: MeshBuilder, precision: int = 6) Body

Returns a ACIS Body entity from a MeshBuilder instance.

This entity can be assigned to a Solid3d DXF entity as SAT or SAB data according to the version your DXF document uses (SAT for DXF R2000 to R2010 and SAB for DXF R2013 and later).

If the mesh contains multiple separated meshes, each mesh will be a separated Lump node. If each mesh should get its own Body entity, separate the meshes beforehand by the method separate_meshes().

A closed mesh creates a solid body and an open mesh creates an open (hollow) shell. The detection if the mesh is open or closed is based on the edges of the mesh: if all edges of mesh have two adjacent faces the mesh is closed.

The current implementation applies automatically a vertex optimization, which merges coincident vertices into a single vertex.

ezdxf.acis.api.vertices_from_body(body: Body) list[Vec3]

Returns all stored vertices in the given Body entity. The result is not optimized, meaning the vertices are in no particular order and there are duplicates.

This function can be useful to determining the approximate bounding box of an ACIS entity. The result is exact for polyhedra with flat faces with straight edges, but not for bodies with curved edges and faces.

Parameters:

body – ACIS entity of type Body

Raises:

TypeError – given body entity has invalid type

Exceptions

class ezdxf.acis.api.AcisException

Base exception of the ezdxf.acis package.

class ezdxf.acis.api.ParsingError

Exception raised when loading invalid or unknown ACIS structures.

class ezdxf.acis.api.ExportError

Exception raised when exporting invalid or unknown ACIS structures.

class ezdxf.acis.api.InvalidLinkStructure

Exception raised when the internal link structure is damaged.

Entities

A document (sat.pdf) about the basic ACIS 7.0 file format is floating in the internet.

This section contains the additional information about the entities, I got from analyzing the SAT data extracted from DXF files exported by BricsCAD.

This documentation ignores the differences to the ACIS format prior to version 7.0 and all this differences are handled internally.

Writing support for ACIS version < 7.0 is not required because all CAD applications should be able to process version 7.0, even if embedded in a very old DXF R2000 format (tested with Autodesk TrueView, BricsCAD and Nemetschek Allplan).

The first goal is to document the entities which are required to represent a geometry as flat polygonal faces (polyhedron), which can be converted into a MeshBuilder object.

Topology Entities:

Geometry Entities:

ezdxf.acis.entities.NONE_REF

Special sentinel entity which supports the type attribute and the is_none property. Represents all unset entities. Use this idiom on any entity type to check if an entity is unset:

if entity.is_none:
    ...

AcisEntity

class ezdxf.acis.entities.AcisEntity

Base class for all ACIS entities.

type

Name of the type as str.

id

Unique id as int or -1 if not set.

attributes

Reference to the first Attribute entity (not supported).

is_none

True for unset entities represented by the NONE_REF instance.

Transform

class ezdxf.acis.entities.Transform(AcisEntity)

Represents an affine transformation operation which transform the body to the final location, size and rotation.

matrix

Transformation matrix of type ezdxf.math.Matrix44.

Body

class ezdxf.acis.entities.Body(AcisEntity)

Represents a solid geometry, which can consist of multiple Lump entities.

pattern

Reference to the Pattern entity.

lump

Reference to the first Lump entity

wire

Reference to the first Wire entity

transform

Reference to the Transform entity (optional)

lumps() list[Lump]

Returns all linked Lump entities as a list.

append_lump(lump: Lump) None

Append a Lump entity as last lump.

Pattern

class ezdxf.acis.entities.Pattern(AcisEntity)

Not implemented.

Lump

class ezdxf.acis.entities.Lump(AcisEntity)

The lump represents a connected entity and there can be multiple lumps in a Body. Multiple lumps are linked together by the next_lump attribute which points to the next lump entity the last lump has a NONE_REF as next lump. The body attribute references to the parent Body entity.

next_lump

Reference to the next Lump entity, the last lump references NONE_REF.

shell

Reference to the Shell entity.

body

Reference to the parent Body entity.

shells() list[Shell]

Returns all linked Shell entities as a list.

append_shell(shell: Shell) None

Append a Shell entity as last shell.

Wire

class ezdxf.acis.entities.Wire(AcisEntity)

Not implemented.

Shell

class ezdxf.acis.entities.Shell(AcisEntity)

A shell defines the boundary of a solid object or a void (subtraction object). A shell references a list of Face and Wire entities. All linked Shell entities are disconnected.

next_shell

Reference to the next Shell entity, the last shell references NONE_REF.

subshell

Reference to the first Subshell entity.

face

Reference to the first Face entity.

wire

Reference to the first Wire entity.

lump

Reference to the parent Lump entity.

faces() list[Face]

Returns all linked Face entities as a list.

append_face(face: Face) None

Append a Face entity as last face.

Subshell

class ezdxf.acis.entities.Subshell(AcisEntity)

Not implemented.

Face

class ezdxf.acis.entities.Face(AcisEntity)

A face is the building block for Shell entities. The boundary of a face is represented by one or more Loop entities. The spatial geometry of the face is defined by the surface object, which is a bounded or unbounded parametric 3d surface (plane, ellipsoid, spline-surface, …).

next_face

Reference to the next Face entity, the last face references NONE_REF.

loop

Reference to the first Loop entity.

shell

Reference to the parent Shell entity.

subshell

Reference to the parent Subshell entity.

surface

Reference to the parametric Surface geometry.

sense

Boolean value of direction of the face normal with respect to the Surface entity:

  • True: “reversed” direction of the face normal

  • False: “forward” for same direction of the face normal

double_sided

Boolean value which indicates the sides of the face:

  • True: the face is part of a hollow object and has two sides.

  • False: the face is part of a solid object and has only one side which points away from the “material”.

containment

Unknown meaning.

If double_sided is True:

  • True is “in”

  • False is “out”

loops() list[Loop]

Returns all linked Loop entities as a list.

append_loop(loop: Loop) None

Append a Loop entity as last loop.

Loop

class ezdxf.acis.entities.Loop(AcisEntity)

A loop represents connected coedges which are building the boundaries of a Face, there can be multiple loops for a single face e.g. faces can contain holes. The coedge attribute references the first Coedge of the loop, the additional coedges are linked to this first Coedge. In closed loops the coedges are organized as a circular list, in open loops the last coedge references the NONE_REF entity as next_coedge and the first coedge references the NONE_REF as prev_coedge.

next_loop

Reference to the next Loop entity, the last loop references NONE_REF.

coedge

Reference to the first Coedge entity.

face

Reference to the parent Face entity.

coedges() list[Coedge]

Returns all linked Coedge entities as a list.

set_coedges(coedges: list[Coedge], close=True) None

Set all coedges of a loop at once.

Coedge

class ezdxf.acis.entities.Coedge(AcisEntity)

The coedges are a double linked list where next_coedge points to the next Coedge and prev_coedge to the previous Coedge.

The partner_coedge attribute references the first partner Coedge of an adjacent Face, the partner edges are organized as a circular list. In a manifold closed surface each Face is connected to one partner face by an Coedge. In a non-manifold surface a face can have more than one partner face.

next_coedge

References the next Coedge, reference the NONE_REF if it is the last coedge in an open Loop.

prev_coedge

References the previous Coedge, reference the NONE_REF if it is the first coedge in an open Loop.

partner_coedge

References the partner Coedge of an adjacent Face entity. The partner coedges are organized in a circular list.

edge

References the Edge entity.

loop

References the parent Loop entity.

pcurve

References the PCurve entity.

Edge

class ezdxf.acis.entities.Edge(AcisEntity)

The Edge entity represents the physical edge of an object. Its geometry is defined by the bounded portion of a parametric space curve. This bounds are stored as object-space Vertex entities.

start_vertex

The start Vertex of the space-curve in object coordinates, if NONE_REF the curve is unbounded in this direction.

start_param

The parametric starting bound for the parametric curve. Evaluating the curve for this parameter should return the coordinates of the start_vertex.

end_vertex

The end Vertex of the space-curve in object coordinates, if NONE_REF the curve is unbounded in this direction.

end_param

The parametric end bound for the parametric curve.

coedge

Parent Coedge of this edge.

curve

The parametric space-curve which defines this edge. The curve can be the NULL_REF while both Vertex entities are the same vertex. In this case the Edge represents an single point like the apex of a cone.

sense

Boolean value which indicates the direction of the edge:

  • True: the edge has the “reversed” direction as the underlying curve

  • False: the edge has the same direction as the underlying curve (“forward”)

convexity

Unknown meaning, always the string “unknown”.

Vertex

class ezdxf.acis.entities.Vertex(AcisEntity)

Represents a vertex of an Edge entity and references a Point entity.

point

The spatial location in object-space as Point entity.

edge

Parent Edge of this vertex. The vertex can be referenced by multiple edges, anyone of them can be the parent of the vertex.

Surface

class ezdxf.acis.entities.Surface(AcisEntity)

Abstract base class for all parametric surfaces.

The parameterization of any Surface maps a 2D rectangle (u, v parameters) into the spatial object-space (x, y, z).

u_bounds

Tuple of (start bound, end bound) parameters as two floats which define the bounds of the parametric surface in the u-direction, one or both values can be math.inf which indicates an unbounded state of the surface in that direction.

v_bounds

Tuple of (start bound, end bound) parameters as two floats which define the bounds of the parametric surface in the v-direction, one or both values can be math.inf which indicates an unbounded state of the surface in that direction.

abstract evaluate(u: float, v: float) Vec3

Returns the spatial location at the parametric surface for the given parameters u and v.

Plane

class ezdxf.acis.entities.Plane(Surface)

Defines a flat plan as parametric surface.

origin

Location vector of the origin of the flat plane as Vec3.

normal

Normal vector of the plane as Vec3. Has to be an unit-vector!

u_dir

Direction vector of the plane in u-direction as Vec3. Has to be an unit-vector!

v_dir

Direction vector of the plane in v-direction as Vec3. Has to be an unit-vector!

reverse_v

Boolean value which indicates the orientation of the coordinate system:

  • True: left-handed system, the v-direction is reversed and the normal vector is v_dir cross u_dir.

  • False: right-handed system and the normal vector is u_dir cross v_dir.

Curve

class ezdxf.acis.entities.Curve(AcisEntity)

Abstract base class for all parametric curves.

The parameterization of any Curve maps a 1D line (the parameter) into the spatial object-space (x, y, z).

bounds

Tuple of (start bound, end bound) parameters as two floats which define the bounds of the parametric curve, one or both values can be math.inf which indicates an unbounded state of the curve in that direction.

abstract evaluate(param: float) Vec3

Returns the spatial location at the parametric curve for the given parameter.

StraightCurve

class ezdxf.acis.entities.StraightCurve(Curve)

Defines a straight line as parametric curve.

origin

Location vector of the origin of the straight line as Vec3.

direction

Direction vector the straight line as Vec3. Has to be an unit-vector!

PCurve

class ezdxf.acis.entities.PCurve(AcisEntity)

Not implemented.

Point

class ezdxf.acis.entities.Point(AcisEntity)

Represents a point in the 3D object-space.

location

Cartesian coordinates as Vec3.