Provided by: python3-ezdxf_1.1.3-1_all 

NAME
ezdxf - ezdxf Documentation [image]
Welcome! This is the documentation for ezdxf release 1.1.3, last updated Nov 25, 2023.
• ezdxf is a Python package to create new DXF documents and read/modify/write existing DXF documents
• MIT-License
• the intended audience are programmers
• requires at least Python 3.8
• OS independent
• tested with CPython and pypy3
• has type annotations and passes mypy --ignore-missing-imports -p ezdxf successful
• additional required packages for the core package without add-ons: typing_extensions, pyparsing, numpy,
fontTools
• read/write/new support for DXF versions: R12, R2000, R2004, R2007, R2010, R2013 and R2018
• additional read-only support for DXF versions R13/R14 (upgraded to R2000)
• additional read-only support for older DXF versions than R12 (upgraded to R12)
• read/write support for ASCII DXF and Binary DXF
• retains third-party DXF content
• optional C-extensions for CPython are included in the binary wheels, available on PyPI for Windows,
Linux and macOS
INCLUDED EXTENSIONS
Additional packages required for these add-ons are not automatically installed during the basic setup,
for more information about the setup & dependencies visit the documentation.
• drawing add-on to visualise and convert DXF files to images which can be saved as PNG, PDF or SVG files
• r12writer add-on to write basic DXF entities direct and fast into a DXF R12 file or stream
• iterdxf add-on to iterate over DXF entities from the modelspace of huge DXF files (> 5GB) which do not
fit into memory
• importer add-on to import entities, blocks and table entries from another DXF document
• dxf2code add-on to generate Python code for DXF structures loaded from DXF documents as starting point
for parametric DXF entity creation
• acadctb add-on to read/write Plot Style Files (CTB/STB)
• pycsg add-on for Constructive Solid Geometry (CSG) modeling technique
• MTextExplode add-on for exploding MTEXT entities into single-line TEXT entities
• text2path add-on to convert text into outline paths
• geo add-on to support the __geo_interface__
• meshex add-on for exchanging meshes with other tools as STL, OFF or OBJ files
• openscad add-on, an interface to OpenSCAD
• odafc add-on, an interface to the ODA File Converter to read and write DWG files
• hpgl2 add-on for converting HPGL/2 plot files to DXF, SVG and PDF
WEBSITE
https://ezdxf.mozman.at/
DOCUMENTATION
Documentation of development version at https://ezdxf.mozman.at/docs
Documentation of latest release at http://ezdxf.readthedocs.io/
KNOWLEDGE GRAPH
The Knowledge Graph contains additional information beyond the documentation and is managed by logseq.
The source data is included in the repository in the folder ezdxf/notes. There is also a HTML export on
the website which gets regular updates.
RELEASE NOTES
The release notes are included in the Knowledge Graph.
CHANGELOG
The changelog is included in the Knowledge Graph.
SOURCE CODE & FEEDBACK
Source Code: http://github.com/mozman/ezdxf.git
Issue Tracker: http://github.com/mozman/ezdxf/issues
Forum: https://github.com/mozman/ezdxf/discussions
QUESTIONS AND ANSWERS
Please post questions at the forum or stack overflow to make answers available to other users as well.
INTRODUCTION
What is ezdxf
Ezdxf is a Python interface to the DXF (drawing interchange file) format developed by Autodesk, ezdxf
allows developers to read and modify existing DXF documents or create new DXF documents.
The main objective in the development of ezdxf was to hide complex DXF details from the programmer but
still support most capabilities of the DXF format. Nevertheless, a basic understanding of the DXF format
is required, also to understand which tasks and goals are possible to accomplish by using the DXF format.
Not all DXF features are supported yet, but additional features will be added in the future gradually.
Ezdxf is also a replacement for the outdated dxfwrite and dxfgrabber packages but with different APIs,
for more information see also: What is the Relationship between ezdxf, dxfwrite and dxfgrabber?
What ezdxf can’t do
• ezdxf is not a DXF converter: ezdxf can not convert between different DXF versions, if you are looking
for an appropriate application, try the free ODAFileConverter from the Open Design Alliance, which
converts between different DXF version and also between the DXF and the DWG file format.
• ezdxf is not a CAD file format converter: ezdxf can not convert DXF files to other CAD formats such as
DWG
• ezdxf is not a CAD kernel and does not provide high level functionality for construction work, it is
just an interface to the DXF file format. If you are looking for a CAD kernel with Python scripting
support, look at FreeCAD.
Supported Python Versions
Ezdxf requires at least Python 3.8 (determined by numpy) and will be tested with the latest stable
CPython version and the latest stable release of pypy3 during development.
Ezdxf is written in pure Python with optional Cython implementations of some low level math classes and
requires pyparsing, numpy, fontTools and typing_extensions as additional library beside the Python
Standard Library. Pytest is required to run the unit and integration tests. Data to run the stress and
audit test can not be provided, because I don’t have the rights for publishing these DXF files.
Supported Operating Systems
Ezdxf is OS independent and runs on all platforms which provide an appropriate Python interpreter
(>=3.8).
Supported DXF Versions
──────────────────────────────────
Version AutoCAD Release
──────────────────────────────────
AC1009 AutoCAD R12
──────────────────────────────────
AC1012 AutoCAD R13 -> R2000
──────────────────────────────────
AC1014 AutoCAD R14 -> R2000
──────────────────────────────────
AC1015 AutoCAD R2000
──────────────────────────────────
AC1018 AutoCAD R2004
──────────────────────────────────
AC1021 AutoCAD R2007
──────────────────────────────────
AC1024 AutoCAD R2010
──────────────────────────────────
AC1027 AutoCAD R2013
──────────────────────────────────
AC1032 AutoCAD R2018
┌─────────┬──────────────────────┐
│ │ │
Ezdxf also reads older DXF versions│but saves│it as DXF R12. │
│ │ │
--
SETUP & DEPENDENCIES │ │ │
--
USAGE FOR BEGINNERS
This section shows the intended usage of the ezdxf package. This is just a brief overview for new ezdxf
users, follow the provided links for more detailed information.
First import the package:
import ezdxf
Loading DXF Files
ezdxf supports loading ASCII and binary DXF documents from a file:
doc = ezdxf.readfile(filename)
or from a zip-file:
doc = ezdxf.readzip(zipfilename[, filename])
Which loads the DXF document filename from the zip-file zipfilename or the first DXF file in the zip-file
if filename is absent.
It is also possible to read a DXF document from a stream by the ezdxf.read() function, but this is a more
advanced feature, because this requires detection of the file encoding in advance.
This works well with DXF documents from trusted sources like AutoCAD or BricsCAD. For loading DXF
documents with minor or major flaws use the ezdxf.recover module.
SEE ALSO:
Documentation for ezdxf.readfile(), ezdxf.readzip() and ezdxf.read(), for more information about file
management go to the Document Management section. For loading DXF documents with structural errors
look at the ezdxf.recover module.
Layouts and Blocks
Layouts are containers for DXF entities like LINE or CIRCLE. The most important layout is the modelspace
labeled as “Model” in CAD applications which represents the “world” work space. Paperspace layouts
represents plottable sheets which contains often the framing and the tile block of a drawing and VIEWPORT
entities as scaled and clipped “windows” into the modelspace.
The modelspace is always present and can not be deleted. The active paperspace is also always present in
a new DXF document but can be deleted, in that case another paperspace layout gets the new active
paperspace, but you can not delete the last paperspace layout.
Getting the modelspace of a DXF document:
msp = doc.modelspace()
Getting a paperspace layout by the name as shown in the tab of a CAD application:
psp = doc.paperspace("Layout1")
A block is just another kind of entity space, which can be inserted multiple times into other layouts and
blocks by the INSERT entity also called block references, this is a very powerful and an important
concept of the DXF format.
Getting a block layout by the block name:
blk = doc.blocks.get("NAME")
All these layouts have factory functions to create graphical DXF entities for their entity space, for
more information about creating entities see section: Create new DXF Entities
Query DXF Entities
As said in the Layouts and Blocks section, all graphical DXF entities are stored in layouts, all these
layouts can be iterated and do support the index operator e.g. layout[-1] returns the last entity.
The main difference between iteration and index access is, that iteration filters destroyed entities, but
the index operator returns also destroyed entities until these entities are purged by layout.purge(),
more about this topic in section: Delete Entities.
There are two advanced query methods: query() and groupby().
Get all lines of layer "MyLayer":
lines = msp.query('LINE[layer=="MyLayer"]')
This returns an EntityQuery container, which also provides the same query() and groupby() methods.
Get all lines categorized by a DXF attribute like color:
all_lines_by_color = msp.query("LINE").groupby("color")
lines_with_color_1 = all_lines_by_color.get(1, [])
The groupby() method returns a regular Python dict with colors as key and a regular Python list of
entities as values (not an EntityQuery container).
SEE ALSO:
For more information go to the Tutorial for Getting Data from DXF Files
Examine DXF Entities
Each DXF entity has a dxf namespace attribute, which stores the named DXF attributes, some entity
attributes and assets are only available from Python properties or methods outside the dxf namespace like
the vertices of the LWPOLYLINE entity. More information about the DXF attributes of each entity can found
in the documentation of the ezdxf.entities module.
Get some basic DXF attributes:
layer = entity.dxf.layer # default is "0"
color = entity.dxf.color # default is 256 = BYLAYER
Most DXF attributes have a default value, which will be returned if the DXF attribute is not present, for
DXF attributes without a default value you can check if the attribute really exist:
entity.dxf.hasattr("true_color")
or use the get() method and provide a default value:
entity.dxf.get("true_color", 0)
SEE ALSO:
• Common graphical DXF attributes
• Helper class ezdxf.gfxattribs.GfxAttribs for building DXF attribute dictionaries.
Create a New DXF File
Create new document for the latest supported DXF version:
doc = ezdxf.new()
Create a new DXF document for a specific DXF version, e.g. for DXF R12:
doc = ezdxf.new("R12")
The ezdxf.new() function can create some standard resources, such as linetypes and text styles, by
setting the argument setup to True:
doc = ezdxf.new(setup=True)
SEE ALSO:
• Tutorial for Creating DXF Drawings
• Documentation for ezdxf.new(), for more information about file management go to the Document
Management section.
Create New DXF Entities
The factory methods for creating new graphical DXF entities are located in the BaseLayout class and these
factory methods are available for all entity containers:
• Modelspace
• Paperspace
• BlockLayout
The usage is simple:
msp = doc.modelspace()
msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "MyLayer"})
A few important/required DXF attributes are explicit method arguments, most additional DXF attributes are
gives as a regular Python dict object by the keyword only argument dxfattribs. The supported DXF
attributes can be found in the documentation of the ezdxf.entities module.
WARNING:
Do not instantiate DXF entities by yourself and add them to layouts, always use the provided factory
methods to create new graphical entities, this is the intended way to use ezdxf.
SEE ALSO:
• Thematic Index of Layout Factory Methods
• Tutorial for Creating DXF Drawings
• Tutorial for Simple DXF Entities
• Tutorial for LWPolyline
• Tutorial for Text
• Tutorial for MText and MTextEditor
• Tutorial for Hatch
Saving DXF Files
Save the DXF document with a new name:
doc.saveas("new_name.dxf")
or with the same name as loaded:
doc.save()
SEE ALSO:
Documentation for ezdxf.document.Drawing.save() and ezdxf.document.Drawing.saveas(), for more
information about file management go to the Document Management section.
Create New Blocks
The block definitions of a DXF document are managed by the BlocksSection object:
my_block = doc.blocks.new("MyBlock")
SEE ALSO:
Tutorial for Blocks
Create Block References
A block reference is just another DXF entity called INSERT. The Insert entity is created by the factory
method: add_blockref():
msp.add_blockref("MyBlock", (0, 0))
SEE ALSO:
See Tutorial for Blocks for more advanced features like using Attrib entities.
Create New Layers
A layer is not an entity container, a layer is just another DXF attribute stored in the entity and the
entity can inherit some properties from this Layer object. Layer objects are stored in the layer table
which is available as attribute doc.layers.
You can create your own layers:
my_layer = doc.layers.add("MyLayer")
The layer object also controls the visibility of entities which references this layer, the on/off state
of the layer is unfortunately stored as positive or negative color value which make the raw DXF attribute
of layers useless, to change the color of a layer use the property Layer.color
my_layer.color = 1
To change the state of a layer use the provided methods of the Layer object, like on(), off(), freeze()
or thaw():
my_layer.off()
SEE ALSO:
Layers
Delete Entities
The safest way to delete entities is to delete the entity from the layout containing that entity:
line = msp.add_line((0, 0), (1, 0))
msp.delete_entity(line)
This removes the entity immediately from the layout and destroys the entity. The property is_alive
returns False for a destroyed entity and all Python attributes are deleted, so line.dxf.color will raise
an AttributeError exception, because line does not have a dxf attribute anymore.
Ezdxf also supports manually destruction of entities by calling the method destroy():
line.destroy()
Manually destroyed entities are not removed immediately from entities containers like Modelspace or
EntityQuery, but iterating such a container will filter destroyed entities automatically, so a for e in
msp: ... loop will never yield destroyed entities. The index operator and the len() function do not
filter deleted entities, to avoid getting deleted entities call the purge() method of the container
manually to remove deleted entities.
Further Information
• Reference
BASIC CONCEPTS
The Basic Concepts section teach the intended meaning of DXF attributes and structures without teaching
the application of this information or the specific implementation by ezdxf, if you are looking for more
information about the ezdxf internals look at the Reference section or if you want to learn how to use
ezdxf go to the Tutorials section and for the solution of specific problems go to the Howto section.
What is DXF?
The common assumption is also the cite of Wikipedia:
AutoCAD DXF (Drawing eXchange Format) is a CAD data file format developed by Autodesk for enabling
data interoperability between AutoCAD and other applications.
DXF was originally introduced in December 1982 as part of AutoCAD 1.0, and was intended to provide an
exact representation of the data in the AutoCAD native file format, DWG (Drawing). For many years
Autodesk did not publish specifications making correct imports of DXF files difficult. Autodesk now
publishes the DXF specifications online.
The more precise cite from the DXF reference itself:
The DXF™ format is a tagged data representation of all the information contained in an AutoCAD®
drawing file. Tagged data means that each data element in the file is preceded by an integer number
that is called a group code. A group code’s value indicates what type of data element follows. This
value also indicates the meaning of a data element for a given object (or record) type. Virtually all
user-specified information in a drawing file can be represented in DXF format.
No mention of interoperability between AutoCAD and other applications.
In reality the DXF format was designed to ensure AutoCAD cross-platform compatibility in the early days
when different hardware platforms with different binary data formats were used. The name DXF (Drawing
eXchange Format) may suggest an universal exchange format, but it is not. It is based on the
infrastructure installed by Autodesk products (fonts) and the implementation details of AutoCAD (MTEXT)
or on licensed third party technologies (embedded ACIS entities).
For more information about the AutoCAD history see the document: The Autodesk File - Bits of History,
Words of Experience by John Walker, founder of Autodesk, Inc. and co-author of AutoCAD.
DXF Reference Quality
The DXF reference is by far no specification nor a standard like the W3C standard for SVG or the ISO
standard for PDF.
The reference describes many but not all DXF entities and some basic concepts like the tag structure or
the arbitrary axis algorithm. But the existing documentation (reference) is incomplete and partly
misleading or wrong. Also missing from the reference are some important parts like the complex
relationship between the entities to create higher order structures like block definitions, layouts
(model space & paper space) or dynamic blocks to name a few.
Reliable CAD Applications
Because of the suboptimal quality of the DXF reference not all DXF viewers, creators or processors are of
equal quality. I consider a CAD application as a reliable CAD application when the application creates
valid DXF documents in the meaning and interpretation of Autodesk and a reliable DXF viewer when the
result matches in most parts the result of the free Trueview viewer provided by Autodesk.
These are some applications which do fit the criteria of a reliable CAD application:
• AutoCAD and Trueview
• CAD applications based on the OpenDesignAlliance (ODA) SDK, see also ODA on wikipedia, even Autodesk is
a corporate member, see their blog post from 22 Sep 2020 at adsknews but only to use the ODA IFC tools
and not to improve the DWG/DXF compatibility
• BricsCAD (ODA based)
• GstarCAD (ODA based)
• ZWCAD (ODA based)
Unfortunately, I cannot recommend any open source applications because everyone I know has serious
shortcomings, at least as a DXF viewer, and I don’t trust them as a DXF creator either. To be clear, not
even ezdxf (which is not a CAD application) is a reliable library in this sense - it just keeps getting
better, but is far from reliable.
HINT:
Please do not submit bug reports based on the use of LibreCAD or QCAD, these applications are in no
way reliable regarding the DXF format and I will not waste my time on them.
DXF Entities and Objects
DXF entities are objects that make up the design data stored in a DXF file.
Graphical Entities
Graphical entities are visible objects stored in blocks, modelspace- or paperspace layouts. They
represent the various shapes, lines, and other elements that make up a 2D or 3D design.
Some common types of DXF entities include:
• LINE and POLYLINE: These are the basic building blocks of a DXF file. They represent straight and
curved lines.
• CIRCLE and ARC: These entities represent circles and portions of circles, respectively.
• TEXT and MTEXT: DXF files can also contain text entities, which can be used to label parts of the
design or provide other information.
• HATCH: DXF files can also include hatch patterns, which are used to fill in areas with a specific
pattern or texture.
• DIMENSION: DXF files can also contain dimension entities, which provide precise measurements of the
various elements in a design.
• INSERT: A block is a group of entities that can be inserted into a design multiple times by the INSERT
entity, making it a useful way to reuse elements of a design.
These entities are defined using specific codes and values in the DXF file format, and they can be
created and manipulated by ezdxf.
Objects
DXF objects are non-graphical entities and have no visual representation, they store administrative data,
paperspace layout definitions, style definitions for multiple entity types, custom data and objects. The
OBJECTS section in DXF files serves as a container for these non-graphical objects.
Some common DXF types of DXF objects include:
• DICTIONARY: A dictionary object consists of a series of name-value pairs, where the name is a string
that identifies a specific object within the dictionary, and the value is a reference to that object.
The objects themselves can be any type of DXF entity or custom object defined in the DXF file.
• XRECORD entities are used to store custom application data in a DXF file.
• the LAYOUT entity is a DXF entity that represents a single paper space layout in a DXF file. Paper
space is the area in a CAD drawing that represents the sheet of paper or other physical media on which
the design will be plotted or printed.
• MATERIAL, MLINESTYLE, MLEADERSTYLE definitions stored in certain DICTIONARY objects.
• A GROUP entity contains a list of handles that refer to other DXF entities in the drawing. The entities
in the group can be of any type, including entities from the model space or paper space layouts.
TagStorage
The ezdxf package supports many but not all entity types, all these unsupported types are stored as
TagStorage instances to preserve their data when exporting the edited DXF content by ezdxf.
Access Entity Attributes
All DXF attributes are stored in the entity namespace attribute dxf.
print(entity.dxf.layer)
Some attributes are mandatory others are optional in most cases a reasonable values will be returned as
default value if the attribute is missing.
SEE ALSO:
Tutorial for Getting Data from DXF Files
Where to Look for Entities
The DXF document has an entity database where all entities which have a handle are stored in a (key,
value) storage. The query() method is often the easiest way to request data:
for text in doc.entitydb.query("TEXT"):
print(text.dxf.text)
SEE ALSO:
• ezdxf.query module
• ezdxf.entitydb module
Graphical entities are stored in blocks, the modelspace or paperspace layouts.
• The doc.modelspace() function returns the Modelspace instance
• The doc.paperspace() returns a Paperspace instance
• The doc.blocks attribute provides access to the BlocksSection
The query() method of the Drawing class which represents the DXF document, runs the query on all layouts
and block definitions.
Non-graphical entities are stored in the OBJECTS section:
• The doc.objects attribute provides access to the ObjectsSection.
Resource definitions like Layer, Linetype or Textstyle are stored in resource tables:
• doc.layers: the LayerTable
• doc.linetypes: the LinetypeTable
• doc.styles: the TextstyleTable
• doc.dimstyles: the DimStyleTable
IMPORTANT:
A layer assignment is just an attribute of a DXF entity, it’s not an entity container!
SEE ALSO:
• Basic concept of the Modelspace
• Basic concept of Paperspace layouts
• Basic concept of Blocks
• Tutorial for Getting Data from DXF Files
How to Create Entities
The recommended way to create new DXF entities is to use the factory methods of layouts and blocks to
create entities and add them to the entity space automatically.
SEE ALSO:
• Thematic Index of Layout Factory Methods
• Reference of the BaseLayout class
• Tutorial for Simple DXF Entities
AutoCAD Color Index (ACI)
The color attribute represents an ACI (AutoCAD Color Index). AutoCAD and many other CAD application
provides a default color table, but pen table would be the more correct term. Each ACI entry defines the
color value, the line weight and some other attributes to use for the pen. This pen table can be edited
by the user or loaded from an CTB or STB file. Ezdxf provides functions to create (new()) or modify
(ezdxf.acadctb.load()) plot styles files.
DXF R12 and prior do not preserve the layout of a drawing very well, because of the lack of a standard
color table and missing DXF structures to define these color tables in the DXF file. If a CAD user
redefines an ACI color entry in a CAD application and does not provide this CTB or STB file, you can not
know what color or lineweight was used intentionally. This got better in later DXF versions by
supporting additional DXF attributes like lineweight and true_color which can define these attributes by
distinct values. [image]
SEE ALSO:
• Plot Style Files (CTB/STB)
• ezdxf.colors
• Tutorial for Common Graphical Attributes
• Autodesk Knowledge Network: About Setting the Color of Objects
• BricsCAD Help Center: Entity Color
True Color
The support for true color was added to the DXF file format in revision R2004. The true color value has
three components red, green and blue in the range from 0 to 255 and is stored as a 24-bit value in the
DXF namespace as true_color attribute and looks like this 0xRRGGBB as hex value. For a more easy usage
all graphical entities support the rgb property to get and set the true color as (r, g, b) tuples where
the components must be in the range from 0 to 255.
import ezdxf
doc = ezdxf.new()
msp = doc.modelspace()
line = msp.add_line((0, 0), (10, 0))
line.rgb = (255, 128, 32)
The true color value has higher precedence than the AutoCAD Color Index (ACI) value, if the attributes
color and the true_color are present the entity will be rendered with the true color value.
The true color value has the advantage that it defines the color absolutely and unambiguously, no
unexpected overwriting is possible. The representation of the color is fixed and only depends on the
calibration of the output medium: [image]
SEE ALSO:
• ezdxf.colors
• Tutorial for Common Graphical Attributes
• Autodesk Knowledge Network: About Setting the Color of Objects
• BricsCAD Help Center: Entity Color
Transparency
The support for transparency was added to the DXF file format in revision R2004. The raw transparency
value stored as 32 bit value in the DXF namespace as transparency attribute, has a range from 0 to 255
where 0 is fully transparent and 255 if opaque and has the top byte set to 0x02. For a more easy usage
all graphical entities support the transparency property to get and set the transparency as float value
in the range frem 0.0 to 1.0 where 0.0 is opaque and 1.0 is fully transparent. The transparency value can
be set explicit in the entity, by layer or by block.
import ezdxf
doc = ezdxf.new()
msp = doc.modelspace()
line = msp.add_line((0, 0), (10, 0))
line.transparency = 0.5
SEE ALSO:
• ezdxf.colors
• Tutorial for Common Graphical Attributes
• Autodesk Knowledge Network: About Making Objects Transparent
• BricsCAD Help Center: Entity Transparency
Layers
Every object has a layer as one of its properties. You may be familiar with layers - independent drawing
spaces that stack on top of each other to create an overall image - from using drawing programs. Most CAD
programs use layers as the primary organizing principle for all the objects that you draw. You use
layers to organize objects into logical groups of things that belong together; for example, walls,
furniture, and text notes usually belong on three separate layers, for a couple of reasons:
• Layers give you a way to turn groups of objects on and off - both on the screen and on the plot.
• Layers provide the most efficient way of controlling object color and linetype
Create a layer table entry Layer by Drawing.layers.add(), assign the layer properties such as color and
linetype. Then assign those layers to other DXF entities by setting the DXF attribute layer to the layer
name as string.
The DXF format do not require a layer table entry for a layer. A layer without a layer table entry has
the default linetype 'Continuous', a default color of 7 and a lineweight of -3 which represents the
default lineweight of 0.25mm in most circumstances.
Layer Properties
The advantage of assigning properties to a layer is that entities can inherit this properties from the
layer by using the string 'BYLAYER' as linetype string, 256 as color or -1 as lineweight, all these
values are the default values for new entities. DXF version R2004 and later also support inheriting
true_color and transparency attributes from a layer.
Layer Status
The layer status is important for the visibility and the ability to select and edit DXF entities on that
layer in CAD applications. Ezdxf does not care about the visual representation and works at the level of
entity spaces and the entity database and therefore all the layer states documented below are ignored by
ezdxf. This means if you iterate an entity space like the modelspace or the entity database you will get
all entities from that entity space regardless the layer status.
• ON: the layer is visible, entities on that layer are visible, selectable and editable
• OFF: the layer is not visible, entities on that layer are not visible, not selectable and not editable
• FROZEN: the layer is not visible, entities on that layer are not visible, not selectable and not
editable, very similar to the OFF status but layers can be frozen individually in VIEWPORTS and
freezing layers may speed up some commands in CAD applications like ZOOM, PAN or REGEN.
• LOCKED: the layer is visible, entities on that layer are visible but not selectable and not editable
Deleting Layers
Deleting a layer is not as simple as it might seem, especially if you are used to use a CAD application
like AutoCAD. There is no directory of locations where layers can be used and references to layers can
occur even in third-party data. Deleting the layer table entry removes only the default attributes of
that layer and does not delete any layer references automatically. And because a layer can exist without
a layer table entry, the layer exist as long as at least one layer reference to the layer exist.
Renaming Layers
Renaming a layer is also problematic because the DXF format stores the layer references in most cases as
text strings, so renaming the layer table entry just creates a new layer and all entities which still
have a reference to the old layer now inherit their attributes from an undefined layer table entry with
default settings.
Viewport Overrides
Most of the layer properties can be overriden for each Viewport entity individually and this overrides
are stored in layer table entry referenced by the handle of the VIEWPORT entity. In contrast the frozen
status of layers is store in the VIEWPORT entity.
SEE ALSO:
• Tutorial for Layers
• Tutorial for Viewports in Paperspace
• Autodesk Knowledge Network: About Layers
• BricsCAD Help Center: Working with Layers
Linetypes
The linetype defines the rendering pattern of linear graphical entities like LINE, ARC, CIRCLE and so on.
The linetype of an entity can be specified by the DXF attribute linetype, this can be an explicit named
linetype or the entity can inherit its linetype from the assigned layer by setting linetype to 'BYLAYER',
which is also the default value. CONTINUOUS is the default linetype for layers with an unspecified
linetype.
Ezdxf creates several standard linetypes, if the argument setup is True when calling new(), this simple
linetypes are supported by all DXF versions:
doc = ezdxf.new('R2007', setup=True)
[image]
In DXF R13 Autodesk introduced complex linetypes which can contain text or shapes.
SEE ALSO:
• Tutorial for Common Graphical Attributes
• Tutorial for Creating Linetype Pattern
• Autodesk Knowledge Network: About Linetypes
• BricsCAD Help Center: Entity Linetype
Linetype Scaling
Global linetype scaling can be changed by setting the header variable doc.header['$LTSCALE'] = 2, which
stretches the line pattern by factor 2.
The linetype scaling for a single entity can be set by the DXF attribute ltscale, which is supported
since DXF R2000.
Lineweights
The lineweight attribute represents the lineweight as integer value in millimeters * 100, e.g. 0.25mm =
25, independently from the unit system used in the DXF document. The lineweight attribute is supported
by DXF R2000 and newer.
Only certain values are valid, they are stored in ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS: 0, 5, 9, 13,
15, 18, 20, 25, 30, 35, 40, 50, 53, 60, 70, 80, 90, 100, 106, 120, 140, 158, 200, 211.
Values < 0 have a special meaning and can be imported as constants from ezdxf.lldxf.const
┌────┬────────────────────┐
│ -1 │ LINEWEIGHT_BYLAYER │
├────┼────────────────────┤
│ -2 │ LINEWEIGHT_BYBLOCK │
├────┼────────────────────┤
│ -3 │ LINEWEIGHT_DEFAULT │
└────┴────────────────────┘
The validator function: ezdxf.lldxf.validator.is_valid_lineweight() returns True for valid lineweight
values otherwise False.
Sample script which shows all valid lineweights: valid_lineweights.dxf
You have to enable the option to show lineweights in your CAD application or viewer to see the effect on
screen, which is disabled by default, the same has to be done in the page setup options for plotting
lineweights.
Setting the HEADER variable $LWDISPLAY to 1, activates support for displaying lineweights on screen:
# activate on screen lineweight display
doc.header["$LWDISPLAY"] = 1
[image]
The lineweight value can be overridden by CTB or STB files.
SEE ALSO:
• Autodesk Knowledge Network: About Lineweights
• BricsCAD Help Center: Entity Lineweight
Coordinate Systems
AutoLISP Reference to Coordinate Systems provided by Autodesk.
To brush up you knowledge about vectors, watch the YouTube tutorials of 3Blue1Brown about Linear Algebra.
WCS
World coordinate system - the reference coordinate system. All other coordinate systems are defined
relative to the WCS, which never changes. Values measured relative to the WCS are stable across changes
to other coordinate systems.
UCS
User coordinate system - the working coordinate system defined by the user to make drawing tasks easier.
All points passed to AutoCAD commands, including those returned from AutoLISP routines and external
functions, are points in the current UCS. As far as I know, all coordinates stored in DXF files are
always WCS or OCS never UCS.
User defined coordinate systems are not just helpful for interactive CAD, therefore ezdxf provides a
converter class UCS to translate coordinates from UCS into WCS and vice versa, but always remember: store
only WCS or OCS coordinates in DXF files, because there is no method to determine which UCS was active or
used to create UCS coordinates.
SEE ALSO:
• Table entry UCS
• ezdxf.math.UCS - converter between WCS and UCS
OCS
Object coordinate system are coordinates relative to the object itself. The main goal of OCS is to
place 2D elements in 3D space and the OCS is defined by the extrusion vector of the entity. As long the
extrusion vector is (0, 0, 1) (the WCS z-axis) the OCS is coincident to the WCS, which means the OCS
coordinates are equal to the WCS coordinates, most of the time this is true for 2D entities.
OCS entities: ARC, CIRCLE, TEXT, LWPOLYLINE, HATCH, SOLID, TRACE, INSERT, IMAGE
Because ezdxf is just an interface to DXF, it does not automatically convert OCS into WCS, this is the
domain of the user/application. These lines convert the center of a 3D circle from OCS to WCS:
ocs = circle.ocs()
wcs_center = ocs.to_wcs(circle.dxf.center)
SEE ALSO:
• Object Coordinate System (OCS) - deeper insights into OCS
• ezdxf.math.OCS - converter between WCS and OCS
DCS
Display coordinate system - the coordinate system into which objects are transformed before they are
displayed. The origin of the DCS is the point stored in the AutoCAD system variable TARGET, and its
z-axis is the viewing direction. In other words, a viewport is always a plan view of its DCS. These
coordinates can be used to determine where something will be displayed to the AutoCAD user. Ezdxf does
not use or support DCS in any way.
Object Coordinate System (OCS)
• DXF Reference for OCS provided by Autodesk.
The points associated with each entity are expressed in terms of the entity’s own object coordinate
system (OCS). The OCS was referred to as ECS in previous releases of AutoCAD.
With OCS, the only additional information needed to describe the entity’s position in 3D space is the 3D
vector describing the z-axis of the OCS (often referenced as extrusion vector), and the elevation value,
which is the distance of the entity xy-plane to the WCS/OCS origin.
For a given z-axis (extrusion) direction, there are an infinite number of coordinate systems, defined by
translating the origin in 3D space and by rotating the x- and y-axis around the z-axis. However, for the
same z-axis direction, there is only one OCS. It has the following properties:
• Its origin coincides with the WCS origin.
• The orientation of the x- and y-axis within the xy-plane are calculated in an arbitrary but consistent
manner. AutoCAD performs this calculation using the arbitrary axis algorithm (see below).
• Because of the Arbitrary Axis Algorithm the OCS can only represent a right-handed coordinate system!
The following entities do not lie in a particular plane. All points are expressed in world coordinates.
Of these entities, only lines and points can be extruded. Their extrusion direction can differ from the
world z-axis.
• Line
• Point
• 3DFace
• Polyline (3D)
• Vertex (3D)
• Polymesh
• Polyface
• Viewport
These entities are planar in nature. All points are expressed in object coordinates. All of these
entities can be extruded. Their extrusion direction can differ from the world z-axis.
• Circle
• Arc
• Solid
• Trace
• Text
• Attrib
• Attdef
• Shape
• Insert
• Polyline (2D)
• Vertex (2D)
• LWPolyline
• Hatch
• Image
Some of a Dimension’s points are expressed in WCS and some in OCS.
Elevation
Elevation group code 38:
Exists only in output from versions prior to R11. Otherwise, Z coordinates are supplied as part of each
of the entity’s defining points.
Arbitrary Axis Algorithm
• DXF Reference for Arbitrary Axis Algorithm provided by Autodesk.
The arbitrary axis algorithm is used by AutoCAD internally to implement the arbitrary but consistent
generation of object coordinate systems for all entities that use object coordinates.
Given a unit-length vector to be used as the z-axis of a coordinate system, the arbitrary axis algorithm
generates a corresponding x-axis for the coordinate system. The y-axis follows by application of the
right-hand rule.
We are looking for the arbitrary x- and y-axis to go with the normal Az (the arbitrary z-axis). They will
be called Ax and Ay (using Vec3):
Az = Vec3(entity.dxf.extrusion).normalize() # normal (extrusion) vector
if (abs(Az.x) < 1/64.) and (abs(Az.y) < 1/64.):
Ax = Vec3(0, 1, 0).cross(Az).normalize() # the cross-product operator
else:
Ax = Vec3(0, 0, 1).cross(Az).normalize() # the cross-product operator
Ay = Az.cross(Ax).normalize()
WCS to OCS
def wcs_to_ocs(point):
px, py, pz = Vec3(point) # point in WCS
x = px * Ax.x + py * Ax.y + pz * Ax.z
y = px * Ay.x + py * Ay.y + pz * Ay.z
z = px * Az.x + py * Az.y + pz * Az.z
return Vec3(x, y, z)
OCS to WCS
Wx = wcs_to_ocs((1, 0, 0))
Wy = wcs_to_ocs((0, 1, 0))
Wz = wcs_to_ocs((0, 0, 1))
def ocs_to_wcs(point):
px, py, pz = Vec3(point) # point in OCS
x = px * Wx.x + py * Wx.y + pz * Wx.z
y = px * Wy.x + py * Wy.y + pz * Wy.z
z = px * Wz.x + py * Wz.y + pz * Wz.z
return Vec3(x, y, z)
DXF Units
The DXF reference has no explicit information how to handle units in DXF, any information in this section
is based on experiments with BricsCAD and may differ in other CAD applications, BricsCAD tries to be as
compatible with AutoCAD as possible. Therefore, this information should also apply to AutoCAD.
Please open an issue on github if you have any corrections or additional information about this topic.
Length Units
Any length or coordinate value in DXF is unitless in the first place, there is no unit information
attached to the value. The unit information comes from the context where a DXF entity is used. The
document/modelspace get the unit information from the header variable $INSUNITS, paperspace and block
layouts get their unit information from the attribute units. The modelspace object has also a units
property, but this value do not represent the modelspace units, this value is always set to 0 “unitless”.
Get and set document/modelspace units as enum by the Drawing property units:
import ezdxf
from ezdxf import units
doc = ezdxf.new()
# Set centimeter as document/modelspace units
doc.units = units.CM
# which is a shortcut (including validation) for
doc.header['$INSUNITS'] = units.CM
Block Units
As said each block definition can have independent units, but there is no implicit unit conversion
applied, not in CAD applications and not in ezdxf.
When inserting a block reference (INSERT) into the modelspace or another block layout with different
units, the scaling factor between these units must be applied explicit as DXF attributes (xscale, …) of
the Insert entity, e.g. modelspace in meters and block in centimeters, x-, y- and z-scaling has to be
0.01:
doc.units = units.M
my_block = doc.blocks.new('MYBLOCK')
my_block.units = units.CM
block_ref = msp.add_block_ref('MYBLOCK')
# Set uniform scaling for x-, y- and z-axis
block_ref.set_scale(0.01)
Use helper function conversion_factor() to calculate the scaling factor between units:
factor = units.conversion_factor(doc.units, my_block.units)
# factor = 100 for 1m is 100cm
# scaling factor = 1 / factor
block_ref.set_scale(1.0/factor)
HINT:
It is never a good idea to use different measurement system in one project, ask the NASA about their
Mars Climate Orbiter from 1999. The same applies for units of the same measurement system, just use
one unit like meters or inches.
Angle Units
Angles are always in degrees (360 deg = full circle) in counter-clockwise orientation, unless stated
explicit otherwise.
Display Format
How values are shown in the CAD GUI is controlled by the header variables $LUNITS and $AUNITS, but this
has no meaning for values stored in DXF files.
$INSUNITS
The most important setting is the header variable $INSUNITS, this variable defines the drawing units for
the modelspace and therefore for the DXF document if no further settings are applied.
The modelspace LAYOUT entity has a property units as any layout like object, but it seem to have no
meaning for the modelspace, BricsCAD set this property always to 0, which means unitless.
The most common units are 6 for meters and 1 for inches.
doc.header['$INSUNITS'] = 6
┌────┬───────────────────────┐
│ 0 │ Unitless │
├────┼───────────────────────┤
│ 1 │ Inches, units.IN │
├────┼───────────────────────┤
│ 2 │ Feet, units.FT │
├────┼───────────────────────┤
│ 3 │ Miles, units.MI │
├────┼───────────────────────┤
│ 4 │ Millimeters, units.MM │
├────┼───────────────────────┤
│ 5 │ Centimeters, units.CM │
├────┼───────────────────────┤
│ 6 │ Meters, units.M │
├────┼───────────────────────┤
│ 7 │ Kilometers, units.KM │
├────┼───────────────────────┤
│ 8 │ Microinches │
├────┼───────────────────────┤
│ 9 │ Mils │
├────┼───────────────────────┤
│ 10 │ Yards, units.YD │
├────┼───────────────────────┤
│ 11 │ Angstroms │
├────┼───────────────────────┤
│ 12 │ Nanometers │
├────┼───────────────────────┤
│ 13 │ Microns │
├────┼───────────────────────┤
│ 14 │ Decimeters, units.DM │
├────┼───────────────────────┤
│ 15 │ Decameters │
├────┼───────────────────────┤
│ 16 │ Hectometers │
├────┼───────────────────────┤
│ 17 │ Gigameters │
├────┼───────────────────────┤
│ 18 │ Astronomical units │
├────┼───────────────────────┤
│ 19 │ Light years │
├────┼───────────────────────┤
│ 20 │ Parsecs │
├────┼───────────────────────┤
│ 21 │ US Survey Feet │
├────┼───────────────────────┤
│ 22 │ US Survey Inch │
├────┼───────────────────────┤
│ 23 │ US Survey Yard │
├────┼───────────────────────┤
│ 24 │ US Survey Mile │
└────┴───────────────────────┘
See also enumeration ezdxf.enums.InsertUnits.
$MEASUREMENT
The header variable $MEASUREMENT controls whether the current drawing uses imperial or metric hatch
pattern and linetype files:
This setting is independent from $INSUNITS, it is possible to set the drawing units to inch and use
metric linetypes and hatch pattern.
In BricsCAD the base scaling of linetypes and hatch pattern is defined by the $MEASUREMENT value, the
value of $INSUNITS is ignored.
doc.header['$MEASUREMENT'] = 1
┌───┬─────────┐
│ 0 │ English │
├───┼─────────┤
│ 1 │ Metric │
└───┴─────────┘
See also enumeration ezdxf.enums.Measurement
$LUNITS
The header variable $LUNITS defines how CAD applications display linear values in the GUI and has no
meaning for ezdxf:
doc.header['$LUNITS'] = 2
┌───┬───────────────────┐
│ 1 │ Scientific │
├───┼───────────────────┤
│ 2 │ Decimal (default) │
├───┼───────────────────┤
│ 3 │ Engineering │
├───┼───────────────────┤
│ 4 │ Architectural │
├───┼───────────────────┤
│ 5 │ Fractional │
└───┴───────────────────┘
See also enumeration ezdxf.enums.LengthUnits
$AUNITS
The header variable $AUNITS defines how CAD applications display angular values in the GUI and has no
meaning for ezdxf, DXF angles are always stored as degrees in counter-clockwise orientation, unless
stated explicit otherwise:
doc.header['$AUNITS'] = 0
───────────────────────────────
0 Decimal degrees
───────────────────────────────
1 Degrees/minutes/seconds
───────────────────────────────
2 Grad
───────────────────────────────
3 Radians
┌───┬─────────────────────────┐
│ │ │
--
TUTORIALS
Tutorial for Getting Data from DXF Files
This tutorial shows how to get data from an existing DXF document. If you are a new user of ezdxf, read
also the tutorial Usage for Beginners.
Loading the DXF file:
import sys
import ezdxf
try:
doc = ezdxf.readfile("your_dxf_file.dxf")
except IOError:
print(f"Not a DXF file or a generic I/O error.")
sys.exit(1)
except ezdxf.DXFStructureError:
print(f"Invalid or corrupted DXF file.")
sys.exit(2)
This works well for DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files with
minor or major flaws look at the ezdxf.recover module.
SEE ALSO:
• Document Management
• Usage for Beginners
Layouts
The term layout is used as a synonym for an arbitrary entity space which can contain DXF entities like
LINE, CIRCLE, TEXT and so on. Each DXF entity can only reside in exact one layout.
There are three different layout types:
• Modelspace: the common construction space
• Paperspace: used to to create print layouts
• BlockLayout: reusable elements, every block has its own entity space
A DXF document consist of exact one modelspace and at least one paperspace. DXF R12 has only one unnamed
paperspace the later DXF versions support more than one paperspace and each paperspace has a name.
Getting the modelspace layout
The modelspace contains the “real” world representation of the drawing subjects in real world units. The
modelspace has the fixed name “Model” and the DXF document has a special getter method modelspace().
msp = doc.modelspace()
Iterate over DXF entities of a layout
This code shows how to iterate over all DXF entities in modelspace:
# helper function
def print_entity(e):
print("LINE on layer: %s\n" % e.dxf.layer)
print("start point: %s\n" % e.dxf.start)
print("end point: %s\n" % e.dxf.end)
# iterate over all entities in modelspace
msp = doc.modelspace()
for e in msp:
if e.dxftype() == "LINE":
print_entity(e)
# entity query for all LINE entities in modelspace
for e in msp.query("LINE"):
print_entity(e)
All layout objects supports the standard Python iterator protocol and the in operator.
Access DXF attributes of an entity
The e.dxftype() method returns the DXF type, the DXF type is always an uppercase string like "LINE". All
DXF attributes of an entity are grouped in the namespace attribute dxf:
e.dxf.layer # layer of the entity as string
e.dxf.color # color of the entity as integer
See Common graphical DXF attributes
If a DXF attribute is not set (the DXF attribute does not exist), a DXFValueError will be raised. The
get() method returns a default value in this case or None if no default value is specified:
# If DXF attribute 'paperspace' does not exist, the entity defaults
# to modelspace:
p = e.dxf.get("paperspace", 0)
or check beforehand if the attribute exist:
if e.dxf.hasattr("paperspace"):
...
An unsupported DXF attribute raises a DXFAttributeError, to check if an attribute is supported by an
entity use:
if e.dxf.is_supported("paperspace"):
...
Getting a paperspace layout
paperspace = doc.paperspace("layout0")
The code above retrieves the paperspace named layout0, the usage of the Paperspace object is the same as
of the modelspace object. DXF R12 provides only one paperspace, therefore the paperspace name in the
method call doc.paperspace("layout0") is ignored or can be left off. For newer DXF versions you can get
a list of the available layout names by the methods layout_names() and layout_names_in_taborder().
Retrieve entities by query language
Ezdxf provides a flexible query language for DXF entities. All layout types have a query() method to
start an entity query or use the ezdxf.query.new() function.
The query string is the combination of two queries, first the required entity query and second the
optional attribute query, enclosed in square brackets: "EntityQuery[AttributeQuery]"
The entity query is a whitespace separated list of DXF entity names or the special name *. Where * means
all DXF entities, all DXF names have to be uppercase. The * search can exclude entity types by adding the
entity name with a preceding ! (e.g. * !LINE, search all entities except lines).
The attribute query is used to select DXF entities by its DXF attributes. The attribute query is an
addition to the entity query and matches only if the entity already match the entity query. The attribute
query is a boolean expression, supported operators: and, or, !.
SEE ALSO:
Entity Query String
Get all LINE entities from the modelspace:
msp = doc.modelspace()
lines = msp.query("LINE")
The result container EntityQuery also provides the query() method to further refine the query, such as
retrieving all LINE entities at layer construction:
construction_lines = lines.query('*[layer=="construction"]')
The * is a wildcard for all DXF types, in this case you could also use LINE instead of *, * works here
because the source just contains LINE entities.
This could be executed as a single query:
lines = msp.query('LINE[layer=="construction"]')
An advanced query for getting all modelspace entities at layer construction, but excluding entities with
linetype DASHED:
not_dashed_entities = msp.query('*[layer=="construction" and linetype!="DASHED"]')
Extended EntityQuery Features
The EntityQuery class has properties and overloaded operators to build extended queries by Python
features instead of a query string.
Same task as in the previous section but using features of the EntityQuery container:
# The overloaded rational operators return an EntityQuery object and not a bool value!
lines = msp.query("LINES").layer == "construction"
not_dashed_lines = lines.linetype != "DASHED"
SEE ALSO:
Extended EntityQuery Features
Retrieve entities by groupby() function
The groupby() function searches and group entities by a user defined criteria. As an example let’s group
all entities from modelspace by layer, the result will be a dict with layer names as dict-key and a list
of all entities from the modelspace matching this layer as dict-value:
from ezdxf.groupby import groupby
group = groupby(entities=msp, dxfattrib="layer")
The entities argument can be any container or generator which yields DXF entities:
group = msp.groupby(dxfattrib="layer")
for layer, entities in group.items():
print(f'Layer "{layer}" contains following entities:')
for entity in entities:
print(f" {entity}")
print("-"*40)
The previous example shows how to group entities by a single DXF attribute. For a more advanced query
create a custom key function, which accepts a DXF entity as argument and returns a hashable value as
dict-key or None to exclude the entity.
The following example shows how to group entities by layer and color, the dict-key is a (layer, color)
tuple and the dict-value is a list of entities with matching DXF attributes:
def layer_and_color_key(entity):
# return None to exclude entities from the result container
if entity.dxf.layer == "0": # exclude entities from default layer "0"
return None
else:
return entity.dxf.layer, entity.dxf.color
group = msp.groupby(key=layer_and_color_key)
for key, entities in group.items():
print(f'Grouping criteria "{key}" matches following entities:')
for entity in entities:
print(f" {entity}")
print("-"*40)
The groupby() function catches DXFAttributeError exceptions while processing entities and excludes this
entities from the result. There is no need to worry about DXF entities which do not support certain
attributes, they will be excluded automatically.
SEE ALSO:
groupby() documentation
Tutorial for Creating DXF Drawings
Create a new DXF document by the ezdxf.new() function:
import ezdxf
# create a new DXF R2010 document
doc = ezdxf.new("R2010")
# add new entities to the modelspace
msp = doc.modelspace()
# add a LINE entity
msp.add_line((0, 0), (10, 0))
# save the DXF document
doc.saveas("line.dxf")
New entities are always added to layouts, a layout can be the modelspace, a paperspace layout or a block
layout.
SEE ALSO:
Thematic Index of Layout Factory Methods
Predefined Resources
Ezdxf creates new DXF documents with as little content as possible, this means only the resources that
are absolutely necessary are created. The ezdxf.new() function can create some standard resources, such
as linetypes and text styles, by setting the argument setup to True.
import ezdxf
doc = ezdxf.new("R2010", setup=True)
msp = doc.modelspace()
msp.add_line((0, 0), (10, 0), dxfattribs={"linetype": "DASHED"})
The defined standard linetypes are shown in the basic concept section for Linetypes and the available
text styles are shown in the Tutorial for Text.
IMPORTANT:
To see the defined text styles in a DXF viewer or CAD application, the applications have to know where
the referenced TTF fonts can be found. This configuration is not possible by ezdxf and has to be done
for each application as described in their documentation.
See also: Font Resources
Simple DXF R12 drawings
The r12writer add-on creates simple DXF R12 drawings with a restricted set of DXF types: LINE, CIRCLE,
ARC, TEXT, POINT, SOLID, 3DFACE and POLYLINE.
The advantage of the r12writer is the speed and the small memory footprint, all entities are written
directly to a file or stream without creating a document structure in memory.
SEE ALSO:
r12writer
Tutorial for Common Graphical Attributes
The graphical attributes color, linetype, lineweight, true_color, transparency, ltscale and invisible are
available for all graphical DXF entities and are located in the DXF namespace attribute dxf of the DXF
entities. All these attributes are optional and all except for true_color and transparency have a
default value.
Not all of these attributes are supported by all DXF versions. This table shows the minimum required DXF
version for each attribute:
┌───────┬────────────────────────────────┐
│ R12 │ color, linetype │
├───────┼────────────────────────────────┤
│ R2000 │ lineweight, ltscale, invisible │
├───────┼────────────────────────────────┤
│ R2004 │ true_color, transparency │
└───────┴────────────────────────────────┘
Color
Please read the section about the AutoCAD Color Index (ACI) to understand the basics.
The usage of the color attribute is very straight forward. Setting the value is:
entity.dxf.color = 1
and getting the value looks like this:
value = entity.dxf.color
The color attribute has a default value of 256, which means take the color defined by the layer
associated to the entity. The ezdxf.colors module defines some constants for often used color values:
entity.dxf.color = ezdxf.colors.RED
The ezdxf.colors.aci2rgb() function converts the ACI value to the RGB value of the default modelspace
palette.
SEE ALSO:
• Basics about AutoCAD Color Index (ACI)
• ezdxf.colors module
True Color
Please read the section about True Color to understand the basics.
The easiest way is to use the rgb property to set and get the true color values as RGB tuples:
entity.rgb = (255, 128, 16)
The rgb property return None if the true_color attribute is not present:
rgb = entity.rgb
if rgb is not None:
r, g, b = rgb
Setting and getting the true_color DXF attribute directly is possible and the ezdxf.colors module has
helper function to convert RGB tuples to 24-bit value and back:
entity.dxf.true_color = ezdxf.colors.rgb2int(255, 128, 16)
The true_color attribute is optional does not have a default value and therefore it is not safe to use
the attribute directly, check if the attribute exists beforehand:
if entity.dxf.hasattr("true_color"):
r, g, b = ezdxf.colors.int2rgb(entity.dxf.true_color)
or use the get() method of the dxf namespace attribute to get a default value if the attribute does not
exist:
r, g, b = ezdxf.colors.int2rgb(entity.dxf.get("true_color", 0)
SEE ALSO:
• Basics about True Color
• ezdxf.colors module
Transparency
Please read the section about Transparency to understand the basics.
It’s recommended to use the transparency property of the DXFGraphic base class. The transparency
property is a float value in the range from 0.0 to 1.0 where 0.0 is opaque and 1.0 if fully transparent:
entity.transparency = 0.5
or set the values of the DXF attribute by constants defined in the ezdxf.colors module:
entity.dxf.transparency = ezdxf.colors.TRANSPARENCY_50
The default setting for transparency in CAD applications is always transparency by layer, but the
transparency property in ezdxf has a default value of 0.0 (opaque), so there are additional entity
properties to check if the transparency value should be taken from the associated entity layer or from
the parent block:
if entity.is_transparency_by_layer:
...
elif entity.is_transparency_by_block:
...
else:
...
The top level entity attribute transparency does not support setting transparency by layer or block:
from ezdxf import colors
...
# set transparency by layer by removing the DXF attribute "transparency":
entity.dxf.discard("transparency")
# set transparency by block:
entity.dxf.transparency = colors.TRANSPARENCY_BYBLOCK
# there are also some handy constants in the colors module:
# TRANSPARENCY_10 upto TRANSPARENCY_90 in steps of 10
entity.dxf.transparency = colors.TRANSPARENCY_30 # set 30% transparency
entity.dxf.transparency = colors.OPAQUE
SEE ALSO:
• Basics about Transparency
• ezdxf.colors module
Linetype
Please read the section about Linetypes to understand the basics.
The linetype attribute contains the name of the linetype as string and can be set by the dxf namespace
attribute directly:
entity.dxf.linetype = "DASHED" # linetype DASHED must exist!
The linetype attribute is optional and has a default value of “BYLAYER”, so the attribute can always be
used without any concerns:
name = entity.dxf.linetype
WARNING:
Make sure the linetype you assign to an entity is really defined in the linetype table otherwise
AutoCAD will not open the DXF file. There are no implicit checks for that by ezdxf but you can call
the audit() method of the DXF document explicitly to validate the document before exporting.
Ezdxf creates new DXF documents with as little content as possible, this means only the resources that
are absolutely necessary are created. The ezdxf.new() function can create some standard linetypes by
setting the argument setup to True:
doc = ezdxf.new("R2010", setup=True)
SEE ALSO:
• Basics about Linetypes
• Tutorial for Creating Linetype Pattern
Lineweight
Please read the section about Lineweights to understand the basics.
The lineweight attribute contains the lineweight as an integer value and can be set by the dxf namespace
attribute directly:
entity.dxf.lineweight = 25
The lineweight value is the line width in millimeters times 100 e.g. 0.25mm = 25, but only certain
values are valid for more information go to section: Lineweights.
Values < 0 have a special meaning and can be imported as constants from ezdxf.lldxf.const
┌────┬────────────────────┐
│ -1 │ LINEWEIGHT_BYLAYER │
├────┼────────────────────┤
│ -2 │ LINEWEIGHT_BYBLOCK │
├────┼────────────────────┤
│ -3 │ LINEWEIGHT_DEFAULT │
└────┴────────────────────┘
The lineweight attribute is optional and has a default value of -1, so the attribute can always be used
without any concerns:
lineweight = entity.dxf.lineweight
IMPORTANT:
You have to enable the option to show lineweights in your CAD application or viewer to see the effect
on screen, which is disabled by default, the same has to be done in the page setup options for
plotting lineweights.
# activate on screen lineweight display
doc.header["$LWDISPLAY"] = 1
SEE ALSO:
• Basics about Lineweights
Linetype Scale
The ltscale attribute scales the linetype pattern by a float value and can be set by the dxf namespace
attribute directly:
entity.dxf.ltscale = 2.0
The ltscale attribute is optional and has a default value of 1.0, so the attribute can always be used
without any concerns:
scale = entity.dxf.ltscale
SEE ALSO:
• Basics about Linetypes
Invisible
The invisible attribute an boolean value (0/1) which defines if an entity is invisible or visible and can
be set by the dxf namespace attribute directly:
entity.dxf.invisible = 1
The invisible attribute is optional and has a default value of 0, so the attribute can always be used
without any concerns:
is_invisible = bool(entity.dxf.invisible)
GfxAttribs
When adding new entities to an entity space like the modelspace or a block definition, the factory
methods expect the graphical DXF attributes by the argument dxfattribs. This object can be a Python dict
where the key is the DXF attribute name and the value is the attribute value, or better use the
GfxAttribs object which has some additional validation checks and support for code completions by IDEs:
import ezdxf
from ezdxf.gfxattribs import GfxAttribs
doc = ezdxf.new()
msp = doc.modelspace()
line = msp.add_line(
(0, 0), (10, 10), dxfattribs=GfxAttribs(layer="0", rgb=(25, 128, 16))
)
SEE ALSO:
• ezdxf.gfxattribs module
Tutorial for Layers
If you are not familiar with the concept of layers, please read this first: Concept of Layers
Reminder: a layer definition is not required for using a layer!
Create a Layer Definition
import ezdxf
doc = ezdxf.new(setup=True) # setup required line types
msp = doc.modelspace()
doc.layers.add(name="MyLines", color=7, linetype="DASHED")
The advantage of assigning a linetype and a color to a layer is that entities on this layer can inherit
this properties by using "BYLAYER" as linetype string and 256 as color, both values are default values
for new entities so you can leave off these assignments:
msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "MyLines"})
The new created line will be drawn with color 7 and linetype "DASHED".
Moving an Entity to a Different Layer
Moving an entity to a different layer is a simple assignment of the new layer name to the layer attribute
of the entity.
line = msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "MyLines"})
# move the entity to layer "OtherLayer"
line.dxf.layer = "OtherLayer"
Changing Layer State
Get the layer definition object from the layer table:
my_lines = doc.layers.get('MyLines')
Check the state of the layer:
my_lines.is_off() # True if layer is off
my_lines.is_on() # True if layer is on
my_lines.is_locked() # True if layer is locked
layer_name = my_lines.dxf.name # get the layer name
Change the state of the layer:
# switch layer off, entities at this layer will not shown in CAD applications/viewers
my_lines.off()
# lock layer, entities at this layer are not editable in CAD applications
my_lines.lock()
Get/set the color of a layer by property Layer.color, because the DXF attribute Layer.dxf.color is
misused for switching the layer on and off, the layer is off if the color value is negative.
Changing the layer properties:
my_lines.dxf.linetype = "DOTTED"
my_lines.color = 13 # preserves on/off state of layer
SEE ALSO:
For all methods and attributes see class Layer.
Check Available Layers
The LayerTable object supports some standard Python protocols:
# iteration
for layer in doc.layers:
if layer.dxf.name != "0":
layer.off() # switch all layers off except layer "0"
# check for existing layer definition
if "MyLines" in doc.layers:
layer = doc.layers.get("MyLines")
layer_count = len(doc.layers) # total count of layer definitions
Renaming a Layer
The Layer class has a method for renaming the layer, but has same limitations, not all places where layer
references can occur are documented, third-party entities are black-boxes with unknown content and layer
references could be stored in the extended data section of any DXF entity or in a XRECORD entity, so some
references may reference a non-existing layer definition after the renaming, at least these references
are still valid, because a layer definition is not required for using a layer.
my_lines = doc.layers.get("MyLines")
my_lines.rename("YourLines")
Deleting a Layer Definition
Delete a layer definition:
doc.layers.remove("MyLines")
This just deletes the layer definition, all DXF entities referencing this layer still exist, if they
inherit any properties from the deleted layer they will now get the default layer properties.
WARNING:
The behavior of entities referencing the layer by handle is unknown and may break the DXF document.
Deleting All Entities From a Layer
Because of all these uncertainties about layer references mentioned above, deleting all entities
referencing a certain layer from a DXF document is not implemented as an API call!
Nonetheless deleting all graphical entities from the DXF document which do reference a certain layer by
the layer attribute is a safe procedure:
key_func = doc.layers.key
layer_key = key_func("MyLines")
# The trashcan context-manager is a safe way to delete entities from the
# entities database while iterating.
with doc.entitydb.trashcan() as trash:
for entity in doc.entitydb.values():
if not entity.dxf.hasattr("layer"):
continue
if layer_key == key_func(entity.dxf.layer):
# safe destruction while iterating
trash.add(entity.dxf.handle)
Tutorial for Creating Linetype Pattern
Simple line type example: [image]
You can define your own linetypes. A linetype definition has a name, a description and line pattern
elements:
elements = [total_pattern_length, elem1, elem2, ...]
total_pattern_length
Sum of all linetype elements (absolute values)
elem if elem > 0 it is a line, if elem < 0 it is gap, if elem == 0.0 it is a dot
Create a new linetype definition:
import ezdxf
from ezdxf.tools.standards import linetypes # some predefined linetypes
doc = ezdxf.new()
msp = doc.modelspace()
my_line_types = [
(
"DOTTED",
"Dotted . . . . . . . . . . . . . . . .",
[0.2, 0.0, -0.2],
),
(
"DOTTEDX2",
"Dotted (2x) . . . . . . . . ",
[0.4, 0.0, -0.4],
),
(
"DOTTED2",
"Dotted (.5) . . . . . . . . . . . . . . . . . . . ",
[0.1, 0.0, -0.1],
),
]
for name, desc, pattern in my_line_types:
if name not in doc.linetypes:
doc.linetypes.add(
name=name,
pattern=pattern,
description=desc,
)
Setup some predefined linetypes:
for name, desc, pattern in linetypes():
if name not in doc.linetypes:
doc.linetypes.add(
name=name,
pattern= pattern,
description=desc,
)
Check Available Linetypes
The linetypes object supports some standard Python protocols:
# iteration
print("available linetypes:")
for lt in doc.linetypes:
print(f"{lt.dxf.name}: {lt.dxf.description}")
# check for existing linetype
if "DOTTED" in doc.linetypes:
pass
count = len(doc.linetypes) # total count of linetypes
Removing Linetypes
WARNING:
Ezdxf does not check if a linetype is still in use and deleting a linetype which is still in use
generates an invalid DXF file. The audit process audit() of the DXF document removes linetype
attributes referencing non existing linetypes.
You can delete a linetype:
doc.layers.remove("DASHED")
This just removes the linetype definition, the linetype attribute of DXF entities may still refer the
removed linetype definition “DASHED” and AutoCAD will not open DXF files including undefined linetypes.
Tutorial for Creating Complex Linetype Pattern
In DXF R13 Autodesk introduced complex linetypes, containing TEXT or SHAPES in line types.
Complex linetype example with text: [image]
Complex line type example with shapes: [image]
For easy usage the pattern string for complex line types is mostly the same string as the pattern
definition strings in AutoCAD “.lin” files.
Example for complex line type TEXT:
doc = ezdxf.new("R2018") # DXF R13 or later is required
doc.linetypes.add(
name="GASLEITUNG2",
# linetype definition string from acad.lin:
pattern='A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25',
description= "Gasleitung2 ----GAS----GAS----GAS----GAS----GAS----",
length=1, # required for complex line types
})
The pattern always starts with an “A”, the following float values have the same meaning as for simple
linetypes, a value > 0 is a line, a value < 0 is a gap, and a 0 is a point, the opening square bracket
“[” starts the complex part of the linetype pattern.
The text after the “[” defines the complex linetype:
• A text in quotes (e.g. “GAS”) defines a complex TEXT linetype and represents the pattern text itself.
• A text without quotes is a SHAPE name (in “.lin” files) and defines a complex SHAPE linetype. Ezdxf can
not translate this SHAPE name from the “.lin” file into the required shape file index, so *YOU have to
translate this SHAPE name into the shape file index, e.g. saving the file with AutoCAD as DXF and
searching for the DXF linetype definition, see example below and the DXF Internals: LTYPE Table.
For complex TEXT linetypes the second parameter is the text style, for complex SHAPE linetypes the second
parameter is the shape file name, the shape file has to be in the same directory as the DXF file or in
one of the CAD application support paths.
The meaning of the following comple linetype parameters are shown in the table below:
┌────────┬───────────────────────────────────────┐
│ S │ scaling factor, always > 0, if S=0 │
│ │ the TEXT or SHAPE is not visible │
├────────┼───────────────────────────────────────┤
│ R or U │ rotation relative to the line │
│ │ direction │
├────────┼───────────────────────────────────────┤
│ X │ x-direction offset (along the line) │
├────────┼───────────────────────────────────────┤
│ Y │ y-direction offset (perpendicular to │
│ │ the line) │
└────────┴───────────────────────────────────────┘
These parameters are case insensitive and the closing square bracket “]” ends the complex part of the
linetype pattern.
The fine tuning of this parameters is a try an error process, for complex TEXT linetypes the scaling
factor (e.g. the STANDARD text style) sets the text height (e.g. “S=0.1” sets the text height to 0.1
units), by shifting in y-direction by half of the scaling factor, the text is vertically centered to the
line. For the x-direction it seems to be a good practice to place a gap in front of the text and after
the text, find x shifting value and gap sizes by try and error. The overall length is at least the sum of
all line and gap definitions (absolute values).
Example for complex line type SHAPE:
doc.linetypes.add("GRENZE2",
# linetype definition in acad.lin:
# A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1
# replacing BOX by shape index 132 (got index from an AutoCAD file),
# ezdxf can't get shape index from ltypeshp.shx
pattern="A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1",
description="Grenze eckig ----[]-----[]----[]-----[]----[]--",
length= 1.45, # required for complex line types
})
Complex line types with shapes only work if the associated shape file (e. g. ltypeshp.shx) and the DXF
file are in the same directory or the shape file is placed in one of the CAD application support folders.
Tutorial for Simple DXF Entities
These are basic graphical entities located in an entity space like the modelspace or a block definition
and only support the common graphical attributes.
The entities in the following examples are always placed in the xy-plane of the WCS aka the 2D drawing
space. Some of these entities can only be placed outside the xy-plane in 3D space by utilizing the OCS,
but this feature is beyond the scope of this tutorial, for more information about that go to: Tutorial
for OCS/UCS Usage.
Prelude to all following examples:
import ezdxf
from ezdxf.gfxattribs import GfxAttribs
doc = ezdxf.new()
doc.layers.new("ENTITY", color=1)
msp = doc.modelspace()
attribs = GfxAttribs(layer="ENTITY")
SEE ALSO:
• Tutorial for Creating DXF Drawings
• Tutorial for Layers
• ezdxf.gfxattribs module
Point
The Point entity marks a 3D point in the WCS:
point = msp.add_point((10, 10), dxfattribs=attribs)
All Point entities have the same styling stored in the header variable $PDMODE, for more information read
the reference of class Point.
SEE ALSO:
• Reference of class Point
• Tutorial for Common Graphical Attributes
Line
The Line entity is a 3D line with a start- and an end point in the WCS:
line = msp.add_line((0, 0), (10, 10), dxfattribs=attribs)
SEE ALSO:
• Reference of class Line
• Tutorial for Common Graphical Attributes
• ezdxf.math.ConstructionLine
Circle
The Circle entity is an OCS entity defined by a center point and a radius:
circle = msp.add_circle((10, 10), radius=3, dxfattribs=attribs)
SEE ALSO:
• Reference of class Circle
• Tutorial for Common Graphical Attributes
• ezdxf.math.ConstructionCircle
Arc
The Arc entity is an OCS entity defined by a center point, a radius a start- and an end angle in
degrees:
arc = msp.add_arc((10, 10), radius=3, start_angle=30, end_angle=120, dxfattribs=attribs)
The arc goes always in counter-clockwise orientation around the z-axis more precisely the extrusion
vector of OCS, but this is beyond the scope of this tutorial.
The helper class ezdxf.math.ConstructionArc provides constructors to create arcs from different
scenarios:
• from_2p_angle: arc from 2 points and an angle
• from_2p_radius: arc from 2 points and a radius
• from_3p: arc from 3 points
This example creates an arc from point (10, 0) to point (0, 0) passing the point (5, 3):
from ezdxf.math import ConstructionArc
# -x-x-x- snip -x-x-x-
arc = ConstructionArc.from_3p(
start_point=(10, 0), end_point=(0, 0), def_point=(5, 3)
)
arc.add_to_layout(msp, dxfattribs=attribs)
SEE ALSO:
• Reference of class Arc
• Tutorial for Common Graphical Attributes
• ezdxf.math.ConstructionArc
Ellipse
The Ellipse entity requires DXF R2000 or newer and is a true WCS entity. The ellipse is defined by a
center point, a vector for the major axis, the ratio between major- and minor axis and the start- and end
parameter in radians:
ellipse = msp.add_ellipse(
(10, 10), major_axis=(5, 0), ratio=0.5, start_param=0, end_param=math.pi, dxfattribs=attribs
)
When placed in 3D space the extrusion vector defines the normal vector of the ellipse plane and the minor
axis is the extrusion vector cross the major axis.
SEE ALSO:
• Reference of class Ellipse
• Tutorial for Common Graphical Attributes
• ezdxf.math.ConstructionEllipse
Further Tutorials
• Tutorial for LWPolyline
• Tutorial for Spline
• Tutorial for Text
• Tutorial for MText and MTextEditor
• Tutorial for Hatch
• Tutorial for MultiLeader
• Tutorial for Mesh
Tutorial for Blocks
If you are not familiar with the concept of blocks, please read this first: Concept of Blocks
Create a Block
Blocks are managed as BlockLayout objects by the BlocksSection object, every drawing has only one blocks
section referenced by attribute Drawing.blocks.
import ezdxf
import random # needed for random placing points
def get_random_point():
"""Returns random x, y coordinates."""
x = random.randint(-100, 100)
y = random.randint(-100, 100)
return x, y
# Create a new drawing in the DXF format of AutoCAD 2010
doc = ezdxf.new('R2010')
# Create a block with the name 'FLAG'
flag = doc.blocks.new(name='FLAG')
# Add DXF entities to the block 'FLAG'.
# The default base point (= insertion point) of the block is (0, 0).
flag.add_lwpolyline([(0, 0), (0, 5), (4, 3), (0, 3)]) # the flag symbol as 2D polyline
flag.add_circle((0, 0), .4, dxfattribs={'color': 2}) # mark the base point with a circle
Block References (Insert)
A block reference can be created by adding an Insert entity to any of these layout types:
• Modelspace
• Paperspace
• BlockLayout
A block reference can be scaled and rotated individually. Lets add some random flags to the modelspace:
# Get the modelspace of the drawing.
msp = doc.modelspace()
# Get 50 random placing points.
placing_points = [get_random_point() for _ in range(50)]
for point in placing_points:
# Every flag has a different scaling and a rotation of -15 deg.
random_scale = 0.5 + random.random() * 2.0
# Add a block reference to the block named 'FLAG' at the coordinates 'point'.
msp.add_blockref('FLAG', point, dxfattribs={
'xscale': random_scale,
'yscale': random_scale,
'rotation': -15
})
# Save the drawing.
doc.saveas("blockref_tutorial.dxf")
Query all block references of block FLAG:
for flag_ref in msp.query('INSERT[name=="FLAG"]'):
print(str(flag_ref))
When adding a block reference to a layout with different units, the scaling factor between these units
should be applied as scaling attributes (xscale, …) e.g. modelspace in meters and block in centimeters,
xscale has to be 0.01.
Block Attributes
A block attribute (Attrib) is a text annotation attached to a block reference with an associated tag.
Attributes are often used to add information to blocks which can be evaluated and exported by CAD
applications. An attribute can be added to a block reference by the Insert.add_attrib() method, the
ATTRIB entity is geometrically not related to the block reference, so insertion point, rotation and
scaling of the attribute have to be calculated by the user, but helper tools for that do exist.
Using Attribute Definitions
Another way to add attributes to block references is using attribute templates (AttDef). First create the
attribute definition in the block definition, then add the block reference by add_blockref() and attach
and fill attributes automatically by the add_auto_attribs() method to the block reference. This method
has the advantage that all attributes are placed relative to the block base point with the same rotation
and scaling as the block reference, but non-uniform scaling is not handled very well.
The add_auto_blockref() method handles non-uniform scaling better by wrapping the block reference and its
attributes into an anonymous block and let the CAD application do the transformation work. This method
has the disadvantage of a more complex evaluation of attached attributes
Using attribute definitions (AttDef templates):
# Define some attributes for the block 'FLAG', placed relative
# to the base point, (0, 0) in this case.
flag.add_attdef('NAME', (0.5, -0.5), dxfattribs={'height': 0.5, 'color': 3})
flag.add_attdef('XPOS', (0.5, -1.0), dxfattribs={'height': 0.25, 'color': 4})
flag.add_attdef('YPOS', (0.5, -1.5), dxfattribs={'height': 0.25, 'color': 4})
# Get another 50 random placing points.
placing_points = [get_random_point() for _ in range(50)]
for number, point in enumerate(placing_points):
# values is a dict with the attribute tag as item-key and
# the attribute text content as item-value.
values = {
'NAME': "P(%d)" % (number + 1),
'XPOS': "x = %.3f" % point[0],
'YPOS': "y = %.3f" % point[1]
}
# Every flag has a different scaling and a rotation of +15 deg.
random_scale = 0.5 + random.random() * 2.0
blockref = msp.add_blockref('FLAG', point, dxfattribs={
'rotation': 15
}).set_scale(random_scale)
blockref.add_auto_attribs(values)
# Save the drawing.
doc.saveas("auto_blockref_tutorial.dxf")
Get/Set Attributes of Existing Block References
See the howto: Get/Set Block Reference Attributes
Evaluate Wrapped Block References
As mentioned above the evaluation of block references wrapped into anonymous blocks is complex:
# Collect all anonymous block references starting with '*U'
anonymous_block_refs = modelspace.query('INSERT[name ? "^\*U.+"]')
# Collect the references of the 'FLAG' block
flag_refs = []
for block_ref in anonymous_block_refs:
# Get the block layout of the anonymous block
block = doc.blocks.get(block_ref.dxf.name)
# Find all block references to 'FLAG' in the anonymous block
flag_refs.extend(block.query('INSERT[name=="FLAG"]'))
# Evaluation example: collect all flag names.
flag_numbers = [
flag.get_attrib_text("NAME")
for flag in flag_refs
if flag.has_attrib("NAME")
]
print(flag_numbers)
Exploding Block References
This is an advanced feature and the results may not be perfect. A non-uniform scaling lead to incorrect
results for text entities (TEXT, MTEXT, ATTRIB) and some other entities like HATCH with circular- or
elliptic path segments. The “exploded” entities are added to the same layout as the block reference by
default.
for flag_ref in msp.query('INSERT[name=="FLAG"]'):
flag_ref.explode()
Examine Entities of Block References
To just examine the content entities of a block reference use the virtual_entities() method. This
methods yields “virtual” entities with properties identical to “exploded” entities but they are not
stored in the entity database, have no handle and are not assigned to any layout.
for flag_ref in msp.query('INSERT[name=="FLAG"]'):
for entity in flag_ref.virtual_entities():
if entity.dxftype() == "LWPOLYLINE":
print(f"Found {str(entity)}.")
Tutorial for LWPolyline
The LWPolyline (lightweight polyline) was introduced in DXF R13/14 and it is defined as a single graphic
entity, which differs from the old-style Polyline entity, which is defined as a group of sub-entities. It
is recommended to prefer the LWPOLYLINE over the 2D POLYLINE entity because it requires less space in
memory and in DXF files and displays faster in AutoCAD.
IMPORTANT:
The LWPOLYLINE is a planar element, therefore the (x, y) point coordinates are located in the OCS and
the z-axis is stored in the LWPolyline.dxf.elevation attribute. The method vertices_in_wcs returns
the polyline vertices as WCS coordinates.
Create a simple polyline:
import ezdxf
doc = ezdxf.new("R2000")
msp = doc.modelspace()
points = [(0, 0), (3, 0), (6, 3), (6, 6)]
msp.add_lwpolyline(points)
doc.saveas("lwpolyline1.dxf")
Append multiple points to a polyline:
doc = ezdxf.readfile("lwpolyline1.dxf")
msp = doc.modelspace()
line = msp.query("LWPOLYLINE").first
if line is not None:
line.append_points([(8, 7), (10, 7)])
doc.saveas("lwpolyline2.dxf")
The index operator [] always returns polyline points as 5-tuple (x, y, start_width, end_width, bulge),
the start_width, end_width and bulge values are 0 if not present:
first_point = line[0]
x, y, start_width, end_width, bulge = first_point
The context manager points() can be used to edit polyline points, this method was introduced because
accessing individual points was very slow in early versions of ezdxf, in current versions of ezdxf the
direct access by the index operator [] is very fast and using the context manager is not required
anymore, but the context manager still exist and has the advantage of supporting an user defined point
format:
doc = ezdxf.readfile("lwpolyline2.dxf")
msp = doc.modelspace()
line = msp.query("LWPOLYLINE").first
with line.points("xyseb") as points:
# points is a standard Python list
# existing points are 5-tuples, but new points can be
# set as (x, y, [start_width, [end_width, [bulge]]]) tuple
# set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).
# delete last 2 points
del points[-2:]
# adding two points
points.extend([(4, 7), (0, 7)])
doc.saveas("lwpolyline3.dxf")
Each line segment can have a different start- and end width, if omitted start- and end width is 0:
doc = ezdxf.new("R2000")
msp = doc.modelspace()
# point format = (x, y, [start_width, [end_width, [bulge]]])
# set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).
points = [(0, 0, .1, .15), (3, 0, .2, .25), (6, 3, .3, .35), (6, 6)]
msp.add_lwpolyline(points)
doc.saveas("lwpolyline4.dxf")
The first point carries the start- and end-width of the first segment, the second point of the second
segment and so on, the start- and end width value of the last point is used for the closing segment if
the polyline is closed else these values are ignored. Start- and end width only works if the DXF
attribute dxf.const_width is unset, delete it to be sure it’s unset:
# no exception will be raised if const_width is already unset:
del line.dxf.const_width
LWPolyline can also have curved elements, they are defined by the Bulge value:
doc = ezdxf.new("R2000")
msp = doc.modelspace()
# point format = (x, y, [start_width, [end_width, [bulge]]])
# set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).
points = [(0, 0, 0, .05), (3, 0, .1, .2, -.5), (6, 0, .1, .05), (9, 0)]
msp.add_lwpolyline(points)
doc.saveas("lwpolyline5.dxf")
[image]
The curved segment is drawn from the point which defines the bulge value to the following point, the
curved segment is always an arc. The bulge value defines the ratio of the arc sagitta (segment height h)
to half line segment length (point distance), a bulge value of 1 defines a semicircle. The curve is on
the right side of the line for a bulge value > 0, and on the left side of the line for a bulge value < 0.
Helper functions to handle bulge values: Bulge Related Functions
The user defined point format, default is xyseb:
• x = x coordinate
• y = y coordinate
• s = start width
• e = end width
• b = bulge value
• v = (x, y) as tuple
msp.add_lwpolyline([(0, 0, 0), (10, 0, 1), (20, 0, 0)], format="xyb")
msp.add_lwpolyline([(0, 10, 0), (10, 10, .5), (20, 10, 0)], format="xyb")
[image]
Tutorial for Text
Add a simple one line text entity by factory function add_text().
import ezdxf
from ezdxf.enums import TextEntityAlignment
# The TEXT entity is a DXF primitive and is supported in all DXF versions.
# The argument setup=True creates standard linetypes and text styles in the
# new DXF document.
doc = ezdxf.new("R12", setup=True)
msp = doc.modelspace()
# Use method set_placement() to define the TEXT alignment, because the
# relations between the DXF attributes 'halign', 'valign', 'insert' and
# 'align_point' are tricky.
msp.add_text("A Simple Text").set_placement(
(2, 3),
align=TextEntityAlignment.MIDDLE_RIGHT
)
# Using a predefined text style:
msp.add_text(
"Text Style Example: Liberation Serif",
height=0.35,
dxfattribs={"style": "LiberationSerif"}
).set_placement((2, 6), align=TextEntityAlignment.LEFT)
doc.saveas("simple_text.dxf")
Alignments defined by the enum TextEntityAlignment:
┌────────────┬─────────────┬───────────────┬──────────────┐
│ Vert/Horiz │ Left │ Center │ Right │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Top │ TOP_LEFT │ TOP_CENTER │ TOP_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Middle │ MIDDLE_LEFT │ MIDDLE_CENTER │ MIDDLE_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Bottom │ BOTTOM_LEFT │ BOTTOM_CENTER │ BOTTOM_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Baseline │ LEFT │ CENTER │ RIGHT │
└────────────┴─────────────┴───────────────┴──────────────┘
Special alignments are ALIGNED and FIT, they require a second alignment point, the text is justified with
the vertical alignment Baseline on the virtual line between these two points.
┌───────────┬───────────────────────────────────────┐
│ Alignment │ Description │
├───────────┼───────────────────────────────────────┤
│ ALIGNED │ Text is stretched or compressed to │
│ │ fit exactly between p1 and p2 and the │
│ │ text height is also adjusted to │
│ │ preserve height/width ratio. │
├───────────┼───────────────────────────────────────┤
│ FIT │ Text is stretched or compressed to │
│ │ fit exactly between p1 and p2 but │
│ │ only the text width is adjusted, the │
│ │ text height is fixed by the height │
│ │ attribute. │
├───────────┼───────────────────────────────────────┤
│ MIDDLE │ also a special adjustment, but the │
│ │ result is the same as for │
│ │ MIDDLE_CENTER. │
└───────────┴───────────────────────────────────────┘
Standard Text Styles
Setup some standard text styles and linetypes by argument setup=True:
doc = ezdxf.new('R12', setup=True)
Replaced all proprietary font declarations in setup_styles() (ARIAL, ARIAL_NARROW, ISOCPEUR and TIMES) by
open source fonts, this is also the style name (e.g. {'style': 'OpenSans-Italic'}): [image]
IMPORTANT:
To see the defined text styles in a DXF viewer or CAD application, the applications have to know where
the referenced TTF fonts can be found. This configuration is not possible by ezdxf and has to be done
for each application as described in their documentation.
See also: Font Resources
New Text Style
Creating a new text style is simple:
doc.styles.new("myStandard", dxfattribs={"font" : "OpenSans-Regular.ttf"})
Getting the correct font name is often not that simple, especially on Windows. This shows the required
steps to get the font name for Open Sans:
• open font folder c:\windows\fonts
• select and open the font-family Open Sans
• right-click on Open Sans Standard and select Properties
• on top of the first tab you see the font name: 'OpenSans-Regular.ttf'
The style name has to be unique in the DXF document, otherwise ezdxf will raise an DXFTableEntryError
exception. To replace an existing entry, delete the existing entry by doc.styles.remove(name), and add
the replacement entry.
3D Text
It is possible to place the 2D Text entity into 3D space by using the OCS, for further information see:
Tutorial for OCS/UCS Usage and Tutorial for UCS Based Transformations.
Tutorial for MText and MTextEditor
The MText entity is a multi line entity with extended formatting possibilities and requires at least DXF
version R2000, to use all features (e.g. background fill) DXF R2007 is required.
IMPORTANT:
The rendering result of the MTEXT entity depends on the DXF viewer or CAD application and can differ
between different applications. These differences have the greatest impact on line wrapping, which can
cause columns of text to have different heights in different applications!
In order for the text to look similar in different programs, the formatting should be as simple as
possible or omitted altogether.
Prolog code:
import ezdxf
doc = ezdxf.new("R2007", setup=True)
msp = doc.modelspace()
lorem_ipsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
"""
Adding a MTEXT entity
The MTEXT entity can be added to any layout (modelspace, paperspace or block) by the add_mtext()
function.
# store MTEXT entity for additional manipulations
mtext = msp.add_mtext(lorem_ipsum, dxfattribs={"style": "OpenSans"})
This adds a MTEXT entity with text style “OpenSans”. The MTEXT content can be accessed by the text
attribute, this attribute can be edited like any Python string:
mtext.text += "Append additional text to the MTEXT entity."
# even shorter with __iadd__() support:
mtext += "Append additional text to the MTEXT entity."
[image]
The MText entity has an alias MText.dxf.text for the MText.text attribute for compatibility to the Text
entity.
IMPORTANT:
Line endings “\n” will be replaced by the MTEXT line endings “\P” at DXF export, but not vice versa
“\P” by “\n” at DXF file loading.
Text placement
The location of the MTEXT entity is defined by the MText.dxf.insert and the MText.dxf.attachment_point
attributes in WCS coordinates. The attachment_point defines the text alignment relative to the insert
location, default value is 1.
Attachment point constants defined in ezdxf.lldxf.const:
┌────────────────────────────┬───────┐
│ MText.dxf.attachment_point │ Value │
├────────────────────────────┼───────┤
│ MTEXT_TOP_LEFT │ 1 │
├────────────────────────────┼───────┤
│ MTEXT_TOP_CENTER │ 2 │
├────────────────────────────┼───────┤
│ MTEXT_TOP_RIGHT │ 3 │
├────────────────────────────┼───────┤
│ MTEXT_MIDDLE_LEFT │ 4 │
├────────────────────────────┼───────┤
│ MTEXT_MIDDLE_CENTER │ 5 │
├────────────────────────────┼───────┤
│ MTEXT_MIDDLE_RIGHT │ 6 │
├────────────────────────────┼───────┤
│ MTEXT_BOTTOM_LEFT │ 7 │
├────────────────────────────┼───────┤
│ MTEXT_BOTTOM_CENTER │ 8 │
├────────────────────────────┼───────┤
│ MTEXT_BOTTOM_RIGHT │ 9 │
└────────────────────────────┴───────┘
The MTEXT entity has a method for setting insert, attachment_point and rotation attributes by one call:
set_location()
Character height
The character height is defined by the DXF attribute MText.dxf.char_height in drawing units, which has
also consequences for the line spacing of the MTEXT entity:
mtext.dxf.char_height = 0.5
The character height can be changed inline, see also MTEXT formatting and MText Inline Codes.
Text rotation (direction)
The MText.dxf.rotation attribute defines the text rotation as angle between the x-axis and the horizontal
direction of the text in degrees. The MText.dxf.text_direction attribute defines the horizontal
direction of MTEXT as vector in WCS. Both attributes can be present at the same entity, in this case the
MText.dxf.text_direction attribute has the higher priority.
The MTEXT entity has two methods to get/set rotation: get_rotation() returns the rotation angle in
degrees independent from definition as angle or direction, and set_rotation() set the rotation attribute
and removes the text_direction attribute if present.
Defining a wrapping border
The wrapping border limits the text width and forces a line break for text beyond this border. Without
attribute dxf.width (or setting 0) the lines are wrapped only at the regular line endings “ \P” or “\n”,
setting the reference column width forces additional line wrappings at the given width. The text height
can not be limited, the text always occupies as much space as needed.
mtext.dxf.width = 60
[image]
MTEXT formatting
MTEXT supports inline formatting by special codes: MText Inline Codes
mtext.text = "{\\C1;red text} - {\\C3;green text} - {\\C5;blue text}"
[image]
See also the support class MTextEditor.
Stacked text
MTEXT supports stacked text:
# the space ' ' in front of 'Lower' and the ';' behind 'Lower' are necessary
# combined with vertical center alignment
mtext.text = "\\A1;\\SUpper^ Lower; - \\SUpper/ Lower;} - \\SUpper# Lower;"
[image]
See also the support class MTextEditor.
Background color (filling)
The MTEXT entity can have a background filling:
• AutoCAD Color Index (ACI)
• true color value as (r, g, b) tuple
• color name as string, use special name 'canvas' to use the canvas background color
Because of the complex dependencies ezdxf provides a method to set all required DXF attributes at once:
mtext.set_bg_color(2, scale=1.5)
The parameter scale determines how much border there is around the text, the value is based on the text
height, and should be in the range of 1 - 5, where 1 fits exact the MTEXT entity. [image]
MTextEditor
WARNING:
The MTextEditor assembles just the inline code, which has to be parsed and rendered by the target CAD
application, ezdxf has no influence to that result.
Keep inline formatting as simple as possible, don’t test the limits of its capabilities, this will not
work across different CAD applications and keep the formatting in a logic manner like, do not change
paragraph properties in the middle of a paragraph.
There is no official documentation for the inline codes!
The MTextEditor class provides a floating interface to build MText content in an easy way.
This example only shows the connection between MText and the MTextEditor, and shows no additional
features to the first example of this tutorial:
Init Editor
import ezdxf
from ezdxf.tools.text import MTextEditor
doc = ezdxf.new("R2007", setup=True)
msp = doc.modelspace()
lorem_ipsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, ... see prolog code
"""
# create a new editor object with an initial text:
editor = MTextEditor(lorem_ipsum)
# get the MTEXT content string from the editor by the str() function:
mtext = msp.add_mtext(str(editor), dxfattribs={"style": "OpenSans"})
Tutorial Prolog:
# use constants defined in MTextEditor:
NP = MTextEditor.NEW_PARAGRAPH
ATTRIBS = {
"char_height": 0.7,
"style": "OpenSans",
"width": 10,
}
editor = MTextEditor("using colors:" + NP)
Set Text Color
There are three ways to change the color inline:
• by color name “red”, “green”, “blue”, “yellow”, “cyan”, “magenta”, “white”
• by AutoCAD Color Index (ACI)
• by RGB values
# RED: set color by name - red, green, blue, yellow, cyan, magenta, white
editor.color("red").append("RED" + NP)
# RED: the color stays the same until the next change
editor.append("also RED" + NP)
# GREEN: change color by ACI (AutoCAD Color Index)
editor.aci(3).append("GREEN" + NP)
# BLUE: change color by RGB tuples
editor.rgb((0, 0, 255)).append("BLUE" + NP)
# add the MTEXT entity to the model space:
msp.add_mtext(str(editor), attribs)
[image]
Changing Text Height
The MtextEditor.height() method set the text height as absolute value in drawing units (text height = cap
height):
attribs = dict(ATTRIBS)
attribs["width"] = 40.0
editor = MTextEditor("changing text height absolute: default height is 0.7" + NP)
# doubling the default height = 1.4
editor.height(1.4)
editor.append("text height: 1.4" + NP)
editor.height(3.5).append("text height: 3.5" + NP)
editor.height(0.7).append("back to default height: 0.7" + NP)
msp.add_mtext(str(editor), attribs)
[image]
The MtextEditor.scale_height() method set the text height by a relative factor, the MtextEditor object
does not keep track of current text height, you have to do this by yourself. The initial text height is
MText.dxf.char_height:
attribs = dict(ATTRIBS)
attribs["width"] = 40.0
editor = MTextEditor("changing text height relative: default height is 0.7" + NP)
# this is the default text height in the beginning:
current_height = attribs["char_height"]
# The text height can only be changed by a factor:
editor.scale_height(2) # scale by 2 = 1.4
# keep track of the actual height:
current_height *= 2
editor.append("text height: 1.4" + NP)
# to set an absolute height, calculate the required factor:
desired_height = 3.5
factor = desired_height / current_height
editor.scale_height(factor).append("text height: 3.5" + NP)
current_height = desired_height
# and back to 0.7
editor.scale_height(0.7 / current_height).append("back to default height: 0.7" + NP)
msp.add_mtext(str(editor), attribs).set_location(insert=location)
Changing Font
The font name for changing MText fonts inline is the font family name! The font family name is the name
shown in font selection widgets in desktop applications: “Arial”, “Times New Roman”, “Comic Sans MS”.
The font has to be installed at the target system, else then CAD default font will be used, in
AutoCAD/BricsCAD is this the font defined for the text style “Standard”.
IMPORTANT:
The DXF/DWG format is not optimal for preserving text layouts across multiple systems, and it’s
getting really bad across different CAD applications.
attribs = dict(ATTRIBS)
attribs["width"] = 15.0
editor = MTextEditor("changing fonts:" + NP)
editor.append("Default: Hello World!" + NP)
editor.append("SimSun: ")
# change font in a group to revert back to the default font at the end:
simsun_editor = MTextEditor().font("SimSun").append("你好,世界" + NP)
# reverts the font back at the end of the group:
editor.group(str(simsun_editor))
# back to default font OpenSans:
editor.append("Times New Roman: ")
# change font outside of a group until next font change:
editor.font("Times New Roman").append("Привет мир!" + NP)
# If the font does not exist, a replacement font will be used:
editor.font("Does not exist").append("This is the replacement font!")
msp.add_mtext(str(editor), attribs)
[image]
Set Paragraph Properties
The paragraph properties are set by the paragraph() method and a ParagraphProperties object, which
bundles all paragraph properties in a named tuple.
Each paragraph can have its own properties for:
• indentation arguments:
• indent is the left indentation of the first line
• left is the left side indentation of the paragraph
• right is the right side indentation of the paragraph
• text adjustment: align, by enum MTextParagraphAlignment
• MTextParagraphAlignment.LEFT
• MTextParagraphAlignment.RIGHT
• MTextParagraphAlignment.CENTER
• MTextParagraphAlignment.JUSTIFIED
• MTextParagraphAlignment.DISTRIBUTED
• tabulator stops: tab_stops, a tuple of tabulator stops
Indentation and tabulator stops are multiples of the default MText text height stored in
MText.dxf.char_height. Calculate the drawing units for indentation and tabulator stops, by multiplying
the indentation value by the char_height value.
Mtext paragraphs are separated by new paragraph “\P” characters.
# import support classes:
from ezdxf.tools.text import ParagraphProperties, MTextParagraphAlignment
attribs = dict(ATTRIBS)
attribs["char_height"] = 0.25
attribs["width"] = 7.5
editor = MTextEditor("Indent the first line:" + NP)
props = ParagraphProperties(
indent=1, # indent first line = 1x0.25 drawing units
align=MTextParagraphAlignment.JUSTIFIED
)
editor.paragraph(props)
editor.append(lorem_ipsum)
msp.add_mtext(str(editor), attribs)
[image]
The first line indentation “indent” is relative to the “left” indentation.
# import support classes:
from ezdxf.tools.text import ParagraphProperties, MTextParagraphAlignment
attribs = dict(ATTRIBS)
attribs["char_height"] = 0.25
attribs["width"] = 7.5
editor = MTextEditor("Indent left paragraph side:" + NP)
indent = 0.7 # 0.7 * 0.25 = 0.175 drawing units
props = ParagraphProperties(
# first line indentation is relative to "left", this reverses the
# left indentation:
indent=-indent, # first line
# indent left paragraph side:
left=indent,
align=MTextParagraphAlignment.JUSTIFIED
)
editor.paragraph(props)
editor.append(" ".join(lorem_ipsum(100)))
msp.add_mtext(str(editor), attribs).set_location(insert=location)
[image]
Bullet List
There are no special commands to build bullet list, the list is build of indentation and a tabulator
stop. Each list item needs a marker as an arbitrary string. For more information about paragraph
indentation and tabulator stops see also chapter Set Paragraph Properties.
attribs = dict(ATTRIBS)
attribs["char_height"] = 0.25
attribs["width"] = 7.5
bullet = "•" # alt + numpad 7
editor = MTextEditor("Bullet List:" + NP)
editor.bullet_list(
indent=1,
bullets=[bullet] * 3, # each list item needs a marker
content=[
"First item",
"Second item",
" ".join(lorem_ipsum(30)),
])
msp.add_mtext(str(editor), attribs)
[image]
Numbered List
There are no special commands to build numbered list, the list is build of indentation and a tabulator
stop. There is no automatic numbering, but therefore the absolute freedom for using any string as list
marker. For more information about paragraph indentation and tabulator stops see also chapter Set
Paragraph Properties.
attribs = dict(ATTRIBS)
attribs["char_height"] = 0.25
attribs["width"] = 7.5
editor = MTextEditor("Numbered List:" + NP)
editor.bullet_list(
indent=1,
bullets=["1.", "2.", "3."],
content=[
"First item",
"Second item",
" ".join(lorem_ipsum(30)),
])
msp.add_mtext(str(editor), attribs)
[image]
Stacked Text
MText supports stacked text (fractions) as a single inline code, which means it is not possible to change
any property inside the fraction. This example shows a fraction with scaled down text height, placed in
a group to revert the text height afterwards:
editor = MTextEditor("Stacked text:" + NP)
stack = MTextEditor().scale_height(0.6).stack("1", "2", "^")
editor.append("over: ").group(str(stack)).append(NP)
stack = MTextEditor().scale_height(0.6).stack("1", "2", "/")
editor.append("fraction: ").group(str(stack)).append(NP)
stack = MTextEditor().scale_height(0.6).stack("1", "2", "#")
editor.append("slanted: ").group(str(stack)).append(NP)
# Additional formatting in numerator and denominator is not supported
# by AutoCAD or BricsCAD, switching the color inside the stacked text
# to red does not work:
numerator = MTextEditor().color("red").append("1")
stack = MTextEditor().scale_height(0.6).stack(str(numerator), "2", "#")
editor.append("color red: ").group(str(stack)).append(NP)
msp.add_mtext(str(editor), attribs)
[image]
SEE ALSO:
• MTextEditor example code on github.
• Documentation of MTextEditor
Tutorial for Spline
Background information about B-spline at Wikipedia.
Splines from fit points
Splines can be defined by fit points only, this means the curve passes all given fit points. AutoCAD and
BricsCAD generates required control points and knot values by itself, if only fit points are present.
Create a simple spline:
doc = ezdxf.new("R2000")
fit_points = [(0, 0, 0), (750, 500, 0), (1750, 500, 0), (2250, 1250, 0)]
msp = doc.modelspace()
spline = msp.add_spline(fit_points)
[image]
Append a fit point to a spline:
# fit_points, control_points, knots and weights are list-like containers:
spline.fit_points.append((2250, 2500, 0))
[image]
You can set additional control points, but if they do not fit the auto-generated AutoCAD values, they
will be ignored and don’t mess around with knot values.
doc = ezdxf.readfile("AutoCAD_generated.dxf")
msp = doc.modelspace()
spline = msp.query("SPLINE").first
# fit_points, control_points, knots and weights are list-like objects:
spline.fit_points.append((2250, 2500, 0))
As far as I have tested, this approach works without complaints from AutoCAD, but for the case of
problems remove invalid data from the SPLINE entity:
# current control points do not match spline defined by fit points
spline.control_points = []
# count of knots is not correct:
# count of knots = count of control points + degree + 1
spline.knots = []
# same for weights, count of weights == count of control points
spline.weights = []
Splines by control points
Creating splines from fit points is the easiest way, but this method is also the least accurate, because
a spline is defined by control points and knot values, which are generated for the case of a definition
by fit points, and the worst fact is that for every given set of fit points exist an infinite number of
possible splines as solution.
AutoCAD (and BricsCAD) uses an unknown proprietary algorithm to generate control points and knot values
from fit points. Therefore splines generated from fit points by ezdxf do not match splines generated by
AutoCAD (BricsCAD).
To ensure the same spline geometry for all CAD applications, the spline has to be defined by control
points. The method add_spline_control_frame() adds a spline passing the given fit points by calculating
the control points by the Global Curve Interpolation algorithm. There is also a low level function
ezdxf.math.global_bspline_interpolation() which calculates the control points from fit points.
msp.add_spline_control_frame(fit_points, method='uniform', dxfattribs={'color': 1})
msp.add_spline_control_frame(fit_points, method='chord', dxfattribs={'color': 3})
msp.add_spline_control_frame(fit_points, method='centripetal', dxfattribs={'color': 5})
• black curve: AutoCAD/BricsCAD spline generated from fit points
• red curve: spline curve interpolation, “uniform” method
• green curve: spline curve interpolation, “chord” method
• blue curve: spline curve interpolation, “centripetal” method
[image]
Open Spline
Add and open (clamped) spline defined by control points with the method add_open_spline(). If no knot
values are given, an open uniform knot vector will be generated. A clamped B-spline starts at the first
control point and ends at the last control point.
control_points = [(0, 0, 0), (1250, 1560, 0), (3130, 610, 0), (2250, 1250, 0)]
msp.add_open_spline(control_points)
[image]
Rational Spline
Rational B-splines have a weight for every control point, which can raise or lower the influence of the
control point, default weight = 1, to lower the influence set a weight < 1 to raise the influence set a
weight > 1. The count of weights has to be always equal to the count of control points.
Example to raise the influence of the first control point:
msp.add_closed_rational_spline(control_points, weights=[3, 1, 1, 1])
[image]
Spline properties
Check if spline is a closed curve or close/open spline, for a closed spline the last point is connected
to the first point:
if spline.closed:
# this spline is closed
pass
# close spline
spline.closed = True
# open spline
spline.closed = False
Set start- and end tangent for splines defined by fit points:
spline.dxf.start_tangent = (0, 1, 0)
spline.dxf.end_tangent = (1, 0, 0)
Get data count as stored in DXF attributes:
count = spline.dxf.n_fit_points
count = spline.dxf.n_control_points
count = spline.dxf.n_knots
Get data count from existing data:
count = spline.fit_point_count
count = spline.control_point_count
count = spline.knot_count
Tutorial for Polyface
The Polyface entity represents a 3D mesh build of vertices and faces and is just an extended POLYLINE
entity with a complex VERTEX structure. The Polyface entity was used in DXF R12 and older DXF versions
and is still supported by newer DXF versions. The new Mesh entity stores the same data much more
efficient but requires DXF R2000 or newer. The Polyface entity supports only triangles and quadrilaterals
as faces, the Mesh entity supports also n-gons.
Its recommended to use the MeshBuilder objects to create 3D meshes and render them as POLYFACE entities
by the render_polymesh() method into a layout:
import ezdxf
from ezdxf import colors
from ezdxf.gfxattribs import GfxAttribs
from ezdxf.render import forms
cube = forms.cube().scale_uniform(10).subdivide(2)
red = GfxAttribs(color=colors.RED)
green = GfxAttribs(color=colors.GREEN)
blue = GfxAttribs(color=colors.BLUE)
doc = ezdxf.new()
msp = doc.modelspace()
# render as MESH entity
cube.render_mesh(msp, dxfattribs=red)
cube.translate(20)
# render as POLYFACE a.k.a. POLYLINE entity
cube.render_polyface(msp, dxfattribs=green)
cube.translate(20)
# render as a bunch of 3DFACE entities
cube.render_3dfaces(msp, dxfattribs=blue)
doc.saveas("meshes.dxf")
[image]
WARNING:
If the mesh contains n-gons the render methods for POLYFACE and 3DFACES subdivides the n-gons into
triangles, which does not work for concave faces.
The usage of the MeshBuilder object is also recommended for inspecting Polyface entities:
• MeshBuilder.vertices is a sequence of 3D points as ezdxf.math.Vec3 objects
• a face in MeshBuilder.faces is a sequence of indices into the MeshBuilder.vertices sequence
import ezdxf
from ezdxf.render import MeshBuilder
def process(mesh):
# vertices is a sequence of 3D points
vertices = mses.vertices
# a face is a sequence of indices into the vertices sequence
faces = mesh.faces
...
doc = ezdxf.readfile("meshes.dxf")
msp = doc.modelspace()
for polyline in msp.query("POLYLINE"):
if polyline.is_poly_face_mesh:
mesh = MeshBuilder.from_polyface(polyline)
process(mesh)
SEE ALSO:
Tutorial for Mesh
Tutorial for Mesh
The Mesh entity is a 3D object in WCS build up from vertices and faces.
Create a cube mesh by directly accessing the base data structures:
import ezdxf
# 8 corner vertices
cube_vertices = [
(0, 0, 0),
(1, 0, 0),
(1, 1, 0),
(0, 1, 0),
(0, 0, 1),
(1, 0, 1),
(1, 1, 1),
(0, 1, 1),
]
# 6 cube faces
cube_faces = [
[0, 1, 2, 3],
[4, 5, 6, 7],
[0, 1, 5, 4],
[1, 2, 6, 5],
[3, 2, 6, 7],
[0, 3, 7, 4]
]
# MESH requires DXF R2000 or later
doc = ezdxf.new("R2000")
msp = doc.modelspace()
mesh = msp.add_mesh()
# do not subdivide cube, 0 is the default value
mesh.dxf.subdivision_levels = 0
with mesh.edit_data() as mesh_data:
mesh_data.vertices = cube_vertices
mesh_data.faces = cube_faces
doc.saveas("cube_mesh_1.dxf")
Create a cube mesh by assembling single faces using the edit_data() context manager of the Mesh class and
the helper class MeshData:
import ezdxf
# 8 corner vertices
p = [
(0, 0, 0),
(1, 0, 0),
(1, 1, 0),
(0, 1, 0),
(0, 0, 1),
(1, 0, 1),
(1, 1, 1),
(0, 1, 1),
]
# MESH requires DXF R2000 or later
doc = ezdxf.new("R2000")
msp = doc.modelspace()
mesh = msp.add_mesh()
with mesh.edit_data() as mesh_data:
mesh_data.add_face([p[0], p[1], p[2], p[3]])
mesh_data.add_face([p[4], p[5], p[6], p[7]])
mesh_data.add_face([p[0], p[1], p[5], p[4]])
mesh_data.add_face([p[1], p[2], p[6], p[5]])
mesh_data.add_face([p[3], p[2], p[6], p[7]])
mesh_data.add_face([p[0], p[3], p[7], p[4]])
# optional call optimize(): minimizes the vertex count
mesh_data.optimize()
doc.saveas("cube_mesh_2.dxf")
Its recommended to use the MeshBuilder objects to create 3D meshes and render them as MESH entities by
the render_mesh() method into a layout:
import ezdxf
from ezdxf import colors
from ezdxf.gfxattribs import GfxAttribs
from ezdxf.render import forms
cube = forms.cube().scale_uniform(10).subdivide(2)
red = GfxAttribs(color=colors.RED)
green = GfxAttribs(color=colors.GREEN)
blue = GfxAttribs(color=colors.BLUE)
doc = ezdxf.new()
msp = doc.modelspace()
# render as MESH entity
cube.render_mesh(msp, dxfattribs=red)
cube.translate(20)
# render as POLYFACE a.k.a. POLYLINE entity
cube.render_polyface(msp, dxfattribs=green)
cube.translate(20)
# render as a bunch of 3DFACE entities
cube.render_3dfaces(msp, dxfattribs=blue)
doc.saveas("meshes.dxf")
[image]
There exist some tools to manage meshes:
• ezdxf.render.MeshBuilder: The MeshBuilder classes are helper tools to manage meshes buildup by vertices
and faces.
• ezdxf.render.MeshTransformer: Same functionality as MeshBuilder but supports inplace transformation.
• ezdxf.render.MeshDiagnose: A diagnose tool which can be used to analyze and detect errors of
MeshBuilder objects like topology errors for closed surfaces.
• ezdxf.render.FaceOrientationDetector: A helper class for face orientation and face normal vector
detection
The ezdxf.render.forms module provides function to create basic geometries like cube, cone, sphere and so
on and functions to create meshes from profiles by extrusion, rotation or sweeping.
This example shows how to sweep a gear profile along a helix:
import ezdxf
from ezdxf.render import forms
doc = ezdxf.new()
doc.layers.add("MESH", color=ezdxf.colors.YELLOW)
msp = doc.modelspace()
# sweeping a gear-profile
gear = forms.gear(
8, top_width=0.01, bottom_width=0.02, height=0.02, outside_radius=0.1
)
helix = path.helix(radius=2, pitch=1, turns=6)
# along a helix spine
sweeping_path = helix.flattening(0.1)
mesh = forms.sweep(gear, sweeping_path, close=True, caps=True)
# and render as MESH entity
mesh.render_mesh(msp, dxfattribs={"layer": "MESH"})
doc.saveas("gear_along_helix.dxf")
[image]
Tutorial for Hatch
Create hatches with one boundary path
The simplest form of the Hatch entity has one polyline path with only straight lines as boundary path:
import ezdxf
# hatch requires DXF R2000 or later
doc = ezdxf.new("R2000")
msp = doc.modelspace()
# by default a solid fill hatch with fill color=7 (white/black)
hatch = msp.add_hatch(color=2)
# every boundary path is a 2D element
# vertex format for the polyline path is: (x, y[, bulge])
# there are no bulge values in this example
hatch.paths.add_polyline_path(
[(0, 0), (10, 0), (10, 10), (0, 10)], is_closed=True
)
doc.saveas("solid_hatch_polyline_path.dxf")
But like all polyline entities the polyline path can also have bulge values:
import ezdxf
# hatch requires the DXF R2000 or later
doc = ezdxf.new("R2000")
msp = doc.modelspace()
# by default a solid fill hatch with fill color=7 (white/black)
hatch = msp.add_hatch(color=2)
# every boundary path is a 2D element
# vertex format for the polyline path is: (x, y[, bulge])
# bulge value 1 = an arc with diameter=10 (= distance to next vertex * bulge value)
# bulge value > 0 ... arc is right of line
# bulge value < 0 ... arc is left of line
hatch.paths.add_polyline_path(
[(0, 0, 1), (10, 0), (10, 10, -0.5), (0, 10)], is_closed=True
)
doc.saveas("solid_hatch_polyline_path_with_bulge.dxf")
The most flexible way to define a boundary path is the edge path. An edge path can have multiple edges
and each edge can be one of the following elements:
• line EdgePath.add_line()
• arc EdgePath.add_arc()
• ellipse EdgePath.add_ellipse()
• spline EdgePath.add_spline()
Create a solid hatch with an edge path (ellipse) as boundary path:
import ezdxf
# hatch requires the DXF R2000 or later
doc = ezdxf.new("R2000")
msp = doc.modelspace()
# important: major axis >= minor axis (ratio <= 1.)
# minor axis length = major axis length * ratio
msp.add_ellipse((0, 0), major_axis=(0, 10), ratio=0.5)
# by default a solid fill hatch with fill color=7 (white/black)
hatch = msp.add_hatch(color=2)
# every boundary path is a 2D element
edge_path = hatch.paths.add_edge_path()
# each edge path can contain line, arc, ellipse and spline elements
# important: major axis >= minor axis (ratio <= 1.)
edge_path.add_ellipse((0, 0), major_axis=(0, 10), ratio=0.5)
doc.saveas("solid_hatch_ellipse.dxf")
Create hatches with multiple boundary paths (islands)
The DXF attribute hatch_style defines the island detection style:
┌───┬───────────────────────────────────────┐
│ 0 │ nested - altering filled and unfilled │
│ │ areas │
├───┼───────────────────────────────────────┤
│ 1 │ outer - area between external and │
│ │ outermost path is filled │
├───┼───────────────────────────────────────┤
│ 2 │ ignore - external path is filled │
└───┴───────────────────────────────────────┘
hatch = msp.add_hatch(
color=1,
dxfattribs={
"hatch_style": ezdxf.const.HATCH_STYLE_NESTED,
# 0 = nested: ezdxf.const.HATCH_STYLE_NESTED
# 1 = outer: ezdxf.const.HATCH_STYLE_OUTERMOST
# 2 = ignore: ezdxf.const.HATCH_STYLE_IGNORE
},
)
# The first path has to set flag: 1 = external
# flag const.BOUNDARY_PATH_POLYLINE is added (OR) automatically
hatch.paths.add_polyline_path(
[(0, 0), (10, 0), (10, 10), (0, 10)],
is_closed=True,
flags=ezdxf.const.BOUNDARY_PATH_EXTERNAL,
)
This is also the result for all 4 paths and hatch_style set to 2 (ignore). [image]
# The second path has to set flag: 16 = outermost
hatch.paths.add_polyline_path(
[(1, 1), (9, 1), (9, 9), (1, 9)],
is_closed=True,
flags=ezdxf.const.BOUNDARY_PATH_OUTERMOST,
)
This is also the result for all 4 paths and hatch_style set to 1 (outer). [image]
# The third path has to set flag: 0 = default
hatch.paths.add_polyline_path(
[(2, 2), (8, 2), (8, 8), (2, 8)],
is_closed=True,
flags=ezdxf.const.BOUNDARY_PATH_DEFAULT,
)
[image]
# The forth path has to set flag: 0 = default, and so on
hatch.paths.add_polyline_path(
[(3, 3), (7, 3), (7, 7), (3, 7)],
is_closed=True,
flags=ezdxf.const.BOUNDARY_PATH_DEFAULT,
)
doc.saveas(OUTDIR / "solid_hatch_islands_04.dxf")
[image]
The expected result of combinations of various hatch_style values and paths flags, or the handling of
overlapping paths is not documented by the DXF reference, so don’t ask me, ask Autodesk or just try it by
yourself and post your experience in the forum.
Example for Edge Path Boundary
hatch = msp.add_hatch(color=1)
# 1. polyline path
hatch.paths.add_polyline_path(
[
(240, 210, 0),
(0, 210, 0),
(0, 0, 0.0),
(240, 0, 0),
],
is_closed=1,
flags=ezdxf.const.BOUNDARY_PATH_EXTERNAL,
)
# 2. edge path
edge_path = hatch.paths.add_edge_path(flags=ezdxf.const.BOUNDARY_PATH_OUTERMOST)
edge_path.add_spline(
control_points=[
(126.658105895725, 177.0823706957212),
(141.5497003747484, 187.8907860433995),
(205.8997365206943, 154.7946313459515),
(113.0168862297068, 117.8189380884978),
(202.9816918983783, 63.17222935389572),
(157.363511042264, 26.4621294342132),
(144.8204003260554, 28.4383294369643),
],
knot_values=[
0.0,
0.0,
0.0,
0.0,
55.20174685732758,
98.33239645153571,
175.1126541251052,
213.2061566683142,
213.2061566683142,
213.2061566683142,
213.2061566683142,
],
)
edge_path.add_arc(
center=(152.6378550678883, 128.3209356351659),
radius=100.1880612627354,
start_angle=94.4752130054052,
end_angle=177.1345242028005,
)
edge_path.add_line(
(52.57506282464041, 123.3124200796114),
(126.658105895725, 177.0823706957212),
)
[image]
Associative Boundary Paths
A HATCH entity can be associative to a base geometry, which means if the base geometry is edited in a CAD
application the HATCH get the same modification. Because ezdxf is not a CAD application, this
association is not maintained nor verified by ezdxf, so if you modify the base geometry afterwards the
geometry of the boundary path is not updated and no verification is done to check if the associated
geometry matches the boundary path, this opens many possibilities to create invalid DXF files: USE WITH
CARE.
This example associates a LWPOLYLINE entity to the hatch created from the LWPOLYLINE vertices:
# Create base geometry
lwpolyline = msp.add_lwpolyline(
[(0, 0, 0), (10, 0, 0.5), (10, 10, 0), (0, 10, 0)],
format="xyb",
close=True,
)
hatch = msp.add_hatch(color=1)
path = hatch.paths.add_polyline_path(
# get path vertices from associated LWPOLYLINE entity
lwpolyline.get_points(format="xyb"),
# get closed state also from associated LWPOLYLINE entity
is_closed=lwpolyline.closed,
)
# Set association between boundary path and LWPOLYLINE
hatch.associate(path, [lwpolyline])
An EdgePath needs associations to all geometry entities forming the boundary path.
Predefined Hatch Pattern
Use predefined hatch pattern by name:
hatch.set_pattern_fill("ANSI31", scale=0.5)
[image]
SEE ALSO:
Tutorial for Hatch Pattern Definition
Tutorial for Hatch Pattern Definition
A hatch pattern consist of one or more hatch lines. A hatch line defines a set of lines which have the
same orientation an the same line pattern. All the lines defined by a hatch line are parallel and have a
constant distance to each other. The origin defines the start point of the hatch line and also the
starting point of the line pattern. The direction defines the angle between the WCS x-axis and the hatch
line. The offset is a 2D vector which will be added consecutively the the origin for each new hatch line.
The line pattern has the same format as as the simple linetype pattern (Tutorial for Creating Linetype
Pattern).
IMPORTANT:
The hatch pattern must be defined for a hatch scaling factor of 1.0 and a hatch rotation angle of 0
degrees!
The first example creates a simple pattern of horizontal solid lines with a vertical distance of 0.5
drawing units.
import ezdxf
doc = ezdxf.new("R2010")
msp = doc.modelspace()
hatch = msp.add_hatch()
hatch.set_pattern_fill(
"MyPattern",
color=7,
angle=0,
scale=1.0,
style=0, # normal hatching style
pattern_type=0, # user-defined
# pattern definition as list of:
# [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
# line pattern is a solid line
definition=[[0, (0, 0), (0, 0.5), []]],
)
points = [(0, 0), (10, 0), (10, 10), (0, 10)]
hatch.paths.add_polyline_path(points)
msp.add_lwpolyline(points, close=True, dxfattribs={"color": 1})
doc.saveas("user_defined_hatch_pattern.dxf")
[image]
The next example shows how the offset value works:
# -x-x-x- snip -x-x-x-
hatch = msp.add_hatch()
hatch.set_pattern_fill(
"MyPattern",
color=7,
angle=0,
scale=1.0,
style=0, # normal hatching style
pattern_type=0, # user-defined
# the line pattern is a dashed line: - - - -
# the offset is 1 unit vertical and 0.3 units horizontal
# [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
definition=[[0, (0, 0), (0.3, 1), [1, -1]]],
)
# -x-x-x- snip -x-x-x-
[image]
The next example combines two parallel hatch lines, the origin defines how the hatch lines are offset
from each other:
# -x-x-x- snip -x-x-x-
hatch = msp.add_hatch()
hatch.set_pattern_fill(
"MyPattern",
color=7,
angle=0,
scale=1.0,
style=0, # normal hatching style
pattern_type=0, # user-defined
# [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
definition=[
[0, (0, 0), (0.3, 1), [1, -1]], # dashed line
[0, (0, 0.5), (0, 1), []], # solid line
],
)
# -x-x-x- snip -x-x-x-
[image]
The next example combines two hatch lines with different angles. The origins can be the same for this
example. The Vec2 class is used to calculate the offset value for a normal distance of 0.7 drawing units
between the slanted lines:
from ezdxf.math import Vec2
# -x-x-x- snip -x-x-x-
hatch = msp.add_hatch()
# offset vector for a normal distance of 0.7 for a 45 deg slanted hatch line
offset = Vec2.from_deg_angle(45 + 90, length=0.7)
hatch.set_pattern_fill(
"MyPattern",
color=7,
angle=0,
scale=1.0,
style=0, # normal hatching style
pattern_type=0, # user-defined
# [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
definition=[
[0, (0, 0), (0, 1), [1, -1]], # horizontal dashed line
[45, (0, 0), offset, []], # slanted solid line
],
)
# -x-x-x- snip -x-x-x-
[image]
Tutorial for Image and ImageDef
This example shows how to use a raster image in a DXF document. Each IMAGE entity requires an associated
IMAGEDEF entity in the objects section, which stores the filename of the linked image and the size in
pixels. Multiple IMAGE entities can share the same IMAGEDEF entity.
IMPORTANT:
The raster image is NOT embedded in the DXF file!
import ezdxf
# The IMAGE entity requires the DXF R2000 format or later.
doc = ezdxf.new("R2000")
# The IMAGEDEF entity is like a block definition, it just defines the image.
my_image_def = doc.add_image_def(
filename="mycat.jpg", size_in_pixel=(640, 360)
)
msp = doc.modelspace()
# The IMAGE entity is like the INSERT entity, it's just an image reference,
# and there can be multiple references to the same picture in a DXF document.
# 1st image reference
msp.add_image(
insert=(2, 1),
size_in_units=(6.4, 3.6),
image_def=my_image_def,
rotation=0
)
# 2nd image reference
msp.add_image(
insert=(4, 5),
size_in_units=(3.2, 1.8),
image_def=my_image_def,
rotation=30
)
# Get existing image definitions from the OBJECTS section:
image_defs = doc.objects.query("IMAGEDEF")
doc.saveas("dxf_with_cat.dxf")
Tutorial for Underlay and UnderlayDefinition
This example shows hot to insert a a PDF, DWF, DWFx or DGN file as drawing underlay. Each UNDERLAY entity
requires an associated UNDERLAYDEF entity in the objects section, which stores the filename of the linked
document and the parameters of the underlay. Multiple UNDERLAY entities can share the same UNDERLAYDEF
entity.
IMPORTANT:
The underlay file is NOT embedded into the DXF file:
import ezdxf
doc = ezdxf.new('AC1015') # underlay requires the DXF R2000 format or later
my_underlay_def = doc.add_underlay_def(filename='my_underlay.pdf', name='1')
# The (PDF)DEFINITION entity is like a block definition, it just defines the underlay
# 'name' is misleading, because it defines the page/sheet to be displayed
# PDF: name is the page number to display
# DGN: name='default' ???
# DWF: ????
msp = doc.modelspace()
# add first underlay
msp.add_underlay(my_underlay_def, insert=(2, 1, 0), scale=0.05)
# The (PDF)UNDERLAY entity is like the INSERT entity, it creates an underlay reference,
# and there can be multiple references to the same underlay in a drawing.
msp.add_underlay(my_underlay_def, insert=(4, 5, 0), scale=.5, rotation=30)
# get existing underlay definitions, Important: UNDERLAYDEFs resides in the objects section
pdf_defs = doc.objects.query('PDFDEFINITION') # get all pdf underlay defs in drawing
doc.saveas("dxf_with_underlay.dxf")
Tutorial for MultiLeader
A multileader object typically consists of an arrowhead, a horizontal landing (a.k.a. “dogleg”), a leader
line or curve, and either a MTEXT object or a BLOCK.
Factory methods of the BaseLayout class to create new MultiLeader entities:
• add_multileader_mtext()
• add_multileader_block()
Because of the complexity of the MULTILEADER entity, the factory method add_multileader_mtext() returns a
MultiLeaderMTextBuilder instance to build a new entity and the factory method add_multileader_block()
returns a MultiLeaderBlockBuilder instance.
Due of the lack of good documentation it’s not possible to support all combinations of MULTILEADER
properties with decent quality, so stick to recipes and hints shown in this tutorial to get usable
results otherwise, you will enter uncharted territory.
The rendering result of the MULTILEADER entity is highly dependent on the CAD application. The
MULTILEADER entity does not have a pre-rendered anonymous block of DXF primitives like all DIMENSION
entities, so results may vary from CAD application to CAD application. The general support for this
entity is only good in Autodesk products other CAD applications often struggle when rendering
MULTILEADERS, even my preferred testing application BricsCAD has rendering issues.
IMPORTANT:
MULTILEADER support has flaws in many CAD applications except Autodesk products!
SEE ALSO:
• ezdxf.render.MultiLeaderBuilder classes
• ezdxf.entities.MultiLeader class
• ezdxf.entities.MLeaderStyle class
• ezdxf.tools.text.MTextEditor class
• MULTILEADER Internals
MTEXT Quick Draw
Full Python script: mtext_quick_leader.py
The quick_leader() method of a MTEXT - MULTILEADER entity constructs the geometry parameters in reverse
manner, starting from a given target point:
DXF document setup:
doc = ezdxf.new(setup=True)
# Create a new custom MLEADERSTYLE:
mleaderstyle = doc.mleader_styles.duplicate_entry("Standard", "EZDXF")
# The required TEXT style "OpenSans" was created by ezdxf.new() because setup is True:
mleaderstyle.set_mtext_style("OpenSans")
msp = doc.modelspace()
Draw a red circle to mark the target point:
target_point = Vec2(40, 15)
msp.add_circle(
target_point, radius=0.5, dxfattribs=GfxAttribs(color=colors.RED)
)
Create four horizontal placed MULTILEADER entities pointing at the target point, the first segment of the
leader line is determined by an angle in this example pointing away from the target point:
for angle in [45, 135, 225, -45]:
ml_builder = msp.add_multileader_mtext("EZDXF")
ml_builder.quick_leader(
f"angle={angle}°\n2nd text line",
target=target_point,
segment1=Vec2.from_deg_angle(angle, 14),
)
[image]
The content is automatically aligned to the end of the leader line. The first segment is a relative
vector to the target point and the optional second segment vector is relative to the end of the first
segment. The default connection type is horizontal but can be changed to vertical:
A smaller text size is required:
mleaderstyle = doc.mleader_styles.duplicate_entry("Standard", "EZDXF")
mleaderstyle.set_mtext_style("OpenSans")
mleaderstyle.dxf.char_height = 2.0 # set the default char height of MTEXT
Adding vertical placed MULTILEADER entities:
for angle in [45, 135, 225, -45]:
ml_builder = msp.add_multileader_mtext("EZDXF")
ml_builder.quick_leader(
f"angle={angle}°\n2nd text line",
target=target_point,
segment1=Vec2.from_deg_angle(angle, 14),
connection_type=mleader.VerticalConnection.center_overline,
)
This example already shows the limitation caused by different text renderings in various CAD
applications. The ezdxf text measurement by matplotlib is different to AutoCAD and BricsCAD and the
result is a misalignment of the overline and the leader line.
The DXF file shown in BricsCAD: [image]
The same DXF file shown with the ezdxf view command (drawing add-on): [image]
My advice is to avoid vertical placed MULTILEADER entities at all and for horizontal placed MULTILEADER
entities avoid styles including an “underline” or an “overline”.
The quick_leader() method is not very customizable for ease of use, but follows the settings of the
associated MLeaderStyle.
The following sections show how to have more control when adding MULTILEADER entities.
Create MTEXT Content
Full Python script: mtext_content.py
This section shows how to create a MULTILEADER entity with MTEXT content the manual way with full control
over all settings.
For good results the MTEXT alignment should match the leader connection side, e.g. if you attach leaders
to the left side also align the MTEXT to the left side, for leaders attached at the right side, align the
MTEXT to the right side and if you attach leaders at both sides one side will fit better than the other
or maybe a center aligned MTEXT is a good solution, for further details see section MTEXT Alignment.
The first example uses the default connection type of the MLEADERSTYLE “Standard” which is “middle of the
top line” for left and right attached leaders. The render UCS for this example is the WCS to keep things
simple.
Create a new MULTILEADER entity.
ml_builder = msp.add_multileader_mtext("Standard")
Set MTEXT content, text style and alignment.
ml_builder.set_content(
"Line1\nLine2",
style="OpenSans",
alignment=mleader.TextAlignment.left, # set MTEXT alignment!
)
Add the first leader on the left side. The leader points always to the first given vertex and all
vertices are given in render UCS coordinates (= WCS in this example).
ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])
More than one vertex per leader can be used:
ml_builder.add_leader_line(
mleader.ConnectionSide.left,
[Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
)
The insert point of the build() method is the alignment point for the MTEXT content.
ml_builder.build(insert=Vec2(5, 0))
The “dogleg” settings are defined by the MLEADERSTYLE “Standard”. [image]
This example shows a leader attached to the right side and the MTEXT aligned to the right side.
ml_builder = msp.add_multileader_mtext("Standard")
ml_builder.set_content(
"Line1\nLine2",
style="OpenSans",
alignment=mleader.TextAlignment.right, # set MTEXT alignment!
)
ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
ml_builder.build(insert=Vec2(15, 0))
[image]
This example shows two leaders attached to both sides and the MTEXT aligned to the left side, which shows
that the right landing gap (space between text and start of vertex) is bigger than the gap on the left
size. This is due to the different text size calculations from AutoCAD/BricsCAD and Matplotlib. The
longer the text, the greater the error.
ml_builder = msp.add_multileader_mtext("Standard")
ml_builder.set_content(
"Line1\nLine1",
style="OpenSans",
alignment=mleader.TextAlignment.left, # set MTEXT alignment!
)
ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])
ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
ml_builder.build(insert=Vec2(5, 0))
[image]
A centered MTEXT alignment gives a more even result.
ml_builder = msp.add_multileader_mtext("Standard")
ml_builder.set_content(
"First Line\n2. Line",
style="OpenSans",
alignment=mleader.TextAlignment.center, # set MTEXT alignment!
)
ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])
ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
ml_builder.build(insert=Vec2(10, 0))
[image]
But even this has its disadvantages, the attachment calculation is always based on the bounding box of
the MTEXT content. [image]
MTEXT Connection Types
There are four connection sides defined by the enum ezdxf.render.ConnectionSide:
• left
• right
• top
• bottom
The MultiLeader entity supports as the name says multiple leader lines, but all have to have a horizontal
(left/right) connection side or a vertical (top/bottom) connection side, it’s not possible to mix
left/right and top/bottom connection sides. This is determined by the DXF format.
There are different connection types available for the horizontal and the vertical connection sides. All
leaders connecting to the same side have the same connection type. The horizontal connection sides
support following connection types, defined by the enum ezdxf.render.HorizontalConnection:
• by_style
• top_of_top_line
• middle_of_top_line
• middle_of_text
• middle_of_bottom_line
• bottom_of_bottom_line
• bottom_of_bottom_line_underline (not recommended)
• bottom_of_top_line_underline (not recommended)
• bottom_of_top_line
• bottom_of_top_line_underline_all (not recommended)
The vertical connection sides support following connection types, defined by the enum
ezdxf.render.VerticalConnection:
• by_style
• center
• center_overline (not recommended)
The connection type for each side can be set by the method set_connection_types(), the default for all
sides is by_style:
ml_builder.set_connection_types(
left=mleader.HorizontalConnection.middle_of_top_line,
right=mleader.HorizontalConnection.middle_of_bottom_line,
)
[image]
HINT:
As shown in the quick draw section using connection types including underlines or overlines do not
render well in AutoCAD/BricsCAD because of the different text measurement of matplotlib, therefore
it’s not recommended to use any of these connection types when creating MULTILEADERS by ezdxf.
MTEXT Alignment
In contrast to the standalone MTEXT entity supports the MTEXT content entity only three text alignments
defined by the enum ezdxf.render.TextAlignment.
• left
• center
• right
The MTEXT alignment is set as argument alignment of the set_content() method and the alignment point is
the insert point of the build() method.
Create BLOCK Content
Full Python script: block_content.py
This section shows how to create a MULTILEADER entity with BLOCK content the manual way with full control
over all settings.
The BLOCK content consist of a BLOCK layout and optional ATTDEF entities which defines the location and
DXF attributes of dynamically created ATTRIB entities.
Create the BLOCK content, the full create_square_block() function can be found in the block_content.py
script.
block = create_square_block(
doc, size=8.0, margin=0.25, base_point=base_point
)
Create the MULTILEADER and set the content:
ml_builder = msp.add_multileader_block(style="Standard")
ml_builder.set_content(
name=block.name, alignment=mleader.BlockAlignment.insertion_point
)
Set the BLOCK attribute content as text:
ml_builder.set_attribute("ONE", "Data1")
ml_builder.set_attribute("TWO", "Data2")
Add some leader lines to the left and right side of the BLOCK:
Construction plane of the entity is defined by a render UCS. The leader lines vertices are expected in
render UCS coordinates, which means relative to the UCS origin and this example shows the simple case
where the UCS is the WCS which is also the default setting.
ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(x2, y1)])
ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(x2, y2)])
ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(x1, y1)])
ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(x1, y2)])
Last step is to build the final MULTILEADER entity. This example uses the alignment type insertion_point
where the insert point of the build() method is the base point of the BLOCK:
ml_builder.build(insert=Vec2(5, 2), rotation=30)
[image]
The result is shown in BricsCAD as expected, although BricsCAD shows “Center extents” as attachment type
in the properties dialog instead of the correct attachment type “Insertion point”.
BLOCK Connection Types
There are four connection sides defined by the enum ezdxf.render.ConnectionSide:
• left
• right
• top
• bottom
The connection point for leader lines is always the center of the side of the block bounding box the
leader is connected to and has the same limitation as for the MTEXT content, it’s not possible to mix the
connection sides left/right and top/bottom.
The connection side is set when adding the leader line by the add_leader_line() method.
Unfortunately BricsCAD has an error in version 22.2.03 and renders all connection types as left/right,
this is top/bottom connection shown in Autodesk TrueView 2022: [image]
The top/bottom connection type does not support the “dogleg” feature.
BLOCK Alignment
There are two alignments types, defined by the enum ezdxf.render.BlockAlignment
• center_extents
• insertion_point
The alignment is set by the set_content() method.
The alignment type center_extent inserts the BLOCK with the center of the bounding box at the insert
point of the build() method. The insert point is (5, 2) in this example: [image]
The same MULTILEADER with alignment type insert_point: [image]
BLOCK Scaling
The BLOCK content can be scaled independently from the overall scaling of the MULTILEADER entity:
The block scaling factor is set by the set_content() method:
ml_builder.set_content(
name=block.name, scale=2.0, alignment=mleader.BlockAlignment.center_extents
)
This is the first example with a block scaling factor of 2. The BLOCK and the attached ATTRIB entities
are scaled but not the arrows. [image]
BLOCK Rotation
The rotation around the render UCS z-axis in degrees is applied by the build() method:
ml_builder.build(insert=Vec2(5, 2), rotation=30)
This is the first example with a rotation of 30 degrees. The BLOCK, the attached ATTRIB entities and the
last connection lines (“dogleg”) are rotated. [image]
BLOCK Attributes
BLOCK attributes are defined as ATTDEF entities in the BLOCK layout. This ATTDEF entities will be
replaced by ATTRIB entities at the rendering process of the CAD application. Only the text content and
the text width factor can be changed for each MULTILEADER entity individually by the set_attribute()
method. The ATTDEF is addressed by it’s DXF tag attribute:
ml_builder.set_attribute("ONE", "Data1")
ml_builder.set_attribute("TWO", "Data2")
Leader Properties
“Dogleg” Properties
The “dogleg” is the last line segment from the last leader vertex to the MULTILEADER content for polyline
leaders. [image]
The length of the dogleg and the landing gap size is set by the set_connection_properties().
Polyline Leader
A polygon leader line has only straight line segments and is added by the add_leader_line():
ml_builder.add_leader_line(
mleader.ConnectionSide.left,
[Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
)
[image]
All leader line vertices have render UCS coordinates and the start- and end-vertex of the “dogleg” is
calculated automatically.
Spline Leader
A spline leader line has a single curved line as leader line and is also added by the add_leader_line().
This is spline leader has the same vertices as the previous created polyline leader:
ml_builder.set_leader_properties(leader_type=mleader.LeaderType.splines)
ml_builder.add_leader_line(
mleader.ConnectionSide.left,
[Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
)
[image]
The spline leader has no “dogleg” and spline leaders and polyline leaders can not be mixed in a single
MULTILEADER entity.
The leader type is set by the set_leader_properties() method.
The LeaderType enum:
• none
• straight_lines
• splines
Line Styling
The leader color, linetype and lineweight is set by the set_leader_properties() method:
ml_builder.set_leader_properties(
color=colors.MAGENTA,
linetype="DASHEDX2",
lineweight=70,
)
[image]
All leader lines have the same properties.
Arrowheads
The arrow head is set by the set_arrow_properties() method:
from ezdxf.render import ARROWS
ml_builder.set_arrow_properties(name=ARROWS.closed_blank, size=8.0)
[image]
All leader lines have the same arrow head and size. The available arrow heads are defined in the ARROWS
object.
Overall Scaling
The overall scaling has to be applied by the set_overall_scaling() method and scales the MTEXT or BLOCK
content and the arrows.
Setup MLEADERSTYLE
The MLeaderStyle stores many of the MULTILEADER settings but most of them are copied to the MULTILINE
entity at initialization. So changing the MLEADERSTYLE style afterwards has little to no effect for
existing MULTILEADER entities.
Create a new MLEADERSTYLE called “MY_STYLE” and set the MTEXT style to “OpenSans”:
my_style = doc.mleader_styles.duplicate_entry("Standard", "MY_STYLE")
my_style.set_mtext_style("OpenSans")
The style for a MULTILEADER is set at the add_multileader_mtext() and add_multileader_block() factory
methods.
Tutorial for Viewports in Paperspace
This tutorial is based on the example script viewports_in_paperspace.py. The script creates DXF files
for the version R12 and for R2000+, but the export for DXF R12 has a wrong papersize in BricsCAD and
wrong margins in Autodesk DWG Trueview. I don’t know why this happens and I don’t waste my time to fix
this.
IMPORTANT:
If you need paperspace layouts use DXF version R2000 or newer because the export of the page
dimensions does not work for DXF R12!
The scripts creates three flat geometries in the xy-plane of the WCS and a 3D mesh as content of the
modelspace: [image]
Page Setup
The paperspace layout feature lacks documentation in the DXF reference, there is no information in
practice on how it is used, so most of the information here is assumptions gathered through trail and
error.
The page_setup() method defines the properties of the paper sheet itself. The units of the modelspace
and the paperspace are not related and can even have different unit systems (imperial, meters), but to
keep things simple it’s recommended to use the same unit system for both spaces.
layout.page_setup(size=(24, 18), margins=(1, 1, 1, 1), units="inch")
The size argument defines the overall paper size in rotation mode 0, it seems to be the best practice to
define the paper extents in landscape mode and rotate the paper by the rotate argument afterwards.
Choices for the rotation argument:
┌───┬──────────────────────────────┐
│ 0 │ no rotation │
├───┼──────────────────────────────┤
│ 1 │ 90 degrees counter-clockwise │
├───┼──────────────────────────────┤
│ 2 │ upside-down │
├───┼──────────────────────────────┤
│ 3 │ 90 degrees clockwise │
└───┴──────────────────────────────┘
The scale argument reflects the relationship between paper unit and drawing unit in paperspace. It’s
recommended to let this scale at the default value of 1:1 and draw lines and text in paperspace with the
same units as you defined the paper size.
SEE ALSO:
• AutoCAD: About Plotting and About Setting the Plot Scale
• BricsCAD: General Procedure for Printing
Drawing in Paperspace
You can add DXF entities to the paperspace like to any other layout space. The coordinate origin (0, 0)
is in the left bottom corner of the canvas which is the paper size minus the margins. You can draw beyond
this limits but CAD applications may not print that content.
HINT:
By writing this tutorial I noticed that changing the printer/plotter and the paper size does shift the
layout content, because all paper sizes are defined without margins. Maybe it’s preferable to set all
margins to zero.
I added the helper method page_setup() to the Drawing class and an example simple_page_setup.py how to
use it.
Adding Viewports
The Viewport entity is a window to the modelspace to display the content of the modelspace in paperspace
with an arbitrary scaling and rotation. The VIEWPORT entity will be added by the factory method
add_viewport(), the center argument defines the center and the size argument defines the width and height
of the of the VIEWPORT in paperspace. The source of the modelspace to display is defined by the arguments
view_center_point and view_height. [image]
Scaling Factor
The scaling factor of the VIEWPORT is not an explicit value, the factor is defined by the relation of the
VIEWPORT height of the size argument and the view_height argument.
If both values are equal the scaling is 1:1
paperspace.add_viewport(
center=(14.5, 2.5),
size=(5, 5),
view_center_point=(12.5, 7.5),
view_height=5,
)
If the view_height is 5x larger than the VIEWPORT height the scaling is 1:5
paperspace.add_viewport(
center=(8.5, 2.5),
size=(5, 5),
view_center_point=(10, 5),
view_height=25,
)
View Direction
The default view direction is the top down view, but can be changed to any view by the attributes
view_target_point and view_direction_vector of the dxf namespace.
vp = paperspace.add_viewport(
center=(16, 10), size=(4, 4), view_center_point=(0, 0), view_height=30
)
vp.dxf.view_target_point = (40, 40, 0)
vp.dxf.view_direction_vector = (-1, -1, 1)
Viewport Frame
The VIEWPORT frame (borderlines) are shown in paperspace by default. The VIEWPORT entity does not have
an attribute to change this. The visibility of the VIEWPORT frame is controlled by the layer assigned to
the VIEWPORT entity which is the layer “VIEWPORTS” by default in ezdxf. Turning off this layer hides the
frames of the VIEWPORT entities on this layer, to do that the layer “VIEWPORTS” have to be created by the
library user:
vp_layer = doc.layers.add("VIEWPORTS")
vp_layer.off()
Freeze Layers
Each VIEWPORT can have individual frozen layers, which means the layers are not visible in this VIEWPORT.
To freeze layers in a VIEWPORT assign the names of the frozen layers as a list-like object to the
frozen_layers attribute of the VIEWPORT entity:
vp.frozen_layers = ["Layer0", "Layer1"]
IMPORTANT:
AutoCAD and BricsCAD do not crash if the layer names do not have layer table entries and the layer
names are case insensitive as all table names.
SEE ALSO:
• Basic concept of Layers
• Layer
Override Layer Properties
Each VIEWPORT can override layer properties individually. These overrides are stored in the Layer entity
and referenced by the handle of the VIEWPORT. This procedure is a bit more complex and shown in the
example file viewports_override_layer_attributes.py.
1. get the Layer object
2. get the LayerOverrides object from the layer
3. override the properties of the VIEWPORT
4. commit changes
layer = doc.layers.get("Layer0")
override = layer.get_vp_overrides()
override.set_linetype(vp.dxf.handle, "DASHED")
override.commit()
Supported property overrides:
• ACI color
• true color
• transparency
• linetype
• lineweight
SEE ALSO:
• Basic concept of Layers
• Basic concept of AutoCAD Color Index (ACI)
• Basic concept of True Color
• Basic concept of Transparency
• Basic concept of Linetypes
• Basic concept of Lineweights
• Layer
• LayerOverrides
Tutorial for OCS/UCS Usage
For OCS/UCS usage is a basic understanding of vector math required, for a brush up, watch the YouTube
tutorials of 3Blue1Brown about Linear Algebra.
Second read the Coordinate Systems introduction please.
SEE ALSO:
The free online book 3D Math Primer for Graphics and Game Development is a very good resource for
learning vector math and other graphic related topics, it is easy to read for beginners and especially
targeted to programmers.
For WCS there is not much to say as, it is what it is: the main world coordinate system, and a drawing
unit can have any real world unit you want. Autodesk added some mechanism to define a scale for
dimension and text entities, but because I am not an AutoCAD user, I am not familiar with it, and further
more I think this is more an AutoCAD topic than a DXF topic.
Object Coordinate System (OCS)
The OCS is used to place planar 2D entities in 3D space. ALL points of a planar entity lay in the same
plane, this is also true if the plane is located in 3D space by an OCS. There are three basic DXF
attributes that gives a 2D entity its spatial form.
Extrusion
The extrusion vector defines the OCS, it is a normal vector to the base plane of a planar entity. This
base plane is always located in the origin of the WCS. But there are some entities like Ellipse, which
have an extrusion vector, but do not establish an OCS. For this entities the extrusion vector defines
only the extrusion direction and thickness defines the extrusion distance, but all other points and
directions in WCS.
Elevation
The elevation value defines the z-axis value for all points of a planar entity, this is an OCS value, and
defines the distance of the entity plane from the base plane.
This value exists only in output from DXF versions prior to R11 as separated DXF attribute (group code
38). In DXF R12 and later, the elevation value is supplied as z-axis value of each point. But as always
in DXF, this simple rule does not apply to all entities: LWPolyline and Hatch have an DXF attribute
elevation as a 3D point, where the z-values of this point is the elevation height and the x-value and the
y-value are 0.
Thickness
Defines the extrusion distance for an entity.
NOTE:
There is a new edition of this tutorial using UCS based transformation, which are available in ezdxf
v0.11 and later: Tutorial for UCS Based Transformations
This edition shows the hard way to accomplish the transformations by low level operations.
Placing 2D Circle in 3D Space
The colors of the system axis follow the AutoCAD standard:
• red is x-axis
• green is y-axis
• blue is z-axis
import ezdxf
from ezdxf.math import OCS
doc = ezdxf.new('R2010')
msp = doc.modelspace()
# For this example the OCS is rotated around x-axis about 45 degree
# OCS z-axis: x=0, y=1, z=1
# extrusion vector must not normalized here
ocs = OCS((0, 1, 1))
msp.add_circle(
# You can place the 2D circle in 3D space
# but you have to convert WCS into OCS
center=ocs.from_wcs((0, 2, 2)),
# center in OCS: (0.0, 0.0, 2.82842712474619)
radius=1,
dxfattribs={
# here the extrusion vector should be normalized,
# which is granted by using the ocs.uz
'extrusion': ocs.uz,
'color': 1,
})
# mark center point of circle in WCS
msp.add_point((0, 2, 2), dxfattribs={'color': 1})
The following image shows the 2D circle in 3D space in AutoCAD Left and Front view. The blue line shows
the OCS z-axis (extrusion direction), elevation is the distance from the origin to the center of the
circle in this case 2.828, and you see that the x- and y-axis of the OCS and the WCS are not aligned.
[image: circle in ocs as side view] [image] [image: circle in ocs as front view] [image]
Placing LWPolyline in 3D Space
For simplicity of calculation I use the UCS class in this example to place a 2D pentagon in 3D space.
# The center of the pentagon should be (0, 2, 2), and the shape is
# rotated around x-axis about 45 degree, to accomplish this I use an
# UCS with z-axis (0, 1, 1) and an x-axis parallel to WCS x-axis.
ucs = UCS(
origin=(0, 2, 2), # center of pentagon
ux=(1, 0, 0), # x-axis parallel to WCS x-axis
uz=(0, 1, 1), # z-axis
)
# calculating corner points in local (UCS) coordinates
points = [Vec3.from_deg_angle((360 / 5) * n) for n in range(5)]
# converting UCS into OCS coordinates
ocs_points = list(ucs.points_to_ocs(points))
# LWPOLYLINE accepts only 2D points and has an separated DXF attribute elevation.
# All points have the same z-axis (elevation) in OCS!
elevation = ocs_points[0].z
msp.add_lwpolyline(
points=ocs_points,
format='xy', # ignore z-axis
close=True,
dxfattribs={
'elevation': elevation,
'extrusion': ucs.uz,
'color': 1,
})
The following image shows the 2D pentagon in 3D space in AutoCAD Left, Front and Top view. The three
lines from the center of the pentagon show the UCS, the three colored lines in the origin show the OCS,
the white lines in the origin show the WCS.
The z-axis of the UCS and the OCS pointing in the same direction (extrusion direction), and the x-axis of
the UCS and the WCS pointing also in the same direction. The elevation is the distance from the origin
to the center of the pentagon and all points of the pentagon have the same elevation, and you see that
the y-axis of the UCS, the OCS and the WCS are not aligned. [image: pentagon in ucs as side view]
[image] [image: pentagon in ucs as front view] [image]
Using UCS to Place 3D Polyline
It is much simpler to use a 3D Polyline to create the 3D pentagon. The UCS class is handy for this
example and all kind of 3D operations.
# Using an UCS simplifies 3D operations, but UCS definition can happen later
# calculating corner points in local (UCS) coordinates without Vec3 class
angle = math.radians(360 / 5)
corners_ucs = [(math.cos(angle * n), math.sin(angle * n), 0) for n in range(5)]
# let's do some transformations
tmatrix = Matrix44.chain( # creating a transformation matrix
Matrix44.z_rotate(math.radians(15)), # 1. rotation around z-axis
Matrix44.translate(0, .333, .333), # 2. translation
)
transformed_corners_ucs = tmatrix.transform_vertices(corners_ucs)
# transform UCS into WCS
ucs = UCS(
origin=(0, 2, 2), # center of pentagon
ux=(1, 0, 0), # x-axis parallel to WCS x-axis
uz=(0, 1, 1), # z-axis
)
corners_wcs = list(ucs.points_to_wcs(transformed_corners_ucs))
msp.add_polyline3d(
points=corners_wcs,
close=True,
)
# add lines from center to corners
center_wcs = ucs.to_wcs((0, .333, .333))
for corner in corners_wcs:
msp.add_line(center_wcs, corner, dxfattribs={'color': 1})
ucs.render_axis(msp)
[image: 3d poyline with UCS] [image]
Placing 2D Text in 3D Space
The problem of placing text in 3D space is the text rotation, which is always counter clockwise around
the OCS z-axis, and 0 degree is the direction of the positive OCS x-axis, and the OCS x-axis is
calculated by the Arbitrary Axis Algorithm.
Calculate the OCS rotation angle by converting the TEXT rotation angle (in UCS or WCS) into a vector or
begin with text direction as vector, transform this direction vector into OCS and convert the OCS vector
back into an angle in the OCS xy-plane (see example), this procedure is available as
UCS.to_ocs_angle_deg() or UCS.to_ocs_angle_rad().
AutoCAD supports thickness for the TEXT entity only for .shx fonts and not for true type fonts.
# Thickness for text works only with shx fonts not with true type fonts
doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'})
ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
# calculation of text direction as angle in OCS:
# convert text rotation in degree into a vector in UCS
text_direction = Vec3.from_deg_angle(-45)
# transform vector into OCS and get angle of vector in xy-plane
rotation = ucs.to_ocs(text_direction).angle_deg
text = msp.add_text(
text="TEXT",
dxfattribs={
# text rotation angle in degrees in OCS
'rotation': rotation,
'extrusion': ucs.uz,
'thickness': .333,
'color': 1,
'style': 'TXT',
})
# set text position in OCS
text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER')
[image: text in ucs as top view] [image] [image: text in ucs as front view] [image]
HINT:
For calculating OCS angles from an UCS, be aware that 2D entities, like TEXT or ARC, are placed
parallel to the xy-plane of the UCS.
Placing 2D Arc in 3D Space
Here we have the same problem as for placing text, you need the start- and end angle of the arc in
degrees in the OCS, and this example also shows a shortcut for calculating the OCS angles.
ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
msp.add_arc(
center=ucs.to_ocs((0, 0)),
radius=1,
start_angle=ucs.to_ocs_angle_deg(45),
end_angle=ucs.to_ocs_angle_deg(270),
dxfattribs={
'extrusion': ucs.uz,
'color': 1,
})
center = ucs.to_wcs((0, 0))
msp.add_line(
start=center,
end=ucs.to_wcs(Vec3.from_deg_angle(45)),
dxfattribs={'color': 1},
)
msp.add_line(
start=center,
end=ucs.to_wcs(Vec3.from_deg_angle(270)),
dxfattribs={'color': 1},
)
[image: arc in ucs as top view] [image] [image: arc in ucs as front view] [image]
Placing Block References in 3D Space
Despite the fact that block references (Insert) can contain true 3D entities like Line or Mesh, the
Insert entity uses the same placing principe as Text or Arc shown in the previous chapters.
Placement by OCS coordinates and rotation about the OCS z-axis, can be achieved the same way as for
generic 2D entities. The DXF attribute Insert.dxf.rotation rotates a block reference around the block
z-axis, which is located in the Block.dxf.base_point. To rotate the block reference around the WCS
x-axis, a transformation of the block z-axis into the WCS x-axis is required by rotating the block z-axis
90 degree counter-clockwise around y-axis by using an UCS:
This is just an excerpt of the important parts, see the whole code of insert.py at github.
# rotate UCS around an arbitrary axis:
def ucs_rotation(ucs: UCS, axis: Vec3, angle: float):
# new in ezdxf v0.11: UCS.rotate(axis, angle)
t = Matrix44.axis_rotate(axis, math.radians(angle))
ux, uy, uz = t.transform_vertices([ucs.ux, ucs.uy, ucs.uz])
return UCS(origin=ucs.origin, ux=ux, uy=uy, uz=uz)
doc = ezdxf.new('R2010', setup=True)
blk = doc.blocks.new('CSYS')
setup_csys(blk)
msp = doc.modelspace()
ucs = ucs_rotation(UCS(), axis=Y_AXIS, angle=90)
# transform insert location to OCS
insert = ucs.to_ocs((0, 0, 0))
# rotation angle about the z-axis (= WCS x-axis)
rotation = ucs.to_ocs_angle_deg(15)
msp.add_blockref('CSYS', insert, dxfattribs={
'extrusion': ucs.uz,
'rotation': rotation,
})
[image] [image]
To rotate a block reference around another axis than the block z-axis, you have to find the rotated
z-axis (extrusion vector) of the rotated block reference, following example rotates the block reference
around the block x-axis by 15 degrees:
# t is a transformation matrix to rotate 15 degree around the x-axis
t = Matrix44.axis_rotate(axis=X_AXIS, angle=math.radians(15))
# transform block z-axis into new UCS z-axis (= extrusion vector)
uz = Vec3(t.transform(Z_AXIS))
# create new UCS at the insertion point, because we are rotating around the x-axis,
# ux is the same as the WCS x-axis and uz is the rotated z-axis.
ucs = UCS(origin=(1, 2, 0), ux=X_AXIS, uz=uz)
# transform insert location to OCS, block base_point=(0, 0, 0)
insert = ucs.to_ocs((0, 0, 0))
# for this case a rotation around the z-axis is not required
rotation = 0
blockref = msp.add_blockref('CSYS', insert, dxfattribs={
'extrusion': ucs.uz,
'rotation': rotation,
})
[image] [image]
The next example shows how to translate a block references with an already established OCS:
# translate a block references with an established OCS
translation = Vec3(-3, -1, 1)
# get established OCS
ocs = blockref.ocs()
# get insert location in WCS
actual_wcs_location = ocs.to_wcs(blockref.dxf.insert)
# translate location
new_wcs_location = actual_wcs_location + translation
# convert WCS location to OCS location
blockref.dxf.insert = ocs.from_wcs(new_wcs_location)
Setting a new insert location is the same procedure without adding a translation vector, just transform
the new insert location into the OCS. [image] [image]
The next operation is to rotate a block reference with an established OCS, rotation axis is the block
y-axis, rotation angle is -90 degrees. First transform block y-axis (rotation axis) and block z-axis
(extrusion vector) from OCS into WCS:
# rotate a block references with an established OCS around the block y-axis about 90 degree
ocs = blockref.ocs()
# convert block y-axis (= rotation axis) into WCS vector
rotation_axis = ocs.to_wcs((0, 1, 0))
# convert local z-axis (=extrusion vector) into WCS vector
local_z_axis = ocs.to_wcs((0, 0, 1))
Build transformation matrix and transform extrusion vector and build new UCS:
# build transformation matrix
t = Matrix44.axis_rotate(axis=rotation_axis, angle=math.radians(-90))
uz = t.transform(local_z_axis)
uy = rotation_axis
# the block reference origin stays at the same location, no rotation needed
wcs_insert = ocs.to_wcs(blockref.dxf.insert)
# build new UCS to convert WCS locations and angles into OCS
ucs = UCS(origin=wcs_insert, uy=uy, uz=uz)
Set new OCS attributes, we also have to set the rotation attribute even though we do not rotate the block
reference around the local z-axis, the new block x-axis (0 deg) differs from OCS x-axis and has to be
adjusted:
# set new OCS
blockref.dxf.extrusion = ucs.uz
# set new insert
blockref.dxf.insert = ucs.to_ocs((0, 0, 0))
# set new rotation: we do not rotate the block reference around the local z-axis,
# but the new block x-axis (0 deg) differs from OCS x-axis and has to be adjusted
blockref.dxf.rotation = ucs.to_ocs_angle_deg(0)
[image] [image]
And here is the point, where my math knowledge ends, for more advanced CAD operation you have to look
elsewhere.
Tutorial for UCS Based Transformations
The ezdxf version v0.13 introduced a transformation interface for DXF primitives, which makes working
with OCS/UCS much easier. This is a new edition of the Tutorial for OCS/UCS Usage. Please read the old
tutorial for the basics about the OCS.
For this tutorial we don’t have to worry about the OCS and the extrusion vector, this is done
automatically by the transform() method of each DXF entity.
Placing 2D Circle in 3D Space
To recreate the situation of the old tutorial instantiate a new UCS and rotate it around the local
x-axis. Use UCS coordinates to place the 2D CIRCLE in 3D space and transform the UCS coordinates to the
WCS.
import math
import ezdxf
from ezdxf.math import UCS
doc = ezdxf.new('R2010')
msp = doc.modelspace()
ucs = UCS() # New default UCS
# All rotation angles in radians, and rotation
# methods always return a new UCS.
ucs = ucs.rotate_local_x(math.radians(-45))
circle = msp.add_circle(
# Use UCS coordinates to place the 2d circle in 3d space
center=(0, 0, 2),
radius=1,
dxfattribs={'color': 1}
)
circle.transform(ucs.matrix)
# mark center point of circle in WCS
msp.add_point((0, 0, 2), dxfattribs={'color': 1}).transform(ucs.matrix)
[image: circle in ucs as side view] [image] [image: circle in ucs as front view] [image]
Placing LWPolyline in 3D Space
Simplified LWPOLYLINE example:
# The center of the pentagon should be (0, 2, 2), and the shape is
# rotated around x-axis about -45 degree
ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
msp.add_lwpolyline(
# calculating corner points in UCS coordinates
points=(Vec3.from_deg_angle((360 / 5) * n) for n in range(5)),
format='xy', # ignore z-axis
close=True,
dxfattribs={
'color': 1,
}
).transform(ucs.matrix)
The 2D pentagon in 3D space in BricsCAD Left and Front view. [image: pentagon in ucs as side view]
[image] [image: pentagon in ucs as front view] [image]
Using UCS to Place 3D Polyline
Simplified POLYLINE example: Using a first UCS to transform the POLYLINE and a second UCS to place the
POLYLINE in 3D space.
# using an UCS simplifies 3D operations, but UCS definition can happen later
# calculating corner points in local (UCS) coordinates without Vec3 class
angle = math.radians(360 / 5)
corners_ucs = [(math.cos(angle * n), math.sin(angle * n), 0) for n in range(5)]
# let's do some transformations by UCS
transformation_ucs = UCS().rotate_local_z(math.radians(15)) # 1. rotation around z-axis
transformation_ucs.shift((0, .333, .333)) # 2. translation (inplace)
corners_ucs = list(transformation_ucs.points_to_wcs(corners_ucs))
location_ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
msp.add_polyline3d(
points=corners_ucs,
close=True,
dxfattribs={
'color': 1,
}
).transform(location_ucs.matrix)
# Add lines from the center of the POLYLINE to the corners
center_ucs = transformation_ucs.to_wcs((0, 0, 0))
for corner in corners_ucs:
msp.add_line(
center_ucs, corner, dxfattribs={'color': 1}
).transform(location_ucs.matrix)
[image: 3d poyline with UCS] [image]
Placing 2D Text in 3D Space
The problem with the text rotation in the old tutorial disappears with the new UCS based transformation
method:
AutoCAD supports thickness for the TEXT entity only for .shx fonts and not for true type fonts.
# thickness for text works only with shx fonts not with true type fonts
doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'})
ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
text = msp.add_text(
text="TEXT",
dxfattribs={
# text rotation angle in degrees in UCS
'rotation': -45,
'thickness': .333,
'color': 1,
'style': 'TXT',
}
)
# set text position in UCS
text.set_pos((0, 0, 0), align='MIDDLE_CENTER')
text.transform(ucs.matrix)
[image: text in ucs as top view] [image] [image: text in ucs as front view] [image]
Placing 2D Arc in 3D Space
Same as for the text example, OCS angle transformation can be ignored:
ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
CENTER = (0, 0)
START_ANGLE = 45
END_ANGLE = 270
msp.add_arc(
center=CENTER,
radius=1,
start_angle=START_ANGLE,
end_angle=END_ANGLE,
dxfattribs={'color': 6},
).transform(ucs.matrix)
msp.add_line(
start=CENTER,
end=Vec3.from_deg_angle(START_ANGLE),
dxfattribs={'color': 6},
).transform(ucs.matrix)
msp.add_line(
start=CENTER,
end=Vec3.from_deg_angle(END_ANGLE),
dxfattribs={'color': 6},
).transform(ucs.matrix)
[image: arc in ucs as top view] [image] [image: arc in ucs as front view] [image]
Placing Block References in 3D Space
Despite the fact that block references (INSERT) can contain true 3D entities like LINE or MESH, the
INSERT entity uses the same placing principe as TEXT or ARC shown in the previous sections.
To rotate the block reference 15 degrees around the WCS x-axis, we place the block reference in the
origin of the UCS, and rotate the UCS 90 degrees around its local y-axis, to align the UCS z-axis with
the WCS x-axis:
This is just an excerpt of the important parts, see the whole code of insert.py at github.
doc = ezdxf.new('R2010', setup=True)
blk = doc.blocks.new('CSYS')
setup_csys(blk)
msp = doc.modelspace()
ucs = UCS().rotate_local_y(angle=math.radians(90))
msp.add_blockref(
'CSYS',
insert=(0, 0),
# rotation around the block z-axis (= WCS x-axis)
dxfattribs={'rotation': 15},
).transform(ucs.matrix)
[image] [image]
A more simple approach is to ignore the rotate attribute at all and just rotate the UCS. To rotate a
block reference around any axis rather than the block z-axis, rotate the UCS into the desired position.
The following example rotates the block reference around the block x-axis by 15 degrees:
ucs = UCS(origin=(1, 2, 0)).rotate_local_x(math.radians(15))
blockref = msp.add_blockref('CSYS', insert=(0, 0, 0))
blockref.transform(ucs.matrix)
[image] [image]
The next example shows how to translate a block references with an already established OCS:
# New UCS at the translated location, axis aligned to the WCS
ucs = UCS((-3, -1, 1))
# Transform an already placed block reference, including
# the transformation of the established OCS.
blockref.transform(ucs.matrix)
[image] [image]
The next operation is to rotate a block reference with an established OCS, rotation axis is the block
y-axis, rotation angle is -90 degrees. The idea is to create an UCS in the origin of the already placed
block reference, UCS axis aligned to the block axis and resetting the block reference parameters for a
new WCS transformation.
# Get UCS at the block reference insert location, UCS axis aligned
# to the block axis.
ucs = blockref.ucs()
# Rotate UCS around the local y-axis.
ucs = ucs.rotate_local_y(math.radians(-90))
Reset block reference parameters, this places the block reference in the UCS origin and aligns the block
axis to the UCS axis, now we do a new transformation from UCS to WCS:
# Reset block reference parameters to place block reference in
# UCS origin, without any rotation and OCS.
blockref.reset_transformation()
# Transform block reference from UCS to WCS
blockref.transform(ucs.matrix)
[image] [image]
Tutorial for Linear Dimensions
The Dimension entity is the generic entity for all dimension types, but unfortunately AutoCAD is not
willing to show a dimension line defined only by this dimension entity, it also needs an anonymous block
which contains the dimension line shape constructed by DXF primitives like LINE and TEXT entities, this
representation is called the dimension line rendering in this documentation, beside the fact that this is
not a real graphical rendering. BricsCAD is a much more friendly CAD application, which do show the
dimension entity without the graphical rendering as block, which was very useful for testing, because
there is no documentation how to apply all the dimension style variables (more than 80). This seems to
be the reason why dimension lines are rendered so differently by many CAD application.
Don’t expect to get the same rendering results by ezdxf as you get from AutoCAD. Ezdxf tries to be as
close to the results rendered by BricsCAD, but it is not possible to implement all the various
combinations of dimension style parameters, which often affect one another.
NOTE:
Ezdxf does not consider all DIMSTYLE variables, so the rendering results are different from CAD
applications.
Text rendering is another problem, because ezdxf has no real rendering engine. Some font properties,
like the real text width, which is only available to ezdxf if the Matplotlib package is installed and
this value may also vary slightly for different CAD applications. Without access to the Matplotlib
package the text properties in ezdxf are based on an abstract monospaced font and are bigger than
required by true type fonts.
Not all DIMENSION and DIMSTYLE features are supported by all DXF versions, especially DXF R12 does not
support many features, but in this case the required rendering of dimension lines is an advantage,
because if the application just shows the rendered block, all features which can be used in DXF R12 will
be displayed, but these features will disappear if the dimension line will be edited in the CAD
application. Ezdxf writes only the supported DIMVARS of the used DXF version to avoid invalid DXF files.
So it is not that critical to know all the supported features of a DXF version, except for limits and
tolerances, ezdxf uses the advanced features of the MTEXT entity to create limits and tolerances and
therefore they are not supported (displayed) in DXF R12 files.
SEE ALSO:
• Graphical reference of many DIMVARS and some advanced information: DIMSTYLE Table
• Source code file standards.py shows how to create your own DIMSTYLES.
• The Script dimension_linear.py shows examples for linear dimensions.
Horizontal Dimension
import ezdxf
# Create a DXF R2010 document:
# Use argument setup=True to setup the default dimension styles.
doc = ezdxf.new("R2010", setup=True)
# Add new dimension entities to the modelspace:
msp = doc.modelspace()
# Add a LINE entity for visualization, not required to create the DIMENSION
# entity:
msp.add_line((0, 0), (3, 0))
# Add a horizontal linear DIMENSION entity:
dim = msp.add_linear_dim(
base=(3, 2), # location of the dimension line
p1=(0, 0), # 1st measurement point
p2=(3, 0), # 2nd measurement point
dimstyle="EZDXF", # default dimension style
)
# Necessary second step to create the BLOCK entity with the dimension geometry.
# Additional processing of the DIMENSION entity could happen between adding
# the entity and the rendering call.
dim.render()
doc.saveas("dim_linear_horiz.dxf")
[image]
The example above creates a horizontal Dimension entity. The default dimension style “EZDXF” is defined
as:
• 1 drawing unit = 1m
• measurement text height = 0.25 (drawing scale = 1:100)
• the length factor dimlfac = 100, which creates a measurement text in cm.
• arrow is “ARCHTICK”, arrow size dimasz = 0.175
Every dimension style which does not exist will be replaced by the dimension style “Standard” at DXF
export by save() or saveas() (e.g. dimension style setup was not initiated).
The base point defines the location of the dimension line, ezdxf accepts any point on the dimension line,
the point p1 defines the start point of the first extension line, which also defines the first
measurement point and the point p2 defines the start point of the second extension line, which also
defines the second measurement point.
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the
dimension entity is stored as attribute dim.dimension.
Vertical and Rotated Dimension
Argument angle defines the angle of the dimension line in relation to the x-axis of the WCS or UCS,
measurement is the distance between first and second measurement point in direction of angle.
# assignment to dim is not necessary, if no additional processing happens
msp.add_linear_dim(base=(3, 2), p1=(0, 0), p2=(3, 0), angle=-30).render()
doc.saveas("dim_linear_rotated.dxf")
[image]
For a vertical dimension set argument angle to 90 degree, but in this example the vertical distance would
be 0.
Aligned Dimension
An aligned dimension line is parallel to the line defined by the definition points p1 and p2. The
placement of the dimension line is defined by the argument distance, which is the distance between the
definition line and the dimension line. The distance of the dimension line is orthogonal to the base line
in counter clockwise orientation.
msp.add_line((0, 2), (3, 0))
dim = msp.add_aligned_dim(p1=(0, 2), p2=(3, 0), distance=1)
doc.saveas("dim_linear_aligned.dxf")
[image]
Dimension Style Override
Many dimension styling options are defined by the associated DimStyle entity. But often you wanna change
just a few settings without creating a new dimension style, therefore the DXF format has a protocol to
store this changed settings in the dimension entity itself. This protocol is supported by ezdxf and
every factory function which creates dimension entities supports the override argument. This override
argument is a simple Python dictionary (e.g. override = {"dimtad": 4}, place measurement text below
dimension line).
The overriding protocol is managed by the DimStyleOverride object, which is returned by the most
dimension factory functions.
Placing Measurement Text
The default location of the measurement text depends on various DimStyle parameters and is applied if no
user defined text location is defined.
Default Text Locations
“Horizontal direction” means in direction of the dimension line and “vertical direction” means
perpendicular to the dimension line direction.
The “horizontal” location of the measurement text is defined by dimjust:
┌───┬───────────────────────────────────────┐
│ 0 │ Center of dimension line │
├───┼───────────────────────────────────────┤
│ 1 │ Left side of the dimension line, near │
│ │ first extension line │
├───┼───────────────────────────────────────┤
│ 2 │ Right side of the dimension line, │
│ │ near second extension line │
├───┼───────────────────────────────────────┤
│ 3 │ Over first extension line │
├───┼───────────────────────────────────────┤
│ 4 │ Over second extension line │
└───┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2), p1=(0, 0), p2=(3, 0), override={"dimjust": 1}
).render()
[image]
The “vertical” location of the measurement text relative to the dimension line is defined by dimtad:
┌───┬───────────────────────────────────────┐
│ 0 │ Center, it is possible to adjust the │
│ │ vertical location by dimtvp │
├───┼───────────────────────────────────────┤
│ 1 │ Above │
├───┼───────────────────────────────────────┤
│ 2 │ Outside, handled like Above by ezdxf │
├───┼───────────────────────────────────────┤
│ 3 │ JIS, handled like Above by ezdxf │
├───┼───────────────────────────────────────┤
│ 4 │ Below │
└───┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2), p1=(0, 0), p2=(3, 0), override={"dimtad": 4}
).render()
[image]
The distance between text and dimension line is defined by dimgap.
The DimStyleOverride object has a method set_text_align() to set the default text location in an easy
way, this is also the reason for the 2 step creation process of dimension entities:
dim = msp.add_linear_dim(base=(3, 2), p1=(0, 0), p2=(3, 0))
dim.set_text_align(halign="left", valign="center")
dim.render()
┌────────┬───────────────────────────────────────┐
│ halign │ “left”, “right”, “center”, “above1”, │
│ │ “above2” │
├────────┼───────────────────────────────────────┤
│ valign │ “above”, “center”, “below” │
└────────┴───────────────────────────────────────┘
Run function example_for_all_text_placings_R2007() in the example script dimension_linear.py to create a
DXF file with all text placings supported by ezdxf.
User Defined Text Locations
Beside the default location, it is possible to locate the measurement text freely.
Location Relative to Origin
The user defined text location can be set by the argument location in most dimension factory functions
and always references the midpoint of the measurement text:
msp.add_linear_dim(
base=(3, 2), p1=(3, 0), p2=(6, 0), location=(4, 4)
).render()
[image]
The location is relative to the origin of the active coordinate system or WCS if no UCS is defined in the
render() method, the user defined location can also be set by user_location_override().
Location Relative to Center of Dimension Line
The method set_location() has additional features for linear dimensions. Argument leader = True adds a
simple leader from the measurement text to the center of the dimension line and argument relative = True
places the measurement text relative to the center of the dimension line.
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_location(location=(-1, 1), leader=True, relative=True)
dim.render()
[image]
Location Relative to Default Location
The method shift_text() shifts the measurement text away from the default text location. The shifting
directions are aligned to the text direction, which is the direction of the dimension line in most cases,
dh (for delta horizontal) shifts the text parallel to the text direction, dv (for delta vertical) shifts
the text perpendicular to the text direction. This method does not support leaders.
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.shift_text(dh=1, dv=1)
dim.render()
[image]
Overriding Text Rotation
All factory methods supporting the argument text_rotation can override the measurement text rotation.
The user defined rotation is relative to the render UCS x-axis (default is WCS).
Measurement Text Formatting and Styling
Text Properties
┌──────────┬───────────────────────────────────────┐
│ DIMVAR │ Description │
├──────────┼───────────────────────────────────────┤
│ dimtxsty │ Specifies the text style of the │
│ │ dimension as Textstyle name. │
├──────────┼───────────────────────────────────────┤
│ dimtxt │ Text height in drawing units. │
├──────────┼───────────────────────────────────────┤
│ dimclrt │ Measurement text color as AutoCAD │
│ │ Color Index (ACI). │
└──────────┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimtxsty": "Standard",
"dimtxt": 0.35,
"dimclrt": 1,
}
).render()
[image]
Background Filling
Background fillings are supported since DXF R2007, and ezdxf uses the MTEXT entity to implement this
feature, so setting background filling in DXF R12 has no effect. The DIMVAR dimtfill defines the kind of
background filling and the DIMVAR dimtfillclr defines the fill color.
┌─────────────┬───────────────────────────────────────┐
│ DIMVAR │ Description │
├─────────────┼───────────────────────────────────────┤
│ dimtfill │ Enables background filling if bigger │
│ │ than 0 │
├─────────────┼───────────────────────────────────────┤
│ dimtfillclr │ Fill color as AutoCAD Color Index │
│ │ (ACI), if dimtfill is 2 │
└─────────────┴───────────────────────────────────────┘
┌──────────┬──────────────────────────────┐
│ dimtfill │ Description │
├──────────┼──────────────────────────────┤
│ 0 │ disabled │
├──────────┼──────────────────────────────┤
│ 1 │ canvas color │
├──────────┼──────────────────────────────┤
│ 2 │ color defined by dimtfillclr │
└──────────┴──────────────────────────────┘
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimtfill": 2,
"dimtfillclr": 1,
}
).render()
[image]
Text Formatting
• decimal places: dimdec defines the number of decimal places displayed for the primary units of a
dimension. (DXF R2000)
• decimal point character: dimdsep defines the decimal point as ASCII code, get the ASCII code by
ord('.')
• rounding: dimrnd, rounds all dimensioning distances to the specified value, for instance, if dimrnd is
set to 0.25, all distances round to the nearest 0.25 unit. If dimrnd is set to 1.0, all distances round
to the nearest integer. For more information look at the documentation of the ezdxf.math.xround()
function.
• zero trimming: dimzin, ezdxf supports only a subset of values:
• 4 to suppress leading zeros
• 8 to suppress trailing zeros
• 12 as the combination of both
• measurement factor: scale measurement by factor dimlfac, e.g. to get the dimensioning text in cm for a
DXF file where 1 drawing unit represents 1m, set dimlfac to 100.
• text template: dimpost, “<>” represents the measurement text, e.g. “~<>cm” produces “~300cm” for
measurement in previous example.
To set this values the ezdxf.entities.DimStyle.set_text_format() and
ezdxf.entities.DimStyleOverride.set_text_format() methods are very recommended.
Overriding Measurement Text
This feature allows overriding the real measurement text by a custom measurement text, the text is stored
as string in the Dimension entity as attribute text. Special values of the text attribute are: one space
“ “ to suppress the measurement text at all, an empty string “” or “<>” to display the real measurement.
All factory functions have an explicit text argument, which always replaces the text value in the
dxfattribs dict.
msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0), text=">1m").render()
[image]
Dimension Line Properties
The dimension line color is defined by the DIMVAR dimclrd as AutoCAD Color Index (ACI), dimclrd and also
defines the color of the arrows. The linetype is defined by dimltype and requires DXF R2007. The
lineweight is defined by dimlwd and requires DXF R2000, see also the lineweight reference for valid
values. The dimdle is the extension of the dimension line beyond the extension lines, this dimension
line extension is not supported for all arrows.
┌──────────┬───────────────────────────────────────┐
│ DIMVAR │ Description │
├──────────┼───────────────────────────────────────┤
│ dimclrd │ dimension line and arrows color as │
│ │ AutoCAD Color Index (ACI) │
├──────────┼───────────────────────────────────────┤
│ dimltype │ linetype of dimension line │
├──────────┼───────────────────────────────────────┤
│ dimlwd │ line weight of dimension line │
├──────────┼───────────────────────────────────────┤
│ dimdle │ extension of dimension line in │
│ │ drawing units │
└──────────┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimclrd": 1, # red
"dimdle": 0.25,
"dimltype": "DASHED2",
"dimlwd": 35, # 0.35mm line weight
}
).render()
[image]
DimStyleOverride() method:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_dimline_format(
color=1, linetype="DASHED2", lineweight=35, extension=0.25
)
dim.render()
Extension Line Properties
The extension line color is defined by the DIMVAR dimclre as AutoCAD Color Index (ACI). The linetype for
the first and the second extension line is defined by dimltex1 and dimltex2 and requires DXF R2007. The
lineweight is defined by dimlwe and required DXF R2000, see also the lineweight reference for valid
values.
The dimexe is the extension of the extension line beyond the dimension line, and dimexo defines the
offset of the extension line from the measurement point.
┌──────────┬───────────────────────────────────────┐
│ DIMVAR │ Description │
├──────────┼───────────────────────────────────────┤
│ dimclre │ extension line color as AutoCAD Color │
│ │ Index (ACI) │
├──────────┼───────────────────────────────────────┤
│ dimltex1 │ linetype of first extension line │
├──────────┼───────────────────────────────────────┤
│ dimltex2 │ linetype of second extension line │
├──────────┼───────────────────────────────────────┤
│ dimlwe │ line weight of extension line │
├──────────┼───────────────────────────────────────┤
│ dimexe │ extension beyond dimension line in │
│ │ drawing units │
├──────────┼───────────────────────────────────────┤
│ dimexo │ offset of extension line from │
│ │ measurement point │
├──────────┼───────────────────────────────────────┤
│ dimfxlon │ set to 1 to enable fixed length │
│ │ extension line │
├──────────┼───────────────────────────────────────┤
│ dimfxl │ length of fixed length extension line │
│ │ in drawing units │
├──────────┼───────────────────────────────────────┤
│ dimse1 │ suppress first extension line if 1 │
├──────────┼───────────────────────────────────────┤
│ dimse2 │ suppress second extension line if 1 │
└──────────┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimclre": 1, # red
"dimltex1": "DASHED2",
"dimltex2": "CENTER2",
"dimlwe": 35, # 0.35mm line weight
"dimexe": 0.3, # length above dimension line
"dimexo": 0.1, # offset from measurement point
}
).render()
[image]
DimStyleOverride() methods:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_extline_format(color=1, lineweight=35, extension=0.3, offset=0.1)
dim.set_extline1(linetype="DASHED2")
dim.set_extline2(linetype="CENTER2")
dim.render()
Fixed length extension lines are supported in DXF R2007, set dimfxlon to 1 and dimfxl defines the length
of the extension line starting at the dimension line.
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimfxlon": 1, # fixed length extension lines
"dimexe": 0.2, # length above dimension line
"dimfxl": 0.4, # length below dimension line
}
).render()
[image]
DimStyleOverride() method:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_extline_format(extension=0.2, fixed_length=0.4)
dim.render()
To suppress extension lines set dimse1 to 1 to suppress the first extension line and dimse2 to 1 to
suppress the second extension line.
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimse1": 1, # suppress first extension line
"dimse2": 1, # suppress second extension line
"dimblk": ezdxf.ARROWS.closed_filled, # arrows just looks better
}
).render()
[image]
DimStyleOverride() methods:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_arrows(blk=ezdxf.ARROWS.closed_filled)
dim.set_extline1(disable=True)
dim.set_extline2(disable=True)
dim.render()
Arrows
“Arrows” mark then beginning and the end of a dimension line, and most of them do not look like arrows.
DXF distinguish between the simple tick (a slanted line) and arrows as blocks.
To use a simple tick as “arrow” set dimtsz to a value greater than 0, this also disables arrow blocks as
side effect:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_tick(size=0.25)
dim.render()
Ezdxf uses the “ARCHTICK” block at double size to render the tick (AutoCAD and BricsCad just draw a
simple line), so there is no advantage of using the tick instead of an arrow.
Using arrows:
dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
dim.set_arrow(blk="OPEN_30", size=0.25)
dim.render()
┌─────────┬───────────────────────────────────────┐
│ DIMVAR │ Description │
├─────────┼───────────────────────────────────────┤
│ dimtsz │ tick size in drawing units, set to 0 │
│ │ to use arrows │
├─────────┼───────────────────────────────────────┤
│ dimblk │ set both arrow block names at once │
├─────────┼───────────────────────────────────────┤
│ dimblk1 │ first arrow block name │
├─────────┼───────────────────────────────────────┤
│ dimblk2 │ second arrow block name │
├─────────┼───────────────────────────────────────┤
│ dimasz │ arrow size in drawing units │
└─────────┴───────────────────────────────────────┘
msp.add_linear_dim(
base=(3, 2),
p1=(3, 0),
p2=(6, 0),
override={
"dimtsz": 0, # set tick size to 0 to enable arrow usage
"dimasz": 0.25, # arrow size in drawing units
"dimblk": "OPEN_30", # arrow block name
}
).render()
The dimension line extension (dimdle) works only for a few arrow blocks and the simple tick:
• “ARCHTICK”
• “OBLIQUE”
• “NONE”
• “SMALL”
• “DOTSMALL”
• “INTEGRAL”
Arrow Shapes
[image]
Arrow Names
The arrow names are stored as attributes in the ezdxf.ARROWS object.
─────────────────────────────────────────────
closed_filled “” (empty string)
─────────────────────────────────────────────
dot “DOT”
─────────────────────────────────────────────
dot_small “DOTSMALL”
─────────────────────────────────────────────
dot_blank “DOTBLANK”
─────────────────────────────────────────────
origin_indicator “ORIGIN”
─────────────────────────────────────────────
origin_indicator_2 “ORIGIN2”
─────────────────────────────────────────────
open “OPEN”
─────────────────────────────────────────────
right_angle “OPEN90”
─────────────────────────────────────────────
open_30 “OPEN30”
─────────────────────────────────────────────
closed “CLOSED”
─────────────────────────────────────────────
dot_smallblank “SMALL”
─────────────────────────────────────────────
none “NONE”
─────────────────────────────────────────────
oblique “OBLIQUE”
─────────────────────────────────────────────
box_filled “BOXFILLED”
─────────────────────────────────────────────
box “BOXBLANK”
─────────────────────────────────────────────
closed_blank “CLOSEDBLANK”
─────────────────────────────────────────────
datum_triangle_filled “DATUMFILLED”
─────────────────────────────────────────────
datum_triangle “DATUMBLANK”
─────────────────────────────────────────────
integral “INTEGRAL”
─────────────────────────────────────────────
architectural_tick “ARCHTICK”
─────────────────────────────────────────────
ez_arrow “EZ_ARROW”
─────────────────────────────────────────────
ez_arrow_blank “EZ_ARROW_BLANK”
─────────────────────────────────────────────
ez_arrow_filled “EZ_ARROW_FILLED”
┌───────────────────────┬───────────────────┐
│ │ │
Tolerances and Limits │ │ │
--
EXTERNAL REFERENCES (XREF)
New in version 1.1.
Attached XREFs are links to the modelspace of a specified drawing file. Changes made to the referenced
drawing are automatically reflected in the current drawing when it’s opened or if the XREF is reloaded.
XREFs can be nested within other XREFs: that is, you can attach an XREF that contains another XREF. You
can attach as many copies of an XREF as you want, and each copy can have a different position, scale, and
rotation.
You can also overlay an XREF on your drawing. Unlike an attached XREF, an overlaid XREF is not included
when the drawing is itself attached or overlaid as an XREF to another drawing.
DXF Files as Attached XREFs
IMPORTANT:
AutoCAD can only display DWG files as attached XREFs but ezdxf can only create DXF files.
Consequently, any DXF file attached as an XREF to a DXF document must be converted to DWG in order to
be viewed in AutoCAD. Fortunately, other CAD applications are more cooperative, BricsCAD has no
problem displaying DXF files as XREFs, although it is not possible to attach a DXF file as an XREF in
the BricsCAD application itself.
The ezdxf.xref module provides an interface for working with XREFs.
• attach() - attach a DXF/DWG file as XREF
• detach() - detach a BLOCK definition as XREF
• embed() - embed an XREF as a BLOCK definition
• dxf_info() - scans a DXF file for basic settings and properties
For loading the content of DWG files is a loading function required, which loads the DWG file as Drawing
document. The odafc add-on module provides such a function: readfile()
SEE ALSO:
• Tutorial for External References
XREF Structures
An XREF is a normal block definition located in the BLOCKS section with special flags set and a filename
to the referenced DXF/DWG file and without any content, the block content is the modelspace of the
referenced file. An XREF can be referenced (inserted) by one or multiple INSERT entities.
Find block definitions in the BLOCKS section:
for block_layout in doc.blocks:
block = block_layout.block # the BLOCK entity
if block.is_xref:
handle_xref(block_layout)
elif block.is_xref_overlay:
handle_xref_overlay(block_layout)
Find XREF references in modelspace:
for insert in msp.query("INSERT"):
if insert.is_xref:
handle_xref_reference(insert)
# ... or get the XREF definition
block_layout = insert.block()
if block_layout is not None:
handle_xref_definition(block_layout)
Use the helper function define() to create your own XREF definition, the attach() creates this definition
automatically and raises an exception if the block already exists.
Supported Entities
The current implementation supports only copyable and transformable DXF entities, these are all basic
entity types as LINE, CIRCLE, … and block references and their associated required table entries and
objects from the OBJECTS section.
Unsupported are all ACIS based entities, the ACAD_TABLE entity, preserved unknown entities wrapped in a
DXFTagStorage class, proxy entities and objects. Support for these entities may be added in a later
version of ezdxf. Unsupported entities are ignored and do not raise exceptions.
Most document features stored in the HEADER and OBJECTS sections are not supported by this module like
GROUPS, LAYER_FILTER, GEODATA, SUN.
Importing Data and Resources
The ezdxf.xref module replaces the Importer add-on.
The basic functionality of the ezdxf.xref module is loading data from external files including their
required resources, which is an often requested feature by users for importing data from other DXF files
into the current document.
The Importer add-on was very limited and removed many resources, where the ezdxf.xref module tries to
preserve as much information as possible.
• load_modelspace() - loads the modelspace content from another DXF document
• load_paperspace() - loads a paperspace layout from another DXF document
• write_block() - writes entities into the modelspace of a new DXF document
• Loader - low level loading interface
High Level Functions
ezdxf.xref.attach(doc: Drawing, *, block_name: str, filename: str, insert: UVec = (0, 0, 0), scale: float
= 1.0, rotation: float = 0.0, overlay=False) -> Insert
Attach the file filename to the host document as external reference (XREF) and creates a default
block reference for the XREF in the modelspace of the document. The function raises an
XrefDefinitionError exception if the block definition already exist, but an XREF can be inserted
multiple times by adding additional block references:
msp.add_blockref(block_name, insert=another_location)
IMPORTANT:
If the XREF has different drawing units than the host document, the scale factor between these
units must be applied as a uniform scale factor to the block reference! Unfortunately the XREF
drawing units can only be detected by scanning the HEADER section of a document by the function
dxf_info() and is therefore not done automatically by this function. Advice: always use the
same units for all drawings of a project!
Parameters
• doc – host DXF document
• block_name – name of the XREF definition block
• filename – file name of the XREF
• insert – location of the default block reference
• scale – uniform scaling factor
• rotation – rotation angle in degrees
• overlay – creates an XREF overlay if True and an XREF attachment otherwise
Returns
default block reference for the XREF
Return type
Insert
Raises XrefDefinitionError – block with same name exist
New in version 1.1.
ezdxf.xref.define(doc: Drawing, block_name: str, filename: str, overlay=False) -> None
Add an external reference (xref) definition to a document.
XREF attachment types:
• attached: the XREF that’s inserted into this drawing is also present in a document to which this
document is inserted as an XREF.
• overlay: the XREF that’s inserted into this document is not present in a document to which this
document is inserted as an XREF.
Parameters
• doc – host document
• block_name – name of the xref block
• filename – external reference filename
• overlay – creates an XREF overlay if True and an XREF attachment otherwise
Raises XrefDefinitionError – block with same name exist
New in version 1.1.
ezdxf.xref.detach(block: BlockLayout, *, xref_filename: str | PathLike, overlay=False) -> Drawing
Write the content of block into the modelspace of a new DXF document and convert block to an
external reference (XREF). The new DXF document has to be written by the caller:
xref_doc.saveas(xref_filename). This way it is possible to convert the DXF document to DWG by the
odafc add-on if necessary:
xref_doc = xref.detach(my_block, "my_block.dwg")
odafc.export_dwg(xref_doc, "my_block.dwg")
It’s recommended to clean up the entity database of the host document afterwards:
doc.entitydb.purge()
The function does not create any block references. These references should already exist and do
not need to be changed since references to blocks and XREFs are the same.
Parameters
• block – block definition to detach
• xref_filename – name of the external referenced file
• overlay – creates an XREF overlay if True and an XREF attachment otherwise
New in version 1.1.
ezdxf.xref.dxf_info(filename: str | PathLike) -> DXFInfo
Scans the HEADER section of a DXF document and returns a DXFInfo object, which contains
information about the DXF version, text encoding, drawing units and insertion base point.
Raises IOError – not a DXF file or a generic IO error
ezdxf.xref.embed(xref: BlockLayout, *, load_fn: Callable[[str], Drawing] | None = None, search_paths:
Iterable[Path | str] = tuple(), conflict_policy=ConflictPolicy.XREF_PREFIX) -> None
Loads the modelspace of the XREF as content into a block layout.
The loader function loads the XREF as Drawing object, by default the function ezdxf.readfile() is
used to load DXF files. To load DWG files use the readfile() function from the ezdxf.addons.odafc
add-on. The ezdxf.recover.readfile() function is very robust for reading DXF files with errors.
If the XREF path isn’t absolute the XREF is searched in the folder of the host DXF document and in
the search_path folders.
Parameters
• xref – BlockLayout of the XREF document
• load_fn – function to load the content of the XREF as Drawing object
• search_paths – list of folders to search for XREFS, default is the folder of the host
document or the current directory if no filepath is set
• conflict_policy – how to resolve name conflicts
Raises
• XrefDefinitionError – argument xref is not a XREF definition
• FileNotFoundError – XREF file not found
• DXFVersionError – cannot load a XREF with a newer DXF version than the host
document, try the odafc add-on to downgrade the XREF
document or upgrade the host document
New in version 1.1.
ezdxf.xref.load_modelspace(sdoc: Drawing, tdoc: Drawing, filter_fn: Callable[[DXFEntity], bool] | None =
None, conflict_policy=ConflictPolicy.KEEP) -> None
Loads the modelspace content of the source document into the modelspace of the target document.
The filter function filter_fn gets every source entity as input and returns True to load the
entity or False otherwise.
Parameters
• sdoc – source document
• tdoc – target document
• filter_fn – optional function to filter entities from the source modelspace
• conflict_policy – how to resolve name conflicts
New in version 1.1.
ezdxf.xref.load_paperspace(psp: Paperspace, tdoc: Drawing, filter_fn: Callable[[DXFEntity], bool] | None
= None, conflict_policy=ConflictPolicy.KEEP) -> None
Loads the paperspace layout psp into the target document. The filter function filter_fn gets
every source entity as input and returns True to load the entity or False otherwise.
Parameters
• psp – paperspace layout to load
• tdoc – target document
• filter_fn – optional function to filter entities from the source paperspace layout
• conflict_policy – how to resolve name conflicts
New in version 1.1.
ezdxf.xref.write_block(entities: Sequence[DXFEntity], *, origin: UVec = (0, 0, 0)) -> Drawing
Write entities into the modelspace of a new DXF document.
This function is called “write_block” because the new DXF document can be used as an external
referenced block. This function is similar to the WBLOCK command in CAD applications.
Virtual entities are not supported, because each entity needs a real database- and owner handle.
Parameters
• entities – DXF entities to write
• origin – block origin, defines the point in the modelspace which will be inserted at the
insert location of the block reference
Raises EntityError – virtual entities are not supported
New in version 1.1.
Conflict Policy
class ezdxf.xref.ConflictPolicy(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
These conflict policies define how to handle resource name conflicts.
New in version 1.1.
KEEP Keeps the existing resource name of the target document and ignore the resource from the
source document.
XREF_PREFIX
This policy handles the resource import like CAD applications by always renaming the loaded
resources to <xref>$0$<name>, where xref is the name of source document, the $0$ part is a
number to create a unique resource name and <name> is the name of the resource itself.
NUM_PREFIX
This policy renames the loaded resources to $0$<name> only if the resource <name> already
exists. The $0$ prefix is a number to create a unique resource name and <name> is the name
of the resource itself.
Low Level Loading Interface
The Loader class is the basic building block for loading entities and resources. The class manages a list
of loading commands which is executed at once by calling the Loader.execute() method. It is important to
execute the commands at once to get a consistent renaming of resources when using resource name prefixes
otherwise the loaded resources would get a new unique name at each loading process even when the
resources are loaded from the same document.
class ezdxf.xref.Loader(sdoc: Drawing, tdoc: Drawing, conflict_policy=ConflictPolicy.KEEP)
Load entities and resources from the source DXF document sdoc into the target DXF document.
Parameters
• sdoc – source DXF document
• tdoc – target DXF document
• conflict_policy – ConflictPolicy
load_modelspace(target_layout: BaseLayout | None = None, filter_fn: Callable[[DXFEntity], bool] |
None = None) -> None
Loads the content of the modelspace of the source document into a layout of the target
document, the modelspace of the target document is the default target layout. The filter
function filter_fn is used to skip source entities, the function should return False for
entities to ignore and True otherwise.
Parameters
• target_layout – target layout can be any layout: modelspace, paperspace layout or
block layout.
• filter_fn – function to filter source entities
load_paperspace_layout(psp: Paperspace, filter_fn: Callable[[DXFEntity], bool] | None = None) ->
None
Loads a paperspace layout as a new paperspace layout into the target document. If a
paperspace layout with same name already exists the layout will be renamed to “<layout
name> (2)” or “<layout name> (3)” and so on. The filter function filter_fn is used to skip
source entities, the function should return False for entities to ignore and True
otherwise.
The content of the modelspace which may be displayed through a VIEWPORT entity will not be
loaded!
Parameters
• psp – the source paperspace layout
• filter_fn – function to filter source entities
load_paperspace_layout_into(psp: Paperspace, target_layout: BaseLayout, filter_fn:
Callable[[DXFEntity], bool] | None = None) -> None
Loads the content of a paperspace layout into an existing layout of the target document.
The filter function filter_fn is used to skip source entities, the function should return
False for entities to ignore and True otherwise.
The content of the modelspace which may be displayed through a VIEWPORT entity will not be
loaded!
Parameters
• psp – the source paperspace layout
• target_layout – target layout can be any layout: modelspace, paperspace layout or
block layout.
• filter_fn – function to filter source entities
load_block_layout(block_layout: BlockLayout) -> None
Loads a block layout (block definition) as a new block layout into the target document. If
a block layout with the same name exists the conflict policy will be applied. This method
cannot load modelspace or paperspace layouts.
Parameters
block_layout – the source block layout
load_block_layout_into(block_layout: BlockLayout, target_layout: BaseLayout) -> None
Loads the content of a block layout (block definition) into an existing layout of the
target document. This method cannot load the content of modelspace or paperspace layouts.
Parameters
• block_layout – the source block layout
• target_layout – target layout can be any layout: modelspace, paperspace layout or
block layout.
load_layers(names: Sequence[str]) -> None
Loads the layers defined by the argument names into the target document. In the case of a
name conflict the conflict policy will be applied.
load_linetypes(names: Sequence[str]) -> None
Loads the linetypes defined by the argument names into the target document. In the case of
a name conflict the conflict policy will be applied.
load_text_styles(names: Sequence[str]) -> None
Loads the TEXT styles defined by the argument names into the target document. In the case
of a name conflict the conflict policy will be applied.
load_dim_styles(names: Sequence[str]) -> None
Loads the DIMENSION styles defined by the argument names into the target document. In the
case of a name conflict the conflict policy will be applied.
load_mline_styles(names: Sequence[str]) -> None
Loads the MLINE styles defined by the argument names into the target document. In the case
of a name conflict the conflict policy will be applied.
load_mleader_styles(names: Sequence[str]) -> None
Loads the MULTILEADER styles defined by the argument names into the target document. In the
case of a name conflict the conflict policy will be applied.
load_materials(names: Sequence[str]) -> None
Loads the MATERIALS defined by the argument names into the target document. In the case of
a name conflict the conflict policy will be applied.
execute(xref_prefix: str = '') -> None
Execute all loading commands. The xref_prefix string is used as XREF name when the conflict
policy ConflictPolicy.XREF_PREFIX is applied.
HOWTO
The Howto section show how to accomplish specific tasks with ezdxf in a straight forward way without
teaching basics or internals, if you are looking for more information about the ezdxf internals look at
the Reference section or if you want to learn how to use ezdxf go to the Tutorials section or to the
Basic Concepts section.
General Document
General preconditions:
import sys
import ezdxf
try:
doc = ezdxf.readfile("your_dxf_file.dxf")
except IOError:
print(f"Not a DXF file or a generic I/O error.")
sys.exit(1)
except ezdxf.DXFStructureError:
print(f"Invalid or corrupted DXF file.")
sys.exit(2)
msp = doc.modelspace()
This works well with DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files with
minor or major flaws look at the ezdxf.recover module.
Load DXF Files with Structure Errors
If you know the files you will process have most likely minor or major flaws, use the ezdxf.recover
module:
import sys
from ezdxf import recover
try: # low level structure repair:
doc, auditor = recover.readfile(name)
except IOError:
print(f"Not a DXF file or a generic I/O error.")
sys.exit(1)
except ezdxf.DXFStructureError:
print(f"Invalid or corrupted DXF file: {name}.")
sys.exit(2)
# DXF file can still have unrecoverable errors, but this is maybe
# just a problem when saving the recovered DXF file.
if auditor.has_errors:
print(f"Found unrecoverable errors in DXF file: {name}.")
auditor.print_error_report()
For more loading scenarios follow the link: ezdxf.recover
Set/Get Header Variables
ezdxf has an interface to get and set HEADER variables:
doc.header["VarName"] = value
value = doc.header["VarName"]
SEE ALSO:
HeaderSection and online documentation from Autodesk for available header variables.
Set DXF Drawing Units
The header variable $INSUNITS defines the drawing units for the modelspace and therefore for the DXF
document if no further settings are applied. The most common units are 6 for meters and 1 for inches.
Use this HEADER variables to setup the default units for CAD applications opening the DXF file. This
setting is not relevant for ezdxf API calls, which are unitless for length values and coordinates and
decimal degrees for angles (in most cases).
Sets drawing units:
doc.header["$INSUNITS"] = 6
For more information see section DXF Units.
Create More Readable DXF Files (DXF Pretty Printer)
DXF files are plain text files, you can open this files with every text editor which handles bigger
files. But it is not really easy to get quick the information you want.
Create a more readable HTML file (DXF Pretty Printer):
# Call as executable script from the command line:
ezdxf pp FILE [FILE ...]
# Call as module on Windows:
py -m ezdxf pp FILE [FILE ...]
# Call as module on Linux/Mac
python3 -m ezdxf pp FILE [FILE ...]
This creates a HTML file with a nicer layout than a plain text file, and handles are links between DXF
entities, this simplifies the navigation between the DXF entities.
usage: ezdxf pp [-h] [-o] [-r] [-x] [-l] FILE [FILE ...]
positional arguments:
FILE DXF files pretty print
optional arguments:
-h, --help show this help message and exit
-o, --open open generated HTML file with the default web browser
-r, --raw raw mode - just print tags, no DXF structure interpretation
-x, --nocompile don't compile points coordinates into single tags (only in
raw mode)
-l, --legacy legacy mode - reorders DXF point coordinates
IMPORTANT:
This does not render the graphical content of the DXF file to a HTML canvas element.
Calculate Extents for the Modelspace
Since ezdxf v0.16 exist a ezdxf.bbox module to calculate bounding boxes for DXF entities. This module
makes the extents calculation very easy, but read the documentation for the bbox module to understand its
limitations.
import ezdxf
from ezdxf import bbox
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
extents = bbox.extents(msp)
The returned extents is a ezdxf.math.BoundingBox object.
Set Initial View/Zoom for the Modelspace
To show an arbitrary location of the modelspace centered in the CAD application window, set the '*Active'
VPORT to this location. The DXF attribute dxf.center defines the location in the modelspace, and the
dxf.height specifies the area of the modelspace to view. Shortcut function:
doc.set_modelspace_vport(height=10, center=(10, 10))
SEE ALSO:
The ezdxf.zoom module is another way to set the initial modelspace view.
Setting the initial view to the extents of all entities in the modelspace:
import ezdxf
from ezdxf import zoom
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
zoom.extents(msp)
Setting the initial view to the extents of just some entities:
lines = msp.query("LINES")
zoom.objects(lines)
The zoom module also works for paperspace layouts.
IMPORTANT:
The zoom module uses the bbox module to calculate the bounding boxes for DXF entities. Read the
documentation for the bbox module to understand its limitations and the bounding box calculation for
large documents can take a while!
Hide the UCS Icon
The visibility of the UCS icon is controlled by the DXF ucs_icon attribute of the VPort entity:
• bit 0: 0=hide, 1=show
• bit 1: 0=display in lower left corner, 1=display at origin
The state of the UCS icon can be set in conjunction with the initial VPort of the model space, this code
turns off the UCS icon:
doc.set_modelspace_vport(10, center=(10, 10), dxfattribs={"ucs_icon": 0})
Alternative: turn off UCS icons for all VPort entries in the active viewport configuration:
for vport in doc.viewports.get_config("*Active"):
vport.dxf.ucs_icon = 0
Show Lineweights in DXF Viewers
By default lines and curves are shown without lineweights in DXF viewers. By setting the header variable
$LWDISPLAY to 1 the DXF viewer should display lineweights, if supported by the viewer.
doc.header["$LWDISPLAY"] = 1
Add ezdxf Resources to Existing DXF Document
Add all ezdxf specific resources (line types, text- and dimension styles) to an existing DXF document:
import ezdxf
from ezdxf.tools.standards import setup_drawing
doc = ezdxf.readfile("your.dxf")
setup_drawing(doc, topics="all")
Set Logging Level of ezdxf
Set the logging level of the ezdxf package to a higher level to minimize logging messages from ezdxf. At
level ERROR only severe errors will be logged and WARNING, INFO and DEBUG messages will be suppressed:
import logging
logging.getLogger("ezdxf").setLevel(logging.ERROR)
DXF Viewer
A360 Viewer Problems
AutoDesk web service A360 seems to be more picky than the AutoCAD desktop applications, may be it helps
to use the latest DXF version supported by ezdxf, which is DXF R2018 (AC1032) in the year of writing this
lines (2018).
DXF Entities Are Not Displayed in the Viewer
ezdxf does not automatically locate the main viewport of the modelspace at the entities, you have to
perform the “Zoom to Extends” command, here in TrueView 2020: [image]
And here in the Autodesk Online Viewer: [image]
Add this line to your code to relocate the main viewport, adjust the center (in modelspace coordinates)
and the height (in drawing units) arguments to your needs:
doc.set_modelspace_vport(height=10, center=(0, 0))
Show IMAGES/XREFS on Loading in AutoCAD
If you are adding XREFS and IMAGES with relative paths to existing drawings and they do not show up in
AutoCAD immediately, change the HEADER variable $PROJECTNAME='' to (not really) solve this problem. The
ezdxf templates for DXF R2004 and later have $PROJECTNAME='' as default value.
Thanks to David Booth:
If the filename in the IMAGEDEF contains the full path (absolute in AutoCAD) then it shows on loading,
otherwise it won’t display (reports as unreadable) until you manually reload using XREF manager.
A workaround (to show IMAGES on loading) appears to be to save the full file path in the DXF or save
it as a DWG.
Thanks to Zac Luzader:
Has anyone else noticed that very short simple image file names seem to avoid this problem? Once I
ensured that the image file’s name was short and had no special characters (letters, numbers and
underscores only) the problem seemed to go away. I didn’t rigorously analyze the behavior as its very
time consuming.
Also: You can safely put the image in a subdirectory and use a relative path. The name of the
subdirectory does not seem to trigger this problem, provided that the image file name itself is very
short and simple.
Also pro tip: The XRef manager exists in DWG TrueView 2023, but access to it is only possible if you
have a completely broken reference. Create a DXF with a reference to a non-existent file, then the
error dialog will let you open the XRef Manager. Once it is open you can pin it and it will be open
next time, even if you have no broken references.
SEE ALSO:
Discussion on github: Images don’t show in AutoCAD until …
Set Initial View/Zoom for the Modelspace
See section “General Document”: Set Initial View/Zoom for the Modelspace
Show Lineweights in DXF Viewers
By default lines and curves are shown without lineweights in DXF viewers. By setting the header variable
$LWDISPLAY to 1 the DXF viewer should display lineweights, if supported by the viewer.
doc.header["$LWDISPLAY"] = 1
DXF Content
General preconditions:
import sys
import ezdxf
try:
doc = ezdxf.readfile("your_dxf_file.dxf")
except IOError:
print(f'Not a DXF file or a generic I/O error.')
sys.exit(1)
except ezdxf.DXFStructureError:
print(f'Invalid or corrupted DXF file.')
sys.exit(2)
msp = doc.modelspace()
Get/Set Entity Color
The entity color is stored as ACI (AutoCAD Color Index):
aci = entity.dxf.color
Default value is 256 which means BYLAYER:
layer = doc.layers.get(entity.dxf.layer)
aci = layer.get_color()
The special get_color() method is required, because the color attribute Layer.dxf.color is misused as
layer on/off flag, a negative color value means the layer is off.
ACI value 0 means BYBLOCK, which means the color from the block reference (INSERT entity).
Set color as ACI value as int in range [0, 256]:
entity.dxf.color = 1
The ACI value 7 has a special meaning, it is white on dark backgrounds and white on light backgrounds.
Get/Set Entity RGB Color
RGB true color values are supported since DXF R13 (AC1012), the 24-bit RGB value is stored as integer in
the DXF attribute true_color:
# 24 bit binary value: 0bRRRRRRRRGGGGGGGGBBBBBBBB or hex value: 0xRRGGBB
# set true color value to red
entity.dxf.true_color = 0xFF0000
Use the helper functions from the ezdxf.colors module for RGB integer value handling:
from ezdxf import colors
entity.dxf.true_color = colors.rgb2int((0xFF, 0, 0))
r, g, b = colors.int2rgb(entity.dxf.true_color)
The RGB values of the AutoCAD default colors are not officially documented, but an accurate translation
table is included in ezdxf:
# Warning: ACI value 256 (BYLAYER) raises an IndexError!
rgb24 = colors.DXF_DEFAULT_COLORS[aci]
print(f"RGB Hex Value: #{rgb24:06X}")
r, g, b = colors.int2rgb(rgb24)
print(f"RGB Channel Values: R={r:02X} G={g:02X} b={b:02X}")
If color and true_color values are set, BricsCAD and AutoCAD use the true_color value as display color
for the entity.
Get/Set True Color as RGB-Tuple
Get/Set the true color value as (r, g, b)-tuple by the rgb property of the DXFGraphic entity:
# set true color value to red
entity.rgb = (0xFF, 0, 0)
# get true color values
r, g, b = entity.rgb
Get/Set Block Reference Attributes
Block references (Insert) can have attached attributes (Attrib), these are simple text annotations with
an associated tag appended to the block reference.
Iterate over all appended attributes:
# get all INSERT entities with entity.dxf.name == "Part12"
blockrefs = msp.query('INSERT[name=="Part12"]')
if len(blockrefs):
entity = blockrefs[0] # process first entity found
for attrib in entity.attribs:
if attrib.dxf.tag == "diameter": # identify attribute by tag
attrib.dxf.text = "17mm" # change attribute content
Get attribute by tag:
diameter = entity.get_attrib('diameter')
if diameter is not None:
diameter.dxf.text = "17mm"
Adding XDATA to Entities
Adding XDATA as list of tuples (group code, value) by set_xdata(), overwrites data if already present:
doc.appids.new('YOUR_APPID') # IMPORTANT: create an APP ID entry
circle = msp.add_circle((10, 10), 100)
circle.set_xdata(
'YOUR_APPID',
[
(1000, 'your_web_link.org'),
(1002, '{'),
(1000, 'some text'),
(1002, '{'),
(1071, 1),
(1002, '}'),
(1002, '}')
])
For group code meaning see DXF reference section DXF Group Codes in Numerical Order Reference, valid
group codes are in the range 1000 - 1071.
Method get_xdata() returns the extended data for an entity as Tags object.
SEE ALSO:
Tutorial: Storing Custom Data in DXF Files
Get Overridden DIMSTYLE Values from DIMENSION
In general the Dimension styling and config attributes are stored in the Dimstyle entity, but every
attribute can be overridden for each DIMENSION entity individually, get overwritten values by the
DimstyleOverride object as shown in the following example:
for dimension in msp.query('DIMENSION'):
dimstyle_override = dimension.override() # requires v0.12
dimtol = dimstyle_override['dimtol']
if dimtol:
print(f'{str(dimension)} has tolerance values:')
dimtp = dimstyle_override['dimtp']
dimtm = dimstyle_override['dimtm']
print(f'Upper tolerance: {dimtp}')
print(f'Lower tolerance: {dimtm}')
The DimstyleOverride object returns the value of the underlying DIMSTYLE objects if the value in
DIMENSION was not overwritten, or None if the value was neither defined in DIMSTYLE nor in DIMENSION.
Override DIMSTYLE Values for DIMENSION
Same as above, the DimstyleOverride object supports also overriding DIMSTYLE values. But just overriding
this values have no effect on the graphical representation of the DIMENSION entity, because CAD
applications just show the associated anonymous block which contains the graphical representation on the
DIMENSION entity as simple DXF entities. Call the render method of the DimstyleOverride object to
recreate this graphical representation by ezdxf, but ezdxf does not support all DIMENSION types and
DIMVARS yet, and results will differ from AutoCAD or BricsCAD renderings.
dimstyle_override = dimension.override()
dimstyle_override.set_tolerance(0.1)
# delete associated geometry block
del doc.blocks[dimension.dxf.geometry]
# recreate geometry block
dimstyle_override.render()
How to Change the HATCH Pattern Origin Point
This code sets the origin of the first pattern line to the given origin and the origins of all remaining
pattern lines relative to the first pattern line origin.
from ezdxf.entities import Hatch, Pattern
from ezdxf.math import Vec2
def shift_pattern_origin(hatch: Hatch, offset: Vec2):
if isinstance(hatch.pattern, Pattern):
for pattern_line in hatch.pattern.lines:
pattern_line.base_point += offset
def reset_pattern_origin_of_first_pattern_line(hatch: Hatch, origin: Vec2):
if isinstance(hatch.pattern, Pattern) and len(hatch.pattern.lines):
first_pattern_line = hatch.pattern.lines[0]
offset = origin - first_pattern_line.base_point
shift_pattern_origin(hatch, offset)
SEE ALSO:
• Discussion #769
How to Get the Length of a Spline or Polyline
There exist no analytical function to calculate the length of a B-spline, you have to approximate the
curve and calculate the length of the polyline. The construction tool ezdxf.math.ConstructionPolyline is
may be useful for that.
import ezdxf
from ezdxf.math import ConstructionPolyline
doc = ezdxf.new()
msp = doc.modelspace()
fit_points = [(0, 0, 0), (750, 500, 0), (1750, 500, 0), (2250, 1250, 0)]
spline = msp.add_spline(fit_points)
# Adjust the max. sagitta distance to your needs or run the calculation in a loop
# reducing the distance until the difference to the previous run is smaller
# than your expected precision:
polyline = ConstructionPolyline(spline.flattening(distance=0.1))
print(f"approximated length = {polyline.length:.2f}")
How to Resolve DXF Properties
Graphical properties of DXF entities (color, lineweight, …) are sometimes hard to resolve because of the
complex possibilities to inherit properties from layers or blocks, or overriding them by ctb files.
The drawing add-on provides the RenderContext class that can be used to resolve properties of entities in
the context of their use:
import ezdxf
from ezdxf.addons.drawing.properties import RenderContext
doc = ezdxf.new()
doc.layers.add("LINE", color=ezdxf.colors.RED)
msp = doc.modelspace()
line = msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "LINE"})
ctx = RenderContext(doc)
ctx.set_current_layout(msp)
print(f"resolved RGB value: {ctx.resolve_color(line)}")
Output:
resolved RGB value: #ff0000
This works in most simple cases, resolving properties of objects in viewports or nested blocks requires
additional information that is beyond the scope of a simple guide.
How to Find XREF Definitions
XREFs are normal block definitions and can be found in the BLOCKS section:
for block_layout in doc.blocks:
block = block_layout.block # the BLOCK entity
if block.is_xref:
handle_xref(block_layout)
elif block.is_xref_overlay:
handle_xref_overlay(block_layout)
SEE ALSO:
• documentation of the ezdxf.xref module
• ezdxf.layouts.BlockLayout
How to Find XREF References
An XREF reference is a block reference (INSERT entity) to the block definition of the XREF:
for insert in msp.query("INSERT"):
if insert.is_xref:
handle_xref_reference(insert)
# ... or get the XREF definition
block_layout = insert.block()
if block_layout is not None:
block = block_layout.block
if block.is_xref:
handle_xref(block_layout)
elif block.is_xref_overlay:
handle_xref_overlay(block_layout)
Like any normal block, an XREF can be inserted multiple times.
SEE ALSO:
• documentation of the ezdxf.xref module
• ezdxf.layouts.BlockLayout
Fonts
Rendering SHX Fonts
The SHX font format is not documented nor supported by many libraries/packages like Matplotlib and Qt,
therefore only SHX fonts which have corresponding TTF-fonts can be rendered by these backends. The
mapping from/to SHX/TTF fonts is hard coded in the source code file: fonts.py
Since ezdxf v1.1 is the rendering of SHX fonts supported if the path to these fonts is added to the
support_dirs in the Config Files.
Rebuild Font Manager Cache
If you wanna use new installed fonts which are not included in the current cache file of ezdxf you have
to rebuild the cache file:
import ezdxf
from ezdxf.fonts import fonts
fonts.build_system_font_cache()
or call the ezdxf launcher to do that:
ezdxf --fonts
Drawing Add-on
This section consolidates the FAQ about the drawing add-on from the github forum.
All Backends
How to Set Background and Foreground Colors
Override the default background and foreground colors. The foreground color is the AutoCAD Color Index
(ACI) 7, which is white/black depending on the background color. If the foreground color is not
specified, the foreground color is white for dark backgrounds and black for light backgrounds. The
required color format is a hex string “#RRGGBBAA”.
from ezdxf.addons.drawing.properties import LayoutProperties
# -x-x-x snip -x-x-x-
fig: plt.Figure = plt.figure()
ax: plt.Axes = fig.add_axes((0, 0, 1, 1))
ctx = RenderContext(doc)
# get the modelspace properties
msp_properties = LayoutProperties.from_layout(msp)
# set light gray background color and black foreground color
msp_properties.set_colors("#eaeaea")
out = MatplotlibBackend(ax)
# override the layout properties and render the modelspace
Frontend(ctx, out).draw_layout(
msp,
finalize=True,
layout_properties=msp_properties,
)
fig.savefig("image.png")
A light background “#eaeaea” has a black foreground color by default: [image]
A dark background “#0a0a0a” has a white foreground color by default:
# -x-x-x snip -x-x-x-
msp_properties.set_colors("#0a0a0a")
# -x-x-x snip -x-x-x-
[image]
How to Set a Transparent Background Color
The override color include an alpha transparency “#RRGGBBAA” value. An alpha value of “00” is opaque and
“ff” is fully transparent. A transparent background color still defines the foreground color!
HINT:
The savefig() function of the matplotlib backend requires the transparent argument to be set to True
to support transparency.
A light and fully transparent background “#eaeaeaff” has a black foreground color by default:
# -x-x-x snip -x-x-x-
msp_properties.set_colors("#eaeaeaff")
# -x-x-x snip -x-x-x-
fig.savefig("image.png", transparent=True)
[image]
A dark and fully transparent background “#0a0a0aff” has a white foreground color by default:
# -x-x-x snip -x-x-x-
msp_properties.set_colors("#0a0a0aff")
# -x-x-x snip -x-x-x-
fig.savefig("image.png", transparent=True)
[image]
How to Exclude DXF Entities from Rendering
• If all unwanted entities are on the same layer switch off the layer.
• If the document is not saved later, you can delete the entities or set them invisible.
• Filter the unwanted entities by a filter function.
The argument filter_func of the Frontend.draw_layout() method expects a function which takes a graphical
DXF entity as input and returns True if the entity should be rendered or False to exclude the entity from
rendering.
This filter function excludes all DXF entities with an ACI color value of 2:
from ezdxf.entities import DXFGraphic
def my_filter(e: DXFGraphic) -> bool:
return e.dxf.color != 2
# -x-x-x snip -x-x-x-
Frontend(ctx, out).draw_layout(msp, finalize=True, filter_func=my_filter)
IMPORTANT:
Not all attributes have a default value if the attribute does not exist. If you are not sure about
this, use the get() method:
def my_filter(e: DXFGraphic) -> bool:
return e.dxf.get("color", 7) != 2
How to Override Properties of DXF Entities
Create a custom Frontend class and override the the override_properties() method:
class MyFrontend(Frontend):
def override_properties(self, entity: DXFGraphic, properties: Properties) -> None:
# remove alpha channel from all entities, "#RRGGBBAA"
properties.color = properties.color[:7]
# -x-x-x snip -x-x-x-
MyFrontend(ctx, out).draw_layout(msp, finalize=True)
SEE ALSO:
• ezdxf.addons.drawing.properties.Properties
Matplotlib Backend
SEE ALSO:
• Matplotlib package: https://matplotlib.org/stable/api/matplotlib_configuration_api.html
• Figure API: https://matplotlib.org/stable/api/figure_api.html
• Axes API: https://matplotlib.org/stable/api/axis_api.html
How to Get the Pixel Coordinates of DXF Entities
SEE ALSO:
• Source: https://github.com/mozman/ezdxf/discussions/219
Transformation from modelspace coordinates to image coordinates:
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
import ezdxf
from ezdxf.math import Matrix44
from ezdxf.addons.drawing import RenderContext, Frontend
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
def get_wcs_to_image_transform(
ax: plt.Axes, image_size: tuple[int, int]
) -> Matrix44:
"""Returns the transformation matrix from modelspace coordinates to image
coordinates.
"""
x1, x2 = ax.get_xlim()
y1, y2 = ax.get_ylim()
data_width, data_height = x2 - x1, y2 - y1
image_width, image_height = image_size
return (
Matrix44.translate(-x1, -y1, 0)
@ Matrix44.scale(
image_width / data_width, -image_height / data_height, 1.0
)
# +1 to counteract the effect of the pixels being flipped in y
@ Matrix44.translate(0, image_height + 1, 0)
)
# create the DXF document
doc = ezdxf.new()
msp = doc.modelspace()
msp.add_lwpolyline([(0, 0), (1, 0), (1, 1), (0, 1)], close=True)
msp.add_line((0, 0), (1, 1))
# export the pixel image
fig: plt.Figure = plt.figure()
ax: plt.Axes = fig.add_axes([0, 0, 1, 1])
ctx = RenderContext(doc)
out = MatplotlibBackend(ax)
Frontend(ctx, out).draw_layout(msp, finalize=True)
fig.savefig("cad.png")
plt.close(fig)
# reload the pixel image by Pillow (PIL)
img = Image.open("cad.png")
draw = ImageDraw.Draw(img)
# add some annotations to the pixel image by using modelspace coordinates
m = get_wcs_to_image_transform(ax, img.size)
a, b, c = (
(v.x, v.y) # draw.line() expects tuple[float, float] as coordinates
# transform modelspace coordinates to image coordinates
for v in m.transform_vertices([(0.25, 0.75), (0.75, 0.25), (1, 1)])
)
draw.line([a, b, c, a], fill=(255, 0, 0))
# show the image by the default image viewer
img.show()
How to Get Modelspace Coordinates from Pixel Coordinates
This is the reverse operation of the previous how-to: How to Get the Pixel Coordinates of DXF Entities
SEE ALSO:
• Full example script: wcs_to_image_coordinates.py
• Source: https://github.com/mozman/ezdxf/discussions/269
def get_image_to_wcs_transform(
ax: plt.Axes, image_size: tuple[int, int]
) -> Matrix44:
m = get_wcs_to_image_transform(ax, image_size)
m.inverse()
return m
# -x-x-x snip -x-x-x-
img2wcs = get_image_to_wcs_transform(ax, img.size)
print(f"0.25, 0.75 == {img2wcs.transform(a).round(2)}")
print(f"0.75, 0.25 == {img2wcs.transform(b).round(2)}")
print(f"1.00, 1.00 == {img2wcs.transform(c).round(2)}")
How to Export a Specific Area of the Modelspace
This code exports the specified modelspace area from (5, 3) to (7, 8) as a 2x5 inch PNG image to maintain
the aspect ratio of the source area.
Use case: render only a specific area of the modelspace.
SEE ALSO:
• Full example script: export_specific_area.py
• Source: https://github.com/mozman/ezdxf/discussions/451
# -x-x-x snip -x-x-x-
# export the pixel image
fig: plt.Figure = plt.figure()
ax: plt.Axes = fig.add_axes([0, 0, 1, 1])
ctx = RenderContext(doc)
out = MatplotlibBackend(ax)
Frontend(ctx, out).draw_layout(msp, finalize=True)
# setting the export area:
xmin, xmax = 5, 7
ymin, ymax = 3, 8
ax.set_xlim(xmin, xmax)
ax.set_ylim(ymin, ymax)
# set the output size to get the expected aspect ratio:
fig.set_size_inches(xmax - xmin, ymax - ymin)
fig.savefig("x5y3_to_x7y8.png")
plt.close(fig)
How to Render Without Margins
To remove the empty space at the image borders set the margins of the Axes object to zero:
ax.margins(0)
fig.savefig("image_without_margins.png")
plt.close(fig)
SEE ALSO:
• Matplotlib docs about margins
How to Set the Pixel Count per Drawing Unit
This code exports the modelspace with an extent of 5 x 3 drawing units with 100 pixels per drawing unit
as a 500 x 300 pixel image.
Use case: render the content with a fixed number of pixels for a drawing unit, e.g. a drawing unit of 1
inch should be rendered by 100 pixels.
SEE ALSO:
• Full example script: export_image_pixel_size.py
• Source: https://github.com/mozman/ezdxf/discussions/357
# -x-x-x snip -x-x-x-
def set_pixel_density(fig: plt.Figure, ax: plt.Axes, ppu: int):
"""Argument `ppu` is pixels per drawing unit."""
xmin, xmax = ax.get_xlim()
width = xmax - xmin
ymin, ymax = ax.get_ylim()
height = ymax - ymin
dpi = fig.dpi
width_inch = width * ppu / dpi
height_inch = height * ppu / dpi
fig.set_size_inches(width_inch, height_inch)
# -x-x-x snip -x-x-x-
# export image with 100 pixels per drawing unit = 500x300 pixels
set_pixel_density(fig, ax, 100)
fig.savefig("box_500x300.png")
plt.close(fig)
How to Export a Specific Image Size in Pixels
This code exports the modelspace with an extent of 5 x 3 drawing units as a 1000 x 600 pixel Image.
Use case: render the content with a fixed image size in pixels.
SEE ALSO:
• Full example script: export_image_pixel_size.py
• Source: https://github.com/mozman/ezdxf/discussions/357
# -x-x-x snip -x-x-x-
def set_pixel_size(fig: plt.Figure, size: tuple[int, int]):
x, y = size
fig.set_size_inches(x / fig.dpi, y / fig.dpi)
# -x-x-x snip -x-x-x-
# export image with a size of 1000x600 pixels
set_pixel_size(fig, (1000, 600))
fig.savefig("box_1000x600.png")
plt.close(fig)
How to Set the Page Size in Inches
The page- or image size in inches is set by the set_size_inches() method of the Figure class. The content
within the Axes limits will be scaled to fill the page.
Use case: render the whole content to a PDF document with a specific paper size without worrying about
scale.
fig.set_size_inches(8, 11)
How to Render at a Specific Scale
This code exports the modelspace at a specific scale and paper size.
Use case: render the content to a PDF document with a specific paper size and scale, but not all content
may be rendered.
SEE ALSO:
• Full example script: render_to_scale.py
• Source: https://github.com/mozman/ezdxf/discussions/665
# -x-x-x snip -x-x-x-
def render_limits(
origin: tuple[float, float],
size_in_inches: tuple[float, float],
scale: float,
) -> tuple[float, float, float, float]:
"""Returns the final render limits in drawing units.
Args:
origin: lower left corner of the modelspace area to render
size_in_inches: paper size in inches
scale: render scale, e.g. scale=100 means 1:100, 1m is
rendered as 0.01m or 1cm on paper
"""
min_x, min_y = origin
max_x = min_x + size_in_inches[0] * scale
max_y = min_y + size_in_inches[1] * scale
return min_x, min_y, max_x, max_y
def export_to_scale(
paper_size: tuple[float, float] = (8.5, 11),
origin: tuple[float, float] = (0, 0),
scale: float = 1,
dpi: int = 300,
):
"""Render the modelspace content with to a specific paper size and scale.
Args:
paper_size: paper size in inches
origin: lower left corner of the modelspace area to render
scale: render scale, e.g. scale=100 means 1:100, 1m is
rendered as 0.01m or 1cm on paper
dpi: pixel density on paper as dots per inch
"""
# -x-x-x snip -x-x-x-
ctx = RenderContext(doc)
fig: plt.Figure = plt.figure(dpi=dpi)
ax: plt.Axes = fig.add_axes([0, 0, 1, 1])
# disable all margins
ax.margins(0)
# get the final render limits in drawing units:
min_x, min_y, max_x, max_y = render_limits(
origin, paper_size, scale
)
ax.set_xlim(min_x, max_x)
ax.set_ylim(min_y, max_y)
out = MatplotlibBackend(ax)
# finalizing invokes auto-scaling by default!
Frontend(ctx, out).draw_layout(msp, finalize=False)
# set output size in inches:
fig.set_size_inches(paper_size[0], paper_size[1], forward=True)
fig.savefig(f"image_scale_1_{scale}.pdf", dpi=dpi)
plt.close(fig)
How to Control the Line Width
The DXF lineweight attribute defines the line width as absolute width on the output medium (e.g. 25 =
0.25mm) and therefore depends only on the DPI (dots per inch) setting of the Figure class and the
savefig() method.
There are two additional settings in the Configuration class which influences the line width:
• min_lineweight sets the minimum line width in 1/300 inch - a value of 300 is a line width of 1 inch
• lineweight_scaling, multiply the line width by a this factor
The following table shows the line width in pixels for all valid DXF lineweights for a resolution of 72,
100, 200 and 300 dpi: [image]
SEE ALSO:
Discussion: https://github.com/mozman/ezdxf/discussions/797
FAQ
These are the old FAQ until late 2023, new FAQs will only be added to the Knowledge Graph.
What is the Relationship between ezdxf, dxfwrite and dxfgrabber?
In 2010 I started my first Python package for creating DXF documents called dxfwrite, this package can’t
read DXF files and writes only the DXF R12 (AC1009) version. While dxfwrite works fine, I wanted a more
versatile package, that can read and write DXF files and maybe also supports newer DXF formats than DXF
R12.
This was the start of the ezdxf package in 2011, but the progress was so slow, that I created a spin off
in 2012 called dxfgrabber, which implements only the reading part of ezdxf, which I needed for my work
and I wasn’t sure if ezdxf will ever be usable. Luckily in 2014 the first usable version of ezdxf could
be released. The ezdxf package has all the features of dxfwrite and dxfgrabber and much more, but with a
different API. So ezdxf is not a drop-in replacement for dxfgrabber or dxfwrite.
Since ezdxf can do all the things that dxfwrite and dxfgrabber can do, I focused on the development of
ezdxf, dxfwrite and dxfgrabber are in maintenance-only mode and will not get any new features, just
bugfixes.
There are no advantages of dxfwrite over ezdxf, dxfwrite has a smaller memory footprint, but the
r12writer add-on does the same job as dxfwrite without any in-memory structures by writing direct to a
stream or file and there is also no advantage of dxfgrabber over ezdxf for ordinary DXF files, the
smaller memory footprint of dxfgrabber is not noticeable and for really big files the iterdxf add-on does
a better job.
Imported ezdxf package has no content. (readfile, new)
1. AttributeError: partially initialized module ‘ezdxf’ has no attribute ‘readfile’ (most likely due to a
circular import)
Did you name your file/script “ezdxf.py”? This causes problems with circular imports. Renaming your
file/script should solve this issue.
2. AttributeError: module ‘ezdxf’ has no attribute ‘readfile’
This could be a hidden permission error, for more information about this issue read Petr Zemeks
article: https://blog.petrzemek.net/2020/11/17/when-you-import-a-python-package-and-it-is-empty/
How to add/edit ACIS based entities like 3DSOLID, REGION or SURFACE?
The BODY, 3DSOLID, SURFACE, REGION and so on, are stored as ACIS data embedded in the DXF file. The ACIS
data is stored as SAT (text) format in the entity itself for DXF R2000-R2010 and as SAB (binary) format
in the ACDSDATA section for DXF R2013+. Ezdxf can read SAT and SAB data, but only write SAT data.
The ACIS data is a proprietary format from Spatial Inc., and there exist no free available documentation
or open source libraries to create or edit SAT or SAB data, and also ezdxf provides no functionality for
creating or editing ACIS data.
The ACIS support provided by ezdxf is only useful for users which have access to the ACIS SDK from
Spatial Inc..
Are OLE/OLE2 entities supported?
TLDR; NO!
The Wikipedia definition of OLE: Object Linking & Embedding (OLE) is a proprietary technology developed
by Microsoft that allows embedding and linking to documents and other objects. For developers, it brought
OLE Control Extension (OCX), a way to develop and use custom user interface elements. On a technical
level, an OLE object is any object that implements the IOleObject interface, possibly along with a wide
range of other interfaces, depending on the object’s needs.
Therefore ezdxf does not support this entities in any way, this only work on Windows and with the
required editing application installed. The binary data stored in the OLE objects cannot be used without
the editing application.
In my opinion, using OLE objects in a CAD drawing is a very bad design decision that can and will cause
problems opening these files in the future, even in AutoCAD on Windows when the required editing
application is no longer available or the underlying technology is no longer supported.
All of this is unacceptable for a data storage format that should be accessed for many years or decades
(e.g. construction drawings for buildings or bridges).
Rendering SHX fonts
The SHX font format is not documented nor supported by many libraries/packages like Matplotlib and Qt,
therefore only SHX fonts which have corresponding TTF-fonts can be rendered by these backends. See also
how-tos about Fonts
Drawing Add-on
There is a dedicated how-to section for the Drawing Add-on.
Is the AutoCAD command XYZ available?
TLDR; Would you expect Photoshop features from a JPG library?
The package is designed as an interface to the DXF format and therefore does not offer any advanced
features of interactive CAD applications. First, some tasks are difficult to perform without human
guidance, and second, in complex situations, it’s not that easy to tell a “headless” system what exactly
to do, so it’s very likely that not many users would ever use these features, despite the fact that a lot
of time and effort would have to be spent on development, testing and long-term support.
REFERENCE
The DXF Reference is online available at Autodesk.
Quoted from the original DXF 12 Reference which is not available on the web:
Since the AutoCAD drawing database (.dwg file) is written in a compact format that changes
significantly as new features are added to AutoCAD, we do not document its format and do not recommend
that you attempt to write programs to read it directly. To assist in interchanging drawings between
AutoCAD and other programs, a Drawing Interchange file format (DXF) has been defined. All
implementations of AutoCAD accept this format and are able to convert it to and from their internal
drawing file representation.
DXF Document
Document Management
Create New Drawings
ezdxf.new(dxfversion='AC1027', setup=False, units=6) -> Drawing
Create a new Drawing from scratch, dxfversion can be either “AC1009” the official DXF version name
or “R12” the AutoCAD release name.
new() can create drawings for following DXF versions:
┌─────────┬─────────────────┐
│ Version │ AutoCAD Release │
├─────────┼─────────────────┤
│ AC1009 │ AutoCAD R12 │
├─────────┼─────────────────┤
│ AC1015 │ AutoCAD R2000 │
├─────────┼─────────────────┤
│ AC1018 │ AutoCAD R2004 │
├─────────┼─────────────────┤
│ AC1021 │ AutoCAD R2007 │
├─────────┼─────────────────┤
│ AC1024 │ AutoCAD R2010 │
├─────────┼─────────────────┤
│ AC1027 │ AutoCAD R2013 │
├─────────┼─────────────────┤
│ AC1032 │ AutoCAD R2018 │
└─────────┴─────────────────┘
The units argument defines th document and modelspace units. The header variable $MEASUREMENT will
be set according to the given units, 0 for inch, feet, miles, … and 1 for metric units. For more
information go to module ezdxf.units
Parameters
• dxfversion – DXF version specifier as string, default is “AC1027” respectively “R2013”
• setup –
setup default styles, False for no setup, True to setup everything or a list of topics as
strings, e.g. [“linetypes”, “styles”] to setup only some topics:
───────────────────────────────────────────────────────
│ Topic │ Description │
├──────────────┼──────────────────────────────────────┤
│ linetypes │ setup line types │
├──────────────┼──────────────────────────────────────┤
│ styles │ setup text styles │
├──────────────┼──────────────────────────────────────┤
│ dimstyles │ setup default ezdxf dimension styles │
├──────────────┼──────────────────────────────────────┤
│ visualstyles │ setup 25 standard visual styles │
└──────────────┴──────────────────────────────────────┘
• units – document and modelspace units, default is 6 for meters
Open Drawings
Open DXF drawings from file system or text stream, byte stream usage is not supported.
DXF files prior to R2007 requires file encoding defined by header variable $DWGCODEPAGE, DXF R2007 and
later requires an UTF-8 encoding.
ezdxf supports reading of files for following DXF versions:
┌──────────┬─────────┬──────────────┬────────────────────────┐
│ Version │ Release │ Encoding │ Remarks │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ < AC1009 │ │ $DWGCODEPAGE │ pre AutoCAD R12 │
│ │ │ │ upgraded to AC1009 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1009 │ R12 │ $DWGCODEPAGE │ AutoCAD R12 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1012 │ R13 │ $DWGCODEPAGE │ AutoCAD R13 upgraded │
│ │ │ │ to AC1015 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1014 │ R14 │ $DWGCODEPAGE │ AutoCAD R14 upgraded │
│ │ │ │ to AC1015 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1015 │ R2000 │ $DWGCODEPAGE │ AutoCAD R2000 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1018 │ R2004 │ $DWGCODEPAGE │ AutoCAD R2004 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1021 │ R2007 │ UTF-8 │ AutoCAD R2007 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1024 │ R2010 │ UTF-8 │ AutoCAD R2010 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1027 │ R2013 │ UTF-8 │ AutoCAD R2013 │
├──────────┼─────────┼──────────────┼────────────────────────┤
│ AC1032 │ R2018 │ UTF-8 │ AutoCAD R2018 │
└──────────┴─────────┴──────────────┴────────────────────────┘
ezdxf.readfile(filename: str | PathLike, encoding: str | None = None, errors: str = 'surrogateescape') ->
Drawing
Read the DXF document filename from the file-system.
This is the preferred method to load existing ASCII or Binary DXF files, the required text
encoding will be detected automatically and decoding errors will be ignored.
Override encoding detection by setting argument encoding to the estimated encoding. (use Python
encoding names like in the open() function).
If this function struggles to load the DXF document and raises a DXFStructureError exception, try
the ezdxf.recover.readfile() function to load this corrupt DXF document.
Parameters
• filename – filename of the ASCII- or Binary DXF document
• encoding – use None for auto detect (default), or set a specific encoding like “utf-8”,
argument is ignored for Binary DXF files
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• IOError – not a DXF file or file does not exist
• DXFStructureError – for invalid or corrupted DXF structures
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
ezdxf.read(stream: TextIO) -> Drawing
Read a DXF document from a text-stream. Open stream in text mode (mode='rt') and set correct text
encoding, the stream requires at least a readline() method.
Since DXF version R2007 (AC1021) file encoding is always “utf-8”, use the helper function
dxf_stream_info() to detect the required text encoding for prior DXF versions. To preserve
possible binary data in use errors='surrogateescape' as error handler for the import stream.
If this function struggles to load the DXF document and raises a DXFStructureError exception, try
the ezdxf.recover.read() function to load this corrupt DXF document.
Parameters
stream – input text stream opened with correct encoding
Raises DXFStructureError – for invalid or corrupted DXF structures
ezdxf.readzip(zipfile: str | PathLike, filename: str | None = None, errors: str = 'surrogateescape') ->
Drawing
Load a DXF document specified by filename from a zip archive, or if filename is None the first DXF
document in the zip archive.
Parameters
• zipfile – name of the zip archive
• filename – filename of DXF file, or None to load the first DXF document from the zip
archive.
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• IOError – not a DXF file or file does not exist or
if filename is None - no DXF file found
• DXFStructureError – for invalid or corrupted DXF structures
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
ezdxf.decode_base64(data: bytes, errors: str = 'surrogateescape') -> Drawing
Load a DXF document from base64 encoded binary data, like uploaded data to web applications.
Parameters
• data – DXF document base64 encoded binary data
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• DXFStructureError – for invalid or corrupted DXF structures
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
HINT:
This works well with DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files
with minor or major flaws look at the ezdxf.recover module.
Save Drawings
Save the DXF document to the file system by Drawing methods save() or saveas(). Write the DXF document
to a text stream with write(), the text stream requires at least a write() method. Get required output
encoding for text streams by property Drawing.output_encoding
Drawing Settings
The HeaderSection stores meta data like modelspace extensions, user name or saving time and current
application settings, like actual layer, text style or dimension style settings. These settings are not
necessary to process DXF data and therefore many of this settings are not maintained by ezdxf
automatically.
Header variables set at new
┌──────────────────┬───────────────────────────────────┐
│ $ACADVER │ DXF version │
├──────────────────┼───────────────────────────────────┤
│ $TDCREATE │ date/time at creating the drawing │
├──────────────────┼───────────────────────────────────┤
│ $FINGERPRINTGUID │ every drawing gets a GUID │
└──────────────────┴───────────────────────────────────┘
Header variables updated at saving
┌──────────────┬─────────────────────────────────────┐
│ $TDUPDATE │ actual date/time at saving │
├──────────────┼─────────────────────────────────────┤
│ $HANDSEED │ next available handle as hex string │
├──────────────┼─────────────────────────────────────┤
│ $DWGCODEPAGE │ encoding setting │
├──────────────┼─────────────────────────────────────┤
│ $VERSIONGUID │ every saved version gets a new GUID │
└──────────────┴─────────────────────────────────────┘
SEE ALSO:
• Howto: Set/Get Header Variables
• Howto: Set DXF Drawing Units
Ezdxf Metadata
Store internal metadata like ezdxf version and creation time for a new created document as metadata in
the DXF file. Only standard DXF features are used to store meta data and this meta data is preserved by
Autodesk products, BricsCAD and of course ezdxf. Other 3rd party DXF libraries may remove this meta data.
For DXF R12 the meta data is stored as XDATA by AppID EZDXF in the model space BLOCK entity in the BLOCKS
section.
For DXF R2000+ the meta data is stored in the “root” DICTIONARY in the OBJECTS section as a DICTIONARY
object by the key EZDXF_META.
The MetaData object has a dict-like interface and can also store custom metadata:
metadata = doc.ezdxf_metadata()
# set data
metadata["MY_CUSTOM_META_DATA"] = "a string with max. length of 254"
# get data, raises a KeyError() if key not exist
value = metadata["MY_CUSTOM_META_DATA"]
# get data, returns an empty string if key not exist
value = metadata.get("MY_CUSTOM_META_DATA")
# delete entry, raises a KeyError() if key not exist
del metadata["MY_CUSTOM_META_DATA"]
# discard entry, does not raise a KeyError() if key not exist
metadata.discard("MY_CUSTOM_META_DATA")
Keys and values are limited to strings with a max. length of 254 characters and line ending \n will be
replaced by \P.
Keys used by ezdxf:
• WRITTEN_BY_EZDXF: ezdxf version and UTC time in ISO format
• CREATED_BY_EZDXF: ezdxf version and UTC time in ISO format
Example of the ezdxf marker string: 0.16.4b1 @ 2021-06-12T07:35:34.898808+00:00
class ezdxf.document.MetaData
abstract MetaData.__contains__(key: str) -> bool
Returns key in self.
abstract MetaData.__getitem__(key: str) -> str
Returns the value for self[key].
Raises KeyError – key does not exist
MetaData.get(key: str, default: str = '') -> str
Returns the value for key. Returns default if key not exist.
abstract MetaData.__setitem__(key: str, value: str) -> None
Set self[key] to value.
abstract MetaData.__delitem__(key: str) -> None
Delete self[key].
Raises KeyError – key does not exist
MetaData.discard(key: str) -> None
Remove key, does not raise an exception if key not exist.
Drawing Class
The Drawing class is the central management structure of a DXF document.
Access Layouts
• Drawing.modelspace()
• Drawing.paperspace()
Access Resources
• Application ID Table: Drawing.appids
• Block Definition Table: Drawing.blocks
• Dimension Style Table: Drawing.dimstyles
• Layer Table: Drawing.layers
• Linetype Table: Drawing.linetypes
• MLeader Style Table: Drawing.mleader_styles
• MLine Style Table: Drawing.mline_styles
• Material Table: Drawing.materials
• Text Style Table: Drawing.styles
• UCS Table: Drawing.ucs
• VPort Table: Drawing.viewports
• View Table: Drawing.views
• Classes Section: Drawing.classes
• Object Section: Drawing.objects
• Entity Database: Drawing.entitydb
• Entity Groups: Drawing.groups
• Header Variables: Drawing.header
Drawing Class
class ezdxf.document.Drawing
The Drawing class is the central management structure of a DXF document.
dxfversion
Actual DXF version like 'AC1009', set by ezdxf.new() or ezdxf.readfile().
For supported DXF versions see Document Management
acad_release
The AutoCAD release name like 'R12' or 'R2000' for actual dxfversion.
encoding
Text encoding of Drawing, the default encoding for new drawings is 'cp1252'. Starting with
DXF R2007 (AC1021), DXF files are written as UTF-8 encoded text files, regardless of the
attribute encoding. The text encoding can be changed to encodings listed below.
see also: DXF File Encoding
┌───────────┬────────────────┐
│ supported │ encodings │
├───────────┼────────────────┤
│ 'cp874' │ Thai │
├───────────┼────────────────┤
│ 'cp932' │ Japanese │
├───────────┼────────────────┤
│ 'gbk' │ UnifiedChinese │
├───────────┼────────────────┤
│ 'cp949' │ Korean │
├───────────┼────────────────┤
│ 'cp950' │ TradChinese │
├───────────┼────────────────┤
│ 'cp1250' │ CentralEurope │
├───────────┼────────────────┤
│ 'cp1251' │ Cyrillic │
├───────────┼────────────────┤
│ 'cp1252' │ WesternEurope │
├───────────┼────────────────┤
│ 'cp1253' │ Greek │
├───────────┼────────────────┤
│ 'cp1254' │ Turkish │
├───────────┼────────────────┤
│ 'cp1255' │ Hebrew │
├───────────┼────────────────┤
│ 'cp1256' │ Arabic │
├───────────┼────────────────┤
│ 'cp1257' │ Baltic │
├───────────┼────────────────┤
│ 'cp1258' │ Vietnam │
└───────────┴────────────────┘
output_encoding
Returns required output encoding for saving to filesystem or encoding to binary data.
filename
Drawing filename, if loaded by ezdxf.readfile() else None.
rootdict
Reference to the root dictionary of the OBJECTS section.
header Reference to the HeaderSection, get/set drawing settings as header variables.
entities
Reference to the EntitySection of the drawing, where all graphical entities are stored, but
only from modelspace and the active paperspace layout. Just for your information: Entities
of other paperspace layouts are stored as BlockLayout in the BlocksSection.
objects
Reference to the objects section, see also ObjectsSection.
blocks Reference to the blocks section, see also BlocksSection.
tables Reference to the tables section, see also TablesSection.
classes
Reference to the classes section, see also ClassesSection.
layouts
Reference to the layout manager, see also Layouts.
groups Collection of all groups, see also GroupCollection.
requires DXF R13 or later
layers Shortcut for Drawing.tables.layers
Reference to the layers table, where you can create, get and remove layers, see also Table
and Layer
styles Shortcut for Drawing.tables.styles
Reference to the styles table, see also Textstyle.
dimstyles
Shortcut for Drawing.tables.dimstyles
Reference to the dimstyles table, see also DimStyle.
linetypes
Shortcut for Drawing.tables.linetypes
Reference to the linetypes table, see also Linetype.
views Shortcut for Drawing.tables.views
Reference to the views table, see also View.
viewports
Shortcut for Drawing.tables.viewports
Reference to the viewports table, see also VPort.
ucs Shortcut for Drawing.tables.ucs
Reference to the ucs table, see also UCSTableEntry.
appids Shortcut for Drawing.tables.appids
Reference to the appids table, see also AppID.
materials
MaterialCollection of all Material objects.
mline_styles
MLineStyleCollection of all MLineStyle objects.
mleader_styles
MLeaderStyleCollection of all MLeaderStyle objects.
units Get and set the document/modelspace base units as enum, for more information read this: DXF
Units.
get_abs_filepath = <function Drawing.get_abs_filepath>
save(encoding: str | None = None, fmt: str = 'asc') -> None
Write drawing to file-system by using the filename attribute as filename. Override file
encoding by argument encoding, handle with care, but this option allows you to create DXF
files for applications that handle file encoding different from AutoCAD.
Parameters
• encoding – override default encoding as Python encoding string like 'utf-8'
• fmt – 'asc' for ASCII DXF (default) or 'bin' for Binary DXF
saveas(filename: PathLike | str, encoding: str | None = None, fmt: str = 'asc') -> None
Set Drawing attribute filename to filename and write drawing to the file system. Override
file encoding by argument encoding, handle with care, but this option allows you to create
DXF files for applications that handles file encoding different than AutoCAD.
Parameters
• filename – file name as string
• encoding – override default encoding as Python encoding string like 'utf-8'
• fmt – 'asc' for ASCII DXF (default) or 'bin' for Binary DXF
write(stream: TextIO | BinaryIO, fmt: str = 'asc') -> None
Write drawing as ASCII DXF to a text stream or as Binary DXF to a binary stream. For DXF
R2004 (AC1018) and prior open stream with drawing encoding and mode='wt'. For DXF R2007
(AC1021) and later use encoding='utf-8', or better use the later added Drawing property
output_encoding which returns the correct encoding automatically. The correct and required
error handler is errors='dxfreplace'!
If writing to a StringIO stream, use Drawing.encode() to encode the result string from
StringIO.get_value():
binary = doc.encode(stream.get_value())
Parameters
• stream – output text stream or binary stream
• fmt – “asc” for ASCII DXF (default) or “bin” for binary DXF
encode_base64() -> bytes
Returns DXF document as base64 encoded binary data.
encode(s: str) -> bytes
Encode string s with correct encoding and error handler.
query(query: str = '*') -> EntityQuery
Entity query over all layouts and blocks, excluding the OBJECTS section and the resource
tables of the TABLES section.
Parameters
query – query string
SEE ALSO:
Entity Query String and Retrieve entities by query language
groupby(dxfattrib='', key=None) -> dict
Groups DXF entities of all layouts and blocks (excluding the OBJECTS section) by a DXF
attribute or a key function.
Parameters
• dxfattrib – grouping DXF attribute like “layer”
• key – key function, which accepts a DXFEntity as argument and returns a hashable
grouping key or None to ignore this entity.
SEE ALSO:
groupby() documentation
modelspace() -> Modelspace
Returns the modelspace layout, displayed as “Model” tab in CAD applications, defined by
block record named “*Model_Space”.
paperspace(name: str = '') -> Paperspace
Returns paperspace layout name or the active paperspace if no name is given.
Parameters
name – paperspace name or empty string for the active paperspace
Raises KeyError – if the modelspace was acquired or layout name does not exist
layout(name: str = '') -> Layout
Returns paperspace layout name or the first layout in tab-order if no name is given.
Parameters
name – paperspace name or empty string for the first paperspace in tab-order
Raises KeyError – layout name does not exist
active_layout() -> Paperspace
Returns the active paperspace layout, defined by block record name “*Paper_Space”.
layout_names() -> Iterable[str]
Returns all layout names in arbitrary order.
layout_names_in_taborder() -> Iterable[str]
Returns all layout names in tab-order, “Model” is always the first name.
new_layout(name, dxfattribs=None) -> Paperspace
Create a new paperspace layout name. Returns a Paperspace object. DXF R12 (AC1009) supports
only one paperspace layout, only the active paperspace layout is saved, other layouts are
dismissed.
Parameters
• name – unique layout name
• dxfattribs – additional DXF attributes for the DXFLayout entity
Raises DXFValueError – paperspace layout name already exist
page_setup(name: str = 'Layout1', fmt: str = 'ISO A3', landscape=True) -> Paperspace
Creates a new paperspace layout if name does not exist or reset the existing layout. This
method requires DXF R2000 or newer. The paper format name fmt defines one of the following
paper sizes, measures in landscape orientation:
┌─────────┬───────┬───────┬────────┐
│ Name │ Units │ Width │ Height │
├─────────┼───────┼───────┼────────┤
│ ISO A0 │ mm │ 1189 │ 841 │
├─────────┼───────┼───────┼────────┤
│ ISO A1 │ mm │ 841 │ 594 │
├─────────┼───────┼───────┼────────┤
│ ISO A2 │ mm │ 594 │ 420 │
├─────────┼───────┼───────┼────────┤
│ ISO A3 │ mm │ 420 │ 297 │
├─────────┼───────┼───────┼────────┤
│ ISO A4 │ mm │ 297 │ 210 │
├─────────┼───────┼───────┼────────┤
│ ANSI A │ inch │ 11 │ 8.5 │
├─────────┼───────┼───────┼────────┤
│ ANSI B │ inch │ 17 │ 11 │
├─────────┼───────┼───────┼────────┤
│ ANSI C │ inch │ 22 │ 17 │
├─────────┼───────┼───────┼────────┤
│ ANSI D │ inch │ 34 │ 22 │
├─────────┼───────┼───────┼────────┤
│ ANSI E │ inch │ 44 │ 34 │
├─────────┼───────┼───────┼────────┤
│ ARCH C │ inch │ 24 │ 18 │
├─────────┼───────┼───────┼────────┤
│ ARCH D │ inch │ 36 │ 24 │
├─────────┼───────┼───────┼────────┤
│ ARCH E │ inch │ 48 │ 36 │
├─────────┼───────┼───────┼────────┤
│ ARCH E1 │ inch │ 42 │ 30 │
├─────────┼───────┼───────┼────────┤
│ Letter │ inch │ 11 │ 8.5 │
├─────────┼───────┼───────┼────────┤
│ Legal │ inch │ 14 │ 8.5 │
└─────────┴───────┴───────┴────────┘
The layout uses the associated units of the paper format as drawing units, has no margins
or offset defined and the scale of the paperspace layout is 1:1.
Parameters
• name – paperspace layout name
• fmt – paper format
• landscape – True for landscape orientation, False for portrait orientation
delete_layout(name: str) -> None
Delete paper space layout name and all entities owned by this layout. Available only for
DXF R2000 or later, DXF R12 supports only one paperspace, and it can’t be deleted.
add_image_def(filename: str, size_in_pixel: tuple[int, int], name=None)
Add an image definition to the objects section.
Add an ImageDef entity to the drawing (objects section). filename is the image file name as
relative or absolute path and size_in_pixel is the image size in pixel as (x, y) tuple. To
avoid dependencies to external packages, ezdxf can not determine the image size by itself.
Returns a ImageDef entity which is needed to create an image reference. name is the
internal image name, if set to None, name is auto-generated.
Absolute image paths works best for AutoCAD but not perfect, you have to update external
references manually in AutoCAD, which is not possible in TrueView. If the drawing units
differ from 1 meter, you also have to use: set_raster_variables().
Parameters
• filename – image file name (absolute path works best for AutoCAD)
• size_in_pixel – image size in pixel as (x, y) tuple
• name – image name for internal use, None for using filename as name (best for
AutoCAD)
SEE ALSO:
Tutorial for Image and ImageDef
set_raster_variables(frame: int = 0, quality: int = 1, units: str = 'm')
Set raster variables.
Parameters
• frame – 0 = do not show image frame; 1 = show image frame
• quality – 0 = draft; 1 = high
• units –
units for inserting images. This defines the real world unit for one drawing unit
for the purpose of inserting and scaling images with an associated resolution.
──────────────────────────────
mm Millimeter
──────────────────────────────
cm Centimeter
──────────────────────────────
m Meter (ezdxf default)
──────────────────────────────
km Kilometer
──────────────────────────────
in Inch
──────────────────────────────
ft Foot
──────────────────────────────
yd Yard
──────────────────────────────
mi Mile
┌────┬───────────────────────┐
│ │ │
│ │ │
set_wipeout_variables(frame=0) │ │ │
Set wipeout variables. │ │ │
│ │ │
Parameters │ │ │
--
LAUNCHER
The command line script ezdxf launches various sub-commands:
┌─────────────┬───────────────────────────────────────┐
│ pp │ DXF pretty printer, replacement for │
│ │ the previous dxfpp command │
├─────────────┼───────────────────────────────────────┤
│ audit │ Audit and repair DXF files │
├─────────────┼───────────────────────────────────────┤
│ draw │ Draw and convert DXF files by the │
│ │ Matplotlib backend │
├─────────────┼───────────────────────────────────────┤
│ view │ PyQt DXF file viewer │
├─────────────┼───────────────────────────────────────┤
│ browse │ PyQt DXF structure browser for DXF │
│ │ debugging and curious people │
├─────────────┼───────────────────────────────────────┤
│ browse-acis │ PyQt ACIS entity content browser for │
│ │ SAT/SAB debugging │
├─────────────┼───────────────────────────────────────┤
│ strip │ Strip comments and THUMBNAILIMAGE │
│ │ section from DXF files │
├─────────────┼───────────────────────────────────────┤
│ config │ Manage config files │
├─────────────┼───────────────────────────────────────┤
│ info │ Show information and optional stats │
│ │ of DXF files as loaded by ezdxf │
├─────────────┼───────────────────────────────────────┤
│ hpgl │ View and/or convert HPGL/2 plot files │
│ │ to DXF, SVG or PDF │
└─────────────┴───────────────────────────────────────┘
The help option -h is supported by the main script and all sub-commands:
C:\> ezdxf -h
usage: ezdxf [-h] [-V] [-v] [--config CONFIG] [--log LOG]
{pp,audit,draw,view,browse,browse-acis,strip,config} ...
Command launcher for the Python package "ezdxf":
https://pypi.org/project/ezdxf/
positional arguments:
{pp,audit,draw,view,browse,strip}
pp pretty print DXF files as HTML file
audit audit and repair DXF files
draw draw and convert DXF files by Matplotlib
view view DXF files by the PyQt viewer
browse browse DXF file structure
browse-acis browse ACIS structures in DXF files
strip strip comments from DXF files
config manage config files
info show information and optional stats of DXF files loaded by ezdxf,
this may not represent the original content of the file, use the
browse command to see the original content
optional arguments:
-h, --help show this help message and exit
-V, --version show version and exit
-f, --fonts rebuild system font cache and print all fonts found
-v, --verbose give more output
--config CONFIG path to a config file
--log LOG path to a verbose appending log
NOTE:
The ezdxf script is the only executable script installed on the user system.
System
ezdxf -V shows the ezdxf and Python version your are running and if the C-extensions are used.
ezdxf 1.1.0b1 from c:\source\ezdxf.git\src\ezdxf
Python version: 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
using C-extensions: yes
ezdxf -f rebuilds the system font cache and shows all fonts found.
Pretty Printer
Pretty print the DXF text content as HTML file and open the file in the default web browser:
C:\> ezdxf pp -o gear.dxf
[image]
Print help:
C:\> ezdxf pp -h
usage: ezdxf pp [-h] [-o] [-r] [-x] [-l] [-s SECTIONS] FILE [FILE ...]
positional arguments:
FILE DXF files pretty print
optional arguments:
-h, --help show this help message and exit
-o, --open open generated HTML file by the default web browser
-r, --raw raw mode, no DXF structure interpretation
-x, --nocompile don't compile points coordinates into single tags (only in raw mode)
-l, --legacy legacy mode, reorder DXF point coordinates
-s SECTIONS, --sections SECTIONS
choose sections to include and their order, h=HEADER, c=CLASSES,
t=TABLES, b=BLOCKS, e=ENTITIES, o=OBJECTS
Audit
Audit and recover the DXF file “gear.dxf” and save the recovered version as “gear.rec.dxf”:
C:\> ezdxf audit -s gear.dxf
auditing file: gear.dxf
No errors found.
Saved recovered file as: gear.rec.dxf
Print help:
C:\> ezdxf audit -h
usage: ezdxf audit [-h] [-s] FILE [FILE ...]
positional arguments:
FILE audit DXF files
optional arguments:
-h, --help show this help message and exit
-s, --save save recovered files with extension ".rec.dxf"
Draw
Convert the DXF file “gear.dxf” into a SVG file by the Matplotlib backend:
C:\> ezdxf draw -o gear.svg gear.dxf
The “gear.svg” created by the Matplotlib backend: [image]
Show all output formats supported by the Matplotlib backend on your system. This output may vary:
C:\> ezdxf draw --formats
eps: Encapsulated Postscript
jpg: Joint Photographic Experts Group
jpeg: Joint Photographic Experts Group
pdf: Portable Document Format
pgf: PGF code for LaTeX
png: Portable Network Graphics
ps: Postscript
raw: Raw RGBA bitmap
rgba: Raw RGBA bitmap
svg: Scalable Vector Graphics
svgz: Scalable Vector Graphics
tif: Tagged Image File Format
tiff: Tagged Image File Format
Print help:
C:\> ezdxf draw -h
usage: ezdxf draw [-h] [--formats] [-l LAYOUT] [--all-layers-visible]
[--all-entities-visible] [-o OUT] [--dpi DPI] [-v]
[FILE]
positional arguments:
FILE DXF file to view or convert
optional arguments:
-h, --help show this help message and exit
--formats show all supported export formats and exit
-l LAYOUT, --layout LAYOUT
select the layout to draw, default is "Model"
--all-layers-visible draw all layers including the ones marked as invisible
--all-entities-visible
draw all entities including the ones marked as
invisible (some entities are individually marked as
invisible even if the layer is visible)
-o OUT, --out OUT output filename for export
--dpi DPI target render resolution, default is 300
-v, --verbose give more output
View
View the DXF file “gear.dxf” by the PyQt backend:
C:\> ezdxf view gear.dxf
[image]
Print help:
C:\> ezdxf view -h
usage: ezdxf view [-h] [-l LAYOUT] [--lwscale LWSCALE] [FILE]
positional arguments:
FILE DXF file to view
optional arguments:
-h, --help show this help message and exit
-l LAYOUT, --layout LAYOUT
select the layout to draw, default is "Model"
--lwscale LWSCALE set custom line weight scaling, default is 0 to
disable line weights at all
Browse
Browse the internal structure of a DXF file like a file system:
C:\> ezdxf browse gear.dxf
[image]
C:\> ezdxf browse -h
usage: ezdxf browse [-h] [-l LINE] [-g HANDLE] [FILE]
positional arguments:
FILE DXF file to browse
optional arguments:
-h, --help show this help message and exit
-l LINE, --line LINE go to line number
-g HANDLE, --handle HANDLE
go to entity by HANDLE, HANDLE has to be a hex value without
any prefix like 'fefe'
The browse command stores options in the config file, e.g. for the Notepad++ on Windows:
[browse-command]
text_editor = "C:\Program Files\Notepad++\notepad++.exe" "{filename}" -n{num}
icon_size = 32
text_editor is a simple format string: text_editor.format(filename="test.dxf", num=100)
Quote commands including spaces and always quote the filename argument!
For xed on Linux Mint use (note: absolute path to executable):
[browse-command]
text_editor = /usr/bin/xed "{filename}" +{num}
icon_size = 32
For gedit on Linux use (untested):
[browse-command]
text_editor = /usr/bin/gedit +{num} "{filename}"
icon_size = 32
The browse command opens a DXF structure browser to investigate the internals of a DXF file without
interpreting the content. The functionality of the DXF browser is similar to the DXF Pretty Printer (pp
command), but without the disadvantage of creating giant HTML files. The intended usage is debugging
invalid DXF files, which can not be loaded by the ezdxf.readfile() or the ezdxf.recover.readfile()
functions.
Line Numbers
The low level tag loader ignores DXF comments (group code 999). If there are comments in the DXF file the
line numbers displayed in the DXF browser are not synchronized, use the strip command beforehand to
remove all comments from the DXF file in order to keep the line numbers synchronized.
GUI Features
The tree view on the left shows the outline of the DXF file. The number in round brackets on the right
side of each item shows the count of structure entities within the structure layer, the value in angle
brackets on the left side is the entity handle.
The right list view shows the entity content as DXF tags. Structure tags (data type <ctrl>) are shown in
blue, a double click on a reference handle (datatype <ref>) jumps to the referenced entity, reference
handles of non-existent targets are shown in red.
Clicking on the first structure tag in the list opens the DXF reference provided by Autodesk in the
standard web browser.
Auto Reload
The browser automatically displays a dialog for reloading DXF files if they have been modified by an
external application.
Menus and Shortcuts
•
File Menu
• Open DXF file… Ctrl+O
• Reload DXF file Ctrl+R
• Open in Text Editor Ctrl+T, open the DXF file in the associated text editor at the current
location
• Export DXF Entity… Ctrl+E, export the current DXF entity shown in the list view as text file
• Copy selected DXF Tags to Clipboard Ctrl+C, copy the current selected DXF tags into the
clipboard
• Copy DXF Entity to Clipboard Ctrl+Shift+C, copy all DXF tags of the current DXF entity shown
in the list view into the clipboard
• Quit Ctrl+Q
•
Navigate Menu
• Go to Handle… Ctrl+G
• Go to Line… Ctrl+L
• Find Text… Ctrl+F, opens the find text dialog
• Next Entity Ctrl+Right, go to the next entity in the DXF structure
• Previous Entity Ctrl+Right, go to the previous entity in the DXF structure
• Show Entity in TreeView Ctrl+Down, expand the left tree view to the currently displayed entity
in the list view - this does not happen automatically for performance reasons
• Entity History Back Alt+Left
• Entity History Forward Alt+Right
• Go to HEADERS Section Shift+H
• Go to BLOCKS Section Shift+B
• Go to ENTITIES Section Shift+E
• Go to OBJECTS Section Shift+O
•
Bookmarks Menu
• Store Bookmark… Ctrl+Shift+B, store current location as named bookmark
• Go to Bookmark… Ctrl+B, go to stored location
Browse-ACIS
Show and export the SAT or SAB content of ACIS entities:
C:\> ezdxf browse-acis 3dsolid.dxf
[image]
The DXF format stores modern solid geometry as SAT data for DXF R2000 - R2010 and as SAB data for DXF
R2013 and later. This command shows the content of this entities and also let you export the raw data for
further processing.
Entity View
The entity view is a read-only text editor, it’s possible to select and copy parts of the text into the
clipboard. To improve the readability all ACIS entities get automatically an id because AutoCAD and
BricsCAD use relative references for ACIS data export and do not assign entity ids. The id is shown as
decimal number in parenthesis after the entity name. The ~ character is a shortcut for a null-pointer.
C:\>ezdxf browse-acis -h
usage: ezdxf browse-acis [-h] [-g HANDLE] [FILE]
positional arguments:
FILE DXF file to browse
options:
-h, --help show this help message and exit
-g HANDLE, --handle HANDLE
go to entity by HANDLE, HANDLE has to be a hex value
without any prefix like 'fefe'
Menus and Shortcuts
•
File Menu
• Open DXF file… Ctrl+O
• Reload DXF file Ctrl+R
• Export Current Entity View… Ctrl+E, Export the parsed content of the entity view as text file
• Export Raw SAT/SAB Data… Ctrl+W, export the raw SAT data as text file and the raw SAB data as
a binary file for further processing
• Quit Ctrl+Q
Strip
Strip comment tags (group code 999) from ASCII DXF files and can remove the THUMBNAILIMAGE section.
Binary DXF files are not supported.
C:\> ezdxf strip -h
usage: ezdxf strip [-h] [-b] [-v] FILE [FILE ...]
positional arguments:
FILE DXF file to process, wildcards "*" and "?" are supported
optional arguments:
-h, --help show this help message and exit
-b, --backup make a backup copy with extension ".bak" from the DXF file,
overwrites existing backup files
-t, --thumbnail strip THUMBNAILIMAGE section
-v, --verbose give more output
Config
Manage config files.
C:\> ezdxf config -h
usage: ezdxf config [-h] [-p] [-w FILE] [--home] [--reset]
optional arguments:
-h, --help show this help message and exit
-p, --print print configuration
-w FILE, --write FILE
write configuration
--home create config file 'ezdxf.ini' in the user home directory
'~/.config/ezdxf', $XDG_CONFIG_HOME is supported if set
--reset factory reset, delete default config files 'ezdxf.ini'
Info
Show information and optional stats of DXF files as loaded by ezdxf, this may not represent the original
content of the file, use the browse command to see the original content. The upgrade is necessary for
very old DXF versions prior to R12 and for the “special” versions R13 and R14. The -s option shows some
statistics about the DXF content like entity count or table count. Use the -v option show more of
everything.
C:\> ezdxf info -h
usage: ezdxf info [-h] [-v] [-s] FILE [FILE ...]
positional arguments:
FILE DXF file to process, wildcards "*" and "?" are supported
options:
-h, --help show this help message and exit
-v, --verbose give more output
-s, --stats show content stats
This is the verbose output for an old DXF R10 file and shows that the loading process created some
required structures which do not exist in DXF R10 files, like the BLOCK_RECORD table or the OBJECTS
section:
C:\> ezdxf info -v -s test_R10.dxf
Filename: "test_R10.dxf"
Loaded content was upgraded from DXF Version AC1006 (R10)
Release: R12
DXF Version: AC1009
Maintenance Version: <undefined>
Codepage: ANSI_1252
Encoding: cp1252
Unit system: Imperial
Modelspace units: Unitless
$LASTSAVEDBY: <undefined>
$HANDSEED: 0
$FINGERPRINTGUID: {9EADDC7C-5982-4C68-B770-8A62378C2B90}
$VERSIONGUID: {49336E63-D99B-45EC-803C-4D2BD03A7DE0}
$USERI1=0
$USERI2=0
$USERI3=0
$USERI4=0
$USERI5=0
$USERR1=0.0
$USERR2=0.0
$USERR3=0.0
$USERR4=0.0
$USERR5=0.0
File was not created by ezdxf >= 0.16.4
File was not written by ezdxf >= 0.16.4
Content stats:
LAYER table entries: 18
0
Defpoints
LYR_00
LYR_01
LYR_02
LYR_03
LYR_04
LYR_05
LYR_06
LYR_07
LYR_08
LYR_09
LYR_10
LYR_11
LYR_12
LYR_13
LYR_14
LYR_15
LTYPE table entries: 13
BORDER
ByBlock
ByLayer
CENTER
CONTINUOUS
CUTTING
DASHDOT
DASHED
DIVIDE
DOT
HIDDEN
PHANTOM
STITCH
STYLE table entries: 1
STANDARD
DIMSTYLE table entries: 1
Standard
APPID table entries: 1
ACAD
UCS table entries: 0
VIEW table entries: 0
VPORT table entries: 1
*Active
BLOCK_RECORD table entries: 2
*Model_Space
*Paper_Space
Entities in modelspace: 78
ARC (2)
CIRCLE (2)
LINE (74)
Entities in OBJECTS section: 20
ACDBDICTIONARYWDFLT (1)
ACDBPLACEHOLDER (1)
DICTIONARY (11)
LAYOUT (2)
MATERIAL (3)
MLEADERSTYLE (1)
MLINESTYLE (1)
Show Version & Configuration
Show the ezdxf version and configuration:
C:\> ezdxf -Vv
ezdxf v0.16.5b0 @ d:\source\ezdxf.git\src\ezdxf
Python version: 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]
using C-extensions: yes
using Matplotlib: yes
Configuration:
[core]
default_dimension_text_style = OpenSansCondensed-Light
test_files = D:\Source\dxftest
font_cache_directory =
load_proxy_graphics = true
store_proxy_graphics = true
log_unprocessed_tags = false
filter_invalid_xdata_group_codes = true
write_fixed_meta_data_for_testing = false
disable_c_ext = false
[browse-command]
text_editor = "C:\Program Files\Notepad++\notepad++.exe" "{filename}" -n{num}
Environment Variables:
EZDXF_DISABLE_C_EXT=
EZDXF_TEST_FILES=D:\Source\dxftest
EZDXF_CONFIG_FILE=
Existing Configuration Files:
C:\Users\manfred\.config\ezdxf\ezdxf.ini
SEE ALSO:
Documentation of the ezdxf.options module and the Environment Variables.
HPGL/2 Viewer/Converter
New in version 1.1.
The hpgl command shows and/or converts HPGL/2 plot files to DXF, SVG or PDF.
DXF
The page content is created at the origin of the modelspace and 1 drawing unit is 1 plot unit (1 plu =
0.025mm) unless scaling values are provided.
The content of HPGL files is intended to be plotted on white paper, so the appearance on a dark
background in modelspace is not very clear. To fix this, the --map_black_to_white option maps black
fillings and lines to white.
All entities are mapped to a layer named COLOR_<#> according to the pen number. In order to process the
content better, it is also possible to assign the DXF elements an ACI color value according to the pen
number through the --aci option, but then the RGB color is lost because the RGB color always has the
higher priority over the ACI value.
The first paperspace layout “Layout0” is set up to print the entire modelspace on one sheet, the size of
the page is the size of the original plot file in millimeters.
SVG
The plot units are mapped 1:1 to viewBox units and the size of image is the size of the original plot
file in millimeters.
PDF
The plot units are converted to PDF units (1/72 inch) so the size of image is the size of the original
plot file in millimeters.
All Formats
HPGL/2’s merge control works at the pixel level and cannot be replicated by DXF, but to prevent fillings
from obscuring text, the filled polygons are sorted by luminance - this can be forced or disabled by the
--merge_control option.
Some plot files that contain pure HPGL/2 code do not contain the escape sequence “Enter HPGL/2 mode”,
without this sequence the HPGL/2 parser cannot recognize the beginning of the HPGL/2 code. The --force
option inserts the “Enter HPGL/2 mode” escape sequence into the data stream, regardless of whether the
file is an HPGL/2 plot file or not, so be careful.
C:\> ezdxf hpgl -h
usage: ezdxf hpgl [-h] [-e FORMAT] [-r {0,90,180,270}] [-x SX] [-y SY] [-m {0,1,2}]
[-f] [--aci] [--map_black_to_white]
[FILE]
positional arguments:
FILE view and/or convert HPGL/2 plot files, wildcards (*, ?)
supported in command line mode
options:
-h, --help show this help message and exit
-e FORMAT, --export FORMAT
convert HPGL/2 plot file to SVG, PDF or DXF from the
command line (no gui)
-r {0,90,180,270}, --rotate {0,90,180,270}
rotate page about 90, 180 or 270 degrees (no gui)
-x SX, --scale_x SX scale page in x-axis direction, use negative values to
mirror page, (no gui)
-y SY, --scale_y SY scale page in y-axis direction, use negative values to
mirror page (no gui)
-m {0,1,2}, --merge_control {0,1,2}
provides control over the order of filled polygons, 0=off
(print order), 1=luminance (order by luminance), 2=auto
(default)
-f, --force inserts the mandatory 'enter HPGL/2 mode' escape sequence
into the data stream; use this flag when no HPGL/2 data was
found and you are sure the file is a HPGL/2 plot file
--aci use pen numbers as ACI colors (DXF only)
--map_black_to_white map black RGB plot colors to white RGB, does not affect ACI
colors (DXF only)
Note that plot files are intended to be plotted on white paper.
RENDERING
The ezdxf.render subpackage provides helpful utilities to create complex forms.
• create complex meshes as Mesh entity.
• render complex curves like bezier curves, euler spirals or splines as Polyline entity
• vertex generators for simple and complex forms like circle, ellipse or euler spiral
Content
Spline
class ezdxf.render.Spline(points: Iterable[UVec] | None = None, segments: int = 100)
This class can be used to render B-splines into DXF R12 files as approximated Polyline entities.
The advantage of this class over the R12Spline class is, that this is a real 3D curve, which means
that the B-spline vertices do have to be located in a flat plane, and no UCS class is needed to
place the curve in 3D space.
SEE ALSO:
The newer BSpline class provides the advanced vertex interpolation method flattening().
__init__(points: Iterable[UVec] | None = None, segments: int = 100)
Parameters
• points – spline definition points
• segments – count of line segments for approximation, vertex count is segments + 1
subdivide(segments: int = 4) -> None
Calculate overall segment count, where segments is the sub-segment count, segments = 4,
means 4 line segments between two definition points e.g. 4 definition points and 4 segments
= 12 overall segments, useful for fit point rendering.
Parameters
segments – sub-segments count between two definition points
render_as_fit_points(layout: BaseLayout, degree: int = 3, method: str = 'chord', dxfattribs: dict
| None = None) -> None
Render a B-spline as 2D/3D Polyline, where the definition points are fit points.
• 2D spline vertices uses: add_polyline2d()
• 3D spline vertices uses: add_polyline3d()
Parameters
• layout – BaseLayout object
• degree – degree of B-spline (order = degree + 1)
• method – “uniform”, “distance”/”chord”, “centripetal”/”sqrt_chord” or “arc”
calculation method for parameter t
• dxfattribs – DXF attributes for Polyline
render_open_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
Render an open uniform B-spline as 3D Polyline. Definition points are control points.
Parameters
• layout – BaseLayout object
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
render_uniform_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
Render a uniform B-spline as 3D Polyline. Definition points are control points.
Parameters
• layout – BaseLayout object
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
render_closed_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
Render a closed uniform B-spline as 3D Polyline. Definition points are control points.
Parameters
• layout – BaseLayout object
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
render_open_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
dxfattribs=None) -> None
Render a rational open uniform BSpline as 3D Polyline. Definition points are control
points.
Parameters
• layout – BaseLayout object
• weights – list of weights, requires a weight value (float) for each definition
point.
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
render_uniform_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
dxfattribs=None) -> None
Render a rational uniform B-spline as 3D Polyline. Definition points are control points.
Parameters
• layout – BaseLayout object
• weights – list of weights, requires a weight value (float) for each definition
point.
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
render_closed_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
dxfattribs=None) -> None
Render a rational B-spline as 3D Polyline. Definition points are control points.
Parameters
• layout – BaseLayout object
• weights – list of weights, requires a weight value (float) for each definition
point.
• degree – degree of B-spline (order = degree + 1)
• dxfattribs – DXF attributes for Polyline
R12Spline
class ezdxf.render.R12Spline(control_points: Iterable[UVec], degree: int = 2, closed: bool = True)
DXF R12 supports 2D B-splines, but Autodesk do not document the usage in the DXF Reference. The
base entity for splines in DXF R12 is the POLYLINE entity. The spline itself is always in a plane,
but as any 2D entity, the spline can be transformed into the 3D object by elevation and extrusion
(OCS, UCS).
This way it was possible to store the spline parameters in the DXF R12 file, to allow CAD
applications to modify the spline parameters and rerender the B-spline afterward again as polyline
approximation. Therefore, the result is not better than an approximation by the Spline class, it
is also just a POLYLINE entity, but maybe someone need exact this tool in the future.
__init__(control_points: Iterable[UVec], degree: int = 2, closed: bool = True)
Parameters
• control_points – B-spline control frame vertices
• degree – degree of B-spline, only 2 and 3 is supported
• closed – True for closed curve
render(layout: BaseLayout, segments: int = 40, ucs: UCS | None = None, dxfattribs=None) ->
Polyline
Renders the B-spline into layout as 2D Polyline entity. Use an UCS to place the 2D spline
in the 3D space, see approximate() for more information.
Parameters
• layout – BaseLayout object
• segments – count of line segments for approximation, vertex count is segments + 1
• ucs – UCS definition, control points in ucs coordinates.
• dxfattribs – DXF attributes for Polyline
approximate(segments: int = 40, ucs: UCS | None = None) -> list[UVec]
Approximate the B-spline by a polyline with segments line segments. If ucs is not None,
ucs defines an UCS, to transform the curve into OCS. The control points are placed xy-plane
of the UCS, don’t use z-axis coordinates, if so make sure all control points are in a plane
parallel to the OCS base plane (UCS xy-plane), else the result is unpredictable and depends
on the CAD application used to open the DXF file - it may crash.
Parameters
• segments – count of line segments for approximation, vertex count is segments + 1
• ucs – UCS definition, control points in ucs coordinates
Returns
list of vertices in OCS as Vec3 objects
Bezier
class ezdxf.render.Bezier
Render a bezier curve as 2D/3D Polyline.
The Bezier class is implemented with multiple segments, each segment is an optimized 4 point
bezier curve, the 4 control points of the curve are: the start point (1) and the end point (4),
point (2) is start point + start vector and point (3) is end point + end vector. Each segment has
its own approximation count.
SEE ALSO:
The new ezdxf.path package provides many advanced construction tools based on the Path class.
start(point: UVec, tangent: UVec) -> None
Set start point and start tangent.
Parameters
• point – start point
• tangent – start tangent as vector, example: (5, 0, 0) means a horizontal tangent
with a length of 5 drawing units
append(point: UVec, tangent1: UVec, tangent2: UVec | None = None, segments: int = 20)
Append a control point with two control tangents.
Parameters
• point – control point
• tangent1 – first tangent as vector “left” of the control point
• tangent2 – second tangent as vector “right” of the control point, if omitted
tangent2 = -tangent1
• segments – count of line segments for the polyline approximation, count of line
segments from the previous control point to the appended control point.
render(layout: BaseLayout, force3d: bool = False, dxfattribs=None) -> None
Render Bezier curve as 2D/3D Polyline.
Parameters
• layout – BaseLayout object
• force3d – force 3D polyline rendering
• dxfattribs – DXF attributes for Polyline
EulerSpiral
class ezdxf.render.EulerSpiral(curvature: float = 1)
Render an euler spiral as a 3D Polyline or a Spline entity.
This is a parametric curve, which always starts at the origin (0, 0).
__init__(curvature: float = 1)
Parameters
curvature – Radius of curvature
render_polyline(layout: BaseLayout, length: float = 1, segments: int = 100, matrix: Matrix44 |
None = None, dxfattribs=None)
Render curve as Polyline.
Parameters
• layout – BaseLayout object
• length – length measured along the spiral curve from its initial position
• segments – count of line segments to use, vertex count is segments + 1
• matrix – transformation matrix as Matrix44
• dxfattribs – DXF attributes for Polyline
Returns
Polyline
render_spline(layout: BaseLayout, length: float = 1, fit_points: int = 10, degree: int = 3,
matrix: Matrix44 | None = None, dxfattribs=None)
Render curve as Spline.
Parameters
• layout – BaseLayout object
• length – length measured along the spiral curve from its initial position
• fit_points – count of spline fit points to use
• degree – degree of B-spline
• matrix – transformation matrix as Matrix44
• dxfattribs – DXF attributes for Spline
Returns
Spline
Random Paths
Random path generators for testing purpose.
ezdxf.render.random_2d_path(steps: int = 100, max_step_size: float = 1.0, max_heading: float = math.pi /
2, retarget: int = 20) -> Iterable[Vec2]
Returns a random 2D path as iterable of Vec2 objects.
Parameters
• steps – count of vertices to generate
• max_step_size – max step size
• max_heading – limit heading angle change per step to ± max_heading/2 in radians
• retarget – specifies steps before changing global walking target
ezdxf.render.random_3d_path(steps: int = 100, max_step_size: float = 1.0, max_heading: float = math.pi /
2.0, max_pitch: float = math.pi / 8.0, retarget: int = 20) -> Iterable[Vec3]
Returns a random 3D path as iterable of Vec3 objects.
Parameters
• steps – count of vertices to generate
• max_step_size – max step size
• max_heading – limit heading angle change per step to ± max_heading/2, rotation about the
z-axis in radians
• max_pitch – limit pitch angle change per step to ± max_pitch/2, rotation about the x-axis
in radians
• retarget – specifies steps before changing global walking target
Forms
This module provides functions to create 2D and 3D forms as vertices or mesh objects.
2D Forms
• box()
• circle()
• ellipse()
• euler_spiral()
• gear()
• ngon()
• square()
• star()
• turtle()
3D Forms
• cone_2p()
• cone()
• cube()
• cylinder()
• cylinder_2p()
• helix()
• sphere()
• torus()
3D Form Builder
• extrude()
• extrude_twist_scale()
• from_profiles_linear()
• from_profiles_spline()
• rotation_form()
• sweep()
• sweep_profile()
2D Forms
Basic 2D shapes as iterable of Vec3.
ezdxf.render.forms.box(sx: float = 1.0, sy: float = 1.0, center=False) -> tuple[Vec3, Vec3, Vec3, Vec3]
Returns 4 vertices for a box with a width of sx by and a height of sy. The center of the box in
(0, 0) if center is True otherwise the lower left corner is (0, 0), upper right corner is (sx,
sy).
ezdxf.render.forms.circle(count: int, radius: float = 1, elevation: float = 0, close: bool = False) ->
Iterable[Vec3]
Create polygon vertices for a circle with the given radius and approximated by count vertices,
elevation is the z-axis for all vertices.
Parameters
• count – count of polygon vertices
• radius – circle radius
• elevation – z-axis for all vertices
• close – yields first vertex also as last vertex if True.
Returns
vertices in counter-clockwise orientation as Vec3 objects
ezdxf.render.forms.ellipse(count: int, rx: float = 1, ry: float = 1, start_param: float = 0, end_param:
float = math.tau, elevation: float = 0) -> Iterable[Vec3]
Create polygon vertices for an ellipse with given rx as x-axis radius and ry as y-axis radius
approximated by count vertices, elevation is the z-axis for all vertices. The ellipse goes from
start_param to end_param in counter clockwise orientation.
Parameters
• count – count of polygon vertices
• rx – ellipse x-axis radius
• ry – ellipse y-axis radius
• start_param – start of ellipse in range [0, 2π]
• end_param – end of ellipse in range [0, 2π]
• elevation – z-axis for all vertices
Returns
vertices in counter clockwise orientation as Vec3 objects
ezdxf.render.forms.euler_spiral(count: int, length: float = 1, curvature: float = 1, elevation: float =
0) -> Iterable[Vec3]
Create polygon vertices for an euler spiral of a given length and radius of curvature. This is a
parametric curve, which always starts at the origin (0, 0).
Parameters
• count – count of polygon vertices
• length – length of curve in drawing units
• curvature – radius of curvature
• elevation – z-axis for all vertices
Returns
vertices as Vec3 objects
ezdxf.render.forms.gear(count: int, top_width: float, bottom_width: float, height: float, outside_radius:
float, elevation: float = 0, close: bool = False) -> Iterable[Vec3]
Returns the corner vertices of a gear shape (cogwheel).
WARNING:
This function does not create correct gears for mechanical engineering!
Parameters
• count – teeth count >= 3
• top_width – teeth width at outside radius
• bottom_width – teeth width at base radius
• height – teeth height; base radius = outside radius - height
• outside_radius – outside radius
• elevation – z-axis for all vertices
• close – yields first vertex also as last vertex if True.
Returns
vertices in counter clockwise orientation as Vec3 objects
ezdxf.render.forms.ngon(count: int, length: float | None = None, radius: float | None = None, rotation:
float = 0.0, elevation: float = 0.0, close: bool = False) -> Iterable[Vec3]
Returns the corner vertices of a regular polygon. The polygon size is determined by the edge
length or the circum radius argument. If both are given length has the higher priority.
Parameters
• count – count of polygon corners >= 3
• length – length of polygon side
• radius – circum radius
• rotation – rotation angle in radians
• elevation – z-axis for all vertices
• close – yields first vertex also as last vertex if True.
Returns
vertices as Vec3 objects
ezdxf.render.forms.square(size: float = 1.0, center=False) -> tuple[Vec3, Vec3, Vec3, Vec3]
Returns 4 vertices for a square with a side length of the given size. The center of the square in
(0, 0) if center is True otherwise the lower left corner is (0, 0), upper right corner is (size,
size).
ezdxf.render.forms.star(count: int, r1: float, r2: float, rotation: float = 0.0, elevation: float = 0.0,
close: bool = False) -> Iterable[Vec3]
Returns the corner vertices for a star shape.
The shape has count spikes, r1 defines the radius of the “outer” vertices and r2 defines the
radius of the “inner” vertices, but this does not mean that r1 has to be greater than r2.
Parameters
• count – spike count >= 3
• r1 – radius 1
• r2 – radius 2
• rotation – rotation angle in radians
• elevation – z-axis for all vertices
• close – yields first vertex also as last vertex if True.
Returns
vertices as Vec3 objects
ezdxf.render.forms.turtle(commands: str, start=Vec2(0, 0), angle: float = 0) -> Iterator[Vec2]
Returns the 2D vertices of a polyline created by turtle-graphic like commands:
• <length> - go <length> units forward in current direction and yield vertex
• r<angle> - turn right <angle> in degrees, a missing angle is 90 deg
• l<angle> - turn left <angle> in degrees, a missing angle is 90 deg
• @<x>,<y> - go relative <x>,<y> and yield vertex
The command string "10 l 10 l 10" returns the 4 corner vertices of a square with a side length of
10 drawing units.
Parameters
• commands – command string, commands are separated by spaces
• start – starting point, default is (0, 0)
• angle – starting direction, default is 0 deg
3D Forms
Create 3D forms as MeshTransformer objects.
ezdxf.render.forms.cube(center: bool = True) -> MeshTransformer
Create a cube as MeshTransformer object.
Parameters
center – ‘mass’ center of cube, (0, 0, 0) if True, else first corner at (0, 0, 0)
Returns: MeshTransformer
ezdxf.render.forms.cone(count: int = 16, radius: float = 1.0, apex: UVec = (0, 0, 1), *, caps=True) ->
MeshTransformer
Create a cone as MeshTransformer object, the base center is fixed in the origin (0, 0, 0).
Parameters
• count – edge count of basis_vector
• radius – radius of basis_vector
• apex – tip of the cone
• caps – add a bottom face as ngon if True
ezdxf.render.forms.cone_2p(count: int = 16, radius: float = 1.0, base_center: UVec = (0, 0, 0), apex:
UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
Create a cone as MeshTransformer object from two points, base_center is the center of the base
circle and apex as the tip of the cone.
Parameters
• count – edge count of basis_vector
• radius – radius of basis_vector
• base_center – center point of base circle
• apex – tip of the cone
• caps – add a bottom face as ngon if True
Raises ValueError – the cone orientation cannot be detected (base center == apex)
ezdxf.render.forms.cylinder(count: int = 16, radius: float = 1.0, top_radius: float | None = None,
top_center: UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
Create a cylinder as MeshTransformer object, the base center is fixed in the origin (0, 0, 0).
Parameters
• count – profiles edge count
• radius – radius for bottom profile
• top_radius – radius for top profile, if None top_radius == radius
• top_center – location vector for the center of the top profile
• caps – close hull with top- and bottom faces (ngons)
ezdxf.render.forms.cylinder_2p(count: int = 16, radius: float = 1, base_center: UVec = (0, 0, 0),
top_center: UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
Creates a cylinder as MeshTransformer object from two points, base_center is the center of the
base circle and, top_center the center of the top circle.
Parameters
• count – cylinder profile edge count
• radius – radius for bottom profile
• base_center – center of base circle
• top_center – center of top circle
• caps – close hull with top- and bottom faces (ngons)
Raises ValueError – the cylinder orientation cannot be detected (base center == top center)
ezdxf.render.forms.helix(radius: float, pitch: float, turns: float, resolution: int = 16, ccw=True) ->
Iterator[Vec3]
Yields the vertices of a helix. The center of the helix is always (0, 0), a positive pitch value
creates a helix along the +z-axis, a negative value along the -z-axis.
Parameters
• radius – helix radius
• pitch – the height of one complete helix turn
• turns – count of turns
• resolution – vertices per turn
• ccw – creates a counter-clockwise turning (right-handed) helix if True
ezdxf.render.forms.sphere(count: int = 16, stacks: int = 8, radius: float = 1, *, quads=True) ->
MeshTransformer
Create a sphere as MeshTransformer object, the center of the sphere is always at (0, 0, 0).
Parameters
• count – longitudinal slices
• stacks – latitude slices
• radius – radius of sphere
• quads – use quadrilaterals as faces if True else triangles
ezdxf.render.forms.torus(major_count: int = 16, minor_count: int = 8, major_radius=1.0, minor_radius=0.1,
start_angle: float = 0.0, end_angle: float = math.tau, *, caps=True) -> MeshTransformer
Create a torus as MeshTransformer object, the center of the torus is always at (0, 0, 0). The
major_radius has to be bigger than the minor_radius.
Parameters
• major_count – count of circles
• minor_count – count of circle vertices
• major_radius – radius of the circle center
• minor_radius – radius of circle
• start_angle – start angle of torus in radians
• end_angle – end angle of torus in radians
• caps – close hull with start- and end faces (ngons) if the torus is open
3D Form Builder
ezdxf.render.forms.extrude(profile: Iterable[UVec], path: Iterable[UVec], close=True, caps=False) ->
MeshTransformer
Extrude a profile polygon along a path polyline, the vertices of profile should be in
counter-clockwise order. The sweeping profile will not be rotated at extrusion!
Parameters
• profile – sweeping profile as list of (x, y, z) tuples in counter-clockwise order
• path – extrusion path as list of (x, y, z) tuples
• close – close profile polygon if True
• caps – close hull with top- and bottom faces (ngons)
Returns: MeshTransformer
ezdxf.render.forms.extrude_twist_scale(profile: Iterable[UVec], path: Iterable[UVec], *, twist: float =
0.0, scale: float = 1.0, step_size: float = 1.0, close=True, caps=False, quads=True) -> MeshTransformer
Extrude a profile polygon along a path polyline, the vertices of profile should be in
counter-clockwise order. This implementation can scale and twist the sweeping profile along the
extrusion path. The path segment points are fix points, the max_step_size is used to create
intermediate profiles between this fix points. The max_step_size is adapted for each segment to
create equally spaced distances. The twist angle is the rotation angle in radians and the scale
argument defines the scale factor of the final profile. The twist angle and scaling factor of the
intermediate profiles will be linear interpolated between the start and end values.
Parameters
• profile – sweeping profile as list of (x, y, z) tuples in counter-clockwise order
• path – extrusion path as list of (x, y, z) tuples
• twist – rotate sweeping profile up to the given end rotation angle in radians
• scale – scale sweeping profile gradually from 1.0 to given value
• step_size – rough distance between automatically created intermediate profiles, the step
size is adapted to the distances between the path segment points, a value od 0.0 disables
creating intermediate profiles
• close – close profile polygon if True
• caps – close hull with top- and bottom faces (ngons)
• quads – use quads for “sweeping” faces if True else triangles, the top and bottom faces
are always ngons
Returns: MeshTransformer
ezdxf.render.forms.from_profiles_linear(profiles: Sequence[Sequence[Vec3]], *, close=True, quads=True,
caps=False) -> MeshTransformer
Returns a MeshTransformer instance from linear connected profiles.
Parameters
• profiles – list of profiles
• close – close profile polygon if True
• quads – use quadrilaterals as connection faces if True else triangles
• caps – close hull with top- and bottom faces (ngons)
ezdxf.render.forms.from_profiles_spline(profiles: Sequence[Sequence[Vec3]], subdivide: int = 4, *,
close=True, quads=True, caps=False) -> MeshTransformer
Returns a MeshTransformer instance by spline interpolation between given profiles. Requires at
least 4 profiles. A subdivide value of 4, means, create 4 face loops between two profiles, without
interpolation two profiles create one face loop.
Parameters
• profiles – list of profiles
• subdivide – count of face loops
• close – close profile polygon if True
• quads – use quadrilaterals as connection faces if True else triangles
• caps – close hull with top- and bottom faces (ngons)
ezdxf.render.forms.rotation_form(count: int, profile: Iterable[UVec], angle: float = math.tau, axis: UVec
= (1, 0, 0), *, caps=False) -> MeshTransformer
Returns a MeshTransformer instance created by rotating a profile around an axis.
Parameters
• count – count of rotated profiles
• profile – profile to rotate as list of vertices
• angle – rotation angle in radians
• axis – rotation axis
• caps – close hull with start- and end faces (ngons)
ezdxf.render.forms.sweep(profile: Iterable[UVec], sweeping_path: Iterable[UVec], *, close=True,
quads=True, caps=True) -> MeshTransformer
Returns the mesh from sweeping a profile along a 3D path, where the sweeping path defines the
final location in the WCS.
The profile is defined in a reference system. The origin of this reference system will be moved
along the sweeping path where the z-axis of the reference system is pointing into the moving
direction.
Returns the mesh as ezdxf.render.MeshTransformer object.
Parameters
• profile – sweeping profile defined in the reference system as iterable of (x, y, z)
coordinates in counter-clockwise order
• sweeping_path – the sweeping path defined in the WCS as iterable of (x, y, z) coordinates
• close – close sweeping profile if True
• quads – use quadrilaterals as connection faces if True else triangles
• caps – close hull with top- and bottom faces (ngons)
ezdxf.render.forms.sweep_profile(profile: Iterable[UVec], sweeping_path: Iterable[UVec]) ->
list[Sequence[Vec3]]
Returns the intermediate profiles of sweeping a profile along a 3D path where the sweeping path
defines the final location in the WCS.
The profile is defined in a reference system. The origin of this reference system will be moved
along the sweeping path where the z-axis of the reference system is pointing into the moving
direction.
Returns the start-, end- and all intermediate profiles along the sweeping path.
MeshBuilder
The MeshBuilder classes are helper tools to manage meshes buildup by vertices and faces. The vertices
are stored in a vertices list as Vec3 instances. The faces are stored as a sequence of vertex indices
which is the location of the vertex in the vertex list. A single MeshBuilder class can contain multiple
separated meshes at the same time.
The method MeshBuilder.render_mesh() renders the content as a single DXF Mesh entity, which supports
ngons, ngons are polygons with more than 4 vertices. This entity requires at least DXF R2000.
The method MeshBuilder.render_polyface() renders the content as a single DXF Polyface entity, which
supports only triangles and quadrilaterals. This entity is supported by DXF R12.
The method MeshBuilder.render_3dfaces() renders each face of the mesh as a single DXF Face3d entity,
which supports only triangles and quadrilaterals. This entity is supported by DXF R12.
The MeshTransformer class is often used as an interface object to transfer mesh data between functions
and moduls, like for the mesh exchange add-on meshex.
The basic MeshBuilder class does not support transformations.
class ezdxf.render.MeshBuilder
vertices
List of vertices as Vec3 or (x, y, z) tuple
faces List of faces as list of vertex indices, where a vertex index is the index of the vertex
in the vertices list. A face requires at least three vertices, Mesh supports ngons, so the
count of vertices is not limited.
add_face(vertices: Iterable[UVec]) -> None
Add a face as vertices list to the mesh. A face requires at least 3 vertices, each vertex
is a (x, y, z) tuple or Vec3 object. The new vertex indices are stored as face in the faces
list.
Parameters
vertices – list of at least 3 vertices [(x1, y1, z1), (x2, y2, z2), (x3, y3, y3),
...]
add_mesh(vertices: list[Vec3] | None = None, faces: list[Sequence[int]] | None = None, mesh=None)
-> None
Add another mesh to this mesh.
A mesh can be a MeshBuilder, MeshVertexMerger or Mesh object or requires the attributes
vertices and faces.
Parameters
• vertices – list of vertices, a vertex is a (x, y, z) tuple or Vec3 object
• faces – list of faces, a face is a list of vertex indices
• mesh – another mesh entity
add_vertices(vertices: Iterable[UVec]) -> Sequence[int]
Add new vertices to the mesh, each vertex is a (x, y, z) tuple or a Vec3 object, returns
the indices of the vertices added to the vertices list.
e.g. adding 4 vertices to an empty mesh, returns the indices (0, 1, 2, 3), adding
additional 4 vertices returns the indices (4, 5, 6, 7).
Parameters
vertices – list of vertices, vertex as (x, y, z) tuple or Vec3 objects
Returns
indices of the vertices added to the vertices list
Return type
tuple
bbox() -> BoundingBox
Returns the BoundingBox of the mesh.
copy() Returns a copy of mesh.
diagnose() -> MeshDiagnose
Returns the MeshDiagnose object for this mesh.
face_normals() -> Iterator[Vec3]
Yields all face normals, yields the NULLVEC instance for degenerated faces.
face_orientation_detector(reference: int = 0) -> FaceOrientationDetector
Returns a FaceOrientationDetector or short fod instance. The forward orientation is
defined by the reference face which is 0 by default.
The fod can check if all faces are reachable from the reference face and if all faces have
the same orientation. The fod can be reused to unify the face orientation of the mesh.
faces_as_vertices() -> Iterator[list[Vec3]]
Yields all faces as list of vertices.
flip_normals() -> None
Flips the normals of all faces by reversing the vertex order inplace.
classmethod from_builder(other: MeshBuilder)
Create new mesh from other mesh builder, faster than from_mesh() but supports only
MeshBuilder and inherited classes.
classmethod from_mesh(other: MeshBuilder | Mesh) -> T
Create new mesh from other mesh as class method.
Parameters
other – mesh of type MeshBuilder and inherited or DXF Mesh entity or any object
providing attributes vertices, edges and faces.
classmethod from_polyface(other: Polymesh | Polyface) -> T
Create new mesh from a Polyface or Polymesh object.
get_face_vertices(index: int) -> Sequence[Vec3]
Returns the face index as sequence of Vec3 objects.
get_face_normal(index: int) -> Vec3
Returns the normal vector of the face index as Vec3, returns the NULLVEC instance for
degenerated faces.
merge_coplanar_faces(passes: int = 1) -> MeshTransformer
Returns a new MeshBuilder object with merged adjacent coplanar faces.
The faces have to share at least two vertices and have to have the same clockwise or
counter-clockwise vertex order.
The current implementation is not very capable!
mesh_tessellation(max_vertex_count: int = 4) -> MeshTransformer
Returns a new MeshTransformer instance, where each face has no more vertices than the given
max_vertex_count.
The fast mode uses a shortcut for faces with less than 6 vertices which may not work for
concave faces!
normalize_faces() -> None
Removes duplicated vertex indices from faces and stores all faces as open faces, where the
last vertex is not coincident with the first vertex.
open_faces() -> Iterator[Sequence[int]]
Yields all faces as sequence of integers where the first vertex is not coincident with the
last vertex.
optimize_vertices(precision: int = 6) -> MeshTransformer
Returns a new mesh with optimized vertices. Coincident vertices are merged together and all
faces are open faces (first vertex != last vertex). Uses internally the MeshVertexMerger
class to merge vertices.
render_3dfaces(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs:
UCS | None = None)
Render mesh as Face3d entities into layout.
Parameters
• layout – BaseLayout object
• dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}
• matrix – transformation matrix of type Matrix44
• ucs – transform vertices by UCS to WCS
render_mesh(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs: UCS |
None = None)
Render mesh as Mesh entity into layout.
Parameters
• layout – BaseLayout object
• dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}
• matrix – transformation matrix of type Matrix44
• ucs – transform vertices by UCS to WCS
render_normals(layout: GenericLayoutType, length: float = 1, relative=True, dxfattribs=None)
Render face normals as Line entities into layout, useful to check orientation of mesh
faces.
Parameters
• layout – BaseLayout object
• length – visual length of normal, use length < 0 to point normals in opposite
direction
• relative – scale length relative to face size if True
• dxfattribs – dict of DXF attributes e.g. {'layer': 'normals', 'color': 6}
render_polyface(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs:
UCS | None = None)
Render mesh as Polyface entity into layout.
Parameters
• layout – BaseLayout object
• dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}
• matrix – transformation matrix of type Matrix44
• ucs – transform vertices by UCS to WCS
separate_meshes() -> list[MeshTransformer]
A single MeshBuilder instance can store multiple separated meshes. This function returns
this separated meshes as multiple MeshTransformer instances.
subdivide(level: int = 1, quads=True) -> MeshTransformer
Returns a new MeshTransformer object with all faces subdivided.
Parameters
• level – subdivide levels from 1 to max of 5
• quads – create quad faces if True else create triangles
subdivide_ngons(max_vertex_count=4) -> Iterator[Sequence[Vec3]]
Yields all faces as sequence of Vec3 instances, where all ngons which have more than
max_vertex_count vertices gets subdivided. In contrast to the tessellation() method,
creates this method a new vertex in the centroid of the face. This can create a more
regular tessellation but only works reliable for convex faces!
tessellation(max_vertex_count: int = 4) -> Iterator[Sequence[Vec3]]
Yields all faces as sequence of Vec3 instances, each face has no more vertices than the
given max_vertex_count. This method uses the “ear clipping” algorithm which works with
concave faces too and does not create any additional vertices.
unify_face_normals(*, fod: FaceOrientationDetector | None = None) -> MeshTransformer
Returns a new MeshTransformer object with unified face normal vectors of all faces. The
forward direction (not necessarily outwards) is defined by the face-normals of the majority
of the faces. This function can not process non-manifold meshes (more than two faces are
connected by a single edge) or multiple disconnected meshes in a single MeshBuilder object.
It is possible to pass in an existing FaceOrientationDetector instance as argument fod.
Raises
• NonManifoldError – non-manifold mesh
• MultipleMeshesError – the MeshBuilder object contains multiple disconnected meshes
unify_face_normals_by_reference(reference: int = 0, *, force_outwards=False, fod:
FaceOrientationDetector | None = None) -> MeshTransformer
Returns a new MeshTransformer object with unified face normal vectors of all faces. The
forward direction (not necessarily outwards) is defined by the reference face, which is the
first face of the mesh by default. This function can not process non-manifold meshes (more
than two faces are connected by a single edge) or multiple disconnected meshes in a single
MeshBuilder object.
The outward direction of all face normals can be forced by stetting the argument
force_outwards to True but this works only for closed surfaces, and it’s time-consuming!
It is not possible to check for a closed surface as long the face normal vectors are not
unified. But it can be done afterward by the attribute MeshDiagnose.is_closed_surface() to
see if the result is trustworthy.
It is possible to pass in an existing FaceOrientationDetector instance as argument fod.
Parameters
• reference – index of the reference face
• force_outwards – forces face-normals to point outwards, this works only for closed
surfaces, and it’s time-consuming!
• fod – FaceOrientationDetector instance
Raises ValueError – non-manifold mesh or the MeshBuilder object
contains multiple disconnected meshes
MeshTransformer
Same functionality as MeshBuilder but supports inplace transformation.
class ezdxf.render.MeshTransformer
Subclass of MeshBuilder
transform(matrix: Matrix44)
Transform mesh inplace by applying the transformation matrix.
Parameters
matrix – 4x4 transformation matrix as Matrix44 object
translate(dx: float | UVec = 0, dy: float = 0, dz: float = 0)
Translate mesh inplace.
Parameters
• dx – translation in x-axis or translation vector
• dy – translation in y-axis
• dz – translation in z-axis
scale(sx: float = 1, sy: float = 1, sz: float = 1)
Scale mesh inplace.
Parameters
• sx – scale factor for x-axis
• sy – scale factor for y-axis
• sz – scale factor for z-axis
scale_uniform(s: float)
Scale mesh uniform inplace.
Parameters
s – scale factor for x-, y- and z-axis
rotate_x(angle: float)
Rotate mesh around x-axis about angle inplace.
Parameters
angle – rotation angle in radians
rotate_y(angle: float)
Rotate mesh around y-axis about angle inplace.
Parameters
angle – rotation angle in radians
rotate_z(angle: float)
Rotate mesh around z-axis about angle inplace.
Parameters
angle – rotation angle in radians
rotate_axis(axis: UVec, angle: float)
Rotate mesh around an arbitrary axis located in the origin (0, 0, 0) about angle.
Parameters
• axis – rotation axis as Vec3
• angle – rotation angle in radians
MeshVertexMerger
Same functionality as MeshBuilder, but created meshes with unique vertices and no doublets, but
MeshVertexMerger needs extra memory for bookkeeping and also does not support transformations. The
location of the merged vertices is the location of the first vertex with the same key.
This class is intended as intermediate object to create compact meshes and convert them to
MeshTransformer objects to apply transformations:
mesh = MeshVertexMerger()
# create your mesh
mesh.add_face(...)
# convert mesh to MeshTransformer object
return MeshTransformer.from_builder(mesh)
class ezdxf.render.MeshVertexMerger(precision: int = 6)
Subclass of MeshBuilder
Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping.
MeshVertexMerger creates a key for every vertex by rounding its components by the Python round()
function and a given precision value. Each vertex with the same key gets the same vertex index,
which is the index of first vertex with this key, so all vertices with the same key will be
located at the location of this first vertex. If you want an average location of all vertices with
the same key use the MeshAverageVertexMerger class.
Parameters
precision – floating point precision for vertex rounding
MeshAverageVertexMerger
This is an extended version of MeshVertexMerger. The location of the merged vertices is the average
location of all vertices with the same key, this needs extra memory and runtime in comparison to
MeshVertexMerger and this class also does not support transformations.
class ezdxf.render.MeshAverageVertexMerger(precision: int = 6)
Subclass of MeshBuilder
Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping and runtime for
calculation of average vertex location.
MeshAverageVertexMerger creates a key for every vertex by rounding its components by the Python
round() function and a given precision value. Each vertex with the same key gets the same vertex
index, which is the index of first vertex with this key, the difference to the MeshVertexMerger
class is the calculation of the average location for all vertices with the same key, this needs
extra memory to keep track of the count of vertices for each key and extra runtime for updating
the vertex location each time a vertex with an existing key is added.
Parameters
precision – floating point precision for vertex rounding
class ezdxf.render.mesh.EdgeStat(count: int, balance: int)
Named tuple of edge statistics.
count how often the edge (a, b) is used in faces as (a, b) or (b, a)
balance
count of edges (a, b) - count of edges (b, a) and should be 0 in “healthy” closed surfaces,
if the balance is not 0, maybe doubled coincident faces exist or faces may have mixed
clockwise and counter-clockwise vertex orders
MeshBuilder Helper Classes
class ezdxf.render.MeshDiagnose
Diagnose tool which can be used to analyze and detect errors of MeshBuilder objects like topology
errors for closed surfaces. The object contains cached values, which do not get updated if the
source mesh will be changed!
NOTE:
There exist no tools in ezdxf to repair broken surfaces, but you can use the
ezdxf.addons.meshex addon to exchange meshes with the open source tool MeshLab.
Create an instance of this tool by the MeshBuilder.diagnose() method.
property bbox: BoundingBox
Returns the BoundingBox of the mesh. (cached data)
property edge_stats: Dict[Tuple[int, int], EdgeStat]
Returns the edge statistics as a dict. The dict-key is the edge as tuple of two vertex
indices (a, b) where a is always smaller than b. The dict-value is an EdgeStat tuple of
edge count and edge balance, see EdgeStat for the definition of edge count and edge
balance. (cached data)
property euler_characteristic: int
Returns the Euler characteristic: https://en.wikipedia.org/wiki/Euler_characteristic
This number is always 2 for convex polyhedra.
property face_normals: Sequence[Vec3]
Returns all face normal vectors as sequence. The NULLVEC instance is used as normal vector
for degenerated faces. (cached data)
property faces: Sequence[Sequence[int]]
Sequence of faces as Sequence[int]
property is_closed_surface: bool
Returns True if the mesh has a closed surface. This method does not require a unified face
orientation. If multiple separated meshes are present the state is only True if all meshes
have a closed surface. (cached data)
Returns False for non-manifold meshes.
property is_edge_balance_broken: bool
Returns True if the edge balance is broken, this indicates a topology error for closed
surfaces. A non-broken edge balance reflects that each edge connects two faces, where the
edge is clockwise oriented in the first face and counter-clockwise oriented in the second
face. A broken edge balance indicates possible topology errors like mixed face vertex
orientations or a non-manifold mesh where an edge connects more than two faces. (cached
data)
property is_manifold: bool
Returns True if all edges have an edge count < 3. (cached data)
A non-manifold mesh has edges with 3 or more connected faces.
property n_edges: int
Returns the unique edge count. (cached data)
property n_faces: int
Returns the face count.
property n_vertices: int
Returns the vertex count.
property vertices: Sequence[Vec3]
Sequence of mesh vertices as Vec3 instances
centroid() -> Vec3
Returns the centroid of all vertices. (center of mass)
estimate_face_normals_direction() -> float
Returns the estimated face-normals direction as float value in the range [-1.0, 1.0] for a
closed surface.
This heuristic works well for simple convex hulls but struggles with more complex
structures like a torus (doughnut).
A counter-clockwise (ccw) vertex arrangement for outward pointing faces is assumed but a
clockwise (cw) arrangement works too but the return values are reversed.
The closer the value to 1.0 (-1.0 for cw) the more likely all normals pointing outwards
from the surface.
The closer the value to -1.0 (1.0 for cw) the more likely all normals pointing inwards from
the surface.
There are no exact confidence values if all faces pointing outwards, here some examples for
surfaces created by ezdxf.render.forms functions:
• cube() returns 1.0
• cylinder() returns 0.9992
• sphere() returns 0.9994
• cone() returns 0.9162
• cylinder() with all hull faces pointing outwards but caps pointing inwards returns
0.7785 but the property is_edge_balance_broken returns True which indicates the mixed
vertex orientation
• and the estimation of 0.0469 for a torus() is barely usable
has_non_planar_faces() -> bool
Returns True if any face is non-planar.
surface_area() -> float
Returns the surface area.
total_edge_count() -> int
Returns the total edge count of all faces, shared edges are counted separately for each
face. In closed surfaces this count should be 2x the unique edge count n_edges. (cached
data)
unique_edges() -> Iterable[Tuple[int, int]]
Yields the unique edges of the mesh as int 2-tuples. (cached data)
volume() -> float
Returns the volume of a closed surface or 0 otherwise.
WARNING:
The face vertices have to be in counter-clockwise order, this requirement is not checked
by this method.
The result is not correct for multiple separated meshes in a single MeshBuilder
object!!!
class ezdxf.render.FaceOrientationDetector(mesh: MeshBuilder, reference: int = 0)
Helper class for face orientation and face normal vector detection. Use the method
MeshBuilder.face_orientation_detector() to create an instance.
The face orientation detector classifies the faces of a mesh by their forward or backward
orientation. The forward orientation is defined by a reference face, which is the first face of
the mesh by default and this orientation is not necessarily outwards.
This class has some overlapping features with MeshDiagnose but it has a longer setup time and
needs more memory than MeshDiagnose.
Parameters
• mesh – source mesh as MeshBuilder object
• reference – index of the reference face
is_manifold
True if all edges have an edge count < 3. A non-manifold mesh has edges with 3 or more
connected faces.
property all_reachable: bool
Returns True if all faces are reachable from the reference face same as property
is_single_mesh.
property count: tuple[int, int]
Returns the count of forward and backward oriented faces.
property backward_faces: Iterator[Sequence[int]]
Yields all backward oriented faces.
property forward_faces: Iterator[Sequence[int]]
Yields all forward oriented faces.
property has_uniform_face_normals: bool
Returns True if all reachable faces are forward oriented according to the reference face.
property is_closed_surface: bool
Returns True if the mesh has a closed surface. This method does not require a unified face
orientation. If multiple separated meshes are present the state is only True if all meshes
have a closed surface.
Returns False for non-manifold meshes.
property is_single_mesh: bool
Returns True if only a single mesh is present same as property all_reachable.
classify_faces(reference: int = 0) -> None
Detect the forward and backward oriented faces.
The forward and backward orientation has to be defined by a reference face.
is_reference_face_pointing_outwards() -> bool
Returns True if the normal vector of the reference face is pointing outwards. This works
only for meshes with unified faces which represent a closed surfaces, and it’s a
time-consuming calculation!
Trace
This module provides tools to create banded lines like LWPOLYLINE with width information. Path rendering
as quadrilaterals: Trace, Solid or Face3d.
class ezdxf.render.trace.TraceBuilder
Sequence of 2D banded lines like polylines with start- and end width or curves with start- and end
width.
NOTE:
Accepts 3D input, but z-axis is ignored. The TraceBuilder is a 2D only object and uses only the
OCS coordinates!
abs_tol
Absolute tolerance for floating point comparisons
append(trace: AbstractTrace) -> None
Append a new trace.
close()
Close multi traces by merging first and last trace, if linear traces.
faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
Yields all faces as 4-tuples of Vec2 objects in OCS.
faces_wcs(ocs: OCS, elevation: float) -> Iterable[Sequence[Vec3]]
Yields all faces as 4-tuples of Vec3 objects in WCS.
virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
Iterable[Quadrilateral]
Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.
If a document is given, the doc attribute of the new entities will be set and the new
entities will be automatically added to the entity database of that document.
NOTE:
The TraceBuilder is a 2D only object and uses only the OCS coordinates!
Parameters
• dxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”
• dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities
• doc – associated document
classmethod from_polyline(polyline: DXFGraphic, segments: int = 64) -> TraceBuilder
Create a complete trace from a LWPOLYLINE or a 2D POLYLINE entity, the trace consist of
multiple sub-traces if bulge values are present. Uses only the OCS coordinates!
Parameters
• polyline – LWPolyline or 2D Polyline
• segments – count of segments for bulge approximation, given count is for a full
circle, partial arcs have proportional less segments, but at least 3
__len__()
__getitem__()
class ezdxf.render.trace.LinearTrace
Linear 2D banded lines like polylines with start- and end width.
Accepts 3D input, but z-axis is ignored.
abs_tol
Absolute tolerance for floating point comparisons
is_started
True if at least one station exist.
add_station(point: UVec, start_width: float, end_width: float | None = None) -> None
Add a trace station (like a vertex) at location point, start_width is the width of the next
segment starting at this station, end_width is the end width of the next segment.
Adding the last location again, replaces the actual last location e.g. adding lines (a,
b), (b, c), creates only 3 stations (a, b, c), this is very important to connect to/from
splines.
Parameters
• point – 2D location (vertex), z-axis of 3D vertices is ignored.
• start_width – start width of next segment
• end_width – end width of next segment
faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
Yields all faces as 4-tuples of Vec2 objects.
First and last miter is 90 degrees if the path is not closed, otherwise the intersection of
first and last segment is taken into account, a closed path has to have explicit the same
last and first vertex.
virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
Iterable[Quadrilateral]
Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.
If a document is given, the doc attribute of the new entities will be set and the new
entities will be automatically added to the entity database of that document.
Parameters
• dxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”
• dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities
• doc – associated document
class ezdxf.render.trace.CurvedTrace
2D banded curves like arcs or splines with start- and end width.
Represents always only one curved entity and all miter of curve segments are perpendicular to
curve tangents.
Accepts 3D input, but z-axis is ignored.
faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
Yields all faces as 4-tuples of Vec2 objects.
virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
Iterable[Quadrilateral]
Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.
If a document is given, the doc attribute of the new entities will be set and the new
entities will be automatically added to the entity database of that document.
Parameters
• dxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”
• dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities
• doc – associated document
classmethod from_arc(arc: ConstructionArc, start_width: float, end_width: float, segments: int =
64) -> CurvedTrace
Create curved trace from an arc.
Parameters
• arc – ConstructionArc object
• start_width – start width
• end_width – end width
• segments – count of segments for full circle (360 degree) approximation, partial
arcs have proportional less segments, but at least 3
Raises ValueError – if arc.radius <= 0
classmethod from_spline(spline: BSpline, start_width: float, end_width: float, segments: int) ->
CurvedTrace
Create curved trace from a B-spline.
Parameters
• spline – BSpline object
• start_width – start width
• end_width – end width
• segments – count of segments for approximation
Point Rendering
Helper function to render Point entities as DXF primitives.
ezdxf.render.point.virtual_entities(point: Point, pdsize: float = 1, pdmode: int = 0) -> list[DXFGraphic]
Yields point graphic as DXF primitives LINE and CIRCLE entities. The dimensionless point is
rendered as zero-length line!
Check for this condition:
e.dxftype() == 'LINE' and e.dxf.start.isclose(e.dxf.end)
if the rendering engine can’t handle zero-length lines.
Parameters
• point – DXF POINT entity
• pdsize – point size in drawing units
• pdmode – point styling mode, see Point class
SEE ALSO:
Go to ezdxf.entities.Point class documentation for more information about POINT styling modes.
MultiLeaderBuilder
These are helper classes to build MultiLeader entities in an easy way. The MultiLeader entity supports
two kinds of content, for each exist a specialized builder class:
• MultiLeaderMTextBuilder for MText content
• MultiLeaderBlockBuilder for Block content
The usual steps of the building process are:
1. create entity by a factory method
• add_multileader_mtext()
• add_multileader_block()
2. set the content
• MultiLeaderMTextBuilder.set_content()
• MultiLeaderBlockBuilder.set_content()
• MultiLeaderBlockBuilder.set_attribute()
3. set properties
• MultiLeaderBuilder.set_arrow_properties()
• MultiLeaderBuilder.set_connection_properties()
• MultiLeaderBuilder.set_connection_types()
• MultiLeaderBuilder.set_leader_properties()
• MultiLeaderBuilder.set_mleader_style()
• MultiLeaderBuilder.set_overall_scaling()
4. add one or more leader lines
• MultiLeaderBuilder.add_leader_line()
5. finalize building process
• MultiLeaderBuilder.build()
The Tutorial for MultiLeader shows how to use these helper classes in more detail.
class ezdxf.render.MultiLeaderBuilder
Abstract base class to build MultiLeader entities.
property context: MLeaderContext
Returns the context entity MLeaderContext.
property multileader: MultiLeader
Returns the MultiLeader entity.
add_leader_line(side: ConnectionSide, vertices: Iterable[Vec2]) -> None
Add leader as iterable of vertices in render UCS coordinates (WCS by default).
NOTE:
Vertical (top, bottom) and horizontal attachment sides (left, right) can not be mixed in
a single entity - this is a limitation of the MULTILEADER entity.
Parameters
• side – connection side where to attach the leader line
• vertices – leader vertices
build(insert: Vec2, rotation: float = 0.0, ucs: UCS | None = None) -> None
Compute the required geometry data. The construction plane is the xy-plane of the given
render UCS.
Parameters
• insert – insert location for the content in render UCS coordinates
• rotation – content rotation angle around the render UCS z-axis in degrees
• ucs – the render UCS, default is the WCS
set_arrow_properties(name: str = '', size: float = 0.0)
Set leader arrow properties all leader lines have the same arrow type.
The MULTILEADER entity is able to support multiple arrows, but this seems to be unsupported
by CAD applications and is therefore also not supported by the builder classes.
set_connection_properties(landing_gap: float = 0.0, dogleg_length: float = 0.0)
Set the properties how to connect the leader line to the content.
The landing gap is the space between the content and the start of the leader line. The
“dogleg” is the first line segment of the leader in the “horizontal” direction of the
content.
set_connection_types(left=HorizontalConnection.by_style, right=HorizontalConnection.by_style,
top=VerticalConnection.by_style, bottom=VerticalConnection.by_style)
Set the connection type for each connection side.
set_leader_properties(color: int | RGB = colors.BYBLOCK, linetype: str = 'BYBLOCK', lineweight:
int = const.LINEWEIGHT_BYBLOCK, leader_type=LeaderType.straight_lines)
Set leader line properties.
Parameters
• color – line color as AutoCAD Color Index (ACI) or RGB tuple
• linetype – as name string, e.g. “BYLAYER”
• lineweight – as integer value, see: Lineweights
• leader_type – straight lines of spline type
set_mleader_style(style: MLeaderStyle)
Reset base properties by MLeaderStyle properties. This also resets the content!
set_overall_scaling(scale: float)
Set the overall scaling factor for the whole entity, except for the leader line vertices!
Parameters
scale – scaling factor > 0.0
MultiLeaderMTextBuilder
Specialization of MultiLeaderBuilder to build MultiLeader with MTEXT content.
class ezdxf.render.MultiLeaderMTextBuilder
set_content(content: str, color: int | RGB | None = None, char_height: float = 0.0, alignment:
TextAlignment = TextAlignment.left, style: str = '')
Set MTEXT content.
Parameters
• content – MTEXT content as string
• color – block color as AutoCAD Color Index (ACI) or RGB tuple
• char_height – initial char height in drawing units
• alignment – TextAlignment - left, center, right
• style – name of Textstyle as string
quick_leader(content: str, target: Vec2, segment1: Vec2, segment2: Vec2 | None = None,
connection_type: HorizontalConnection | VerticalConnection =
HorizontalConnection.middle_of_top_line, ucs: UCS | None = None) -> None
Creates a quick MTEXT leader. The target point defines where the leader points to. The
segment1 is the first segment of the leader line relative to the target point, segment2 is
an optional second line segment relative to the first line segment. The connection_type
defines the type of connection (horizontal or vertical) and the MTEXT alignment (left,
center or right). Horizontal connections are always left or right aligned, vertical
connections are always center aligned.
Parameters
• content – MTEXT content string
• target – leader target point as Vec2
• segment1 – first leader line segment as relative distance to insert
• segment2 – optional second leader line segment as relative distance to first line
segment
• connection_type – one of HorizontalConnection or VerticalConnection
• ucs – the rendering UCS, default is the WCS
MultiLeaderBlockBuilder
Specialization of MultiLeaderBuilder to build MultiLeader with BLOCK content.
class ezdxf.render.MultiLeaderBlockBuilder
property block_layout: BlockLayout
Returns the block layout.
property extents: BoundingBox
Returns the bounding box of the block.
set_content(name: str, color: int | RGB = colors.BYBLOCK, scale: float = 1.0,
alignment=BlockAlignment.center_extents)
Set BLOCK content.
Parameters
• name – the block name as string
• color – block color as AutoCAD Color Index (ACI) or RGB tuple
• scale – the block scaling, not to be confused with overall scaling
• alignment – the block insertion point or the center of extents
set_attribute(tag: str, text: str, width: float = 1.0)
Add BLOCK attributes based on an ATTDEF entity in the block definition. All properties of
the new created ATTRIB entity are defined by the template ATTDEF entity including the
location.
Parameters
• tag – attribute tag name
• text – attribute content string
• width – width factor
Enums
class ezdxf.render.LeaderType(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
The leader type.
none
straight_lines
splines
class ezdxf.render.ConnectionSide(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
The leader connection side.
Vertical (top, bottom) and horizontal attachment sides (left, right) can not be mixed in a single
entity - this is a limitation of the MULTILEADER entity.
left
right
top
bottom
class ezdxf.render.HorizontalConnection(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
The horizontal leader connection type.
by_style
top_of_top_line
middle_of_top_line
middle_of_text
middle_of_bottom_line
bottom_of_bottom_line
bottom_of_bottom_line_underline
bottom_of_top_line_underline
bottom_of_top_line
bottom_of_top_line_underline_all
class ezdxf.render.VerticalConnection(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
The vertical leader connection type.
by_style
center
center_overline
class ezdxf.render.TextAlignment(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
The MText alignment type.
left
center
right
class ezdxf.render.BlockAlignment(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
The Block alignment type.
center_extents
insertion_point
Arrows
This module provides support for the AutoCAD standard arrow heads used in DIMENSION, LEADER and
MULTILEADER entities. Library user don’t have to use the ARROWS objects directly, but should know the
arrow names stored in it as attributes. The arrow names should be accessed that way:
import ezdxf
arrow = ezdxf.ARROWS.closed_filled
ezdxf.render.arrows.ARROWS
Single instance of _Arrows to work with.
class ezdxf.render.arrows._Arrows
Management object for standard arrows.
__acad__
Set of AutoCAD standard arrow names.
__ezdxf__
Set of arrow names special to ezdxf.
architectural_tick
[image]
closed_filled
[image]
dot [image]
dot_small
[image]
dot_blank
[image]
origin_indicator
[image]
origin_indicator_2
[image]
open [image]
right_angle
[image]
open_30
[image]
closed [image]
dot_smallblank
[image]
none [image]
oblique
[image]
box_filled
[image]
box [image]
closed_blank
[image]
datum_triangle_filled
[image]
datum_triangle
[image]
integral
[image]
ez_arrow
[image]
ez_arrow_blank
[image]
ez_arrow_filled
[image]
is_acad_arrow(item: str) -> bool
Returns True if item is a standard AutoCAD arrow.
is_ezdxf_arrow(item: str) -> bool
Returns True if item is a special ezdxf arrow.
insert_arrow(layout: GenericLayoutType, name: str, insert: UVec = NULLVEC, size: float = 1.0,
rotation: float = 0, *, dxfattribs=None) -> Vec2
Insert arrow as block reference into layout.
render_arrow(layout: GenericLayoutType, name: str, insert: UVec = NULLVEC, size: float = 1.0,
rotation: float = 0, *, dxfattribs=None) -> Vec2
Render arrow as basic DXF entities into layout.
virtual_entities(name: str, insert: UVec = NULLVEC, size: float = 0.625, rotation: float = 0, *,
dxfattribs=None) -> Iterator[DXFGraphic]
Returns all arrow components as virtual DXF entities.
Hatching
This module provides rendering support for hatch patterns as used in Hatch and MPolygon entities.
High Level Functions
ezdxf.render.hatching.hatch_entity(polygon: DXFPolygon, filter_text_boxes=True, jiggle_origin: bool =
True) -> Iterator[tuple[Vec3, Vec3]]
Yields the hatch pattern of the given HATCH or MPOLYGON entity as 3D lines. Each line is a pair
of Vec3 instances as start- and end vertex, points are represented as lines of zero length, which
means the start vertex is equal to the end vertex.
The function yields nothing if polygon has a solid- or gradient filling or does not have a usable
pattern assigned.
Parameters
• polygon – Hatch or MPolygon entity
• filter_text_boxes – ignore text boxes if True
• jiggle_origin – move pattern line origins a small amount to avoid intersections in corner
points which causes errors in patterns
ezdxf.render.hatching.hatch_polygons(baseline: HatchBaseLine, polygons: Sequence[Sequence[Vec2]],
terminate: Callable[[], bool] | None = None) -> Iterator[Line]
Yields all pattern lines for all hatch lines generated by the given HatchBaseLine, intersecting
the given 2D polygons as Line instances. The polygons should represent a single entity with or
without holes, the order of the polygons and their winding orientation (cw or ccw) is not
important. Entities which do not intersect or overlap should be handled separately!
Each polygon is a sequence of Vec2 instances, they are treated as closed polygons even if the last
vertex is not equal to the first vertex.
The hole detection is done by a simple inside/outside counting algorithm and far from perfect, but
is able to handle ordinary polygons well.
The terminate function WILL BE CALLED PERIODICALLY AND should return True to terminate execution.
This can be used to implement a timeout, which can be required if using a very small hatching
distance, especially if you get the data from untrusted sources.
Parameters
• baseline – HatchBaseLine
• polygons – multiple sequences of Vec2 instances of a single entity, the order of
exterior- and hole paths and the winding orientation (cw or ccw) of paths is not
important
• terminate – callback function which is called periodically and should return True to
terminate the hatching function
ezdxf.render.hatching.hatch_paths(baseline: HatchBaseLine, paths: Sequence[Path], terminate: Callable[[],
bool] | None = None) -> Iterator[Line]
Yields all pattern lines for all hatch lines generated by the given HatchBaseLine, intersecting
the given 2D Path instances as Line instances. The paths are handled as projected into the
xy-plane the z-axis of path vertices will be ignored if present.
Same as the hatch_polygons() function, but for Path instances instead of polygons build of
vertices. This function does not flatten the paths into vertices, instead the real intersections
of the Bézier curves and the hatch lines are calculated.
For more information see the docs of the hatch_polygons() function.
Parameters
• baseline – HatchBaseLine
• paths – sequence of Path instances of a single entity, the order of exterior- and hole
paths and the winding orientation (cw or ccw) of the paths is not important
• terminate – callback function which is called periodically and should return True to
terminate the hatching function
Classes
class ezdxf.render.hatching.HatchBaseLine(origin: Vec2, direction: Vec2, offset: Vec2, line_pattern:
list[float] | None = None, min_hatch_line_distance=MIN_HATCH_LINE_DISTANCE)
A hatch baseline defines the source line for hatching a geometry. A complete hatch pattern of a
DXF entity can consist of one or more hatch baselines.
Parameters
• origin – the origin of the hatch line as Vec2 instance
• direction – the hatch line direction as Vec2 instance, must not (0, 0)
• offset – the offset of the hatch line origin to the next or to the previous hatch line
• line_pattern – line pattern as sequence of floats, see also PatternRenderer
• min_hatch_line_distance – minimum hatch line distance to render, raises an
DenseHatchingLinesError exception if the distance between hatch lines is smaller than
this value
Raises
• HatchLineDirectionError – hatch baseline has no direction, (0, 0) vector
• DenseHatchingLinesError – hatching lines are too narrow
hatch_line(distance: float) -> HatchLine
Returns the HatchLine at the given signed distance.
pattern_renderer(distance: float) -> PatternRenderer
Returns the PatternRenderer for the given signed distance.
signed_distance(point: Vec2) -> float
Returns the signed normal distance of the given point from this hatch baseline.
class ezdxf.render.hatching.HatchLine(origin: Vec2, direction: Vec2, distance: float)
Represents a single hatch line.
Parameters
• origin – the origin of the hatch line as Vec2 instance
• direction – the hatch line direction as Vec2 instance, must not (0, 0)
• distance – the normal distance to the base hatch line as float
intersect_line(a: Vec2, b: Vec2, dist_a: float, dist_b: float) -> Intersection
Returns the Intersection of this hatch line and the line defined by the points a and b.
The arguments dist_a and dist_b are the signed normal distances of the points a and b from
the hatch baseline. The normal distances from the baseline are easy to calculate by the
HatchBaseLine.signed_distance() method and allow a fast intersection calculation by a
simple point interpolation.
Parameters
• a – start point of the line as Vec2 instance
• b – end point of the line as Vec2 instance
• dist_a – normal distance of point a to the hatch baseline as float
• dist_b – normal distance of point b to the hatch baseline as float
intersect_cubic_bezier_curve(curve: Bezier4P) -> Sequence[Intersection]
Returns 0 to 3 Intersection points of this hatch line with a cubic Bèzier curve.
Parameters
curve – the cubic Bèzier curve as ezdxf.math.Bezier4P instance
class ezdxf.render.hatching.PatternRenderer(hatch_line: HatchLine, pattern: Sequence[float])
The hatch pattern of a DXF entity has one or more HatchBaseLine instances with an origin,
direction, offset and line pattern. The PatternRenderer for a certain distance from the baseline
has to be acquired from the HatchBaseLine by the pattern_renderer() method.
The origin of the hatch line is the starting point of the line pattern. The offset defines the
origin of the adjacent hatch line and doesn’t have to be orthogonal to the hatch line direction.
Line Pattern
The line pattern is a sequence of floats, where a value > 0.0 is a dash, a value < 0.0 is a gap
and value of 0.0 is a point.
Parameters
• hatch_line – HatchLine
• pattern – the line pattern as sequence of float values
render(start: Vec2, end: Vec2) -> Iterator[tuple[Vec2, Vec2]]
Yields the pattern lines as pairs of Vec2 instances from the start- to the end point on the
hatch line. For points the start- and end point are the same Vec2 instance and can be
tested by the is operator.
The start- and end points should be located collinear at the hatch line of this instance,
otherwise the points a projected onto this hatch line.
class ezdxf.render.hatching.Intersection(type: IntersectionType = IntersectionType.NONE, p0: Vec2 =
Vec2(nan, nan), p1: Vec2 = Vec2(nan, nan))
Represents an intersection.
type intersection type as IntersectionType instance
p0 (first) intersection point as Vec2 instance
p1 second intersection point as Vec2 instance, only if type is COLLINEAR
class ezdxf.render.hatching.IntersectionType(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
NONE no intersection
REGULAR
regular intersection point at a polygon edge or a Bèzier curve
START intersection point at the start vertex of a polygon edge
END intersection point at the end vertex of a polygon edge
COLLINEAR
intersection is collinear to a polygon edge
class ezdxf.render.hatching.Line(start: 'Vec2', end: 'Vec2', distance: 'float')
start start point as Vec2 instance
end end point as Vec2 instance
distance
signed normal distance to the HatchBaseLine
Helper Functions
ezdxf.render.hatching.hatch_boundary_paths(polygon: DXFPolygon, filter_text_boxes=True) -> list[Path]
Returns the hatch boundary paths as ezdxf.path.Path instances of HATCH and MPOLYGON entities.
Ignores text boxes if argument filter_text_boxes is True.
ezdxf.render.hatching.hatch_line_distances(point_distances: Sequence[float], normal_distance: float) ->
list[float]
Returns all hatch line distances in the range of the given point distances.
ezdxf.render.hatching.pattern_baselines(polygon: DXFPolygon, min_hatch_line_distance: float =
MIN_HATCH_LINE_DISTANCE, *, jiggle_origin: bool = False) -> Iterator[HatchBaseLine]
Yields the hatch pattern baselines of HATCH and MPOLYGON entities as HatchBaseLine instances. Set
jiggle_origin to True to move pattern line origins a small amount to avoid intersections in corner
points which causes errors in patterns.
Exceptions
class ezdxf.render.hatching.HatchingError
Base exception class of the hatching module.
class ezdxf.render.hatching.HatchLineDirectionError
Hatching direction is undefined or a (0, 0) vector.
class ezdxf.render.hatching.DenseHatchingLinesError
Very small hatching distance which creates too many hatching lines.
ADD-ONS
Drawing / Export Add-on
This add-on provides the functionality to render a DXF document to produce a rasterized or vector-graphic
image which can be saved to a file or viewed interactively depending on the backend being used.
The module provides two example scripts in the folder examples/addons/drawing which can be run to save
rendered images to files or view an interactive visualisation.
$ ./draw_cad.py --supported_formats
# will list the file formats supported by the matplotlib backend.
# Many formats are supported including vector graphics formats
# such as pdf and svg
$ ./draw_cad.py <my_file.dxf> --out image.png
# draw a layout other than the model space
$ ./draw_cad.py <my_file.dxf> --layout Layout1 --out image.png
# opens a GUI application to view CAD files
$ ./cad_viewer.py
SEE ALSO:
How-to section for the FAQ about the Drawing Add-on.
Design
The implementation of the drawing add-on is divided into a frontend and multiple backends. The frontend
handles the translation of DXF features and properties into simplified structures, which are then
processed by the backends.
Common Limitations to all Backends
• rich text formatting of the MTEXT entity is close to AutoCAD but not pixel perfect
• relative size of POINT entities cannot be replicated exactly
• rendering of ACIS entities is not supported
• no 3D rendering engine, therefore:
• 3D entities are projected into the xy-plane and 3D text is not supported
• only top view rendering of the modelspace
• VIEWPORTS are always rendered as top view
• no visual style support
• only basic support for:
• infinite lines (rendered as lines with a finite length)
• OLE2FRAME entities (rendered as rectangles)
• vertical text (will render as horizontal text)
• rendering of additional MTEXT columns may be incorrect
MatplotlibBackend
The MatplotlibBackend is used by the Draw command of the ezdxf launcher.
Example for the usage of the Matplotlib backend:
import sys
import matplotlib.pyplot as plt
from ezdxf import recover
from ezdxf.addons.drawing import RenderContext, Frontend
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
# Safe loading procedure (requires ezdxf v0.14):
try:
doc, auditor = recover.readfile('your.dxf')
except IOError:
print(f'Not a DXF file or a generic I/O error.')
sys.exit(1)
except ezdxf.DXFStructureError:
print(f'Invalid or corrupted DXF file.')
sys.exit(2)
# The auditor.errors attribute stores severe errors,
# which may raise exceptions when rendering.
if not auditor.has_errors:
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ctx = RenderContext(doc)
out = MatplotlibBackend(ax)
Frontend(ctx, out).draw_layout(doc.modelspace(), finalize=True)
fig.savefig('your.png', dpi=300)
Simplified render workflow but with less control:
from ezdxf import recover
from ezdxf.addons.drawing import matplotlib
# Exception handling left out for compactness:
doc, auditor = recover.readfile('your.dxf')
if not auditor.has_errors:
matplotlib.qsave(doc.modelspace(), 'your.png')
PyQtBackend
class ezdxf.addons.drawing.pyqt.PyQtBackend(scene=None)
Backend which uses the PySide6 package to implement an interactive viewer. The PyQt5 package can
be used as fallback if the PySide6 package is not available.
Parameters
scene -- drawing canvas of type QtWidgets.QGraphicsScene, if None a new canvas will be
created
The PyQtBackend is used by the View command of the ezdxf launcher.
SEE ALSO:
The qtviewer.py module implements the core of a simple DXF viewer and the cad_viewer.py example is a
skeleton to show how to launch the CADViewer class.
Recorder
New in version 1.1.
This is a special backend which records the output of the Frontend class in compact numpy arrays and
these recordings and can be played by a Player instance on one or more backends. The recorded numpy
arrays support measurement of bounding boxes and transformations which is for some backends a requirement
to place the DXF content on size limited pages.
class ezdxf.addons.drawing.recorder.Recorder
Records the output of the Frontend class.
The class implements the BackendInterface but does not record enter_entity(), exit_entity() and
clear() events.
player() -> Player
Returns a Player instance with the original recordings! Make a copy of this player to
protect the original recordings from being modified:
safe_player = recorder.player().copy()
class ezdxf.addons.drawing.recorder.Player
Plays the recordings of the Recorder backend on another backend.
bbox() -> BoundingBox2d
Returns the bounding box of all records as BoundingBox2d.
copy() -> Self
Returns a copy of the player with non-shared recordings.
crop_rect(p1: UVec, p2: UVec, distance: float) -> None
Crop recorded shapes inplace by a rectangle defined by two points.
The argument distance defines the approximation precision for paths which have to be
approximated as polylines for cropping but only paths which are really get cropped are
approximated, paths that are fully inside the crop box will not be approximated.
Parameters
• p1 -- first corner of the clipping rectangle
• p2 -- second corner of the clipping rectangle
• distance -- maximum distance from the center of the curve to the center of the
line segment between two approximation points to determine if a segment should be
subdivided.
recordings() -> Iterator[tuple[RecordType, BackendProperties, Any]]
Yields all recordings as (RecordType, BackendProperties, Data) tuples.
The content of the Data field is determined by the enum RecordType:
• RecordType.POINTS returns a NumpyPoints2d instance, len() == 1 is a point, len() == 2 is
a line, len() > 2 is a filled polygon
• RecordType.SOLID_LINES returns a NumpyPoints2d instance where each pair (n, n+1)
represents the start- and end point of a line
• RecordType.PATH: returns a NumpyPath2d instance that represents a linear 2D path
• RecordType.FILLED_PATHS returns a tuple (exterior_paths, holes), where exterior_paths and
holes are tuples of NumpyPath2d.
replay(backend: BackendInterface, override: Callable[[BackendProperties], Override] | None = None)
-> None
Replay the recording on another backend that implements the BackendInterface. The optional
override function can be used to override the properties and state of data records, it gets
the BackendProperties as input and must return an Override instance.
transform(m: Matrix44) -> None
Transforms the recordings inplace by a transformation matrix m of type Matrix44.
class ezdxf.addons.drawing.recorder.Override(properties: BackendProperties, is_visible: bool = True)
Represents the override state for a data record.
properties
original or modified BackendProperties
Type ezdxf.addons.drawing.properties.BackendProperties
is_visible
override visibility e.g. switch layers on/off
Type bool
class ezdxf.addons.drawing.recorder.RecordType(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
Enum, determines the data record type.
POINTS
SOLID_LINES
PATH
FILLED_PATHS
Layout
New in version 1.1.
The Layout class builds the page layout and the matrix to transform the DXF content to page coordinates
according to the layout Settings. The DXF coordinate transformation is required for PDF and HPGL/2 which
expects the output coordinates in the first quadrant and SVG which has an inverted y-axis.
The Layout class uses following classes and enums for configuration:
• Page - page definition
• Margins - page margins definition
• Settings - configuration settings
• Units - enum for page units
class ezdxf.addons.drawing.layout.Page(width: float, height: float, units: Units = Units.mm, margins:
Margins = (0, 0, 0, 0), max_width: float = 0.0, max_height: float = 0.0)
Page definition class
width page width, 0 for auto-detect
Type float
height page height, 0 for auto-detect
Type float
units page units as enum Units
Type ezdxf.addons.drawing.layout.Units
margins
page margins in page units
Type ezdxf.addons.drawing.layout.Margins
max_width
limit width for auto-detection, 0 for unlimited
Type float
max_height
limit height for auto-detection, 0 for unlimited
Type float
property is_landscape: bool
Returns True if the page has landscape orientation.
property is_portrait: bool
Returns True if the page has portrait orientation. (square is portrait)
to_landscape() -> None
Converts the page to landscape orientation.
to_portrait() -> None
Converts the page to portrait orientation.
class ezdxf.addons.drawing.layout.Margins(top: float, right: float, bottom: float, left: float)
Page margins definition class
top
Type float
left
Type float
bottom
Type float
right
Type float
classmethod all(margin: float) -> Self
Returns a page margins definition class with four equal margins.
classmethod all2(top_bottom: float, left_right: float) -> Self
Returns a page margins definition class with equal top-bottom and left-right margins.
scale(factor: float) -> Self
class ezdxf.addons.drawing.layout.PageAlignment(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
Page alignment of content as enum.
TOP_LEFT
TOP_CENTER
TOP_RIGHT
MIDDLE_LEFT
MIDDLE_CENTER
MIDDLE_RIGHT
BOTTOM_LEFT
BOTTOM_CENTER
BOTTOM_RIGHT
class ezdxf.addons.drawing.layout.Settings(content_rotation: int = 0, fit_page: bool = True, scale: float
= 1.0, page_alignment: PageAlignment = PageAlignment.MIDDLE_CENTER, crop_at_margins: bool = False,
max_stroke_width: float = 0.001, min_stroke_width: float = 0.05, fixed_stroke_width: float = 0.15,
output_coordinate_space: float = 1000000)
The Layout settings.
content_rotation
Rotate content about 0, 90, 180 or 270 degrees
Type int
fit_page
Scale content to fit the page.
Type bool
page_alignment
Supported by backends that use the Page class to define the size of the output media,
default alignment is PageAlignment.MIDDLE_CENTER
Type ezdxf.addons.drawing.layout.PageAlignment
crop_at_margins
crops the content at the page margins if True, when supported by the backend, default is
False
Type bool
scale Factor to scale the DXF units of model- or paperspace, to represent 1mm in the rendered
output drawing. Only uniform scaling is supported.
e.g. scale 1:100 and DXF units are meters, 1m = 1000mm corresponds 10mm in the output
drawing = 10 / 1000 = 0.01;
e.g. scale 1:1; DXF units are mm = 1 / 1 = 1.0 the default value
The value is ignored if the page size is defined and the content fits the page and the
value is also used to determine missing page sizes (width or height).
Type float
max_stroke_width
Used for LineweightPolicy.RELATIVE policy, max_stroke_width is defined as percentage of the
content extents, e.g. 0.001 is 0.1% of max(page-width, page-height)
Type float
min_stroke_width
Used for LineweightPolicy.RELATIVE policy, min_stroke_width is defined as percentage of
max_stroke_width, e.g. 0.05 is 5% of max_stroke_width
Type float
fixed_stroke_width
Used for LineweightPolicy.RELATIVE_FIXED policy, fixed_stroke_width is defined as
percentage of max_stroke_width, e.g. 0.15 is 15% of max_stroke_width
Type float
output_coordinate_space
expert feature to map the DXF coordinates to the output coordinate system [0,
output_coordinate_space]
Type float
class ezdxf.addons.drawing.layout.Units(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
Page units as enum.
inch 25.4 mm
px 1/96 inch
pt 1/72 inch
mm
cm
SVGBackend
New in version 1.1.
class ezdxf.addons.drawing.svg.SVGBackend
This is a native SVG rendering backend and does not require any external packages to render SVG
images other than the core dependencies. This backend support content cropping at page margins.
get_xml_root_element(page: Page, *, settings: Settings = layout.Settings(), render_box:
BoundingBox2d | None = None) -> Element
get_string(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d | None
= None, xml_declaration=True) -> str
Returns the XML data as unicode string.
Parameters
• page -- page definition, see Page
• settings -- layout settings, see Settings
• render_box -- set explicit region to render, default is content bounding box
• xml_declaration -- inserts the "<?xml version='1.0' encoding='utf-8'?>" string in
front of the <svg> element
Usage:
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, svg
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
backend = svg.SVGBackend()
Frontend(RenderContext(doc), backend).draw_layout(msp)
with open("your.svg", "wt") as fp:
fp.write(backend.get_string(layout.Page(0, 0))
PyMuPdfBackend
New in version 1.1.
class ezdxf.addons.drawing.pymupdf.PyMuPdfBackend
This backend uses the PyMuPdf package to create PDF, PNG, PPM and PBM output. This backend
support content cropping at page margins.
PyMuPDF is licensed under the AGPL. Sorry, but it's the best package for the job I've found so
far.
Install package:
pip install pymupdf
get_pdf_bytes(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d |
None = None) -> bytes
Returns the PDF document as bytes.
Parameters
• page -- page definition, see Page
• settings -- layout settings, see Settings
• render_box -- set explicit region to render, default is content bounding box
get_pixmap_bytes(page: Page, *, fmt='png', settings: Settings = layout.Settings(), dpi: int = 96,
alpha=False, render_box: BoundingBox2d | None = None) -> bytes
Returns a pixel image as bytes, supported image formats:
┌─────┬────────────────────────────────────┐
│ png │ Portable Network Graphics │
├─────┼────────────────────────────────────┤
│ ppm │ Portable Pixmap (no alpha channel) │
├─────┼────────────────────────────────────┤
│ pbm │ Portable Bitmap (no alpha channel) │
└─────┴────────────────────────────────────┘
Parameters
• page -- page definition, see Page
• fmt -- image format
• settings -- layout settings, see Settings
• dpi -- output resolution in dots per inch
• alpha -- add alpha channel (transparency)
• render_box -- set explicit region to render, default is content bounding box
Usage:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, pymupdf
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
backend = pymupdf.PyMuPdfBackend()
Frontend(RenderContext(doc), backend).draw_layout(msp)
with open("your.pdf", "wb") as fp:
fp.write(backend.get_pdf_bytes(layout.Page(0, 0))
Load the output of the PyMuPdfBackend into the Image class of the Pillow package for further processing
or to output additional image formats:
import io
from PIL import Image
... # see above
# the ppm format is faster to process than png
fp = io.BytesIO(backend.get_pixmap_bytes(layout.Page(0, 0), fmt="ppm", dpi=300))
image = Image.open(fp, formats=["ppm"])
PlotterBackend
New in version 1.1.
class ezdxf.addons.drawing.hpgl2.PlotterBackend
The PlotterBackend creates HPGL/2 plot files for output on raster plotters. This backend does not
need any additional packages. This backend support content cropping at page margins.
The plot files are tested by the plot file viewer ViewCompanion Standard but not on real hardware
- please use with care and give feedback.
get_bytes(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d | None
= None, curves=True, decimal_places: int = 1, base=64) -> bytes
Returns the HPGL/2 data as bytes.
Parameters
• page -- page definition, see Page
• settings -- layout settings, see Settings
• render_box -- set explicit region to render, default is content bounding box
• curves -- use Bèzier curves for HPGL/2 output
• decimal_places -- HPGL/2 output precision, less decimal places creates smaller
files but for the price of imprecise curves (text)
• base -- base for polyline encoding, 32 for 7 bit encoding or 64 for 8 bit encoding
compatible(page: Page, settings: Settings = layout.Settings()) -> bytes
Returns the HPGL/2 data as 7-bit encoded bytes curves as approximated polylines and
coordinates are rounded to integer values. Has often the smallest file size and should be
compatible to all output devices but has a low quality text rendering.
low_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier curves and coordinates are
rounded to integer values. Has a smaller file size than normal quality and the output
device must support 8-bit encoding and Bèzier curves.
normal_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier curves and coordinates are
floats rounded to one decimal place. Has a smaller file size than high quality and the
output device must support 8-bit encoding, Bèzier curves and fractional coordinates.
high_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
Returns the HPGL/2 data as 8-bit encoded bytes and all curves as Bézier curves and
coordinates are floats rounded to two decimal places. Has the largest file size and the
output device must support 8-bit encoding, Bèzier curves and fractional coordinates.
Usage:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, hpgl2
doc = ezdxf.readfile("your.dxf")
psp = doc.paperspace("Layout1")
backend = hpgl2.PlotterBackend()
Frontend(RenderContext(doc), backend).draw_layout(psp)
page = layout.Page.from_dxf_layout(psp)
with open("your.plt", "wb") as fp:
fp.write(backend.normal_quality(page)
You can check the output by the HPGL/2 viewer:
ezdxf hpgl your.plt
DXFBackend
New in version 1.1.
class ezdxf.addons.drawing.dxf.DXFBackend(layout: BaseLayout, color_mode: ColorMode = ColorMode.RGB)
The DXFBackend creates simple DXF files of POINT, LINE, LWPOLYLINE and HATCH entities. This
backend does ot need any additional packages.
Parameters
• layout -- a DXF BaseLayout
• color_mode -- see ColorMode
class ezdxf.addons.drawing.dxf.ColorMode(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
This enum is used to define the color output mode of the DXFBackend.
ACI the color is set as AutoCAD Color Index (ACI) and assigned by layer
RGB the color is set as RGB true color value
Render a paperspace layout into modelspace:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, dxf
doc = ezdxf.readfile("your.dxf")
layout1 = doc.paperspace("Layout1")
output_doc = ezdxf.new()
output_msp = output_doc.modelspace()
backend = dxf.DXFBackend(output_msp)
Frontend(RenderContext(doc), backend).draw_layout(layout1)
output_doc.saveas("layout1_in_modelspace.dxf")
Configuration
Additional options for the drawing add-on can be passed by the config argument of the Frontend
constructor __init__(). Not every option will be supported by all backends.
Usage:
my_config = Configuration(lineweight_scaling=2)
class ezdxf.addons.drawing.config.Configuration(pdsize: int | None = None, pdmode: int | None = None,
measurement: Measurement | None = None, show_defpoints: bool = False, proxy_graphic_policy:
ProxyGraphicPolicy = ProxyGraphicPolicy.SHOW, line_policy: LinePolicy = LinePolicy.ACCURATE,
hatch_policy: HatchPolicy = HatchPolicy.NORMAL, infinite_line_length: float = 20, lineweight_scaling:
float = 1.0, min_lineweight: float | None = None, min_dash_length: float = 0.1, max_flattening_distance:
float = 0.01, circle_approximation_count: int = 128, hatching_timeout: float = 30.0,
min_hatch_line_distance: float = 0.0001, color_policy: ColorPolicy = ColorPolicy.COLOR, custom_fg_color:
str = '#000000', background_policy: BackgroundPolicy = BackgroundPolicy.DEFAULT, custom_bg_color: str =
'#ffffff', lineweight_policy: LineweightPolicy = LineweightPolicy.ABSOLUTE, text_policy: TextPolicy =
TextPolicy.FILLING)
Configuration options for the drawing add-on.
pdsize the size to draw POINT entities (in drawing units) set to None to use the $PDSIZE value
from the dxf document header
┌──────┬───────────────────────────────────────┐
│ 0 │ 5% of draw area height │
├──────┼───────────────────────────────────────┤
│ <0 │ Specifies a percentage of the │
│ │ viewport size │
├──────┼───────────────────────────────────────┤
│ >0 │ Specifies an absolute size │
├──────┼───────────────────────────────────────┤
│ None │ use the $PDMODE value from the dxf │
│ │ document header │
└──────┴───────────────────────────────────────┘
Type int | None
pdmode point styling mode (see POINT documentation)
see Point class documentation
Type int | None
measurement
whether to use metric or imperial units as enum ezdxf.enums.Measurement
┌──────┬───────────────────────────────────────┐
│ 0 │ use imperial units (in, ft, yd, ...) │
├──────┼───────────────────────────────────────┤
│ 1 │ use metric units (ISO meters) │
├──────┼───────────────────────────────────────┤
│ None │ use the $MEASUREMENT value from the │
│ │ dxf document header │
└──────┴───────────────────────────────────────┘
Type ezdxf.enums.Measurement | None
show_defpoints
whether to show or filter out POINT entities on the defpoints layer
Type bool
proxy_graphic_policy
the action to take when a proxy graphic is encountered
Type ezdxf.addons.drawing.config.ProxyGraphicPolicy
line_policy
the method to use when drawing styled lines (eg dashed, dotted etc)
Type ezdxf.addons.drawing.config.LinePolicy
hatch_policy
the method to use when drawing HATCH entities
Type ezdxf.addons.drawing.config.HatchPolicy
infinite_line_length
the length to use when drawing infinite lines
Type float
lineweight_scaling
multiplies every lineweight by this factor; set this factor to 0.0 for a constant minimum
line width defined by the min_lineweight setting for all lineweights; the correct DXF
lineweight often looks too thick in SVG, so setting a factor < 1 can improve the visual
appearance
Type float
min_lineweight
the minimum line width in 1/300 inch; set to None for let the backend choose.
Type float | None
min_dash_length
the minimum length for a dash when drawing a styled line (default value is arbitrary)
Type float
max_flattening_distance
Max flattening distance in drawing units see Path.flattening documentation. The backend
implementation should calculate an appropriate value, like 1 screen- or paper pixel on the
output medium, but converted into drawing units. Sets Path() approximation accuracy
Type float
circle_approximation_count
Approximate a full circle by n segments, arcs have proportional less segments. Only used
for approximation of arcs in banded polylines.
Type int
hatching_timeout
hatching timeout for a single entity, very dense hatching patterns can cause a very long
execution time, the default timeout for a single entity is 30 seconds.
Type float
min_hatch_line_distance
minimum hatch line distance to render, narrower pattern lines are rendered as solid filling
Type float
color_policy
Type ezdxf.addons.drawing.config.ColorPolicy
custom_fg_color
Used for ColorPolicy.custom policy, custom foreground color as "#RRGGBBAA" color string
(RGB+alpha)
Type str
background_policy
Type ezdxf.addons.drawing.config.BackgroundPolicy
custom_bg_color
Used for BackgroundPolicy.custom policy, custom background color as "#RRGGBBAA" color
string (RGB+alpha)
Type str
lineweight_policy
Type ezdxf.addons.drawing.config.LineweightPolicy
text_policy
Type ezdxf.addons.drawing.config.TextPolicy
with_changes()
Returns a new frozen Configuration object with modified values.
BackgroundPolicy
class ezdxf.addons.drawing.config.BackgroundPolicy(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
This enum is used to define the background color.
DEFAULT
as resolved by the Frontend class
WHITE white background
BLACK black background
OFF fully transparent background
CUSTOM custom background color by Configuration.custom_bg_color
ColorPolicy
class ezdxf.addons.drawing.config.ColorPolicy(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
This enum is used to define how to determine the line/fill color.
COLOR as resolved by the Frontend class
COLOR_SWAP_BW
as resolved by the Frontend class but swaps black and white
COLOR_NEGATIVE
invert all colors
MONOCHROME
maps all colors to gray scale in range [0%, 100%]
MONOCHROME_DARK_BG
maps all colors to gray scale in range [30%, 100%], brightens colors for dark backgrounds
MONOCHROME_LIGHT_BG
maps all colors to gray scale in range [0%, 70%], darkens colors for light backgrounds
BLACK maps all colors to black
WHITE maps all colors to white
CUSTOM maps all colors to custom color Configuration.custom_fg_color
HatchPolicy
class ezdxf.addons.drawing.config.HatchPolicy(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
The action to take when a HATCH entity is encountered
NORMAL render pattern and solid fillings
IGNORE do not show HATCH entities at all
SHOW_OUTLINE
show only the outline of HATCH entities
SHOW_SOLID
show HATCH entities as solid filling regardless of the pattern
LinePolicy
class ezdxf.addons.drawing.config.LinePolicy(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
SOLID draw all lines as solid regardless of the linetype style
ACCURATE
render styled lines as accurately as possible
LineweightPolicy
class ezdxf.addons.drawing.config.LineweightPolicy(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
This enum is used to define how to determine the lineweight.
ABSOLUTE
in mm as resolved by the Frontend class
RELATIVE
lineweight is relative to page size
RELATIVE_FIXED
fixed lineweight relative to page size for all strokes
ProxyGraphicPolicy
class ezdxf.addons.drawing.config.ProxyGraphicPolicy(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
The action to take when an entity with a proxy graphic is encountered
NOTE:
To get proxy graphics support proxy graphics have to be loaded: Set the global option
ezdxf.options.load_proxy_graphics to True, which is the default value.
This can not prevent drawing proxy graphic inside of blocks, because this is beyond the domain
of the drawing add-on!
IGNORE do not display proxy graphics (skip_entity will be called instead)
SHOW if the entity cannot be rendered directly (e.g. if not implemented) but a proxy is present:
display the proxy
PREFER display proxy graphics even for entities where direct rendering is available
TextPolicy
class ezdxf.addons.drawing.config.TextPolicy(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
This enum is used to define the text rendering.
FILLING
text is rendered as solid filling (default)
OUTLINE
text is rendered as outline paths
REPLACE_RECT
replace text by a rectangle
REPLACE_FILL
replace text by a filled rectangle
IGNORE ignore text at all
Properties
class ezdxf.addons.drawing.properties.Properties
An implementation agnostic representation of DXF entity properties like color and linetype. These
properties represent the actual values after resolving all DXF specific rules like "by layer", "by
block" and so on.
color The actual color value of the DXF entity as "#RRGGBB" or "#RRGGBBAA" string. An alpha value
of "00" is opaque and "ff" is fully transparent.
rgb RGB values extract from the color value as tuple of integers.
luminance
Perceived luminance calculated from the color value as float in the range [0.0, 1.0].
linetype_name
The actual linetype name as string like "CONTINUOUS"
linetype_pattern
The simplified DXF linetype pattern as tuple of floats, all line elements and gaps are
values greater than 0.0 and 0.0 represents a point. Line or point elements do always
alternate with gap elements: line-gap-line-gap-point-gap and the pattern always ends with a
gap. The continuous line is an empty tuple.
linetype_scale
The scaling factor as float to apply to the linetype_pattern.
lineweight
The absolute lineweight to render in mm as float.
is_visible
Visibility flag as bool.
layer The actual layer name the entity resides on as UPPERCASE string.
font The FontFace used for text rendering or None.
filling
The actual Filling properties of the entity or None.
units The actual drawing units as InsertUnits enum.
LayerProperties
class ezdxf.addons.drawing.properties.LayerProperties
Actual layer properties, inherits from class Properties.
is_visible
Modified meaning: whether entities belonging to this layer should be drawn
layer Modified meaning: stores real layer name (mixed case)
LayoutProperties
class ezdxf.addons.drawing.properties.LayoutProperties
Actual layout properties.
name Layout name as string
units Layout units as InsertUnits enum.
property LayoutProperties.background_color: str
Returns the default layout background color.
property LayoutProperties.default_color: str
Returns the default layout foreground color.
property LayoutProperties.has_dark_background: bool
Returns True if the actual background-color is "dark".
LayoutProperties.set_colors(bg: str, fg: str | None = None) -> None
Setup default layout colors.
Required color format "#RRGGBB" or including alpha transparency "#RRGGBBAA".
RenderContext
class ezdxf.addons.drawing.properties.RenderContext(doc: Drawing | None = None, *, ctb: str = '',
export_mode: bool = False)
The render context for the given DXF document. The RenderContext resolves the properties of DXF
entities from the context they reside in to actual values like RGB colors, transparency, linewidth
and so on.
A given ctb file (plot style file) overrides the default properties for all layouts, which means
the plot style table stored in the layout is always ignored.
Parameters
• doc -- DXF document
• ctb -- path to a plot style table
• export_mode -- Whether to render the document as it would look when exported (plotted) by
a CAD application to a file such as pdf, or whether to render the document as it would
appear inside a CAD application.
resolve_aci_color(aci: int, resolved_layer: str) -> str
Resolve the aci color as hex color string: "#RRGGBB"
resolve_all(entity: DXFGraphic) -> Properties
Resolve all properties of entity.
resolve_color(entity: DXFGraphic, *, resolved_layer: str | None = None) -> str
Resolve the rgb-color of entity as hex color string: "#RRGGBB" or "#RRGGBBAA".
resolve_filling(entity: DXFGraphic) -> Filling | None
Resolve filling properties (SOLID, GRADIENT, PATTERN) of entity.
resolve_font(entity: DXFGraphic) -> FontFace | None
Resolve the text style of entity to a font name. Returns None for the default font.
resolve_layer(entity: DXFGraphic) -> str
Resolve the layer of entity, this is only relevant for entities inside of block references.
resolve_layer_properties(layer: Layer) -> LayerProperties
Resolve layer properties.
resolve_linetype(entity: DXFGraphic, *, resolved_layer: str | None = None) -> tuple[str,
Sequence[float]]
Resolve the linetype of entity. Returns a tuple of the linetype name as upper-case string
and the simplified linetype pattern as tuple of floats.
resolve_lineweight(entity: DXFGraphic, *, resolved_layer: str | None = None) -> float
Resolve the lineweight of entity in mm.
DXF stores the lineweight in mm times 100 (e.g. 0.13mm = 13). The smallest line weight is
0 and the biggest line weight is 211. The DXF/DWG format is limited to a fixed value
table, see: ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS
CAD applications draw lineweight 0mm as an undefined small value, to prevent backends to
draw nothing for lineweight 0mm the smallest return value is 0.01mm.
resolve_units() -> InsertUnits
resolve_visible(entity: DXFGraphic, *, resolved_layer: str | None = None) -> bool
Resolve the visibility state of entity. Returns True if entity is visible.
set_current_layout(layout: Layout, ctb: str = '')
Set the current layout and update layout specific properties.
set_layer_properties_override(func: Callable[[Sequence[LayerProperties]], None] | None = None)
The function func is called with the current layer properties as argument after resetting
them, so the function can override the layer properties.
The RenderContext class can be used isolated from the drawing add-on to resolve DXF properties.
Frontend
class ezdxf.addons.drawing.frontend.Frontend(ctx: RenderContext, out: BackendInterface, config:
Configuration = Configuration.defaults(), bbox_cache: ezdxf.bbox.Cache = None)
Drawing frontend for 2D backends, responsible for decomposing entities into graphic primitives and
resolving entity properties.
By passing the bounding box cache of the modelspace entities can speed up paperspace rendering,
because the frontend can filter entities which are not visible in the VIEWPORT. Even passing in an
empty cache can speed up rendering time when multiple viewports need to be processed.
Parameters
• ctx -- the properties relevant to rendering derived from a DXF document
• out -- the 2D backend to draw to
• config -- settings to configure the drawing frontend and backend
• bbox_cache -- bounding box cache of the modelspace entities or an empty cache which will
be filled dynamically when rendering multiple viewports or None to disable bounding box
caching at all
log_message(message: str)
Log given message - override to alter behavior.
skip_entity(entity: DXFEntity, msg: str) -> None
Called for skipped entities - override to alter behavior.
override_properties(entity: DXFGraphic, properties: Properties) -> None
The override_properties() filter can change the properties of an entity independent of the
DXF attributes.
This filter has access to the DXF attributes by the entity object, the current render
context, and the resolved properties by the properties object. It is recommended to modify
only the properties object in this filter.
draw_layout(layout: Layout, finalize: bool = True, *, filter_func: Callable[[DXFGraphic], bool] |
None = None, layout_properties: LayoutProperties | None = None) -> None
Draw all entities of the given layout.
Draws the entities of the layout in the default or redefined redraw-order and calls the
finalize() method of the backend if requested. The default redraw order is the ascending
handle order not the order the entities are stored in the layout.
The method skips invisible entities and entities for which the given filter function
returns False.
Parameters
• layout -- layout to draw of type Layout
• finalize -- True if the finalize() method of the backend should be called
automatically
• filter_func -- function to filter DXf entities, the function should return False
if a given entity should be ignored
• layout_properties -- override the default layout properties
BackendInterface
class ezdxf.addons.drawing.backend.BackendInterface
Public interface definition for 2D rendering backends.
For more information read the source code: backend.py
Backend
class ezdxf.addons.drawing.backend.Backend
Abstract base class for concrete backend implementations and implements some default features.
For more information read the source code: backend.py
Details
The rendering is performed in two stages. The frontend traverses the DXF document structure, converting
each encountered entity into primitive drawing commands. These commands are fed to a backend which
implements the interface: Backend.
Although the resulting images will not be pixel-perfect with AutoCAD (which was taken as the ground truth
when developing this add-on) great care has been taken to achieve similar behavior in some areas:
• The algorithm for determining color should match AutoCAD. However, the color palette is not stored in
the DXF file, so the chosen colors may be different to what is expected. The RenderContext class
supports passing a plot style table (CTB-file) as custom color palette but uses the same palette as
AutoCAD by default.
• Text rendering is quite accurate, text positioning, alignment and word wrapping are very faithful.
Differences may occur if a different font from what was used by the CAD application but even in that
case, for supported backends, measurements are taken of the font being used to match text as closely as
possible.
• Visibility determination (based on which layers are visible) should match AutoCAD
SEE ALSO:
• draw_cad.py for a simple use of this module
• cad_viewer.py for an advanced use of this module
• Notes on Rendering DXF Content for additional behaviours documented during the development of this
add-on.
Geo Interface
Intended Usage
The intended usage of the ezdxf.addons.geo module is as tool to work with geospatial data in conjunction
with dedicated geospatial applications and libraries and the module can not and should not replicate
their functionality.
The only reimplemented feature is the most common WSG84 EPSG:3395 World Mercator projection, for
everything else use the dedicated packages like:
• pyproj - Cartographic projections and coordinate transformations library.
• Shapely - Manipulation and analysis of geometric objects in the Cartesian plane.
• PyShp - The Python Shapefile Library (PyShp) reads and writes ESRI Shapefiles in pure Python.
• GeoJSON - GeoJSON interface for Python.
• GDAL - Tools for programming and manipulating the GDAL Geospatial Data Abstraction Library.
• Fiona - Fiona is GDAL’s neat and nimble vector API for Python programmers.
• QGIS - A free and open source geographic information system.
• and many more …
This module provides support for the __geo_interface__: https://gist.github.com/sgillies/2217756
Which is also supported by Shapely, for supported types see the GeoJSON Standard and examples in
Appendix-A.
SEE ALSO:
Tutorial for the Geo Add-on for loading GPX data into DXF files with an existing geo location
reference and exporting DXF entities as GeoJSON data.
Proxy From Mapping
The GeoProxy represents a __geo_interface__ mapping, create a new proxy by GeoProxy.parse() from an
external __geo_interface__ mapping. GeoProxy.to_dxf_entities() returns new DXF entities from this
mapping. Returns “Point” as Point entity, “LineString” as LWPolyline entity and “Polygon” as Hatch
entity or as separated LWPolyline entities (or both) and new in v0.16.6 as MPolygon. Supports
“MultiPoint”, “MultiLineString”, “MultiPolygon”, “GeometryCollection”, “Feature” and
“FeatureCollection”. Add new DXF entities to a layout by the Layout.add_entity() method.
Proxy From DXF Entity
The proxy() function or the constructor GeoProxy.from_dxf_entities() creates a new GeoProxy object from a
single DXF entity or from an iterable of DXF entities, entities without a corresponding representation
will be approximated.
Supported DXF entities are:
• POINT as “Point”
• LINE as “LineString”
• LWPOLYLINE as “LineString” if open and “Polygon” if closed
• POLYLINE as “LineString” if open and “Polygon” if closed, supports only 2D and 3D polylines, POLYMESH
and POLYFACE are not supported
• SOLID, TRACE, 3DFACE as “Polygon”
• CIRCLE, ARC, ELLIPSE and SPLINE by approximation as “LineString” if open and “Polygon” if closed
• HATCH and MPOLYGON as “Polygon”, holes are supported
WARNING:
This module does no extensive validity checks for “Polygon” objects and because DXF has different
requirements for HATCH boundary paths than the GeoJSON Standard, it is possible to create invalid
“Polygon” objects. It is recommended to check critical objects by a sophisticated geometry library
like Shapely.
Module Functions
ezdxf.addons.geo.proxy(entity: DXFGraphic | Iterable[DXFGraphic], distance: float =
MAX_FLATTENING_DISTANCE, force_line_string: bool = False) -> GeoProxy
Returns a GeoProxy object.
Parameters
• entity – a single DXF entity or iterable of DXF entities
• distance – maximum flattening distance for curve approximations
• force_line_string – by default this function returns Polygon objects for closed
geometries like CIRCLE, SOLID, closed POLYLINE and so on, by setting argument
force_line_string to True, this entities will be returned as LineString objects.
ezdxf.addons.geo.dxf_entities(geo_mapping: MutableMapping[str, Any], polygon=PolygonConversion.HATCH,
dxfattribs=None, *, post_process: Callable[[DXFGraphic, MutableMapping[str, Any]], None] | None = None)
-> Iterator[DXFGraphic]
Returns __geo_interface__ mappings as DXF entities.
The enum polygon determines the method to convert polygons, use PolygonConversion.HATCH for Hatch
entity, PolygonConversion.POLYLINE for LWPolyline or PolygonConversion.HATCH_AND_POLYLINE for
both. Option PolygonConversion.POLYLINE returns for the exterior path and each hole a separated
LWPolyline entity. The Hatch entity supports holes, but has no explicit borderline.
Yields Hatch always before LWPolyline entities.
PolygonConversion.MPOLYGON support was added in v0.16.6, which is like a Hatch entity with
additional borderlines, but the MPOLYGON entity is not a core DXF entity and DXF viewers,
applications and libraries my not support this entity. The DXF attribute color defines the
borderline color and fill_color the color of the solid filling.
The returned DXF entities can be added to a layout by the Layout.add_entity() method.
Parameters
• geo_mapping – __geo__interface__ mapping as dict or a Python object with a
__geo__interface__ property
• polygon – see PolygonConversion
• dxfattribs – dict with additional DXF attributes
• post_process – post process function of type PostProcesFunc that get the created DXF
entity and the geo mapping as input, see reference implementation assign_layers()
ezdxf.addons.geo.gfilter(entities: Iterable[DXFGraphic]) -> Iterator[DXFGraphic]
Filter DXF entities from iterable entities, which are incompatible to the __geo_reference__
interface.
GeoProxy Class
class ezdxf.addons.geo.GeoProxy(geo_mapping: MutableMapping[str, Any], places: int = 6)
Stores the __geo_interface__ mapping in a parsed and compiled form.
Stores coordinates as Vec3 objects and represents “Polygon” always as tuple (exterior, holes) even
without holes.
The GeoJSON specification recommends 6 decimal places for latitude and longitude which equates to
roughly 10cm of precision. You may need slightly more for certain applications, 9 decimal places
would be sufficient for professional survey-grade GPS coordinates.
Parameters
• geo_mapping – parsed and compiled __geo_interface__ mapping
• places – decimal places to round for __geo_interface__ export
__geo_interface__
Returns the __geo_interface__ compatible mapping as dict.
geotype
Property returns the top level entity type or None.
classmethod parse(geo_mapping: MutableMapping[str, Any]) -> Self
Parse and compile a __geo_interface__ mapping as dict or a Python object with a
__geo_interface__ property, does some basic syntax checks, converts all coordinates into
Vec3 objects, represents “Polygon” always as tuple (exterior, holes) even without holes.
classmethod from_dxf_entities(entity: DXFGraphic | Iterable[DXFGraphic], distance: float =
MAX_FLATTENING_DISTANCE, force_line_string: bool = False) -> GeoProxy
Constructor from a single DXF entity or an iterable of DXF entities.
Parameters
• entity – DXF entity or entities
• distance – maximum flattening distance for curve approximations
• force_line_string – by default this function returns Polygon objects for closed
geometries like CIRCLE, SOLID, closed POLYLINE and so on, by setting argument
force_line_string to True, this entities will be returned as LineString objects.
to_dxf_entities(polygon=PolygonConversion.HATCH, dxfattribs=None, *, post_process:
Callable[[DXFGraphic, MutableMapping[str, Any]], None] | None = None) -> Iterator[DXFGraphic]
Returns stored __geo_interface__ mappings as DXF entities.
The polygon argument determines the method to convert polygons, use 1 for Hatch entity, 2
for LWPolyline or 3 for both. Option 2 returns for the exterior path and each hole a
separated LWPolyline entity. The Hatch entity supports holes, but has no explicit
borderline.
Yields Hatch always before LWPolyline entities.
MPolygon support was added in v0.16.6, which is like a Hatch entity with additional
borderlines, but the MPOLYGON entity is not a core DXF entity and DXF viewers, applications
and libraries my not support this entity. The DXF attribute color defines the borderline
color and fill_color the color of the solid filling.
The returned DXF entities can be added to a layout by the Layout.add_entity() method.
Parameters
• polygon – see PolygonConversion
• dxfattribs – dict with additional DXF attributes
• post_process – post process function of type PostProcesFunc that get the created
DXF entity and the geo mapping as input, see reference implementation
assign_layers()
copy() -> GeoProxy
Returns a deep copy.
__iter__() -> Iterator[MutableMapping[str, Any]]
Iterate over all geometry entities.
Yields only “Point”, “LineString”, “Polygon”, “MultiPoint”, “MultiLineString” and
“MultiPolygon” objects, returns the content of “GeometryCollection”, “FeatureCollection”
and “Feature” as geometry objects (“Point”, …).
wcs_to_crs(crs: Matrix44) -> None
Transform all coordinates recursive from WCS coordinates into Coordinate Reference System
(CRS) by transformation matrix crs inplace.
The CRS is defined by the GeoData entity, get the GeoData entity from the modelspace by
method get_geodata(). The CRS transformation matrix can be acquired form the GeoData
object by get_crs_transformation() method:
doc = ezdxf.readfile('file.dxf')
msp = doc.modelspace()
geodata = msp.get_geodata()
if geodata:
matrix, axis_ordering = geodata.get_crs_transformation()
If axis_ordering is False the CRS is not compatible with the __geo_interface__ or GeoJSON
(see chapter 3.1.1).
Parameters
crs – transformation matrix of type Matrix44
crs_to_wcs(crs: Matrix44) -> None
Transform all coordinates recursive from CRS into WCS coordinates by transformation matrix
crs inplace, see also GeoProxy.wcs_to_crs().
Parameters
crs – transformation matrix of type Matrix44
globe_to_map(func: Callable[[Vec3], Vec3] | None = None) -> None
Transform all coordinates recursive from globe representation in longitude and latitude in
decimal degrees into 2D map representation in meters.
Default is WGS84 EPSG:4326 (GPS) to WGS84 EPSG:3395 World Mercator function
wgs84_4326_to_3395().
Use the pyproj package to write a custom projection function as needed.
Parameters
func – custom transformation function, which takes one Vec3 object as argument and
returns the result as a Vec3 object.
map_to_globe(func: Callable[[Vec3], Vec3] | None = None) -> None
Transform all coordinates recursive from 2D map representation in meters into globe
representation as longitude and latitude in decimal degrees.
Default is WGS84 EPSG:3395 World Mercator to WGS84 EPSG:4326 GPS function
wgs84_3395_to_4326().
Use the pyproj package to write a custom projection function as needed.
Parameters
func – custom transformation function, which takes one Vec3 object as argument and
returns the result as a Vec3 object.
apply(func: Callable[[Vec3], Vec3]) -> None
Apply the transformation function func recursive to all coordinates.
Parameters
func – transformation function as Callable[[Vec3], Vec3]
filter(func: Callable[[GeoProxy], bool]) -> None
Removes all mappings for which func() returns False. The function only has to handle
Point, LineString and Polygon entities, other entities like MultiPolygon are divided into
separate entities also any collection.
Helper Functions
ezdxf.addons.geo.wgs84_4326_to_3395(location: Vec3) -> Vec3
Transform WGS84 EPSG:4326 location given as latitude and longitude in decimal degrees as used by
GPS into World Mercator cartesian 2D coordinates in meters EPSG:3395.
Parameters
location – Vec3 object, x-attribute represents the longitude value (East-West) in decimal
degrees and the y-attribute represents the latitude value (North-South) in decimal degrees.
ezdxf.addons.geo.wgs84_3395_to_4326(location: Vec3, tol: float = 1e-6) -> Vec3
Transform WGS84 World Mercator EPSG:3395 location given as cartesian 2D coordinates x, y in meters
into WGS84 decimal degrees as longitude and latitude EPSG:4326 as used by GPS.
Parameters
• location – Vec3 object, z-axis is ignored
• tol – accuracy for latitude calculation
ezdxf.addons.geo.dms2dd(d: float, m: float = 0, s: float = 0) -> float
Convert degree, minutes, seconds into decimal degrees.
ezdxf.addons.geo.dd2dms(dd: float) -> tuple[float, float, float]
Convert decimal degrees into degree, minutes, seconds.
ezdxf.addons.geo.assign_layers(entity: DXFGraphic, mapping: MutableMapping[str, Any]) -> None
Reference implementation for a post_process() function.
SEE ALSO:
dxf_entities()
def assign_layers(entity: DXFGraphic, mapping: GeoMapping) -> None:
properties = mapping.get("properties)
if properties is None:
return
layer = properties.get("layer")
if layer:
entity.dxf.layer = layer
Types
class ezdxf.addons.geo.PolygonConversion(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
Polygon conversion types as IntEnum.
HATCH
POLYLINE
HATCH_AND_POLYLINE
MPOLYGON
ezdxf.addons.geo.GeoMapping
alias of MutableMapping[str, Any]
ezdxf.addons.geo.PostProcessFunc
alias of Callable[[DXFGraphic, MutableMapping[str, Any]], None]
Importer
This add-on is meant to import graphical entities from another DXF drawing and their required table
entries like LAYER, LTYPE or STYLE.
Because of complex extensibility of the DXF format and the lack of sufficient documentation, I decided to
remove most of the possible source drawing dependencies from imported entities, therefore imported
entities may not look the same as the original entities in the source drawing, but at least the geometry
should be the same and the DXF file does not break.
Removed data which could contain source drawing dependencies: Extension Dictionaries, AppData and XDATA.
WARNING:
DON’T EXPECT PERFECT RESULTS!
The Importer supports following data import:
• entities which are really safe to import: LINE, POINT, CIRCLE, ARC, TEXT, SOLID, TRACE, 3DFACE,
SHAPE, POLYLINE, ATTRIB, ATTDEF, INSERT, ELLIPSE, MTEXT, LWPOLYLINE, SPLINE, HATCH, MESH, XLINE,
RAY, DIMENSION, LEADER, VIEWPORT
• table and table entry import is restricted to LAYER, LTYPE, STYLE, DIMSTYLE
• import of BLOCK definitions is supported
• import of paper space layouts is supported
Import of DXF objects from the OBJECTS section is not supported.
DIMSTYLE override for entities DIMENSION and LEADER is not supported.
Example:
import ezdxf
from ezdxf.addons import Importer
sdoc = ezdxf.readfile('original.dxf')
tdoc = ezdxf.new()
importer = Importer(sdoc, tdoc)
# import all entities from source modelspace into modelspace of the target drawing
importer.import_modelspace()
# import all paperspace layouts from source drawing
importer.import_paperspace_layouts()
# import all CIRCLE and LINE entities from source modelspace into an arbitrary target layout.
# create target layout
tblock = tdoc.blocks.new('SOURCE_ENTS')
# query source entities
ents = sdoc.modelspace().query('CIRCLE LINE')
# import source entities into target block
importer.import_entities(ents, tblock)
# This is ALWAYS the last & required step, without finalizing the target drawing is maybe invalid!
# This step imports all additional required table entries and block definitions.
importer.finalize()
tdoc.saveas('imported.dxf')
class ezdxf.addons.importer.Importer(source: Drawing, target: Drawing)
The Importer class is central element for importing data from other DXF documents.
Parameters
• source – source Drawing
• target – target Drawing
source source DXF document
target target DXF document
used_layers
Set of used layer names as string, AutoCAD accepts layer names without a LAYER table entry.
used_linetypes
Set of used linetype names as string, these linetypes require a TABLE entry or AutoCAD will
crash.
used_styles
Set of used text style names, these text styles require a TABLE entry or AutoCAD will
crash.
used_dimstyles
Set of used dimension style names, these dimension styles require a TABLE entry or AutoCAD
will crash.
finalize() -> None
Finalize the import by importing required table entries and BLOCK definitions, without
finalization the target document is maybe invalid for AutoCAD. Call the finalize() method
as last step of the import process.
import_block(block_name: str, rename=True) -> str
Import one BLOCK definition from source document.
If the BLOCK already exist the BLOCK will be renamed if argument rename is True, otherwise
the existing BLOCK in the target document will be used instead of the BLOCK in the source
document. Required name resolving for imported block references (INSERT), will be done in
the Importer.finalize() method.
To replace an existing BLOCK in the target document, just delete it before importing data:
target.blocks.delete_block(block_name, safe=False)
Parameters
• block_name – name of BLOCK to import
• rename – rename BLOCK if a BLOCK with the same name already exist in target
document
Returns: (renamed) BLOCK name
Raises ValueError – BLOCK in source document not found (defined)
import_blocks(block_names: Iterable[str], rename=False) -> None
Import all BLOCK definitions from source document.
If a BLOCK already exist the BLOCK will be renamed if argument rename is True, otherwise
the existing BLOCK in the target document will be used instead of the BLOCK from the source
document. Required name resolving for imported BLOCK references (INSERT), will be done in
the Importer.finalize() method.
Parameters
• block_names – names of BLOCK definitions to import
• rename – rename BLOCK if a BLOCK with the same name already exist in target
document
Raises ValueError – BLOCK in source document not found (defined)
import_entities(entities: Iterable[DXFEntity], target_layout: BaseLayout | None = None) -> None
Import all entities into target_layout or the modelspace of the target document, if
target_layout is None.
Parameters
• entities – Iterable of DXF entities
• target_layout – any layout (modelspace, paperspace or block) from the target
document
Raises DXFStructureError – target_layout is not a layout of target document
import_entity(entity: DXFEntity, target_layout: BaseLayout | None = None) -> None
Imports a single DXF entity into target_layout or the modelspace of the target document, if
target_layout is None.
Parameters
• entity – DXF entity to import
• target_layout – any layout (modelspace, paperspace or block) from the target
document
Raises DXFStructureError – target_layout is not a layout of target document
import_modelspace(target_layout: BaseLayout | None = None) -> None
Import all entities from source modelspace into target_layout or the modelspace of the
target document, if target_layout is None.
Parameters
target_layout – any layout (modelspace, paperspace or block) from the target
document
Raises DXFStructureError – target_layout is not a layout of target document
import_paperspace_layout(name: str) -> Layout
Import paperspace layout name into the target document.
Recreates the source paperspace layout in the target document, renames the target
paperspace if a paperspace with same name already exist and imports all entities from the
source paperspace into the target paperspace.
Parameters
name – source paper space name as string
Returns: new created target paperspace Layout
Raises
• KeyError – source paperspace does not exist
• DXFTypeError – invalid modelspace import
import_paperspace_layouts() -> None
Import all paperspace layouts and their content into the target document. Target layouts
will be renamed if a layout with the same name already exist. Layouts will be imported in
original tab order.
import_shape_files(fonts: set[str]) -> None
Import shape file table entries from the source document into the target document. Shape
file entries are stored in the styles table but without a name.
import_table(name: str, entries: str | Iterable[str] = '*', replace=False) -> None
Import specific table entries from the source document into the target document.
Parameters
• name – valid table names are “layers”, “linetypes” and “styles”
• entries – Iterable of table names as strings, or a single table name or “*” for
all table entries
• replace – True to replace the already existing table entry else ignore existing
entries
Raises TypeError – unsupported table type
import_tables(table_names: str | Iterable[str] = '*', replace=False) -> None
Import DXF tables from the source document into the target document.
Parameters
• table_names – iterable of tables names as strings, or a single table name as
string or “*” for all supported tables
• replace – True to replace already existing table entries else ignore existing
entries
Raises TypeError – unsupported table type
recreate_source_layout(name: str) -> Layout
Recreate source paperspace layout name in the target document. The layout will be renamed
if name already exist in the target document. Returns target modelspace for layout name
“Model”.
Parameters
name – layout name as string
Raises KeyError – if source layout name not exist
dxf2code
Translate DXF entities and structures into Python source code.
Short example:
import ezdxf
from ezdxf.addons.dxf2code import entities_to_code, block_to_code
doc = ezdxf.readfile('original.dxf')
msp = doc.modelspace()
source = entities_to_code(msp)
# create source code for a block definition
block_source = block_to_code(doc.blocks['MyBlock'])
# merge source code objects
source.merge(block_source)
with open('source.py', mode='wt') as f:
f.write(source.import_str())
f.write('\n\n')
f.write(source.code_str())
f.write('\n')
ezdxf.addons.dxf2code.entities_to_code(entities: Iterable[DXFEntity], layout: str = 'layout', ignore:
Iterable[str] | None = None) -> Code
Translates DXF entities into Python source code to recreate this entities by ezdxf.
Parameters
• entities – iterable of DXFEntity
• layout – variable name of the layout (model space or block) as string
• ignore – iterable of entities types to ignore as strings like ['IMAGE', 'DIMENSION']
Returns
Code
ezdxf.addons.dxf2code.block_to_code(block: BlockLayout, drawing: str = 'doc', ignore: Iterable[str] |
None = None) -> Code
Translates a BLOCK into Python source code to recreate the BLOCK by ezdxf.
Parameters
• block – block definition layout
• drawing – variable name of the drawing as string
• ignore – iterable of entities types to ignore as strings like [‘IMAGE’, ‘DIMENSION’]
Returns
Code
ezdxf.addons.dxf2code.table_entries_to_code(entities: Iterable[DXFEntity], drawing='doc') -> Code
ezdxf.addons.dxf2code.black(code: str, line_length=88, fast: bool = True) -> str
Returns the source code as a single string formatted by Black
Requires the installed Black formatter:
pip3 install black
Parameters
• code – source code
• line_length – max. source code line length
• fast – True for fast mode, False to check that the reformatted code is valid
Raises ImportError – Black is not available
class ezdxf.addons.dxf2code.Code
Source code container.
code Source code line storage, store lines without line ending \\n
imports
source code line storage for global imports, store lines without line ending \\n
layers Layers used by the generated source code, AutoCAD accepts layer names without a LAYER table
entry.
linetypes
Linetypes used by the generated source code, these linetypes require a TABLE entry or
AutoCAD will crash.
styles Text styles used by the generated source code, these text styles require a TABLE entry or
AutoCAD will crash.
dimstyles
Dimension styles used by the generated source code, these dimension styles require a TABLE
entry or AutoCAD will crash.
blocks Blocks used by the generated source code, these blocks require a BLOCK definition in the
BLOCKS section or AutoCAD will crash.
code_str(indent: int = 0) -> str
Returns the source code as a single string.
Parameters
indent – source code indentation count by spaces
black_code_str(line_length=88) -> str
Returns the source code as a single string formatted by Black
Parameters
line_length – max. source code line length
Raises ImportError – Black is not available
import_str(indent: int = 0) -> str
Returns required imports as a single string.
Parameters
indent – source code indentation count by spaces
merge(code: Code, indent: int = 0) -> None
Add another Code object.
add_import(statement: str) -> None
Add import statement, identical import statements are merged together.
add_line(code: str, indent: int = 0) -> None
Add a single source code line without line ending \n.
add_lines(code: Iterable[str], indent: int = 0) -> None
Add multiple source code lines without line ending \n.
iterdxf
This add-on allows iterating over entities of the modelspace of really big (> 5GB) DXF files which do not
fit into memory by only loading one entity at the time. Only ASCII DXF files are supported.
The entities are regular DXFGraphic objects with access to all supported DXF attributes, this entities
can be written to new DXF files created by the IterDXF.export() method. The new add_foreign_entity()
method allows also to add this entities to new regular ezdxf drawings (except for the INSERT entity), but
resources like linetype and style are removed, only layer will be preserved but only with default
attributes like color 7 and linetype CONTINUOUS.
The following example shows how to split a big DXF files into several separated DXF files which contains
only LINE, TEXT or POLYLINE entities.
from ezdxf.addons import iterdxf
doc = iterdxf.opendxf('big.dxf')
line_exporter = doc.export('line.dxf')
text_exporter = doc.export('text.dxf')
polyline_exporter = doc.export('polyline.dxf')
try:
for entity in doc.modelspace():
if entity.dxftype() == 'LINE':
line_exporter.write(entity)
elif entity.dxftype() == 'TEXT':
text_exporter.write(entity)
elif entity.dxftype() == 'POLYLINE':
polyline_exporter.write(entity)
finally:
line_exporter.close()
text_exporter.close()
polyline_exporter.close()
doc.close()
Supported DXF types:
3DFACE, ARC, ATTDEF, ATTRIB, CIRCLE, DIMENSION, ELLIPSE, HATCH, HELIX, IMAGE, INSERT, LEADER, LINE,
LWPOLYLINE, MESH, MLEADER, MLINE, MTEXT, POINT, POLYLINE, RAY, SHAPE, SOLID, SPLINE, TEXT, TRACE, VERTEX,
WIPEOUT, XLINE
Transfer simple entities to another DXF document, this works for some supported entities, except for
entities with strong dependencies to the original document like INSERT look at add_foreign_entity() for
all supported types:
newdoc = ezdxf.new()
msp = newdoc.modelspace()
# line is an entity from a big source file
msp.add_foreign_entity(line)
# and so on ...
msp.add_foreign_entity(lwpolyline)
msp.add_foreign_entity(mesh)
msp.add_foreign_entity(polyface)
Transfer MESH and POLYFACE (dxftype for POLYFACE and POLYMESH is POLYLINE!) entities into a new DXF
document by the MeshTransformer class:
from ezdxf.render import MeshTransformer
# mesh is MESH from a big source file
t = MeshTransformer.from_mesh(mesh)
# create a new MESH entity from MeshTransformer
t.render(msp)
# polyface is POLYFACE from a big source file
t = MeshTransformer.from_polyface(polyface)
# create a new POLYMESH entity from MeshTransformer
t.render_polyface(msp)
Another way to import entities from a big source file into new DXF documents is to split the big file
into smaller parts and use the Importer add-on for a more safe entity import.
ezdxf.addons.iterdxf.opendxf(filename: Path | str, errors: str = 'surrogateescape') -> IterDXF
Open DXF file for iterating, be sure to open valid DXF files, no DXF structure checks will be
applied.
Use this function to split up big DXF files as shown in the example above.
Parameters
• filename – DXF filename of a seekable DXF file.
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• DXFStructureError – invalid or incomplete DXF file
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
ezdxf.addons.iterdxf.modelspace(filename: Path | str, types: Iterable[str] | None = None, errors: str =
'surrogateescape') -> Iterable[DXFGraphic]
Iterate over all modelspace entities as DXFGraphic objects of a seekable file.
Use this function to iterate “quick” over modelspace entities of a DXF file, filtering DXF types
may speed up things if many entity types will be skipped.
Parameters
• filename – filename of a seekable DXF file
• types – DXF types like ['LINE', '3DFACE'] which should be returned, None returns all
supported types.
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• DXFStructureError – invalid or incomplete DXF file
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
ezdxf.addons.iterdxf.single_pass_modelspace(stream: BinaryIO, types: Iterable[str] | None = None, errors:
str = 'surrogateescape') -> Iterable[DXFGraphic]
Iterate over all modelspace entities as DXFGraphic objects in a single pass.
Use this function to ‘quick’ iterate over modelspace entities of a not seekable binary DXF stream,
filtering DXF types may speed up things if many entity types will be skipped.
Parameters
• stream – (not seekable) binary DXF stream
• types – DXF types like ['LINE', '3DFACE'] which should be returned, None returns all
supported types.
• errors –
specify decoding error handler
• ”surrogateescape” to preserve possible binary data (default)
• ”ignore” to use the replacement char U+FFFD “�” for invalid data
• ”strict” to raise an UnicodeDecodeError exception for invalid data
Raises
• DXFStructureError – Invalid or incomplete DXF file
• UnicodeDecodeError – if errors is “strict” and a decoding error occurs
class ezdxf.addons.iterdxf.IterDXF
export(name: Path | str) -> IterDXFWriter
Returns a companion object to export parts from the source DXF file into another DXF file,
the new file will have the same HEADER, CLASSES, TABLES, BLOCKS and OBJECTS sections, which
guarantees all necessary dependencies are present in the new file.
Parameters
name – filename, no special requirements
modelspace(types: Iterable[str] | None = None) -> Iterable[DXFGraphic]
Returns an iterator for all supported DXF entities in the modelspace. These entities are
regular DXFGraphic objects but without a valid document assigned. It is not possible to add
these entities to other ezdxf documents.
It is only possible to recreate the objects by factory functions base on attributes of the
source entity. For MESH, POLYMESH and POLYFACE it is possible to use the MeshTransformer
class to render (recreate) this objects as new entities in another document.
Parameters
types – DXF types like ['LINE', '3DFACE'] which should be returned, None returns all
supported types.
close()
Safe closing source DXF file.
class ezdxf.addons.iterdxf.IterDXFWriter
write(entity: DXFGraphic)
Write a DXF entity from the source DXF file to the export file.
Don’t write entities from different documents than the source DXF file, dependencies and
resources will not match, maybe it will work once, but not in a reliable way for different
DXF documents.
close()
Safe closing of exported DXF file. Copying of OBJECTS section happens only at closing the
file, without closing the new DXF file is invalid.
ODA File Converter Support
Use an installed ODA File Converter for converting between different versions of .dwg, .dxb and .dxf.
WARNING:
Execution of an external application is a big security issue! Especially when the path to the
executable can be altered.
To avoid this problem delete the ezdxf.addons.odafc.py module.
Install ODA File Converter
The ODA File Converter has to be installed by the user, the application is available for Windows XP,
Windows 7 or later, Mac OS X, and Linux in 32/64-bit RPM and DEB format.
AppImage Support
The option “unix_exec_path” defines an executable for Linux and macOS, this executable overrides the
default command ODAFileConverter. Assign an absolute path to the executable to that key and if the
executable is not found the add-on falls back to the ODAFileConverter command.
The option “unix_exec_path” also adds support for AppImages provided by the Open Design Alliance.
Download the AppImage file and store it in a folder of your choice (e.g. ~/Apps) and make the file
executable:
chmod a+x ~/Apps/ODAFileConverter_QT5_lnxX64_8.3dll_23.9.AppImage
Add the absolute path as config option “unix_exec_path” to the “odafc-addon” section:
[odafc-addon]
win_exec_path = "C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"
unix_exec_path = "/home/<your user name>/Apps/ODAFileConverter_QT5_lnxX64_8.3dll_23.9.AppImage"
This overrides the default command ODAFileConverter and if the executable is not found the add-on falls
back to the ODAFileConverter command.
SEE ALSO:
For more information about config files see section: Global Options Object
Suppressed GUI
On Windows the GUI of the ODA File Converter is suppressed, on Linux you may have to install the xvfb
package to prevent this, for macOS is no solution known.
Supported DXF and DWG Versions
ODA File Converter version strings, you can use any of this strings to specify a version, 'R..' and
'AC....' strings will be automatically mapped to 'ACAD....' strings:
┌──────────┬───────────────┬─────────┐
│ ODAFC │ ezdxf │ Version │
├──────────┼───────────────┼─────────┤
│ ACAD9 │ not supported │ AC1004 │
├──────────┼───────────────┼─────────┤
│ ACAD10 │ not supported │ AC1006 │
├──────────┼───────────────┼─────────┤
│ ACAD12 │ R12 │ AC1009 │
├──────────┼───────────────┼─────────┤
│ ACAD13 │ R13 │ AC1012 │
├──────────┼───────────────┼─────────┤
│ ACAD14 │ R14 │ AC1014 │
├──────────┼───────────────┼─────────┤
│ ACAD2000 │ R2000 │ AC1015 │
├──────────┼───────────────┼─────────┤
│ ACAD2004 │ R2004 │ AC1018 │
├──────────┼───────────────┼─────────┤
│ ACAD2007 │ R2007 │ AC1021 │
├──────────┼───────────────┼─────────┤
│ ACAD2010 │ R2010 │ AC1024 │
├──────────┼───────────────┼─────────┤
│ ACAD2013 │ R2013 │ AC1027 │
├──────────┼───────────────┼─────────┤
│ ACAD2018 │ R2018 │ AC1032 │
└──────────┴───────────────┴─────────┘
Config
On Windows the path to the ODAFileConverter.exe executable is stored in the config file (see
ezdxf.options) in the “odafc-addon” section as key “win_exec_path”, the default entry is:
[odafc-addon]
win_exec_path = "C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"
unix_exec_path =
On Linux and macOS the ODAFileConverter command is located by the shutil.which() function but can be
overridden since version 1.0 by the key “linux_exec_path”.
Usage
from ezdxf.addons import odafc
# Load a DWG file
doc = odafc.readfile('my.dwg')
# Use loaded document like any other ezdxf document
print(f'Document loaded as DXF version: {doc.dxfversion}.')
msp = doc.modelspace()
...
# Export document as DWG file for AutoCAD R2018
odafc.export_dwg(doc, 'my_R2018.dwg', version='R2018')
ezdxf.addons.odafc.win_exec_path
Path to installed ODA File Converter executable on Windows systems, default is "C:\Program
Files\ODA\ODAFileConverter\ODAFileConverter.exe".
ezdxf.addons.odafc.unix_exec_path
Absolute path to a Linux or macOS executable if set, otherwise an empty string and the default
command ODAFileConverter is used.
ezdxf.addons.odafc.is_installed() -> bool
Returns True if the ODAFileConverter is installed.
ezdxf.addons.odafc.readfile(filename: str | PathLike, version: str | None = None, *, audit: bool = False)
-> Drawing | None
Uses an installed ODA File Converter to convert a DWG/DXB/DXF file into a temporary DXF file and
load this file by ezdxf.
Parameters
• filename – file to load by ODA File Converter
• version – load file as specific DXF version, by default the same version as the source
file or if not detectable the latest by ezdxf supported version.
• audit – audit source file before loading
Raises
• FileNotFoundError – source file not found
• odafc.UnknownODAFCError – conversion failed for unknown reasons
• odafc.UnsupportedVersion – invalid DWG version specified
• odafc.UnsupportedFileFormat – unsupported file extension
• odafc.ODAFCNotInstalledError – ODA File Converter not installed
ezdxf.addons.odafc.export_dwg(doc: Drawing, filename: str | PathLike, version: str | None = None, *,
audit: bool = False, replace: bool = False) -> None
Uses an installed ODA File Converter to export the DXF document doc as a DWG file.
A temporary DXF file will be created and converted to DWG by the ODA File Converter. If version is
not specified the DXF version of the source document is used.
Parameters
• doc – ezdxf DXF document as Drawing object
• filename – output DWG filename, the extension will be set to “.dwg”
• version – DWG version to export, by default the same version as the source document.
• audit – audit source file by ODA File Converter at exporting
• replace – replace existing DWG file if True
Raises
• FileExistsError – target file already exists, and argument replace is
False
• FileNotFoundError – parent directory of target file does not exist
• odafc.UnknownODAFCError – exporting DWG failed for unknown reasons
• odafc.ODAFCNotInstalledError – ODA File Converter not installed
ezdxf.addons.odafc.convert(source: str | PathLike, dest: str | PathLike = '', *, version='R2018',
audit=True, replace=False)
Convert source file to dest file.
The file extension defines the target format e.g. convert("test.dxf", "Test.dwg") converts the
source file to a DWG file. If dest is an empty string the conversion depends on the source file
format and is DXF to DWG or DWG to DXF. To convert DXF to DXF an explicit destination filename is
required: convert("r12.dxf", "r2013.dxf", version="R2013")
Parameters
• source – source file
• dest – destination file, an empty string uses the source filename with the extension of
the target format e.g. “test.dxf” -> “test.dwg”
• version – output DXF/DWG version e.g. “ACAD2018”, “R2018”, “AC1032”
• audit – audit files
• replace – replace existing destination file
Raises
• FileNotFoundError – source file or destination folder does not exist
• FileExistsError – destination file already exists and argument replace
is False
• odafc.UnsupportedVersion – invalid DXF version specified
• odafc.UnsupportedFileFormat – unsupported file extension
• odafc.UnknownODAFCError – conversion failed for unknown reasons
• odafc.ODAFCNotInstalledError – ODA File Converter not installed
R12 Export
New in version 1.1.
This module exports any DXF file as a simple DXF R12 file. Many complex entities will be converted into
DXF primitives. This exporter is intended for creating a simple file format as an input format for other
software such as laser cutters. In order to get a file that can be edited well in a CAD application, the
results of the ODA file converter are much better.
Usage
import ezdxf
from ezdxf.addons import r12export
doc = ezdxf.readfile("any.dxf")
r12export.saveas(doc, "r12.dxf")
Converted Entity Types
┌─────────────┬───────────────────────────────────────┐
│ LWPOLYLINE │ translated to POLYLINE │
├─────────────┼───────────────────────────────────────┤
│ MESH │ translated to POLYLINE (PolyfaceMesh) │
├─────────────┼───────────────────────────────────────┤
│ SPLINE │ flattened to POLYLINE │
├─────────────┼───────────────────────────────────────┤
│ ELLIPSE │ flattened to POLYLINE │
├─────────────┼───────────────────────────────────────┤
│ MTEXT │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ LEADER │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ MLEADER │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ MULTILEADER │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ MLINE │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ HATCH │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ MPOLYGON │ exploded into DXF primitives │
├─────────────┼───────────────────────────────────────┤
│ ACAD_TABLE │ export of pre-rendered BLOCK content │
└─────────────┴───────────────────────────────────────┘
For proxy- or unknown entities the available proxy graphic will be exported as DXF primitives.
Limitations
• Explosion of MTEXT into DXF primitives is not perfect
• Pattern rendering for complex HATCH entities has issues
• Solid fill rendering for complex HATCH entities has issues
ODA File Converter
The advantage of the r12export module is that the ODA file converter isn’t needed, but the ODA file
converter will produce a much better result:
from ezdxf.addons import odafc
odafc.convert("any.dxf", "r12.dxf", version="R12")
Functions
┌─────────┬───────────────────────────────────────┐
│ write │ Write a DXF document as DXF version │
│ │ R12 to a text stream. │
├─────────┼───────────────────────────────────────┤
│ saveas │ Write a DXF document as DXF version │
│ │ R12 to a file. │
├─────────┼───────────────────────────────────────┤
│ convert │ Export and reload DXF document as DXF │
│ │ version R12. │
└─────────┴───────────────────────────────────────┘
ezdxf.addons.r12export.write(doc: Drawing, stream: TextIO, *, max_sagitta: float = MAX_SAGITTA) -> None
Write a DXF document as DXF version R12 to a text stream. The max_sagitta argument determines the
accuracy of the curve flatting for SPLINE and ELLIPSE entities.
Parameters
• doc – DXF document to export
• stream – output stream, use doc.encoding as encoding
• max_sagitta – maximum distance from the center of the curve to the center of the line
segment between two approximation points to determine if a segment should be subdivided.
ezdxf.addons.r12export.saveas(doc: Drawing, filepath: str | PathLike, *, max_sagitta: float =
MAX_SAGITTA) -> None
Write a DXF document as DXF version R12 to a file. The max_sagitta argument determines the
accuracy of the curve flatting for SPLINE and ELLIPSE entities.
Parameters
• doc – DXF document to export
• filepath – output filename
• max_sagitta – maximum distance from the center of the curve to the center of the line
segment between two approximation points to determine if a segment should be subdivided.
ezdxf.addons.r12export.convert(doc: Drawing, *, max_sagitta: float = MAX_SAGITTA) -> Drawing
Export and reload DXF document as DXF version R12.
Writes the DXF document into a temporary file at the file-system and reloads this file by the
ezdxf.readfile() function.
r12writer
The fast file/stream writer creates simple DXF R12 drawings with just an ENTITIES section. The HEADER,
TABLES and BLOCKS sections are not present except FIXED-TABLES are written. Only LINE, CIRCLE, ARC, TEXT,
POINT, SOLID, 3DFACE and POLYLINE entities are supported. FIXED-TABLES is a predefined TABLES section,
which will be written, if the init argument fixed_tables of R12FastStreamWriter is True.
The R12FastStreamWriter writes the DXF entities as strings direct to the stream without creating an
in-memory drawing and therefore the processing is very fast.
Because of the lack of a BLOCKS section, BLOCK/INSERT can not be used. Layers can be used, but this
layers have a default setting color = 7 (black/white) and linetype = 'Continuous'. If writing the
FIXED-TABLES, some predefined text styles and line types are available, else text style is always
'STANDARD' and line type is always 'ByLayer'.
If using FIXED-TABLES, following predefined line types are available:
• CONTINUOUS
• CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____
• CENTERX2 ________ __ ________ __ ________
• CENTER2 ____ _ ____ _ ____ _ ____ _ ____
• DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ _
• DASHEDX2 ____ ____ ____ ____ ____ ____
• DASHED2 _ _ _ _ _ _ _ _ _ _ _ _ _ _
• PHANTOM ______ __ __ ______ __ __ ______
• PHANTOMX2 ____________ ____ ____ ____________
• PHANTOM2 ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___
• DASHDOT __ . __ . __ . __ . __ . __ . __ . __
• DASHDOTX2 ____ . ____ . ____ . ____
• DASHDOT2 _ . _ . _ . _ . _ . _ . _ . _
• DOT . . . . . . . . . . . . . . . .
• DOTX2 . . . . . . . .
• DOT2 . . . . . . . . . . . . . . . . . . .
• DIVIDE __ . . __ . . __ . . __ . . __ . . __
• DIVIDEX2 ____ . . ____ . . ____ . . ____
• DIVIDE2 _ . _ . _ . _ . _ . _ . _ . _
If using FIXED-TABLES, following predefined text styles are available:
• OpenSans
• OpenSansCondensed-Light
Tutorial
A simple example with different DXF entities:
from random import random
from ezdxf.addons import r12writer
with r12writer("quick_and_dirty_dxf_r12.dxf") as dxf:
dxf.add_line((0, 0), (17, 23))
dxf.add_circle((0, 0), radius=2)
dxf.add_arc((0, 0), radius=3, start=0, end=175)
dxf.add_solid([(0, 0), (1, 0), (0, 1), (1, 1)])
dxf.add_point((1.5, 1.5))
# 2d polyline, new in v0.12
dxf.add_polyline_2d([(5, 5), (7, 3), (7, 6)])
# 2d polyline with bulge value, new in v0.12
dxf.add_polyline_2d([(5, 5), (7, 3, 0.5), (7, 6)], format='xyb')
# 3d polyline only, changed in v0.12
dxf.add_polyline([(4, 3, 2), (8, 5, 0), (2, 4, 9)])
dxf.add_text("test the text entity", align="MIDDLE_CENTER")
A simple example of writing really many entities in a short time:
from random import random
from ezdxf.addons import r12writer
MAX_X_COORD = 1000.0
MAX_Y_COORD = 1000.0
CIRCLE_COUNT = 1000000
with r12writer("many_circles.dxf") as dxf:
for i in range(CIRCLE_COUNT):
dxf.add_circle((MAX_X_COORD*random(), MAX_Y_COORD*random()), radius=2)
Show all available line types:
import ezdxf
LINETYPES = [
'CONTINUOUS', 'CENTER', 'CENTERX2', 'CENTER2',
'DASHED', 'DASHEDX2', 'DASHED2', 'PHANTOM', 'PHANTOMX2',
'PHANTOM2', 'DASHDOT', 'DASHDOTX2', 'DASHDOT2', 'DOT',
'DOTX2', 'DOT2', 'DIVIDE', 'DIVIDEX2', 'DIVIDE2',
]
with r12writer('r12_linetypes.dxf', fixed_tables=True) as dxf:
for n, ltype in enumerate(LINETYPES):
dxf.add_line((0, n), (10, n), linetype=ltype)
dxf.add_text(ltype, (0, n+0.1), height=0.25, style='OpenSansCondensed-Light')
Reference
ezdxf.addons.r12writer.r12writer(stream: TextIO | BinaryIO | str, fixed_tables=False, fmt='asc') ->
R12FastStreamWriter
Context manager for writing DXF entities to a stream/file. stream can be any file like object with
a write() method or just a string for writing DXF entities to the file system. If fixed_tables is
True, a standard TABLES section is written in front of the ENTITIES section and some predefined
text styles and line types can be used.
Set argument fmt to “asc” to write ASCII DXF file (default) or “bin” to write Binary DXF files.
ASCII DXF require a TextIO stream and Binary DXF require a BinaryIO stream.
class ezdxf.addons.r12writer.R12FastStreamWriter(stream: TextIO, fixed_tables=False)
Fast stream writer to create simple DXF R12 drawings.
Parameters
• stream – a file like object with a write() method.
• fixed_tables – if fixed_tables is True, a standard TABLES section is written in front of
the ENTITIES section and some predefined text styles and line types can be used.
close() -> None
Writes the DXF tail. Call is not necessary when using the context manager r12writer().
add_line(start: Sequence[float], end: Sequence[float], layer: str = '0', color: int | None = None,
linetype: str | None = None) -> None
Add a LINE entity from start to end.
Parameters
• start – start vertex as (x, y[, z]) tuple
• end – end vertex as as (x, y[, z]) tuple
• layer – layer name as string, without a layer definition the assigned color = 7
(black/white) and line type is 'Continuous'.
• color – color as AutoCAD Color Index (ACI) in the range from 0 to 256, 0 is
ByBlock and 256 is ByLayer, default is ByLayer which is always color = 7
(black/white) without a layer definition.
• linetype – line type as string, if FIXED-TABLES are written some predefined line
types are available, else line type is always ByLayer, which is always
'Continuous' without a LAYERS table.
add_circle(center: Sequence[float], radius: float, layer: str = '0', color: int | None = None,
linetype: str | None = None) -> None
Add a CIRCLE entity.
Parameters
• center – circle center point as (x, y) tuple
• radius – circle radius as float
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_arc(center: Sequence[float], radius: float, start: float = 0, end: float = 360, layer: str =
'0', color: int | None = None, linetype: str | None = None) -> None
Add an ARC entity. The arc goes counter-clockwise from start angle to end angle.
Parameters
• center – arc center point as (x, y) tuple
• radius – arc radius as float
• start – arc start angle in degrees as float
• end – arc end angle in degrees as float
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_point(location: Sequence[float], layer: str = '0', color: int | None = None, linetype: str |
None = None) -> None
Add a POINT entity.
Parameters
• location – point location as (x, y [,z]) tuple
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_3dface(vertices: Iterable[Sequence[float]], invisible: int = 0, layer: str = '0', color: int |
None = None, linetype: str | None = None) -> None
Add a 3DFACE entity. 3DFACE is a spatial area with 3 or 4 vertices, all vertices have to be
in the same plane.
Parameters
• vertices – iterable of 3 or 4 (x, y, z) vertices.
• invisible –
bit coded flag to define the invisible edges,
1. edge = 1
2. edge = 2
3. edge = 4
4. edge = 8
Add edge values to set multiple edges invisible, 1. edge + 3. edge = 1 + 4 = 5,
all edges = 15
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_solid(vertices: Iterable[Sequence[float]], layer: str = '0', color: int | None = None,
linetype: str | None = None) -> None
Add a SOLID entity. SOLID is a solid filled area with 3 or 4 edges and SOLID is a 2D
entity.
Parameters
• vertices – iterable of 3 or 4 (x, y[, z]) tuples, z-axis will be ignored.
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_polyline_2d(points: Iterable[Sequence], format: str = 'xy', closed: bool = False, start_width:
float = 0, end_width: float = 0, layer: str = '0', color: int | None = None, linetype: str | None
= None) -> None
Add a 2D POLYLINE entity with start width, end width and bulge value support.
Format codes:
┌───┬──────────────────────────────────┐
│ x │ x-coordinate │
├───┼──────────────────────────────────┤
│ y │ y-coordinate │
├───┼──────────────────────────────────┤
│ s │ start width │
├───┼──────────────────────────────────┤
│ e │ end width │
├───┼──────────────────────────────────┤
│ b │ bulge value │
├───┼──────────────────────────────────┤
│ v │ (x, y) tuple (z-axis is ignored) │
└───┴──────────────────────────────────┘
Parameters
• points – iterable of (x, y, [start_width, [end_width, [bulge]]]) tuple, value
order according to the format string, unset values default to 0
• format – format: format string, default is 'xy'
• closed – True creates a closed polyline
• start_width – default start width, default is 0
• end_width – default end width, default is 0
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_polyline(vertices: Iterable[Sequence[float]], closed: bool = False, layer: str = '0', color:
int | None = None, linetype: str | None = None) -> None
Add a 3D POLYLINE entity.
Parameters
• vertices – iterable of (x, y[, z]) tuples, z-axis is 0 by default
• closed – True creates a closed polyline
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_polyface(vertices: Iterable[Sequence[float]], faces: Iterable[Sequence[int]], layer: str =
'0', color: int | None = None, linetype: str | None = None) -> None
Add a POLYFACE entity. The POLYFACE entity supports only faces of maximum 4 vertices, more
indices will be ignored. A simple square would be:
v0 = (0, 0, 0)
v1 = (1, 0, 0)
v2 = (1, 1, 0)
v3 = (0, 1, 0)
dxf.add_polyface(vertices=[v0, v1, v2, v3], faces=[(0, 1, 2, 3)])
All 3D form functions of the ezdxf.render.forms module return MeshBuilder objects, which
provide the required vertex and face lists.
See sphere example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py
Parameters
• vertices – iterable of (x, y, z) tuples
• faces – iterable of 3 or 4 vertex indices, indices have to be 0-based
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_polymesh(vertices: Iterable[Sequence[float]], size: tuple[int, int], closed=(False, False),
layer: str = '0', color: int | None = None, linetype: str | None = None) -> None
Add a POLYMESH entity. A POLYMESH is a mesh of m rows and n columns, each mesh vertex has
its own x-, y- and z coordinates. The mesh can be closed in m- and/or n-direction. The
vertices have to be in column order: (m0, n0), (m0, n1), (m0, n2), (m1, n0), (m1, n1),
(m1, n2), …
See example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py
Parameters
• vertices – iterable of (x, y, z) tuples, in column order
• size – mesh dimension as (m, n)-tuple, requirement: len(vertices) == m*n
• closed – (m_closed, n_closed) tuple, for closed mesh in m and/or n direction
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
• linetype – line type as string see add_line()
add_text(text: str, insert: Sequence[float] = (0, 0), height: float = 1.0, width: float = 1.0,
align: str = 'LEFT', rotation: float = 0.0, oblique: float = 0.0, style: str = 'STANDARD', layer:
str = '0', color: int | None = None) -> None
Add a one line TEXT entity.
Parameters
• text – the text as string
• insert – insert location as (x, y) tuple
• height – text height in drawing units
• width – text width as factor
• align – text alignment, see table below
• rotation – text rotation in degrees as float
• oblique – oblique in degrees as float, vertical = 0 (default)
• style – text style name as string, if FIXED-TABLES are written some predefined
text styles are available, else text style is always 'STANDARD'.
• layer – layer name as string see add_line()
• color – color as AutoCAD Color Index (ACI) see add_line()
┌────────────┬─────────────┬───────────────┬──────────────┐
│ Vert/Horiz │ Left │ Center │ Right │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Top │ TOP_LEFT │ TOP_CENTER │ TOP_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Middle │ MIDDLE_LEFT │ MIDDLE_CENTER │ MIDDLE_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Bottom │ BOTTOM_LEFT │ BOTTOM_CENTER │ BOTTOM_RIGHT │
├────────────┼─────────────┼───────────────┼──────────────┤
│ Baseline │ LEFT │ CENTER │ RIGHT │
└────────────┴─────────────┴───────────────┴──────────────┘
The special alignments ALIGNED and FIT are not available.
text2path
Tools to convert text strings and text based DXF entities into outer- and inner linear paths as Path
objects. At the moment only the TEXT and the ATTRIB entity can be converted into paths and hatches.
New in version 1.1: Text rendering is done by the fontTools package, which is a hard dependency of ezdxf.
Support for stroke fonts, these are the basic vector fonts included in CAD applications, like .shx, .shp
or .lff fonts was added but these fonts cannot be rendered as HATCH entities.
The required font files are not included with ezdxf as they are copyrighted or, in the case of the
LibreCAD font format, licensed under the “GPL v2 and later”. Set the paths to such stroke fonts in the
config file, see option ezdxf.options.support_dirs:
[core]
support_dirs =
"C:\Program Files\Bricsys\BricsCAD V23 en_US\Fonts",
~/shx_fonts,
~/shp_fonts,
~/lff_fonts,
Don’t expect a 100% match compared to CAD applications but the results with fontTools are better than the
previous Matplotlib renderings.
Text Alignments
The text alignments are enums of type ezdxf.enums.TextEntityAlignment
┌──────────┬─────────────┬───────────────┬──────────────┐
│ Vertical │ Left │ Center │ Right │
├──────────┼─────────────┼───────────────┼──────────────┤
│ Top │ TOP_LEFT │ TOP_CENTER │ TOP_RIGHT │
├──────────┼─────────────┼───────────────┼──────────────┤
│ Middle │ MIDDLE_LEFT │ MIDDLE_CENTER │ MIDDLE_RIGHT │
├──────────┼─────────────┼───────────────┼──────────────┤
│ Bottom │ BOTTOM_LEFT │ BOTTOM_CENTER │ BOTTOM_RIGHT │
├──────────┼─────────────┼───────────────┼──────────────┤
│ Baseline │ LEFT │ CENTER │ RIGHT │
└──────────┴─────────────┴───────────────┴──────────────┘
The vertical middle alignments (MIDDLE_XXX), center the text vertically in the middle of the uppercase
letter “X” (cap height).
Special alignments, where the horizontal alignment is always in the center of the text:
• ALIGNED: text is scaled to match the given length, scales x- and y-direction by the same factor.
• FIT: text is scaled to match the given length, but scales only in x-direction.
• MIDDLE: insertion point is the center of the total height (cap height + descender height) without
scaling, the length argument is ignored.
Font Face Definition
A font face is defined by the Matplotlib compatible FontFace object by font-family, font-style,
font-stretch and font-weight.
SEE ALSO:
• Font Anatomy
• Font Properties
String Functions
ezdxf.addons.text2path.make_path_from_str(s: str, font: FontFace, size: float = 1.0,
align=TextEntityAlignment.LEFT, length: float = 0, m: Matrix44 = None) -> Path
Convert a single line string s into a Multi-Path object. The text size is the height of the
uppercase letter “X” (cap height). The paths are aligned about the insertion point at (0, 0).
BASELINE means the bottom of the letter “X”.
Parameters
• s – text to convert
• font – font face definition as FontFace object
• size – text size (cap height) in drawing units
• align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFT
• length – target length for the ALIGNED and FIT alignments
• m – transformation Matrix44
ezdxf.addons.text2path.make_paths_from_str(s: str, font: FontFace, size: float = 1.0,
align=TextEntityAlignment.LEFT, length: float = 0, m: Matrix44 = None) -> list[Path]
Convert a single line string s into a list of Path objects. All paths are returned as a list of
Single-Path objects. The text size is the height of the uppercase letter “X” (cap height). The
paths are aligned about the insertion point at (0, 0). BASELINE means the bottom of the letter
“X”.
Parameters
• s – text to convert
• font – font face definition as FontFace object
• size – text size (cap height) in drawing units
• align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFT
• length – target length for the ALIGNED and FIT alignments
• m – transformation Matrix44
ezdxf.addons.text2path.make_hatches_from_str(s: str, font: FontFace, size: float = 1.0,
align=TextEntityAlignment.LEFT, length: float = 0, dxfattribs=None, m: Matrix44 = None) -> list[Hatch]
Convert a single line string s into a list of virtual Hatch entities. The text size is the height
of the uppercase letter “X” (cap height). The paths are aligned about the insertion point at (0,
0). The HATCH entities are aligned to this insertion point. BASELINE means the bottom of the
letter “X”.
IMPORTANT:
Returns an empty list for .shx, .shp and .lff fonts a.k.a. stroke fonts.
Parameters
• s – text to convert
• font – font face definition as FontFace object
• size – text size (cap height) in drawing units
• align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFT
• length – target length for the ALIGNED and FIT alignments
• dxfattribs – additional DXF attributes
• m – transformation Matrix44
Entity Functions
class ezdxf.addons.text2path.Kind(value, names=None, *, module=None, qualname=None, type=None, start=1,
boundary=None)
The Kind enum defines the DXF types to create as bit flags, e.g. 1+2 to get HATCHES as filling and
SPLINES and POLYLINES as outline:
┌─────┬─────────────┬──────────────────────────────┐
│ Int │ Enum │ Description │
├─────┼─────────────┼──────────────────────────────┤
│ 1 │ HATCHES │ Hatch entities as filling │
├─────┼─────────────┼──────────────────────────────┤
│ 2 │ SPLINES │ Spline and 3D Polyline │
│ │ │ entities as outline │
├─────┼─────────────┼──────────────────────────────┤
│ 4 │ LWPOLYLINES │ LWPolyline entities as │
│ │ │ approximated (flattened) │
│ │ │ outline │
└─────┴─────────────┴──────────────────────────────┘
ezdxf.addons.text2path.virtual_entities(entity: Text | Attrib, kind: int = Kind.HATCHES) -> EntityQuery
Convert the text content of DXF entities TEXT and ATTRIB into virtual SPLINE and 3D POLYLINE
entities or approximated LWPOLYLINE entities as outlines, or as HATCH entities as fillings.
Returns the virtual DXF entities as an EntityQuery object.
Parameters
• entity – TEXT or ATTRIB entity
• kind – kind of entities to create as bit flags, see enum Kind
ezdxf.addons.text2path.explode(entity: Text | Attrib, kind: int = Kind.HATCHES, target=None) ->
EntityQuery
Explode the text entity into virtual entities, see virtual_entities(). The source entity will be
destroyed.
The target layout is given by the target argument, if target is None, the target layout is the
source layout of the text entity.
Returns the created DXF entities as an EntityQuery object.
Parameters
• entity – TEXT or ATTRIB entity to explode
• kind – kind of entities to create as bit flags, see enum Kind
• target – target layout for new created DXF entities, None for the same layout as the
source entity.
ezdxf.addons.text2path.make_path_from_entity(entity: Text | Attrib) -> Path
Convert text content from DXF entities TEXT and ATTRIB into a Multi-Path object. The paths are
located at the location of the source entity.
ezdxf.addons.text2path.make_paths_from_entity(entity: Text | Attrib) -> list[Path]
Convert text content from DXF entities TEXT and ATTRIB into a list of Path objects. All paths are
returned as a list of Single-Path objects. The paths are located at the location of the source
entity.
MTextExplode
This tool is meant to explode MTEXT entities into single line TEXT entities by replicating the MTEXT
layout as close as possible. This tool requires the optional Matplotlib package to create usable results,
nonetheless it also works without Matplotlib, but then uses a mono-spaced replacement font for text size
measuring which leads to very inaccurate results.
The supported MTEXT features are:
• changing text color
• text strokes: underline, overline and strike through
• changing text size, width and oblique
• changing font faces
• stacked text (fractions)
• multi-column support
• background color
• text frame
The tool requires an initialized DXF document io implement all these features by creating additional text
styles. When exploding multiple MTEXT entities, they can share this new text styles. Call the
MTextExplode.finalize() method just once after all MTEXT entities are processed to create the required
text styles, or use MTextExplode as context manager by using the with statement, see examples below.
There are also many limitations:
• A 100% accurate result cannot be achieved.
• Character tracking is not supported.
• Tabulator stops have only limited support for LEFT and JUSTIFIED aligned paragraphs to support numbered
and bullet lists. An excessive use of tabs will lead to incorrect results.
• The DISTRIBUTED alignment will be replaced by the JUSTIFIED alignment.
• Text flow is always “left to right”.
• The line spacing mostly corresponds to the “EXACT” style, except for stacked text (fractions), which
corresponds more to the “AT LEAST” style, but not precisely. This behavior maybe will improve in the
future.
• FIELDS are not evaluated by ezdxf.
class ezdxf.addons.MTextExplode(layout, doc=None, spacing_factor=1.0)
The MTextExplode class is a tool to disassemble MTEXT entities into single line TEXT entities and
additional LINE entities if required to emulate strokes.
The layout argument defines the target layout for “exploded” parts of the MTEXT entity. Use
argument doc if the target layout has no DXF document assigned like virtual layouts. The
spacing_factor argument is an advanced tuning parameter to scale the size of space chars.
explode(mtext: MText, destroy=True)
Explode mtext and destroy the source entity if argument destroy is True.
finalize()
Create required text styles. This method is called automatically if the class is used as
context manager. This method does not work with virtual layouts if no document was assigned
at initialization!
Example to explode all MTEXT entities in the DXF file “mtext.dxf”:
import ezdxf
from ezdxf.addons import MTextExplode
doc = ezdxf.readfile("mtext.dxf")
msp = doc.modelspace()
with MTextExplode(msp) as xpl:
for mtext in msp.query("MTEXT"):
xpl.explode(mtext)
doc.saveas("xpl_mtext.dxf")
Explode all MTEXT entities into the block “EXPLODE”:
import ezdxf
from ezdxf.addons import MTextExplode
doc = ezdxf.readfile("mtext.dxf")
msp = doc.modelspace()
blk = doc.blocks.new("EXPLODE")
with MTextExplode(blk) as xpl:
for mtext in msp.query("MTEXT"):
xpl.explode(mtext)
msp.add_block_ref("EXPLODE", (0, 0))
doc.saveas("xpl_into_block.dxf")
HPGL/2 Converter Add-on
New in version 1.1.
The hpgl2 add-on provides tools to process and convert HPGL/2 plot files.
What are HPGL/2 Plot Files?
The Hewlett-Packard Graphics Language (HPGL) is a vector graphics language originally developed by
Hewlett-Packard in the 1970s. HPGL is widely used for controlling pen plotters and other output devices,
and it has become a de facto standard for communicating between computers and output devices in the field
of computer-aided design (CAD) and drafting.
HPGL is a command-driven language that consists of a series of commands that control the movement of the
plotter pen, the selection of pens and other output parameters, and the drawing of geometric shapes such
as lines, arcs, circles, and text. The language is interpreted by the plotter or other output device and
translated into physical pen movements on the drawing surface.
HPGL has evolved over the years, and various extensions have been added to support more complex graphics
operations and to improve compatibility with other graphics languages. Despite the development of newer
graphics languages and file formats, HPGL remains a widely used format for vector-based graphics,
particularly in the engineering and architectural fields.
The Goal of This Add-on
An HPGL/2 plot file contains all of the data generated by a CAD application that has been sent to a
plotter to print an engineering drawing. In the past, the only way to access this data was to view it on
a plotter or an specialized application, which could be expensive and impractical for many people.
However, this module provides functions and classes to convert HPGL/2 plot files into modern vector
graphic formats such as PDF and SVG and of course DXF, allowing the data to be viewed and processed using
a wide range of software tools.
IMPORTANT:
The Python module PyMuPDF is required for the PDF export: https://pypi.org/project/PyMuPDF/
The Plotter class in the hpgl2 add-on supports only the most commonly used commands of HPGL/2. This is
because many CAD applications use only a small subset of HPGL/2 to create their output, typically
consisting of polylines and filled polygons. For more information on the supported commands, please
refer to the documentation for the Plotter class.
To use the HPGL2 add-on, the entry point is the ezdxf.addons.hpgl2.api module. This module contains the
public interface of the add-on and should be imported in the following way:
from ezdxf.addons.hpgl2 import api as hpgl2
with open("hpgl2.plt", "rb") as fp:
data = fp.read()
doc = hpgl2.to_dxf(data, color_mode=hpgl2.ColorMode.ACI)
doc.saveas("hpgl2_as.dxf")
High Level Functions
┌───────────┬───────────────────────────────────────┐
│ to_dxf │ Exports the HPGL/2 commands of the │
│ │ byte stream b as a DXF document. │
├───────────┼───────────────────────────────────────┤
│ to_svg │ Exports the HPGL/2 commands of the │
│ │ byte stream b as SVG string. │
├───────────┼───────────────────────────────────────┤
│ to_pdf │ Exports the HPGL/2 commands of the │
│ │ byte stream b as PDF data. │
├───────────┼───────────────────────────────────────┤
│ to_pixmap │ Exports the HPGL/2 commands of the │
│ │ byte stream b as pixel image. │
└───────────┴───────────────────────────────────────┘
ezdxf.addons.hpgl2.api.to_dxf(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
False, color_mode=ColorMode.RGB, merge_control: MergeControl = MergeControl.AUTO) -> Drawing
Exports the HPGL/2 commands of the byte stream b as a DXF document.
The page content is created at the origin of the modelspace and 1 drawing unit is 1 plot unit (1
plu = 0.025mm) unless scaling values are provided.
The content of HPGL files is intended to be plotted on white paper, therefore a white filling will
be added as background in color mode RGB.
All entities are assigned to a layer according to the pen number with the name scheme PEN_<###>.
In order to be able to process the file better, it is also possible to assign the ACI color by
layer by setting the argument color_mode to ColorMode.ACI, but then the RGB color is lost because
the RGB color has always the higher priority over the ACI.
The first paperspace layout “Layout1” of the DXF document is set up to print the entire modelspace
on one sheet, the size of the page is the size of the original plot file in millimeters.
HPGL/2’s merge control works at the pixel level and cannot be replicated by DXF, but to prevent
fillings from obscuring text, the filled polygons are sorted by luminance - this can be forced or
disabled by the argument merge_control, see also MergeControl enum.
Parameters
• b – plot file content as bytes
• rotation – rotation angle of 0, 90, 180 or 270 degrees
• mirror_x – mirror in x-axis direction
• mirror_y – mirror in y-axis direction
• color_mode – the color mode controls how color values are assigned to DXF entities, see
ColorMode
• merge_control – how to order filled polygons, see MergeControl
Returns: DXF document as instance of class Drawing
ezdxf.addons.hpgl2.api.to_svg(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
False, merge_control=MergeControl.AUTO) -> str
Exports the HPGL/2 commands of the byte stream b as SVG string.
The plot units are mapped 1:1 to viewBox units and the size of image is the size of the original
plot file in millimeters.
HPGL/2’s merge control works at the pixel level and cannot be replicated by the backend, but to
prevent fillings from obscuring text, the filled polygons are sorted by luminance - this can be
forced or disabled by the argument merge_control, see also MergeControl enum.
Parameters
• b – plot file content as bytes
• rotation – rotation angle of 0, 90, 180 or 270 degrees
• mirror_x – mirror in x-axis direction
• mirror_y – mirror in y-axis direction
• merge_control – how to order filled polygons, see MergeControl
Returns: SVG content as str
ezdxf.addons.hpgl2.api.to_pdf(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
False, merge_control=MergeControl.AUTO) -> bytes
Exports the HPGL/2 commands of the byte stream b as PDF data.
The plot units (1 plu = 0.025mm) are converted to PDF units (1/72 inch) so the image has the size
of the original plot file.
HPGL/2’s merge control works at the pixel level and cannot be replicated by the backend, but to
prevent fillings from obscuring text, the filled polygons are sorted by luminance - this can be
forced or disabled by the argument merge_control, see also MergeControl enum.
Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/
Parameters
• b – plot file content as bytes
• rotation – rotation angle of 0, 90, 180 or 270 degrees
• mirror_x – mirror in x-axis direction
• mirror_y – mirror in y-axis direction
• merge_control – how to order filled polygons, see MergeControl
Returns: PDF content as bytes
ezdxf.addons.hpgl2.api.to_pixmap(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
False, merge_control=MergeControl.AUTO, fmt: str = 'png', dpi: int = 96) -> bytes
Exports the HPGL/2 commands of the byte stream b as pixel image.
Supported image formats:
┌─────┬───────────────────────────┐
│ png │ Portable Network Graphics │
├─────┼───────────────────────────┤
│ ppm │ Portable Pixmap │
├─────┼───────────────────────────┤
│ pbm │ Portable Bitmap │
└─────┴───────────────────────────┘
The plot units (1 plu = 0.025mm) are converted to dot per inch (dpi) so the image has the size of
the original plot file.
HPGL/2’s merge control works at the pixel level and cannot be replicated by the backend, but to
prevent fillings from obscuring text, the filled polygons are sorted by luminance - this can be
forced or disabled by the argument merge_control, see also MergeControl enum.
Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/
Parameters
• b – plot file content as bytes
• rotation – rotation angle of 0, 90, 180 or 270 degrees
• mirror_x – mirror in x-axis direction
• mirror_y – mirror in y-axis direction
• merge_control – how to order filled polygons, see MergeControl
• fmt – image format
• dpi – output resolution in dots per inch
Returns: image content as bytes
class ezdxf.addons.hpgl2.api.ColorMode
The color mode controls how color values are assigned to DXF entities
ACI Use the pen number as AutoCAD Color Index (ACI) for DXF entities, ignores the RGB color
values
RGB Use the pen number as AutoCAD Color Index (ACI) but also set the RGB color for DXF
entities, RGB color values have always higher priority than the ACI when displaying DXF
content.
class ezdxf.addons.hpgl2.api.MergeControl
Merge control enumeration.
NONE export filled polygons in print order
LUMINANCE
sort filled polygons by luminance
AUTO guess best order of filled polygons
The Low Level Functions and Classes
ezdxf.addons.hpgl2.api.hpgl2_commands(s: bytes) -> list[Command]
Low level plot file parser, extracts the HPGL/2 from the byte stream b.
IMPORTANT:
This parser expects the “Enter HPGL/2 mode” escape sequence to recognize HPGL/2 commands. The
sequence looks like this: [ESC]%1B, multiple variants of this sequence are supported.
The HPGL/2 commands are often mixed with the Printer Command Language (PCL) and/or the Raster Transfer
Language (RTL) commands in a single plot file.
Some plot files that contain pure HPGL/2 code do not contain the escape sequence “Enter HPGL/2 mode”,
without this sequence the HPGL/2 parser cannot recognize the beginning of the HPGL/2 code. Add the
ENTER_HPGL2_MODE sequence in front of the bytes stream to switch on the HPGL/2 manually, regardless of
whether the file is an HPGL/2 plot file or not, so be careful:
commands = hpgl2_commands(hpgl2.ENTER_HPGL2_MODE + data)
class ezdxf.addons.hpgl2.api.Interpreter(plotter: Plotter)
The Interpreter is the frontend for the Plotter class. The run() methods interprets the low level
HPGL commands from the hpgl2_commands() parser and sends the commands to the virtual plotter
device, which sends his output to a low level Backend class.
Most CAD application send a very restricted subset of commands to plotters, mostly just polylines
and filled polygons. Implementing the whole HPGL/2 command set is not worth the effort - unless
reality proofs otherwise.
Not implemented commands:
• the whole character group - text is send as filled polygons or polylines
• configuration group: IN, DF, RO, IW - the plotter is initialized by creating a new plotter
and page rotation is handled by the add-on itself
• polygon group: EA, ER, EW, FA, RR, WG, the rectangle and wedge commands
• line and fill attributes group: LA, RF, SM, SV, TR, UL, WU, linetypes and hatch patterns are
decomposed into simple lines by CAD applications
Parameters
plotter – virtual Plotter device
errors List of error messages occurred during the interpretation of the HPGL/2 commands.
not_implemented_commands
List of all unsupported/ignored commands from the input stream.
run(commands: list[Command]) -> None
Interprets the low level HPGL commands from the hpgl2_commands() parser and sends the
commands to the virtual plotter device.
disable_commands(commands: Iterable[str]) -> None
Disable commands manually, like the scaling command [“SC”, “IP”, “IR”]. This is a feature
for experts, because disabling commands which changes the pen location may distort or
destroy the plotter output.
class ezdxf.addons.hpgl2.api.Plotter(backend: Backend)
The Plotter class represents a virtual plotter device.
The HPGL/2 commands send by the Interpreter are processed into simple polylines and filled
polygons and send to low level Backend.
HPGL/2 uses a units system called “Plot Units”:
• 1 plot unit (plu) = 0.025mm
• 40 plu = 1 mm
• 1016 plu = 1 inch
The Plotter device does not support font rendering and page rotation (RO). The scaling commands
IP, RP, SC are supported.
Recorder
class ezdxf.addons.hpgl2.api.Recorder
The Recorder class records the output of the Plotter class.
All input coordinates are page coordinates:
• 1 plot unit (plu) = 0.025mm
• 40 plu = 1 mm
• 1016 plu = 1 inch
player() -> Player
Returns a Player instance with the original recordings. Make a copy of this player to
protect the original recordings from being modified:
safe_player = recorder.player().copy()
draw_polyline(properties: Properties, points: Sequence[Vec2]) -> None
Draws a polyline from a sequence points. The input coordinates are page coordinates in plot
units. The points sequence can contain 0 or more points!
Parameters
• properties – display Properties for the polyline
• points – sequence of ezdxf.math.Vec2 instances
draw_paths(properties: Properties, paths: Sequence[Path], filled: bool) -> None
Draws filled or outline paths from the sequence of paths. The input coordinates are page
coordinates in plot units. The paths sequence can contain 0 or more single Path instances.
Draws outline paths if Properties.FillType is NONE and filled paths otherwise.
Parameters
• properties – display Properties for the filled polygon
• paths – sequence of single ezdxf.path.Path instances
• filled – draw filled paths if True otherwise outline paths
Player
class ezdxf.addons.hpgl2.api.Player(records: list[DataRecord], properties: dict[int, Properties])
This class replays the recordings of the Recorder class on another backend. The class can modify
the recorded output.
copy() -> Self
Returns a new Player instance with a copy of recordings.
recordings() -> Iterator[tuple[RecordType, Properties, Any]]
Yields all recordings as (RecordType, Properties, Data) tuples.
The content of the Data field is determined by the enum RecordType:
• RecordType.POLYLINE returns a NumpyPoints2d instance
• RecordType.FILLED_POLYGON returns a tuple of NumpyPath2d instances
replay(backend: Backend) -> None
Replay the recording on another backend.
bbox() -> BoundingBox2d
Returns the bounding box of all recorded polylines and polygons as BoundingBox2d.
transform(m: Matrix44) -> None
Transforms the recordings by a transformation matrix m of type Matrix44.
sort_filled_paths() -> None
Sort filled paths by descending luminance (from light to dark).
This also changes the plot order in the way that all filled paths are plotted before
polylines and outline paths.
Properties
class ezdxf.addons.hpgl2.properties.Properties
Consolidated display properties.
pen_index
pen index as int
pen_color
pen color as RGB tuple
pen_width
pen width in millimeters (float)
fill_type
FillType of filled polygons
fill_method
FillMethod of filled polygons
fill_hatch_line_angle
fill hatch line angle in degrees
fill_hatch_line_spacing
fill hatch line distance in plotter units
fill_shading_density
fill shading density in percent from 0 to 100.
resolve_pen_color() -> RGB
Returns the final RGB pen color.
resolve_fill_color() -> RGB
Returns the final RGB fill color.
class ezdxf.addons.hpgl2.properties.FillType(value, names=None, *, module=None, qualname=None, type=None,
start=1, boundary=None)
Fill type enumeration.
NONE
SOLID
HATCHING
CROSS_HATCHING
SHADING
class ezdxf.addons.hpgl2.properties.FillMethod(value, names=None, *, module=None, qualname=None,
type=None, start=1, boundary=None)
Fill method enumeration.
EVEN_ODD
NONE_ZERO_WINDING
Exceptions
class ezdxf.addons.hpgl2.api.Hpgl2Error
Base exception for the hpgl2 add-on.
class ezdxf.addons.hpgl2.api.Hpgl2DataNotFound
No HPGL/2 data was found, maybe the “Enter HPGL/2 mode” escape sequence is missing.
class ezdxf.addons.hpgl2.api.EmptyDrawing
The HPGL/2 commands do not produce any content.
PyCSG
Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean operations like union and
intersection to combine 3D solids. This library implements CSG operations on meshes elegantly and
concisely using BSP trees, and is meant to serve as an easily understandable implementation of the
algorithm. All edge cases involving overlapping coplanar polygons in both solids are correctly handled.
Example for usage:
import ezdxf
from ezdxf.render.forms import cube, cylinder_2p
from ezdxf.addons.pycsg import CSG
# create new DXF document
doc = ezdxf.new()
msp = doc.modelspace()
# create same geometric primitives as MeshTransformer() objects
cube1 = cube()
cylinder1 = cylinder_2p(count=32, base_center=(0, -1, 0), top_center=(0, 1, 0), radius=.25)
# build solid union
union = CSG(cube1) + CSG(cylinder1)
# convert to mesh and render mesh to modelspace
union.mesh().render(msp, dxfattribs={'color': 1})
# build solid difference
difference = CSG(cube1) - CSG(cylinder1)
# convert to mesh, translate mesh and render mesh to modelspace
difference.mesh().translate(1.5).render(msp, dxfattribs={'color': 3})
# build solid intersection
intersection = CSG(cube1) * CSG(cylinder1)
# convert to mesh, translate mesh and render mesh to modelspace
intersection.mesh().translate(2.75).render(msp, dxfattribs={'color': 5})
doc.saveas('csg.dxf')
[image: Cube vs Cylinder] [image]
This CSG kernel supports only meshes as MeshBuilder objects, which can be created from and converted to
DXF Mesh entities.
This CSG kernel is not compatible with ACIS objects like Solid3d, Body, Surface or Region.
NOTE:
This is a pure Python implementation, don’t expect great performance and the implementation is based
on an unbalanced BSP tree, so in the case of RecursionError, increase the recursion limit:
import sys
actual_limit = sys.getrecursionlimit()
# default is 1000, increasing too much may cause a seg fault
sys.setrecursionlimit(10000)
... # do the CSG stuff
sys.setrecursionlimit(actual_limit)
CSG works also with spheres, but with really bad runtime behavior and most likely RecursionError
exceptions, and use quadrilaterals as body faces to reduce face count by setting argument quads to True.
import ezdxf
from ezdxf.render.forms import sphere, cube
from ezdxf.addons.pycsg import CSG
doc = ezdxf.new()
doc.set_modelspace_vport(6, center=(5, 0))
msp = doc.modelspace()
cube1 = cube().translate(-.5, -.5, -.5)
sphere1 = sphere(count=32, stacks=16, radius=.5, quads=True)
union = (CSG(cube1) + CSG(sphere1)).mesh()
union.render(msp, dxfattribs={'color': 1})
subtract = (CSG(cube1) - CSG(sphere1)).mesh().translate(2.5)
subtract.render(msp, dxfattribs={'color': 3})
intersection = (CSG(cube1) * CSG(sphere1)).mesh().translate(4)
intersection.render(msp, dxfattribs={'color': 5})
[image: Cube vs Sphere] [image]
Hard Core CSG - Menger Sponge Level 3 vs Sphere
Required runtime on an old Xeon E5-1620 Workstation @ 3.60GHz, with default recursion limit of 1000 on
Windows 10:
• CPython 3.8.1 64bit: ~60 seconds,
• pypy3 [PyPy 7.2.0] 32bit: ~6 seconds, and using __slots__ reduced runtime below 5 seconds, yes -
pypy is worth a look for long running scripts!
from ezdxf.render.forms import sphere
from ezdxf.addons import MengerSponge
from ezdxf.addons.pycsg import CSG
doc = ezdxf.new()
doc.layers.new('sponge', dxfattribs={'color': 5})
doc.layers.new('sphere', dxfattribs={'color': 6})
doc.set_modelspace_vport(6, center=(5, 0))
msp = doc.modelspace()
sponge1 = MengerSponge(level=3).mesh()
sphere1 = sphere(count=32, stacks=16, radius=.5, quads=True).translate(.25, .25, 1)
subtract = (CSG(sponge1, meshid=1) - CSG(sphere1, meshid=2))
# get mesh result by id
subtract.mesh(1).render(msp, dxfattribs={'layer': 'sponge'})
subtract.mesh(2).render(msp, dxfattribs={'layer': 'sphere'})
[image: Menger Sponge vs Sphere] [image]
CSG Class
class ezdxf.addons.pycsg.CSG(mesh: MeshBuilder, meshid: int = 0)
Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean operations like union
and intersection to combine 3D solids. This class implements CSG operations on meshes.
New 3D solids are created from MeshBuilder objects and results can be exported as MeshTransformer
objects to ezdxf by method mesh().
Parameters
• mesh – ezdxf.render.MeshBuilder or inherited object
• meshid – individual mesh ID to separate result meshes, 0 is default
mesh(meshid: int = 0) -> MeshTransformer
Returns a ezdxf.render.MeshTransformer object.
Parameters
meshid – individual mesh ID, 0 is default
union(other: CSG) -> CSG
Return a new CSG solid representing space in either this solid or in the solid other.
Neither this solid nor the solid other are modified:
A.union(B)
+-------+ +-------+
| | | |
| A | | |
| +--+----+ = | +----+
+----+--+ | +----+ |
| B | | |
| | | |
+-------+ +-------+
__add__()
union = A + B
subtract(other: CSG) -> CSG
Return a new CSG solid representing space in this solid but not in the solid other. Neither
this solid nor the solid other are modified:
A.subtract(B)
+-------+ +-------+
| | | |
| A | | |
| +--+----+ = | +--+
+----+--+ | +----+
| B |
| |
+-------+
__sub__()
difference = A - B
intersect(other: CSG) -> CSG
Return a new CSG solid representing space both this solid and in the solid other. Neither
this solid nor the solid other are modified:
A.intersect(B)
+-------+
| |
| A |
| +--+----+ = +--+
+----+--+ | +--+
| B |
| |
+-------+
__mul__()
intersection = A * B
inverse() -> CSG
Return a new CSG solid with solid and empty space switched. This solid is not modified.
License
• Original implementation csg.js, Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT
license.
• Python port pycsg, Copyright (c) 2012 Tim Knip (http://www.floorplanner.com), under the MIT license.
• Additions by Alex Pletzer (Pennsylvania State University)
• Integration as ezdxf add-on, Copyright (c) 2020, Manfred Moitzi, MIT License.
Plot Style Files (CTB/STB)
CTB and STB files store plot styles used by AutoCAD and BricsCAD for printing and plotting.
If the plot style table is attached to a Paperspace or the Modelspace, a change of a plot style affects
any object that uses that plot style. CTB files contain color dependent plot style tables, STB files
contain named plot style tables.
SEE ALSO:
• Using plot style tables in AutoCAD
• AutoCAD Plot Style Table Editor
• BricsCAD Plot Style Table Editor
• AUTODESK KNOWLEDGE NETWORK: How to install CTB files in AutoCAD
ezdxf.addons.acadctb.load(filename: str | PathLike) -> ColorDependentPlotStyles | NamedPlotStyles
Load the CTB or STB file filename from file system.
ezdxf.addons.acadctb.new_ctb() -> ColorDependentPlotStyles
Create a new CTB file.
ezdxf.addons.acadctb.new_stb() -> NamedPlotStyles
Create a new STB file.
ColorDependentPlotStyles
Color dependent plot style table (CTB file), table entries are PlotStyle objects.
class ezdxf.addons.acadctb.ColorDependentPlotStyles
description
Custom description of plot style file.
scale_factor
Specifies the factor by which to scale non-ISO linetypes and fill patterns.
apply_factor
Specifies whether or not you want to apply the scale_factor.
custom_lineweight_display_units
Set 1 for showing lineweight in inch in AutoCAD CTB editor window, but lineweights are
always defined in millimeters.
lineweights
Lineweights table as array.array
__getitem__(aci: int) -> PlotStyle
Returns PlotStyle for AutoCAD Color Index (ACI) aci.
__iter__()
Iterable of all plot styles.
new_style(aci: int, data: dict | None = None) -> PlotStyle
Set aci to new attributes defined by data dict.
Parameters
• aci – AutoCAD Color Index (ACI)
• data – dict of PlotStyle attributes: description, color, physical_pen_number,
virtual_pen_number, screen, linepattern_size, linetype, adaptive_linetype,
lineweight, end_style, join_style, fill_style
get_lineweight(aci: int)
Returns the assigned lineweight for PlotStyle aci in millimeter.
get_lineweight_index(lineweight: float) -> int
Get index of lineweight in the lineweight table or append lineweight to lineweight table.
get_table_lineweight(index: int) -> float
Returns lineweight in millimeters of lineweight table entry index.
Parameters
index – lineweight table index = PlotStyle.lineweight
Returns
lineweight in mm or 0.0 for use entity lineweight
set_table_lineweight(index: int, lineweight: float) -> int
Argument index is the lineweight table index, not the AutoCAD Color Index (ACI).
Parameters
• index – lineweight table index = PlotStyle.lineweight
• lineweight – in millimeters
save() Save CTB file as filename to the file system.
write(stream: BinaryIO) -> None
Compress and write CTB file to binary stream.
NamedPlotStyles
Named plot style table (STB file), table entries are PlotStyle objects.
class ezdxf.addons.acadctb.NamedPlotStyles
description
Custom description of plot style file.
scale_factor
Specifies the factor by which to scale non-ISO linetypes and fill patterns.
apply_factor
Specifies whether or not you want to apply the scale_factor.
custom_lineweight_display_units
Set 1 for showing lineweight in inch in AutoCAD CTB editor window, but lineweights are
always defined in millimeters.
lineweights
Lineweights table as array.array
__getitem__(name: str) -> PlotStyle
Returns PlotStyle by name.
__delitem__(name: str) -> None
Delete plot style name. Plot style 'Normal' is not deletable.
__iter__() -> Iterable[str]
Iterable of all plot style names.
new_style(name: str, data: dict | None = None, localized_name: str | None = None) -> PlotStyle
Create new class:PlotStyle name by attribute dict data, replaces existing class:PlotStyle
objects.
Parameters
• name – plot style name
• localized_name – name shown in plot style editor, uses name if None
• data – dict of PlotStyle attributes: description, color, physical_pen_number,
virtual_pen_number, screen, linepattern_size, linetype, adaptive_linetype,
lineweight, end_style, join_style, fill_style
get_lineweight(name: str)
Returns the assigned lineweight for PlotStyle name in millimeter.
get_lineweight_index(lineweight: float) -> int
Get index of lineweight in the lineweight table or append lineweight to lineweight table.
get_table_lineweight(index: int) -> float
Returns lineweight in millimeters of lineweight table entry index.
Parameters
index – lineweight table index = PlotStyle.lineweight
Returns
lineweight in mm or 0.0 for use entity lineweight
set_table_lineweight(index: int, lineweight: float) -> int
Argument index is the lineweight table index, not the AutoCAD Color Index (ACI).
Parameters
• index – lineweight table index = PlotStyle.lineweight
• lineweight – in millimeters
save() Save STB file as filename to the file system.
write()
Compress and write STB file to binary stream.
PlotStyle
class ezdxf.addons.acadctb.PlotStyle
index Table index (0-based). (int)
aci AutoCAD Color Index (ACI) in range from 1 to 255. Has no meaning for named plot styles.
(int)
description
Custom description of plot style. (str)
physical_pen_number
Specifies physical plotter pen, valid range from 1 to 32 or AUTOMATIC. (int)
virtual_pen_number
Only used by non-pen plotters and only if they are configured for virtual pens. valid range
from 1 to 255 or AUTOMATIC. (int)
screen Specifies the color intensity of the plot on the paper, valid range is from 0 to 100. (int)
If you select 100 the drawing will plotted with its full color intensity. In order for
screening to work, the dithering option must be active.
linetype
Overrides the entity linetype, default value is OBJECT_LINETYPE. (bool)
adaptive_linetype
True if a complete linetype pattern is more important than a correct linetype scaling,
default is True. (bool)
linepattern_size
Line pattern size, default = 0.5. (float)
lineweight
Overrides the entity lineWEIGHT, default value is OBJECT_LINEWEIGHT. This is an index into
the UserStyles.lineweights table. (int)
end_style
Line end cap style, see table below, default is END_STYLE_OBJECT (int)
join_style
Line join style, see table below, default is JOIN_STYLE_OBJECT (int)
fill_style
Line fill style, see table below, default is FILL_STYLE_OBJECT (int)
dithering
Depending on the capabilities of your plotter, dithering approximates the colors with dot
patterns. When this option is False, the colors are mapped to the nearest color, resulting
in a smaller range of colors when plotting.
Dithering is available only whether you select the object’s color or assign a plot style
color.
grayscale
Plot colors in grayscale. (bool)
Default Line Weights
┌────┬──────┐
│ # │ [mm] │
├────┼──────┤
│ 0 │ 0.00 │
├────┼──────┤
│ 1 │ 0.05 │
├────┼──────┤
│ 2 │ 0.09 │
├────┼──────┤
│ 3 │ 0.10 │
├────┼──────┤
│ 4 │ 0.13 │
├────┼──────┤
│ 5 │ 0.15 │
├────┼──────┤
│ 6 │ 0.18 │
├────┼──────┤
│ 7 │ 0.20 │
├────┼──────┤
│ 8 │ 0.25 │
├────┼──────┤
│ 9 │ 0.30 │
├────┼──────┤
│ 10 │ 0.35 │
├────┼──────┤
│ 11 │ 0.40 │
├────┼──────┤
│ 12 │ 0.45 │
├────┼──────┤
│ 13 │ 0.50 │
├────┼──────┤
│ 14 │ 0.53 │
├────┼──────┤
│ 15 │ 0.60 │
├────┼──────┤
│ 16 │ 0.65 │
├────┼──────┤
│ 17 │ 0.70 │
├────┼──────┤
│ 18 │ 0.80 │
├────┼──────┤
│ 19 │ 0.90 │
├────┼──────┤
│ 20 │ 1.00 │
├────┼──────┤
│ 21 │ 1.06 │
├────┼──────┤
│ 22 │ 1.20 │
├────┼──────┤
│ 23 │ 1.40 │
├────┼──────┤
│ 24 │ 1.58 │
├────┼──────┤
│ 25 │ 2.00 │
├────┼──────┤
│ 26 │ 2.11 │
└────┴──────┘
Predefined Values
ezdxf.addons.acadctb.AUTOMATIC
ezdxf.addons.acadctb.OBJECT_LINEWEIGHT
ezdxf.addons.acadctb.OBJECT_LINETYPE
ezdxf.addons.acadctb.OBJECT_COLOR
ezdxf.addons.acadctb.OBJECT_COLOR2
Line End Style
[image]
┌───────────────────┬───┐
│ END_STYLE_BUTT │ 0 │
├───────────────────┼───┤
│ END_STYLE_SQUARE │ 1 │
├───────────────────┼───┤
│ END_STYLE_ROUND │ 2 │
├───────────────────┼───┤
│ END_STYLE_DIAMOND │ 3 │
├───────────────────┼───┤
│ END_STYLE_OBJECT │ 4 │
└───────────────────┴───┘
Line Join Style
[image]
┌────────────────────┬───┐
│ JOIN_STYLE_MITER │ 0 │
├────────────────────┼───┤
│ JOIN_STYLE_BEVEL │ 1 │
├────────────────────┼───┤
│ JOIN_STYLE_ROUND │ 2 │
├────────────────────┼───┤
│ JOIN_STYLE_DIAMOND │ 3 │
├────────────────────┼───┤
│ JOIN_STYLE_OBJECT │ 5 │
└────────────────────┴───┘
Fill Style
[image]
┌────────────────────────────┬────┐
│ FILL_STYLE_SOLID │ 64 │
├────────────────────────────┼────┤
│ FILL_STYLE_CHECKERBOARD │ 65 │
├────────────────────────────┼────┤
│ FILL_STYLE_CROSSHATCH │ 66 │
├────────────────────────────┼────┤
│ FILL_STYLE_DIAMONDS │ 67 │
├────────────────────────────┼────┤
│ FILL_STYLE_HORIZONTAL_BARS │ 68 │
├────────────────────────────┼────┤
│ FILL_STYLE_SLANT_LEFT │ 69 │
├────────────────────────────┼────┤
│ FILL_STYLE_SLANT_RIGHT │ 70 │
├────────────────────────────┼────┤
│ FILL_STYLE_SQUARE_DOTS │ 71 │
├────────────────────────────┼────┤
│ FILL_STYLE_VERICAL_BARS │ 72 │
├────────────────────────────┼────┤
│ FILL_STYLE_OBJECT │ 73 │
└────────────────────────────┴────┘
Linetypes
[image] [image]
─────────────────────────────────────────────
Linetype name Value
─────────────────────────────────────────────
Solid 0
─────────────────────────────────────────────
Dashed 1
─────────────────────────────────────────────
Dotted 2
─────────────────────────────────────────────
Dash Dot 3
─────────────────────────────────────────────
Short Dash 4
─────────────────────────────────────────────
Medium Dash 5
─────────────────────────────────────────────
Long Dash 6
─────────────────────────────────────────────
Short Dash x2 7
─────────────────────────────────────────────
Medium Dash x2 8
─────────────────────────────────────────────
Long Dash x2 9
─────────────────────────────────────────────
Medium Lang Dash 10
─────────────────────────────────────────────
Medium Dash Short Dash Short Dash 11
─────────────────────────────────────────────
Long Dash Short Dash 12
─────────────────────────────────────────────
Long Dash Dot Dot 13
─────────────────────────────────────────────
Long Dash Dot 14
─────────────────────────────────────────────
Medium Dash Dot Short Dash Dot 15
─────────────────────────────────────────────
Sparse Dot 16
─────────────────────────────────────────────
ISO Dash 17
─────────────────────────────────────────────
ISO Dash Space 18
─────────────────────────────────────────────
ISO Long Dash Dot 19
─────────────────────────────────────────────
ISO Long Dash Double Dot 20
─────────────────────────────────────────────
ISO Long Dash Triple Dot 21
─────────────────────────────────────────────
ISO Dot 22
─────────────────────────────────────────────
ISO Long Dash Short Dash 23
─────────────────────────────────────────────
ISO Long Dash Double Short Dash 24
─────────────────────────────────────────────
ISO Dash Dot 25
─────────────────────────────────────────────
ISO Double Dash Dot 26
─────────────────────────────────────────────
ISO Dash Double Dot 27
─────────────────────────────────────────────
ISO Double Dash Double Dot 28
─────────────────────────────────────────────
ISO Dash Triple Dot 29
─────────────────────────────────────────────
ISO Double Dash Triple Dot 30
─────────────────────────────────────────────
Use entity linetype 31
┌───────────────────────────────────┬───────┐
│ │ │
Showcase Forms │ │ │
MengerSponge │ │ │
Build a 3D Menger sponge. │ │ │
│ │ │
--
DXF INTERNALS
• DXF Reference provided by Autodesk.
• DXF Developer Documentation provided by Autodesk.
Basic DXF Structures
DXF File Encoding
DXF R2004 and prior
Drawing files of DXF R2004 (AC1018) and prior are saved as ASCII files with the encoding set by the
header variable $DWGCODEPAGE, which is ANSI_1252 by default if $DWGCODEPAGE is not set.
Characters used in the drawing which do not exist in the chosen ASCII encoding are encoded as unicode
characters with the schema \U+nnnn. see Unicode table
Known $DWGCODEPAGE encodings
┌───────────┬────────┬────────────────┐
│ DXF │ Python │ Name │
├───────────┼────────┼────────────────┤
│ ANSI_874 │ cp874 │ Thai │
├───────────┼────────┼────────────────┤
│ ANSI_932 │ cp932 │ Japanese │
├───────────┼────────┼────────────────┤
│ ANSI_936 │ gbk │ UnifiedChinese │
├───────────┼────────┼────────────────┤
│ ANSI_949 │ cp949 │ Korean │
├───────────┼────────┼────────────────┤
│ ANSI_950 │ cp950 │ TradChinese │
├───────────┼────────┼────────────────┤
│ ANSI_1250 │ cp1250 │ CentralEurope │
├───────────┼────────┼────────────────┤
│ ANSI_1251 │ cp1251 │ Cyrillic │
├───────────┼────────┼────────────────┤
│ ANSI_1252 │ cp1252 │ WesternEurope │
├───────────┼────────┼────────────────┤
│ ANSI_1253 │ cp1253 │ Greek │
├───────────┼────────┼────────────────┤
│ ANSI_1254 │ cp1254 │ Turkish │
├───────────┼────────┼────────────────┤
│ ANSI_1255 │ cp1255 │ Hebrew │
├───────────┼────────┼────────────────┤
│ ANSI_1256 │ cp1256 │ Arabic │
├───────────┼────────┼────────────────┤
│ ANSI_1257 │ cp1257 │ Baltic │
├───────────┼────────┼────────────────┤
│ ANSI_1258 │ cp1258 │ Vietnam │
└───────────┴────────┴────────────────┘
DXF R2007 and later
Starting with DXF R2007 (AC1021) the drawing file is UTF-8 encoded, the header variable $DWGCODEPAGE is
still in use, but I don’t know, if the setting still has any meaning.
Encoding characters in the unicode schema \U+nnnn is still functional.
SEE ALSO:
String value encoding
DXF Tags
A Drawing Interchange File is simply an ASCII text file with a file type of .dxf and special formatted
text. The basic file structure are DXF tags, a DXF tag consist of a DXF group code as an integer value on
its own line and a the DXF value on the following line. In the ezdxf documentation DXF tags will be
written as (group code, value).
With the introduction of extended symbol names in DXF R2000, the 255-character limit for strings has been
increased to 2049 single-byte characters not including the newline at the end of the line. Nonetheless
its safer to use only strings with 255 and less characters, because its not clear if this fact is true
for ALL string group codes or only for symbols like layer- or text style names and not all 3rd party
libraries may handle this fact correct. The MTEXT content and binary data is still divided into chunks
with less than 255 characters.
Group codes are indicating the value type:
┌────────────┬───────────────────────────────────────┐
│ Group Code │ Value Type │
├────────────┼───────────────────────────────────────┤
│ 0-9 │ String │
├────────────┼───────────────────────────────────────┤
│ 10-39 │ Double precision 3D point value │
├────────────┼───────────────────────────────────────┤
│ 40-59 │ Double-precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 60-79 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 90-99 │ 32-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 100 │ String │
├────────────┼───────────────────────────────────────┤
│ 102 │ String │
├────────────┼───────────────────────────────────────┤
│ 105 │ String representing hexadecimal (hex) │
│ │ handle value │
├────────────┼───────────────────────────────────────┤
│ 110-119 │ Double precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 120-129 │ Double precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 130-139 │ Double precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 140-149 │ Double precision scalar │
│ │ floating-point value │
├────────────┼───────────────────────────────────────┤
│ 160-169 │ 64-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 170-179 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 210-239 │ Double-precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 270-279 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 280-289 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 290-299 │ Boolean flag value │
├────────────┼───────────────────────────────────────┤
│ 300-309 │ Arbitrary text string │
├────────────┼───────────────────────────────────────┤
│ 310-319 │ String representing hex value of │
│ │ binary chunk │
├────────────┼───────────────────────────────────────┤
│ 320-329 │ Arbitrary pointer, hex object ID, not │
│ │ translated during INSERT and XREF │
│ │ operations │
├────────────┼───────────────────────────────────────┤
│ 330-339 │ Soft-pointer, hex object ID, │
│ │ translated during INSERT and XREF │
│ │ operations │
├────────────┼───────────────────────────────────────┤
│ 340-349 │ Hard-pointer, hex object ID, │
│ │ translated during INSERT and XREF │
│ │ operations │
├────────────┼───────────────────────────────────────┤
│ 350-359 │ Soft-owner, hex object ID, translated │
│ │ during INSERT and XREF operations │
├────────────┼───────────────────────────────────────┤
│ 360-369 │ Hard-owner, hex object ID, translated │
│ │ during INSERT and XREF operations │
├────────────┼───────────────────────────────────────┤
│ 370-379 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 380-389 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 390-399 │ String representing hex handle value │
├────────────┼───────────────────────────────────────┤
│ 400-409 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 410-419 │ String │
├────────────┼───────────────────────────────────────┤
│ 420-429 │ 32-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 430-439 │ String │
├────────────┼───────────────────────────────────────┤
│ 440-449 │ 32-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 450-459 │ Long │
├────────────┼───────────────────────────────────────┤
│ 460-469 │ Double-precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 470-479 │ String │
├────────────┼───────────────────────────────────────┤
│ 480-481 │ Hard-pointer, hex object ID, │
│ │ translated during INSERT and XREF │
│ │ operations │
├────────────┼───────────────────────────────────────┤
│ 999 │ Comment (string) │
├────────────┼───────────────────────────────────────┤
│ 1000-1009 │ String │
├────────────┼───────────────────────────────────────┤
│ 1010-1059 │ Double-precision floating-point value │
├────────────┼───────────────────────────────────────┤
│ 1060-1070 │ 16-bit integer value │
├────────────┼───────────────────────────────────────┤
│ 1071 │ 32-bit integer value │
└────────────┴───────────────────────────────────────┘
Explanation for some important group codes:
┌───────────────┬───────────────────────────────────────┐
│ Group Code │ Meaning │
├───────────────┼───────────────────────────────────────┤
│ 0 │ DXF structure tag, entity start/end │
│ │ or table entries │
├───────────────┼───────────────────────────────────────┤
│ 1 │ The primary text value for an entity │
├───────────────┼───────────────────────────────────────┤
│ 2 │ A name: Attribute tag, Block name, │
│ │ and so on. Also used to identify a │
│ │ DXF section or table name. │
├───────────────┼───────────────────────────────────────┤
│ 3-4 │ Other textual or name values │
├───────────────┼───────────────────────────────────────┤
│ 5 │ Entity handle as hex string (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 6 │ Line type name (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 7 │ Text style name (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 8 │ Layer name (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 9 │ Variable name identifier (used only │
│ │ in HEADER section of the DXF file) │
├───────────────┼───────────────────────────────────────┤
│ 10 │ Primary X coordinate (start point of │
│ │ a Line or Text entity, center of a │
│ │ Circle, etc.) │
├───────────────┼───────────────────────────────────────┤
│ 11-18 │ Other X coordinates │
├───────────────┼───────────────────────────────────────┤
│ 20 │ Primary Y coordinate. 2n values │
│ │ always correspond to 1n values and │
│ │ immediately follow them in the file │
│ │ (expected by ezdxf!) │
├───────────────┼───────────────────────────────────────┤
│ 21-28 │ Other Y coordinates │
├───────────────┼───────────────────────────────────────┤
│ 30 │ Primary Z coordinate. 3n values │
│ │ always correspond to 1n and 2n values │
│ │ and immediately follow them in the │
│ │ file (expected by ezdxf!) │
├───────────────┼───────────────────────────────────────┤
│ 31-38 │ Other Z coordinates │
├───────────────┼───────────────────────────────────────┤
│ 39 │ This entity’s thickness if nonzero │
│ │ (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 40-48 │ Float values (text height, scale │
│ │ factors, etc.) │
├───────────────┼───────────────────────────────────────┤
│ 49 │ Repeated value - multiple 49 groups │
│ │ may appear in one entity for variable │
│ │ length tables (such as the dash │
│ │ lengths in the LTYPE table). A 7x │
│ │ group always appears before the first │
│ │ 49 group to specify the table length │
├───────────────┼───────────────────────────────────────┤
│ 50-58 │ Angles in degree │
├───────────────┼───────────────────────────────────────┤
│ 62 │ Color number (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 66 │ “Entities follow” flag (fixed), only │
│ │ in INSERT and POLYLINE entities │
├───────────────┼───────────────────────────────────────┤
│ 67 │ Identifies whether entity is in │
│ │ modelspace (0) or paperspace (1) │
├───────────────┼───────────────────────────────────────┤
│ 68 │ Identifies whether viewport is on but │
│ │ fully off screen, is not active, or │
│ │ is off │
├───────────────┼───────────────────────────────────────┤
│ 69 │ Viewport identification number │
├───────────────┼───────────────────────────────────────┤
│ 70-78 │ Integer values such as repeat counts, │
│ │ flag bits, or modes │
├───────────────┼───────────────────────────────────────┤
│ 105 │ DIMSTYLE entity handle as hex string │
│ │ (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 210, 220, 230 │ X, Y, and Z components of extrusion │
│ │ direction (fixed) │
├───────────────┼───────────────────────────────────────┤
│ 310 │ Proxy entity graphics as binary │
│ │ encoded data │
├───────────────┼───────────────────────────────────────┤
│ 330 │ Owner handle as hex string │
├───────────────┼───────────────────────────────────────┤
│ 347 │ MATERIAL handle as hex string │
├───────────────┼───────────────────────────────────────┤
│ 348 │ VISUALSTYLE handle as hex string │
├───────────────┼───────────────────────────────────────┤
│ 370 │ Lineweight in mm times 100 (e.g. │
│ │ 0.13mm = 13). │
├───────────────┼───────────────────────────────────────┤
│ 390 │ PLOTSTYLE handle as hex string │
├───────────────┼───────────────────────────────────────┤
│ 420 │ True color value as 0x00RRGGBB 24-bit │
│ │ value │
├───────────────┼───────────────────────────────────────┤
│ 430 │ Color name as string │
├───────────────┼───────────────────────────────────────┤
│ 440 │ Transparency value 0x020000TT 0 = │
│ │ fully transparent / 255 = opaque │
├───────────────┼───────────────────────────────────────┤
│ 999 │ Comments │
└───────────────┴───────────────────────────────────────┘
For explanation of all group codes see: DXF Group Codes in Numerical Order Reference provided by Autodesk
Extended Data
DXF R2018 Reference
Extended data (XDATA) is created by AutoLISP or ObjectARX applications but any other application like
ezdxf can also define XDATA. If an entity contains extended data, it follows the entity’s normal
definition.
But extended group codes (>=1000) can appear before the XDATA section, an example is the
BLOCKBASEPOINTPARAMETER entity in AutoCAD Civil 3D or AutoCAD Map 3D.
┌──────────────────┬───────────────────────────────────────┐
│ Group Code │ Description │
├──────────────────┼───────────────────────────────────────┤
│ 1000 │ Strings in extended data can be up to │
│ │ 255 bytes long (with the 256th byte │
│ │ reserved for the null character) │
├──────────────────┼───────────────────────────────────────┤
│ 1001 │ (fixed) Registered application name │
│ │ (ASCII string up to 31 bytes long) │
│ │ for XDATA │
├──────────────────┼───────────────────────────────────────┤
│ 1002 │ (fixed) An extended data control │
│ │ string can be either '{' or '}'. │
│ │ These braces enable applications to │
│ │ organize their data by subdividing │
│ │ the data into lists. Lists can be │
│ │ nested. │
├──────────────────┼───────────────────────────────────────┤
│ 1003 │ Name of the layer associated with the │
│ │ extended data │
├──────────────────┼───────────────────────────────────────┤
│ 1004 │ Binary data is organized into │
│ │ variable-length chunks. The maximum │
│ │ length of each chunk is 127 bytes. In │
│ │ ASCII DXF files, binary data is │
│ │ represented as a string of │
│ │ hexadecimal digits, two per binary │
│ │ byte │
├──────────────────┼───────────────────────────────────────┤
│ 1005 │ Database Handle of entities in the │
│ │ drawing database, see also: About │
│ │ 1005 Group Codes │
├──────────────────┼───────────────────────────────────────┤
│ 1010, 1020, 1030 │ Three real values, in the order X, Y, │
│ │ Z. They can be used as a point or │
│ │ vector record that will not be │
│ │ modified at any transformation of the │
│ │ entity. │
├──────────────────┼───────────────────────────────────────┤
│ 1011, 1021, 1031 │ a WCS point that is moved, scaled, │
│ │ rotated and mirrored along with the │
│ │ entity │
├──────────────────┼───────────────────────────────────────┤
│ 1012, 1012, 1022 │ a WCS displacement that is scaled, │
│ │ rotated and mirrored along with the │
│ │ entity, but is not moved │
├──────────────────┼───────────────────────────────────────┤
│ 1013, 1023, 1033 │ a WCS direction that is rotated and │
│ │ mirrored along with the entity, but │
│ │ is not moved or scaled │
├──────────────────┼───────────────────────────────────────┤
│ 1040 │ A real value │
├──────────────────┼───────────────────────────────────────┤
│ 1041 │ Distance, a real value that is scaled │
│ │ along with the parent entity │
├──────────────────┼───────────────────────────────────────┤
│ 1042 │ Scale Factor, also a real value that │
│ │ is scaled along with the parent. The │
│ │ difference between a distance and a │
│ │ scale factor is application-defined │
├──────────────────┼───────────────────────────────────────┤
│ 1070 │ A 16-bit integer (signed or unsigned) │
├──────────────────┼───────────────────────────────────────┤
│ 1071 │ A 32-bit signed (long) integer │
└──────────────────┴───────────────────────────────────────┘
The (1001, …) tag indicates the beginning of extended data. In contrast to normal entity data, with
extended data the same group code can appear multiple times, and order is important.
Extended data is grouped by registered application name. Each registered application group begins with a
(1001, APPID) tag, with the application name as APPID string value. Registered application names
correspond to APPID symbol table entries.
An application can use as many APPID names as needed. APPID names are permanent, although they can be
purged if they aren’t currently used in the drawing. Each APPID name can have no more than one data
group attached to each entity. Within an application group, the sequence of extended data groups and
their meaning is defined by the application.
String value encoding
String values stored in a DXF file is plain ASCII or UTF-8, AutoCAD also supports CIF (Common Interchange
Format) and MIF (Maker Interchange Format) encoding. The UTF-8 format is only supported in DXF R2007 and
later.
Ezdxf on import converts all strings into Python unicode strings without encoding or decoding CIF/MIF.
String values containing Unicode characters are represented with control character sequences \U+nnnn.
(e.g. r'TEST\U+7F3A\U+4E4F\U+89E3\U+91CA\U+6B63THIS\U+56FE')
To support the DXF unicode encoding ezdxf registers an encoding codec dxf_backslash_replace, defined in
ezdxf.lldxf.encoding().
String values can be stored with these dxf group codes:
• 0 - 9
• 100 - 101
• 300 - 309
• 410 - 419
• 430 - 439
• 470 - 479
• 999 - 1003
Multi tag text (MTEXT)
If the text string is less than 250 characters, all characters appear in tag (1, …). If the text string
is longer than 250 characters, the string is divided into 250-character chunks, which appear in one or
more (3, …) tags. If (3, …) tags are used, the last group is a (1, …) tag and has fewer than 250
characters:
3
... TwoHundredAndFifty Characters ....
3
... TwoHundredAndFifty Characters ....
1
less than TwoHundredAndFifty Characters
As far I know this is only supported by the MTEXT entity.
SEE ALSO:
DXF File Encoding
DXF R13 and later tag structure
With the introduction of DXF R13 Autodesk added additional group codes and DXF tag structures to the DXF
Standard.
Subclass Markers
Subclass markers (100, Subclass Name) divides DXF objects into several sections. Group codes can be
reused in different sections. A subclass ends with the following subclass marker or at the beginning of
xdata or the end of the object. See Subclass Marker Example in the DXF Reference.
Quote about group codes from the DXF reference
Some group codes that define an entity always appear; others are optional and appear only if their
values differ from the defaults.
Do not write programs that rely on the order given here. The end of an entity is indicated by the next
0 group, which begins the next entity or indicates the end of the section.
Note: Accommodating DXF files from future releases of AutoCAD will be easier if you write your DXF
processing program in a table-driven way, ignore undefined group codes, and make no assumptions about
the order of group codes in an entity. With each new AutoCAD release, new group codes will be added to
entities to accommodate additional features.
Usage of group codes in subclasses twice
Some later entities entities contains the same group code twice for different purposes, so order in the
sense of which one comes first is important. (e.g. ATTDEF group code 280)
Tag order is sometimes important especially for AutoCAD
In LWPOLYLINE the order of tags is important, if the count tag is not the first tag in the AcDbPolyline
subclass, AutoCAD will not close the polyline when the close flag is set, by the way other applications
like BricsCAD ignores the tag order and renders the polyline always correct.
Extension Dictionary
The extension dictionary is an optional sequence that stores the handle of a DICTIONARY object that
belongs to the current object, which in turn may contain entries. This facility allows attachment of
arbitrary database objects to any database object. Any object or entity may have this section.
The extension dictionary tag sequence:
102
{ACAD_XDICTIONARY
360
Hard-owner ID/handle to owner dictionary
102
}
Persistent Reactors
Persistent reactors are an optional sequence that stores object handles of objects registering themselves
as reactors on the current object. Any object or entity may have this section.
The persistent reactors tag sequence:
102
{ACAD_REACTORS
330
first Soft-pointer ID/handle to owner dictionary
330
second Soft-pointer ID/handle to owner dictionary
...
102
}
Application-Defined Codes
Starting at DXF R13, DXF objects can contain application-defined codes outside of XDATA. This
application-defined codes can contain any tag except (0, …) and (102, ‘{…’). “{YOURAPPID” means the APPID
string with an preceding “{”. The application defined data tag sequence:
102
{YOURAPPID
...
102
}
(102, 'YOURAPPID}') is also a valid closing tag:
102
{YOURAPPID
...
102
YOURAPPID}
All groups defined with a beginning (102, …) appear in the DXF reference before the first subclass
marker, I don’t know if these groups can appear after the first or any subclass marker. Ezdxf accepts
them at any position, and by default ezdxf adds new app data in front of the first subclass marker to the
first tag section of an DXF object.
Exception XRECORD: Tags with group code 102 and a value string without a preceding “{” or the scheme
“YOURAPPID}”, should be treated as usual group codes.
Embedded Objects
The concept of embedded objects was introduced with AutoCAD 2018 (DXF version AC1032) and this is the
only information I found about it at the Autodesk knowledge base: Embedded and Encapsulated Objects
Quote from Embedded and Encapsulated Objects:
For DXF filing, the embedded object must be filed out and in after all the data of the encapsulating
object has been filed out and in.
A separator is needed between the encapsulating object’s data and the subsequent embedded object’s
data. The separator must be similar in function to the group 0 or 100 in that it must cause the filer
to stop reading data. The normal DXF group code 0 cannot be used because DXF proxies use it to
determine when to stop reading data. The group code 100 could have been used, but it might have caused
confusion when manually reading a DXF file, and there was a need to distinguish when an embedded
object is about to be written out in order to do some internal bookkeeping. Therefore, the DXF group
code 101 was introduced.
Hard facts:
• Only used in ATTRIB, ATTDEF (embedded MTEXT) and MTEXT (columns) in DXF R2018.
• Embedded object start with (101, “Embedded Object”) tag
• Embedded object is appended to the encapsulated object
• Embedded object tags can contain any group code except the DXF structure tag (0, …)
Unconfirmed assumptions:
• The embedded object is written before the Extended Data. No examples for entities including embedded
objects and XDATA at the same time.
• XDATA sections replaced by embedded objects, at least for the MTEXT entity
• The encapsulating object can contain more than one embedded object.
• Embedded objects separated by (101, “Embedded Object”) tags
• every entity can contain embedded objects
Real world example from an AutoCAD 2018 file:
100 <<< start of encapsulating object
AcDbMText
10
2762.148
20
2327.073
30
0.0
40
2.5
41
18.852
46
0.0
71
1
72
5
1
{\fArial|b0|i0|c162|p34;CHANGE;\P\P\PTEXT}
73
1
44
1.0
101 <<< start of embedded object
Embedded Object
70
1
10
1.0
20
0.0
30
0.0
11
2762.148
21
2327.073
31
0.0
40
18.852
41
0.0
42
15.428
43
15.043
71
2
72
1
44
18.852
45
12.5
73
0
74
0
46
0.0
Handles
A handle is an arbitrary but in your DXF file unique hex value as string like ‘10FF’. It is common to to
use uppercase letters for hex numbers. Handle can have up to 16 hexadecimal digits (8 bytes).
For DXF R10 until R12 the usage of handles was optional. The header variable $HANDLING set to 1 indicate
the usage of handles, else $HANDLING is 0 or missing.
For DXF R13 and later the usage of handles is mandatory and the header variable $HANDLING was removed.
The $HANDSEED variable in the header section should be greater than the biggest handle used in the DXF
file, so a CAD application can assign handle values starting with the $HANDSEED value. But as always,
don’t rely on the header variable it could be wrong, AutoCAD ignores this value.
Handle Definition
Entity handle definition is always the (5, ...), except for entities of the DIMSTYLE table (105, ...),
because the DIMSTYLE entity has also a group code 5 tag for DIMBLK.
Handle Pointer
A pointer is a reference to a DXF object in the same DXF file. There are four types of pointers:
• Soft-pointer handle
• Hard-pointer handle
• Soft-owner handle
• Hard-owner handle
Also, a group code range for “arbitrary” handles is defined to allow convenient storage of handle values
that are unchanged at any operation (AutoCAD).
Pointer and Ownership
A pointer is a reference that indicates usage, but not possession or responsibility, for another object.
A pointer reference means that the object uses the other object in some way, and shares access to it. An
ownership reference means that an owner object is responsible for the objects for which it has an owner
handle. An object can have any number of pointer references associated with it, but it can have only one
owner.
Hard and Soft References
Hard references, whether they are pointer or owner, protect an object from being purged. Soft references
do not.
In AutoCAD, block definitions and complex entities are hard owners of their elements. A symbol table and
dictionaries are soft owners of their elements. Polyline entities are hard owners of their vertex and
seqend entities. Insert entities are hard owners of their attrib and seqend entities.
When establishing a reference to another object, it is recommended that you think about whether the
reference should protect an object from the PURGE command.
A hard- and soft pointers will be translated during INSERT and XREF operations.
Arbitrary Handles
Arbitrary handles are distinct in that they are not translated to session-persistent identifiers
internally, or to entity names in AutoLISP, and so on. They are stored as handles. When handle values are
translated in drawing-merge operations, arbitrary handles are ignored.
In all environments, arbitrary handles can be exchanged for entity names of the current drawing by means
of the handent functions. A common usage of arbitrary handles is to refer to objects in external DXF and
DWG files.
About 1005 Group Codes
(1005, ...) xdata have the same behavior and semantics as soft pointers, which means that they are
translated whenever the host object is merged into a different drawing. However, 1005 items are not
translated to session-persistent identifiers or internal entity names in AutoLISP and ObjectARX. They are
stored as handles.
When a drawing with handles and extended data handles is imported into another drawing using INSERT,
INSERT , XREF Bind, XBIND, or partial OPEN, the extended data handles are **translated* in the same
manner as their corresponding entity handles, thus maintaining their binding. This is also done in the
EXPLODE block operation or for any other AutoCAD operation. When AUDIT detects an extended data handle
that doesn’t match the handle of an entity in the drawing file, it is considered an error. If AUDIT is
fixing entities, it sets the handle to “0”
DXF File Structure
A DXF File is simply an ASCII text file with a file type of .dxf and special formatted text. The basic
file structure are DXF tags, a DXF tag consist of a DXF group code as an integer value on its own line
and a the DXF value on the following line. In the ezdxf documentation DXF tags will be written as (group
code, value). There exist a binary DXF format, but it seems that it is not often used and for reducing
file size, zipping is much more efficient. ezdxf does support reading binary encoded DXF files.
SEE ALSO:
For more information about DXF tags see: DXF Tags
A usual DXF file is organized in sections, starting with the DXF tag (0, ‘SECTION’) and ending with the
DXF tag (0, ‘ENDSEC’). The (0, ‘EOF’) tag signals the end of file.
1. HEADER: General information about the drawing is found in this section of the DXF file. Each
parameter has a variable name starting with ‘$’ and an associated value. Has to be the first section.
2. CLASSES: Holds the information for application defined classes. (DXF R13 and later)
3. TABLES:: Contains several tables for style and property definitions.
• Linetype table (LTYPE)
• Layer table (LAYER)
• Text Style table (STYLE)
• View table (VIEW): (IMHO) layout of the CAD working space, only interesting for interactive CAD
applications
• Viewport configuration table (VPORT): The VPORT table is unique in that it may contain several
entries with the same name (indicating a multiple-viewport configuration). The entries corresponding
to the active viewport configuration all have the name *ACTIVE. The first such entry describes the
current viewport.
• Dimension Style table (DIMSTYLE)
• User Coordinate System table (UCS) (IMHO) only interesting for interactive CAD applications
• Application Identification table (APPID): Table of names for all applications registered with a
drawing.
• Block Record table (BLOCK_RECORD) (DXF R13 and Later)
4. BLOCKS: Contains all block definitions. The block name *Model_Space or *MODEL_SPACE is reserved for
the drawing modelspace and the block name *Paper_Space or *PAPER_SPACE is reserved for the active
paperspace layout. Both block definitions are empty, the content of the modelspace and the active
paperspace is stored in the ENTITIES section. The entities of other layouts are stored in special
block definitions called *Paper_Spacennn, nnn is an arbitrary but unique number.
5. ENTITIES: Contains all graphical entities of the modelspace and the active paperspace layout. Entities
of other layouts are stored in the BLOCKS sections.
6. OBJECTS: Contains all non-graphical objects of the drawing (DXF R13 and later)
7. THUMBNAILIMAGE: Contains a preview image of the DXF file, it is optional and can usually be ignored.
(DXF R13 and later)
8. ACDSDATA: (DXF R2013 and later) No information in the DXF reference about this section
9. END OF FILE
For further information read the original DXF Reference.
Structure of a usual DXF R12 file:
0 <<< Begin HEADER section, has to be the first section
SECTION
2
HEADER
<<< Header variable items go here
0 <<< End HEADER section
ENDSEC
0 <<< Begin TABLES section
SECTION
2
TABLES
0
TABLE
2
VPORT
70 <<< viewport table maximum item count
<<< viewport table items go here
0
ENDTAB
0
TABLE
2
APPID, DIMSTYLE, LTYPE, LAYER, STYLE, UCS, VIEW, or VPORT
70 <<< Table maximum item count, a not reliable value and ignored by AutoCAD
<<< Table items go here
0
ENDTAB
0 <<< End TABLES section
ENDSEC
0 <<< Begin BLOCKS section
SECTION
2
BLOCKS
<<< Block definition entities go here
0 <<< End BLOCKS section
ENDSEC
0 <<< Begin ENTITIES section
SECTION
2
ENTITIES
<<< Drawing entities go here
0 <<< End ENTITIES section
ENDSEC
0 <<< End of file marker (required)
EOF
Minimal DXF Content
DXF R12
Contrary to the previous chapter, the DXF R12 format (AC1009) and prior requires just the ENTITIES
section:
0
SECTION
2
ENTITIES
0
ENDSEC
0
EOF
DXF R13/R14 and later
DXF version R13/14 and later needs much more DXF content than DXF R12.
Required sections: HEADER, CLASSES, TABLES, ENTITIES, OBJECTS
The HEADER section requires two entries:
• $ACADVER
• $HANDSEED
The CLASSES section can be empty, but some DXF entities requires class definitions to work in AutoCAD.
The TABLES section requires following tables:
• VPORT entry *ACTIVE is not required! Empty table is ok for AutoCAD.
• LTYPE with at least the following line types defined:
• BYBLOCK
• BYLAYER
• CONTINUOUS
• LAYER with at least an entry for layer ‘0’
• STYLE with at least an entry for style STANDARD
• VIEW can be empty
• UCS can be empty
• APPID with at least an entry for ACAD
• DIMSTYLE with at least an entry for style STANDARD
• BLOCK_RECORDS with two entries:
• *MODEL_SPACE
• *PAPER_SPACE
The BLOCKS section requires two BLOCKS:
• *MODEL_SPACE
• *PAPER_SPACE
The ENTITIES section can be empty.
The OBJECTS section requires following entities:
• DICTIONARY - the root dict - one entry named ACAD_GROUP
• DICTIONARY ACAD_GROUP can be empty
Minimal DXF to download: https://github.com/mozman/ezdxf/tree/master/examples_dxf
Data Model
Database Objects
(from the DXF Reference)
AutoCAD drawings consist largely of structured containers for database objects. Database objects each
have the following features:
• A handle whose value is unique to the drawing/DXF file, and is constant for the lifetime of the
drawing. This format has existed since AutoCAD Release 10, and as of AutoCAD Release 13, handles are
always enabled.
• An optional XDATA table, as entities have had since AutoCAD Release 11.
• An optional persistent reactor table.
• An optional ownership pointer to an extension dictionary which, in turn, owns subobjects placed in
it by an application.
Symbol tables and symbol table records are database objects and, thus, have a handle. They can also have
xdata and persistent reactors in their DXF records.
DXF R12 Data Model
The DXF R12 data model is identical to the file structure:
• HEADER section: common settings for the DXF drawing
• TABLES section: definitions for LAYERS, LINETYPE, STYLES ….
• BLOCKS section: block definitions and its content
• ENTITIES section: modelspace and paperspace content
References are realized by simple names. The INSERT entity references the BLOCK definition by the BLOCK
name, a TEXT entity defines the associated STYLE and LAYER by its name and so on, handles are not needed.
Layout association of graphical entities in the ENTITIES section by the paper_space tag (67, 0 or 1), 0
or missing tag means modelspace, 1 means paperspace. The content of BLOCK definitions is enclosed by the
BLOCK and the ENDBLK entity, no additional references are needed.
A clean and simple file structure and data model, which seems to be the reason why the DXF R12 Reference
(released 1992) is still a widely used file format and Autodesk/AutoCAD supports the format by reading
and writing DXF R12 files until today (DXF R13/R14 has no writing support by AutoCAD!).
TODO: list of available entities
SEE ALSO:
More information about the DXF DXF File Structure
DXF R13+ Data Model
With the DXF R13 file format, handles are mandatory and they are really used for organizing the new data
structures introduced with DXF R13.
The HEADER section is still the same with just more available settings.
The new CLASSES section contains AutoCAD specific data, has to be written like AutoCAD it does, but must
not be understood.
The TABLES section got a new BLOCK_RECORD table - see Block Management Structures for more information.
The BLOCKS sections is mostly the same, but with handles, owner tags and new ENTITY types. Not active
paperspace layouts store their content also in the BLOCKS section - see Layout Management Structures for
more information.
The ENTITIES section is also mostly same, but with handles, owner tags and new ENTITY types.
TODO: list of new available entities
And the new OBJECTS section - now its getting complicated!
Most information about the OBJECTS section is just guessed or gathered by trail and error, because the
documentation of the OBJECTS section and its objects in the DXF reference provided by Autodesk is very
shallow. This is also the reason why I started the DXF Internals section, may be it helps other
developers to start one or two steps above level zero.
The OBJECTS sections stores all the non-graphical entities of the DXF drawing. Non-graphical entities
from now on just called ‘DXF objects’ to differentiate them from graphical entities, just called
‘entities’. The OBJECTS section follows commonly the ENTITIES section, but this is not mandatory.
DXF R13 introduces several new DXF objects, which resides exclusive in the OBJECTS section, taken from
the DXF R14 reference, because I have no access to the DXF R13 reference, the DXF R13 reference is a
compiled .hlp file which can’t be read on Windows 10 or later, this a perfect example for not using
closed (proprietary) data formats ;):
• DICTIONARY: a general structural entity as a <name: handle> container
• ACDBDICTIONARYWDFLT: a DICTIONARY with a default value
• DICTIONARYVAR: used by AutoCAD to store named values in the database
• ACAD_PROXY_OBJECT: proxy object for entities created by other applications than AutoCAD
• GROUP: groups graphical entities without the need of a BLOCK definition
• IDBUFFER: just a list of references to objects
• IMAGEDEF: IMAGE definition structure, required by the IMAGE entity
• IMAGEDEF_REACTOR: also required by the IMAGE entity
• LAYER_INDEX: container for LAYER names
• MLINESTYLE
• OBJECT_PTR
• RASTERVARIABLES
• SPATIAL_INDEX: is always written out empty to a DXF file. This object can be ignored.
• SPATIAL_FILTER
• SORTENTSTABLE: control for regeneration/redraw order of entities
• XRECORD: used to store and manage arbitrary data. This object is similar in concept to XDATA but is
not limited by size or order. Not supported by R13c0 through R13c3.
Still missing the LAYOUT object, which is mandatory in DXF R2000 to manage multiple paperspace layouts. I
don’t know how DXF R13/R14 manages multiple layouts or if they even support this feature, but I don’t
care much about DXF R13/R14, because AutoCAD has no write support for this two formats anymore. Ezdxf
tries to upgrade this two DXF versions to DXF R2000 with the advantage of only two different data models
to support: DXF R12 and DXF R2000+
New objects introduced by DXF R2000:
• LAYOUT: management object for modelspace and multiple paperspace layouts
• ACDBPLACEHOLDER: surprise - just a place holder
New objects in DXF R2004:
• DIMASSOC
• LAYER_FILTER
• MATERIAL
• PLOTSETTINGS
• VBA_PROJECT
New objects in DXF R2007:
• DATATABLE
• FIELD
• LIGHTLIST
• RENDER
• RENDERENVIRONMENT
• MENTALRAYRENDERSETTINGS
• RENDERGLOBAL
• SECTION
• SUNSTUDY
• TABLESTYLE
• UNDERLAYDEFINITION
• VISUALSTYLE
• WIPEOUTVARIABLES
New objects in DXF R2013:
• GEODATA
New objects in DXF R2018:
• ACDBNAVISWORKSMODELDEF
Undocumented objects:
• SCALE
• ACDBSECTIONVIEWSTYLE
• FIELDLIST
Objects Organisation
Many objects in the OBJECTS section are organized in a tree-like structure of DICTIONARY objects.
Starting point for this data structure is the ‘root’ DICTIONARY with several entries to other DICTIONARY
objects. The root DICTIONARY has to be the first object in the OBJECTS section. The management dicts
for GROUP and LAYOUT objects are really important, but IMHO most of the other management tables are
optional and for the most use cases not necessary. Ezdxf creates only these entries in the root dict and
most of them pointing to an empty DICTIONARY:
• ACAD_COLOR: points to an empty DICTIONARY
• ACAD_GROUP: required
• ACAD_LAYOUT: required
• ACAD_MATERIAL: points to an empty DICTIONARY
• ACAD_MLEADERSTYLE: points to an empty DICTIONARY
• ACAD_MLINESTYLE: points to an empty DICTIONARY
• ACAD_PLOTSETTINGS: points to an empty DICTIONARY
• ACAD_PLOTSTYLENAME: required, points to ACDBDICTIONARYWDFLT with one entry: ‘Normal’
• ACAD_SCALELIST: points to an empty DICTIONARY
• ACAD_TABLESTYLE: points to an empty DICTIONARY
• ACAD_VISUALSTYLE: points to an empty DICTIONARY
Root DICTIONARY content for DXF R2018
0
SECTION
2 <<< start of the OBJECTS section
OBJECTS
0 <<< root DICTIONARY has to be the first object in the OBJECTS section
DICTIONARY
5 <<< handle
C
330 <<< owner tag
0 <<< always #0, has no owner
100
AcDbDictionary
281 <<< hard owner flag
1
3 <<< first entry
ACAD_CIP_PREVIOUS_PRODUCT_INFO
350 <<< handle to target (pointer)
78B <<< points to a XRECORD with product info about the creator application
3 <<< entry with unknown meaning, if I should guess: something with about colors ...
ACAD_COLOR
350
4FB <<< points to a DICTIONARY
3 <<< entry with unknown meaning
ACAD_DETAILVIEWSTYLE
350
7ED <<< points to a DICTIONARY
3 <<< GROUP management, mandatory in all DXF versions
ACAD_GROUP
350
4FC <<< points to a DICTIONARY
3 <<< LAYOUT management, mandatory if more than the *active* paperspace is used
ACAD_LAYOUT
350
4FD <<< points to a DICTIONARY
3 <<< MATERIAL management
ACAD_MATERIAL
350
4FE <<< points to a DICTIONARY
3 <<< MLEADERSTYLE management
ACAD_MLEADERSTYLE
350
4FF <<< points to a DICTIONARY
3 <<< MLINESTYLE management
ACAD_MLINESTYLE
350
500 <<< points to a DICTIONARY
3 <<< PLOTSETTINGS management
ACAD_PLOTSETTINGS
350
501 <<< points to a DICTIONARY
3 <<< plot style name management
ACAD_PLOTSTYLENAME
350
503 <<< points to a ACDBDICTIONARYWDFLT
3 <<< SCALE management
ACAD_SCALELIST
350
504 <<< points to a DICTIONARY
3 <<< entry with unknown meaning
ACAD_SECTIONVIEWSTYLE
350
7EB <<< points to a DICTIONARY
3 <<< TABLESTYLE management
ACAD_TABLESTYLE
350
505 <<< points to a DICTIONARY
3 <<< VISUALSTYLE management
ACAD_VISUALSTYLE
350
506 <<< points to a DICTIONARY
3 <<< entry with unknown meaning
ACDB_RECOMPOSE_DATA
350
7F3
3 <<< entry with unknown meaning
AcDbVariableDictionary
350
7AE <<< points to a DICTIONARY with handles to DICTIONARYVAR objects
0
DICTIONARY
...
...
0
ENDSEC
DXF Structures
DXF Sections
HEADER Section
In DXF R12 and prior the HEADER section was optional, but since DXF R13 the HEADER section is mandatory.
The overall structure is:
0 <<< Begin HEADER section
SECTION
2
HEADER
9
$ACADVER <<< Header variable items go here
1
AC1009
...
0
ENDSEC <<< End HEADER section
A header variable has a name defined by a (9, Name) tag and following value tags.
SEE ALSO:
Documentation of ezdxf HeaderSection class.
DXF Reference: Header Variables
CLASSES Section
The CLASSES section contains CLASS definitions which are only important for Autodesk products, some DXF
entities require a class definition or AutoCAD will not open the DXF file.
The CLASSES sections was introduced with DXF AC1015 (AutoCAD Release R13).
SEE ALSO:
DXF Reference: About the DXF CLASSES Section
Documentation of ezdxf ClassesSection class.
The CLASSES section in DXF files holds the information for application-defined classes whose instances
appear in the BLOCKS, ENTITIES, and OBJECTS sections of the database. It is assumed that a class
definition is permanently fixed in the class hierarchy. All fields are required.
Update 2019-03-03:
Class names are not unique, Autodesk Architectural Desktop 2007 uses the same name, but with different
CPP class names in the CLASS section, so storing classes in a dictionary by name as key caused loss of
class entries in ezdxf, using a tuple of (name, cpp_class_name) as storage key solved the problem.
CLASS Entities
SEE ALSO:
DXF Reference: Group Codes for the CLASS entity
CLASS entities have no handle and therefore ezdxf does not store the CLASS entity in the drawing entities
database!
0
SECTION
2 <<< begin CLASSES section
CLASSES
0 <<< first CLASS entity
CLASS
1 <<< class DXF entity name; THIS ENTRY IS MAYBE NOT UNIQUE
ACDBDICTIONARYWDFLT
2 <<< C++ class name; always unique
AcDbDictionaryWithDefault
3 <<< application name
ObjectDBX Classes
90 <<< proxy capabilities flags
0
91 <<< instance counter for custom class, since DXF version AC1018 (R2004)
0 <<< no problem if the counter is wrong, AutoCAD doesn't care about
280 <<< was-a-proxy flag: 1= class was not loaded when this DXF file was created
0 <<< 0= otherwise
281 <<< is-an-entity flag: 1= instances reside in the BLOCKS or ENTITIES section
0 <<< 0= instances may appear only in the OBJECTS section
0 <<< next CLASS entity
CLASS
...
0 <<< end of CLASSES section
ENDSEC
TABLES Section
The TABLES section contains the resource tables of a DXF document.
APPID Table
The APPID table stores unique application identifiers. These identifiers are used to mark sub-sections in
the XDATA section of DXF entities. AutoCAD will not load DXF files which uses AppIDs without an entry in
the AppIDs table and the “ACAD” entry must always exist.
Some known AppIDs:
┌──────────────────────┬──────────┬──────────────────────────────┐
│ APPID │ Used by │ Description │
├──────────────────────┼──────────┼──────────────────────────────┤
│ ACAD │ Autodesk │ various use cases │
├──────────────────────┼──────────┼──────────────────────────────┤
│ AcAecLayerStandard │ Autodesk │ layer description │
├──────────────────────┼──────────┼──────────────────────────────┤
│ AcCmTransparency │ Autodesk │ layer transparency │
├──────────────────────┼──────────┼──────────────────────────────┤
│ HATCHBACKGROUNDCOLOR │ Autodesk │ background color for pattern │
│ │ │ fillings │
├──────────────────────┼──────────┼──────────────────────────────┤
│ EZDXF │ ezdxf │ meta data │
└──────────────────────┴──────────┴──────────────────────────────┘
SEE ALSO:
• DXF Reference: TABLES Section
• DXF Reference: APPID Table
• AppID class
Table Structure DXF R12
0 <<< start of table
TABLE
2 <<< table type
APPID
70 <<< count of table entries, AutoCAD ignores this value
3
0 <<< 1. table entry
APPID
2 <<< unique application identifier
ACAD
70 <<< flags, see `APPID`_ reference
0 <<< in common cases always 0
0 <<< next table entry
APPID
...
0 <<< end of APPID table
ENDTAB
Table Structure DXF R2000+
0 <<< start of table
TABLE
2 <<< table type
APPID
5 <<< table handle
3
330 <<< owner tag, tables have no owner
0
100 <<< subclass marker
AcDbSymbolTable
70 <<< count of table entries, AutoCAD ignores this value
3
0 <<< first table entry
APPID
5 <<< handle of appid
2A
330 <<< owner handle, handle of APPID table
3
100 <<< subclass marker
AcDbSymbolTableRecord
100 <<< subclass marker
AcDbRegAppTableRecord
2 <<< unique application identifier
ACAD
70 <<< flags, see `APPID`_ reference
0 <<< in common cases always 0
0 <<< next table entry
APPID
...
0 <<< end of APPID table
ENDTAB
Name References
APPID table entries are referenced by name:
• XDATA section of DXF entities
BLOCK_RECORD Table
Block records are essential elements for the entities management, each layout (modelspace and paperspace)
and every block definition has a block record entry. This block record is the hard owner of the entities
of layouts, each entity has an owner handle which points to a block record of the layout.
DIMSTYLE Table
The DIMSTYLE table stores all dimension style definitions of a DXF drawing.
You have access to the dimension styles table by the attribute Drawing.dimstyles.
SEE ALSO:
• DXF Reference: TABLES Section
• DXF Reference: DIMSTYLE Table
Table Structure DXF R12
0 <<< start of table
TABLE
2 <<< set table type
DIMSTYLE
70 <<< count of line types defined in this table, AutoCAD ignores this value
9
0 <<< 1. DIMSTYLE table entry
DIMSTYLE
<<< DIMSTYLE data tags
0 <<< 2. DIMSTYLE table entry
DIMSTYLE
<<< DIMSTYLE data tags and so on
0 <<< end of DIMSTYLE table
ENDTAB
DIMSTYLE Entry DXF R12
DIMSTYLE Variables DXF R12
Source: CADDManager Blog [image] [image]
──────────────────────────────────────────────────
DIMVAR Code Description
──────────────────────────────────────────────────
DIMALT 170 Controls the display of
alternate units in
dimensions.
──────────────────────────────────────────────────
DIMALTD 171 Controls the number of
decimal places in alternate
units. If DIMALT is turned
on, DIMALTD sets the number
of digits displayed to the
right of the decimal point
in the alternate
measurement.
──────────────────────────────────────────────────
DIMALTF 143 Controls the multiplier for
alternate units. If DIMALT
is turned on, DIMALTF
multiplies linear dimensions
by a factor to produce a
value in an alternate system
of measurement. The initial
value represents the number
of millimeters in an inch.
──────────────────────────────────────────────────
DIMAPOST 4 Specifies a text prefix or
suffix (or both) to the
alternate dimension
measurement for all types of
dimensions except angular.
For instance, if the current
units are Architectural,
DIMALT is on, DIMALTF is
25.4 (the number of
millimeters per inch),
DIMALTD is 2, and DIMPOST is
set to “mm”, a distance of
10 units would be displayed
as 10”[254.00mm].
──────────────────────────────────────────────────
DIMASZ 41 Controls the size of
dimension line and leader
line arrowheads. Also
controls the size of hook
lines. Multiples of the
arrowhead size determine
whether dimension lines and
text should fit between the
extension lines. DIMASZ is
also used to scale arrowhead
blocks if set by DIMBLK.
DIMASZ has no effect when
DIMTSZ is other than zero.
──────────────────────────────────────────────────
DIMBLK 5 Sets the arrowhead block
displayed at the ends of
dimension lines.
──────────────────────────────────────────────────
DIMBLK1 6 Sets the arrowhead for the
first end of the dimension
line when DIMSAH is 1.
──────────────────────────────────────────────────
DIMBLK2 7 Sets the arrowhead for the
second end of the dimension
line when DIMSAH is 1.
──────────────────────────────────────────────────
DIMCEN 141 Controls drawing of circle
or arc center marks and
centerlines by the
DIMCENTER, DIMDIAMETER, and
DIMRADIUS commands. For
DIMDIAMETER and DIMRADIUS,
the center mark is drawn
only if you place the
dimension line outside the
circle or arc.
• 0 = No center
marks or lines are
drawn
• <0 = Centerlines
are drawn
• >0 = Center marks
are drawn
──────────────────────────────────────────────────
DIMCLRD 176 Assigns colors to dimension
lines, arrowheads, and
dimension leader lines.
• 0 = BYBLOCK
• 1-255 = ACI AutoCAD
Color Index
• 256 = BYLAYER
──────────────────────────────────────────────────
DIMCLRE 177 Assigns colors to dimension
extension lines, values like
DIMCLRD
──────────────────────────────────────────────────
DIMCLRT 178 Assigns colors to dimension
text, values like DIMCLRD
──────────────────────────────────────────────────
DIMDLE 46 Sets the distance the
dimension line extends
beyond the extension line
when oblique strokes are
drawn instead of arrowheads.
──────────────────────────────────────────────────
DIMDLI 43 Controls the spacing of the
dimension lines in baseline
dimensions. Each dimension
line is offset from the
previous one by this amount,
if necessary, to avoid
drawing over it. Changes
made with DIMDLI are not
applied to existing
dimensions.
──────────────────────────────────────────────────
DIMEXE 44 Specifies how far to extend
the extension line beyond
the dimension line.
──────────────────────────────────────────────────
DIMEXO 42 Specifies how far extension
lines are offset from origin
points. With fixed-length
extension lines, this value
determines the minimum
offset.
──────────────────────────────────────────────────
DIMGAP 147 Sets the distance around the
dimension text when the
dimension line breaks to
accommodate dimension text.
Also sets the gap between
annotation and a hook line
created with the LEADER
command. If you enter a
negative value, DIMGAP
places a box around the
dimension text.
DIMGAP is also used as the
minimum length for pieces of
the dimension line. When the
default position for the
dimension text is
calculated, text is
positioned inside the
extension lines only if
doing so breaks the
dimension lines into two
segments at least as long as
DIMGAP. Text placed above
or below the dimension line
is moved inside only if
there is room for the
arrowheads, dimension text,
and a margin between them at
least as large as DIMGAP: 2
* (DIMASZ + DIMGAP).
──────────────────────────────────────────────────
DIMLFAC 144 Sets a scale factor for
linear dimension
measurements. All linear
dimension distances,
including radii, diameters,
and coordinates, are
multiplied by DIMLFAC before
being converted to dimension
text. Positive values of
DIMLFAC are applied to
dimensions in both
modelspace and paperspace;
negative values are applied
to paperspace only.
DIMLFAC applies primarily to
nonassociative dimensions
(DIMASSOC set 0 or 1). For
nonassociative dimensions in
paperspace, DIMLFAC must be
set individually for each
layout viewport to
accommodate viewport
scaling.
DIMLFAC has no effect on
angular dimensions, and is
not applied to the values
held in DIMRND, DIMTM, or
DIMTP.
──────────────────────────────────────────────────
DIMLIM 72 Generates dimension limits
as the default text. Setting
DIMLIM to On turns DIMTOL
off.
• 0 = Dimension
limits are not
generated as
default text
• 1 = Dimension
limits are
generated as
default text
──────────────────────────────────────────────────
DIMPOST 3 Specifies a text prefix or
suffix (or both) to the
dimension measurement.
For example, to establish a
suffix for millimeters, set
DIMPOST to mm; a distance of
19.2 units would be
displayed as 19.2 mm. If
tolerances are turned on,
the suffix is applied to the
tolerances as well as to the
main dimension.
Use “<>” to indicate
placement of the text in
relation to the dimension
value. For example, enter
“<>mm” to display a 5.0
millimeter radial dimension
as “5.0mm”. If you entered
mm “<>”, the dimension would
be displayed as “mm 5.0”.
──────────────────────────────────────────────────
DIMRND 45 Rounds all dimensioning
distances to the specified
value.
For instance, if DIMRND is
set to 0.25, all distances
round to the nearest 0.25
unit. If you set DIMRND to
1.0, all distances round to
the nearest integer. Note
that the number of digits
edited after the decimal
point depends on the
precision set by DIMDEC.
DIMRND does not apply to
angular dimensions.
──────────────────────────────────────────────────
DIMSAH 173 Controls the display of
dimension line arrowhead
blocks.
• 0 = Use arrowhead
blocks set by
DIMBLK
• 1 = Use arrowhead
blocks set by
DIMBLK1 and DIMBLK2
──────────────────────────────────────────────────
DIMSCALE 40 Sets the overall scale
factor applied to
dimensioning variables that
specify sizes, distances, or
offsets. Also affects the
leader objects with the
LEADER command.
Use MLEADERSCALE to scale
multileader objects created
with the MLEADER command.
• 0.0 = A reasonable
default value is
computed based on
the scaling between
the current model
space viewport and
paperspace. If you
are in paperspace
or modelspace and
not using the
paperspace feature,
the scale factor is
1.0.
• >0 = A scale factor
is computed that
leads text sizes,
arrowhead sizes,
and other scaled
distances to plot
at their face
values.
DIMSCALE does not
affect measured
lengths, coordinates,
or angles.
Use DIMSCALE to
control the overall
scale of dimensions.
However, if the
current dimension
style is annotative,
DIMSCALE is
automatically set to
zero and the
dimension scale is
controlled by the
CANNOSCALE system
variable. DIMSCALE
cannot be set to a
non-zero value when
using annotative
dimensions.
──────────────────────────────────────────────────
DIMSE1 75 Suppresses display of the
first extension line.
• 0 = Extension line
is not suppressed
• 1 = Extension line
is suppressed
──────────────────────────────────────────────────
DIMSE2 76 Suppresses display of the
second extension line.
• 0 = Extension line
is not suppressed
• 1 = Extension line
is suppressed
──────────────────────────────────────────────────
DIMSOXD 175 Suppresses arrowheads if not
enough space is available
inside the extension lines.
• 0 = Arrowheads are
not suppressed
• 1 = Arrowheads are
suppressed
If not enough space
is available inside
the extension lines
and DIMTIX is on,
setting DIMSOXD to On
suppresses the
arrowheads. If DIMTIX
is off, DIMSOXD has
no effect.
──────────────────────────────────────────────────
DIMTAD 77 Controls the vertical
position of text in relation
to the dimension line.
• 0 = Centers the
dimension text
between the
extension lines.
• 1 = Places the
dimension text
above the dimension
line except when
the dimension line
is not horizontal
and text inside the
extension lines is
forced horizontal
(DIMTIH = 1). The
distance from the
dimension line to
the baseline of the
lowest line of text
is the current
DIMGAP value.
• 2 = Places the
dimension text on
the side of the
dimension line
farthest away from
the defining
points.
• 3 = Places the
dimension text to
conform to Japanese
Industrial
Standards (JIS).
• 4 = Places the
dimension text
below the dimension
line.
──────────────────────────────────────────────────
DIMTFAC 146 Specifies a scale factor for
the text height of fractions
and tolerance values
relative to the dimension
text height, as set by
DIMTXT.
For example, if DIMTFAC is
set to 1.0, the text height
of fractions and tolerances
is the same height as the
dimension text. If DIMTFAC
is set to 0.7500, the text
height of fractions and
tolerances is three-quarters
the size of dimension text.
──────────────────────────────────────────────────
DIMTIH 73 Controls the position of
dimension text inside the
extension lines for all
dimension types except
Ordinate.
• 0 = Aligns text
with the dimension
line
• 1 = Draws text
horizontally
──────────────────────────────────────────────────
DIMTIX 174 Draws text between extension
lines.
• 0 = Varies with the
type of dimension.
For linear and
angular dimensions,
text is placed
inside the
extension lines if
there is sufficient
room. For radius
and diameter
dimensions hat
don’t fit inside
the circle or arc,
DIMTIX has no
effect and always
forces the text
outside the circle
or arc.
• 1 = Draws dimension
text between the
extension lines
even if it would
ordinarily be
placed outside
those lines
──────────────────────────────────────────────────
DIMTM 48 Sets the minimum (or lower)
tolerance limit for
dimension text when DIMTOL
or DIMLIM is on. DIMTM
accepts signed values. If
DIMTOL is on and DIMTP and
DIMTM are set to the same
value, a tolerance value is
drawn. If DIMTM and DIMTP
│ │ │ values differ, the upper │
│ │ │ tolerance is drawn above the │
│ │ │ lower, and a plus sign is │
│ │ │ added to the DIMTP value if │
│ │ │ it is positive. For DIMTM, │
│ │ │ the program uses the │
│ │ │ negative of the value you │
│ │ │ enter (adding a minus sign │
│ │ │ if you specify a positive │
│ │ │ number and a plus sign if │
│ │ │ you specify a negative │
│ │ │ number). │
├──────────┼──────┼──────────────────────────────┤
│ DIMTOFL │ 172 │ Controls whether a dimension │
│ │ │ line is drawn between the │
│ │ │ extension lines even when │
│ │ │ the text is placed outside. │
│ │ │ For radius and diameter │
│ │ │ dimensions (when DIMTIX is │
│ │ │ off), draws a dimension line │
│ │ │ inside the circle or arc and │
│ │ │ places the text, arrowheads, │
│ │ │ and leader outside. │
│ │ │ │
│ │ │ • 0 = Does not draw │
│ │ │ dimension lines │
│ │ │ between the │
│ │ │ measured points │
│ │ │ when arrowheads are │
│ │ │ placed outside the │
│ │ │ measured points │
│ │ │ │
│ │ │ • 1 = Draws dimension │
│ │ │ lines between the │
│ │ │ measured points │
│ │ │ even when │
│ │ │ arrowheads are │
│ │ │ placed outside the │
│ │ │ measured points │
├──────────┼──────┼──────────────────────────────┤
│ DIMTOH │ 74 │ Controls the position of │
│ │ │ dimension text outside the │
│ │ │ extension lines. │
│ │ │ │
│ │ │ • 0 = Aligns text │
│ │ │ with the dimension │
│ │ │ line │
│ │ │ │
│ │ │ • 1 = Draws text │
│ │ │ horizontally │
├──────────┼──────┼──────────────────────────────┤
│ DIMTOL │ 71 │ Appends tolerances to │
│ │ │ dimension text. Setting │
│ │ │ DIMTOL to on turns DIMLIM │
│ │ │ off. │
├──────────┼──────┼──────────────────────────────┤
│ DIMTP │ 47 │ Sets the maximum (or upper) │
│ │ │ tolerance limit for │
│ │ │ dimension text when DIMTOL │
│ │ │ or DIMLIM is on. DIMTP │
│ │ │ accepts signed values. If │
│ │ │ DIMTOL is on and DIMTP and │
│ │ │ DIMTM are set to the same │
│ │ │ value, a tolerance value is │
│ │ │ drawn. If DIMTM and DIMTP │
│ │ │ values differ, the upper │
│ │ │ tolerance is drawn above the │
│ │ │ lower and a plus sign is │
│ │ │ added to the DIMTP value if │
│ │ │ it is positive. │
├──────────┼──────┼──────────────────────────────┤
│ DIMTSZ │ 142 │ Specifies the size of │
│ │ │ oblique strokes drawn │
│ │ │ instead of arrowheads for │
│ │ │ linear, radius, and diameter │
│ │ │ dimensioning. │
│ │ │ │
│ │ │ • 0 = Draws │
│ │ │ arrowheads. │
│ │ │ │
│ │ │ • >0 = Draws oblique │
│ │ │ strokes instead of │
│ │ │ arrowheads. The │
│ │ │ size of the oblique │
│ │ │ strokes is │
│ │ │ determined by this │
│ │ │ value multiplied by │
│ │ │ the DIMSCALE value │
├──────────┼──────┼──────────────────────────────┤
│ DIMTVP │ 145 │ Controls the vertical │
│ │ │ position of dimension text │
│ │ │ above or below the dimension │
│ │ │ line. The DIMTVP value is │
│ │ │ used when DIMTAD = 0. The │
│ │ │ magnitude of the vertical │
│ │ │ offset of text is the │
│ │ │ product of the text height │
│ │ │ and DIMTVP. Setting DIMTVP │
│ │ │ to 1.0 is equivalent to │
│ │ │ setting DIMTAD = 1. The │
│ │ │ dimension line splits to │
│ │ │ accommodate the text only if │
│ │ │ the absolute value of DIMTVP │
│ │ │ is less than 0.7. │
├──────────┼──────┼──────────────────────────────┤
│ DIMTXT │ 140 │ Specifies the height of │
│ │ │ dimension text, unless the │
│ │ │ current text style has a │
│ │ │ fixed height. │
├──────────┼──────┼──────────────────────────────┤
│ DIMZIN │ 78 │ Controls the suppression of │
│ │ │ zeros in the primary unit │
│ │ │ value. Values 0-3 affect │
│ │ │ feet-and-inch dimensions │
│ │ │ only: │
│ │ │ │
│ │ │ • 0 = Suppresses zero │
│ │ │ feet and precisely │
│ │ │ zero inches │
│ │ │ │
│ │ │ • 1 = Includes zero │
│ │ │ feet and precisely │
│ │ │ zero inches │
│ │ │ │
│ │ │ • 2 = Includes zero │
│ │ │ feet and suppresses │
│ │ │ zero inches │
│ │ │ │
│ │ │ • 3 = Includes zero │
│ │ │ inches and │
│ │ │ suppresses zero │
│ │ │ feet │
│ │ │ │
│ │ │ • 4 (Bit 3) = │
│ │ │ Suppresses leading │
│ │ │ zeros in decimal │
│ │ │ dimensions (for │
│ │ │ example, 0.5000 │
│ │ │ becomes .5000) │
│ │ │ │
│ │ │ • 8 (Bit 4) = │
│ │ │ Suppresses trailing │
│ │ │ zeros in decimal │
│ │ │ dimensions (for │
│ │ │ example, 12.5000 │
│ │ │ becomes 12.5) │
│ │ │ │
│ │ │ • 12 (Bit 3+4) = │
│ │ │ Suppresses both │
│ │ │ leading and │
│ │ │ trailing zeros (for │
│ │ │ example, 0.5000 │
│ │ │ becomes .5) │
└──────────┴──────┴──────────────────────────────┘
Table Structure DXF R2000+
0 <<< start of table
TABLE
2 <<< set table type
DIMSTYLE
5 <<< DIMSTYLE table handle
5F
330 <<< owner tag, tables has no owner
0
100 <<< subclass marker
AcDbSymbolTable
70 <<< count of dimension styles defined in this table, AutoCAD ignores this value
9
0 <<< 1. DIMSTYLE table entry
DIMSTYLE
<<< DIMSTYLE data tags
0 <<< 2. DIMSTYLE table entry
DIMSTYLE
<<< DIMSTYLE data tags and so on
0 <<< end of DIMSTYLE table
ENDTAB
Additional DIMSTYLE Variables DXF R13/14
Source: CADDManager Blog
─────────────────────────────────────────────────────────────
DIMVAR code Description
─────────────────────────────────────────────────────────────
DIMADEC 179 Controls the number of
precision places displayed
in angular dimensions.
─────────────────────────────────────────────────────────────
DIMALTTD 274 Sets the number of decimal
places for the tolerance
values in the alternate
units of a dimension.
─────────────────────────────────────────────────────────────
DIMALTTZ 286 Controls suppression of
zeros in tolerance values.
─────────────────────────────────────────────────────────────
DIMALTU 273 Sets the units format for
alternate units of all
dimension substyles except
Angular.
─────────────────────────────────────────────────────────────
DIMALTZ 285 Controls the suppression of
zeros for alternate unit
dimension values. DIMALTZ
values 0-3 affect
feet-and-inch dimensions
only.
─────────────────────────────────────────────────────────────
DIMAUNIT 275 Sets the units format for
angular dimensions.
• 0 = Decimal degrees
• 1 =
Degrees/minutes/seconds
• 2 = Grad
• 3 = Radians
─────────────────────────────────────────────────────────────
DIMBLK_HANDLE 342 defines DIMBLK as handle to the
BLOCK RECORD entry
─────────────────────────────────────────────────────────────
DIMBLK1_HANDLE 343 defines DIMBLK1 as handle to the
BLOCK RECORD entry
─────────────────────────────────────────────────────────────
DIMBLK2_HANDLE 344 defines DIMBLK2 as handle to the
BLOCK RECORD entry
─────────────────────────────────────────────────────────────
DIMDEC 271 Sets the number of decimal
places displayed for the primary
units of a dimension. The
precision is based on the units
or angle format you have
selected.
─────────────────────────────────────────────────────────────
DIMDSEP 278 Specifies a single-character
decimal separator to use when
creating dimensions whose unit
format is decimal. When
prompted, enter a single
character at the Command prompt.
If dimension units is set to
Decimal, the DIMDSEP character
is used instead of the default
decimal point. If DIMDSEP is set
to NULL (default value, reset by
entering a period), the decimal
point is used as the dimension
separator.
─────────────────────────────────────────────────────────────
DIMJUST 280 Controls the horizontal
positioning of dimension text.
• 0 = Positions the text
above the dimension
line and
center-justifies it
between the extension
lines
• 1 = Positions the text
next to the first
extension line
• 2 = Positions the text
next to the second
extension line
• 3 = Positions the text
above and aligned with
the first extension
line
• 4 = =Positions the
text above and aligned
with the second
extension line
─────────────────────────────────────────────────────────────
DIMSD1 281 Controls suppression of the
first dimension line and
arrowhead. When turned on,
suppresses the display of the
dimension line and arrowhead
between the first extension line
and the text.
• 0 = First dimension
line is not suppressed
• 1 = First dimension
line is suppressed
─────────────────────────────────────────────────────────────
DIMSD2 282 Controls suppression of the
second dimension line and
arrowhead. When turned on,
suppresses the display of the
dimension line and arrowhead
between the second extension
line and the text.
• 0 = Second dimension
line is not suppressed
• 1 = Second dimension
line is suppressed
─────────────────────────────────────────────────────────────
DIMTDEC 272 Sets the number of decimal
places to display in tolerance
values for the primary units in
a dimension. This system
variable has no effect unless
DIMTOL is set to On. The default
for DIMTOL is Off.
─────────────────────────────────────────────────────────────
DIMTOLJ 283 Sets the vertical justification
for tolerance values relative to
the nominal dimension text.
This system variable has no
effect unless DIMTOL is set to
On. The default for DIMTOL is
Off.
• 0 = Bottom
• 1 = Middle
• 2 = Top
─────────────────────────────────────────────────────────────
DIMTXSTY_HANDLE 340 Specifies the text style of the
dimension as handle to STYLE
table entry
─────────────────────────────────────────────────────────────
DIMTZIN 284 Controls the suppression of
zeros in tolerance values.
Values 0-3 affect feet-and-inch
dimensions only.
• 0 = Suppresses zero
feet and precisely zero
inches
• 1 = Includes zero feet
and precisely zero
inches
• 2 = Includes zero feet
and suppresses zero
inches
• 3 = Includes zero
inches and suppresses
zero feet
• 4 = Suppresses leading
zeros in decimal
dimensions (for
example, 0.5000 becomes
.5000)
• 8 = Suppresses trailing
zeros in decimal
dimensions (for
example, 12.5000
becomes 12.5)
• 12 = Suppresses both
leading and trailing
zeros (for example,
0.5000 becomes .5)
─────────────────────────────────────────────────────────────
DIMUPT 288 Controls options for
user-positioned text.
• 0 = Cursor controls
only the dimension line
location
• 1 = Cursor controls
both the text position
and the dimension line
location
┌─────────────────┬──────┬──────────────────────────────────┐
│ │ │ │
--
DEVELOPER GUIDES
Information about ezdxf internals.
Source Code Formatting
Reformat code by Black with the default setting of 88 characters per line:
C:\> black <python-file>
Type Annotations
The use of type annotations is encouraged. New modules should pass mypy without errors in non-strict
mode. Using # type: ignore is fine in tricky situations - type annotations should be helpful in
understanding the code and not be a burden.
The following global options are required to pass mypy without error messages:
[mypy]
python_version = 3.7
ignore_missing_imports = True
Read this to learn where mypy searches for config files.
Use the mypy command line option --ignore-missing-imports and -p to check the whole package from any
location in the file system:
PS D:\Source\ezdxf.git> mypy --ignore-missing-imports -p ezdxf
Success: no issues found in 255 source files
Design
The Package Design for Developers section shows the structure of the ezdxf package for developers with
more experience, which want to have more insight into the package an maybe want to develop add-ons or
want contribute to the ezdxf package. !!! UNDER CONSTRUCTION !!!
Package Design for Developers
A DXF document is divided into several sections, this sections are managed by the Drawing object. For
each section exist a corresponding attribute in the Drawing object:
┌──────────┬──────────────────┐
│ Section │ Attribute │
├──────────┼──────────────────┤
│ HEADER │ Drawing.header │
├──────────┼──────────────────┤
│ CLASSES │ Drawing.classes │
├──────────┼──────────────────┤
│ TABLES │ Drawing.tables │
├──────────┼──────────────────┤
│ BLOCKS │ Drawing.blocks │
├──────────┼──────────────────┤
│ ENTITIES │ Drawing.entities │
├──────────┼──────────────────┤
│ OBJECTS │ Drawing.objects │
└──────────┴──────────────────┘
Resource entities (LAYER, STYLE, LTYPE, …) are stored in tables in the TABLES section. A table owns the
table entries, the owner handle of table entry is the handle of the table. Each table has a shortcut in
the Drawing object:
┌──────────────┬───────────────────────┐
│ Table │ Attribute │
├──────────────┼───────────────────────┤
│ APPID │ Drawing.appids │
├──────────────┼───────────────────────┤
│ BLOCK_RECORD │ Drawing.block_records │
├──────────────┼───────────────────────┤
│ DIMSTYLE │ Drawing.dimstyles │
├──────────────┼───────────────────────┤
│ LAYER │ Drawing.layers │
├──────────────┼───────────────────────┤
│ LTYPE │ Drawing.linetypes │
├──────────────┼───────────────────────┤
│ STYLE │ Drawing.styles │
├──────────────┼───────────────────────┤
│ UCS │ Drawing.ucs │
├──────────────┼───────────────────────┤
│ VIEW │ Drawing.views │
├──────────────┼───────────────────────┤
│ VPORT │ Drawing.viewports │
└──────────────┴───────────────────────┘
Graphical entities are stored in layouts: Modelspace, Paperspace layouts and BlockLayout. The core
management object of this layouts is the BLOCK_RECORD entity (BlockRecord), the BLOCK_RECORD is the real
owner of the entities, the owner handle of the entities is the handle of the BLOCK_RECORD and the
BLOCK_RECORD also owns and manages the entity space of the layout which contains all entities of the
layout.
For more information about layouts see also: Layout Management Structures
For more information about blocks see also: Block Management Structures
Non-graphical entities (objects) are stored in the OBJECTS section. Every object has a parent object in
the OBJECTS section, most likely a DICTIONARY object, and is stored in the entity space of the OBJECTS
section.
For more information about the OBJECTS section see also: OBJECTS Section
All table entries, DXF entities and DXF objects are stored in the entities database accessible as
Drawing.entitydb. The entity database is a simple key, value storage, key is the entity handle, value is
the DXF object.
For more information about the DXF data model see also: Data Model
Terminology
States
DXF entities and objects can have different states:
UNBOUND
Entity is not stored in the Drawing entity database and DXF attribute handle is None and attribute
doc can be None
BOUND Entity is stored in the Drawing entity database, attribute doc has a reference to Drawing and DXF
attribute handle is not None
UNLINKED
Entity is not linked to a layout/owner, DXF attribute owner is None
LINKED Entity is linked to a layout/owner, DXF attribute owner is not None
Virtual Entity
State: UNBOUND & UNLINKED
Unlinked Entity
State: BOUND & UNLINKED
Bound Entity
State: BOUND & LINKED
Actions
NEW Create a new DXF document
LOAD Load a DXF document from an external source
CREATE Create DXF structures from NEW or LOAD data
DESTROY
Delete DXF structures
BIND Bind an entity to a Drawing, set entity state to BOUND & UNLINKED and check or create required
resources
UNBIND unbind …
LINK Link an entity to an owner/layout. This makes an entity to a real DXF entity, which will be
exported at the saving process. Any DXF entity can only be linked to one parent entity like
DICTIONARY or BLOCK_RECORD.
UNLINK unlink …
Loading a DXF Document
Loading a DXF document from an external source, creates a new Drawing object. This loading process has
two stages:
First Loading Stage
• LOAD content from external source as SectionDict: loader.load_dxf_structure()
• LOAD tag structures as DXFEntity objects: loader.load_dxf_entities()
• BIND entities: loader.load_and_bind_dxf_content(); Special handling of the BIND process, because the
Drawing is not full initialized, a complete validation is not possible at this stage.
Second Loading Stage
Parse SectionDict:
• CREATE sections: HEADER, CLASSES, TABLES, BLOCKS and OBJECTS
• CREATE layouts: Blocks, Layouts
• LINK entities to a owner/layout
The ENTITIES section is a relict from older DXF versions and has to be exported including the modelspace
and active paperspace entities, but all entities reside in a BLOCK definition, even modelspace and
paperspace layouts are only BLOCK definitions and ezdxf has no explicit ENTITIES section.
Source Code: as developer start your journey at ezdxf.document.Drawing.read(), which has no public
documentation, because package-user should use ezdxf.read() and ezdxf.readfile().
New DXF Document
Creating New DXF Entities
The default constructor of each entity type creates a new virtual entity:
• DXF attribute owner is None
• DXF attribute handle is None
• Attribute doc is None
The DXFEntity.new() constructor creates entities with given owner, handle and doc attributes, if doc is
not None and entity is not already bound to a document, the new() constructor automatically bind the
entity to the given document doc.
There exist only two scenarios:
1. UNBOUND: doc is None and handle is None
2. BOUND: doc is not None and handle is not None
Factory functions
• new(), create a new virtual DXF object/entity
• load(), load (create) virtual DXF object/entity from DXF tags
• bind(), bind an entity to a document, create required resources if necessary (e.g. ImageDefReactor,
SEQEND) and raise exceptions for non-existing resources.
• Bind entity loaded from an external source to a document, all referenced resources must exist, but
try to repair as many flaws as possible because errors were created by another application and are
not the responsibility of the package-user.
• Bind an entity from another DXF document, all invalid resources will be removed silently or created
(e.g. SEQEND). This is a simple import from another document without resource import, for a more
advanced import including resources exist the importer add-on.
• Bootstrap problem for binding loaded table entries and objects in the OBJECTS section! Can’t use
Auditor to repair this objects, because the DXF document is not fully initialized.
• is_bound() returns True if entity is bound to document doc
• unbind() function to remove an entity from a document and set state to a virtual entity, which should
also UNLINK the entity from layout, because an layout can not store a virtual entity.
• cls(), returns the class
• register_entity(), registration decorator
• replace_entity(), registration decorator
Class Interfaces
DXF Entities
• NEW constructor to create an entity from scratch
• LOAD constructor to create an entity loaded from an external source
• DESTROY interface to kill an entity, set entity state to dead, which means entity.is_alive returns
False. All entity iterators like EntitySpace, EntityQuery, and EntityDB must filter (ignore) dead
entities. Calling DXFEntity.destroy() is a regular way to delete entities.
• LINK an entity to a layout by BlockRecord.link(), which set the owner handle to BLOCK_RECORD handle (=
layout key) and add the entity to the entity space of the BLOCK_RECORD and set/clear the paperspace
flag.
DXF Objects
• NEW, LOAD, DESTROY see DXF entities
• LINK: Linking an DXF object means adding the entity to a parent object in the OBJECTS section, most
likely a DICTIONARY object, and adding the object to the entity space of the OBJECTS section, the
root-dict is the only entity in the OBJECTS section which has an invalid owner handle “0”. Any other
object with an invalid or destroyed owner is an orphaned entity. The audit process destroys and
removes orphaned objects.
• Extension dictionaries (ACAD_XDICTIONARY) are DICTIONARY objects located in the OBJECTS sections and
can reference/own other entities of the OBJECTS section.
• The root-dictionary is the only entity in the OBJECTS section which has an invalid owner handle “0”.
Any other object with an invalid or destroyed owner is an orphaned entity.
Layouts
• LINK interface to link an entity to a layout
• UNLINK interface to remove an entity from a layout
Database
• BIND interface to add an entity to the database of a document
• delete_entity() interface, same as UNBIND and DESTROY an entity
Internal Data Structures
Entity Database
The EntityDB is a simple key/value database to store DXFEntity objects by it’s handle, every Drawing has
its own EntityDB, stored in the Drawing attribute entitydb.
Every DXF entity/object, except tables and sections, are represented as DXFEntity or inherited types,
this entities are stored in the EntityDB, database-key is the dxf.handle as plain hex string.
All iterators like keys(), values(), items() and __iter__() do not yield destroyed entities.
WARNING:
The get() method and the index operator [], return destroyed entities and entities from the trashcan.
class ezdxf.entitydb.EntityDB
__getitem__(handle: str) -> DXFEntity
Get entity by handle, does not filter destroyed entities nor entities in the trashcan.
__setitem__(handle: str, entity: DXFEntity) -> None
Set entity for handle.
__delitem__(handle: str) -> None
Delete entity by handle. Removes entity only from database, does not destroy the entity.
__contains__(item: str | DXFEntity) -> bool
True if database contains handle.
__len__() -> int
Count of database items.
__iter__() -> Iterator[str]
Iterable of all handles, does filter destroyed entities but not entities in the trashcan.
get(handle: str) -> DXFEntity | None
Returns entity for handle or None if no entry exist, does not filter destroyed entities.
next_handle() -> str
Returns next unique handle.
keys() -> Iterable[str]
Iterable of all handles, does filter destroyed entities.
values() -> Iterable[DXFEntity]
Iterable of all entities, does filter destroyed entities.
items() -> Iterable[Tuple[str, DXFEntity]]
Iterable of all (handle, entities) pairs, does filter destroyed entities.
add(entity: DXFEntity) -> None
Add entity to database, assigns a new handle to the entity if entity.dxf.handle is None.
Adding the same entity multiple times is possible and creates only a single database entry.
new_trashcan() -> Trashcan
Returns a new trashcan, empty trashcan manually by: : func:Trashcan.clear().
trashcan() -> Trashcan
Returns a new trashcan in context manager mode, trashcan will be emptied when leaving
context.
purge() -> None
Remove all destroyed entities from database, but does not empty the trashcan.
query(query: str = '*') -> EntityQuery
Entity query over all entities in the DXF document.
Parameters
query – query string
SEE ALSO:
Entity Query String and Retrieve entities by query language
Entity Space
class ezdxf.entitydb.EntitySpace(entities: Iterable[DXFEntity] | None = None)
An EntitySpace is a collection of DXFEntity objects, that stores only references to DXFEntity
objects.
The Modelspace, any Paperspace layout and BlockLayout objects have an EntitySpace container to
store their entities.
__iter__() -> Iterable[DXFEntity]
Iterable of all entities, filters destroyed entities.
__getitem__(index) -> DXFEntity
Get entity at index item
EntitySpace has a standard Python list like interface, therefore index can be any valid
list indexing or slicing term, like a single index layout[-1] to get the last entity, or an
index slice layout[:10] to get the first 10 or fewer entities as list[DXFEntity]. Does not
filter destroyed entities.
__len__() -> int
Count of entities including destroyed entities.
has_handle(handle: str) -> bool
True if handle is present, does filter destroyed entities.
purge()
Remove all destroyed entities from entity space.
add(entity: DXFEntity) -> None
Add entity.
extend(entities: Iterable[DXFEntity]) -> None
Add multiple entities.
remove(entity: DXFEntity) -> None
Remove entity.
clear() -> None
Remove all entities.
DXF Types
Required DXF tag interface:
• property code: group code as int
• property value: tag value of unspecific type
• dxfstr(): returns the DXF string
• clone(): returns a deep copy of tag
DXFTag Factory Functions
ezdxf.lldxf.types.dxftag(code: int, value: Any) -> DXFTag
DXF tag factory function.
Parameters
• code – group code
• value – tag value
Returns: DXFTag or inherited
ezdxf.lldxf.types.tuples_to_tags(iterable: Iterable[tuple[int, Any]]) -> Iterable[DXFTag]
Returns an iterable if DXFTag or inherited, accepts an iterable of (code, value) tuples as input.
DXFTag
class ezdxf.lldxf.types.DXFTag(code: int, value: Any)
Immutable DXFTag class.
Parameters
• code – group code as int
• value – tag value, type depends on group code
code group code as int (do not change)
value tag value (read-only property)
__eq__(other) -> bool
True if other and self has same content for code and value.
__getitem__(index: int)
Returns code for index 0 and value for index 1, emulates a tuple.
__hash__()
Hash support, DXFTag can be used in sets and as dict key.
__iter__()
Returns (code, value) tuples.
__repr__() -> str
Returns representation string 'DXFTag(code, value)'.
__str__() -> str
Returns content string '(code, value)'.
clone() -> DXFTag
Returns a clone of itself, this method is necessary for the more complex (and not
immutable) DXF tag types.
dxfstr() -> str
Returns the DXF string e.g. ' 0\nLINE\n'
DXFBinaryTag
class ezdxf.lldxf.types.DXFBinaryTag(DXFTag)
Immutable BinaryTags class - immutable by design, not by implementation.
dxfstr() -> str
Returns the DXF string for all vertex components.
tostring() -> str
Returns binary value as single hex-string.
DXFVertex
class ezdxf.lldxf.types.DXFVertex(DXFTag)
Represents a 2D or 3D vertex, stores only the group code of the x-component of the vertex, because
the y-group-code is x-group-code + 10 and z-group-code id x-group-code+20, this is a rule that
ALWAYS applies. This tag is immutable by design, not by implementation.
Parameters
• code – group code of x-component
• value – sequence of x, y and optional z values
dxfstr() -> str
Returns the DXF string for all vertex components.
dxftags() -> Iterable[DXFTag]
Returns all vertex components as single DXFTag objects.
NONE_TAG
ezdxf.lldxf.types.NONE_TAG
Special tag representing a none existing tag.
Tags
A list of DXFTag, inherits from Python standard list. Unlike the statement in the DXF Reference “Do not
write programs that rely on the order given here”, tag order is sometimes essential and some group codes
may appear multiples times in one entity. At the worst case (Material: normal map shares group codes with
diffuse map) using same group codes with different meanings.
class ezdxf.lldxf.tags.Tags
Subclass of list.
Collection of DXFTag as flat list. Low level tag container, only required for advanced stuff.
classmethod from_text(text: str) -> Tags
Constructor from DXF string.
dxftype() -> str
Returns DXF type of entity, e.g. 'LINE'.
get_handle() -> str
Get DXF handle. Raises DXFValueError if handle not exist.
Returns
handle as plain hex string like 'FF00'
Raises DXFValueError – no handle found
replace_handle(new_handle: str) -> None
Replace existing handle.
Parameters
new_handle – new handle as plain hex string e.g. 'FF00'
has_tag(code: int) -> bool
Returns True if a DXFTag with given group code is present.
Parameters
code – group code as int
has_embedded_objects() -> bool
get_first_tag(code: int, default=DXFValueError) -> DXFTag
Returns first DXFTag with given group code or default, if default != DXFValueError, else
raises DXFValueError.
Parameters
• code – group code as int
• default – return value for default case or raises DXFValueError
get_first_value(code: int, default=DXFValueError) -> Any
Returns value of first DXFTag with given group code or default if default != DXFValueError,
else raises DXFValueError.
Parameters
• code – group code as int
• default – return value for default case or raises DXFValueError
find_all(code: int) -> List[DXFTag]
Returns a list of DXFTag with given group code.
Parameters
code – group code as int
filter(codes: Iterable[int]) -> Iterable[DXFTag]
Iterate and filter tags by group codes.
Parameters
codes – group codes to filter
collect_consecutive_tags(codes: Iterable[int], start: int = 0, end: int = None) -> Tags
Collect all consecutive tags with group code in codes, start and end delimits the search
range. A tag code not in codes ends the process.
Parameters
• codes – iterable of group codes
• start – start index as int
• end – end index as int, None for end index = len(self)
Returns
collected tags as Tags
tag_index(code: int, start: int = 0, end: int | None = None) -> int
Return index of first DXFTag with given group code.
Parameters
• code – group code as int
• start – start index as int
• end – end index as int, None for end index = len(self)
update(tag: DXFTag)
Update first existing tag with same group code as tag, raises DXFValueError if tag not
exist.
set_first(tag: DXFTag)
Update first existing tag with group code tag.code or append tag.
remove_tags(codes: Iterable[int]) -> None
Remove all tags inplace with group codes specified in codes.
Parameters
codes – iterable of group codes as int
remove_tags_except(codes: Iterable[int]) -> None
Remove all tags inplace except those with group codes specified in codes.
Parameters
codes – iterable of group codes
pop_tags(codes: Iterable[int]) -> Iterable[DXFTag]
Pop tags with group codes specified in codes.
Parameters
codes – iterable of group codes
classmethod strip(tags: Tags, codes: Iterable[int]) -> Tags
Constructor from tags, strips all tags with group codes in codes from tags.
Parameters
• tags – iterable of DXFTag
• codes – iterable of group codes as int
ezdxf.lldxf.tags.group_tags(tags: Iterable[DXFTag], splitcode: int = 0) -> Iterable[Tags]
Group of tags starts with a SplitTag and ends before the next SplitTag. A SplitTag is a tag with
code == splitcode, like (0, ‘SECTION’) for splitcode == 0.
Parameters
• tags – iterable of DXFTag
• splitcode – group code of split tag
class ezdxf.lldxf.extendedtags.ExtendedTags(tags: Iterable[DXFTag] = None, legacy=False)
Represents the extended DXF tag structure introduced with DXF R13.
Args: tags: iterable of DXFTag legacy: flag for DXF R12 tags
appdata
Application defined data as list of Tags
subclasses
Subclasses as list of Tags
xdata XDATA as list of Tags
embedded_objects
embedded objects as list of Tags
noclass
Short cut to access first subclass.
get_handle() -> str
Returns handle as hex string.
dxftype() -> str
Returns DXF type as string like “LINE”.
replace_handle(handle: str) -> None
Replace the existing entity handle by a new value.
legacy_repair()
Legacy (DXF R12) tags handling and repair.
clone() -> ExtendedTags
Shallow copy.
flatten_subclasses()
Flatten subclasses in legacy mode (DXF R12).
There exists DXF R12 with subclass markers, technical incorrect but works if the reader
ignore subclass marker tags, unfortunately ezdxf tries to use this subclass markers and
therefore R12 parsing by ezdxf does not work without removing these subclass markers.
This method removes all subclass markers and flattens all subclasses into
ExtendedTags.noclass.
get_subclass(name: str, pos: int = 0) -> Tags
Get subclass name.
Parameters
• name – subclass name as string like “AcDbEntity”
• pos – start searching at subclass pos.
has_xdata(appid: str) -> bool
True if has XDATA for appid.
get_xdata(appid: str) -> Tags
Returns XDATA for appid as Tags.
set_xdata(appid: str, tags: IterableTags) -> None
Set tags as XDATA for appid.
new_xdata(appid: str, tags: 'IterableTags' = None) -> Tags
Append a new XDATA block.
Assumes that no XDATA block with the same appid already exist:
try:
xdata = tags.get_xdata('EZDXF')
except ValueError:
xdata = tags.new_xdata('EZDXF')
has_app_data(appid: str) -> bool
True if has application defined data for appid.
get_app_data(appid: str) -> Tags
Returns application defined data for appid as Tags including marker tags.
get_app_data_content(appid: str) -> Tags
Returns application defined data for appid as Tags without first and last marker tag.
set_app_data_content(appid: str, tags: IterableTags) -> None
Set application defined data for appid for already exiting data.
new_app_data(appid: str, tags: 'IterableTags' = None, subclass_name: str = None) -> Tags
Append a new application defined data to subclass subclass_name.
Assumes that no app data block with the same appid already exist:
try:
app_data = tags.get_app_data('{ACAD_REACTORS', tags)
except ValueError:
app_data = tags.new_app_data('{ACAD_REACTORS', tags)
classmethod from_text(text: str, legacy: bool = False) -> ExtendedTags
Create ExtendedTags from DXF text.
Packed DXF Tags
Store DXF tags in compact data structures as list or array.array to reduce memory usage.
class ezdxf.lldxf.packedtags.TagList(data: Iterable = None)
Store data in a standard Python list.
Args: data: iterable of DXF tag values.
values Data storage as list.
clone() -> TagList
Returns a deep copy.
classmethod from_tags(tags: Tags, code: int) -> TagList
Setup list from iterable tags.
Parameters
• tags – tag collection as Tags
• code – group code to collect
clear() -> None
Delete all data values.
class ezdxf.lldxf.packedtags.TagArray(data: Iterable = None)
TagArray is a subclass of TagList, which store data in an array.array. Array type is defined by
class variable DTYPE.
Args: data: iterable of DXF tag values.
DTYPE array.array type as string
values Data storage as array.array
set_values(values: Iterable) -> None
Replace data by values.
class ezdxf.lldxf.packedtags.VertexArray(data: Iterable = None)
Store vertices in an array.array('d'). Vertex size is defined by class variable VERTEX_SIZE.
Args: data: iterable of vertex values as linear list e.g. [x1, y1, x2, y2, x3, y3, ...].
VERTEX_SIZE
Size of vertex (2 or 3 axis).
__len__() -> int
Count of vertices.
__getitem__(index: int)
Get vertex at index, extended slicing supported.
__setitem__(index: int, point: Sequence[float]) -> None
Set vertex point at index, extended slicing not supported.
__delitem__(index: int) -> None
Delete vertex at index, extended slicing supported.
__iter__() -> Iterator[Sequence[float]]
Returns iterable of vertices.
__str__() -> str
String representation.
insert(pos: int, point: Sequence[float])
Insert point in front of vertex at index pos.
Parameters
• pos – insert position
• point – point as tuple
append(point: Sequence[float]) -> None
Append point.
extend(points: Iterable[Sequence[float]]) -> None
Extend array by points.
set(points: Iterable[Sequence[float]]) -> None
Replace all vertices by points.
clear() -> None
Delete all vertices.
clone() -> VertexArray
Returns a deep copy.
classmethod from_tags(tags: Iterable[DXFTag], code: int = 10) -> VertexArray
Setup point array from iterable tags.
Parameters
• tags – iterable of DXFVertex
• code – group code to collect
export_dxf(tagwriter: AbstractTagWriter, code=10)
XData
class ezdxf.entities.xdata.XData
Internal management class for XDATA.
SEE ALSO:
• XDATA user reference: Extended Data (XDATA)
• Wrapper class to store a list in XDATA: XDataUserList
• Wrapper class to store a dict in XDATA: XDataUserDict
• Tutorial: Storing Custom Data in DXF Files
• DXF Internals: Extended Data
• DXF R2018 Reference
__contains__(appid: str) -> bool
Returns True if DXF tags for appid exist.
add(appid: str, tags: Iterable[tuple[int, Any] | DXFTag]) -> None
Add a list of DXF tags for appid. The tags argument is an iterable of (group code, value)
tuples, where the group code has to be an integer value. The mandatory XDATA marker (1001,
appid) is added automatically if front of the tags if missing.
Each entity can contain only one list of tags for each appid. Adding a second list of tags
for the same appid replaces the existing list of tags.
The valid XDATA group codes are restricted to some specific values in the range from 1000
to 1071, for more information see also the internals about Extended Data.
get(appid: str) -> Tags
Returns the DXF tags as Tags list stored by appid.
Raises DXFValueError – no data for appid exist
discard(appid)
Delete DXF tags for appid. None existing appids are silently ignored.
has_xlist(appid: str, name: str) -> bool
Returns True if list name from XDATA appid exists.
Parameters
• appid – APPID
• name – list name
get_xlist(appid: str, name: str) -> list[tuple]
Get list name from XDATA appid.
Parameters
• appid – APPID
• name – list name
Returns: list of DXFTags including list name and curly braces ‘{’ ‘}’ tags
Raises
• DXFKeyError – XDATA appid does not exist
• DXFValueError – list name does not exist
set_xlist(appid: str, name: str, tags: Iterable) -> None
Create new list name of XDATA appid with xdata_tags and replaces list name if already
exists.
Parameters
• appid – APPID
• name – list name
• tags – list content as DXFTags or (code, value) tuples, list name and curly braces
‘{’ ‘}’ tags will be added
discard_xlist(appid: str, name: str) -> None
Deletes list name from XDATA appid. Ignores silently if XDATA appid or list name not exist.
Parameters
• appid – APPID
• name – list name
replace_xlist(appid: str, name: str, tags: Iterable) -> None
Replaces list name of existing XDATA appid by tags. Appends new list if list name do not
exist, but raises DXFValueError if XDATA appid do not exist.
Low level interface, if not sure use set_xdata_list() instead.
Parameters
• appid – APPID
• name – list name
• tags – list content as DXFTags or (code, value) tuples, list name and curly braces
‘{’ ‘}’ tags will be added
Raises DXFValueError – XDATA appid do not exist
transform(m: Matrix44) -> None
Transform XDATA tags with group codes 1011, 1012, 1013, 1041 and 1042 inplace. For more
information see Extended Data Internals.
Application-Defined Data (AppData)
Starting at DXF R13, DXF objects can contain application-defined codes (AppData) outside of XDATA.
All AppData is defined with a beginning (102, “{APPID”) tag and according to the DXF reference appear
should appear before the first subclass marker.
There are two known use cases of this data structure in Autodesk products:
• ACAD_REACTORS, store handles to persistent reactors in a DXF entity
• ACAD_XDICTIONARY, store handle to the extension dictionary of a DXF entity
Both AppIDs are not defined/stored in the AppID table!
class ezdxf.entities.appdata.AppData
Internal management class for Application defined data.
SEE ALSO:
• User reference: Application-Defined Data (AppData)
• Internals about Application-Defined Codes tags
__contains__(appid: str) -> bool
Returns True if application-defined data exist for appid.
__len__() -> int
Returns the count of AppData.
add(appid: str, data: Iterable[Sequence]) -> None
Add application-defined tags for appid. Adds first tag (102, “{APPID”) if not exist. Adds
last tag (102, “}” if not exist.
get(appid: str) -> Tags
Get application-defined data for appid as Tags container. The first tag is always (102,
“{APPID”). The last tag is always (102, “}”).
set(tags: Tags) -> None
Store raw application-defined data tags. The first tag has to be (102, “{APPID”). The
last tag has to be (102, “}”).
discard(appid: str)
Delete application-defined data for appid without raising and error if appid doesn’t exist.
Reactors
class ezdxf.entities.appdata.Reactors
Internal management class for persistent reactor handles. Handles are stored as hex strings like
"ABBA".
SEE ALSO:
• User reference: Reactors
• Internals about Persistent Reactors tags
__contains__(handle: str) -> bool
Returns True if handle is registered.
__len__() -> int
Returns count of registered handles.
__iter__() -> Iterator[str]
Returns an iterator for all registered handles.
add(handle: str) -> None
Add a single handle.
get() -> list[str]
Returns all registered handles as sorted list.
set(handles: Iterable[str] | None) -> None
Reset all handles.
discard(handle: str)
Discard a single handle.
Documentation Guide
Formatting Guide
This section is only for myself, because of the long pauses between develop iterations, I often forget to
be consistent in documentation formatting.
Documentation is written with Sphinx and reSturcturedText.
Started integration of documentation into source code and using autodoc features of Sphinx wherever
useful.
Sphinx theme provided by Read the Docs :
pip install sphinx-rtd-theme
guide — Example module
guide.example_func(a: int, b: str, test: str = None, flag: bool = True) -> None
Parameters a and b are positional arguments, argument test defaults to None and flag to True. Set
a to 70 and b to “x” as an example. Inline code examples example_func(70, 'x') or simple
example_func(70, "x")
• arguments: a, b, test and flags
• literal number values: 1, 2 … 999
• literal string values: “a String”
• literal tags: (5, “F000”)
• inline code: call a example_func(x)
• Python keywords: None, True, False, tuple, list, dict, str, int, float
• Exception classes: DXFAttributeError
class guide.ExampleCls(**kwargs)
The ExampleCls constructor accepts a number of optional keyword arguments. Each keyword argument
corresponds to an instance attribute, so for example
e = ExampleCls(flag=True)
flag This is the attribute flag.
set_axis(axis)
axis as (x, y, z) tuple
Args: axis: (x, y, z) tuple
example_method(flag: bool = False) -> None
Method example_method() of class ExampleCls
Text Formatting
DXF version
DXF R12 (AC1009), DXF R2004 (AC1018)
DXF Types
DXF types are always written in uppercase letters but without further formatting: DXF, LINE,
CIRCLE
(internal API)
Marks methods as internal API, gets no public documentation.
(internal class)
Marks classes only for internal usage, gets not public documentation.
Spatial Dimensions
2D and 3D with an uppercase letter D
Axis x-axis, y-axis and z-axis
Planes xy-plane, xz-plane, yz-plane
Layouts
modelspace, paperspace [layout], block [layout]
Extended Entity Data
AppData, XDATA, embedded object, APPID
GLOSSARY
ACI AutoCAD Color Index (ACI)
ACIS The 3D ACIS Modeler (ACIS) is a geometric modeling kernel developed by Spatial Corp. ® (formerly
Spatial Technology) and now part of Dassault Systems. All ACIS based DXF entities store their
geometry as SAT or SAB data. These are not open data formats and a license has to be purchased to
get access to their SDK, therefore ezdxf can not provide any support for creating, processing or
transforming of ACIS based DXF entities.
bulge The Bulge value is used to create arc shaped line segments in Polyline and LWPolyline entities.
CAD Computer-Assisted Drafting or Computer-Aided Design
CTB Color dependent plot style table (ColorDependentPlotStyles)
DWG Proprietary file format of AutoCAD ®. Documentation for this format is available from the Open
Design Alliance (ODA) at their Downloads section. This documentation is created by reverse
engineering therefore not perfect nor complete.
DXF Drawing eXchange Format is a file format used by AutoCAD ® to interchange data with other CAD
applications. DXF is a trademark of Autodesk ®. See also What is DXF?
proxy-graphic
The proxy-graphic is an internal data format to add a graphical representation to DXF entities
which are unknown (custom DXF entities), not documented or very complex so CAD applications can
display them without knowledge about the internal structure of these entities.
raw-color
Raw color value as stored in DWG files, this integer value can represent ACI values as well as and
true-color values
reliable CAD application
CAD applications which create valid DXF documents in the meaning and interpretation of Autodesk.
See also What is DXF?
SAB ACIS file format (Standard ACIS Binary), binary stored data
SAT ACIS file format (Standard ACIS Text), data stored as ASCII text
STB Named plot style table (NamedPlotStyles)
true-color
RGB color representation, a combination red, green and blue values to define a color.
KNOWLEDGE GRAPH
I have started managing notes and documents that are not included in the ezdxf documentation in Logseq in
late 2023. It works like a wiki but does not require a backend server. The Information is edited as
Markdown files, which is much more intuitive than reStructured Text, and the content is stored in local
files.
The notes are included in the source code repository on Github in the notes folder.
A published edition of this Knowledge Graph is included on the ezdxf website and is accessible by the
link https://ezdxf.mozman.at/notes.
The Knowledge Graph includes:
• Release Notes of future releases and some versions back
• CHANGELOG
• IDEAS for future releases
• FAQ and the HOWTO sections from this documentation
• all my notes to ezdxf
• In the future the DXF Internals section from this documentation may also move to the Knowledge Graph.
Logseq’s outline structure is not ideal for all the documents I want to include, but I chose Logseq over
Obsidian.md because it is open source and can publish the knowledge graph as a static website, static in
the sense of no server-side code execution.
his feature is important to me for hosting the content of the Knowledge Graph on the ezdxf` website and
cannot be achieved for free with Obsidian.md.
Logseq is an Electron application that runs on all platforms, with the disadvantage: it’s an Electron
application.
INDICES AND TABLES
• Index
• Search Page
AUTHOR
Manfred Moitzi
COPYRIGHT
2011-2023, Manfred Moitzi
1.1.3 Nov 25, 2023 EZDXF(1)