EZDXF(1) | ezdxf | EZDXF(1) |
ezdxf - ezdxf Documentation [image]
Welcome! This is the documentation for ezdxf release 1.1.3, last updated Nov 25, 2023.
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.
https://ezdxf.mozman.at/
Documentation of development version at https://ezdxf.mozman.at/docs
Documentation of latest release at http://ezdxf.readthedocs.io/
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.
The release notes are included in the Knowledge Graph.
The changelog is included in the Knowledge Graph.
Source Code: http://github.com/mozman/ezdxf.git
Issue Tracker: http://github.com/mozman/ezdxf/issues
Forum: https://github.com/mozman/ezdxf/discussions
Please post questions at the forum or stack overflow to make answers available to other users as well.
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?
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.
Ezdxf is OS independent and runs on all platforms which provide an appropriate Python interpreter (>=3.8).
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.
The DXF format allows third-party applications to embed application-specific information. Ezdxf manages DXF data in a structure-preserving form, but for the price of large memory requirement. Because of this, processing of DXF information of third-party applications is possible and will retained on rewriting.
Ezdxf is licensed under the very liberal MIT-License.
The primary goal is to keep the dependencies of the core package as small as possible. The add-ons are not part of the core package and can therefore use as many packages as needed. The only requirement for these packages is an easy way to install them on Windows, Linux and macOS, preferably as:
pip3 install ezdxf
The packages pyparsing, numpy, fontTools and typing_extensions are the hard dependency and will be installed automatically by pip3!
The minimal required Python version is determined by the latest release version of numpy.
The most common case is the installation by pip3 including the optional C-extensions from PyPI as binary wheels:
pip3 install ezdxf
To use all features of the drawing add-on, add the [draw] tag:
pip3 install ezdxf[draw]
Tag | Additional Installed Packages |
[draw] | Matplotlib, PySide6, PyMuPDF |
[draw5] | Matplotlib, PyQt5, PyMuPDF (use only if PySide6 is not available) |
[test] | pytest |
[dev] | setuptools, wheel, Cython + [test] |
[all] | [draw] + [test] + [dev] |
[all5] | [draw5] + [test] + [dev] (use only if PySide6 is not available) |
Maybe PySide6 won’t launch on debian based distributions and shows this error message:
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. ...
This may fix the issue:
sudo apt-get install libxcb-cursor0
Ezdxf includes some C-extensions, which will be deployed automatically at each release to PyPI as binary wheels to PyPI:
The wheels are created by the continuous integration (CI) service provided by GitHub and the build container cibuildwheel provided by PyPA the Python Packaging Authority. The workflows are kept short and simple, so my future me will understand what’s going on and they are maybe also helpful for other developers which do not touch CI services every day.
The C-extensions are disabled for pypy3, because the JIT compiled code of pypy is much faster than the compiled C-extensions.
It is possible to disable the C-Extensions by setting the environment variable EZDXF_DISABLE_C_EXT to 1 or true:
set EZDXF_DISABLE_C_EXT=1
or on Linux:
export EZDXF_DISABLE_C_EXT=1
This is has to be done before anything from ezdxf is imported! If you are working in an interactive environment, you have to restart the interpreter.
Install the latest development version by pip3 from GitHub:
pip3 install git+https://github.com/mozman/ezdxf.git@master
This is only required if you want the compiled C-extensions, the ezdxf installation by pip from the source code package works without the C-extension but is slower. There are binary wheels available on PyPi which included the compiled C-extensions.
Make a build directory and a virtual environment:
mkdir build cd build py -m venv py310 py310/Scripts/activate.bat
A working C++ compiler setup is required to compile the C-extensions from source code. Windows users need the build tools from Microsoft: https://visualstudio.microsoft.com/de/downloads/
Download and install the required Visual Studio Installer of the community edition and choose the option: Visual Studio Build Tools 20..
Install required packages to build and install ezdxf with C-extensions:
pip3 install setuptools wheel cython
Clone the GitHub repository:
git clone https://github.com/mozman/ezdxf.git
Build and install ezdxf from source code:
cd ezdxf pip3 install .
Check if the installation was successful:
python3 -m ezdxf -V
The ezdxf command should run without a preceding python3 -m, but calling the launcher through the interpreter guarantees to call the version which was installed in the venv if there exist a global installation of ezdxf like in my development environment.
The output should look like this:
ezdxf 0.17.2b4 from D:\Source\build\py310\lib\site-packages\ezdxf Python version: 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] using C-extensions: yes using Matplotlib: no
To install optional packages go to section: Install Optional Packages
To run the included tests go to section: Run the Tests
I use sometimes the Windows Subsystem for Linux (WSL) with Ubuntu 20.04 LTS for some tests (how to install WSL).
By doing as fresh install on WSL & Ubuntu, I encountered an additional requirement, the build-essential package adds the required C++ support and the python3.10-dev package the required headers, change 3.10 to the Python version you are using:
sudo apt install build-essential python3.10-dev
The system Python 3 interpreter has the version 3.8 (in 2021), but I will show in a later section how to install an additional newer Python version from the source code:
cd ~ mkdir build cd build python3 -m venv py38 source py38/bin/activate
Install Cython and wheel in the venv to get the C-extensions compiled:
pip3 install cython wheel
Clone the GitHub repository:
git clone https://github.com/mozman/ezdxf.git
Build and install ezdxf from source code:
cd ezdxf pip3 install .
Check if the installation was successful:
python3 -m ezdxf -V
The output should look like this:
ezdxf 0.17.2b4 from /home/mozman/src/py38/lib/python3.8/site-packages/ezdxf Python version: 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0] using C-extensions: yes using Matplotlib: no
To install optional packages go to section: Install Optional Packages
To run the included tests go to section: Run the Tests
Testing platform is a Raspberry Pi 400 and the OS is the Raspberry Pi OS which runs on 64bit hardware but is a 32bit OS. The system Python 3 interpreter comes in version 3.7 (in 2021), but I will show in a later section how to install an additional newer Python version from the source code.
Install the build requirements, Matplotlib and the PyQt5 bindings from the distribution repository:
sudo apt install python3-pip python3-matplotlib python3-pyqt5
Installing Matplotlib and the PyQt5 bindings by pip from piwheels in the venv worked, but the packages showed errors at import, seems to be an packaging error in the required numpy package. PySide6 is the preferred Qt binding but wasn’t available on Raspberry Pi OS at the time of writing this - PyQt5 is supported as fallback.
Create the venv with access to the system site-packages for using Matplotlib and the Qt bindings from the system installation:
cd ~ mkdir build cd build python3 -m venv --system-site-packages py37 source py37/bin/activate
Install Cython and wheel in the venv to get the C-extensions compiled:
pip3 install cython wheel
Clone the GitHub repository:
git clone https://github.com/mozman/ezdxf.git
Build and install ezdxf from source code:
cd ezdxf pip3 install .
Check if the installation was successful:
python3 -m ezdxf -V
The output should look like this:
ezdxf 0.17.2b4 from /home/pi/src/py37/lib/python3.7/site-packages/ezdxf Python version: 3.7.3 (default, Jan 22 2021, 20:04:44) [GCC 8.3.0] using C-extensions: yes using Matplotlib: yes
To run the included tests go to section: Run the Tests
Because the (very well working) Raspberry Pi OS is only a 32bit OS, I searched for a 64bit alternative like Ubuntu, which just switched to version 21.10 and always freezes at the installation process! So I tried Manjaro as rolling release, which I used prior in a virtual machine and wasn’t really happy, because there is always something to update. Anyway the distribution looks really nice and has Python 3.9.9 installed.
Install build requirements and optional packages by the system packager pacman:
sudo pacman -S python-pip python-matplotlib python-pyqt5
Create and activate the venv:
cd ~ mkdir build cd build python3 -m venv --system-site-packages py39 source py39/bin/activate
The rest is the same procedure as for the Raspberry Pi OS:
pip3 install cython wheel git clone https://github.com/mozman/ezdxf.git cd ezdxf pip3 install . python3 -m ezdxf -V
To run the included tests go to section: Run the Tests
I gave the Ubuntu Server 21.10 a chance after the desktop version failed to install by a nasty bug and it worked well. The distribution comes with Python 3.9.4 and after installing some requirements:
sudo apt install build-essential python3-pip python3.9-venv
The remaining process is like on WSL & Ubuntu except for the newer Python version. Installing Matplotlib by pip works as expected and is maybe useful even on a headless server OS to create SVG and PNG from DXF files. PySide6 is not available by pip and the installation of PyQt5 starts from the source code package which I stopped because this already didn’t finished on Manjaro, but the installation of the PyQt5 bindings by apt works:
sudo apt install python3-pyqt5
Use the --system-site-packages option for creating the venv to get access to the PyQt5 package.
Install the optional dependencies by pip only for Windows 10 and WSL & Ubuntu, for Raspberry Pi OS and Manjaro on Raspberry Pi install these packages by the system packager:
pip3 install matplotlib PySide6
This is the same procedure for all systems, assuming you are still in the build directory build/ezdxf and ezdxf is now installed in the venv.
Install the test dependencies and run the tests:
pip3 install pytest python3 -m pytest tests integration_tests
Assuming you are still in the build directory build/ezdxf of the previous section.
Install Sphinx:
pip3 install Sphinx sphinx-rtd-theme
Build the HTML documentation:
cd docs make html
The output is located in build/ezdxf/docs/build/html.
Debian based systems have often very outdated software installed and sometimes there is no easy way to install a newer Python version. This is a brief summery how I installed Python 3.9.9 on the Raspberry Pi OS, for more information go to the source of the recipe: Real Python
Install build requirements:
sudo apt-get update sudo apt-get upgrade sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \ libncurses5-dev libncursesw5-dev xz-utils tk-dev
Make a build directory:
cd ~ mkdir build cd build
Download and unpack the source code from Python.org, replace 3.9.9 by your desired version:
wget https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tgz tar -xvzf Python-3.9.9.tgz cd Python-3.9.9/
Configure the build process, use a prefix to the directory where the interpreter should be installed:
./configure --prefix=/opt/python3.9.9 --enable-optimizations
Build & install the Python interpreter. The -j option simply tells make to split the building into parallel steps to speed up the compilation, my Raspberry Pi 400 has 4 cores so 4 seems to be a good choice:
make -j 4 sudo make install
The building time was ~25min and the new Python 3.9.9 interpreter is now installed as /opt/python3.9.9/bin/python3.
At the time there were no system packages for Matplotlib and PyQt5 for this new Python version available, so there is no benefit of using the option --system-site-packages for building the venv:
cd ~/build /opt/python3.9.9/bin/python3 -m venv py39 source py39/bin/activate
I have not tried to build Matplotlib and PyQt5 by myself and the installation by pip from piwheels did not work, in this case you don’t get Matplotlib support for better font measuring and the drawing add-on will not work.
Proceed with the ezdxf installation from source as shown for the Raspberry Pi OS.
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
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:
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
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:
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:
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:
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:
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:
SEE ALSO:
Save the DXF document with a new name:
doc.saveas("new_name.dxf")
or with the same name as loaded:
doc.save()
SEE ALSO:
The block definitions of a DXF document are managed by the BlocksSection object:
my_block = doc.blocks.new("MyBlock")
SEE ALSO:
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:
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:
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.
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.
The common assumption is also the cite of Wikipedia:
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:
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.
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.
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:
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:
DXF entities are objects that make up the design data stored in a DXF file.
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:
These entities are defined using specific codes and values in the DXF file format, and they can be created and manipulated by ezdxf.
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:
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.
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:
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:
Graphical entities are stored in blocks, the modelspace or paperspace layouts.
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:
Resource definitions like Layer, Linetype or Textstyle are stored in resource tables:
IMPORTANT:
SEE ALSO:
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:
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:
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:
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:
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:
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.
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.
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.
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 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.
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:
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)
In DXF R13 Autodesk introduced complex linetypes which can contain text or shapes.
SEE ALSO:
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.
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
The lineweight value can be overridden by CTB or STB files.
SEE ALSO:
AutoLISP Reference to Coordinate Systems provided by Autodesk.
To brush up you knowledge about vectors, watch the YouTube tutorials of 3Blue1Brown about Linear Algebra.
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.
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:
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:
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.
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:
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.
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.
Some of a Dimension’s points are expressed in WCS and some in OCS.
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.
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()
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)
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)
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.
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
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:
Angles are always in degrees (360 deg = full circle) in counter-clockwise orientation, unless stated explicit otherwise.
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.
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.
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
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
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 |
See also enumeration ezdxf.enums.AngularUnits
E.g. millimeter in centimeter conversion_factor(MM, CM) returns 0.1, because 1 mm = 0.1 cm
The modelspace contains the “real” world representation of the drawing subjects in real world units and is displayed in the tab called “Model” in CAD applications. The modelspace is always present and can’t be deleted.
The modelspace object is acquired by the method modelspace() of the Drawing class and new entities should be added to the modelspace by factory methods: Thematic Index of Layout Factory Methods.
This is a common idiom for creating a new document and acquiring the modelspace:
import ezdxf doc = ezdxf.new() msp = doc.modelspace()
The modelspace can have one or more rectangular areas called modelspace viewports. The modelspace viewports can be used for displaying different views of the modelspace from different locations of the modelspace or viewing directions. It is important to know that modelspace viewports (VPort) are not the same as paperspace viewport entities (Viewport).
SEE ALSO:
A paperspace layout is where the modelspace drawing content is assembled and organized for 2D output, such as printing on a sheet of paper, or as a digital document, such as a PDF file.
Each DXF document can have one or more paperspace layouts but the DXF version R12 supports only one paperspace layout and it is not recommended to rely on paperspace layouts in DXF version R12.
Graphical entities can be added to the paperspace by factory methods: Thematic Index of Layout Factory Methods. Views or “windows” to the modelspace are added as Viewport entities, each viewport displays a region of the modelspace and can have an individual scaling factor, rotation angle, clipping path, view direction or overridden layer attributes.
SEE ALSO:
Blocks are collections of DXF entities which can be placed multiple times as block references in different layouts and other block definitions. The block reference (Insert) can be rotated, scaled, placed in 3D space by OCS and arranged in a grid like manner, each Insert entity can have individual attributes (Attrib) attached.
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 block references which can be evaluated and exported by CAD applications.
Autodesk added many new features to BLOCKS (dynamic blocks, constraints) as undocumented DXF entities, many of these features are not fully supported by other CAD application and ezdxf also has no support or these features beyond the preservation of these undocumented DXF entities.
SEE ALSO:
The extents and limits of an layout represents borders which can be referenced by the ZOOM command or read from some header variables from the HeaderSection, if the creator application maintains these values – ezdxf does this not automatically.
The extents of an layout are determined by the maximum extents of all DXF entities that are in this layout. The command:
ZOOM extents
sets the current viewport to the extents of the currently selected layout.
A paperspace layout in an arbitrary zoom state: [image]
The same layout after the ZOOM extents command: [image]
Sets an invisible rectangular boundary in the drawing area that can limit the grid display and limit clicking or entering point locations. The default limits for paperspace layouts is defined by the paper size.
The layout from above after the ZOOM all command: [image]
SEE ALSO:
The extents of the modelspace (the tab called “Model”) are stored in the header variable $EXTMIN and $EXTMAX. The default values of $EXTMIN is (+1e20, +1e20, +1e20) and $EXTMAX is (-1e20, -1e20, -1e20), which do not describe real borders. These values are copies of the extents attributes of the Layout object as Layout.dxf.extmin and Layout.dxf.extmax.
The limits of the modelspace are stored in the header variables $LIMMIN and $LIMMAX and have default values of (0, 0) and (420, 297), the default paper size of ezdxf in drawing units. These are copies of the Layout attributes Layout.dxf.extmin and Layout.dxf.extmax.
The extents and the limits of the actual paperspace layout, which is the last activated paperspace layout tab, are stored in the header variable $PEXTMIN, $PEXTMAX, $PLIMMIN and $PLIMMAX.
Each paperspace layout has its own values stored in the Layout attributes Layout.dxf.extmin, Layout.dxf.extmax, Layout.dxf.limmin and Layout.dxf.limmax.
Since v0.16 ezdxf it is sufficient to define the attributes for extents and limits (Layout.dxf.extmax, Layout.dxf.limmin and Layout.dxf.limmax) of Layout object. The header variables are synchronized when the document is saved.
The extents of a layout are not calculated automatically by ezdxf, as this can take a long time for large documents and correct values are not required to create a valid DXF document.
SEE ALSO:
DXF relies on the infrastructure installed by AutoCAD like the included SHX files or True Type fonts. There is no simple way to store additional information about a used fonts beside the plain file system name like "arial.ttf". The CAD application or viewer which opens the DXF file has to have access to the specified fonts used in your DXF document or it has to use an appropriate replacement font, which is not that easy in the age of unicode. Later DXF versions can store font family names in the XDATA of the STYLE entity but not all CAD application use this information.
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:
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:
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.
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()
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.
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"): ...
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().
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:
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"]')
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:
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:
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:
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:
See also: Font Resources
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:
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 |
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:
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:
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:
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:
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:
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:
# activate on screen lineweight display doc.header["$LWDISPLAY"] = 1
SEE ALSO:
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:
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)
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:
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!
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 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"
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:
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
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")
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:
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)
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, ...]
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, )
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
WARNING:
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.
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:
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.
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:
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:
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:
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:
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:
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:
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:
If you are not familiar with the concept of blocks, please read this first: Concept of Blocks
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
A block reference can be created by adding an Insert entity to any of these layout types:
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.
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.
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")
See the howto: Get/Set Block Reference Attributes
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)
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()
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)}.")
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:
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")
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:
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")
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. |
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:
See also: Font Resources
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:
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.
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.
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:
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. """
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."
The MText entity has an alias MText.dxf.text for the MText.text attribute for compatibility to the Text entity.
IMPORTANT:
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()
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.
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.
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
MTEXT supports inline formatting by special codes: MText Inline Codes
mtext.text = "{\\C1;red text} - {\\C3;green text} - {\\C5;blue text}"
See also the support class MTextEditor.
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;"
See also the support class MTextEditor.
The MTEXT entity can have a background filling:
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]
WARNING:
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:
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)
There are three ways to change the color inline:
# 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)
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)
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)
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:
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)
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 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)
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)
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)
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)
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)
SEE ALSO:
Background information about B-spline at Wikipedia.
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)
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))
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 = []
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})
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)
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])
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
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")
WARNING:
The usage of the MeshBuilder object is also recommended for inspecting Polyface entities:
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:
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")
There exist some tools to manage meshes:
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")
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:
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")
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, )
# 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")
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.
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]
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.
Use predefined hatch pattern by name:
hatch.set_pattern_fill("ANSI31", scale=0.5)
SEE ALSO:
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 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")
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-
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-
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-
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:
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")
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:
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")
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:
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:
SEE ALSO:
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), )
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.
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))
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))
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))
But even this has its disadvantages, the attachment calculation is always based on the bounding box of the MTEXT content. [image]
There are four connection sides defined by the enum ezdxf.render.ConnectionSide:
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:
The vertical connection sides support following connection types, defined by the enum ezdxf.render.VerticalConnection:
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, )
HINT:
In contrast to the standalone MTEXT entity supports the MTEXT content entity only three text alignments defined by the enum ezdxf.render.TextAlignment.
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.
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)
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”.
There are four connection sides defined by the enum ezdxf.render.ConnectionSide:
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.
There are two alignments types, defined by the enum ezdxf.render.BlockAlignment
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]
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]
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 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")
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().
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)], )
All leader line vertices have render UCS coordinates and the start- and end-vertex of the “dogleg” is calculated automatically.
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)], )
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:
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, )
All leader lines have the same properties.
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)
All leader lines have the same arrow head and size. The available arrow heads are defined in the ARROWS object.
The overall scaling has to be applied by the set_overall_scaling() method and scales the MTEXT or BLOCK content and the arrows.
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.
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:
The scripts creates three flat geometries in the xy-plane of the WCS and a 3D mesh as content of the modelspace: [image]
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:
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:
I added the helper method page_setup() to the Drawing class and an example simple_page_setup.py how to use it.
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]
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, )
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)
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()
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:
SEE ALSO:
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.
layer = doc.layers.get("Layer0") override = layer.get_vp_overrides() override.set_linetype(vp.dxf.handle, "DASHED") override.commit()
Supported property overrides:
SEE ALSO:
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:
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.
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.
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.
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.
Defines the extrusion distance for an entity.
NOTE:
This edition shows the hard way to accomplish the transformations by low level operations.
The colors of the system axis follow the AutoCAD standard:
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]
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]
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)
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')
HINT:
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}, )
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, })
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, })
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)
And here is the point, where my math knowledge ends, for more advanced CAD operation you have to look elsewhere.
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.
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)
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]
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)
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)
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)
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)
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)
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)
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)
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:
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:
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:
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.
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")
For a vertical dimension set argument angle to 90 degree, but in this example the vertical distance would be 0.
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")
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.
The default location of the measurement text depends on various DimStyle parameters and is applied if no user defined text location is defined.
“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()
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()
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.
Beside the default location, it is possible to locate the measurement text freely.
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()
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().
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()
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()
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).
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 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]
To set this values the ezdxf.entities.DimStyle.set_text_format() and ezdxf.entities.DimStyleOverride.set_text_format() methods are very recommended.
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()
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()
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()
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()
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()
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” 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:
[image]
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” |
The tolerances and limits features are implemented by using inline codes for the MText entity, therefore DXF R2000 is required. It is not possible to use both tolerances and limits at the same time.
Geometrical tolerances are shown as additional text appended to the measurement text. It is recommend to use set_tolerance() method in DimStyleOverride or DimStyle.
The attribute dimtp defines the upper tolerance value, dimtm defines the lower tolerance value if present, else the lower tolerance value is the same as the upper tolerance value. Tolerance values are shown as given!
Same upper and lower tolerance value:
dim = msp.add_linear_dim(base=(0, 3), p1=(3, 0), p2=(6.5, 0)) dim.set_tolerance(.1, hfactor=.4, align="top", dec=2) dim.render()
Different upper and lower tolerance values:
dim = msp.add_linear_dim(base=(0, 3), p1=(3, 0), p2=(6.5, 0)) dim.set_tolerance(upper=.1, lower=.15, hfactor=.4, align="middle", dec=2) dim.render()
The attribute dimtfac specifies a scale factor for the text height of limits 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 dimtxt is set to 0.75, the text height of limits and tolerances is three-quarters the size of dimension text.
Vertical justification for tolerances is specified by dimtolj:
dimtolj | Description |
0 | Align with bottom line of dimension text |
1 | Align vertical centered to dimension text |
2 | Align with top line of dimension text |
DIMVAR | Description |
dimtol | set to 1 to enable tolerances |
dimtp | set the maximum (or upper) tolerance limit for dimension text |
dimtm | set the minimum (or lower) tolerance limit for dimension text |
dimtfac | specifies a scale factor for the text height of limits and tolerance values relative to the dimension text height, as set by dimtxt. |
dimtzin | 4 to suppress leading zeros, 8 to suppress trailing zeros or 12 to suppress both, like dimzin for dimension text, see also Text Formatting |
dimtolj | set the vertical justification for tolerance values relative to the nominal dimension text. |
dimtdec | set the number of decimal places to display in tolerance values |
The geometrical limits are shown as upper and lower measurement limit and replaces the usual measurement text. It is recommend to use set_limits() method in DimStyleOverride or DimStyle.
For limits the tolerance values are drawing units scaled by measurement factor dimlfac, the upper limit is scaled measurement value + dimtp and the lower limit is scaled measurement value - dimtm.
The attributes dimtfac, dimtzin and dimtdec have the same meaning for limits as for tolerances.
dim = msp.add_linear_dim(base=(0, 3), p1=(3, 0), p2=(6.5, 0)) dim.set_limits(upper=.1, lower=.15, hfactor=.4, dec=2) dim.render()
DIMVAR | Description |
dimlim | set to 1 to enable limits |
Alternative units are not supported.
Please read the Tutorial for Linear Dimensions before, if you haven’t.
NOTE:
import ezdxf # DXF R2010 drawing, official DXF version name: 'AC1024', # setup=True setups the default dimension styles doc = ezdxf.new("R2010", setup=True) msp = doc.modelspace() # add new dimension entities to the modelspace msp.add_circle((0, 0), radius=3) # add a CIRCLE entity, not required # add default radius dimension, measurement text is located outside dim = msp.add_radius_dim( center=(0, 0), radius=3, angle=45, dimstyle="EZ_RADIUS" ) # necessary second step, to create the BLOCK entity with the dimension geometry. dim.render() doc.saveas("radius_dimension.dxf")
The example above creates a 45 degrees slanted radius Dimension entity, the default dimension style “EZ_RADIUS” is defined as 1 drawing unit = 1m, drawing scale = 1:100 and the length factor = 100, which creates a measurement text in cm, the default location for the measurement text is outside of the circle.
The center point defines the center of the circle but there doesn’t have to exist a circle entity, radius defines the circle radius, which is also the measurement, and angle defines the slope of the dimension line, it is also possible to define the circle by a measurement point mpoint on the circle.
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the dimension entity is stored as dim.dimension.
There are different predefined DIMSTYLES to achieve various text placing locations.
The basic DIMSTYLE “EZ_RADIUS” settings are:
NOTE:
SEE ALSO:
Advanced “EZ_RADIUS” settings for placing the text outside of the circle:
tmove | 1 = add a leader when dimension text is moved, this is the best setting for text outside to preserve the appearance of the DIMENSION entity, if editing afterwards in a CAD application. |
dimtad | 1 = place the text vertical above the dimension line |
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS" ) dim.render() # always required, but not shown in the following examples
[image]
To force text outside horizontal set dimtoh to 1:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS", override={"dimtoh": 1} )
DIMSTYLE “EZ_RADIUS_INSIDE” can be used to place the dimension text inside the circle at a default location.
The basic DIMSTYLE “EZ_RADIUS_INSIDE” settings are:
Advanced “EZ_RADIUS_INSIDE” settings to place (force) the text inside of the circle:
tmove | 0 = moves the dimension line with dimension text, this is the best setting for text inside to preserve the appearance of the DIMENSION entity, if editing afterwards in a CAD application. |
dimtix | 1 = force text inside |
dimatfit | 0 = force text inside, required by BricsCAD and AutoCAD |
dimtad | 0 = center text vertical, BricsCAD and AutoCAD always create a vertical centered text, ezdxf let you choose the vertical placement (above, below, center), but editing the DIMENSION in BricsCAD or AutoCAD will reset text to center placement. |
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS_INSIDE" )
To force text inside horizontal set dimtih to 1:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS_INSIDE", override={"dimtih": 1} )
Beside the default location it is always possible to override the text location by a user defined location. This location also determines the angle of the dimension line and overrides the argument angle. For user defined locations it is not necessary to force text inside (dimtix=1), because the location of the text is explicit given, therefore the DIMSTYLE “EZ_RADIUS” can be used for all this examples.
User defined location outside of the circle:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, location=(4, 4), dimstyle="EZ_RADIUS" )
User defined location outside of the circle and forced horizontal text:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, location=(4, 4), dimstyle="EZ_RADIUS", override={"dimtoh": 1} )
User defined location inside of the circle:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, location=(1, 1), dimstyle="EZ_RADIUS" )
User defined location inside of the circle and forced horizontal text:
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, location=(1, 1), dimstyle="EZ_RADIUS", override={"dimtih": 1}, )
Center mark/lines are controlled by dimcen, default value is 0 for predefined dimstyles “EZ_RADIUS” and “EZ_RADIUS_INSIDE”:
0 | Center mark is off |
>0 | Create center mark of given size |
<0 | Create center lines |
dim = msp.add_radius_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS", override={"dimcen": 0.25}, )
[image]
See Linear Dimension Tutorial: Overriding Measurement Text
See Linear Dimension Tutorial: Measurement Text Formatting and Styling
Please read the Tutorial for Radius Dimensions before, if you haven’t.
NOTE:
This is a repetition of the radius tutorial, just with diameter dimensions.
import ezdxf # setup=True setups the default dimension styles doc = ezdxf.new("R2010", setup=True) msp = doc.modelspace() # add new dimension entities to the modelspace msp.add_circle((0, 0), radius=3) # add a CIRCLE entity, not required # add default diameter dimension, measurement text is located outside dim = msp.add_diameter_dim( center=(0, 0), radius=3, angle=45, dimstyle="EZ_RADIUS" ) dim.render() doc.saveas("diameter_dimension.dxf")
The example above creates a 45 degrees slanted diameter Dimension entity, the default dimension style “EZ_RADIUS” (same as for radius dimensions) is defined as 1 drawing unit = 1m, drawing scale = 1:100 and the length factor = 100, which creates a measurement text in cm, the default location for the measurement text is outside of the circle.
The center point defines the center of the circle but there doesn’t have to exist a circle entity, radius defines the circle radius and angle defines the slope of the dimension line, it is also possible to define the circle by a measurement point mpoint on the circle.
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the dimension entity is stored as dim.dimension.
There are different predefined DIMSTYLES to achieve various text placing locations.
The basic DIMSTYLE “EZ_RADIUS” settings are:
NOTE:
SEE ALSO:
“EZ_RADIUS” default settings for to place text outside:
tmove | 1 = add a leader when dimension text is moved, this is the best setting for text outside to preserve the appearance of the DIMENSION entity, if editing afterwards in a CAD application. |
dimtad | 1 = place the text vertical above the dimension line |
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS" ) dim.render() # always required, but not shown in the following examples
[image]
To force text outside horizontal set dimtoh to 1:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS", override={"dimtoh": 1} )
DIMSTYLE “EZ_RADIUS_INSIDE” can be used to place the dimension text inside the circle at a default location.
The basic DIMSTYLE settings are:
Advanced “EZ_RADIUS_INSIDE” settings to place (force) the text inside of the circle:
tmove | 0 = moves the dimension line with dimension text, this is the best setting for text inside to preserve the appearance of the DIMENSION entity, if editing afterwards in a CAD application. |
dimtix | 1 = force text inside |
dimatfit | 0 = force text inside, required by BricsCAD and AutoCAD |
dimtad | 0 = center text vertical, BricsCAD and AutoCAD always create a vertical centered text, ezdxf let you choose the vertical placement (above, below, center), but editing the DIMENSION in BricsCAD or AutoCAD will reset text to center placement. |
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS_INSIDE" )
To force text inside horizontal set dimtih to 1:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, angle=45, dimstyle="EZ_RADIUS_INSIDE", override={"dimtih": 1} )
Beside the default location it is always possible to override the text location by a user defined location. This location also determines the angle of the dimension line and overrides the argument angle. For user defined locations it is not necessary to force text inside (dimtix=1), because the location of the text is explicit given, therefore the DIMSTYLE “EZ_RADIUS” can be used for all this examples.
User defined location outside of the circle:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, location=(4, 4), dimstyle="EZ_RADIUS" )
User defined location outside of the circle and forced horizontal text:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, location=(4, 4), dimstyle="EZ_RADIUS", override={"dimtoh": 1} )
User defined location inside of the circle:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, location=(1, 1), dimstyle="EZ_RADIUS" )
User defined location inside of the circle and forced horizontal text:
dim = msp.add_diameter_dim( center=(0, 0), radius=2.5, location=(1, 1), dimstyle="EZ_RADIUS", override={"dimtih": 1}, )
See Radius Dimension Tutorial: Center Mark/Lines
See Linear Dimension Tutorial: Overriding Measurement Text
See Linear Dimension Tutorial: Measurement Text Formatting and Styling
Please read the Tutorial for Linear Dimensions before, if you haven’t.
NOTE:
All factory methods to create angular dimensions uses the dimension style “EZ_CURVED” for curved dimension lines which is defined as:
This DIMENSION style only exist if the argument setup is True for creating a new DXF document by ezdxf.new(). 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).
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")
The first example shows an angular dimension defined by the center point, radius, start- and end angles:
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 entities to the modelspace: msp = doc.modelspace() # Add an angular DIMENSION defined by the center point, start- and end angles, # the measurement text is placed at the default location above the dimension # line: dim = msp.add_angular_dim_cra( center=(5, 5), # center point of the angle radius= 7, # distance from center point to the start of the extension lines start_angle=60, # start angle in degrees end_angle=120, # end angle in degrees distance=3, # distance from start of the extension lines to the dimension line dimstyle="EZ_CURVED", # default angular 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("angular_dimension_cra.dxf")
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the dimension entity is stored as dim.dimension. [image]
The next example shows an angular dimension for an angle defined by two lines:
import ezdxf doc = ezdxf.new(setup=True) msp = doc.modelspace() # Setup the geometric parameters for the DIMENSION entity: base = (5.8833, -6.3408) # location of the dimension line p1 = (2.0101, -7.5156) # start point of 1st leg p2 = (2.7865, -10.4133) # end point of 1st leg p3 = (6.7054, -7.5156) # start point of 2nd leg p4 = (5.9289, -10.4133) # end point of 2nd leg # Draw the lines for visualization, not required to create the # DIMENSION entity: msp.add_line(p1, p2) msp.add_line(p3, p4) # Add an angular DIMENSION defined by two lines, the measurement text is # placed at the default location above the dimension line: dim = msp.add_angular_dim_2l( base=base, # defines the location of the dimension line line1=(p1, p2), # start leg of the angle line2=(p3, p4), # end leg of the angle dimstyle="EZ_CURVED", # default angular dimension style ) # Necessary second step to create the dimension line geometry: dim.render() doc.saveas("angular_dimension_2l.dxf")
The example above creates an angular Dimension entity to measures the angle between two lines (line1 and line2).
The base point defines the location of the dimension line (arc), any point on the dimension line is valid. The points p1 and p2 define the first leg of the angle, p1 also defines the start point of the first extension line. The points p3 and p4 define the second leg of the angle and point p3 also defines the start point of the second extension line.
The measurement of the DIMENSION entity is the angle enclosed by the first and the second leg and where the dimension line passes the base point. [image]
The next example shows an angular dimension defined by three points, a center point and the two end points of the angle legs:
import ezdxf doc = ezdxf.new(setup=True) msp = doc.modelspace() msp.add_angular_dim_3p( base=(0, 7), # location of the dimension line center=(0, 0), # center point p1=(-3, 5), # end point of 1st leg = start angle p2=(3, 5), # end point of 2nd leg = end angle ).render()
The ezdxf.math.ConstructionArc provides various class methods for creating arcs and the construction tool can be created from an ARC entity.
Add an angular dimension to an ARC entity:
import ezdxf doc = ezdxf.new(setup=True) msp = doc.modelspace() arc = msp.add_arc( center=(0, 0), radius=5, start_angle = 60, end_angle = 120, ) msp.add_angular_dim_arc( arc.construction_tool(), distance=2, ).render()
The default location of the measurement text depends on various DimStyle parameters and is applied if no user defined text location is defined.
NOTE:
SEE ALSO:
The DIMSTYLE “EZ_CURVED” places the measurement text in the center of the angle above the dimension line. The first examples above show the measurement text at the default text location.
The text direction angle is always perpendicular to the line from the text center to the center point of the angle unless this angle is manually overridden.
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_angular_dim_cra( center=(3, 3), radius=3, distance=1, start_angle=60, end_angle=120, override={ "dimtad": 1, # 0=center; 1=above; 4=below; }, ).render()
Arrows and measurement text are placed “outside” automatically if the available space between the extension lines isn’t sufficient. This overrides the dimtad value by 1 (“above”). Ezdxf follows its own rules, ignores the dimatfit attribute and works similar to dimatfit = 1, move arrows first, then text: [image]
The method shift_text() shifts the measurement text away from the default location. The shifting direction is aligned to the text rotation of the default measurement text.
dim = msp.add_angular_dim_cra( center=(3, 3), radius=3, distance=1, start_angle=60, end_angle=120, ) # shift text from default text location: dim.shift_text(0.5, 1.0) dim.render()
This is just a rendering effect, editing the dimension line in a CAD application resets the text to the default location.
Beside the default location it is always possible to override the text location by a user defined location.
The coordinates of user locations are located in the rendering UCS and the default rendering UCS is the WCS.
Absolute placing of the measurement text means relative to the origin of the render UCS. The user location is stored in the DIMENSION entity, which means editing the dimension line in a CAD application does not alter the text location. This location also determines the rotation of the measurement text.
dim = msp.add_angular_dim_cra( center=(3, 3), radius=3, distance=1, start_angle=60, end_angle=120, location=(5, 8), # user defined measurement text location ) dim.render()
Relative placing of the measurement text means relative to the middle of the dimension line. This is only possible by calling the set_location() method, and the argument relative has to be True. The user location is stored in the DIMENSION entity, which means editing the dimension line in a CAD application does not alter the text location. This location also determines the rotation of the measurement text.
dim = msp.add_angular_dim_cra( center=(3, 3), radius=3, distance=1, start_angle=60, end_angle=120, ) dim.set_location((1, 2), relative=True) dim.render()
The method set_location() has the option to add a leader line to the measurement text. This also aligns the text rotation to the render UCS x-axis, this means in the default case the measurement text is horizontal. The leader line can be “below” the text or start at the “left” or “right” center of the text, this location is defined by the dimtad attribute, 0 means “center” and any value != 0 means “below”.
for dimtad, x in [(0, 0), (4, 6)]: dim = msp.add_angular_dim_cra( center=(3 + x, 3), radius=3, distance=1, start_angle=60, end_angle=120, override={"dimtad": dimtad} # "center" == 0; "below" != 0; ) dim.set_location((1, 2), relative=True, leader=True) dim.render()
Advanced version which calculates the relative text location: The user location vector has a length 2 and the orientation is defined by center_angle pointing away from the center of the angle.
import ezdxf from ezdxf.math import Vec3 doc = ezdxf.new(setup=True) msp = doc.modelspace() for dimtad, y, leader in [ [0, 0, False], [0, 7, True], [4, 14, True], ]: for x, center_angle in [ (0, 0), (7, 45), (14, 90), (21, 135), (26, 225), (29, 270) ]: dim = msp.add_angular_dim_cra( center=(x, y), radius=3.0, distance=1.0, start_angle=center_angle - 15.0, end_angle=center_angle + 15.0, override={"dimtad": dimtad}, ) # The user location is relative to the center of the dimension line: usr_location = Vec3.from_deg_angle(angle=center_angle, length=2.0) dim.set_location(usr_location, leader=leader, relative=True) dim.render()
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).
This example uses a relative text location without a leader and forces the text rotation to 90 degrees:
for x, center_angle in [(7, 45), (14, 90), (21, 135)]: dim = msp.add_angular_dim_cra( center=(x, 0), radius=3.0, distance=1.0, start_angle=center_angle - 15.0, end_angle=center_angle + 15.0, text_rotation=90, # vertical text ) usr_location = Vec3.from_deg_angle(angle=center_angle, length=1.0) dim.set_location(usr_location, leader=False, relative=True) dim.render()
Angular units are set by dimaunit:
0 | Decimal degrees |
1 | Degrees/Minutes/Seconds, dimadec controls the shown precision 0.0 • 2 dimadec=0: 30° • 2 dimadec=2: 30°35’ • 2 dimadec=4: 30°35’25” • 2 dimadec=7: 30°35’25.15” 168u |
2 | Grad |
3 | Radians |
d1 = 15 d2 = 15.59031944 for x, (dimaunit, dimadec) in enumerate( [ (0, 4), (1, 7), (2, 4), (3, 4), ] ): dim = msp.add_angular_dim_cra( center=(x * 4.0, 0.0), radius=3.0, distance=1.0, start_angle=90.0 - d1, end_angle=90.0 + d2, override={ "dimaunit": dimaunit, "dimadec": dimadec, }, ) dim.render()
[image] [image]
See Linear Dimension Tutorial: Overriding Measurement Text
See Linear Dimension Tutorial: Measurement Text Formatting and Styling
See Linear Dimension Tutorial: Tolerances and Limits
Please read the Tutorial for Linear Dimensions before, if you haven’t. This is a repetition of the Tutorial for Angular Dimensions, because ezdxf reuses the angular dimension to render arc dimensions. This approach is very different to CAD applications, but also much less work.
NOTE:
All factory methods to create arc dimensions uses the dimension style “EZ_CURVED” for curved dimension lines which is defined as:
For more information go to: Dimension Style “EZ_CURVED”
The first example shows an arc dimension defined by the center point, radius, start- and end angles:
import ezdxf # Use argument setup=True to setup the default dimension styles. doc = ezdxf.new(setup=True) # Add new entities to the modelspace: msp = doc.modelspace() # Add an arc DIMENSION defined by the center point, start- and end angles, # the measurement text is placed at the default location above the dimension # line: dim = msp.add_arc_dim_cra( center=(5, 5), # center point of the angle radius=5, # distance from center point to the start of the extension lines start_angle=60, # start angle in degrees end_angle=120, # end angle in degrees distance=2, # distance from start of the extension lines to the dimension line dimstyle="EZ_CURVED", # default angular 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("arc_dimension_cra.dxf")
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the dimension entity is stored as dim.dimension. [image]
The next example shows an angular dimension defined by three points, a center point and the two end points of the angle legs, the first point defines the radius, the second point defines only the end angle, the distance from the center point is not relevant:
import ezdxf doc = ezdxf.new(setup=True) msp = doc.modelspace() msp.add_arc_dim_3p( base=(0, 7), # location of the dimension line center=(0, 0), # center point p1=(2.5, 4.330127018922193), # 1st point of arc defines start angle and radius p2=(-2.5, 4.330127018922194), # 2nd point defines the end angle ).render()
The ezdxf.math.ConstructionArc provides various class methods for creating arcs and the construction tool can be created from an ARC entity.
Add an angular dimension to an ARC entity:
import ezdxf doc = ezdxf.new(setup=True) msp = doc.modelspace() arc = msp.add_arc( center=(0, 0), radius=5, start_angle = 60, end_angle = 120, ) msp.add_arc_dim_arc( arc.construction_tool(), distance=2, ).render()
The default location of the measurement text depends on various DimStyle parameters and is applied if no user defined text location is defined.
NOTE:
SEE ALSO:
The DIMSTYLE “EZ_CURVED” places the measurement text in the center of the angle above the dimension line. The first examples above show the measurement text at the default text location.
The text direction angle is always perpendicular to the line from the text center to the center point of the angle unless this angle is manually overridden.
Arrows and measurement text are placed “outside” automatically if the available space between the extension lines isn’t sufficient.
For more information go to: Default Text Locations
The method shift_text() shifts the measurement text away from the default location. The shifting direction is aligned to the text rotation of the default measurement text.
For more information go to: Shift Text From Default Location
Beside the default location it is always possible to override the text location by a user defined location.
The coordinates of user locations are located in the rendering UCS and the default rendering UCS is the WCS.
For more information go to: User Defined Text Locations
Absolute placing of the measurement text means relative to the origin of the render UCS.
For more information go to: User Defined Text Locations
Relative placing of the measurement text means relative to the middle of the dimension line.
For more information go to: User Defined Text Locations
Add a leader line to the measurement text and set the text rotation to “horizontal”.
For more information go to: User Defined Text Locations
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).
For more information go to: User Defined Text Locations
See Linear Dimension Tutorial: Overriding Text Rotation
See Linear Dimension Tutorial: Measurement Text Formatting and Styling
See Linear Dimension Tutorial: Tolerances and Limits
Please read the Tutorial for Linear Dimensions before, if you haven’t.
NOTE:
Ordinate dimensioning is used when the x- and the y-coordinates from a location (feature), are the only dimensions necessary. The dimensions to each feature, originate from one datum location, called “origin” in this tutorial.
The local coordinate system (LCS) in which the measurement is done, is defined by the origin and the rotation angle around the z-axis in the rendering UCS, which is the WCS by default.
All factory methods for creating ordinate dimensions expect global coordinates to define the feature location.
The first example shows ordinate dimensions defined in the render UCS, in this example the WCS, this is how the DIMENSION entity expects the coordinates of the feature location:
import ezdxf from ezdxf.math import Vec3 from ezdxf.render import forms # Use argument setup=True to setup the default dimension styles. doc = ezdxf.new(setup=True) # Add new entities to the modelspace: msp = doc.modelspace() # Add a rectangle: width=4, height = 2.5, lower left corner is WCS(x=2, y=3) origin = Vec3(2, 3) msp.add_lwpolyline( forms.translate(forms.box(4, 2.5), origin), close=True ) # Add an x-type ordinate DIMENSION with global feature locations: msp.add_ordinate_x_dim( # lower left corner feature_location=origin + (0, 0), # feature location in the WCS offset=(0, -2), # end of leader, relative to the feature location origin=origin, ).render() msp.add_ordinate_x_dim( # lower right corner feature_location=origin + (4, 0), # feature location in the WCS offset=(0, -2), origin=origin, ).render() # Add an y-type ordinate DIMENSION with global feature locations: msp.add_ordinate_y_dim( # lower right corner feature_location=origin + (4, 0), # feature location in the WCS offset=(2, 0), origin=origin, ).render() msp.add_ordinate_y_dim( # upper right corner feature_location=origin + (4, 2.5), # feature location in the WCS offset=(2, 0), origin=origin, ).render() # 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. doc.saveas("ord_global_features.dxf")
The return value dim is not a dimension entity, instead a DimStyleOverride object is returned, the dimension entity is stored as dim.dimension. [image]
The previous examples shows that the calculation of the global feature location is cumbersome and it gets even more complicated for a rotated LCS.
This example shows how to use a render UCS for using locale coordinates to define the feature locations:
import ezdxf from ezdxf.math import Vec3, UCS from ezdxf.render import forms doc = ezdxf.new(setup=True) msp = doc.modelspace() # Create a special DIMSTYLE for "vertical" centered measurement text: dimstyle = doc.dimstyles.duplicate_entry("EZDXF", "ORD_CENTER") dimstyle.dxf.dimtad = 0 # "vertical" centered measurement text # Add a rectangle: width=4, height = 2.5, lower left corner is WCS(x=2, y=3), # rotated about 30 degrees: origin = Vec3(2, 3) msp.add_lwpolyline( forms.translate(forms.rotate(forms.box(4, 2.5), 30), origin), close=True ) # Define the rotated local render UCS. # The origin is the lower-left corner of the rectangle and the axis are # aligned to the rectangle edges: # The y-axis "uy" is calculated automatically by the right-hand rule. ucs = UCS(origin, ux=Vec3.from_deg_angle(30), uz=(0, 0, 1)) # Add a x-type ordinate DIMENSION with local feature locations: # the origin is now the origin of the UCS, which is (0, 0) the default value of # "origin" and the feature coordinates are located in the UCS: msp.add_ordinate_x_dim( # lower left corner feature_location=(0, 0), # feature location in the UCS offset=(0.25, -2), # # leader with a "knee" dimstyle="ORD_CENTER", ).render(ucs=ucs) # Important when using a render UCS! msp.add_ordinate_x_dim( # lower right corner feature_location=(4, 0), # feature location in the UCS offset=(0.25, -2), # leader with a "knee" dimstyle="ORD_CENTER", ).render(ucs=ucs) # Important when using a render UCS! # Add a y-type ordinate DIMENSION with local feature coordinates: msp.add_ordinate_y_dim( # lower right corner feature_location=(4, 0), # feature location in the UCS offset=(2, 0.25), # leader with a "knee" dimstyle="ORD_CENTER", ).render(ucs=ucs) # Important when using a render UCS! msp.add_ordinate_y_dim( # upper right corner feature_location=(4, 2.5), # feature location in the UCS offset=(2, 0.25), # leader with a "knee" dimstyle="ORD_CENTER", ).render(ucs=ucs) # Important when using a render UCS! doc.saveas("ord_local_features.dxf")
The ezdxf ordinate DIMENSION renderer places the measurement text always at the default location, because the location of the leader end point is given by the argument offset in the factory methods, which provides a flexible way to place the measurement text, overriding the text location by an explicit user location is not supported, also the user text rotation is not supported, the text is always aligned to the local coordinate system x- and y-axis.
SEE ALSO:
See Linear Dimension Tutorial: Overriding Text Rotation
See Linear Dimension Tutorial: Measurement Text Formatting and Styling
See Linear Dimension Tutorial: Tolerances and Limits
This tutorial shows how to load a GPS track into a geo located DXF file and also the inverse operation, exporting geo located DXF entities as GeoJSON files.
Please read the section Intended Usage in the documentation of the ezdxf.addons.geo module first.
WARNING:
If you are just learning to work with geospatial data, using DXF files is not the way to go! DXF is not the first choice for storing data for spatial data analysts. If you run into problems I cannot help you as I am just learning myself.
The complete source code and test data for this tutorial are available in the github repository:
https://github.com/mozman/ezdxf/tree/master/docs/source/tutorials/src/geo
The first step is setting up the geo location reference, which is not doable with ezdxf yet - this feature may come in the future - but for now you have to use a CAD application to do this. If the DXF file has no geo location reference the projected 2D coordinates are most likely far away from the WCS origin (0, 0), use the CAD command “ZOOM EXTENDS” to find the data.
The GPX format stores GPS data in a XML format, use the ElementTree class to load the data:
def load_gpx_track(p: Path) -> Iterable[Tuple[float, float]]: """Load all track points from all track segments at once.""" gpx = ET.parse(p) root = gpx.getroot() for track_point in root.findall(".//gpx:trkpt", GPX_NS): data = track_point.attrib # Elevation is not supported by the geo add-on. yield float(data["lon"]), float(data["lat"])
The loaded GPS data has a WSG84 EPSG:4326 projection as longitude and latitude in decimal degrees. The next step is to create a GeoProxy object from this data, the GeoProxy.parse() method accepts a __geo_interface__ mapping or a Python object with a __geo_interface__ attribute/property. In this case as simple “LineString” object for all GPS points is sufficient:
def add_gpx_track(msp, track_data, layer: str): geo_mapping = { "type": "LineString", "coordinates": track_data, } geo_track = geo.GeoProxy.parse(geo_mapping)
Transform the data from the polar representation EPSG:4326 into a 2D cartesian map representation EPSG:3395 called “World Mercator”, this is the only projection supported by the add-on, without the need to write a custom transformation function:
geo_track.globe_to_map()
The data is now transformed into 2D cartesian coordinates in meters and most likely far away from origin (0, 0), the data stored in the GEODATA entity helps to transform the data into the DXF WCS in modelspace units, if the DXF file has no geo location reference you have to stick with the large coordinates:
# Load geo data information from the DXF file: geo_data = msp.get_geodata() if geo_data: # Get the transformation matrix and epsg code: m, epsg = geo_data.get_crs_transformation() else: # Identity matrix for DXF files without a geo location reference: m = Matrix44() epsg = 3395 # Check for compatible projection: if epsg == 3395: # Transform CRS coordinates into DXF WCS: geo_track.crs_to_wcs(m) # Create DXF entities (LWPOLYLINE) for entity in geo_track.to_dxf_entities(dxfattribs={"layer": layer}): # Add entity to the modelspace: msp.add_entity(entity) else: print(f"Incompatible CRS EPSG:{epsg}")
We are ready to save the final DXF file:
doc.saveas(str(out_path))
In BricsCAD the result looks like this, the underlying images were added by the BricsCAD command MAPCONNECT and such a feature is not planned for the add-on: [image]
This will only work with a proper geo location reference, the code shown accepts also WCS data from DXF files without a GEODATA object, but the result is just unusable - but in valid GeoJSON notation.
First get epsg code and the CRS transformation matrix:
# Get the geo location information from the DXF file: geo_data = msp.get_geodata() if geo_data: # Get transformation matrix and epsg code: m, epsg = geo_data.get_crs_transformation() else: # Identity matrix for DXF files without geo reference data: m = Matrix44()
Query the DXF entities to export:
for track in msp.query("LWPOLYLINE"): export_geojson(track, m)
Create a GeoProxy object from the DXF entity:
def export_geojson(entity, m): # Convert DXF entity into a GeoProxy object: geo_proxy = geo.proxy(entity)
Transform DXF WCS coordinates in modelspace units into the CRS coordinate system by the transformation matrix m:
# Transform DXF WCS coordinates into CRS coordinates: geo_proxy.wcs_to_crs(m)
The next step assumes a EPSG:3395 projection, everything else needs a custom transformation function:
# Transform 2D map projection EPSG:3395 into globe (polar) # representation EPSG:4326 geo_proxy.map_to_globe()
Use the json module from the Python standard library to write the GeoJSON data, provided by the GeoProxy.__geo_interface__ property:
# Export GeoJSON data: name = entity.dxf.layer + ".geojson" with open(TRACK_DATA / name, "wt", encoding="utf8") as fp: json.dump(geo_proxy.__geo_interface__, fp, indent=2)
The content of the GeoJSON file looks like this:
{ "type": "LineString", "coordinates": [ [ 15.430999, 47.06503 ], [ 15.431039, 47.064797 ], [ 15.431206, 47.064582 ], [ 15.431283, 47.064342 ], ... }
This sections shows how to use the GDAL package to write a custom transformation function. The example reimplements the builtin transformation from unprojected WGS84 coordinates to 2D map coordinates EPSG:3395 “World Mercator”:
from osgeo import osr from ezdxf.math import Vec3 # GPS track in WGS84, load_gpx_track() code see above gpx_points = list(load_gpx_track('track1.gpx')) # Create source coordinate system: src_datum = osr.SpatialReference() src_datum.SetWellKnownGeoCS('WGS84') # Create target coordinate system: target_datum = osr.SpatialReference() target_datum.SetWellKnownGeoCS('EPSG:3395') # Create transformation object: ct = osr.CoordinateTransform(src_datum, target_datum) # Create GeoProxy() object: geo_proxy = GeoProxy.parse({ 'type': 'LineString', 'coordinates': gpx_points }) # Apply a custom transformation function to all coordinates: geo_proxy.apply(lambda v: Vec3(ct.TransformPoint(v.x, v.y)))
The same example with the pyproj package:
from pyproj import Transformer from ezdxf.math import Vec3 # GPS track in WGS84, load_gpx_track() code see above gpx_points = list(load_gpx_track('track1.gpx')) # Create transformation object: ct = Transformer.from_crs('EPSG:4326', 'EPSG:3395') # Create GeoProxy() object: geo_proxy = GeoProxy.parse({ 'type': 'LineString', 'coordinates': gpx_points }) # Apply a custom transformation function to all coordinates: geo_proxy.apply(lambda v: Vec3(ct.transform(v.x, v.y)))
Ezdxf tries to avoid to create invalid polygons from HATCH entities like a hole in another hole, but not all problems are detected by ezdxf, especially overlapping polygons. For a reliable and robust result use the Shapely package to check for valid polygons:
import ezdxf from ezdxf.addons import geo from shapely.geometry import shape # Load DXF document including HATCH entities. doc = ezdxf.readfile('hatch.dxf') msp = doc.modelspace() # Test a single entity # Get the first DXF hatch entity: hatch_entity = msp.query('HATCH').first # Create GeoProxy() object: hatch_proxy = geo.proxy(hatch_entity) # Shapely supports the __geo_interface__ shapely_polygon = shape(hatch_proxy) if shapely_polygon.is_valid: ... else: print(f'Invalid Polygon from {str(hatch_entity)}.') # Remove invalid entities by a filter function def validate(geo_proxy: geo.GeoProxy) -> bool: # Multi-entities are divided into single entities: # e.g. MultiPolygon is verified as multiple single Polygon entities. if geo_proxy.geotype == 'Polygon': return shape(geo_proxy).is_valid return True # The gfilter() function let only pass compatible DXF entities msp_proxy = geo.GeoProxy.from_dxf_entities(geo.gfilter(msp)) # remove all mappings for which validate() returns False msp_proxy.filter(validate)
The GDAL/OGR package has no direct support for the __geo_interface__, but has builtin support for the GeoJSON format:
from osgeo import ogr from ezdxf.addons import geo from ezdxf.render import random_2d_path import json p = geo.GeoProxy({'type': 'LineString', 'coordinates': list(random_2d_path(20))}) # Create a GeoJSON string from the __geo_interface__ object by the json # module and feed the result into ogr: line_string = ogr.CreateGeometryFromJson(json.dumps(p.__geo_interface__)) # Parse the GeoJSON string from ogr by the json module and feed the result # into a GeoProxy() object: p2 = geo.GeoProxy.parse(json.loads(line_string.ExportToJson()))
This tutorial describes how to store custom data in DXF files using standard DXF features.
Saving data in comments is not covered in this section, because comments are not a reliable way to store information in DXF files and ezdxf does not support adding comments to DXF files. Comments are also ignored by ezdxf and many other DXF libraries when loading DXF files, but there is a ezdxf.comments module to load comments from DXF files.
The DXF data format is a very versatile and flexible data format and supports various ways to store custom data. This starts by setting special header variables, storing XData, AppData and extension dictionaries in DXF entities and objects, storing XRecords in the OBJECTS section and ends by using proxy entities or even extending the DXF format by user defined entities and objects.
This is the common prolog for all Python code examples shown in this tutorial:
import ezdxf doc = ezdxf.new() msp = doc.modelspace()
Retrieving the is a simple task by ezdxf, but often not possible in CAD applications without using the scripting features (AutoLISP) or even the SDK.
WARNING:
The HEADER section has tow ways to store custom data.
There are ten predefined user variables, five 16-bit integer variables called $USERI1 up to $USERI5 and five floating point variables (reals) called $USERR1 up to $USERR5. This is very limited and the data maybe will be overwritten by the next application which opens and saves the DXF file. Advantage of this methods is, it works for all supported DXF versions starting at R12.
Settings the data:
doc.header["$USERI1"] = 4711 doc.header["$USERR1"] = 3.141592
Getting the data by ezdxf:
i1 = doc.header["$USERI1"] r1 = doc.header["$USERR1"]
Getting the data in BricsCAD at the command line:
: USERI1 New current value for USERI1 (-32768 to 32767) <4711>:
Getting the data by AutoLISP:
: (getvar 'USERI1) 4711
Setting the value by AutoLISP:
: (setvar 'USERI1 1234) 1234
This method defines custom document properties, but requires at least DXF R2004. The custom document properties are stored in a CustomVars instance in the custom_vars attribute of the HeaderSection object and supports only string values.
Settings the data:
doc.header.custom_vars.append("MyFirstVar", "First Value")
Getting the data by ezdxf:
my_first_var = doc.header.custom_vars.get("MyFirstVar", "Default Value")
The document property MyFirstVar is available in BricsCAD as FIELD variable: [image]
AutoLISP script for getting the custom document properties:
(defun C:CUSTOMDOCPROPS (/ Info Num Index Custom) (vl-load-com) (setq acadObject (vlax-get-acad-object)) (setq acadDocument (vla-get-ActiveDocument acadObject)) ;;Get the SummaryInfo (setq Info (vlax-get-Property acadDocument 'SummaryInfo)) (setq Num (vla-NumCustomInfo Info)) (setq Index 0) (repeat Num (vla-getCustomByIndex Info Index 'ID 'Value) (setq Custom (cons (cons ID Value) Custom)) (setq Index (1+ Index)) ) ;repeat (if Custom (reverse Custom)) )
Running the script in BricsCAD:
: (load "customdocprops.lsp") C:CUSTOMDOCPROPS : CUSTOMDOCPROPS (("MyFirstVar" . "First Value"))
Starting with version v0.16.4 ezdxf stores some meta data in the DXF file and the AppID EZDXF will be created. Two entries will be added to the MetaData instance, the CREATED_BY_EZDXF for DXF documents created by ezdxf and the entry WRITTEN_BY_EZDXF if the DXF document will be saved by ezdxf. The marker string looks like this "0.17b0 @ 2021-09-18T05:14:37.921826+00:00" and contains the ezdxf version and an UTC timestamp in ISO format.
You can add your own data to the MetaData instance as a string with a maximum of 254 characters and choose a good name which may never be used by ezdxf in the future.
metadata = doc.ezdxf_metadata() metadata["MY_UNIQUE_KEY"] = "my additional meta data" print(metadata.get("CREATED_BY_EZDXF")) print(metadata.get("MY_UNIQUE_KEY"))
The data is stored as XDATA in then BLOCK entity of the model space for DXF R12 and for DXF R2000 and later as a DXF Dictionary in the root dictionary by the key EZDXF_META. See following chapters for accessing such data by AutoLISP.
Extended Data (XDATA) is a way to attach arbitrary data to DXF entities. Each application needs a unique AppID registered in the AppID table to add XDATA to an entity. The AppID ACAD is reserved and by using ezdxf the AppID EZDXF is also registered automatically. The total size of XDATA for a single DXF entity is limited to 16kB for AutoCAD. XDATA is supported by all DXF versions and is accessible by AutoLISP.
The valid group codes for extended data are limited to the following values, see also the internals of Extended Data:
Group Code | Description |
1000 | Strings up to 255 bytes long |
1001 | (fixed) Registered application name up to 31 bytes long |
1002 | (fixed) An extended data control string '{' or '}' |
1004 | Binary data |
1005 | Database Handle of entities in the drawing database |
1010 | 3D point, in the order X, Y, Z that will not be modified at any transformation of the entity |
1011 | A WCS point that is moved, scaled, rotated and mirrored along with the entity |
1012 | A WCS displacement that is scaled, rotated and mirrored along with the entity, but not moved |
1013 | A WCS direction that is rotated and mirrored along with the entity but not moved and scaled. |
1040 | A real value |
1041 | Distance, a real value that is scaled along with the entity |
1042 | Scale Factor, a real value that is scaled along with the entity |
1070 | A 16-bit integer (signed or unsigned) |
1071 | A 32-bit signed (long) integer |
Group codes are not unique in the XDATA section and can be repeated, therefore tag order matters.
# register your appid APPID = "YOUR_UNIQUE_ID" doc.appids.add(APPID) # create a DXF entity line = msp.add_line((0, 0), (1, 0)) # setting the data line.set_xdata(APPID, [ # basic types (1000, "custom text"), (1040, 3.141592), (1070, 4711), # 16bit (1071, 1_048_576), # 32bit # points and vectors (1010, (10, 20, 30)), (1011, (11, 21, 31)), (1012, (12, 22, 32)), (1013, (13, 23, 33)), # scaled distances and factors (1041, 10), (1042, 10), ]) # getting the data if line.has_xdata(APPID): tags = line.get_xdata(APPID) print(f"{str(line)} has {len(tags)} tags of XDATA for AppID {APPID!r}") for tag in tags: print(tag)
AutoLISP script for getting XDATA for AppID YOUR_UNIQUE_ID:
(defun C:SHOWXDATA (/ entity_list xdata_list) (setq entity_list (entget (car (entsel)) '("YOUR_UNIQUE_ID"))) (setq xdata_list (assoc -3 entity_list)) (car (cdr xdata_list)) )
Script output:
: SHOWXDATA Select entity: ("YOUR_UNIQUE_ID" (1000 . "custom text") (1040 . 3.141592) ...
SEE ALSO:
The XDataUserList and XDataUserDict are helper classes to manage XDATA content in a simple way.
Both classes store the Python types int, float and str and the ezdxf type Vec3. As the names suggests has the XDataUserList a list-like interface and the XDataUserDict a dict-like interface. This classes can not contain additional container types, but multiple lists and/or dicts can be stored in the same XDATA section for the same AppID.
These helper classes uses a fixed group code for each data type:
1001 | strings (max. 255 chars) |
1040 | floats |
1071 | 32-bit ints |
1010 | Vec3 |
Additional required imports for these examples:
from ezdxf.math import Vec3 from ezdxf.entities.xdata import XDataUserDict, XDataUserList
Example for XDataUserDict:
Each XDataUserDict has a unique name, the default name is “DefaultDict” and the default AppID is EZDXF. If you use your own AppID, don’t forget to create the requited AppID table entry like doc.appids.new("MyAppID"), otherwise AutoCAD will not open the DXF file.
doc = ezdxf.new() msp = doc.modelspace() line = msp.add_line((0, 0), (1, 0)) with XDataUserDict.entity(line) as user_dict: user_dict["CreatedBy"] = "mozman" user_dict["Float"] = 3.1415 user_dict["Int"] = 4711 user_dict["Point"] = Vec3(1, 2, 3)
If you modify the content of without using the context manager entity(), you have to call commit() by yourself, to transfer the modified data back into the XDATA section.
Getting the data back from an entity:
with XDataUserDict.entity(line) as user_dict: print(user_dict) # acts like any other dict() storage = dict(user_dict)
Example for XDataUserList:
This example stores the data in a XDataUserList named “AppendedPoints”, the default name is “DefaultList” and the default AppID is EZDXF.
with XDataUserList.entity(line, name="AppendedPoints") as user_list: user_list.append(Vec3(1, 0, 0)) user_list.append(Vec3(0, 1, 0)) user_list.append(Vec3(0, 0, 1))
Now the content of both classes are stored in the same XDATA section for AppID EZDXF. The XDataUserDict is stored by the name “DefaultDict” and the XDataUserList is stored by the name “AppendedPoints”.
Getting the data back from an entity:
with XDataUserList.entity(line, name="AppendedPoints") as user_list: print(user_list) storage = list(user_list) print(f"Copy of XDataUserList: {storage}")
SEE ALSO:
Extension dictionaries are another way to attach custom data to any DXF entity. This method requires DXF R13/14 or later. I will use the short term XDICT for extension dictionaries in this tutorial.
The Extension Dictionary is a regular DXF Dictionary which can store (key, value) pairs where the key is a string and the value is a DXF object from the OBJECTS section. The usual objects to store custom data are DictionaryVar to store simple strings and XRecord to store complex data.
Unlike XDATA, custom data attached by extension dictionary will not be transformed along with the DXF entity!
This example shows how to manage the XDICT and to store simple strings as DictionaryVar objects in the XDICT, to store more complex data go to the next section XRecord.
# create a DXF entity line = msp.add_line((0, 0), (1, 0)) if line.has_extension_dict: # get the extension dictionary xdict = line.get_extension_dict() else: # create a new extension dictionary xdict = line.new_extension_dict()
2. Add strings as DictionaryVar objects to the XDICT. No AppIDs required, but existing keys will be overridden, so be careful by choosing your keys:
xdict.add_dictionary_var("DATA1", "Your custom data string 1") xdict.add_dictionary_var("DATA2", "Your custom data string 2")
3. Retrieve the strings from the XDICT as DictionaryVar objects:
print(f"DATA1 is '{xdict['DATA1'].value}'") print(f"DATA2 is '{xdict['DATA2'].value}'")
The AutoLISP access to DICTIONARIES is possible, but it gets complex and I’m only referring to the AfraLISP Dictionaries and XRecords tutorial.
SEE ALSO:
The XRecord object can store arbitrary data like the XDATA section, but is not limited by size and can use all group codes in the range from 1 to 369 for DXF Tags. The XRecord can be referenced by any DXF Dictionary, other XRecord objects (tricky ownership!), the XDATA section (store handle by group code 1005) or any other DXF object by adding the XRecord object to the Extension Dictionary of the DXF entity.
It is recommend to follow the DXF reference to assign appropriate group codes to DXF Tags. My recommendation is shown in the table below, but all group codes from 1 to 369 are valid. I advice against using the group codes 100 and 102 (structure tags) to avoid confusing generic tag loaders. Unfortunately, Autodesk doesn’t like general rules and uses DXF format exceptions everywhere.
1 | strings (max. 2049 chars) |
2 | structure tags as strings like "{" and "}" |
10 | points and vectors |
40 | floats |
90 | integers |
330 | handles |
Group codes are not unique in XRecord and can be repeated, therefore tag order matters.
This example shows how to attach a XRecord object to a LINE entity by Extension Dictionary:
line = msp.add_line((0, 0), (1, 0)) line2 = msp.add_line((0, 2), (1, 2)) if line.has_extension_dict: xdict = line.get_extension_dict() else: xdict = line.new_extension_dict() xrecord = xdict.add_xrecord("DATA1") xrecord.reset([ (1, "text1"), # string (40, 3.141592), # float (90, 256), # 32-bit int (10, (1, 2, 0)), # points and vectors (330, line2.dxf.handle) # handles ]) print(xrecord.tags)
Script output:
[DXFTag(1, 'text1'), DXFTag(40, 3.141592), DXFTag(90, 256), DXFVertex(10, (1.0, 2.0, 0.0)), DXFTag(330, '30')]
Unlike XDATA, custom data attached by extension dictionary will not be transformed along with the DXF entity! To react to entity modifications by a CAD applications it is possible to write event handlers by AutoLISP, see the AfraLISP Reactors Tutorial for more information. This is very advanced stuff!
SEE ALSO:
The UserRecord and BinaryRecord are helper classes to manage XRECORD content in a simple way. The UserRecord manages the data as plain Python types: dict, list, int, float, str and the ezdxf types Vec2 and Vec3. The top level type for the UserRecord.data attribute has to be a list. The BinaryRecord stores arbitrary binary data as BLOB. These helper classes uses fixed group codes to manage the data in XRECORD, you have no choice to change them.
Additional required imports for these examples:
from pprint import pprint import ezdxf from ezdxf.math import Vec3 from ezdxf.urecord import UserRecord, BinaryRecord from ezdxf.entities import XRecord import zlib
Example 1: Store entity specific data in the Extension Dictionary:
line = msp.add_line((0, 0), (1, 0)) xdict = line.new_extension_dict() xrecord = xdict.add_xrecord("MyData") with UserRecord(xrecord) as user_record: user_record.data = [ # top level has to be a list! "MyString", 4711, 3.1415, Vec3(1, 2, 3), { "MyIntList": [1, 2, 3], "MyFloatList": [4.5, 5.6, 7.8], }, ]
Example 1: Get entity specific data back from the Extension Dictionary:
if line.has_extension_dict: xdict = line.get_extension_dict() xrecord = xdict.get("MyData") if isinstance(xrecord, XRecord): user_record = UserRecord(xrecord) pprint(user_record.data)
If you modify the content of UserRecord.data without using the context manager, you have to call commit() by yourself, to store the modified data back into the XRECORD.
Example 2: Store arbitrary data in DICTIONARY objects. The XRECORD is stored in the named DICTIONARY, called rootdict in ezdxf. This DICTIONARY is the root entity for the tree-like data structure stored in the OBJECTS section, see also the documentation of the ezdxf.sections.objects module.
# Get the existing DICTIONARY object or create a new DICTIONARY object: my_dict = doc.objects.rootdict.get_required_dict("MyDict") # Create a new XRECORD object, the DICTIONARY object is the owner of this # new XRECORD: xrecord = my_dict.add_xrecord("MyData") # This example creates the user record without the context manager. user_record = UserRecord(xrecord) # Store user data: user_record.data = [ "Just another user record", 4711, 3.1415, ] # Store user data in associated XRECORD: user_record.commit()
Example 2: Get user data back from the DICTIONARY object
my_dict = doc.rootdict.get_required_dict("MyDict") entity = my_dict["MyData"] if isinstance(entity, XRecord): user_record = UserRecord(entity) pprint(user_record.data)
Example 3: Store arbitrary binary data
my_dict = doc.rootdict.get_required_dict("MyDict") xrecord = my_dict.add_xrecord("MyBinaryData") with BinaryRecord(xrecord) as binary_record: # The content is stored as hex strings (e.g. ABBAFEFE...) in one or more # group code 310 tags. # A preceding group code 160 tag stores the data size in bytes. data = b"Store any binary data, even line breaks\r\n" * 20 # compress data if required binary_record.data = zlib.compress(data, level=9)
Example 3: Get binary data back from the DICTIONARY object
entity = my_dict["MyBinaryData"] if isinstance(entity, XRecord): binary_record = BinaryRecord(entity) print("\ncompressed data:") pprint(binary_record.data) print("\nuncompressed data:") pprint(zlib.decompress(binary_record.data))
HINT:
SEE ALSO:
Application-Defined Data (AppData) was introduced in DXF R13/14 and is used by AutoCAD internally to store the handle to the Extension Dictionary and the Reactors in DXF entities. Ezdxf supports these kind of data storage for any AppID and the data is preserved by AutoCAD and BricsCAD, but I haven’t found a way to access this data by AutoLISP or even the SDK. So I don’t recommend this feature to store application defined data, because Extended Data (XDATA) and the Extension Dictionary are well documented and safe ways to attach custom data to entities.
# register your appid APPID = "YOUR_UNIQUE_ID" doc.appids.add(APPID) # create a DXF entity line = msp.add_line((0, 0), (1, 0)) # setting the data line.set_app_data(APPID, [(300, "custom text"), (370, 4711), (460, 3.141592)]) # getting the data if line.has_app_data(APPID): tags = line.get_app_data(APPID) print(f"{str(line)} has {len(tags)} tags of AppData for AppID {APPID!r}") for tag in tags: print(tag)
Printed output:
LINE(#30) has 3 tags of AppData for AppID 'YOUR_UNIQUE_ID' (300, 'custom text') (370, 4711) (460, 3.141592)
This tutorial uses the ezdxf.xref module to work with external references (XREF).
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.
IMPORTANT:
The drawing add-on included in ezdxf does not display external references at all!
There are some example files included in the examples/xref folder of the repository:
All operations which move entities between layouts and XREFs copy these entities, therefore only entities which are copyable can be transferred. The following entities are not copyable:
Unsupported entities are ignored and do not raise exceptions.
Required imports to follow this tutorial:
import ezdxf from ezdxf.addons import odafc from ezdxf.document import Drawing from ezdxf import xref, units, colors from ezdxf.render import forms DXFVERSION = "R2013"
Function to create a simple DXF file as XREF, the insertion point of the XREF is set to (5, 5):
def make_dxf_xref_document(name: str) -> Drawing: ref_doc = ezdxf.new(DXFVERSION, units=units.M) ref_doc.layers.add("GEAR", color=colors.YELLOW) msp = ref_doc.modelspace() gear = forms.gear( 16, top_width=0.25, bottom_width=0.75, height=0.5, outside_radius=2.5 ) msp.add_lwpolyline( forms.translate(gear, (5, 5)), close=True, dxfattribs={"layer": "GEAR"} ) ref_doc.header["$INSBASE"] = (5, 5, 0) ref_doc.saveas(name) return ref_doc
Create the DXF file:
make_dxf_xref_document("xref.dxf")
The XREF looks like this: [image]
Create a host document to which the XREF will be attached:
host_doc = ezdxf.new(DXFVERSION, units=units.M)
Attach the XREF by the ezdxf.xref.attach() function and save the host DXF file:
xref.attach(host_doc, block_name="dxf_xref", insert=(0, 0), filename="attached_xref.dxf") host_doc.set_modelspace_vport(height=10, center=(0, 0)) host_doc.saveas("attach_host_dxf.dxf")
The attach() function is meant to simply attach an XREF once without any overhead, therefore the attach() function creates the required block definition automatically and raises an XrefDefinitionError exception if the block definition already exist. To attach additional XREF references use the method add_blockref():
msp.add_blockref("dxf_xref", insert=another_location)
The attached DXF file in BricsCAD: [image]
IMPORTANT:
Export the DXF file as DWG by the odafc add-on:
# It's not required to save the DXF file! doc = make_dxf_xref_document("attached_xref.dxf") try: odafc.export_dwg(doc, "attached_xref.dwg", replace=True) except odafc.ODAFCError as e: print(str(e))
Attach the DWG file by the ezdxf.xref.attach() function and save the host DXF file:
host_doc = ezdxf.new(DXFVERSION, units=units.M) xref.attach(host_doc, block_name="dwg_xref", filename="attached_xref.dwg", insert=(0, 0)) host_doc.set_modelspace_vport(height=10, center=(0, 0)) host_doc.saveas("attached_dwg.dxf")
Attached DWG file in Autodesk DWG TrueView 2023: [image]
The detach() function writes the content of a block definition into the modelspace of a new DXF document and convert the block to an external reference (XREF). The new DXF document has to be written/exported by the caller. 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.
host_doc = ezdxf.new() make_block(host_doc, "GEAR") block_layout = host_doc.blocks.get("GEAR") detached_block_doc = xref.detach(block_layout, xref_filename="detached_gear.dxf") detached_block_doc.saveas("detached_gear.dxf") host_doc.set_modelspace_vport(height=10, center=(0, 0)) host_doc.saveas("detach_host_dxf_xref.dxf")
IMPORTANT:
The detach() function returns a Drawing instance, so it’s possible to convert the DXF document to DWG by the odafc add-on if necessary (e.g. for Autodesk products). It’s important that the argument xref_filename match the filename of the exported DWG file:
host_doc = ezdxf.new() make_block(host_doc, "GEAR") block_layout = host_doc.blocks.get("GEAR") detached_block_doc = xref.detach(block_layout, xref_filename="detached_gear.dwg") try: odafc.export_dwg(detached_block_doc, "detached_gear.dwg", replace=True) except odafc.ODAFCError as e: print(str(e)) host_doc.set_modelspace_vport(height=10, center=(0, 0)) host_doc.saveas("detach_host_dwg_xref.dxf")
It’s recommended to clean up the entity database of the host document afterwards:
host_doc.entitydb.purge()
For understanding, this is the make_block() function:
def make_block(doc: Drawing, name: str) -> None: blk = doc.blocks.new(name, base_point=(5, 5, 0)) doc.layers.add("GEAR", color=colors.YELLOW) gear = forms.gear( 16, top_width=0.25, bottom_width=0.75, height=0.5, outside_radius=2.5 ) blk.add_lwpolyline( forms.translate(gear, (5, 5)), close=True, dxfattribs={"layer": "GEAR"} ) doc.modelspace().add_blockref(name, (0, 0))
The embed() function loads the content of the XREF into the block definition, this is the reverse operation of detaching an XREF.
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().
This example embeds the XREF “attached_xref.dwg” of the first example as content of the block definition “GEAR”, the “attach_host_dwg.dxf” file is the host DXF document:
import ezdxf from ezdxf.addons import odafc doc = ezdxf.readfile("attach_host_dwg.dxf") gear_xref = doc.blocks.get("GEAR") try: xref.embed(gear_xref, load_fn=odafc.readfile) except FileNotFoundError as e: print(str(e))
The default loading function for DXF files is the ezdxf.readfile() function and doesn’t have to be specified. For the loading function from the recover module use a lambda function:
import ezdxf from ezdxf import recover doc = ezdxf.readfile("attach_host_dxf.dxf") gear_xref = doc.blocks.get("GEAR") try: xref.embed(gear_xref, load_fn=lambda f: recover.readfile(f)[0]) except FileNotFoundError as e: print(str(e))
The ezdxf.xref.load_modelspace() function 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.
HINT:
Merge multiple DXF files:
import ezdxf from ezdxf import colors, transform, xref from ezdxf.math import Matrix44 from ezdxf.render import forms def make_gear(name: str) -> None: doc = ezdxf.new() doc.layers.add("GEAR", color=colors.YELLOW) msp = doc.modelspace() gear = forms.gear( 16, top_width=0.25, bottom_width=0.75, height=0.5, outside_radius=2.5 ) msp.add_lwpolyline(gear, close=True, dxfattribs={"layer": "GEAR"}) doc.saveas(name) make_gear("gear.dxf") merged_doc = ezdxf.new() for index in range(3): sdoc = ezdxf.readfile("gear.dxf") # this could be different DXF files transform.inplace(sdoc.modelspace(), Matrix44.translate(index * 10, 0, 0)) xref.load_modelspace(sdoc, merged_doc) merged_doc.saveas("merged.dxf")
The function ezdxf.xref.load_paperspace() loads a paperspace layout as a new paperspace layout into the target document. To be clear this function loads only the content of the paperspace layout, the content of the modelspace isn’t loaded, therefore the loaded VIEWPORT entities show the content of the target modelspace.
The function ezdxf.xref.write_block() writes the given entities into the modelspace of a new DXF document, this document can be, but doesn’t have to be used as an external referenced block.
Resources are definitions of layers, linetypes, text-, dimension-, mline- and mleader styles, materials and blocks.
A resource conflict occurs when the source and target documents contain elements such as layers, linetypes, text styles and so on that share the same name.
Many of the functions shown above support an argument to define the ezdxf.xref.ConflictPolicy, that gives you the choice how to handle resource name conflicts.
Keeps the existing resource name of the target document and ignore the resource from the source document. The loaded entities from the source document use the resources defined in the target document and may alter their visual appearance, when the resources are different.
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.
IMPORTANT:
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.
IMPORTANT:
Resources are definitions of layers, linetypes, text-, dimension-, mline- and mleader styles, materials and blocks.
The Loader class is the low level tool to build a loading operation from simple loading commands. Study the source code of the xref module, most of loading commands used above are build upon the Loader class. This example shows how to import layer, linetype, text- and dimension style definitions:
import ezdxf from ezdxf import xref sdoc = ezdxf.new(setup=True) tdoc = ezdxf.new() # The default conflict policy is ConflictPolicy.KEEP loader = xref.Loader(sdoc, tdoc) # Load all layers: loader.load_layers([layer.dxf.name for layer in sdoc.layers]) # Load specific linetypes: loader.load_linetypes(["CENTER", "DASHED", "DASHDOT"]) # Load specific text style: loader.load_text_styles(["OpenSans", "LiberationMono"]) # Load all DIMENSION styles, this command loads also the dependent text styles: loader.load_dim_styles([dimstyle.dxf.name for dimstyle in sdoc.dimstyles]) # execute all loading commands: loader.execute() tdoc.saveas("target.dxf")
NOTE:
This tutorial shows how to export DXF content of the modelspace or a paperspace as images by the drawing add-on.
The tutorial covers the new added backends in ezdxf version 1.1:
The tutorial does not cover the MatplotlibBackend and PyQtBackend, for information about these backends see:
The rendering process is divided into multiple steps. The frontend resolves the DXF properties and breaks down complex DXF entities into simple drawing primitives which are send to the backend that renders the output format.
import ezdxf from ezdxf.addons.drawing import Frontend, RenderContext, svg, layout def example_doc(): doc = ezdxf.new() msp = doc.modelspace() x0, y0, x1, y1 = 0, 0, 10, 10 start = (x0, y0) end = (x0 + 1, y0) for color in range(1, 6): msp.add_lwpolyline( [start, (x0, y1), (x1, y1), (x1, y0), end], dxfattribs={"color": color} ) x0 += 1 x1 -= 1 y0 += 1 y1 -= 1 start = end end = (x0 + 1, y0) return doc def export(doc): msp = doc.modelspace() # 1. create the render context context = RenderContext(doc) # 2. create the backend backend = svg.SVGBackend() # 3. create the frontend frontend = Frontend(context, backend) # 4. draw the modelspace frontend.draw_layout(msp) # 5. create an A4 page layout, not required for all backends page = layout.Page(210, 297, layout.Units.mm, margins=layout.Margins.all(20)) # 6. get the SVG rendering as string - this step is backend dependent svg_string = backend.get_string(page) with open("output.svg", "wt", encoding="utf8") as fp: fp.write(svg_string) if __name__ == "__main__": export(example_doc())
The exported SVG shows a spiral centered on an A4 page with a margin of 20mm, notice the background has a dark color like the usual background of the modelspace: [image]
The Configuration object configures the rendering process. This example changes the background color from dark grey to white and renders all lines black.
Add the config module to imports:
from ezdxf.addons.drawing import Frontend, RenderContext, svg, layout, config
Create a new configuration and override the background and color policy between the 2nd and the 3rd step:
# 2. create the backend backend = svg.SVGBackend() # create a new configuration for a white background and and a black foreground color cfg = config.Configuration( background_policy=config.BackgroundPolicy.WHITE, color_policy=config.ColorPolicy.BLACK, ) # 3. create the frontend frontend = Frontend(context, backend, config=cfg)
The new exported SVG has a white background and all lines are black: [image]
There are many configuration options:
All configuration options are documented here: Configuration.
The Page object defines the output page for some backends (SVG, PDF, PNG, PLT).
A page is defined by width and height in a given length unit. The supported length units are millimeters (mm), inch (in), point (1 pt is 1/72 in) and pixels (1 px is 1/96 in).
It’s possible to autodetect the page size from the content or fit the content onto the page. In both cases the margin values are used to create space between the content and the page borders. The content is centered in the remaining space without margins.
IMPORTANT:
The required page size is auto-detected by setting the width and/or height to 0. By default the scaling factor is 1, so 1 drawing unit is 1 page unit. The content is fit to page by default and the outcome is shown in the previous examples.
This example shows the output when the scale should be 1:1, 1 drawing unit is 1 page unit (mm):
# auto-detect page size and 2mm margins on all sides page = layout.Page(0, 0, layout.Units.mm, margins=layout.Margins.all(2)) # scale content by 1, do not fit content to page svg_string = backend.get_string( page, settings=layout.Settings(scale=1, fit_page=False) )
The page has a size of 14x14mm, a content size of 10x10mm and 2mm margins on all sides. [image]
Scaling the content by factor 10 means, 10 page units represent 1 drawing unit, which is a scale of 10:1 and only uniform scaling is supported.
def export_2(doc): backend = make_backend(doc) # auto-detect page size and 2mm margins on all sides page = layout.Page(0, 0, layout.Units.mm, margins=layout.Margins.all(2)) # scale content by 10, do not fit content to page svg_string = backend.get_string(
The page has a size of 104x104mm, a content size of 100x100mm and 2mm margins on all sides. [image]
The page arguments max_width and max_height can limit the page size in auto-detection mode, e.g. most plotter devices can only print upto a width of 900mm.
SEE ALSO:
The steps to export a SVG by the SVGBackend are show in the first example, the configuration of the frontend and the page setup are shown in the previous sections.
This is the same code as for the first example:
def export(doc): msp = doc.modelspace() # 1. create the render context context = RenderContext(doc) # 2. create the backend backend = svg.SVGBackend() # 3. create the frontend frontend = Frontend(context, backend) # 4. draw the modelspace frontend.draw_layout(msp) # 5. create an A4 page layout, not required for all backends page = layout.Page(210, 297, layout.Units.mm, margins=layout.Margins.all(20)) # 6. get the SVG rendering as string - this step is backend dependent svg_string = backend.get_string(page) with open("output.svg", "wt", encoding="utf8") as fp: fp.write(svg_string)
The SVG backend flips the coordinates along the y-axis and transforms the content into a compact integer coordinate space and produces therefore a small file size but therefore the output coordinates are different to the DXF coordinates.
The PDF export requires the the PyMuPdf package to be installed.
The steps to export a PDF are very similar to SVG, except for the PyMuPdfBackend class and the backend returns bytes and not a string:
Import the pymupdf backend module:
from ezdxf.addons.drawing import Frontend, RenderContext, pymupdf, layout, config
The export function:
def export_dark_bg(doc): msp = doc.modelspace() # 1. create the render context context = RenderContext(doc) # 2. create the backend backend = pymupdf.PyMuPdfBackend() # 3. create the frontend frontend = Frontend(context, backend) # 4. draw the modelspace frontend.draw_layout(msp) # 5. create an A4 page layout page = layout.Page(210, 297, layout.Units.mm, margins=layout.Margins.all(20)) # 6. get the PDF rendering as bytes pdf_bytes = backend.get_pdf_bytes(page) with open("pdf_dark_bg.pdf", "wb") as fp: fp.write(pdf_bytes)
The PDF has is dark background for the modelspace by default and color index 7 is white. Create a frontend configuration and override the BackgroundPolicy to get a white background:
# 3. create and configure the frontend cfg = config.Configuration(background_policy=config.BackgroundPolicy.WHITE) frontend = Frontend(context, backend, config=cfg)
Now the exported PDF has a white background and color index 7 is black: [image]
The PNG export is done by the PyMuPdfBackend class and differs only in the method to get the PNG data bytes:
# 6. get the PNG rendering as bytes png_bytes = backend.get_pixmap_bytes(page, fmt="png", dpi=96) with open("png_white_bg.png", "wb") as fp: fp.write(png_bytes)
The pymupdf backend supports multiple image formats:
png | Portable Network Graphics |
ppm | Portable Pixmap (no alpha channel) |
pbm | Portable Bitmap (no alpha channel) |
The PlotterBackend creates HPGL/2 plot files for output on raster plotters. The PlotterBackend is designed to print on white paper, so the background color is always white and color index 7 is black by default.
WARNING:
The PLT/HPGL2 export is very similar to the SVG export:
from ezdxf.addons.drawing import Frontend, RenderContext, hpgl2, layout def export(doc): msp = doc.modelspace() # 1. create the render context context = RenderContext(doc) # 2. create the backend backend = hpgl2.PlotterBackend() # 3. create the frontend frontend = Frontend(context, backend) # 4. draw the modelspace frontend.draw_layout(msp) # 5. create an A4 page layout page = layout.Page(210, 297, layout.Units.mm, margins=layout.Margins.all(20)) # 6. get the HPGL2 rendering as bytes plt_bytes = backend.get_bytes(page) with open("output_01.plt", "wb") as fp: fp.write(plt_bytes)
The HPGL/2 viewer does not show the margins around the content, but most construction drawings draw the page borders around the content.
The PlotterBackend has some quality preset methods to get the HPGL/2 data:
The difference are mostly the floating point precision and the usage of Bézier curves, but the Bézier curves are approximated by plotter drivers (even by HP drivers), so there is no real quality improvement, but curves need less space than approximated polylines so the file size is smaller.
Very old plotter may not support Bézier curves and floating point coordinates, for these plotters the compatible() method exports only polylines and integer coordinates.
Usage:
# 6. get the HPGL2 rendering as bytes plt_bytes = backend.high_quality(page)
The DXFBackend exports the content as DXF primitives: POINT, LINE, LWPOLYLINE, SPLINE and HATCH. All blocks are exploded, text is rendered as filled polygons represented by the HATCH entity and arcs are represented by SPLINE entities (internal Bèzier curve representation).
This backend was added to convert HPGL/2 files to DXF files, because the hpgl2 add-on reuses the backends of the drawing add-on for export. Maybe it is useful for other tasks too.
This backend works different than the previous. There is no page setup and everything is rendered into a given layout of a DXF document:
from ezdxf.addons.drawing import Frontend, RenderContext, dxf def export(doc): export_doc = ezdxf.new() msp = doc.modelspace() # 1. create the render context context = RenderContext(doc) # 2. create the backend backend = dxf.DXFBackend(export_doc.modelspace()) # 3. create the frontend frontend = Frontend(context, backend) # 4. draw the modelspace frontend.draw_layout(msp) # 5. save or return DXF document export_doc.saveas("output_01.dxf")
The Recorder backend is an intermediate layer to record the drawing commands of the Frontend class. The Player object can replay this records on any other backend class but also provides some additional features like bounding box detection, content transformation and cropping.
The SVG/PDF/PLT backends use this intermediate layer internally to transform and place the content.
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.
IMPORTANT:
The ezdxf.xref module provides an interface for working with XREFs.
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:
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.
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.
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.
msp.add_blockref(block_name, insert=another_location)
IMPORTANT:
New in version 1.1.
XREF attachment types:
New in version 1.1.
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.
New in version 1.1.
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.
New in version 1.1.
New in version 1.1.
New in version 1.1.
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.
New in version 1.1.
New in version 1.1.
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.
The content of the modelspace which may be displayed through a VIEWPORT entity will not be loaded!
The content of the modelspace which may be displayed through a VIEWPORT entity will not be loaded!
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 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.
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
ezdxf has an interface to get and set HEADER variables:
doc.header["VarName"] = value value = doc.header["VarName"]
SEE ALSO:
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.
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:
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.
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:
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 visibility of the UCS icon is controlled by the DXF ucs_icon attribute of the VPort entity:
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
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 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 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)
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).
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))
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:
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:
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:
See section “General Document”: Set Initial View/Zoom for the Modelspace
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
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()
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.
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 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
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 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:
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.
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()
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:
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}")
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.
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:
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:
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.
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
This section consolidates the FAQ about the drawing add-on from the github forum.
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-
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:
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)
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)
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:
def my_filter(e: DXFGraphic) -> bool: return e.dxf.get("color", 7) != 2
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:
SEE ALSO:
SEE ALSO:
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()
This is the reverse operation of the previous how-to: How to Get the Pixel Coordinates of DXF Entities
SEE ALSO:
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)}")
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:
# -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)
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:
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:
# -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)
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:
# -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)
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)
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:
# -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)
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:
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:
These are the old FAQ until late 2023, new FAQs will only be added to the Knowledge Graph.
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.
Did you name your file/script “ezdxf.py”? This causes problems with circular imports. Renaming your file/script should solve this issue.
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/
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..
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).
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
There is a dedicated how-to section for the Drawing Add-on.
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.
The DXF Reference is online available at Autodesk.
Quoted from the original DXF 12 Reference which is not available on the web:
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
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 |
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 |
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.
specify decoding error handler
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.
specify decoding error handler
specify decoding error handler
HINT:
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
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.
$ACADVER | DXF version |
$TDCREATE | date/time at creating the drawing |
$FINGERPRINTGUID | every drawing gets a GUID |
$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:
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:
Example of the ezdxf marker string: 0.16.4b1 @ 2021-06-12T07:35:34.898808+00:00
The Drawing class is the central management structure of a DXF document.
For supported DXF versions see Document Management
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 |
requires DXF R13 or later
Reference to the layers table, where you can create, get and remove layers, see also Table and Layer
Reference to the styles table, see also Textstyle.
Reference to the dimstyles table, see also DimStyle.
Reference to the linetypes table, see also Linetype.
Reference to the views table, see also View.
Reference to the viewports table, see also VPort.
Reference to the ucs table, see also UCSTableEntry.
Reference to the appids table, see also AppID.
If writing to a StringIO stream, use Drawing.encode() to encode the result string from StringIO.get_value():
binary = doc.encode(stream.get_value())
SEE ALSO:
SEE ALSO:
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.
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().
SEE ALSO:
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 |
SEE ALSO:
If you are messing around with internal structures, call this method before saving to be sure to export valid DXF documents, but be aware this is a long-running task.
Returns: False if unrecoverable errors exist
This module provides functions to “recover” ASCII DXF documents with structural flaws, which prevents the regular ezdxf.read() and ezdxf.readfile() functions to load the document.
The read() and readfile() functions will repair as much flaws as possible and run the required audit process automatically afterwards and return the result of this audit process:
import sys import ezdxf from ezdxf import recover try: doc, auditor = recover.readfile("messy.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) # DXF file can still have unrecoverable errors, but this is maybe just # a problem when saving the recovered DXF file. if auditor.has_errors: auditor.print_error_report()
The loading functions also decode DXF-Unicode encoding automatically e.g. “\U+00FC” -> “ü”. All these efforts cost some time, loading the DXF document with ezdxf.read() or ezdxf.readfile() is faster.
WARNING:
Writing such files back with ezdxf may create invalid DXF files, or at least some information will be lost - handle with care!
To avoid this problem use recover.readfile(filename, errors='strict') which raises an UnicodeDecodeError exception for such binary data. Catch the exception and handle this DXF files as unrecoverable.
Mostly DXF files from AutoCAD or BricsCAD (e.g. for In-house solutions):
try: doc = ezdxf.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 files have only minor flaws, like undefined resources:
try: doc = ezdxf.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) auditor = doc.audit() if auditor.has_errors: auditor.print_error_report()
From trusted and untrusted sources but with good hopes, the worst case works like a cache miss, you pay for the first try and pay the extra fee for the recover mode:
try: # Fast path: doc = ezdxf.readfile(name) except IOError: print(f'Not a DXF file or a generic I/O error.') sys.exit(1) # Catch all DXF errors: except ezdxf.DXFError: try: # Slow path including fixing low level structures: doc, auditor = recover.readfile(name) 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()
Untrusted sources and expecting many invalid or corrupted DXF files, you always pay an extra fee for the recover mode:
try: # Slow path including fixing low level structures: 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()
If files contain binary data which can not be decoded by the document encoding, it is maybe the best to ignore these files, this works in normal and recover mode:
try: doc, auditor = recover.readfile(name, errors='strict') 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) except UnicodeDecodeError: print(f'Decoding error in DXF file: {name}.') sys.exit(3)
Sometimes ignoring decoding errors can recover DXF files or at least you can detect where the decoding errors occur:
try: doc, auditor = recover.readfile(name, errors='ignore') 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) if auditor.has_errors: auditor.print_report()
The error messages with code AuditError.DECODING_ERROR shows the approximate line number of the decoding error: “Fixed unicode decoding error near line: xxx.”
HINT:
specify decoding error handler
specify decoding error handler
specify decoding error handler
New in version 1.1.
Due to ACAD release 14 the resource names, such as layer-, linetype, text style-, dimstyle- and block names, were limited to 31 characters in length and all names were uppercase.
Names can include the letters A to Z, the numerals 0 to 9, and the special characters, dollar sign "$", underscore "_", hyphen "-" and the asterix "*" as first character for special names like anonymous blocks. Most applications do not care about that and work fine with longer names and any characters used in names for some exceptions, but of course Autodesk applications are very picky about that.
The function make_acad_compatible() makes DXF R12 drawings to 100% compatible to Autodesk products and does everything at once, but the different processing steps can be called manually.
IMPORTANT:
import ezdxf from ezdxf import r12strict doc = ezdxf.readfile("r12sloppy.dxf") r12strict.make_acad_compatible(doc) doc.saveas("r12strict.dxf")
make_acad_compatible | Apply all DXF R12 requirements, so Autodesk products will load the document. |
translate_names | Translate table and block names into strict DXF R12 names. |
clean | Removes all features that are not supported for DXF R12 by Autodesk products. |
ACAD Releases upto 14 limit names to 31 characters in length and all names are uppercase. Names can include the letters A to Z, the numerals 0 to 9, and the special characters, dollar sign ($), underscore (_), hyphen (-) and the asterix (*) as first character for special names like anonymous blocks.
Most applications do not care about that and work fine with longer names and any characters used in names for some exceptions, but of course Autodesk applications are very picky about that.
NOTE:
ACAD Releases upto 14 limit names to 31 characters in length and all names are uppercase. Names can include the letters A to Z, the numerals 0 to 9, and the special characters, dollar sign ($), underscore (_), hyphen (-) and the asterix (*) as first character for special names like anonymous blocks.
This is a high-level module for working with CAD application settings and behaviors. None of these settings have any influence on the behavior of ezdxf, since ezdxf only takes care of the content of the DXF file and not of the way it is presented to the user.
IMPORTANT:
The current properties are used by the CAD application to create new entities, these settings do not affect how ezdxf creates new entities.
The module ezdxf.gfxattribs provides the class GfxAttribs(), which can load the current graphical entity settings from the HEADER section for creating new entities by ezdxf: load_from_header()
The function updates only the values in the HEADER section, to zoom the active viewport to this extents, use this recipe:
import ezdxf from ezdxf import zoom, appsettings doc = ezdxf.readfile("your.dxf") extents = appsettings.update_extents(doc) zoom.center(doc.modelspace(), extents.center, extents.size)
SEE ALSO:
The drawing settings are stored in the HEADER section, which is accessible by the header attribute of the Drawing object. See the online documentation from Autodesk for available header variables.
SEE ALSO:
Raises DXFValueError if tag does not exist.
Raises :class:`DXFValueError if tag does not exist.
The CLASSES section in DXF files holds the information for application-defined classes whose instances appear in Layout objects. As usual package user there is no need to bother about CLASSES.
SEE ALSO:
Storage key is the (name, cpp_class_name) tuple, because there are some classes with the same name but different cpp_class_names.
0 | No operations allowed (0) |
1 | Erase allowed (0x1) |
2 | Transform allowed (0x2) |
4 | Color change allowed (0x4) |
8 | Layer change allowed (0x8) |
16 | Linetype change allowed (0x10) |
32 | Linetype scale change allowed (0x20) |
64 | Visibility change allowed (0x40) |
128 | Cloning allowed (0x80) |
256 | Lineweight change allowed (0x100) |
512 | Plot Style Name change allowed (0x200) |
895 | All operations except cloning allowed (0x37F) |
1023 | All operations allowed (0x3FF) |
1024 | Disables proxy warning dialog (0x400) |
32768 | R13 format proxy (0x8000) |
The TABLES section is the home of all TABLE objects of a DXF document.
SEE ALSO:
The BLOCKS section is the home all block definitions (BlockLayout) of a DXF document.
WARNING:
SEE ALSO:
type_char | Anonymous Block Type |
'U' | '*U###' anonymous BLOCK |
'E' | '*E###' anonymous non-uniformly scaled BLOCK |
'X' | '*X###' anonymous HATCH graphic |
'D' | '*D###' anonymous DIMENSION graphic |
'A' | '*A###' anonymous GROUP |
'T' | '*T###' anonymous block for ACAD_TABLE content |
WARNING:
WARNING:
The ENTITIES section is the home of all entities of the Modelspace and the active Paperspace layout. This is a real section in the DXF file but in ezdxf the EntitySection is just a linked entity space of these two layouts.
SEE ALSO:
The OBJECTS section is the home of all none graphical objects of a DXF document. The OBJECTS section is accessible by the Drawing.objects attribute.
Convenience methods of the Drawing object to create essential structures in the OBJECTS section:
SEE ALSO:
The underlying data structure for storing DXF objects is organized like a standard Python list, therefore index can be any valid list indexing or slicing term, like a single index objects[-1] to get the last entity, or an index slice objects[:10] to get the first 10 or fewer objects as list[DXFObject].
The GEODATA entity requires DXF version R2010+. The DXF Reference does not document if other layouts than model space supports geo referencing, so getting/setting geo data may only make sense for the model space layout, but it is also available in paper space layouts.
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 really good, 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().
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 |
none | None |
(internal API), public interface set_raster_variables()
(internal API)
Collection of Layer objects.
Collection of Linetype objects.
SEE ALSO:
Collection of Textstyle objects.
Finding the TTF font files is the task of the DXF viewer and each viewer is different (hint: support files).
Locating the SHX files in the filesystem is the task of the DXF viewer and each viewer is different (hint: support files).
Locating the SHX files in the filesystem is the task of the DXF viewer and each viewer is different (hint: support files).
A shape file table entry has no name, so you have to search by the font attribute.
Collection of DimStyle objects.
Collection of AppID objects.
Collection of UCSTableEntry objects.
Collection of View objects.
The name of the actual displayed viewport configuration is “*ACTIVE”.
Duplication of table entries is not supported: duplicate_entry() raises NotImplementedError
Collection of BlockRecord objects.
LAYER (DXF Reference) definition, defines attribute values for entities on this layer for their attributes set to BYLAYER.
IMPORTANT:
Deleting a layer entry does not delete the entities which reference this layer!
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'LAYER' |
Factory function | Drawing.layers.new() |
SEE ALSO:
1 | Layer is frozen; otherwise layer is thawed; use is_frozen(), freeze() and thaw() |
2 | Layer is frozen by default in new viewports |
4 | Layer is locked; use is_locked(), lock(), unlock() |
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is for the benefit of AutoCAD commands. It can be ignored by most programs that read DXF files and need not be set by programs that write DXF files) |
(requires DXF R2004)
1 | plot layer (default value) |
0 | don’t plot layer |
ezdxf.lldxf.const.LINEWEIGHT_DEFAULT for using global default line weight.
(requires DXF R13)
(requires DXF R13)
(requires DXF R13)
layer.rgb = (30, 40, 50) r, g, b = layer.rgb
This is the recommend method to get/set RGB values, when ever possible do not use the DXF low level attribute dxf.true_color.
WARNING:
There is no complete overview of where layer references are stored, third-party entities are black-boxes with unknown content and layer names could be stored in the extended data section of any DXF entity or in XRECORD entities. Which means that in some rare cases references to the old layer name can persist, at least this does not invalidate the DXF document.
Layer attributes which can be overridden:
Get the override object for a certain layer by the Layer.get_vp_overrides() method.
It is important to write changes back by calling commit(), otherwise the changes are lost.
IMPORTANT:
IMPORTANT:
The final rendering of DXF files is highly dependent on the interpretation of DXF entities by the rendering engine, and the DXF reference does not provide any guidelines for rendering entities. The biggest visual differences of CAD applications are the text renderings, therefore the only way to get the exact same result is to use the same CAD application.
The DXF format does not and can not embed TTF fonts like the PDF format!
The Textstyle entity defines a text style (DXF Reference), and can be used by the entities: Text, Attrib, Attdef, MText, Dimension, Leader and MultiLeader.
Example to create a new text style “Arial” and to apply this text style:
doc.styles.add("Arial", font="Arial.ttf") msp = doc.modelspace() msp.add_text("my text", dxfattribs={"style": "Arial"})
The settings stored in the Textstyle entity are the default text style values used by CAD applications if the text settings are not stored in the text entity itself. But not all setting are substituted by the default value. The height or width attribute must be stored in the text entities itself in order to influence the appearance of the text. It is recommended that you do not rely on the default settings in the Textstyle entity, set all attributes in the text entity itself if supported.
Just a few settings are available exclusive by the Textstyle entity:
The most important setting is the font attribute, this attribute defines the rendering font as raw TTF file name, e.g. “Arial.ttf” or “OpenSansCondensed-Light.ttf”, this file name is often not the name displayed in GUI application and you have to digg down into the fonts folder e.g. (“C:\Windows\Fonts”) to get the real file name for the TTF font. Do not include the path! [image]
AutoCAD supports beyond the legacy SHX fonts only TTF fonts. The SHX font format is not documented and only available in some CAD applications. The ezdxf drawing add-on replaces the SHX fonts by TTF fonts, which look similar to the SHX fonts, unfortunately the license of these fonts is unclear, therefore they can not be packaged with ezdxf. They are installed automatically if you use an Autodesk product like TrueView, or search the internet at you own risk for these TTF fonts.
The extended font data can provide extra information for the font, it is stored in the XDATA section, not well documented and not widely supported.
IMPORTANT:
You need to make sure that the CAD application is properly configured to have access to the system fonts. The DXF format has no setting where the CAD application should search for fonts, and does not guarantee that the text rendering on other computers or operating systems looks the same as on your current system on which you created the DXF.
The second exclusive setting is the vertical text flag in Textstyle.flags. The vertical text style is enabled for all entities using the text style. Vertical text works only for SHX fonts and is not supported for TTF fonts (in AutoCAD) and is works only for the single line entities Text and Attrib. Most CAD applications beside AutoCAD and BricsCAD do not support vertical text rendering and even AutoCAD and BricsCAD have problems with vertical text rendering in some circumstances. Using the vertical text feature is not recommended.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'STYLE' |
Factory function | Drawing.styles.new() |
SEE ALSO:
1 | If set, this entry describes a shape |
4 | Vertical text |
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD)commands. It can be ignored by most programs that read DXF files and need not be set by programs that write DXF files) |
2 | text is backward (mirrored along the x-axis) |
4 | text is upside down (mirrored about the base line) |
The extended font data is optional and not reliable! Returns (“”, False, False) if extended font data is not present.
Defines a linetype (DXF Reference).
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'LTYPE' |
Factory function | Drawing.linetypes.new() |
SEE ALSO:
DXF Internals: LTYPE Table
[image] [image]
DIMSTYLE (DXF Reference) defines the appearance of Dimension entities. Each of this dimension variables starting with "dim..." can be overridden for any Dimension entity individually.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'DIMSTYLE' |
Factory function | Drawing.dimstyles.new() |
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent XREF has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD) |
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.
0 | center |
1 | above |
2 | outside, handled like above by ezdxf |
3 | JIS, handled like above by ezdxf |
4 | below |
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) |
0 | Displays all leading and trailing zeros |
1 | Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000) |
2 | Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) |
3 | Suppresses leading and trailing zeros (for example, 0.5000 becomes .5) |
0 | Moves the dimension line with dimension text |
1 | Adds a leader when dimension text is moved |
2 | Allows text to be moved freely without a leader |
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 |
0 | Align with bottom line of dimension text |
1 | Align vertical centered to dimension text |
2 | Align with top line of dimension text |
0 | arc symbol preceding the measurement text |
1 | arc symbol above the measurement text |
2 | disable arc symbol |
The viewport table (DXF Reference) stores the modelspace viewport configurations. So this entries just modelspace viewports, not paperspace viewports, for paperspace viewports see the Viewport entity.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'VPORT' |
Factory function | Drawing.viewports.new() |
SEE ALSO:
Defines a viewport configurations for the modelspace.
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD) |
The View table (DXF Reference) stores named views of the model or paperspace layouts. This stored views makes parts of the drawing or some view points of the model in a CAD applications more accessible. This views have no influence to the drawing content or to the generated output by exporting PDFs or plotting on paper sheets, they are just for the convenience of CAD application users.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'VIEW' |
Factory function | Drawing.views.new() |
SEE ALSO:
1 | If set, this is a paper space view |
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD) |
0 | 2D Optimized (classic 2D) |
1 | Wireframe |
2 | Hidden line |
3 | Flat shaded |
4 | Gouraud shaded |
5 | Flat shaded with wireframe |
6 | Gouraud shaded with wireframe |
0 | UCS is not orthographic |
1 | Top |
2 | Bottom |
3 | Front |
4 | Back |
5 | Left |
6 | Right |
Defines an APPID (DXF Reference). These table entries maintain a set of names for all registered applications.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'APPID' |
Factory function | Drawing.appids.new() |
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD) |
Defines an named or unnamed user coordinate system (DXF Reference) for usage in CAD applications. This UCS table entry does not interact with ezdxf in any way, to do coordinate transformations by ezdxf use the ezdxf.math.UCS class.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'UCS' |
Factory function | Drawing.ucs.new() |
SEE ALSO:
16 | If set, table entry is externally dependent on an xref |
32 | If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved |
64 | If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is only for the benefit of AutoCAD) |
BLOCK_RECORD (DXF Reference) is the core management structure for BlockLayout and Layout. This is an internal DXF structure managed by ezdxf, package users don’t have to care about it.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'BLOCK_RECORD' |
Factory function | Drawing.block_records.new() |
0 | Unitless |
1 | Inches |
2 | Feet |
3 | Miles |
4 | Millimeters |
5 | Centimeters |
6 | Meters |
7 | Kilometers |
8 | Microinches |
9 | Mils |
10 | Yards |
11 | Angstroms |
12 | Nanometers |
13 | Microns |
14 | Decimeters |
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 |
Do not change this structures, this is just an information for experienced developers!
The BLOCK_RECORD is the owner of all the entities in a layout and stores them in an EntitySpace object (BlockRecord.entity_space). For each layout exist a BLOCK definition in the BLOCKS section, a reference to the Block entity is stored in BlockRecord.block.
Modelspace and Paperspace layouts require an additional DXFLayout object in the OBJECTS section.
SEE ALSO:
A block definition (BlockLayout) is a collection of DXF entities, which can be placed multiply times at different layouts or other blocks as references to the block definition. Block layouts are located in the BLOCKS sections and are accessible by the blocks attribute of the Drawing class.
SEE ALSO:
BLOCK (DXF Reference) entity is embedded into the BlockLayout object. The BLOCK entity is accessible by the BlockLayout.block attribute.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'BLOCK' |
Factory function | Drawing.blocks.new() (returns a BlockLayout) |
SEE ALSO:
Insertion location referenced by the Insert entity to place the block reference and also the center of rotation and scaling.
1 | Anonymous block generated by hatching, associative dimensioning, other internal operations, or an application |
2 | Block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all) |
4 | Block is an external reference (xref) |
8 | Block is an xref overlay |
16 | Block is externally dependent |
32 | This is a resolved external reference, or dependent of an external reference (ignored on input) |
64 | This definition is a referenced external reference (ignored on input) |
ENDBLK entity is embedded into the BlockLayout object. The ENDBLK entity is accessible by the BlockLayout.endblk attribute.
Subclass of | ezdxf.entities.DXFEntity |
DXF type | 'ENDBLK' |
The INSERT entity (DXF Reference) represents a block reference with optional attached attributes as (Attrib) entities.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'INSERT' |
Factory function | ezdxf.layouts.BaseLayout.add_blockref() |
Inherited DXF attributes | Common graphical DXF attributes |
SEE ALSO:
WARNING:
Not all CAD applications support non-uniform scaling (e.g. LibreCAD).
Not all CAD applications support non-uniform scaling (e.g. LibreCAD).
Example for appending an attribute to an INSERT entity:
e.add_attrib('EXAMPLETAG', 'example text').set_placement( (3, 7), align=TextEntityAlignment.MIDDLE_CENTER )
This method avoids the wrapper block of the add_auto_blockref() method, but the visual results may not match the results of CAD applications, especially for non-uniform scaling. If the visual result is very important to you, use the add_auto_blockref() method.
Unlike the transformation matrix m, the INSERT entity can not represent a non-orthogonal target coordinate system and an InsertTransformationError will be raised in that case.
This method is meant to examine the block reference entities at the target location without exploding the block reference. These entities are not stored in the entity database, have no handle and are not assigned to any layout. It is possible to convert these entities into regular drawing entities by adding the entities to the entities database and a layout of the same DXF document as the block reference:
doc.entitydb.add(entity) msp = doc.modelspace() msp.add_entity(entity)
WARNING:
This method does not resolve the MINSERT attributes, only the sub-entities of the first INSERT will be returned. To resolve MINSERT entities check if multi insert processing is required, that’s the case if the property Insert.mcount > 1, use the Insert.multi_insert() method to resolve the MINSERT entity into multiple INSERT entities.
The skipped_entity_callback() will be called for all entities which are not processed, signature: skipped_entity_callback(entity: DXFEntity, reason: str), entity is the original (untransformed) DXF entity of the block definition, the reason string is an explanation why the entity was skipped.
Transforms the block entities into the required WCS location by applying the block reference attributes insert, extrusion, rotation and the scale factors xscale, yscale and zscale.
Attached ATTRIB entities are converted to TEXT entities, this is the behavior of the BURST command of the AutoCAD Express Tools.
WARNING:
The ATTRIB (DXF Reference) entity represents a text value associated with a tag. In most cases an ATTRIB is appended to an Insert entity, but it can also be used as a standalone entity.
Subclass of | ezdxf.entities.Text |
DXF type | 'ATTRIB' |
Factory function | ezdxf.layouts.BaseLayout.add_attrib() (stand alone entity) |
Factory function | Insert.add_attrib() (attached to Insert) |
Inherited DXF attributes | Common graphical DXF attributes |
SEE ALSO:
WARNING:
The fast mode is accurate if the DXF content was created by reliable (and newer) CAD applications like AutoCAD or BricsCAD. The accurate mode is for some rare cases where the content was created by older CAD applications or unreliable DXF libraries and CAD applications.
The accurate mode is much slower than the fast mode.
The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an ordinary single line ATTRIB/ATTDEF entity will be exported.
The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an ordinary single line ATTRIB/ATTDEF entity will be exported.
The ATTDEF (DXF Reference) entity is a template in a BlockLayout, which will be used to create an attached Attrib entity for an Insert entity.
Subclass of | ezdxf.entities.Text |
DXF type | 'ATTDEF' |
Factory function | ezdxf.layouts.BaseLayout.add_attdef() |
Inherited DXF attributes | Common graphical DXF attributes |
SEE ALSO:
WARNING:
The fast mode is accurate if the DXF content was created by reliable (and newer) CAD applications like AutoCAD or BricsCAD. The accurate mode is for some rare cases where the content was created by older CAD applications or unreliable DXF libraries and CAD applications.
The accurate mode is much slower than the fast mode.
The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an ordinary single line ATTRIB/ATTDEF entity will be exported.
The multi-line ATTRIB/ATTDEF entity requires DXF R2018, otherwise an ordinary single line ATTRIB/ATTDEF entity will be exported.
The layout manager is unique to each DXF drawing, access the layout manager as layouts attribute of the Drawing object (e.g. doc.layouts.rename("Layout1", "PlanView")).
A Layout represents and manages DXF entities, there are three different layout objects:
WARNING:
A layout owns all entities residing in their entity space, therefore the dxf.owner attribute of any DXFGraphic entity in this layout is the dxf.handle of the layout, and deleting an entity from a layout is the end of life of this entity, because it is also deleted from the EntityDB. It’s possible to just unlink an entity from a layout to assign the entity to another layout, use the move_to_layout() method to move entities between layouts.
The underlying data structure for storing entities is organized like a standard Python list, 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 less entities as list[DXFGraphic].
To change redraw order associate a different sort-handle to entities, this redefines the order in which the entities are regenerated. The handles argument can be a dict of entity_handle and sort_handle as (k, v) pairs, or an iterable of (entity_handle, sort_handle) tuples.
The sort-handle doesn’t have to be unique, some or all entities can share the same sort-handle and a sort-handle can be an existing handle.
The “0” handle can be used, but this sort-handle will be drawn as latest (on top of all other entities) and not as first as expected.
Not all DXF types are supported and every dependency or resource reference from another DXF document will be removed except attribute layer will be preserved but only with default attributes like color 7 and linetype CONTINUOUS because the layer attribute doesn’t need a layer table entry.
If the entity is part of another DXF document, it will be unlinked from this document and its entity database if argument copy is False, else the entity will be copied. Unassigned entities like from DXF iterators will just be added.
Supported DXF types:
HINT:
HINT:
HINT:
When inserting a block reference into the modelspace or another block 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.
The Attrib entities are placed relative to the insert point, which is equal to the block base point.
This method wraps the INSERT and all the ATTRIB entities into an anonymous block, which produces the best visual results, especially for non-uniform scaled block references, because the transformation and scaling is done by the CAD application. But this makes evaluation of block references with attributes more complicated, if you prefer INSERT and ATTRIB entities without a wrapper block use the add_blockref_with_attribs() method.
Set position and alignment by the idiom:
layout.add_attdef("NAME").set_placement( (2, 3), align=TextEntityAlignment.MIDDLE_CENTER )
The LWPolyline is defined as a single DXF entity and needs less disk space than a Polyline entity. (requires DXF R2000)
Format codes:
This factory method adds automatically a column break "\N" at the end of each column text to force a new column. The height attribute should be big enough to reserve enough space for the tallest column. Too small values produce valid DXF files, but the visual result will not be as expected. The height attribute also defines the total height of the MTEXT entity.
(requires DXF R2000)
This current implementation works best for DXF R2018, because the content is stored as a continuous text in a single MTEXT entity. For DXF versions prior to R2018 the content should be distributed across multiple MTEXT entities (one entity per column), which is not done by ezdxf, but the result is correct for advanced DXF viewers and CAD application, which do the MTEXT content distribution completely by itself.
(requires DXF R2000)
This current implementation works best for DXF R2018, because the content is stored as a continuous text in a single MTEXT entity. For DXF versions prior to R2018 the content should be distributed across multiple MTEXT entities (one entity per column), which is not done by ezdxf, but the result is correct for advanced DXF viewers and CAD application, which do the MTEXT content distribution completely by itself.
Because of the current limitations the use of this method is not recommend. This situation may improve in future releases, but the exact rendering of the content will also slow down the processing speed dramatically.
(requires DXF R2000)
If fit_points is None, an “empty” spline will be created, all data has to be set by the user.
The SPLINE entity requires DXF R2000.
AutoCAD creates a spline through fit points by a global curve interpolation and an unknown method to estimate the direction of the start- and end tangent.
SEE ALSO:
Use function add_cad_spline_control_frame() to create SPLINE entities from fit points similar to CAD application including start- and end tangent constraints.
Open uniform B-splines start and end at your first and last control point.
weights has to be an iterable of floats, which defines the influence of the associated control point to the shape of the B-spline, therefore for each control point is one weight value required.
Open rational uniform B-splines start and end at the first and last control point.
The center of the helix is always (0, 0, 0) and the helix axis direction is the +z-axis.
Transform the new HELIX by the transform() method to your needs.
The MPOLYGON entity is not a core DXF entity and is not supported by every CAD application or DXF library.
DXF version R2004+ is required to use a fill color different from BYLAYER. For R2000 the fill color is always BYLAYER, set any ACI value to create a filled MPOLYGON entity.
This method creates only a 2D entity in the xy-plane of the layout, the z-axis of the input vertices are ignored.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
This method sets many design decisions by itself, the necessary geometry will be generated automatically, no required nor possible render() call. This method is easy to use, but you get what you get.
NOTE:
This method returns a DimStyleOverride object, to create the necessary dimension geometry, you have to call DimStyleOverride.render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
If a UCS is used for dimension line rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
Following render types are supported:
Placing the dimension text at a user defined location, overrides the mpoint and the angle argument, but requires a given radius argument. The location argument does not define the exact text location, instead it defines the dimension line starting at center and the measurement text midpoint projected on this dimension line going through location, if text is aligned to the dimension line. If text is horizontal, location is the kink point of the dimension line from radial to horizontal direction.
NOTE:
Returns: DimStyleOverride
Returns: DimStyleOverride
Returns: DimStyleOverride
If an UCS is used for dimension line rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
Returns: DimStyleOverride
If an UCS is used for angular dimension rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
If an UCS is used for angular dimension rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
Returns: DimStyleOverride
Returns: DimStyleOverride
If an UCS is used for arc dimension rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the ArcDimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
NOTE:
Returns: DimStyleOverride
NOTE:
Returns: DimStyleOverride
If an UCS is used for dimension line rendering, all point definitions in UCS coordinates, translation into WCS and OCS is done by the rendering function. Extrusion vector is defined by UCS or (0, 0, 1) by default.
This method returns a DimStyleOverride object - to create the necessary dimension geometry, you have to call render() manually, this two-step process allows additional processing steps on the Dimension entity between creation and rendering.
NOTE:
Returns: DimStyleOverride
Leader shares its styling infrastructure with Dimension.
By default a Leader without any annotation is created. For creating more fancy leaders and annotations see documentation provided by Autodesk or Demystifying DXF: LEADER and MULTILEADER implementation notes .
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
The ACIS data has to be set as SAT or SAB.
This enables direct access to the underlying LAYOUT entity, e.g. Layout.dxf.layout_flags
“Drawing extents are the bounds of the area occupied by objects.” (Quote Autodesk Knowledge Network)
“Sets an invisible rectangular boundary in the drawing area that can limit the grid display and limit clicking or entering point locations.” (Quote Autodesk Knowledge Network)
The Paperspace class has an additional method reset_paper_limits() to deduce the default limits from the paper size settings.
0 | last screen display |
1 | drawing extents |
2 | drawing limits |
3 | view specific (defined by Layout.dxf.plot_view_name) |
4 | window specific (defined by Layout.set_plot_window_limits()) |
5 | layout information (default) |
The modelspace contains the “real” world representation of the drawing subjects in real world units.
The GEODATA entity requires DXF R2010. The DXF reference does not document if other layouts than the modelspace supports geo referencing, so I assume getting/setting geo data may only make sense for the modelspace.
Paperspace layouts are used to create different drawing sheets of the modelspace subjects for printing or PDF export.
Reset paper limits, extents and viewports.
int | Rotation |
0 | no rotation |
1 | 90 degrees counter-clockwise |
2 | upside-down |
3 | 90 degrees clockwise |
Viewport status:
Ezdxf does not create a main viewport by default, because CAD applications don’t require one.
plot origin = lower left corner of printable area + plot origin offset
Block layouts are reusable sets of graphical entities, which can be referenced by multiple Insert entities. Each reference can be placed, scaled and rotated individually and can have it’s own set of DXF Attrib entities attached.
A group is just a bunch of DXF entities tied together. All entities of a group has to be in the same layout (modelspace or any paperspace layout but not block). Groups can be named or unnamed, but in reality an unnamed groups has just a special name like “*Annnn”. The name of a group has to be unique in the drawing. Groups are organized in the group table, which is stored as attribute groups in the Drawing object.
IMPORTANT:
with group.edit_data() as data: # add new entities to a group data.append(modelspace.add_line((0, 0), (3, 0))) # remove last entity from a group data.pop()
Validation at DXF export may raise a DXFStructureError!
Invalid entities are:
Each Drawing has one group table, which is accessible by the attribute groups.
All DXF entities can only reside in the BaseLayout and inherited classes like Modelspace, Paperspace and BlockLayout.
WARNING:
Common base class for all DXF entities and objects.
WARNING:
# set attribute value entity.dxf.layer = 'MyLayer' # get attribute value linetype = entity.dxf.linetype # delete attribute del entity.dxf.linetype
Dynamic attribute: this UUID will be created at the first request.
Raises DXFAttributeError if key is not an supported DXF attribute.
layer = entity.get_dxf_attrib("layer") # same as layer = entity.dxf.layer
Raises DXFAttributeError if key is not an supported DXF attribute.
entity.set_dxf_attrib("layer", "MyLayer") # same as entity.dxf.layer = "MyLayer"
Raises DXFAttributeError if key is not an supported DXF attribute.
Raises DXFAttributeError if key is not an supported DXF attribute.
Common base class for all graphical DXF entities.
All graphical entities reside in an entity space like Modelspace, any Paperspace or BlockLayout.
SEE ALSO:
Subclass of | ezdxf.entities.DXFEntity |
WARNING:
entity.rgb = (30, 40, 50) r, g, b = entity.rgb
This is the recommend method to get/set RGB values, when ever possible do not use the DXF low level attribute dxf.true_color.
This attribute requires DXF R2004 or later, returns 0 for older DXF versions and raises DXFAttributeError for setting transparency in older DXF versions.
It is more efficient to call the unlink_entity() method of the associated layout, especially if you have to unlink more than one entity.
Basic implementation uses the transform() interface, subclasses may have faster implementations.
Constants defined in ezdxf.lldxf.const or use the ezdxf.colors module
0 | BYBLOCK |
256 | BYLAYER |
257 | BYOBJECT |
Constants defined in ezdxf.lldxf.const
-1 | LINEWEIGHT_BYLAYER |
-2 | LINEWEIGHT_BYBLOCK |
-3 | LINEWEIGHT_DEFAULT |
Valid DXF lineweights stored in 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
(requires DXF R2004)
0 | casts and receives shadows |
1 | casts shadows |
2 | receives shadows |
3 | ignores shadows |
(requires DXF R2007)
SEE ALSO:
The 3DFACE entity (DXF Reference) is real 3D solid filled triangle or quadrilateral. Access vertices by name (entity.dxf.vtx0 = (1.7, 2.3)) or by index (entity[0] = (1.7, 2.3)).
Unlike the entities Solid and Trace, the vertices of Face3d have the expected vertex order:
msp.add_3dface([(0, 0), (10, 0), (10, 10), (0, 10)])
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | '3DFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_3dface() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
1 | first edge is invisible |
2 | second edge is invisible |
4 | third edge is invisible |
8 | fourth edge is invisible |
Combine values by adding them, e.g. 1+4 = first and third edge is invisible.
Returns 4 vertices when close is False and 5 vertices when close is True. Some edges may have zero-length. This is a compatibility interface to SOLID and TRACE. The 3DFACE entity is already defined by WCS vertices.
3DSOLID entity (DXF Reference) created by an ACIS geometry kernel provided by the Spatial Corp.
SEE ALSO:
Subclass of | ezdxf.entities.Body |
DXF type | '3DSOLID' |
Factory function | ezdxf.layouts.BaseLayout.add_3dsolid() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
An ACAD_PROXY_ENTITY (DXF Reference) is a proxy entity that represents an entity created by an Autodesk or 3rd party application. It stores the graphics and data of the original entity.
The internals of this entity are unknown, so the entity cannot be copied or transformed. However, ezdxf can extract the proxy graphic from these entities as virtual entities or replace (explode) the entire entity with its proxy graphic. The meaning and data of this entity is lost when the entity is exploded.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'ACAD_PROXY_ENTITY' |
Factory function | not supported |
Inherited DXF attributes | Common graphical DXF attributes |
The ARC entity (DXF Reference) represents a circular arc, which is defined by the DXF attributes dxf.center, dxf.radius, dxf.start_angle and dxf.end_angle. The arc-curve goes always from dxf.start_angle to dxf.end_angle in counter-clockwise orientation around the dxf.extrusion vector, which is (0, 0, 1) by default and the usual case for 2D arcs. The ARC entity has OCS coordinates.
The helper tool ezdxf.math.ConstructionArc supports creating arcs from various scenarios, like from 3 points or 2 points and an angle or 2 points and a radius and the upright module can convert inverted extrusion vectors from (0, 0, -1) to (0, 0, 1) without changing the curve.
SEE ALSO:
Subclass of | ezdxf.entities.Circle |
DXF type | 'ARC' |
Factory function | ezdxf.layouts.BaseLayout.add_arc() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
Adds the new ELLIPSE entity to the entity database and to the same layout as the source entity.
Adds the new SPLINE entity to the entity database and to the same layout as the source entity.
BODY entity (DXF Reference) created by an ACIS geometry kernel provided by the Spatial Corp.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'BODY' |
Factory function | ezdxf.layouts.BaseLayout.add_body() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
The CIRCLE entity (DXF Reference) defined by the DXF attributes dxf.center and dxf.radius. The CIRCLE entity has OCS coordinates.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'CIRCLE' |
Factory function | ezdxf.layouts.BaseLayout.add_circle() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
Adds the new ELLIPSE entity to the entity database and to the same layout as the source entity.
Adds the new SPLINE entity to the entity database and to the same layout as the source entity.
The DIMENSION entity (DXF Reference) represents several types of dimensions in many orientations and alignments. The basic types of dimensioning are linear, radial, angular, ordinate, and arc length.
For more information about dimensions see the online help from AutoDesk: About the Types of Dimensions
IMPORTANT:
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'DIMENSION' |
factory function | see table below |
Inherited DXF attributes | Common graphical DXF attributes |
Linear and Rotated Dimension (DXF) | add_linear_dim() |
Aligned Dimension (DXF) | add_aligned_dim() |
Angular Dimension (DXF) | add_angular_dim_2l() |
Angular 3P Dimension (DXF) | add_angular_dim_3p() |
Angular Dimension by center, radius, angles | add_angular_dim_cra() |
Angular Dimension by ConstructionArc | add_angular_dim_arc() |
Diameter Dimension (DXF) | add_diameter_dim() |
Radius Dimension (DXF) | add_radius_dim() |
Ordinate Dimension (DXF) | add_ordinate_dim() |
WARNING:
For AutoCAD this graphical representation is mandatory, otherwise AutoCAD will not open the DXF document. BricsCAD will render the DIMENSION entity by itself, if the graphical representation is not present, but displays the BLOCK content if present.
0 | Linear and Rotated Dimension (DXF) |
1 | Aligned Dimension (DXF) |
2 | Angular Dimension (DXF) |
3 | Diameter Dimension (DXF) |
4 | Radius Dimension (DXF) |
5 | Angular 3P Dimension (DXF) |
6 | Ordinate Dimension (DXF) |
8 | subclass ezdxf.entities.ArcDimension introduced in DXF R2004 |
32 | Indicates that graphical representation geometry is referenced by this dimension only. (always set in DXF R13 and later) |
64 | Ordinate type. This is a bit value (bit 7) used only with integer value 6. If set, ordinate is X-type; if not set, ordinate is Y-type |
128 | This is a bit value (bit 8) added to the other dimtype values if the dimension text has been positioned at a user-defined location rather than at the default location |
The dxf.defpoint and dxf.defpoint4 specify the endpoints of the line used to determine the second extension line for arc- and angular dimension:
This value translates the content of the associated anonymous block for cloned linear dimensions, similar to the insert attribute of the Insert entity.
1 | Top left |
2 | Top center |
3 | Top right |
4 | Middle left |
5 | Middle center |
6 | Middle right |
7 | Bottom left |
8 | Bottom center |
9 | Bottom right |
1 | At least (taller characters will override) |
2 | Exact (taller characters will not override) |
Percentage of default (3-on-5) line spacing to be applied. Valid values range from 0.25 to 4.00.
If empty string or “<>”, the dimension measurement is drawn as the text, if “ ” (one blank space), the text is suppressed. Anything else will be displayed as the dimension text.
This attribute determines the orientation of dimension text and lines for horizontal, vertical, and rotated linear dimensions. This value is the negative of the angle in the OCS xy-plane between the dimension line and the OCS x-axis.
Raises NonUniformScalingError() for non uniform scaling.
These virtual entities are located at the original location of the DIMENSION entity, but they are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container containing all DXF primitives.
All of the DimStyle attributes can be overridden for each Dimension entity individually.
The DimStyleOverride class manages all the complex dependencies between DimStyle and Dimension, the different features of all DXF versions and the rendering process to create the Dimension picture as BLOCK, which is required for AutoCAD.
Returns default value for attributes not supported by DXF R12. This is a hack to use the same algorithm to render DXF R2000 and DXF R12 DIMENSION entities. But the DXF R2000 attributes are not stored in the DXF R12 file! This method does not catch invalid attribute names! Check debug log for ignored DIMSTYLE attributes.
You can discard the content BLOCK for a friendly CAD applications like BricsCAD, because the rendering of the dimension entity is done automatically by BricsCAD if the content BLOCK is missing, and the result is in most cases better than the rendering done by ezdxf.
AutoCAD does not render DIMENSION entities automatically, therefore I see AutoCAD as an unfriendly CAD application.
The ARC_DIMENSION entity was introduced in DXF R2004 and is not documented in the DXF reference.
SEE ALSO:
Subclass of | ezdxf.entities.Dimension |
DXF type | 'ARC_DIMENSION' |
factory function | 0.0 • 2 add_arc_dim_3p() • 2 add_arc_dim_cra() • 2 add_arc_dim_arc() 168u |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | R2004 / AC1018 |
WARNING:
The ELLIPSE entity (DXF Reference) is an elliptic 3D curve defined by the DXF attributes dxf.center, the dxf.major_axis vector and the dxf.extrusion vector.
The dxf.ratio attribute is the ratio of minor axis to major axis and has to be smaller or equal 1. The dxf.start_param and dxf.end_param attributes defines the starting- and the end point of the ellipse, a full ellipse goes from 0 to 2π. The curve always goes from start- to end param in counter clockwise orientation.
The dxf.extrusion vector defines the normal vector of the ellipse plane. The minor axis direction is calculated by dxf.extrusion cross dxf.major_axis. The default extrusion vector (0, 0, 1) defines an ellipse plane parallel to xy-plane of the WCS.
All coordinates and vectors in WCS.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'ELLIPSE' |
factory function | add_ellipse() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
All params are normalized in the range [0, 2π).
Adds the new SPLINE entity to the entity database and to the same layout as the source entity.
The new entity has no owner, no handle, is not stored in the entity database nor assigned to any layout!
The HATCH entity (DXF Reference) fills a closed area defined by one or more boundary paths by a hatch pattern, a solid fill, or a gradient fill.
All points in OCS as (x, y) tuples (Hatch.dxf.elevation is the z-axis value).
There are two different hatch pattern default scaling, depending on the HEADER variable $MEASUREMENT, one for ISO measurement (m, cm, mm, …) and one for imperial measurement (in, ft, yd, …).
The default scaling for predefined hatch pattern will be chosen according this measurement setting in the HEADER section, this replicates the behavior of BricsCAD and other CAD applications. Ezdxf uses the ISO pattern definitions as a base line and scales this pattern down by factor 1/25.6 for imperial measurement usage. The pattern scaling is independent from the drawing units of the document defined by the HEADER variable $INSUNITS.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'HATCH' |
Factory function | ezdxf.layouts.BaseLayout.add_hatch() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Boundary paths classes
Path manager: BoundaryPaths
Pattern and gradient classes
1 | solid fill, use method Hatch.set_solid_fill() |
0 | pattern fill, use method Hatch.set_pattern_fill() |
1 | associative hatch |
0 | not associative hatch |
Associations are not managed by ezdxf.
0 | normal |
1 | outer |
2 | ignore |
(search AutoCAD help for more information)
0 | user |
1 | predefined |
2 | custom |
usage:
r, g, b = entity.bgcolor # get pattern fill background color entity.bgcolor = (10, 20, 30) # set pattern fill background color del entity.bgcolor # delete pattern fill background color
The method always starts from the original base scale, the set_pattern_scale(1) call resets the pattern scale to the original appearance as defined by the pattern designer, but only if the pattern attribute dxf.pattern_scale represents the actual scale, it cannot restore the original pattern scale from the pattern definition itself.
The method always starts from the original base rotation of 0, the set_pattern_angle(0) call resets the pattern rotation angle to the original appearance as defined by the pattern designer, but only if the pattern attribute dxf.pattern_angle represents the actual pattern rotation, it cannot restore the original rotation angle from the pattern definition itself.
The pattern definition should be designed for a scale factor 1 and a rotation angle of 0 degrees. The predefined hatch pattern like “ANSI33” are scaled according to the HEADER variable $MEASUREMENT for ISO measurement (m, cm, … ), or imperial units (in, ft, …), this replicates the behavior of BricsCAD.
Valid gradient type names are:
A HATCH entity can be associative to a base geometry, this association is not maintained nor verified by ezdxf, so if you modify the base geometry 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!
The hatch entity is build by different path types, these are the filter flags for the Hatch.dxf.hatch_style:
As you will learn in the next sections, these are more the recommended usage type for the flags, but the fill algorithm doesn’t care much about that, for instance an OUTERMOST path doesn’t have to be inside the EXTERNAL path.
In general the island detection algorithm works always from outside to inside and alternates filled and unfilled areas. The area between then 1st and the 2nd boundary is filled, the area between the 2nd and the 3rd boundary is unfilled and so on. The different hatch styles defined by the Hatch.dxf.hatch_style attribute are created by filtering some boundary path types.
Yields paths in order of EXTERNAL, OUTERMOST and DEFAULT.
0 | default |
1 | external |
2 | polyline, will be set by ezdxf |
16 | outermost |
My interpretation of the path_type_flags, see also Tutorial for Hatch:
If there are troubles with AutoCAD, maybe the hatch entity has the Hatch.dxf.pixel_size attribute set - delete it del hatch.dxf.pixel_size and maybe the problem is solved. Ezdxf does not use the Hatch.dxf.pixel_size attribute, but it can occur in DXF files created by other applications.
NOTE:
0 | default |
1 | external |
16 | outermost |
see PolylinePath.path_type_flags
Adding Clockwise Oriented Arcs:
Clockwise oriented ArcEdge objects are sometimes necessary to build closed loops, but the ArcEdge objects are always represented in counter-clockwise orientation. To add a clockwise oriented ArcEdge you have to swap the start- and end angle and set the ccw flag to False, e.g. to add a clockwise oriented ArcEdge from 180 to 90 degree, add the ArcEdge in counter-clockwise orientation with swapped angles:
edge_path.add_arc(center, radius, start_angle=90, end_angle=180, ccw=False)
Adding Clockwise Oriented Ellipses:
Clockwise oriented EllipseEdge objects are sometimes necessary to build closed loops, but the EllipseEdge objects are always represented in counter-clockwise orientation. To add a clockwise oriented EllipseEdge you have to swap the start- and end angle and set the ccw flag to False, e.g. to add a clockwise oriented EllipseEdge from 180 to 90 degree, add the EllipseEdge in counter-clockwise orientation with swapped angles:
edge_path.add_ellipse(center, major_axis, ratio, start_angle=90, end_angle=180, ccw=False)
WARNING:
Be careful, this changes the base pattern definition, maybe better use Hatch.set_pattern_scale() or Hatch.set_pattern_angle().
SEE ALSO:
The HELIX entity (DXF Reference).
The helix curve is represented by a cubic B-spline curve, therefore the HELIX entity is also derived from the SPLINE entity.
SEE ALSO:
Subclass of | ezdxf.entities.Spline |
DXF type | 'HELIX' |
Factory function | ezdxf.layouts.BaseLayout.add_helix() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
0 | clock wise (left handed) |
1 | counter clockwise (right handed) |
0 | constrain turn height (pitch) |
1 | constrain count of turns |
2 | constrain total height |
The IMAGE entity (DXF Reference) represents a raster image, the image file itself is not embedded into the DXF file, it is always a separated file. The IMAGE entity is like a block reference, it can be used to add the image multiple times at different locations with different scale and rotation angles. Every IMAGE entity requires an image definition, see entity ImageDef. Ezdxf creates only images in the xy-plan, it’s possible to place images in 3D space, therefore the Image.dxf.u_pixel and the Image.dxf.v_pixel vectors has to be set accordingly.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'IMAGE' |
Factory function | ezdxf.layouts.BaseLayout.add_image() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
Image.SHOW_IMAGE | 1 | Show image |
Image.SHOW_WHEN_NOT_ALIGNED | 2 | Show image when not aligned with screen |
Image.USE_CLIPPING_BOUNDARY | 4 | Use clipping boundary |
Image.USE_TRANSPARENCY | 8 | Transparency is on |
0 | clipping off |
1 | clipping on |
1 | Rectangular |
2 | Polygonal |
0 | Outside |
1 | Inside |
requires DXF R2010 or newer
It’s recommended to acquire the clipping path as Path object by the make_path() function:
from ezdxf.path import make_path image = ... # get image entity clipping_path = make_path(image)
The LEADER entity (DXF Reference) represents a pointer line, made up of one or more vertices (or spline fit points) and an arrowhead. The label or other content to which the Leader is attached is stored as a separate entity, and is not part of the Leader itself.
The LEADER entity uses parts of the styling infrastructure of the DIMENSION entity.
By default a Leader without any annotation is created. For creating more fancy leaders and annotations see the documentation provided by Autodesk or Demystifying DXF: LEADER and MULTILEADER implementation notes .
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'LEADER' |
Factory function | ezdxf.layouts.BaseLayout.add_leader() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
0 | Disabled |
1 | Enabled |
0 | Straight line segments |
1 | Spline |
0 | Created with text annotation |
1 | Created with tolerance annotation |
2 | Created with block reference annotation |
3 | Created without any annotation (default) |
0 | Hookline (or end of tangent for a splined leader) is the opposite direction from the horizontal vector |
1 | Hookline (or end of tangent for a splined leader) is the same direction as horizontal vector (see has_hook_line) |
0 | No hookline |
1 | Has a hookline |
These entities are located at the original location, but are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container referencing all DXF primitives.
The LINE entity (DXF Reference) is a 3D line defined by the DXF attributes dxf.start and dxf.end. The LINE entity has WCS coordinates.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'LINE' |
Factory function | ezdxf.layouts.BaseLayout.add_line() |
Inherited DXF Attributes | Common graphical DXF attributes |
WARNING:
The LWPOLYLINE entity (Lightweight POLYLINE, DXF Reference) is defined as a single graphic entity, which differs from the old-style Polyline entity, which is defined as a group of sub-entities. LWPolyline display faster (in AutoCAD) and consume less disk space, it is a planar element, therefore all points are located in the OCS as (x, y)-tuples (LWPolyline.dxf.elevation is the z-axis value).
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'LWPOLYLINE' |
factory function | add_lwpolyline() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Bulge value
The bulge value is used to create arc shaped line segments for Polyline and LWPolyline entities. The arc starts at the vertex which includes the bulge value and ends at the following vertex. The bulge value defines the ratio of the arc sagitta (versine) to half line segment length, a bulge value of 1 defines a semicircle.
The sign of the bulge value defines the side of the bulge:
Start- and end width
The start width and end width values defines the width in drawing units for the following line segment. To use the default width value for a line segment set value to 0.
Width and bulge values at last point
The width and bulge values of the last point has only a meaning if the polyline is closed, and they apply to the last line segment from the last to the first point.
SEE ALSO:
Code | Point Component |
x | x-coordinate |
y | y-coordinate |
s | start width |
e | end width |
b | bulge value |
v | (x, y [, z]) as tuple |
dxf.flags | Value | Description |
LWPOLYLINE_CLOSED | 1 | polyline is closed |
LWPOLYLINE_PLINEGEN | 128 | linetype is generated across the points |
All coordinates in OCS.
All coordinates in OCS.
All coordinates in OCS.
All coordinates in OCS.
All coordinates in OCS.
All points in OCS as (x, y) tuples (dxf.elevation is the z-axis value).
All coordinates in OCS.
All coordinates in OCS.
A non-uniform scaling is not supported if the entity contains circular arc segments (bulges).
These virtual entities are located at the original location, but are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container referencing all DXF primitives.
The MLINE entity (DXF Reference).
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'MLINE' |
factory function | add_mline() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Constants defined in ezdxf.lldxf.const:
dxf.justification | Value |
MLINE_TOP | 0 |
MLINE_ZERO | 1 |
MLINE_BOTTOM | 2 |
MLINE_RIGHT (alias) | 0 |
MLINE_CENTER (alias) | 1 |
MLINE_LEFT (alias) | 2 |
Constants defined in ezdxf.lldxf.const:
dxf.flags | Value |
MLINE_HAS_VERTEX | 1 |
MLINE_CLOSED | 2 |
MLINE_SUPPRESS_START_CAPS | 4 |
MLINE_SUPPRESS_END_CAPS | 8 |
It is possible to work with 3D vertices, but all vertices have to be in the same plane and the normal vector of this plan is stored as extrusion vector in the MLINE entity.
These entities are located at the original positions, but are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container referencing all DXF primitives.
The first value (miter-offset) is the distance from the vertex location along the miter_direction vector to the point where the line element’s path intersects the miter vector.
The next value (line-start-offset) is the distance along the line_direction from the miter/line path intersection point to the actual start of the line element.
The next value (dash-length) is the distance from the start of the line element (dash) to the first break (gap) in the line element. The successive values continue to list the start and stop points of the line element in this segment of the mline.
The update is required if elements were added or removed or the offset of any element was changed.
The MESH entity (DXF Reference) is a 3D surface in WCS build up from vertices and faces similar to the Polyface entity.
All vertices in WCS as (x, y, z) tuples
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'MESH' |
Factory function | ezdxf.layouts.BaseLayout.add_mesh() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
SEE ALSO:
Despite that vertices, edge and faces are accessible as packed data types, the usage of MeshData by context manager edit_data() is still recommended.
Each face consist of a list of vertex indices (= index in vertices).
The MPOLYGON entity is not a core DXF entity and is not supported by all CAD applications and DXF libraries. The MPolygon class is very similar to the Hatch class with small differences in the supported features and DXF attributes.
The boundary paths of the MPOLYGON are visible and use the graphical DXF attributes of the main entity like dxf.color, dxf.linetype and so on. The solid filling is only visible if the attribute dxf.solid_fill is 1, the color of the solid fill is defined by dxf.fill_color as AutoCAD Color Index (ACI). The MPOLYGON supports ezdxf.entities.Gradient settings like HATCH for DXF R2004 and newer. This feature is used by method MPolygon.set_solid_fill() to set a solid RGB fill color as linear gradient, this disables pattern fill automatically. The MPOLYGON does not support associated source path entities, because the MPOLYGON also represents the boundary paths as visible graphical objects. Hatch patterns are supported, but the hatch style tag is not supported, the default hatch style is ezdxf.const.HATCH_STYLE_NESTED and the style flags of the boundary paths are ignored. Background color for pattern fillings is supported, set background color by property MPolygon.bgcolor as RGB tuple.
NOTE:
Autodesk products do support polyline paths including bulges. An example for edge paths as boundary paths is not available or edge paths are not supported. Ezdxf does not export MPOLYGON entities including edge paths! The BoundaryPaths.edge_to_polyline_paths() method converts all edge paths to simple polyline paths with approximated curves, this conversion has to be done explicit.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'MPOLYGON' |
Factory function | ezdxf.layouts.BaseLayout.add_mpolygon() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
1 | solid fill, better use: MPolygon.set_solid_fill() |
0 | pattern fill, better use: MPolygon.set_pattern_fill() |
(search AutoCAD help for more information)
0 | user |
1 | predefined |
2 | custom |
usage:
r, g, b = entity.bgcolor # get pattern fill background color entity.bgcolor = (10, 20, 30) # set pattern fill background color del entity.bgcolor # delete pattern fill background color
The method always starts from the original base scale, the set_pattern_scale(1) call resets the pattern scale to the original appearance as defined by the pattern designer, but only if the pattern attribute dxf.pattern_scale represents the actual scale, it cannot restore the original pattern scale from the pattern definition itself.
The method always starts from the original base rotation of 0, the set_pattern_angle(0) call resets the pattern rotation angle to the original appearance as defined by the pattern designer, but only if the pattern attribute dxf.pattern_angle represents the actual pattern rotation, it cannot restore the original rotation angle from the pattern definition itself.
The pattern definition should be designed for a scale factor 1 and a rotation angle of 0 degrees. The predefined hatch pattern like “ANSI33” are scaled according to the HEADER variable $MEASUREMENT for ISO measurement (m, cm, … ), or imperial units (in, ft, …), this replicates the behavior of BricsCAD.
Valid gradient type names are:
The MTEXT entity (DXF Reference) fits a multiline text in a specified width but can extend vertically to an indefinite length. You can format individual words or characters within the MText.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'MTEXT' |
Factory function | ezdxf.layouts.BaseLayout.add_mtext() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
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 |
MText.dxf.flow_direction | Value | Description |
MTEXT_LEFT_TO_RIGHT | 1 | left to right |
MTEXT_TOP_TO_BOTTOM | 3 | top to bottom |
MTEXT_BY_STYLE | 5 | by style (the flow direction is inherited from the associated text style) |
Constants defined in ezdxf.lldxf.const:
MText.dxf.line_spacing_style | Value | Description |
MTEXT_AT_LEAST | 1 | taller characters will override |
MTEXT_EXACT | 2 | taller characters will not override |
MText.dxf.bg_fill | Value | Description |
MTEXT_BG_OFF | 0 | no background color |
MTEXT_BG_COLOR | 1 | use specified color |
MTEXT_BG_WINDOW_COLOR | 2 | use window color (?) |
MTEXT_BG_CANVAS_COLOR | 3 | use canvas background color |
Requires that the attributes bg_fill, bg_fill_color are present otherwise AutoCAD complains.
It’s recommended to use set_bg_color()
It’s recommended to use set_bg_color()
It’s recommended to use set_bg_color()
It’s recommended to use set_bg_color()
The line ending character \n will be replaced by the MTEXT line ending \P at DXF export, but not vice versa the \P character by \n at DXF file loading, therefore loaded MTEXT entities always use the \P character for line endings.
Use the special color name canvas, to set the background color to the canvas background color. Remove the background filling by setting argument color to None.
The “fast” mode is accurate if the DXF content was created by reliable (and newer) CAD applications like AutoCAD or BricsCAD. The “accurate” mode is for some rare cases where the content was created by older CAD applications or unreliable DXF libraries and CAD applications.
Code | Description |
\L | Start underline |
\l | Stop underline |
\O | Start overline |
\o | Stop overline |
\K | Start strike-through |
\k | Stop strike-through |
\P | New paragraph (new line) |
\p | Paragraphs properties: indentation, alignment, tabulator stops |
\X | Paragraph wrap on the dimension line (only in dimensions) |
\Q | Slanting (oblique) text by angle - e.g. \Q30; |
\H | Text height - e.g. relative \H3x; absolut \H3; |
\W | Text width - e.g. relative \W0.8x; absolut \W0.8; |
\T | Tracking, character spacing - e.g. relative \T0.5x; absolut \T2; |
\F | Font selection e.g. \Fgdt;o - GDT-tolerance |
\S | Stacking, fractions e.g. \SA^ B; space after “^” is required to avoid caret decoding, \SX/Y; \S1#4; |
\A | Alignment 0.0 • 2 \A0; = bottom • 2 \A1; = center • 2 \A2; = top 168u |
\C | Color change 0.0 • 2 \C1; = red • 2 \C2; = yellow • 2 \C3; = green • 2 \C4; = cyan • 2 \C5; = blue • 2 \C6; = magenta • 2 \C7; = white 168u |
\~ | Non breaking space |
{} | Braces - define the text area influenced by the code, codes and braces can be nested up to 8 levels deep |
\ | Escape character - e.g. \{ = “{” |
Constant | Description |
UNDERLINE_START | start underline text |
UNDERLINE_STOP | stop underline text |
OVERSTRIKE_START | start overline |
OVERSTRIKE_STOP | stop overline |
STRIKE_START | start strike through |
STRIKE_STOP | stop strike through |
GROUP_START | start of group |
GROUP_END | end of group |
NEW_LINE | start in new line |
NBSP | none breaking space |
The MULTILEADER entity (DXF Reference) represents one or more leaders, made up of one or more vertices (or spline fit points) and an arrowhead. In contrast to the Leader entity the text- or block content is part of the MULTILEADER entity.
AutoCAD, BricsCAD and maybe other CAD applications do accept “MLEADER” as type string but they always create entities with “MULTILEADER” as type string.
Because of the complexity of the MULTILEADER entity, the usage of factory methods to create new entities by special builder classes is recommended:
The visual design is based on an associated MLeaderStyle, but almost all attributes are also stored in the MULTILEADER entity itself.
The attribute MultiLeader.dxf.property_override_flags should indicate which MLEADERSTYLE attributes are overridden by MULTILEADER attributes, but these flags do not always reflect the state of overridden attributes. The ezdxf MULTILEADER renderer uses always the attributes from the MULTILEADER entity and ignores the override flags.
All vertices are WCS coordinates, even those for BLOCK entities which are OCS coordinates for regular usage.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'MULTILEADER' |
Factory functions | 0.0 • 2 ezdxf.layouts.BaseLayout.add_multileader_mtext() • 2 ezdxf.layouts.BaseLayout.add_multileader_block() 168u |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
0 | center extents |
1 | insertion point |
0 | none |
1 | BLOCK |
2 | MTEXT |
3 | TOLERANCE |
0 | invisible |
1 | straight line leader |
2 | spline leader |
0 | text angle is equal to last leader line segment angle |
1 | text is horizontal |
2 | text angle is equal to last leader line segment angle, but potentially rotated by 180 degrees so the right side is up for readability. |
0 | horizontal - left & right of content |
1 | vertical - top & bottom of content |
1 | top left |
2 | top center |
3 | top right |
9 | center |
10 | overline and center |
0 | top of top MTEXT line |
1 | middle of top MTEXT line |
2 | middle of whole MTEXT |
3 | middle of bottom MTEXT line |
4 | bottom of bottom MTEXT line |
5 | bottom of bottom MTEXT line & underline bottom MTEXT line |
6 | bottom of top MTEXT line & underline top MTEXT line |
7 | bottom of top MTEXT line |
8 | bottom of top MTEXT line & underline all MTEXT lines |
0 | top of top MTEXT line |
1 | middle of top MTEXT line |
2 | middle of whole MTEXT |
3 | middle of bottom MTEXT line |
4 | bottom of bottom MTEXT line |
5 | bottom of bottom MTEXT line & underline bottom MTEXT line |
6 | bottom of top MTEXT line & underline top MTEXT line |
7 | bottom of top MTEXT line |
8 | bottom of top MTEXT line & underline all MTEXT lines |
9 | center |
10 | overline and center |
These entities are located at the original location, but are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container with all DXF primitives.
Non-uniform scaling is not supported.
0 | content extents |
1 | insertion point |
1 | horizontal |
3 | vertical |
6 | by text style |
0 | none |
1 | static |
2 | dynamic |
The POINT entity (DXF Reference) represents a dimensionless point in WCS.
The POINT styling is a global setting, stored as header variable $PDMODE, this also means all POINT entities in a DXF document have the same styling:
0 | center dot (.) |
1 | none ( ) |
2 | cross (+) |
3 | x-cross (x) |
4 | tick (‘) |
Combined with these bit values
32 | circle |
64 | Square |
e.g. circle + square + center dot = 32 + 64 + 0 = 96 [image]
The size of the points is defined by the header variable $PDSIZE:
0 | 5% of draw area height |
<0 | Specifies a percentage of the viewport size |
>0 | Specifies an absolute size |
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'POINT' |
Factory function | ezdxf.layouts.BaseLayout.add_point() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
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.
The POLYLINE entity (POLYLINE DXF Reference) is very complex, it’s used to build 2D/3D polylines, 3D meshes and 3D polyfaces. For every type exists a different wrapper class but they all have the same DXF type “POLYLINE”. Detect the actual POLYLINE type by the method Polyline.get_mode().
POLYLINE types returned by Polyline.get_mode():
For 2D entities all vertices in OCS.
For 3D entities all vertices in WCS.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'POLYLINE' |
2D factory function | ezdxf.layouts.BaseLayout.add_polyline2d() |
3D factory function | ezdxf.layouts.BaseLayout.add_polyline3d() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
# delete first and second vertex del polyline.vertices[:2]
Polyline.dxf.flags | Value | Description |
POLYLINE_CLOSED | 1 | This is a closed Polyline (or a polygon mesh closed in the M direction) |
POLYLINE_MESH_CLOSED_M_DIRECTION | 1 | equals POLYLINE_CLOSED |
POLYLINE_CURVE_FIT_VERTICES_ADDED | 2 | Curve-fit vertices have been added |
POLYLINE_SPLINE_FIT_VERTICES_ADDED | 4 | Spline-fit vertices have been added |
POLYLINE_3D_POLYLINE | 8 | This is a 3D Polyline |
POLYLINE_3D_POLYMESH | 16 | This is a 3D polygon mesh |
POLYLINE_MESH_CLOSED_N_DIRECTION | 32 | The polygon mesh is closed in the N direction |
POLYLINE_POLYFACE_MESH | 64 | This Polyline is a polyface mesh |
POLYLINE_GENERATE_LINETYPE_PATTERN | 128 | The linetype pattern is generated continuously around the vertices of this Polyline |
Constants for smooth_type defined in ezdxf.lldxf.const:
Polyline.dxf.smooth_type | Value | Description |
POLYMESH_NO_SMOOTH | 0 | no smooth surface fitted |
POLYMESH_QUADRATIC_BSPLINE | 5 | quadratic B-spline surface |
POLYMESH_CUBIC_BSPLINE | 6 | cubic B-spline surface |
POLYMESH_BEZIER_SURFACE | 8 | Bezier surface |
A non-uniform scaling is not supported if a 2D POLYLINE contains circular arc segments (bulges).
These virtual entities are located at the original location, but are not stored in the entity database, have no handle and are not assigned to any layout.
Returns an EntityQuery container referencing all DXF primitives.
A VERTEX (VERTEX DXF Reference) represents a polyline/mesh vertex.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'VERTEX' |
Factory function | Polyline.append_vertex() |
Factory function | Polyline.extend() |
Factory function | Polyline.insert_vertices() |
Inherited DXF Attributes | Common graphical DXF attributes |
The bulge value is used to create arc shaped line segments.
Vertex.dxf.flags | Value | Description |
VTX_EXTRA_VERTEX_CREATED | 1 | Extra vertex created by curve-fitting |
VTX_CURVE_FIT_TANGENT | 2 | curve-fit tangent defined for this vertex. A curve-fit tangent direction of 0 may be omitted from the DXF output, but is significant if this bit is set. |
VTX_SPLINE_VERTEX_CREATED | 8 | spline vertex created by spline-fitting |
VTX_SPLINE_FRAME_CONTROL_POINT | 16 | spline frame control point |
VTX_3D_POLYLINE_VERTEX | 32 | 3D polyline vertex |
VTX_3D_POLYGON_MESH_VERTEX | 64 | 3D polygon mesh |
VTX_3D_POLYFACE_MESH_VERTEX | 128 | polyface mesh vertex |
Format codes:
Subclass of | ezdxf.entities.Polyline |
DXF type | 'POLYLINE' |
Factory function | ezdxf.layouts.BaseLayout.add_polymesh() |
Inherited DXF Attributes | Common graphical DXF attributes |
Set vertex location: cache[row, col] = (x, y, z)
Get vertex location: x, y, z = cache[row, col]
Subclass of | ezdxf.entities.Polyline |
DXF type | 'POLYLINE' |
Factory function | ezdxf.layouts.BaseLayout.add_polyface() |
Inherited DXF Attributes | Common graphical DXF attributes |
SEE ALSO:
The RAY entity (DXF Reference) starts at Ray.dxf.point and continues to infinity (construction line).
Subclass of | ezdxf.entities.XLine |
DXF type | 'RAY' |
Factory function | ezdxf.layouts.BaseLayout.add_ray() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Start point as (3D Point in WCS)
Unit direction vector as (3D Point in WCS)
REGION entity (DXF Reference) created by an ACIS geometry kernel provided by the Spatial Corp.
SEE ALSO:
Subclass of | ezdxf.entities.Body |
DXF type | 'REGION' |
Factory function | ezdxf.layouts.BaseLayout.add_region() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
The SHAPE entity (DXF Reference) is used like a block references, each SHAPE reference can be scaled and rotated individually. The SHAPE definitions are stored in external shape files (*.SHX), and ezdxf can not load or create these shape files.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'SHAPE' |
Factory function | ezdxf.layouts.BaseLayout.add_shape() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
The SOLID entity (DXF Reference) is a filled triangle or quadrilateral. Access vertices by name (entity.dxf.vtx0 = (1.7, 2.3)) or by index (entity[0] = (1.7, 2.3)). If only 3 vertices are provided the last (3rd) vertex will be repeated in the DXF file.
The SOLID entity stores the vertices in an unusual way, the last two vertices are reversed:
msp.add_solid([(0, 0), (10, 0), (10, 10), (0, 10)])
Reverse the last two vertices to get the expected square:
msp.add_solid([(0, 0), (10, 0), (0, 10), (10, 10)])
NOTE:
The Solid.vertices() and Solid.wcs_vertices() methods return the vertices in the expected (reversed) order.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'SOLID' |
Factory function | ezdxf.layouts.BaseLayout.add_solid() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
The SPLINE entity (DXF Reference) is a 3D curve, all coordinates have to be 3D coordinates even if the spline is just a 2D planar curve.
The spline curve is defined by control points, knot values and weights. The control points establish the spline, the various types of knot vector determines the shape of the curve and the weights of rational splines define how strong a control point influences the shape.
A SPLINE can be created just from fit points - knot values and weights are optional (tested with AutoCAD 2010). If you add additional data, be sure you know what you do, because invalid data may invalidate the whole DXF file.
The function ezdxf.math.fit_points_to_cad_cv() calculates control vertices from given fit points. This control vertices define a cubic B-spline which matches visually the SPLINE entities created by BricsCAD and AutoCAD from fit points.
SEE ALSO:
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'SPLINE' |
Factory function | see table below |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Basic spline entity | add_spline() |
Spline control frame from fit points | add_spline_control_frame() |
Open uniform spline | add_open_spline() |
Closed uniform spline | add_closed_spline() |
Open rational uniform spline | add_rational_spline() |
Closed rational uniform spline | add_closed_rational_spline() |
dxf.flags | Value | Description |
CLOSED_SPLINE | 1 | Spline is closed |
PERIODIC_SPLINE | 2 | |
RATIONAL_SPLINE | 4 | |
PLANAR_SPLINE | 8 | |
LINEAR_SPLINE | 16 | planar bit is also set |
The new SPLINE entity has no owner, no handle, is not stored in the entity database nor assigned to any layout!
SURFACE entity (DXF Reference) created by an ACIS geometry kernel provided by the Spatial Corp.
SEE ALSO:
Subclass of | ezdxf.entities.Body |
DXF type | 'SURFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_surface() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
(DXF Reference)
Subclass of | ezdxf.entities.Surface |
DXF type | 'EXTRUDEDSURFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_extruded_surface() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2007 ('AC1021') |
0 | No alignment |
1 | Align sweep entity to path |
2 | Translate sweep entity to path |
3 | Translate path to sweep entity |
(DXF Reference)
Subclass of | ezdxf.entities.Surface |
DXF type | 'LOFTEDSURFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_lofted_surface() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2007 ('AC1021') |
(DXF Reference)
Subclass of | ezdxf.entities.Surface |
DXF type | 'REVOLVEDSURFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_revolved_surface() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2007 ('AC1021') |
(DXF Reference)
Subclass of | ezdxf.entities.Surface |
DXF type | 'SWEPTSURFACE' |
Factory function | ezdxf.layouts.BaseLayout.add_swept_surface() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2007 ('AC1021') |
The TEXT entity (DXF Reference) represents a single line of text. The style attribute stores the associated Textstyle entity as string, which defines the basic font properties. The text size is stored as cap-height in the height attribute in drawing units. Text alignments are defined as enums of type ezdxf.enums.TextEntityAlignment.
SEE ALSO:
Tutorial for Text
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'TEXT' |
Factory function | ezdxf.layouts.BaseLayout.add_text() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
0 | Left |
2 | Right |
3 | Aligned (if vertical alignment = 0) |
4 | Middle (if vertical alignment = 0) |
5 | Fit (if vertical alignment = 0) |
0 | Baseline |
1 | Bottom |
2 | Middle |
3 | Top |
2 | text is backward (mirrored in X) |
4 | text is upside down (mirrored in Y) |
The alignments ALIGNED and FIT are special, they require a second alignment point, the text is aligned on the virtual line between these two points and sits vertically at the baseline.
The TRACE entity (DXF Reference) is solid filled triangle or quadrilateral. Access vertices by name (entity.dxf.vtx0 = (1.7, 2.3)) or by index (entity[0] = (1.7, 2.3)). If only 3 vertices are provided the last (3rd) vertex will be repeated in the DXF file.
The TRACE entity stores the vertices in an unusual way, the last two vertices are reversed:
msp.add_solid([(0, 0), (10, 0), (10, 10), (0, 10)])
Reverse the last two vertices to get the expected square:
msp.add_solid([(0, 0), (10, 0), (0, 10), (10, 10)])
NOTE:
The Trace.vertices() and Trace.wcs_vertices() methods return the vertices in the expected (reversed) order.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'TRACE' |
Factory function | ezdxf.layouts.BaseLayout.add_trace() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
The UNDERLAY entity (DXF Reference) links an underlay file to the DXF file, the file itself is not embedded into the DXF file, it is always a separated file. The (PDF)UNDERLAY entity is like a block reference, you can use it multiple times to add the underlay on different locations with different scales and rotations. But therefore you need a also a (PDF)DEFINITION entity, see UnderlayDefinition.
The DXF standard supports three different file formats: PDF, DWF (DWFx) and DGN. An Underlay can be clipped by a rectangle or a polygon path. The clipping coordinates are 2D OCS coordinates in drawing units but without scaling.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | internal base class |
Factory function | ezdxf.layouts.BaseLayout.add_underlay() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
dxf.flags | Value | Description |
UNDERLAY_CLIPPING | 1 | clipping is on/off |
UNDERLAY_ON | 2 | underlay is on/off |
UNDERLAY_MONOCHROME | 4 | Monochrome |
UNDERLAY_ADJUST_FOR_BACKGROUND | 8 | Adjust for background |
Two vertices describe a rectangle (lower left and upper right corner), more than two vertices is a polygon as clipping path.
Subclass of | ezdxf.entities.Underlay |
DXF type | 'PDFUNDERLAY' |
Factory function | ezdxf.layouts.BaseLayout.add_underlay() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Subclass of | ezdxf.entities.Underlay |
DXF type | 'DWFUNDERLAY' |
Factory function | ezdxf.layouts.BaseLayout.add_underlay() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Subclass of | ezdxf.entities.Underlay |
DXF type | 'DGNUNDERLAY' |
Factory function | ezdxf.layouts.BaseLayout.add_underlay() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
The VIEWPORT entity (DXF Reference) is a window from a paperspace layout to the modelspace.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'VIEWPORT' |
Factory function | ezdxf.layouts.Paperspace.add_viewport() |
Inherited DXF attributes | Common graphical DXF attributes |
WARNING:
-1 | On, but is fully off screen, or is one of the viewports that is not active because the $MAXACTVP count is currently being exceeded. |
0 | Off |
>0 | On and active. The value indicates the order of stacking for the viewports, where 1 is the active viewport, 2 is the next, and so forth. |
Bit value | Constant in ezdxf.const | Description |
1 (0x1) | VSF_PERSPECTIVE_MODE | Enables perspective mode |
2 (0x2) | VSF_FRONT_CLIPPING | Enables front clipping |
4 (0x4) | VSF_BACK_CLIPPING | Enables back clipping |
8 (0x8) | VSF_USC_FOLLOW | Enables UCS follow |
16 (0x10) | VSF_FRONT_CLIPPING_NOT_AT_EYE | Enables front clip not at eye |
32 (0x20) | VSF_UCS_ICON_VISIBILITY | Enables UCS icon visibility |
64 (0x40) | VSF_UCS_ICON_AT_ORIGIN | Enables UCS icon at origin |
128 (0x80) | VSF_FAST_ZOOM | Enables fast zoom |
256 (0x100) | VSF_SNAP_MODE | Enables snap mode |
512 (0x200) | VSF_GRID_MODE | Enables grid mode |
1024 (0x400) | VSF_ISOMETRIC_SNAP_STYLE | Enables isometric snap style |
2048 (0x800) | VSF_HIDE_PLOT_MODE | Enables hide plot mode |
4096 (0x1000) | VSF_KISOPAIR_TOP | kIsoPairTop. If set and kIsoPairRight is not set, then isopair top is enabled. If both kIsoPairTop and kIsoPairRight are set, then isopair left is enabled |
8192 (0x2000) | VSF_KISOPAIR_RIGHT | kIsoPairRight. If set and kIsoPairTop is not set, then isopair right is enabled |
16384 (0x4000) | VSF_LOCK_ZOOM | Enables viewport zoom locking |
32768 (0x8000) | VSF_CURRENTLY_ALWAYS_ENABLED | Currently always enabled |
65536 (0x10000) | VSF_NON_RECTANGULAR_CLIPPING | Enables non-rectangular clipping |
131072 (0x20000) | VSF_TURN_VIEWPORT_OFF | Turns the viewport off |
262144 (0x40000) | VSF_NO_GRID_LIMITS | Enables the display of the grid beyond the drawing limits |
524288 (0x80000) | VSF_ADAPTIVE_GRID_DISPLAY | Enable adaptive grid display |
1048576 (0x100000) | VSF_SUBDIVIDE_GRID | Enables subdivision of the grid below the set grid spacing when the grid display is adaptive |
2097152 (0x200000) | VSF_GRID_FOLLOW_WORKPLANE | Enables grid follows workplane switching |
Use helper method set_flag_state() to set and clear viewport flags, e.g. lock viewport:
vp.set_flag_state(ezdxf.const.VSF_LOCK_ZOOM, True)
0 | 2D Optimized (classic 2D) |
1 | Wireframe |
2 | Hidden line |
3 | Flat shaded |
4 | Gouraud shaded |
5 | Flat shaded with wireframe |
6 | Gouraud shaded with wireframe |
0 | not orthographic |
1 | Top |
2 | Bottom |
3 | Front |
4 | Back |
5 | Left |
6 | Right |
0 | As Displayed |
1 | Wireframe |
2 | Hidden |
3 | Rendered |
0 | One distant light |
1 | Two distant lights |
The WIPEOUT entity (DXF Reference) is a polygonal area that masks underlying objects with the current background color. The WIPEOUT entity is based on the IMAGE entity, but usage does not require any knowledge about the IMAGE entity.
The handles to the support entities ImageDef and ImageDefReactor are always “0”, both are not needed by the WIPEOUT entity.
Subclass of | ezdxf.entities.Image |
DXF type | 'WIPEOUT' |
Factory function | ezdxf.layouts.BaseLayout.add_wipeout() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
WARNING:
The XLINE entity (DXF Reference) is a construction line that extents to infinity in both directions.
Subclass of | ezdxf.entities.DXFGraphic |
DXF type | 'XLINE' |
Factory function | ezdxf.layouts.BaseLayout.add_xline() |
Inherited DXF attributes | Common graphical DXF attributes |
Required DXF version | DXF R2000 ('AC1015') |
Location point of line as (3D Point in WCS)
Unit direction vector as (3D Point in WCS)
All DXF objects can only reside in the OBJECTS section of a DXF document.
The purpose of the OBJECTS section is to allow CAD software developers to define and store custom objects that are not included in the basic DXF file format. These custom objects can be used to represent complex data structures, such as database tables or project management information, that are not easily represented by basic DXF entities.
By including custom objects in the OBJECTS section, CAD software developers can extend the functionality of their software to support new types of data and objects. For example, a custom application might define a new type of block or dimension style that is specific to a particular industry or workflow. By storing this custom object definition in the OBJECTS section, the CAD software can recognize and use the new object type in a drawing.
In summary, the OBJECTS section is an important part of the DXF file format because it allows CAD software developers to extend the functionality of their software by defining and storing custom objects and entity types. This makes it possible to represent complex data structures and workflows in CAD drawings, and allows CAD software to be customized to meet the specific needs of different industries and applications.
The DICTIONARY entity is a general storage entity.
AutoCAD maintains items such as MLINE_STYLES and GROUP definitions as objects in dictionaries. Other applications are free to create and use their own dictionaries as they see fit. The prefix 'ACAD_' is reserved for use by AutoCAD applications.
Dictionary entries are (key, DXFEntity) pairs for fully loaded or new created DXF documents. The referenced entities are owned by the dictionary and cannot be graphical entities that always belong to the layout in which they are located.
Loading DXF files is done in two passes, because at the first loading stage not all referenced objects are already stored in the entity database. Therefore the entities are stored as handles strings at the first loading stage and have to be replaced by the real entity at the second loading stage. If the entity is still a handle string after the second loading stage, the entity does not exist.
Dictionary keys are handled case insensitive by AutoCAD, but not by ezdxf, in doubt use an uppercase key. AutoCAD stores all keys in uppercase.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'DICTIONARY' |
Factory function | ezdxf.sections.objects.ObjectsSection.add_dictionary() |
WARNING:
0 | not applicable |
1 | keep existing |
2 | use clone |
3 | <xref>$0$<name> |
4 | $0$<name> |
5 | Unmangle name |
The returned value can be a handle string if the entity does not exist.
Only DXF objects stored in the OBJECTS section are allowed as content of Dictionary objects. DXF entities stored in layouts are not allowed.
If the DICTIONARY is hard owner of its entries, the add() does NOT take ownership of the entity automatically.
Graphical DXF entities have to reside in a layout and therefore can not be owned by a Dictionary.
Subclass of | ezdxf.entities.Dictionary |
DXF type | 'ACDBDICTIONARYWDFLT' |
Factory function | ezdxf.sections.objects.ObjectsSection.add_dictionary_with_default() |
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'DICTIONARYVAR' |
Factory function | ezdxf.entities.Dictionary.add_dict_var() |
LAYOUT entity is part of a modelspace or paperspace layout definitions.
Subclass of | ezdxf.entities.PlotSettings |
DXF type | 'LAYOUT' |
Factory function | internal data structure, use Layouts to manage layout objects. |
1 | Indicates the PSLTSCALE value for this layout when this layout is current |
2 | Indicates the LIMCHECK value for this layout when this layout is current |
0 | UCS is not orthographic |
1 | Top |
2 | Bottom |
3 | Front |
4 | Back |
5 | Left |
6 | Right |
default is 1
Common base class for all non-graphical DXF objects.
The GEODATA entity is associated to the Modelspace object. The GEODATA entity is supported since the DXF version R2000, but was officially documented the first time in the DXF reference for version R2009.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'GEODATA' |
Factory function | ezdxf.layouts.Modelspace.new_geodata() |
Required DXF version | R2010 ('AC1024') |
SEE ALSO:
WARNING:
1 | R2009 |
2 | R2010 |
0 | unknown |
1 | local grid |
2 | projected grid |
3 | geographic (latitude/longitude) |
1 | none |
2 | user specified scale factor |
3 | grid scale at reference point |
4 | prismoidal |
If axis-ordering is False the CRS is not compatible with the __geo_interface__ or GeoJSON (see chapter 3.1.1).
The EPSG number is stored in a tag like:
<Alias id="27700" type="CoordinateSystem"> <ObjectId>OSGB1936.NationalGrid</ObjectId> <Namespace>EPSG Code</Namespace> </Alias>
The axis-ordering is stored in a tag like:
<Axis uom="METER"> <CoordinateSystemAxis> <AxisOrder>1</AxisOrder> <AxisName>Easting</AxisName> <AxisAbbreviation>E</AxisAbbreviation> <AxisDirection>east</AxisDirection> </CoordinateSystemAxis> <CoordinateSystemAxis> <AxisOrder>2</AxisOrder> <AxisName>Northing</AxisName> <AxisAbbreviation>N</AxisAbbreviation> <AxisDirection>north</AxisDirection> </CoordinateSystemAxis> </Axis>
Supports only “Local Grid” transformation!
The CRS string is not validated nor interpreted!
HINT:
The IMAGEDEF entity defines an image file, which can be placed by the Image entity.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'IMAGEDEF' |
Factory function (1) | ezdxf.document.Drawing.add_image_def() |
Factory function (2) | ezdxf.sections.objects.ObjectsSection.add_image_def() |
WARNING:
0 | No units |
2 | Centimeters |
5 | Inch |
default is 0
The MLEADERSTYLE entity (DXF Reference) stores all attributes required to create new MultiLeader entities. The meaning of these attributes are not really documented in the DXF Reference. The default style “Standard” always exist.
SEE ALSO:
Create a new MLeaderStyle:
import ezdxf doc = ezdxf.new() new_style = doc.mleader_styles.new("NewStyle")
Duplicate an existing style:
duplicated_style = doc.mleader_styles.duplicate_entry("Standard", "DuplicatedStyle")
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'MLEADERSTYLE' |
Factory function | ezdxf.document.Drawing.mleader_styles.new() |
0 | center extents |
1 | insertion point |
0 | none |
1 | BLOCK |
2 | MTEXT |
3 | TOLERANCE |
default is MTEXT (2)
0 | invisible |
1 | straight line leader |
2 | spline leader |
default is 1
0 | text angle is equal to last leader line segment angle |
1 | text is horizontal |
2 | text angle is equal to last leader line segment angle, but potentially rotated by 180 degrees so the right side is up for readability. |
default is 1
0 | horizontal - left & right of content |
1 | vertical - top & bottom of content |
default is 0
9 | center |
10 | overline and center |
default is 9
0 | top of top MTEXT line |
1 | middle of top MTEXT line |
2 | middle of whole MTEXT |
3 | middle of bottom MTEXT line |
4 | bottom of bottom MTEXT line |
5 | bottom of bottom MTEXT line & underline bottom MTEXT line |
6 | bottom of top MTEXT line & underline top MTEXT line |
7 | bottom of top MTEXT line |
8 | bottom of top MTEXT line & underline all MTEXT lines |
0 | top of top MTEXT line |
1 | middle of top MTEXT line |
2 | middle of whole MTEXT |
3 | middle of bottom MTEXT line |
4 | bottom of bottom MTEXT line |
5 | bottom of bottom MTEXT line & underline bottom MTEXT line |
6 | bottom of top MTEXT line & underline top MTEXT line |
7 | bottom of top MTEXT line |
8 | bottom of top MTEXT line & underline all MTEXT lines |
9 | center |
10 | overline and center |
The ACDBPLACEHOLDER object for internal usage.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'ACDBPLACEHOLDER' |
Factory function | ezdxf.sections.objects.ObjectsSection.add_placeholder() |
WARNING:
All PLOTSETTINGS attributes are part of the DXFLayout entity, I don’t know if this entity also appears as standalone entity.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'PLOTSETTINGS' |
Factory function | internal data structure |
1 | plot viewport borders |
2 | show plot-styles |
4 | plot centered |
8 | plot hidden == hide paperspace entities? |
16 | use standard scale |
32 | plot with plot-styles |
64 | scale lineweights |
128 | plot entity lineweights |
512 | draw viewports first |
1024 | model type |
2048 | update paper |
4096 | zoom to paper on update |
8192 | initializing |
16384 | prev plot-init |
default is 688
0 | Plot in inches |
1 | Plot in millimeters |
2 | Plot in pixels |
0 | No rotation |
1 | 90 degrees counterclockwise |
2 | Upside-down |
3 | 90 degrees clockwise |
0 | Last screen display |
1 | Drawing extents |
2 | Drawing limits |
3 | View specified by code 6 |
4 | Window specified by codes 48, 49, 140, and 141 |
5 | Layout information |
0 | Scaled to Fit |
1 | 1/128”=1’ |
2 | 1/64”=1’ |
3 | 1/32”=1’ |
4 | 1/16”=1’ |
5 | 3/32”=1’ |
6 | 1/8”=1’ |
7 | 3/16”=1’ |
8 | 1/4”=1’ |
9 | 3/8”=1’ |
10 | 1/2”=1’ |
11 | 3/4”=1’ |
12 | 1”=1’ |
13 | 3”=1’ |
14 | 6”=1’ |
15 | 1’=1’ |
16 | 1:1 |
17 | 1:2 |
18 | 1:4 |
19 | 1:8 |
20 | 1:10 |
21 | 1:16 |
22 | 1:20 |
23 | 1:30 |
24 | 1:40 |
25 | 1:50 |
26 | 1:100 |
27 | 2:1 |
28 | 4:1 |
29 | 8:1 |
30 | 10:1 |
31 | 100:1 |
32 | 1000:1 |
0 | As Displayed |
1 | Wireframe |
2 | Hidden |
3 | Rendered |
0 | Draft |
1 | Preview |
2 | Normal |
3 | Presentation |
4 | Maximum |
5 | Custom |
The SUN entity defines properties of the sun.
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'SUN' |
Factory function | creating a new SUN entity is not supported |
0 | Sun do not cast shadows |
1 | Sun do cast shadows |
UnderlayDefinition (DXF Reference) defines an underlay file, which can be placed by the Underlay entity.
Subclass of | ezdxf.entities.DXFObject |
DXF type | internal base class |
Factory function (1) | ezdxf.document.Drawing.add_underlay_def() |
Factory function (2) | ezdxf.sections.objects.ObjectsSection.add_underlay_def() |
“pdf” | PDF page number |
“dgn” | always “default” |
“dwf” | ? |
WARNING:
Subclass of | ezdxf.entities.UnderlayDefinition |
DXF type | 'PDFDEFINITION' |
Factory function (1) | ezdxf.document.Drawing.add_underlay_def() |
Factory function (2) | ezdxf.sections.objects.ObjectsSection.add_underlay_def() |
Subclass of | ezdxf.entities.UnderlayDefinition |
DXF type | 'DWFDEFINITION' |
Factory function (1) | ezdxf.document.Drawing.add_underlay_def() |
Factory function (2) | ezdxf.sections.objects.ObjectsSection.add_underlay_def() |
Subclass of | ezdxf.entities.UnderlayDefinition |
DXF type | 'DGNDEFINITION' |
Factory function (1) | ezdxf.document.Drawing.add_underlay_def() |
Factory function (2) | ezdxf.sections.objects.ObjectsSection.add_underlay_def() |
Important class for storing application defined data in DXF files.
The XRECORD entities are used to store and manage arbitrary data. They are composed of DXF group codes ranging from 1 through 369. This object is similar in concept to XDATA but is not limited by size or order.
To reference a XRECORD by an DXF entity, store the handle of the XRECORD in the XDATA section, application defined data or the ExtensionDict of the DXF entity.
SEE ALSO:
Subclass of | ezdxf.entities.DXFObject |
DXF type | 'XRECORD' |
Factory function | ezdxf.sections.objects.ObjectsSection.add_xrecord() |
WARNING:
0 | not applicable |
1 | keep existing |
2 | use clone |
3 | <xref>$0$<name> |
4 | $0$<name> |
5 | Unmangle name |
Extended data (XDATA) is a DXF tags structure to store arbitrary data in DXF entities. The XDATA is associated to an AppID and only one tag list is supported for each AppID per entity.
WARNING:
This section shows how to store DXF tags directly in DXF entity but there is also a more user friendly and safer way to store custom XDATA in DXF entities:
Use the high level methods of DXFEntity to manage XDATA tags.
Get XDATA tags as a ezdxf.lldxf.tags.Tags data structure, without the mandatory first tag (1001, AppID):
if entity.has_xdata("EZDXF"): tags = entity.get_xdata("EZDXF") # or use alternatively: try: tags = entity.get_xdata("EZDXF") except DXFValueError: # XDATA for "EZDXF" does not exist ...
Set DXF tags as list of (group code, value) tuples or as ezdxf.lldxf.tags.Tags data structure, valid DXF tags for XDATA are documented in the section about the Extended Data internals. The mandatory first tag (1001, AppID) is inserted automatically if not present.
Set only new XDATA tags:
if not entity.has_xdata("EZDXF"): entity.set_xdata("EZDXF", [(1000, "MyString")])
Replace or set new XDATA tags:
entity.set_xdata("EZDXF", [(1000, "MyString")])
SEE ALSO:
The application-defined data feature is not very well documented in the DXF reference, so usage as custom data store is not recommended. AutoCAD uses these feature to store the handle to the extension dictionary (ExtensionDict) of a DXF entity and the handles to the persistent reactors (Reactors) of a DXF entity.
Use the high level methods of DXFEntity to manage application-defined data tags.
HINT:
Set application-defined data:
entity.set_app_data("YOURAPPID", [(1, "DataString")]))
Setting the content tags can contain the opening structure tag (102, “{YOURAPPID”) and the closing tag (102, “}”), but doesn’t have to. The returned Tags objects does not contain these structure tags. Which tags are valid for application-defined data is not documented.
The AppID has to have an entry in the AppID table.
Get application-defined data:
if entity.has_app_data("YOURAPPID"): tags = entity.get_app_data("YOURAPPID") # tags content is [DXFTag(1, 'DataString')]
SEE ALSO:
Every entity can have an extension dictionary, which can reference arbitrary DXF objects from the OBJECTS section but not graphical entities. Using this mechanism, several applications can attach data to the same entity. The usage of extension dictionaries is more complex than Extended Data (XDATA) but also more flexible with higher capacity for adding data.
Use the high level methods of DXFEntity to manage extension dictionaries.
The main data storage objects referenced by extension dictionaries are:
SEE ALSO:
SEE ALSO:
Only DXF objects stored in the OBJECTS section are allowed as content of the extension dictionary. DXF entities stored in layouts are not allowed.
Linked objects are owned by the extensions dictionary and therefore cannot be a graphical entity, which have to be owned by a BaseLayout.
Persistent reactors are optional object handles of objects registering themselves as reactors on an object. Any DXF object or DXF entity may have reactors.
Use the high level methods of DXFEntity to manage persistent reactor handles.
Ezdxf keeps these reactors only up to date, if this is absolute necessary according to the DXF reference.
SEE ALSO:
The package ezdxf is not designed as a CAD library and does not automatically monitor all internal changes. This enables faster entity processing at the cost of an unknown state of the DXF document.
In order to carry out precise BLOCK reference management, i.e. to handle dependencies or to delete unused BLOCK definition, the block reference status (counter) must be acquired explicitly by the package user. All block reference management structures must be explicitly recreated each time the document content is changed. This is not very efficient, but it is safe.
WARNING:
Always remember that ezdxf is not intended or suitable as a basis for a CAD application!
Check if a block is referenced by any entity or any resource (DIMSYTLE, MLEADERSTYLE) in a DXF document:
import ezdxf from ezdxf.blkrefs import BlockReferenceCounter doc = ezdxf.readfile("your.dxf") counter = BlockReferenceCounter(doc) count = counter.by_name("XYZ") print(f"Block 'XYZ' if referenced {count} times.")
The module ezdxf.lldxf.const, is also accessible from the ezdxf namespace:
from ezdxf.lldxf.const import DXF12 import ezdxf print(DXF12) print(ezdxf.const.DXF12)
Name | Version | Alias |
DXF9 | “AC1004” | “R9” |
DXF10 | “AC1006” | “R10” |
DXF12 | “AC1009” | “R12” |
DXF13 | “AC1012” | “R13” |
DXF14 | “AC1014” | “R14” |
DXF2000 | “AC1015” | “R2000” |
DXF2004 | “AC1018” | “R2004” |
DXF2007 | “AC1021” | “R2007” |
DXF2010 | “AC1024” | “R2010” |
DXF2013 | “AC1027” | “R2013” |
DXF2018 | “AC1032” | “R2018” |
Recommended way to create DXF entities.
For all supported entities exist at least one factory method in the ezdxf.layouts.BaseLayout class. All factory methods have the prefix: add_...
import ezdxf doc = ezdxf.new() msp = doc.modelspace() msp.add_line((0, 0, 0), (3, 0, 0), dxfattribs={"color": 2})
Only available in paper space layouts.
Linear Dimension
Radius and Diameter Dimension
Angular Dimension
Arc Dimension
Ordinate Dimension
The creation of the required ACIS data has do be done by an external library!
SEE ALSO:
Alternative way to create DXF entities for advanced ezdxf users.
The ezdxf.entities.factory module provides the new() function to create new DXF entities by their DXF name and a dictionary of DXF attributes. This will bypass the validity checks in the factory methods of the BaseLayout class.
This new created entities are virtual entities which are not assigned to any DXF document nor to any layout. Add the entity to a layout (and document) by the layout method add_entity().
import ezdxf from ezdxf.entities import factory doc = ezdxf.new() msp = doc.modelspace() line = factory.new( "LINE", dxfattribs={ "start": (0, 0, 0), "end": (3, 0, 0), "color": 2, }, ) msp.add_entity(line)
For advanced developers with knowledge about the internal design of ezdxf.
Import the entity classes from sub-package ezdxf.entities and instantiate them. This will bypass the validity checks in the factory methods of the BaseLayout class and maybe additional required setup procedures for some entities - study the source code!.
WARNING:
This new created entities are virtual entities which are not assigned to any DXF document nor to any layout. Add the entity to a layout (and document) by the layout method add_entity().
import ezdxf from ezdxf.entities import Line doc = ezdxf.new() msp = doc.modelspace() line = Line.new( dxfattribs={ "start": (0, 0, 0), "end": (3, 0, 0), "color": 2, } ) msp.add_entity(line)
This module provides functions and constants to manage all kinds of colors in DXF documents.
Common AutoCAD Color Index (ACI) values, also accessible as IntEnum ezdxf.enums.ACI
BYBLOCK | 0 |
BYLAYER | 256 |
BYOBJECT | 257 |
RED | 1 |
YELLOW | 2 |
GREEN | 3 |
CYAN | 4 |
BLUE | 5 |
MAGENTA | 6 |
BLACK (on light background) | 7 |
WHITE (on dark background) | 7 |
GRAY | 8 |
LIGHT_GRAY | 9 |
Default color mappings from AutoCAD Color Index (ACI) to true-color values.
model space | DXF_DEFAULT_COLORS |
paper space | DXF_DEFAULT_PAPERSPACE_COLORS |
COLOR_TYPE_BY_LAYER | 0xC0 |
COLOR_TYPE_BY_BLOCK | 0xC1 |
COLOR_TYPE_RGB | 0xC2 |
COLOR_TYPE_ACI | 0xC3 |
COLOR_TYPE_WINDOW_BG | 0xC8 |
BY_LAYER_RAW_VALUE | -1073741824 |
BY_BLOCK_RAW_VALUE | -1056964608 |
WINDOW_BG_RAW_VALUE | -939524096 |
OPAQUE | 0x20000FF |
TRANSPARENCY_10 | 0x20000E5 |
TRANSPARENCY_20 | 0x20000CC |
TRANSPARENCY_30 | 0x20000B2 |
TRANSPARENCY_40 | 0x2000099 |
TRANSPARENCY_50 | 0x200007F |
TRANSPARENCY_60 | 0x2000066 |
TRANSPARENCY_70 | 0x200004C |
TRANSPARENCY_80 | 0x2000032 |
TRANSPARENCY_90 | 0x2000019 |
TRANSPARENCY_BYBLOCK | 0x1000000 |
SEE ALSO:
QueryString := EntityQuery ("[" AttribQuery "]" "i"?)*
The query string is the combination of two queries, first the required entity query and second the optional attribute query, enclosed in square brackets, append 'i' after the closing square bracket to ignore case for strings.
The entity query is a whitespace separated list of DXF entity names or the special name '*'. Where '*' means all DXF entities, exclude some entity types by appending their names with a preceding ! (e.g. all entities except LINE = '* !LINE'). All DXF names have to be uppercase.
The optional attribute query is a boolean expression, supported operators are:
Attribute selection is a term: “name comparator value”, where name is a DXF entity attribute in lowercase, value is a integer, float or double quoted string, valid comparators are:
The EntityQuery class is the return type of all query() methods. EntityQuery contains all DXF entities of the source collection, which matches one name of the entity query AND the whole attribute query. If a DXF entity does not have or support a required attribute, the corresponding attribute search term is False.
examples:
Build your own operator to filter by attributes which are not DXF attributes or to build complex queries:
result = msp.query().filter( lambda e: hasattr(e, "rgb") and e.rbg == (0, 0, 0) )
The [] operator got extended features in version 0.18, until then the EntityQuery implemented the __getitem__() interface like a sequence to get entities from the container:
result = msp.query(...) first = result[0] last = result[-1] sequence = result[1:-2] # returns not an EntityQuery container!
Now the __getitem__() function accepts also a DXF attribute name and returns all entities which support this attribute, this is the base for supporting queries by relational operators. More on that later.
The __setitem__() method assigns a DXF attribute to all supported entities in the EntityQuery container:
result = msp.query(...) result["layer"] = "MyLayer"
Entities which do not support an attribute are silently ignored:
result = msp.query(...) result["center"] = (0, 0) # set center only of CIRCLE and ARC entities
The __delitem__() method discards DXF attributes from all entities in the EntityQuery container:
result = msp.query(...) # reset the layer attribute from all entities in container result to the # default layer "0" del result["layer"]
For some basic DXF attributes exist descriptors in the EntityQuery class:
A descriptor simplifies the attribute access through the EntityQuery container and has auto-completion support from IDEs:
result = msp.query(...) # set attribute of all entities in result result.layer = "MyLayer" # delete attribute from all entities in result del result.layer # and for selector usage, see following section assert len(result.layer == "MyLayer") == 1
The attribute selection by __getitem__() allows further selections by relational operators:
msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "MyLayer}) lines = msp.query("LINE") # select all entities on layer "MyLayer" entities = lines["layer"] == "MyLayer" assert len(entities) == 1 # or select all entities except the entities on layer "MyLayer" entities = lines["layer"] != "MyLayer"
These operators work only with real DXF attributes, for instance the rgb attribute of graphical entities is not a real DXF attribute either the vertices of the LWPOLYLINE entity.
The selection by relational operators is case insensitive by default, because all names of DXF table entries are handled case insensitive. But if required the selection mode can be set to case sensitive:
lines = msp.query("LINE") # use case sensitive selection: "MyLayer" != "MYLAYER" lines.ignore_case = False entities = lines["layer"] == "MYLAYER" assert len(entities) == 0 # the result container has the default setting: assert entities.ignore_case is True
Supported selection operators are:
The relational operators <, >, <= and >= are not supported for vector-based attributes such as center or insert and raise a TypeError.
NOTE:
The EntityQuery.match() method returns all entities where the selected DXF attribute matches the given regular expression. This methods work only on string based attributes, raises TypeError otherwise.
From here on I use only descriptors for attribute selection if possible.
msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "Lay1"}) msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "Lay2"}) lines = msp.query("LINE") # select all entities at layers starting with "Lay", # selection is also case insensitive by default: assert len(lines.layer.match("^Lay.*")) == 2
The method EntityQuery.filter can be used to build operators for none-DXF attributes or for complex logic expressions.
Find all MTEXT entities in modelspace containing “SearchText”. All MText entities have a text attribute, no need for a safety check:
mtext = msp.query("MTEXT").filter(lambda e: "SearchText" in e.text)
This filter checks the non-DXF attribute rgb. The filter has to check if the rgb attributes exist to avoid exceptions, because not all entities in modelspace may have the rgb attribute e.g. the DXFTagStorage entities which preserve unknown DXF entities:
result = msp.query().filter( lambda e: hasattr(e, "rgb") and e.rgb == (0, 0, 0) )
Build 1-pass logic filters for complex queries, which would require otherwise multiple passes:
result = msp.query().filter(lambda e: e.dxf.color < 7 and e.dxf.layer == "0")
Combine filters for more complex operations. The first filter passes only valid entities and the second filter does the actual check:
def validator(entity): return True # if entity is valid and has all required attributes def check(entity): return True # if entity passes the attribute checks result = msp.query().filter(validator).filter(check)
The | operator or EntityQuery.union() returns a new EntityQuery with all entities from both queries. All entities are unique - no duplicates. This operator acts like the logical or operator.
entities = msp.query() # select all entities with color < 2 or color > 7 result = (entities.color < 2 ) | (entities.color > 7)
The & operator or EntityQuery.intersection() returns a new EntityQuery with entities common to self and other. This operator acts like the logical and operator.
entities = msp.query() # select all entities with color > 1 and color < 7 result = (entities.color > 1) & (entities.color < 7)
The - operator or EntityQuery.difference() returns a new EntityQuery with all entities from self that are not in other.
entities = msp.query() # select all entities with color > 1 and not layer == "MyLayer" result = (entities.color > 1) - (entities.layer != "MyLayer")
The ^ operator or EntityQuery.symmetric_difference() returns a new EntityQuery with entities in either self or other but not both.
entities = msp.query() # select all entities with color > 1 or layer == "MyLayer", exclusive # entities with color > 1 and layer == "MyLayer" result = (entities.color > 1) ^ (entities.layer == "MyLayer")
SEE ALSO:
def group_key(entity: DXFEntity): return entity.dxf.layer, entity.dxf.color
For not suitable DXF entities return None to exclude this entity, in this case it’s not required, because groupby() catches DXFAttributeError exceptions to exclude entities, which do not provide layer and/or color attributes, automatically.
Result dict for dxfattrib = 'layer' may look like this:
{ '0': [ ... list of entities ], 'ExampleLayer1': [ ... ], 'ExampleLayer2': [ ... ], ... }
Result dict for key = group_key, which returns a (layer, color) tuple, may look like this:
{ ('0', 1): [ ... list of entities ], ('0', 3): [ ... ], ('0', 7): [ ... ], ('ExampleLayer1', 1): [ ... ], ('ExampleLayer1', 2): [ ... ], ('ExampleLayer1', 5): [ ... ], ('ExampleLayer2', 7): [ ... ], ... }
All entity containers (modelspace, paperspace layouts and blocks) and the EntityQuery object have a dedicated groupby() method.
Math core module: ezdxf.math
These are the core math functions and classes which should be imported from ezdxf.math.
arc_angle_span_deg | Returns the counter-clockwise angle span from start to end in degrees. |
arc_angle_span_rad | Returns the counter-clockwise angle span from start to end in radians. |
arc_chord_length | Returns the chord length for an arc defined by radius and the sagitta. |
arc_segment_count | Returns the count of required segments for the approximation of an arc for a given maximum sagitta. |
area | Returns the area of a polygon, returns the projected area in the xy-plane for any vertices (z-axis will be ignored). |
closest_point | Returns the closest point to a give base point. |
ellipse_param_span | Returns the counter-clockwise params span of an elliptic arc from start- to end param. |
has_matrix_2d_stretching | Returns True if matrix m performs a non-uniform xy-scaling. |
has_matrix_3d_stretching | Returns True if matrix m performs a non-uniform xyz-scaling. |
linspace | Return evenly spaced numbers over a specified interval, like numpy.linspace(). |
open_uniform_knot_vector | Returns an open (clamped) uniform knot vector for a B-spline of order and count control points. |
required_knot_values | Returns the count of required knot-values for a B-spline of order and count control points. |
uniform_knot_vector | Returns an uniform knot vector for a B-spline of order and count control points. |
xround | Extended rounding function. |
order = degree + 1
order = degree + 1
Relationship:
“p” is the degree of the B-spline, text-book notation.
The argument rounding defines the rounding limit:
0 | remove fraction |
0.1 | round next to x.1, x.2, … x.0 |
0.25 | round next to x.25, x.50, x.75 or x.00 |
0.5 | round next to x.5 or x.0 |
1.0 | round to a multiple of 1: remove fraction |
2.0 | round to a multiple of 2: xxx2, xxx4, xxx6 … |
5.0 | round to a multiple of 5: xxx5 or xxx0 |
10.0 | round to a multiple of 10: xx10, xx20, … |
Returns num evenly spaced samples, calculated over the interval [start, stop]. The endpoint of the interval can optionally be excluded.
Returns the angle span in the range of [0, 360], 360 is a full circle. Full circle handling is a special case, because normalization of angles which describe a full circle would return 0 if treated as regular angles. e.g. (0, 360) → 360, (0, -360) → 360, (180, -180) → 360. Input angles with the same value always return 0 by definition: (0, 0) → 0, (-180, -180) → 0, (360, 360) → 0.
Returns the angle span in the range of [0, 2π], 2π is a full circle. Full circle handling is a special case, because normalization of angles which describe a full circle would return 0 if treated as regular angles. e.g. (0, 2π) → 2π, (0, -2π) → 2π, (π, -π) → 2π. Input angles with the same value always return 0 by definition: (0, 0) → 0, (-π, -π) → 0, (2π, 2π) → 0.
Returns the param span in the range [0, 2π], 2π is a full ellipse. Full ellipse handling is a special case, because normalization of params which describe a full ellipse would return 0 if treated as regular params. e.g. (0, 2π) → 2π, (0, -2π) → 2π, (π, -π) → 2π. Input params with the same value always return 0 by definition: (0, 0) → 0, (-π, -π) → 0, (2π, 2π) → 0.
Alias to function: ezdxf.math.arc_angle_span_rad()
Does not check if the target system is a cartesian coordinate system, use the Matrix44 property is_cartesian for that.
Does not check if the target system is a cartesian coordinate system, use the Matrix44 property is_cartesian for that.
arc_to_bulge | Returns bulge parameters from arc parameters. |
bulge_3_points | Returns bulge value defined by three points. |
bulge_center | Returns center of arc described by the given bulge parameters. |
bulge_radius | Returns radius of arc defined by the given bulge parameters. |
bulge_to_arc | Returns arc parameters from bulge parameters. |
bulge_from_radius_and_chord | Returns the bulge value for the given arc radius and chord length. |
bulge_from_arc_angle | Returns the bulge value for the given arc angle. |
SEE ALSO:
Based on 3-Points to Bulge by Lee Mac.
Based on Bulge Center by Lee Mac.
Based on Bulge Radius by Lee Mac
The arcs defined by bulge values of LWPolyline and 2D Polyline entities start at the vertex which includes the bulge value and ends at the following vertex.
Based on Bulge to Arc by Lee Mac.
convex_hull_2d | Returns the 2D convex hull of given points. |
distance_point_line_2d | Returns the normal distance from point to 2D line defined by start- and end point. |
intersect_polylines_2d | Returns the intersection points for two polylines as list of Vec2 objects, the list is empty if no intersection points exist. |
intersection_line_line_2d | Compute the intersection of two lines in the xy-plane. |
is_convex_polygon_2d | Returns True if the 2D polygon is convex. |
is_point_in_polygon_2d | Test if point is inside polygon. |
is_point_left_of_line | Returns True if point is "left of line" defined by start- and end point, a colinear point is also "left of line" if argument colinear is True. |
is_point_on_line_2d | Returns True if point is on line. |
offset_vertices_2d | Yields vertices of the offset line to the shape defined by vertices. |
point_to_line_relation | Returns -1 if point is left line, +1 if point is right of line and 0 if point is on the line. |
rytz_axis_construction | The Rytz’s axis construction is a basic method of descriptive Geometry to find the axes, the semi-major axis and semi-minor axis, starting from two conjugated half-diameters. |
Returns a closed polyline, first vertex is equal to the last vertex.
This solution works only for simple non-self-intersecting polygons!
WARNING:
source = [(0, 0), (3, 0), (3, 3), (0, 3)] result = list(offset_vertices_2d(source, offset=0.5, closed=True))
[image]
Example for a closed collinear shape, which creates 2 additional vertices and the first one has an unexpected location:
source = [(0, 0), (0, 1), (0, 2), (0, 3)] result = list(offset_vertices_2d(source, offset=0.5, closed=True))
Source: Wikipedia
Given conjugated diameter d1 is the vector from center C to point P and the given conjugated diameter d2 is the vector from center C to point Q. Center of ellipse is always (0, 0, 0). This algorithm works for 2D/3D vectors.
basic_transformation | Returns a combined transformation matrix for translation, scaling and rotation about the z-axis. |
best_fit_normal | Returns the "best fit" normal for a plane defined by three or more vertices. |
bezier_to_bspline | Convert multiple quadratic or cubic Bèzier curves into a single cubic B-spline. |
closed_uniform_bspline | Creates a closed uniform (periodic) B-spline curve (open curve). |
cubic_bezier_bbox | Returns the BoundingBox of a cubic Bézier curve of type Bezier4P. |
cubic_bezier_from_3p | Returns a cubic Bèzier curve Bezier4P from three points. |
cubic_bezier_from_arc | Returns an approximation for a circular 2D arc by multiple cubic Bézier-curves. |
cubic_bezier_from_ellipse | Returns an approximation for an elliptic arc by multiple cubic Bézier-curves. |
cubic_bezier_interpolation | Returns an interpolation curve for given data points as multiple cubic Bézier-curves. |
distance_point_line_3d | Returns the normal distance from a point to a 3D line. |
estimate_end_tangent_magnitude | Estimate tangent magnitude of start- and end tangents. |
estimate_tangents | Estimate tangents for curve defined by given fit points. |
fit_points_to_cad_cv | Returns a cubic BSpline from fit points as close as possible to common CAD applications like BricsCAD. |
fit_points_to_cubic_bezier | Returns a cubic BSpline from fit points without end tangents. |
global_bspline_interpolation | B-spline interpolation by the Global Curve Interpolation. |
have_bezier_curves_g1_continuity | Return True if the given adjacent Bézier curves have G1 continuity. |
intersect_polylines_3d | Returns the intersection points for two polylines as list of Vec3 objects, the list is empty if no intersection points exist. |
intersection_line_line_3d | Returns the intersection point of two 3D lines, returns None if lines do not intersect. |
intersection_line_polygon_3d | Returns the intersection point of the 3D line form start to end and the given polygon. |
intersection_ray_polygon_3d | Returns the intersection point of the infinite 3D ray defined by origin and the direction vector and the given polygon. |
intersection_ray_ray_3d | Calculate intersection of two 3D rays, returns a 0-tuple for parallel rays, a 1-tuple for intersecting rays and a 2-tuple for not intersecting and not parallel rays with points of the closest approach on each ray. |
is_planar_face | Returns True if sequence of vectors is a planar face. |
linear_vertex_spacing | Returns count evenly spaced vertices from start to end. |
local_cubic_bspline_interpolation | B-spline interpolation by 'Local Cubic Curve Interpolation', which creates B-spline from fit points and estimated tangent direction at start-, end- and passing points. |
normal_vector_3p | Returns normal vector for 3 points, which is the normalized cross product for: a->b x a->c. |
open_uniform_bspline | Creates an open uniform (periodic) B-spline curve (open curve). |
quadratic_bezier_bbox | Returns the BoundingBox of a quadratic Bézier curve of type Bezier3P. |
quadratic_bezier_from_3p | Returns a quadratic Bèzier curve Bezier3P from three points. |
quadratic_to_cubic_bezier | Convert quadratic Bèzier curves (ezdxf.math.Bezier3P) into cubic Bèzier curves (ezdxf.math.Bezier4P). |
rational_bspline_from_arc | Returns a rational B-splines for a circular 2D arc. |
rational_bspline_from_ellipse | Returns a rational B-splines for an elliptic arc. |
safe_normal_vector | Safe function to detect the normal vector for a face or polygon defined by 3 or more vertices. |
spherical_envelope | Calculate the spherical envelope for the given points. |
split_bezier | Split a Bèzier curve at parameter t. |
split_polygon_by_plane | Split a convex polygon by the given plane. |
subdivide_face | Subdivides faces by subdividing edges and adding a center vertex. |
subdivide_ngons | Subdivides faces into triangles by adding a center vertex. |
SEE ALSO:
For good results the curves must be lined up seamlessly, i.e. the starting point of the following curve must be the same as the end point of the previous curve. G1 continuity or better at the connection points of the Bézier curves is required to get best results.
This B-spline does not pass any of the control points.
Available estimation methods:
Available tangent estimation methods:
There exist infinite numerical correct solution for this setup, but some facts are known:
This function uses the cubic Bèzier interpolation to create multiple Bèzier curves and combine them into a single B-spline, this works for short simple splines better than the fit_points_to_cad_cv(), but is worse for longer and more complex splines.
It is possible to constraint the curve by tangents, by start- and end tangent if only two tangents are given or by one tangent for each fit point.
If tangents are given, they represent 1st derivatives and should be scaled if they are unit vectors, if only start- and end tangents given the function estimate_end_tangent_magnitude() helps with an educated guess, if all tangents are given, scaling by chord length is a reasonable choice (Piegl & Tiller).
Source: Piegl & Tiller: “The NURBS Book” - chapter 9.3.4
Available tangent estimation methods:
or pass pre-calculated tangents, which overrides tangent estimation.
This is an unclamped curve, which means the curve passes none of the control points.
NOTE:
Returns the control points for two new Bèzier curves of the same degree and type as the input curve. (source: pomax-1)
Returns a tuple of front- and back vertices (front, back). Returns also coplanar polygons if the argument coplanar is True, the coplanar vertices goes into either front or back depending on their orientation with respect to this plane.
Matrix44 | An optimized 4x4 transformation matrix. |
OCS | Establish an OCS for a given extrusion vector. |
UCS | Establish a user coordinate system (UCS). |
If x- and y-axis are None: ux = (1, 0, 0), uy = (0, 1, 0), uz = (0, 0, 1).
Unit vectors don’t have to be normalized, normalization is done at initialization, this is also the reason why scaling gets lost by copying or rotating.
The OCS is defined by the z-axis of the UCS.
The OCS is defined by the z-axis of the UCS.
The utility functions for constructing transformations and transforming vectors and points assumes that vectors are stored as row vectors, meaning when multiplied, transformations are applied left to right (e.g. vAB transforms v by A then by B).
Matrix44 initialization:
Profiling results - speed gains over transform_vertices():
But speed isn’t everything, returning the processed input points as Vec2 instances is another advantage.
New in version 1.1.
Does not check for left- or right handed orientation, any orientation of the axis valid.
BoundingBox | 3D bounding box. |
BoundingBox2d | 2D bounding box. |
ConstructionArc | Construction tool for 2D arcs. |
ConstructionBox | Construction tool for 2D rectangles. |
ConstructionCircle | Construction tool for 2D circles. |
ConstructionEllipse | Construction tool for 3D ellipsis. |
ConstructionLine | Construction tool for 2D lines. |
ConstructionPolyline | Construction tool for 3D polylines. |
ConstructionRay | Construction tool for infinite 2D rays. |
Plane | Construction tool for 3D planes. |
Shape2d | Construction tools for 2D shapes. |
Vec2 | Immutable 2D vector class. |
Vec3 | Immutable 3D vector class. |
This class is optimized for universality not for speed. Immutable means you can’t change (x, y, z) components after initialization:
v1 = Vec3(1, 2, 3) v2 = v1 v2.z = 7 # this is not possible, raises AttributeError v2 = Vec3(v2.x, v2.y, 7) # this creates a new Vec3() object assert v1.z == 3 # and v1 remains unchanged
Vec3 initialization:
Addition, subtraction, scalar multiplication and scalar division left and right-handed are supported:
v = Vec3(1, 2, 3) v + (1, 2, 3) == Vec3(2, 4, 6) (1, 2, 3) + v == Vec3(2, 4, 6) v - (1, 2, 3) == Vec3(0, 0, 0) (1, 2, 3) - v == Vec3(0, 0, 0) v * 3 == Vec3(3, 6, 9) 3 * v == Vec3(3, 6, 9) Vec3(3, 6, 9) / 3 == Vec3(1, 2, 3) -Vec3(1, 2, 3) == (-1, -2, -3)
Comparison between vectors and vectors or tuples is supported:
Vec3(1, 2, 3) < Vec3 (2, 2, 2) (1, 2, 3) < tuple(Vec3(2, 2, 2)) # conversion necessary Vec3(1, 2, 3) == (1, 2, 3) bool(Vec3(1, 2, 3)) is True bool(Vec3(0, 0, 0)) is False
Learn more about the math.isclose() function in PEP 485.
Vec2 implements a subset of Vec3.
Represents a plane in 3D space as a normal vector and the perpendicular distance from the origin.
Vertices at the box border are inside!
Vertices at the box border are inside!
Vertices at the box border are inside!
bbox1 = BoundingBox([(0, 0, 0), (1, 1, 1)]) bbox2 = BoundingBox([(1, 1, 1), (2, 2, 2)]) assert bbox1.has_intersection(bbox2) is False
bbox1 = BoundingBox([(0, 0, 0), (1, 1, 1)]) bbox2 = BoundingBox([(1, 1, 1), (2, 2, 2)]) assert bbox1.has_overlap(bbox2) is True
Vertices at the box border are inside!
Vertices at the box border are inside!
Vertices at the box border are inside!
bbox1 = BoundingBox2d([(0, 0), (1, 1)]) bbox2 = BoundingBox2d([(1, 1), (2, 2)]) assert bbox1.has_intersection(bbox2) is False
bbox1 = BoundingBox2d([(0, 0), (1, 1)]) bbox2 = BoundingBox2d([(1, 1), (2, 2)]) assert bbox1.has_overlap(bbox2) is True
The ConstructionLine class is similar to ConstructionRay, but has a start- and endpoint. The direction of line goes from start- to endpoint, “left of line” is always in relation to this line direction.
If colinear is True, a colinear point is also left of the line.
tuple size | Description |
0 | no intersection |
1 | ray is a tangent to circle |
2 | ray intersects with the circle |
tuple size | Description |
0 | no intersection |
1 | line intersects or touches the circle at one point |
2 | line intersects the circle at two points |
tuple size | Description |
0 | no intersection |
1 | circle touches the other circle at one point |
2 | circle intersects with the other circle |
ConstructionArc represents a 2D arc in the xy-plane, use an UCS to place a DXF Arc entity in 3D space, see method add_to_layout().
Implements the 2D transformation tools: translate(), scale_uniform() and rotate_z()
All angles are normalized in the range from [0, 360).
The parameter center_is_left defines if the center of the arc is left or right of the line from start_point to end_point. Parameter ccw = False swaps start- and end point, which also inverts the meaning of center_is_left.
Supports 3D arcs by using an UCS. An ConstructionArc is always defined in the xy-plane, but by using an arbitrary UCS, the arc can be placed in 3D space, automatically OCS transformation included.
tuple size | Description |
0 | no intersection |
1 | line intersects or touches the arc at one point |
2 | line intersects the arc at two points |
tuple size | Description |
0 | no intersection |
1 | line intersects or touches the arc at one point |
2 | line intersects the arc at two points |
tuple size | Description |
0 | no intersection |
1 | circle intersects or touches the arc at one point |
2 | circle intersects the arc at two points |
tuple size | Description |
0 | no intersection |
1 | other arc intersects or touches the arc at one point |
2 | other arc intersects the arc at two points |
OCS elevation is stored in center.z.
All params are normalized in the range from [0, 2π).
The vertex don’t have to be exact on the ellipse curve or in the range from start- to end param or even in the ellipse plane. Param is calculated from the intersection point of the ray projected on the ellipse plane from the center of the ellipse through the vertex.
WARNING:
Entity ELLIPSE has always a ratio in range from 1e-6 to 1.
Arc and Circle parameters defined in OCS.
list size | Description |
0 | no intersection |
1 | line touches box at one corner |
2 | line intersects with box |
A polyline construction tool to measure, interpolate and divide anything that can be approximated or flattened into vertices. This is an immutable data structure which supports the Sequence interface.
Example to measure or divide a SPLINE entity:
import ezdxf from ezdxf.math import ConstructionPolyline doc = ezdxf.readfile("your.dxf") msp = doc.modelspace() spline = msp.query("SPLINE").first if spline is not None: polyline = ConstructionPolyline(spline.flattening(0.01)) print(f"Entity {spline} has an approximated length of {polyline.length}") # get dividing points with a distance of 1.0 drawing unit to each other points = list(polyline.divide_by_length(1.0))
A 2D geometry object as list of Vec2 objects, vertices can be moved, rotated and scaled.
ApproxParamT | Approximation tool for parametrized curves. |
BSpline | B-spline construction tool. |
Bezier | Generic Bézier curve of any degree. |
Bezier3P | Implements an optimized quadratic Bézier curve for exact 3 control points. |
Bezier4P | Implements an optimized cubic Bézier curve for exact 4 control points. |
BezierSurface | BezierSurface defines a mesh of m x n control points. |
EulerSpiral | This class represents an euler spiral (clothoid) for curvature (Radius of curvature). |
Internal representation of a B-spline curve. The default configuration of the knot vector is a uniform open knot vector (“clamped”).
Factory functions:
e.g. n=1 returns point and 1st derivative.
e.g. n=1 returns point and 1st derivative.
This is the preferred method to represent the most common non-rational B-splines of 3rd degree by cubic Bézier curves, which are often supported by render backends.
E.g. a B-Spline of 8 control points has 7 segments at the first level, 14 at the 2nd level and 28 at the 3rd level, a level >= 3 is recommended.
A Bézier curve is a parametric curve used in computer graphics and related fields. Bézier curves are used to model smooth curves that can be scaled indefinitely. “Paths”, as they are commonly referred to in image manipulation programs, are combinations of linked Bézier curves. Paths are not bound by the limits of rasterized images and are intuitive to modify. (Source: Wikipedia)
This is a generic implementation which works with any count of definition points greater than 2, but it is a simple and slow implementation. For more performance look at the specialized Bezier4P and Bezier3P classes.
Objects are immutable.
A Bézier curve is a parametric curve, parameter t goes from 0 to 1, where 0 is the first control point and 1 is the fourth control point.
Special behavior:
Special behavior:
These approximations can be applied to all parametrized curves which provide a point() method, like Bezier4P, Bezier3P and BSpline.
The approximation is based on equally spaced parameters from 0 to max_t for a given segment count. The flattening() method can not be used for the curve approximation, because the required parameter t is not logged by the flattening process.
This is a parametric curve, which always starts at the origin = (0, 0).
Clipping module: ezdxf.math.clipping
This class will get an optimized implementation in the future.
Clustering module: ezdxf.math.clustering
https://en.wikipedia.org/wiki/DBSCAN
https://en.wikipedia.org/wiki/K-means_clustering
Linear algebra module for internal usage: ezdxf.math.linalg
Internally used for matrix inverse calculation.
HINT:
Reference implementation for error checking.
Reference implementation for error checking.
Note: a0 is not used but has to be present, cn-1 is also not used and must not be present.
If an ZeroDivisionError exception occurs, the equation system can possibly be solved by BandedMatrixLU(A, 1, 1).solve_vector(B)
diagonal matrix [[a0..an-1], [b0..bn-1], [c0..cn-1]]
[[b0, c0, 0, 0, ...], [a1, b1, c1, 0, ...], [0, a2, b2, c2, ...], ... ]
Note: a0 is not used but has to be present, cn-1 is also not used and must not be present.
If an ZeroDivisionError exception occurs, the equation system can possibly be solved by BandedMatrixLU(A, 1, 1).solve_vector(B)
diagonal matrix [[a0..an-1], [b0..bn-1], [c0..cn-1]]
[[b0, c0, 0, 0, ...], [a1, b1, c1, 0, ...], [0, a2, b2, c2, ...], ... ]
The matrix can be frozen by function freeze_matrix() or method Matrix.freeze(), than the data is stored in immutable tuples.
Initialization:
An index of 0 specifies the main diagonal, negative values specifies diagonals below the main diagonal and positive values specifies diagonals above the main diagonal.
e.g. given a 4x4 matrix:
An index of 0 specifies the main diagonal, negative values specifies diagonals below the main diagonal and positive values specifies diagonals above the main diagonal.
e.g. given a 4x4 matrix: index 0 is [00, 11, 22, 33], index -1 is [10, 21, 32] and index +1 is [01, 12, 23]
This algorithm is a little bit faster than the Gauss-Elimination algorithm using CPython and much faster when using pypy.
The LUDecomposition.matrix attribute gives access to the matrix data as list of rows like in the Matrix class, and the LUDecomposition.index attribute gives access to the swapped row indices.
RTree module: ezdxf.math.rtree
The search tree is buildup once at initialization and immutable afterwards, because rebuilding the tree after inserting or deleting nodes is very costly and also keeps the implementation very simple. Without the ability to alter the content the restrictions which forces the tree balance at growing and shrinking of the original R-trees, could be ignored, like the fixed minimum and maximum node size.
This class uses internally only 3D bounding boxes, but also supports Vec2 as well as Vec3 objects as input data, but point types should not be mixed in a single search tree.
The point objects keep their type and identity and the returned points of queries can be compared by the is operator for identity to the input points.
The implementation requires a maximum node size of at least 2 and does not support empty trees!
WARNING:
Triangulation module: ezdxf.math.triangulation
Implements a modified ear slicing algorithm, optimized by z-order curve hashing and extended to handle holes, twisted polygons, degeneracies and self-intersections in a way that doesn’t guarantee correctness of triangulation, but attempts to always produce acceptable results for practical data.
Source: https://github.com/mapbox/earcut
Implements a modified ear slicing algorithm, optimized by z-order curve hashing and extended to handle holes, twisted polygons, degeneracies and self-intersections in a way that doesn’t guarantee correctness of triangulation, but attempts to always produce acceptable results for practical data.
Source: https://github.com/mapbox/earcut
This module implements a geometric Path, supported by several render backends, with the goal to create such paths from DXF entities like LWPOLYLINE, POLYLINE or HATCH and send them to the render backend, see ezdxf.addons.drawing.
Minimum common interface:
ARC and ELLIPSE entities are approximated by multiple cubic Bézier-curves, which are close enough for display rendering. Non-rational SPLINES of 3rd degree can be represented exact as multiple cubic Bézier-curves, other B-splines will be approximated. The XLINE and the RAY entities are not supported, because of their infinite nature.
This Path class is a full featured 3D object, although the backends only support 2D paths.
HINT:
The usability of the Path class expanded by the introduction of the reverse conversion from Path to DXF entities (LWPOLYLINE, POLYLINE, LINE), and many other tools in ezdxf v0.16. To emphasize this new usability, the Path class has got its own subpackage ezdxf.path.
WARNING:
Functions to create Path objects from other objects.
Functions to create DXF entities from paths and add them to the modelspace, a paperspace layout or a block definition.
The extrusion vector is applied to all paths, all vertices are projected onto the plane normal to this extrusion vector. The default extrusion vector is the WCS z-axis. The plane elevation is the distance from the WCS origin to the start point of the first path.
Functions to create DXF entities from paths.
The extrusion vector is applied to all paths, all vertices are projected onto the plane normal to this extrusion vector. The default extrusion vector is the WCS z-axis. The plane elevation is the distance from the WCS origin to the start point of the first path.
Functions to create construction tools.
Auto-detect the connection point to the given path, if neither the start- nor the end point of the curves is close to the path end point, a line from the path end point to the start point of the first curve will be added automatically.
Auto-detect the connection point to the given path, if neither the start- nor the end point of the curves is close to the path end point, a line from the path end point to the start point of the first curve will be added automatically.
Auto-detect the connection point to the given path, if neither the start- nor the end point of the ellipse is close to the path end point, a line from the path end point to the ellipse start point will be added automatically (see add_bezier4p()).
By default, the start of an empty path is set to the start point of the ellipse, setting argument reset to False prevents this behavior.
Non-rational B-splines of 3rd degree gets a perfect conversion to cubic Bézier curves with a minimal count of curve segments, all other B-spline require much more curve segments for approximation.
Auto-detect the connection point to the given path, if neither the start- nor the end point of the B-spline is close to the path end point, a line from the path end point to the start point of the B-spline will be added automatically. (see add_bezier4p()).
By default, the start of an empty path is set to the start point of the spline, setting argument reset to False prevents this behavior.
Note: if the target size has a z-size of 0, the paths are projected into the xy-plane, same is true for the x-size, projects into the yz-plane and the y-size, projects into and xz-plane.
Example how to create an ellipse with a major axis length of 3, a minor axis length 1.5 and rotated about 90°:
m = elliptic_transformation(radius=3, ratio=0.5, rotation=math.pi / 2) ellipse = shapes.unit_circle(transform=m)
WARNING:
Argument count defines the count of star 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. The star shape starts with the first vertex is on the x-axis! The base geometry is created by function ezdxf.render.forms.star().
The arc spans from the start- to the end angle in counter-clockwise orientation. The end angle has to be greater than the start angle and the angle span has to be greater than 0.
The arc spans from the start- to the end angle in counter-clockwise orientation. The end angle has to be greater than the start angle and the angle span has to be greater than 0.
The text2path add-on provides additional functions to create paths from text strings and DXF text entities.
Does not yield any vertices for empty paths, where only a start point is present!
Approximation of Multi-Path objects is possible, but gaps are indistinguishable from line segments.
Does not yield any vertices for empty paths, where only a start point is present!
Flattening of Multi-Path objects is possible, but gaps are indistinguishable from line segments.
If the move_to() command is the first command, the start point of the path will be reset to location.
It’s safe to call sub_paths() on any path-type: Single-Path, Multi-Path and Empty-Path.
This module provide tools for the recursive decomposition of nested block reference structures into a flat stream of DXF entities and converting DXF entities into geometric primitives of Path and MeshBuilder objects encapsulated into intermediate Primitive classes.
WARNING:
Text boundary calculations are based on monospaced (fixed-pitch, fixed-width, non-proportional) font metrics, which do not provide a good accuracy for text height calculation and much less accuracy for text width calculation. It is possible to improve this results by using the font support from the optional Matplotlib package.
Install Matplotlib from command line:
C:\> pip3 install matplotlib
The Matplotlib font support will improve the results for TEXT, ATTRIB and ATTDEF. The MTEXT entity has many advanced features which would require a full “Rich Text Format” rendering and that is far beyond the goals and capabilities of this library, therefore the boundary box for MTEXT will never be as accurate as in a dedicated CAD application.
Using the Matplotlib font support adds runtime overhead, therefore it is possible to deactivate the Matplotlib font support by setting the global option:
options.use_matplotlib_font_support = False
Point entities will not be disassembled into DXF sub-entities, as defined by the current point style $PDMODE.
These entity types include sub-entities and will be decomposed into simple DXF entities:
Decomposition of XREF, UNDERLAY and ACAD_TABLE entities is not supported.
These functions disassemble DXF entities into simple geometric objects like meshes, paths or vertices. The Primitive is a simplified intermediate class to use a common interface on various DXF entities.
Returns an empty primitive for unsupported entities. The empty state of a primitive can be checked by the property is_empty. The path and the mesh attributes of an empty primitive are None and the vertices() method yields no vertices.
Reference to the source DXF entity of this primitive.
The max_flattening_distance attribute defines the max distance in drawing units between the approximation line and the original curve. Set the value by direct attribute access. (float) default = 0.01
if primitive.path is not None: process(primitive.path)
if primitive.mesh is not None: process(primitive.mesh)
The ezdxf.bbox module provide tools to calculate bounding boxes for many DXF entities, but not for all. The bounding box calculation is based on the ezdxf.disassemble module and therefore has the same limitation.
WARNING:
Unsupported DXF entities:
Unsupported entities are silently ignored, filtering of these DXF types is not necessary.
The base type for bounding boxes is the BoundingBox class from the module ezdxf.math.
The entities iterable as input can be the whole modelspace, an entity query or any iterable container of DXF entities.
The Calculation of bounding boxes of curves is done by flattening the curve by a default flattening distance of 0.01. Set argument flatten to 0 to speedup the bounding box calculation by accepting less precision for curved objects by using only the control vertices.
The optional caching object Cache has to be instantiated by the user, this is only useful if the same entities will be processed multiple times.
Example usage with caching:
from ezdxf import bbox msp = doc.modelspace() cache = bbox.Cache() # get overall bounding box first_bbox = bbox.extents(msp, cache=cache) # bounding box of all LINE entities second_bbox = bbox.extend(msp.query("LINE"), cache=cache)
If argument fast is True the calculation of Bézier curves is based on their control points, this may return a slightly larger bounding box.
If argument fast is True the calculation of Bézier curves is based on their control points, this may return a slightly larger bounding box.
If argument fast is True the calculation of Bézier curves is based on their control points, this may return a slightly larger bounding box.
Because ezdxf is not a CAD application, ezdxf does not manage data structures which are optimized for a usage by a CAD kernel. This means that the content of complex entities like block references or leaders has to be created on demand by DXF primitives on the fly. These temporarily created entities are called virtual entities and have no handle and are not stored in the entity database.
All this is required to calculate the bounding box of complex entities, and it is therefore a very time consuming task. By using a Cache object it is possible to speedup this calculations, but this is not a magically feature, it requires an understanding of what is happening under the hood to achieve any performance gains.
For a single bounding box calculation, without any reuse of entities it makes no sense of using a Cache object, e.g. calculation of the modelspace extents:
from pathlib import Path import ezdxf from ezdxf import bbox CADKitSamples = Path(ezdxf.EZDXF_TEST_FILES) / 'CADKitSamples' doc = ezdxf.readfile(CADKitSamples / 'A_000217.dxf') cache = bbox.Cache() ext = bbox.extents(doc.modelspace(), cache) print(cache)
1226 cached objects and not a single cache hit:
Cache(n=1226, hits=0, misses=3273)
The result for using UUIDs to cache virtual entities is not better:
Cache(n=2206, hits=0, misses=3273)
Same count of hits and misses, but now the cache also references ~1000 virtual entities, which block your memory until the cache is deleted, luckily this is a small DXF file (~838 kB).
Bounding box calculations for multiple entity queries, which have overlapping entity results, using a Cache object may speedup the calculation:
doc = ezdxf.readfile(CADKitSamples / 'A_000217.dxf.dxf') msp = doc.modelspace() cache = bbox.Cache(uuid=False) ext = bbox.extents(msp, cache) print(cache) # process modelspace again ext = bbox.extents(msp, cache) print(cache)
Processing the same data again leads some hits:
1st run: Cache(n=1226, hits=0, misses=3273) 2nd run: Cache(n=1226, hits=1224, misses=3309)
Using uuid=True leads not to more hits, but more cache entries:
1st run: Cache(n=2206, hits=0, misses=3273) 2nd run: Cache(n=2206, hits=1224, misses=3309)
Creating stable virtual entities by disassembling the entities at first leads to more hits:
from ezdxf import disassemble entities = list(disassemble.recursive_decompose(msp)) cache = bbox.Cache(uuid=False) bbox.extents(entities, cache) print(cache) bbox.extents(entities, cache) print(cache)
First without UUID for stable virtual entities:
1st run: Cache(n=1037, hits=0, misses=4074) 2nd run: Cache(n=1037, hits=1037, misses=6078)
Using UUID for stable virtual entities leads to more hits:
1st run: Cache(n=2019, hits=0, misses=4074) 2nd run: Cache(n=2019, hits=2018, misses=4116)
But caching virtual entities needs also more memory.
In conclusion: Using a cache is only useful, if you often process nearly the same data; only then can an increase in performance be expected.
If entities are changed by the user, it is possible to invalidate individual entities. Use with care - discarding the whole cache is the safer workflow.
Ignores entities which are not stored in cache.
The functions in this module can help to convert an inverted OCS defined by an extrusion vector (0, 0, -1) into a WCS aligned OCS defined by an extrusion vector (0, 0, 1).
This simplifies 2D entity processing for ezdxf users and creates DXF output for 3rd party DXF libraries which ignore the existence of the OCS.
Supported DXF entities:
WARNING:
The functions can be applied to any DXF entity without expecting errors or exceptions if the DXF entity is not supported or the extrusion vector differs from (0, 0, -1). This also means you can apply the functions multiple times to the same entities without any problems. A common case would be to upright all entities of the model space:
import ezdxf from ezdxf.upright import upright_all doc = ezdxf.readfile("your.dxf") msp = doc.modelspace() upright_all(msp) # doing it again is no problem but also has no further effects upright_all(msp)
Another use case is exploding block references (INSERT) which may include reflections (= scaling by negative factors) that can lead to inverted extrusion vectors.
for block_ref in msp.query("INSERT"): entities = block_ref.explode() # -> EntityQuery object upright_all(entities)
upright_all(doc.modelspace())
This example shows why the entities with an inverted OCS, extrusion vector is (0, 0, -1), are not exact the same as with an WCS aligned OCS, extrusion vector is (0, 0, 1).
NOTE:
import ezdxf from ezdxf.upright import upright from ezdxf.math import Matrix44 doc = ezdxf.new() msp = doc.modelspace() arc = msp.add_arc( (5, 0), radius=5, start_angle=-90, end_angle=90, dxfattribs={"color": ezdxf.const.RED}, ) # draw lines to the start- and end point of the ARC msp.add_line((0, 0), arc.start_point, dxfattribs={"color": ezdxf.const.GREEN}) msp.add_line((0, 0), arc.end_point, dxfattribs={"color": ezdxf.const.BLUE}) # copy arc mirrored_arc = arc.copy() msp.add_entity(mirrored_arc) # mirror copy mirrored_arc.transform(Matrix44.scale(-1, 1, 1)) # This creates an inverted extrusion vector: assert mirrored_arc.dxf.extrusion.isclose((0, 0, -1)) # draw lines to the start- and end point of the mirrored ARC msp.add_line((0, 0), mirrored_arc.start_point, dxfattribs={"color": ezdxf.const.GREEN}) msp.add_line((0, 0), mirrored_arc.end_point, dxfattribs={"color": ezdxf.const.BLUE})
Result without applying the upright() function - true mirroring: [image]
... # This creates an inverted extrusion vector: assert mirrored_arc.dxf.extrusion.isclose((0, 0, -1)) start_point_inv = mirrored_arc.start_point end_point_inv = mirrored_arc.end_point upright(mirrored_arc) # OCS is aligned with WCS: assert mirrored_arc.dxf.extrusion.isclose((0, 0, 1)) # start- and end points are swapped after applying upright() assert mirrored_arc.start_point.isclose(end_point_inv) assert mirrored_arc.end_point.isclose(start_point_inv) # draw lines to the start- and end point of the mirrored ARC msp.add_line((0, 0), mirrored_arc.start_point, dxfattribs={"color": ezdxf.const.GREEN}) msp.add_line((0, 0), mirrored_arc.end_point, dxfattribs={"color": ezdxf.const.BLUE})
Result after applying the upright() function - false mirroring: [image]
To avoid this issue the ARC entity would have to represent the curve in clockwise orientation around the extrusion vector (0, 0, 1), which is not possible!
NOTE:
Tools to reorder DXF entities by handle or a special sort handle mapping.
Such reorder mappings are stored only in layouts as Modelspace, Paperspace or BlockLayout, and can be retrieved by the method get_redraw_order().
Each entry in the handle mapping replaces the actual entity handle, where the “0” handle has a special meaning, this handle always shows up at last in ascending ordering.
The sort-handle doesn’t have to be the entity handle, every entity handle in mapping will be replaced by the given sort-handle, mapping is an iterable of 2-tuples (entity_handle, sort_handle) or a dict (entity_handle, sort_handle). Entities with equal sort-handles show up in source entities order.
The sort-handle doesn’t have to be the entity handle, every entity handle in mapping will be replaced by the given sort-handle, mapping is an iterable of 2-tuples (entity_handle, sort_handle) or a dict (entity_handle, sort_handle). Entities with equal sort-handles show up in reversed source entities order.
New in version 1.1.
This module provides functions to apply transformations to multiple DXF entities inplace or to virtual copies of that entities in a convenient and safe way:
import math import ezdxf from ezdxf import transform doc = ezdxf.readfile("my.dxf") msp = doc.modelspace() log = transform.inplace(msp, m=transform.Matrix44.rotate_z(math.pi/2)) # or more simple log = transform.z_rotate(msp, math.pi/2)
All functions handle errors by collecting them in an logging object without raising an error. The input entities are an iterable of DXFEntity, which can be any layout, EntityQuery or just a list/sequence of entities and virtual entities are supported as well.
inplace | Transforms the given entities inplace by the transformation matrix m, non-uniform scaling is supported. |
copies | Copy entities and transform them by matrix m. |
translate | Translates (moves) entities inplace by the offset vector. |
scale_uniform | Scales entities inplace by a factor in all axis. |
scale | Scales entities inplace by the factors sx in x-axis, sy in y-axis and sz in z-axis. |
x_rotate | Rotates entities inplace by angle in radians about the x-axis. |
y_rotate | Rotates entities inplace by angle in radians about the y-axis. |
z_rotate | Rotates entities inplace by angle in radians about the x-axis. |
axis_rotate | Rotates entities inplace by angle in radians about the rotation axis starting at the origin pointing in axis direction. |
IMPORTANT:
IMPORTANT:
These are links to tools in the ezdxf.math core module:
ezdxf.math.ConstructionRay | Construction tool for infinite 2D rays. |
ezdxf.math.ConstructionLine | Construction tool for 2D lines. |
ezdxf.math.ConstructionCircle | Construction tool for 2D circles. |
ezdxf.math.ConstructionArc | Construction tool for 2D arcs. |
ezdxf.math.ConstructionEllipse | Construction tool for 3D ellipsis. |
ezdxf.math.ConstructionBox | Construction tool for 2D rectangles. |
ezdxf.math.ConstructionPolyline | Construction tool for 3D polylines. |
ezdxf.math.Shape2d | Construction tools for 2D shapes. |
ezdxf.math.BSpline | B-spline construction tool. |
ezdxf.math.Bezier4P | Implements an optimized cubic Bézier curve for exact 4 control points. |
ezdxf.math.Bezier3P | Implements an optimized quadratic Bézier curve for exact 3 control points. |
ezdxf.math.Bezier | Generic Bézier curve of any degree. |
ezdxf.math.BezierSurface | BezierSurface defines a mesh of m x n control points. |
ezdxf.math.EulerSpiral | This class represents an euler spiral (clothoid) for curvature (Radius of curvature). |
The classes XDataUserList and XDataUserDict manage custom user data stored in the XDATA section of a DXF entity. For more information about XDATA see reference section: Extended Data (XDATA)
These classes store only a limited set of data types with fixed group codes and the types are checked by isinstance() so a Vec3 object can not be replaced by a (x, y, z)-tuple:
Group Code | Data Type |
1000 | str, limited to 255 characters, line breaks "\n" and "\r" are not allowed |
1010 | Vec3 |
1040 | float |
1071 | 32-bit int, restricted by the DXF standard not by Python! |
Strings are limited to 255 characters, line breaks "\n" and "\r" are not allowed.
This classes assume a certain XDATA structure and therefore can not manage arbitrary XDATA!
This classes do not create the required AppID table entry, only the default AppID “EZDXF” exist by default. Setup a new AppID in the AppID table: doc.appids.add("MYAPP").
For usage look at this example at github or go to the tutorial: Storing Custom Data in DXF Files.
SEE ALSO:
Recommended usage by context manager entity():
with XDataUserList.entity(entity, name="MyList", appid="MYAPP") as ul: ul.append("The value of PI") # str "\n" and "\r" are not allowed ul.append(3.141592) # float ul.append(1) # int ul.append(Vec3(1, 2, 3)) # Vec3 # invalid data type raises DXFTypeError ul.append((1, 2, 3)) # tuple instead of Vec3 # retrieve a single value s = ul[0] # store whole content into a Python list data = list(ul)
Implements the MutableSequence interface.
The data is stored in the given xdata object, or in a new created XData instance if None. Changes of the content has to be committed at the end to be stored in the underlying xdata object.
Recommended usage by context manager entity():
with XDataUserDict.entity(entity, name="MyDict", appid="MYAPP") as ud: ud["comment"] = "The value of PI" # str "\n" and "\r" are not allowed ud["pi"] = 3.141592 # float ud["number"] = 1 # int ud["vertex"] = Vec3(1, 2, 3) # Vec3 # invalid data type raises DXFTypeError ud["vertex"] = (1, 2, 3) # tuple instead of Vec3 # retrieve single values s = ud["comment"] pi = ud.get("pi", 3.141592) # store whole content into a Python dict data = dict(ud)
Implements the MutableMapping interface.
The data is stored in XDATA like a XDataUserList by (key, value) pairs, therefore a XDataUserDict can also be loaded as XDataUserList. It is not possible to distinguish a XDataUserDict from a XDataUserList except by the name of the data structure.
The data is stored in the given xdata object, or in a new created XData instance if None. Changes of the content has to be committed at the end to be stored in the underlying xdata object.
The UserRecord and BinaryRecord classes help to store custom data in DXF files in XRecord objects a simple and safe way. This way requires DXF version R2000 or later, for DXF version R12 the only way to store custom data is Extended Data (XDATA).
The UserRecord stores Python types and nested container types: int, float, str, Vec2, Vec3, list and dict.
Requirements for Python structures:
DXF Tag layout for Python types and structures stored in the XRecord object:
Only for the UserRecord the first tag is (2, user record name).
Type | DXF Tag(s) |
str | (1, value) string with less than 2050 chars and including no line breaks |
int | (90, value) int 32-bit, restricted by the DXF standard not by Python! |
float | (40, value) “C” double |
Vec2 | (10, x), (20, y) |
Vec3 | (10, x) (20, y) (30, z) |
list | starts with (2, “[”) and ends with (2, “]”) |
dict | starts with (2, “{”) and ends with (2, “}”) |
The BinaryRecord stores arbitrary binary data as BLOB.
Storage size limits of XRECORD according the DXF reference:
For usage look at this example at github or go to the tutorial: Storing Custom Data in DXF Files.
SEE ALSO:
Nested data structures are supported list or/and dict in list or dict. Dict keys have to be simple Python types: int, float, str.
The data is stored in the given xrecord object, or in a new created XRecord instance if None. If doc is not None the new xrecord is added to the OBJECTS section of the DXF document.
Changes of the content has to be committed at the end to be stored in the underlying xrecord object.
The data is stored in the given xrecord object, or in a new created XRecord instance if None. If doc is not None the new xrecord is added to the OBJECTS section of the DXF document.
Changes of the content has to be committed at the end to be stored in the underlying xrecord object.
The module ezdxf.fonts.fonts manages the internal usage of fonts and has no relation how the DXF formats manages text styles.
SEE ALSO:
New in version 1.1.
Since ezdxf v1.1 text rendering is done by the fontTools package. Support for stroke fonts, these are the basic vector fonts included in CAD applications, like .shx, .shp or .lff fonts was also added.
None of the required font files (.ttf, .ttc, .otf, .shx, .shp or .lff) are included in ezdxf as they are copyrighted or, in the case of the LibreCAD font format (.lff), licensed under the “GPL v2 and later”.
The font manager searches the following directories recursively for .ttf, .ttc and .otf font files.
The fc-list command on Linux shows all available fonts and their location.
The default font is selected in the following order, if none of them is available on your system - install one of them, the open source fonts can be found in the github repository in the folder ezdxf/fonts.
There is no universal way to find the basic stroke fonts of CAD applications on a system, beside scanning all drives. Set the paths to the stroke fonts in your config file manually to tell ezdxf where to search for them, all paths are search recursively, see also option ezdxf.options.support_dirs:
[core] support_dirs = "C:\Program Files\Bricsys\BricsCAD V23 en_US\Fonts", ~/shx_fonts, ~/shp_fonts, ~/lff_fonts,
The .shx fonts can be found on the internet but be aware that they are not free as all websites claim. The LibreCAD font files (.llf) can be downloaded from their github repository: https://github.com/LibreCAD/LibreCAD/tree/master/librecad/support/fonts
The fonts available on a system are cached automatically, the cache has to be rebuild to recognize new installed fonts by build_system_font_cache(). The cache is stored in the users home directory “~/.cache/ezdxf” or the directory specified by the environment variable “XDG_CACHE_HOME”.
When you add new fonts to your system or add a font directory to the support directories in the config file you have to rebuild the font-cache of ezdxf to recognize these new fonts:
import ezdxf from ezdxf.fonts import fonts fonts.build_system_font_cache()
or call the ezdxf launcher to do that:
ezdxf --fonts
Supported font types:
The special name “*monospace” returns the fallback font MonospaceFont for testing and basic measurements.
NOTE:
This function translates a DXF font definition by the TTF font file name into a FontFace object. Returns the FontFace of the default font when a font is not available on the current system.
Pass a DXF document as argument doc to resolve text styles for virtual entities which are not assigned to a DXF document. The argument doc always overrides the DXF document to which the entity is assigned to.
WARNING:
This font exists only for generic text measurement in tests and does not render any glyphs!
DXF to store fonts in the Textstyle entity as TTF file name e.g. “LiberationSans-Regular.ttf”.
The FontFace class can be used to specify a font in a more generic way:
1 | UltraCondensed |
2 | ExtraCondensed |
3 | Condensed |
4 | SemiCondensed |
5 | Normal or Medium |
6 | SemiExpanded |
7 | Expanded |
8 | ExtraExpanded |
9 | UltraExpanded |
100 | Thin |
200 | ExtraLight |
300 | Light |
400 | Normal |
500 | Medium |
600 | SemiBold |
700 | Bold |
800 | ExtraBold |
900 | Black |
SEE ALSO:
The DXF format uses a special form of unicode encoding: “\U+xxxx”.
To avoid a speed penalty such encoded characters are not decoded automatically by the regular loading function:func:ezdxf.readfile, only the recover module does the decoding automatically, because this loading mode is already slow.
This kind of encoding is most likely used only in older DXF versions, because since DXF R2007 the whole DXF file is encoded in utf8 and a special unicode encoding is not necessary.
The ezdxf.has_dxf_unicode() and ezdxf.decode_dxf_unicode() are new support functions to decode unicode characters “\U+xxxx” manually.
Some handy tool functions used internally by ezdxf.
This function creates a GUID for the header variables $VERSIONGUID and $FINGERPRINTGUID, which matches the AutoCAD pattern {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}.
The ezdxf.gfxattribs module provides the GfxAttribs class to create valid attribute dictionaries for the most often used DXF attributes supported by all graphical DXF entities. The advantage of using this class is auto-completion support by IDEs and an instant validation of the attribute values.
import ezdxf from ezdxf.gfxattribs import GfxAttribs doc = ezdxf.new() msp = doc.modelspace() attribs = GfxAttribs(layer="MyLayer", color=ezdxf.colors.RED) line = msp.add_line((0, 0), (1, 0), dxfattribs=attribs) circle = msp.add_circle((0, 0), radius=1.0, dxfattribs=attribs) # Update DXF attributes of existing entities: attribs = GfxAttribs(layer="MyLayer2", color=ezdxf.colors.BLUE) # Convert GfxAttribs() to dict(), but this method cannot reset # attributes to the default values like setting layer to "0". line.update_dxf_attribs(dict(attribs)) # Using GfxAttribs.asdict(default_values=True), can reset attributes to the # default values like setting layer to "0", except for true_color and # transparency, which do not have default values, their absence is the # default value. circle.update_dxf_attribs(attribs.asdict(default_values=True)) # Remove true_color and transparency by assigning None attribs.transparency = None # reset to transparency by layer! attribs.rgb = None
Validation features:
There is no default true color value and the default transparency is not stored in the HEADER section.
Loads following header variables:
Writes following header variables:
Supported attributes are:
All text building methods return self to implement a floating interface:
e = MTextEditor("This example ").color("red").append("switches color to red.") mtext = msp.add_mtext(str(e))
The initial text height, color, text style and so on is determined by the DXF attributes of the MText entity.
WARNING:
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!
e = MTextEditor("First paragraph.\P") e += "Second paragraph.\P")
"^": vertical stacked without divider line, e.g. \SA^ B: A B "/": vertical stacked with divider line, e.g. \SX/Y: X - Y "#": diagonal stacked, with slanting divider line, e.g. \S1#4: 1/4
Useful UTF bullets:
For numbered lists just use numbers as bullets:
MTextEditor.bullet_list( indent=2, bullets=["1.", "2."], content=["first", "second"], )
Constants stored in the MTextEditor class:
NEW_LINE | '\P' |
NEW_PARAGRAPH | '\P' |
NEW_COLUMN | '\N |
UNDERLINE_START | '\L' |
UNDERLINE_STOP | '\l' |
OVERSTRIKE_START | '\O' |
OVERSTRIKE_STOP | '\o' |
STRIKE_START | '\K' |
STRIKE_STOP | '\k' |
ALIGN_BOTTOM | '\A0;' |
ALIGN_MIDDLE | '\A1;' |
ALIGN_TOP | '\A2;' |
NBSP | '\~' |
TAB | '^I' |
see: https://en.wikipedia.org/wiki/Caret_notation
This function is faster than the mtext_size() function, but the result is very inaccurate if inline codes are used or line wrapping at the column border is involved!
This function is more than 4x faster than plain_mtext(), but does not remove single letter inline commands with arguments without a terminating semicolon like this "\C1red text".
NOTE:
This function is much slower than fast_plain_mtext(), but removes all inline codes.
See the text2path add-on for more tools to work with the text path objects created by the Matplotlib package.
This function uses the optional Matplotlib package if available to do font measurements and the internal text layout engine to determine the final rendering size for the MText entity as close as possible. Without access to the Matplotlib package the MonospaceFont is used and the measurements are very inaccurate.
Attention: The required full layout calculation is slow!
The first call to this function with Matplotlib support is very slow, because Matplotlib lookup all available fonts on the system. To speedup the calculation and accepting inaccurate results you can disable the Matplotlib support manually:
ezdxf.option.use_matplotlib = False
This function is faster than the mtext_size() function, but the result is very inaccurate if inline codes are used or line wrapping at the column border is involved!
The ezdxf.acis sub-package provides some ACIS data management tools. The main goals of this tools are:
It is NOT a goal to load and edit arbitrary existing ACIS structures.
These tools cannot replace the official ACIS SDK due to the complexity of the data structures and the absence of an ACIS kernel. Without access to the full documentation it is very cumbersome to reverse-engineer entities and their properties, therefore the analysis of the ACIS data structures is limited to the use as embedded data in DXF and DWG files.
The ezdxf library does not provide an ACIS kernel and there are no plans for implementing one because this is far beyond my capabilities, but it is possible to extract geometries made up only by flat polygonal faces (polyhedron) from ACIS data. Exporting polyhedrons as ACIS data and loading this DXF file by Autodesk products or BricsCAD works for SAT data for DXF R2000-R2010 and for SAB data for DXF R2013-R2018.
IMPORTANT:
The DXF entity has to be an ACIS based entity and inherit from ezdxf.entities.Body. The entity has to be bound to a valid DXF document and the DXF version of the document has to be DXF R2000 or newer.
WARNING:
To emphasize that again: It is not possible to load and re-export arbitrary ACIS data!
Example:
import ezdxf from ezdxf.acis import api as acis doc = ezdxf.readfile("your.dxf") msp = doc.modelspace() for e in msp.query("3DSOLID"): bodies = acis.load_dxf(e) ...
The DXF entity has to be an ACIS based entity and inherit from ezdxf.entities.Body. The entity has to be bound to a valid DXF document and the DXF version of the document has to be DXF R2000 or newer.
Example:
import ezdxf from ezdxf.render import forms from ezdxf.acis import api as acis doc = ezdxf.new("R2000") msp = doc.modelspace() # create an ACIS body from a simple cube-mesh body = acis.body_from_mesh(forms.cube()) solid3d = msp.add_3dsolid() acis.export_dxf(solid3d, [body]) doc.saveas("cube.dxf")
ACIS version 700 is sufficient for DXF versions R2000, R2004, R2007 and R2010, later DXF versions require SAB data.
ACIS version 21800 is sufficient for DXF versions R2013 and R2018, earlier DXF versions require SAT data.
The ACIS format stores the faces in counter-clockwise orientation where the face-normal points outwards (away) from the solid body (material).
NOTE:
The following images show the limitations of the mesh_from_body() function. The first image shows the source 3DSOLID entities with subtraction of entities with flat and curved faces: [image]
Example script to extracts all flat polygonal faces as meshes:
import ezdxf from ezdxf.acis import api as acis doc = ezdxf.readfile("3dsolids.dxf") msp = doc.modelspace() doc_out = ezdxf.new() msp_out = doc_out.modelspace() for e in msp.query("3DSOLID"): for body in acis.load_dxf(data): for mesh in acis.mesh_from_body(body): mesh.render_mesh(msp_out) doc_out.saveas("meshes.dxf")
The second image shows the flat faces extracted from the 3DSOLID entities and exported as Mesh entities: [image]
As you can see all faces which do not have straight lines as boundaries are lost.
This entity can be assigned to a Solid3d DXF entity as SAT or SAB data according to the version your DXF document uses (SAT for DXF R2000 to R2010 and SAB for DXF R2013 and later).
If the mesh contains multiple separated meshes, each mesh will be a separated Lump node. If each mesh should get its own Body entity, separate the meshes beforehand by the method separate_meshes.
A closed mesh creates a solid body and an open mesh creates an open (hollow) shell. The detection if the mesh is open or closed is based on the edges of the mesh: if all edges of mesh have two adjacent faces the mesh is closed.
The current implementation applies automatically a vertex optimization, which merges coincident vertices into a single vertex.
A document (sat.pdf) about the basic ACIS 7.0 file format is floating in the internet.
This section contains the additional information about the entities, I got from analyzing the SAT data extracted from DXF files exported by BricsCAD.
This documentation ignores the differences to the ACIS format prior to version 7.0 and all this differences are handled internally.
Writing support for ACIS version < 7.0 is not required because all CAD applications should be able to process version 7.0, even if embedded in a very old DXF R2000 format (tested with Autodesk TrueView, BricsCAD and Nemetschek Allplan).
The first goal is to document the entities which are required to represent a geometry as flat polygonal faces (polyhedron), which can be converted into a MeshBuilder object.
Topology Entities:
Geometry Entities:
if entity.is_none: ...
The partner_coedge attribute references the first partner Coedge of an adjacent Face, the partner edges are organized as a circular list. In a manifold closed surface each Face is connected to one partner face by an Coedge. In a non-manifold surface a face can have more than one partner face.
The parameterization of any Surface maps a 2D rectangle (u, v parameters) into the spatial object-space (x, y, z).
The parameterization of any Curve maps a 1D line (the parameter) into the spatial object-space (x, y, z).
The global ezdxf options are stored in the object ezdxf.options.
Recommended usage of the global options object:
import ezdxf value = ezdxf.options.attribute
The options object uses the Standard Python class ConfigParser to manage the configuration. Shortcut attributes like test_files are simple properties and most shortcuts are read only marked by (Read only), read and writeable attributes are marked by (Read/Write).
To change options, especially the read only attributes, you have to edit the config file with a text editor, or set options by the set() method and write the current configuration into a config file.
The default config files are loaded from the user home directory as “~/.config/ezdxf/ezdxf.ini”, and the current working directory as “./ezdxf.ini”. A custom config file can be specified by the environment variable EZDXF_CONFIG_FILE. Ezdxf follows the XDG Base Directory specification if the environment variable XDG_CONFIG_HOME is set.
The config file loading order:
A configuration file that is loaded later does not replace the previously loaded ones, only the existing options in the newly loaded file are added to the configuration and can overwrite existing options.
Configuration files are regular INI files, managed by the standard Python ConfigParser class.
File Structure:
[core] default_dimension_text_style = OpenSansCondensed-Light test_files = D:\Source\dxftest support_dirs = "C:\Program Files\Bricsys\BricsCAD V23 en_US\Fonts", "~/dir2", "~/dir3", 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}
This code shows how to get and set values of the underlying ConfigParser object, but use the shortcut attributes if available:
# Set options, value has to ba a str, use "true"/"false" for boolean values ezdxf.options.set(section, key, value) # Get option as string value = ezdxf.options.get(section, key, default="") # Special getter for boolean, int and float value = ezdxf.options.get_bool(section, key, default=False) value = ezdxf.options.get_int(section, key, default=0) value = ezdxf.options.get_float(section, key, default=0.0)
If you set options, they are not stored automatically in a config file, you have to write back the config file manually:
# write back the default user config file "ezdxf.ini" in the # user home directory ezdxf.options.write_home_config() # write back to the default config file "ezdxf.ini" in the # current working directory ezdxf.options.write_file() # write back to a specific config file ezdxf.options.write_file("my_config.ini") # which has to be loaded manually at startup ezdxf.options.read_file("my_config.ini")
This example shows how to change the test_files path and save the changes into a custom config file “my_config.ini”:
import ezdxf test_files = Path("~/my-dxf-test-files").expand_user() ezdxf.options.set( ezdxf.options.CORE, # section "test_files", # key "~/my-dxf-test-files", # value ) ezdxf.options.write_file("my_config.ini")
You can specify a config file by the environment variable EZDXF_CONFIG_FILE, which is loaded after the default config files.
C:\> set EZDXF_CONFIG_FILE=D:\user\path\custom.ini
Custom config files are not loaded automatically like the default config files.
This example shows how to load the previous created custom config file “my_config.ini” from the current working directory:
import ezdxf ezdxf.options.read("my_config.ini")
That is all and because this is the last loaded config file, it overrides all default config files and the config file specified by EZDXF_CONFIG_FILE.
For all core options the section name is core.
The default dimension text style is used by the DIMENSION renderer of ezdxf, if the specified text style exist in the STYLE table. To use any of the default style of ezdxf you have to setup the styles at the creation of the DXF document: ezdxf.new(setup=True), or setup the ezdxf default styles for a loaded DXF document:
import ezdxf from ezdxf.tool.standard import setup_drawing doc = ezdxf.readfile("your.dxf") setup_drawing(doc)
Config file key: default_dimension_text_style
Shortcut attribute:
Proxy graphics are not essential for DXF files, but they can provide a simple graphical representation for complex entities, but extra memory is needed to store this information. You can save some memory by not loading the proxy graphic, but the proxy graphic is lost if you write back the DXF file.
The current version of ezdxf uses this proxy graphic to render MLEADER entities by the drawing add-on.
Config file key: load_proxy_graphics
Shortcut attribute:
Prevent exporting proxy graphics if set to False.
Config file key: store_proxy_graphics
Shortcut attribute:
Search directories for support files:
Config file key: support_dirs
Shortcut attribute:
Use quotes for paths including spaces:
[core] support_dirs = ~/dir1, ~/dir2, "~/dir 3",
For all debugging options the section name is core.
Path to test files. Some of the CADKit test files are used by the integration tests, these files should be located in the ezdxf.options.test_files_path / "CADKitSamples" folder.
Config file key: test_files
Shortcut attributes:
Only a very limited set of group codes is valid in the XDATA section and AutoCAD is very picky about that. Ezdxf removes invalid XDATA group codes if this option is set to True, but this needs processing time, which is wasted if you get your DXF files from trusted sources like AutoCAD or BricsCAD.
Config file key: filter_invalid_xdata_group_codes
Logs unprocessed DXF tags, this helps to find new and undocumented DXF features.
Config file key: log_unprocessed_tags
Write the DXF files with fixed meta data to test your DXF files by a diff-like command, this is necessary to get always the same meta data like the saving time stored in the HEADER section. This may not work across different ezdxf versions!
Config file key: write_fixed_meta_data_for_testing
It is possible to deactivate the optional C-extensions if there are any issues with the C-extensions. This has to be done in a default config file or by environment variable before the first import of ezdxf. For pypy3 the C-extensions are always disabled, because the JIT compiled Python code is much faster.
IMPORTANT:
Config file key: disable_c_ext
Some feature can be controlled by environment variables. Command line example for disabling the optional C-extensions on Windows:
C:\> set EZDXF_DISABLE_C_EXT=1
IMPORTANT:
These functions mimic the ZOOM commands in CAD applications.
Zooming means resetting the current viewport limits to new values. The coordinates for the functions center() and window() are drawing units for the model space and paper space units for paper space layouts. The modelspace units in Drawing.units are ignored.
The extents detection for the functions entities() and extents() is done by the ezdxf.bbox module. Read the associated documentation to understand the limitations of the ezdxf.bbox module. Tl;dr The extents detection is slow and not accurate.
Because the ZOOM operations in CAD applications are not that precise, then zoom functions of this module uses the fast bounding box calculation mode of the bbox module, which means the argument flatten is always False for extents() function calls.
The region displayed by CAD applications also depends on the aspect ratio of the application window, which is not available to ezdxf, therefore the viewport size is just an educated guess of an aspect ratio of 2:1 (16:9 minus top toolbars and the bottom status bar).
WARNING:
Example to reset the main CAD viewport of the model space to the extents of its entities:
import ezdxf from ezdxf import zoom doc = ezdxf.new() msp = doc.modelspace() ... # add your DXF entities zoom.extents(msp) doc.saveas("your.dxf")
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:
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 print the DXF text content as HTML file and open the file in the default web browser:
C:\> ezdxf pp -o gear.dxf
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 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"
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 the DXF file “gear.dxf” by the PyQt backend:
C:\> ezdxf view gear.dxf
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 the internal structure of a DXF file like a file system:
C:\> ezdxf browse gear.dxf
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.
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.
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.
The browser automatically displays a dialog for reloading DXF files if they have been modified by an external application.
Show and export the SAT or SAB content of ACIS entities:
C:\> ezdxf browse-acis 3dsolid.dxf
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.
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'
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
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'
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 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:
New in version 1.1.
The hpgl command shows and/or converts HPGL/2 plot files to DXF, SVG or PDF.
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.
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.
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.
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.
The ezdxf.render subpackage provides helpful utilities to create complex forms.
Content
SEE ALSO:
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.
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:
This is a parametric curve, which always starts at the origin (0, 0).
Random path generators for testing purpose.
2D Forms
3D Forms
3D Form Builder
WARNING:
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.
The command string "10 l 10 l 10" returns the 4 corner vertices of a square with a side length of 10 drawing units.
Create 3D forms as MeshTransformer objects.
Returns: MeshTransformer
Returns: MeshTransformer
Returns: MeshTransformer
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.
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.
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.
A mesh can be a MeshBuilder, MeshVertexMerger or Mesh object or requires the attributes vertices and faces.
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).
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.
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!
The fast mode uses a shortcut for faces with less than 6 vertices which may not work for concave faces!
It is possible to pass in an existing FaceOrientationDetector instance as argument fod.
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.
Same functionality as MeshBuilder but supports inplace transformation.
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)
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.
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.
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.
NOTE:
Create an instance of this tool by the MeshBuilder.diagnose() method.
This number is always 2 for convex polyhedra.
Returns False for non-manifold meshes.
A non-manifold mesh has edges with 3 or more connected faces.
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:
WARNING:
The result is not correct for multiple separated meshes in a single MeshBuilder object!!!
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.
Returns False for non-manifold meshes.
The forward and backward orientation has to be defined by a reference face.
This module provides tools to create banded lines like LWPOLYLINE with width information. Path rendering as quadrilaterals: Trace, Solid or Face3d.
NOTE:
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:
Accepts 3D input, but z-axis is ignored.
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.
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.
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.
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.
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.
Helper function to render Point entities as DXF primitives.
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.
SEE ALSO:
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:
The usual steps of the building process are:
The Tutorial for MultiLeader shows how to use these helper classes in more detail.
NOTE:
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.
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.
Specialization of MultiLeaderBuilder to build MultiLeader with MTEXT content.
Specialization of MultiLeaderBuilder to build MultiLeader with BLOCK content.
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.
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
This module provides rendering support for hatch patterns as used in Hatch and MPolygon entities.
The function yields nothing if polygon has a solid- or gradient filling or does not have a usable pattern assigned.
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.
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.
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.
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.
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:
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.
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')
The PyQtBackend is used by the View command of the ezdxf launcher.
SEE ALSO:
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.
The class implements the BackendInterface but does not record enter_entity(), exit_entity() and clear() events.
safe_player = recorder.player().copy()
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.
The content of the Data field is determined by the enum RecordType:
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:
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).
New in version 1.1.
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))
New in version 1.1.
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
png | Portable Network Graphics |
ppm | Portable Pixmap (no alpha channel) |
pbm | Portable Bitmap (no alpha channel) |
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"])
New in version 1.1.
The plot files are tested by the plot file viewer ViewCompanion Standard but not on real hardware - please use with care and give feedback.
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
New in version 1.1.
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")
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)
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 |
0 | use imperial units (in, ft, yd, ...) |
1 | use metric units (ISO meters) |
None | use the $MEASUREMENT value from the dxf document header |
NOTE:
This can not prevent drawing proxy graphic inside of blocks, because this is beyond the domain of the drawing add-on!
Required color format "#RRGGBB" or including alpha transparency "#RRGGBBAA".
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.
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.
The RenderContext class can be used isolated from the drawing add-on to resolve DXF 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.
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.
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.
For more information read the source code: backend.py
For more information read the source code: backend.py
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:
SEE ALSO:
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:
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:
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.
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:
WARNING:
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.
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.
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.
Yields only “Point”, “LineString”, “Polygon”, “MultiPoint”, “MultiLineString” and “MultiPolygon” objects, returns the content of “GeometryCollection”, “FeatureCollection” and “Feature” as geometry objects (“Point”, …).
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).
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.
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.
SEE ALSO:
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
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:
The Importer supports following data import:
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')
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)
Returns: (renamed) BLOCK name
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.
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.
Returns: new created target paperspace Layout
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')
Requires the installed Black formatter:
pip3 install black
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.
Use this function to split up big DXF files as shown in the example above.
specify decoding error handler
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.
specify decoding error handler
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.
specify decoding error handler
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.
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.
Use an installed ODA File Converter for converting between different versions of .dwg, .dxb and .dxf.
WARNING:
To avoid this problem delete the ezdxf.addons.odafc.py module.
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.
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:
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.
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 |
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”.
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')
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.
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")
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.
import ezdxf from ezdxf.addons import r12export doc = ezdxf.readfile("any.dxf") r12export.saveas(doc, "r12.dxf")
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.
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")
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. |
Writes the DXF document into a temporary file at the file-system and reloads this file by the ezdxf.readfile() function.
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:
If using FIXED-TABLES, following predefined text styles are available:
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')
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.
bit coded flag to define the invisible edges,
Add edge values to set multiple edges invisible, 1. edge + 3. edge = 1 + 4 = 5, all edges = 15
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) |
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
See example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py
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.
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.
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:
A font face is defined by the Matplotlib compatible FontFace object by font-family, font-style, font-stretch and font-weight.
SEE ALSO:
IMPORTANT:
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 |
Returns the virtual DXF entities as an EntityQuery object.
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.
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:
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:
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.
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")
New in version 1.1.
The hpgl2 add-on provides tools to process and convert 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.
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 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")
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. |
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.
Returns: DXF document as instance of class Drawing
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.
Returns: SVG content as str
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/
Returns: PDF content as bytes
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/
Returns: image content as bytes
IMPORTANT:
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)
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 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”:
The Plotter device does not support font rendering and page rotation (RO). The scaling commands IP, RP, SC are supported.
All input coordinates are page coordinates:
safe_player = recorder.player().copy()
The content of the Data field is determined by the enum RecordType:
This also changes the plot order in the way that all filled paths are plotted before polylines and outline paths.
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')
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:
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})
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:
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'})
New 3D solids are created from MeshBuilder objects and results can be exported as MeshTransformer objects to ezdxf by method mesh().
A.union(B) +-------+ +-------+ | | | | | A | | | | +--+----+ = | +----+ +----+--+ | +----+ | | B | | | | | | | +-------+ +-------+
union = A + B
A.subtract(B) +-------+ +-------+ | | | | | A | | | | +--+----+ = | +--+ +----+--+ | +----+ | B | | | +-------+
difference = A - B
A.intersect(B) +-------+ | | | A | | +--+----+ = +--+ +----+--+ | +--+ | B | | | +-------+
intersection = A * B
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:
Color dependent plot style table (CTB file), table entries are PlotStyle objects.
Named plot style table (STB file), table entries are PlotStyle objects.
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.
Dithering is available only whether you select the object’s color or assign a plot style color.
# | [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 |
[image]
END_STYLE_BUTT | 0 |
END_STYLE_SQUARE | 1 |
END_STYLE_ROUND | 2 |
END_STYLE_DIAMOND | 3 |
END_STYLE_OBJECT | 4 |
[image]
JOIN_STYLE_MITER | 0 |
JOIN_STYLE_BEVEL | 1 |
JOIN_STYLE_ROUND | 2 |
JOIN_STYLE_DIAMOND | 3 |
JOIN_STYLE_OBJECT | 5 |
[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 |
[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 |
Build a 3D Menger sponge.
0 | Original Menger Sponge |
1 | Variant XOX |
2 | Variant OXO |
3 | Jerusalem Cube |
Menger Sponge kind=0: [image]
Menger Sponge kind=1: [image]
Menger Sponge kind=2: [image]
Jerusalem Cube kind=3: [image]
Build a 3D Sierpinsky Pyramid.
Sierpinsky Pyramid with triangle base: [image]
Sierpinsky Pyramid with square base: [image]
This add-on is based on the 3D bin packing module py3dbp hosted on PyPI. Both sources of this package are MIT licensed like ezdxf itself.
Quote from the Wikipedia article:
This code replicates the example used by the py3dbp package:
from typing import List import ezdxf from ezdxf import colors from ezdxf.addons import binpacking as bp SMALL_ENVELOPE = ("small-envelope", 11.5, 6.125, 0.25, 10) LARGE_ENVELOPE = ("large-envelope", 15.0, 12.0, 0.75, 15) SMALL_BOX = ("small-box", 8.625, 5.375, 1.625, 70.0) MEDIUM_BOX = ("medium-box", 11.0, 8.5, 5.5, 70.0) MEDIUM_BOX2 = ("medium-box-2", 13.625, 11.875, 3.375, 70.0) LARGE_BOX = ("large-box", 12.0, 12.0, 5.5, 70.0) LARGE_BOX2 = ("large-box-2", 23.6875, 11.75, 3.0, 70.0) ALL_BINS = [ SMALL_ENVELOPE, LARGE_ENVELOPE, SMALL_BOX, MEDIUM_BOX, MEDIUM_BOX2, LARGE_BOX, LARGE_BOX2, ] def build_packer(): packer = bp.Packer() packer.add_item("50g [powder 1]", 3.9370, 1.9685, 1.9685, 1) packer.add_item("50g [powder 2]", 3.9370, 1.9685, 1.9685, 2) packer.add_item("50g [powder 3]", 3.9370, 1.9685, 1.9685, 3) packer.add_item("250g [powder 4]", 7.8740, 3.9370, 1.9685, 4) packer.add_item("250g [powder 5]", 7.8740, 3.9370, 1.9685, 5) packer.add_item("250g [powder 6]", 7.8740, 3.9370, 1.9685, 6) packer.add_item("250g [powder 7]", 7.8740, 3.9370, 1.9685, 7) packer.add_item("250g [powder 8]", 7.8740, 3.9370, 1.9685, 8) packer.add_item("250g [powder 9]", 7.8740, 3.9370, 1.9685, 9) return packer def make_doc(): doc = ezdxf.new() doc.layers.add("FRAME", color=colors.YELLOW) doc.layers.add("ITEMS") doc.layers.add("TEXT") return doc def main(filename): bins: List[bp.Bin] = [] for box in ALL_BINS: packer = build_packer() packer.add_bin(*box) packer.pack(bp.PickStrategy.BIGGER_FIRST) bins.extend(packer.bins) doc = make_doc() bp.export_dxf(doc.modelspace(), bins, offset=(0, 20, 0)) doc.saveas(filename) if __name__ == "__main__": main("py3dbp_example.dxf")
SEE ALSO:
The ezdxf.addons.meshex module provides functions to exchange meshes with other tools in the following file formats:
The source or target object is always a MeshBuilder instance and therefore the supported features are also limited by this class. Only vertices and faces are exchanged, colors, textures and explicit face- and vertex normals are lost.
NOTE:
WARNING:
Example for a simple STL to DXF converter:
import sys import ezdxf from ezdxf.addons import meshex try: mesh = meshex.stl_readfile("your.stl") except (meshex.ParsingError, IOError) as e: print(str(e)) sys.exit(1) doc = ezdxf.new() mesh.render_mesh(doc.modelspace()) doc.saveas("your.dxf")
SEE ALSO:
This function does not check if the mesh obey the STL format rules:
For more information see function: stl_dumps()
IMPORTANT:
WARNING:
The exported IFC4 data can be imported by the following applications:
Interface to the OpenSCAD application to apply boolean operations to MeshBuilder objects. For more information about boolean operations read the documentation of OpenSCAD. The OpenSCAD application is not bundled with ezdxf, you need to install the application yourself.
On Windows the path to the openscad.exe executable is stored in the config file (see ezdxf.options) in the “openscad-addon” section as key “win_exec_path”, the default entry is:
[openscad-addon] win_exec_path = "C:\Program Files\OpenSCAD\openscad.exe"
On Linux and macOS the openscad command is located by the shutil.which() function.
Example:
import ezdxf from ezdxf.render import forms from ezdxf.addons import MengerSponge, openscad doc = ezdxf.new() msp = doc.modelspace() # 1. create the meshes: sponge = MengerSponge(level=3).mesh() sponge.flip_normals() # important for OpenSCAD sphere = forms.sphere( count=32, stacks=16, radius=0.5, quads=True ).translate(0.25, 0.25, 1) sphere.flip_normals() # important for OpenSCAD # 2. create the script: script = openscad.boolean_operation(openscad.DIFFERENCE, sponge, sphere) # 3. execute the script by OpenSCAD: result = openscad.run(script) # 4. render the MESH entity: result.render_mesh(msp) doc.set_modelspace_vport(6, center=(5, 0)) doc.saveas("OpenSCAD.dxf")
The supported operations are:
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#mirror
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#multmatrix
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Primitive_Solids#polyhedron
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Using_the_2D_Subsystem#polygon
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#resize
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#rotate
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#rotate
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#scale
OpenSCAD docs: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#translate
This add-on is not a complete wrapper around OpenSCAD, if you need such a tool look at the openpyscad or pysolid packages at PyPI.
Not sure if the openpyscad package is still maintained, the last commit at github is more than a year old and did not pass the CI process! (state June 2022)
This code snippet shows how to get the MeshTransformer object from the basic openpyscad example:
from ezdxf.addons import openscad import openpyscad as ops c1 = ops.Cube([10, 20, 10]) c2 = ops.Cube([20, 10, 10]) # dump OpenSCAD script as string: script = (c1 + c2).dumps() # execute script and load the result as MeshTransformer instance: mesh = openscad.run(script)
Create an openpyscad Polyhedron object from an ezdxf MeshBuilder object:
from ezdxf.render import forms import openpyscad as ops # create an ezdxf MeshBuilder() object sphere = forms.sphere() sphere.flip_normals() # required for OpenSCAD # create an openpyscad Polyhedron() object polyhedron = ops.Polyhedron( points=[list(p) for p in sphere.vertices], # convert Vec3 objects to lists! faces=[list(f) for f in sphere.faces], # convert face tuples to face lists! ) # create the OpenSCAD script: script = polyhedron.dumps()
The type conversion is needed to get valid OpenSCAD code from openpyscad!
The pysolid package seems to be better maintained than the openpyscad package, but this is just an opinion based on newer commits at github (link) for the pysolid package.
Same example for pysolid:
from ezdxf.addons import openscad from solid import cube, render_scad c1 = cube([10, 20, 10]) c2 = cube([20, 10, 10]) # dump OpenSCAD script as string: script = render_scad(c1 + c2) # execute script and load the result as MeshTransformer instance: mesh = openscad.run(script)
Create a pysolid polyhedron object from an ezdxf MeshBuilder object:
from ezdxf.render import forms from solid import polyhedron, scad_render # create an ezdxf MeshBuilder() object sphere = forms.sphere() sphere.flip_normals() # required for OpenSCAD # create a pysolid polyhedron() object ph = polyhedron( points=[v.xyz for v in sphere.vertices], # convert Vec3 objects to tuples! faces=sphere.faces, # types are compatible ) # create the OpenSCAD script: script = scad_render(ph)
This is an add-on for drawing tables build from DXF primitives.
This add-on was created for porting dxfwrite projects to ezdxf and was not officially documented for ezdxf versions prior the 1.0 release. For the 1.0 version of ezdxf, this class was added as an officially documented add-on because full support for the ACAD_TABLE entity is very unlikely due to the enormous complexity for both the entity itself, and for the required infrastructure and also the lack of a usable documentation to implement all that features.
IMPORTANT:
The table cells can contain multi-line text or BLOCK references. You can create your own cell types by extending the CustomCell class. The cells are addressed by zero-based row and column indices. A table cell can span over multiple columns and/or rows.
A TextCell can contain multi-line text with an arbitrary rotation angle or letters stacked from top to bottom. The MTextSurrogate add-on is used to create multi-line text compatible to DXF version R12.
A BlockCell contains block references (INSERT entities), if the block definition contains attribute definitions as ATTDEF entities, these attributes can be added automatically to the block reference as ATTRIB entities.
NOTE:
Set up a new DXF document:
import ezdxf from ezdxf.enums import MTextEntityAlignment from ezdxf.addons import TablePainter doc = ezdxf.new("R2000") # required for lineweight support doc.header["$LWDISPLAY"] = 1 # show lineweights doc.styles.add("HEAD", font="OpenSans-ExtraBold.ttf") doc.styles.add("CELL", font="OpenSans-Regular.ttf")
Create a new TablePainter object with four rows and four columns, the insert location is the default render location but can be overriden in the render() method:
table = TablePainter( insert=(0, 0), nrows=4, ncols=4, cell_width=6.0, cell_height=2.0 )
Create a new CellStyle object for the table-header called “head”:
table.new_cell_style( "head", text_style="HEAD", text_color=ezdxf.colors.BLUE, char_height=0.7, bg_color=ezdxf.colors.LIGHT_GRAY, align=MTextEntityAlignment.MIDDLE_CENTER, )
Redefine the default CellStyle for the content cells:
# reset default cell style default_style = table.get_cell_style("default") default_style.text_style = "CELL" default_style.char_height = 0.5 default_style.align = MTextEntityAlignment.BOTTOM_LEFT
Set the table-header content:
for col in range(4): table.text_cell(0, col, f"Head[{col}]", style="head")
Set the cell content:
for row in range(1, 4): for col in range(4): # cell style is "default" table.text_cell(row, col, f"Cell[{row}, {col}]")
Add a red frame around the table-header:
# new cell style is required red_frame = table.new_cell_style("red-frame") red_borderline = table.new_border_style(color=ezdxf.colors.RED, lineweight=35) # set the red borderline style for all cell borders red_frame.set_border_style(red_borderline) # create the frame object table.frame(0, 0, 4, style="red-frame")
Render the table into the modelspace and export the DXF file:
# render the table, shifting the left-bottom of the table to the origin: table.render(doc.modelspace(), insert=(0, table.table_height)) th = table.table_height tw = table.table_width doc.set_modelspace_vport(height=th * 1.5, center=(tw/2, th/2)) doc.saveas("table_tutorial.dxf")
SEE ALSO:
The TablePainter instance contains all the data cells.
Content is a block reference inserted by an INSERT entity, attributes will be added if the block definition contains ATTDEF. Assignments are defined by attribs-key to attdef-tag association.
Example: attribs = {‘num’: 1} if an ATTDEF with tag==’num’ in the block definition exists, an attrib with text=str(1) will be created and added to the insert entity.
The cell spans over ‘span’ cells and has the cell style with the name ‘style’.
IMPORTANT:
Implements a cell type containing a block reference.
IMPORTANT:
The render space is defined by the argument coords which is a tuple of 4 float values in the order: left, right, top, bottom. These values are layout coordinates in drawing units. The DXF format does not support clipping boxes, therefore the render method can render beyond these borders!
IMPORTANT:
IMPORTANT:
The rich-text formatting capabilities for the regular MTEXT entity are not supported, if these features are required use the regular MTEXT entity and the MTextExplode add-on to explode the MTEXT entity into DXF primitives.
IMPORTANT:
This add-on creates special DXF files for use by Gerber Technology applications which have a low quality DXF parser and cannot parse/ignore BLOCKS which do not contain data according the ASTM-D6673-10 standard. The function export_file() exports DXF R12 and only DXF R12 files which do not contain the default “$MODEL_SPACE” and “$PAPER_SPACE” layout block definitions, have an empty HEADER section and no TABLES section. These special requirements of the Gerber Technology parser are annoying, but correspond to the DXF R12 standard.
Autodesk applications maybe complain about invalid BLOCK names such as “Shape 0_M”, which in my opinion are valid, maybe spaces were not allowed in the original R12 version, but this is just a minor issue and is more a problem of the picky Autodesk DXF parser, which is otherwise very forgiving for DXF R12 files.
import ezdxf from ezdxf.addons import gerber_D6673 doc = ezdxf.new("R12") # the export function rejects other DXF versions msp = doc.modelspace() # Create your content according the ASTM-D6673-10 standard # Do not use any linetypes or text styles, the TABLES section will not be exported. # The ASTM-D6673-10 standard supports only 7-bit ASCII characters. gerber_D6673.export_file(doc, "gerber_file.dxf")
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
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 |
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:
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
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 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:
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:
With the introduction of DXF R13 Autodesk added additional group codes and DXF tag structures to the DXF Standard.
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.
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.
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)
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.
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 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 }
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.
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:
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:
Unconfirmed assumptions:
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
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.
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.
A pointer is a reference to a DXF object in the same DXF file. There are four types of pointers:
Also, a group code range for “arbitrary” handles is defined to allow convenient storage of handle values that are unchanged at any operation (AutoCAD).
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 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 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.
(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”
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:
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.
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
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 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:
The CLASSES section can be empty, but some DXF entities requires class definitions to work in AutoCAD.
The TABLES section requires following tables:
The BLOCKS section requires two BLOCKS:
The ENTITIES section can be empty.
The OBJECTS section requires following entities:
Minimal DXF to download: https://github.com/mozman/ezdxf/tree/master/examples_dxf
(from the DXF Reference)
AutoCAD drawings consist largely of structured containers for database objects. Database objects each have the following features:
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.
The DXF R12 data model is identical to the file structure:
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:
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 ;):
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:
New objects in DXF R2004:
New objects in DXF R2007:
New objects in DXF R2013:
New objects in DXF R2018:
Undocumented objects:
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:
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
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:
DXF Reference: Header Variables
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:
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.
SEE ALSO:
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
The TABLES section contains the resource tables of a DXF document.
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:
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
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
APPID table entries are referenced by name:
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.
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:
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
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.0 • 2 0 = No center marks or lines are drawn • 2 <0 = Centerlines are drawn • 2 >0 = Center marks are drawn 168u |
DIMCLRD | 176 | Assigns colors to dimension lines, arrowheads, and dimension leader lines. 0.0 • 2 0 = BYBLOCK • 2 1-255 = ACI AutoCAD Color Index • 2 256 = BYLAYER 168u |
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.0 • 2 0 = Dimension limits are not generated as default text • 2 1 = Dimension limits are generated as default text 168u |
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.0 • 2 0 = Use arrowhead blocks set by DIMBLK • 2 1 = Use arrowhead blocks set by DIMBLK1 and DIMBLK2 168u |
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 • 2 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. • 2 >0 = A scale factor is computed that leads text sizes, arrowhead sizes, and other scaled distances to plot at their face values. 168u 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.0 • 2 0 = Extension line is not suppressed • 2 1 = Extension line is suppressed 168u |
DIMSE2 | 76 | Suppresses display of the second extension line. 0.0 • 2 0 = Extension line is not suppressed • 2 1 = Extension line is suppressed 168u |
DIMSOXD | 175 | Suppresses arrowheads if not enough space is available inside the extension lines. 0.0 • 2 0 = Arrowheads are not suppressed • 2 1 = Arrowheads are suppressed 168u 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.0 • 2 0 = Centers the dimension text between the extension lines. • 2 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 2 = Places the dimension text on the side of the dimension line farthest away from the defining points. • 2 3 = Places the dimension text to conform to Japanese Industrial Standards (JIS). • 2 4 = Places the dimension text below the dimension line. 168u |
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.0 • 2 0 = Aligns text with the dimension line • 2 1 = Draws text horizontally 168u |
DIMTIX | 174 | Draws text between extension lines. 0.0 • 2 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. • 2 1 = Draws dimension text between the extension lines even if it would ordinarily be placed outside those lines 168u |
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.0 • 2 0 = Does not draw dimension lines between the measured points when arrowheads are placed outside the measured points • 2 1 = Draws dimension lines between the measured points even when arrowheads are placed outside the measured points 168u |
DIMTOH | 74 | Controls the position of dimension text outside the extension lines. 0.0 • 2 0 = Aligns text with the dimension line • 2 1 = Draws text horizontally 168u |
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.0 • 2 0 = Draws arrowheads. • 2 >0 = Draws oblique strokes instead of arrowheads. The size of the oblique strokes is determined by this value multiplied by the DIMSCALE value 168u |
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.0 • 2 0 = Suppresses zero feet and precisely zero inches • 2 1 = Includes zero feet and precisely zero inches • 2 2 = Includes zero feet and suppresses zero inches • 2 3 = Includes zero inches and suppresses zero feet • 2 4 (Bit 3) = Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000) • 2 8 (Bit 4) = Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) • 2 12 (Bit 3+4) = Suppresses both leading and trailing zeros (for example, 0.5000 becomes .5) 168u |
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
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.0 • 2 0 = Decimal degrees • 2 1 = Degrees/minutes/seconds • 2 2 = Grad • 2 3 = Radians 168u |
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.0 • 2 0 = Positions the text above the dimension line and center-justifies it between the extension lines • 2 1 = Positions the text next to the first extension line • 2 2 = Positions the text next to the second extension line • 2 3 = Positions the text above and aligned with the first extension line • 2 4 = =Positions the text above and aligned with the second extension line 168u |
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.0 • 2 0 = First dimension line is not suppressed • 2 1 = First dimension line is suppressed 168u |
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.0 • 2 0 = Second dimension line is not suppressed • 2 1 = Second dimension line is suppressed 168u |
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.0 • 2 0 = Bottom • 2 1 = Middle • 2 2 = Top 168u |
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.0 • 2 0 = Suppresses zero feet and precisely zero inches • 2 1 = Includes zero feet and precisely zero inches • 2 2 = Includes zero feet and suppresses zero inches • 2 3 = Includes zero inches and suppresses zero feet • 2 4 = Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000) • 2 8 = Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) • 2 12 = Suppresses both leading and trailing zeros (for example, 0.5000 becomes .5) 168u |
DIMUPT | 288 | Controls options for user-positioned text. 0.0 • 2 0 = Cursor controls only the dimension line location • 2 1 = Cursor controls both the text position and the dimension line location 168u |
Source: CADDManager Blog
DIMVAR | Code | Description |
DIMALTRND | 148 | Rounds off the alternate dimension units. |
DIMATFIT | 289 | Determines how dimension text and arrows are arranged when space is not sufficient to place both within the extension lines. 0.0 • 2 0 = Places both text and arrows outside extension lines • 2 1 = Moves arrows first, then text • 2 2 = Moves text first, then arrows • 2 3 = Moves either text or arrows, whichever fits best 168u A leader is added to moved dimension text when DIMTMOVE is set to 1. |
DIMAZIN | 79 | Suppresses zeros for angular dimensions. 0.0 • 2 0 = Displays all leading and trailing zeros • 2 1 = Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000) • 2 2 = Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5) • 2 3 = Suppresses leading and trailing zeros (for example, 0.5000 becomes .5) 168u |
DIMFRAC | 276 | Sets the fraction format when DIMLUNIT is set to 4 (Architectural) or 5 (Fractional). 0.0 • 2 0 = Horizontal stacking • 2 1 = Diagonal stacking • 2 2 = Not stacked (for example, 1/2) 168u |
DIMLDRBLK_HANDLE | 341 | Specifies the arrow type for leaders. Handle to BLOCK RECORD |
DIMLUNIT | 277 | Sets units for all dimension types except Angular. 0.0 • 2 1 = Scientific • 2 2 = Decimal • 2 3 = Engineering • 2 4 = Architectural (always displayed stacked) • 2 5 = Fractional (always displayed stacked) • 2 6 = Microsoft Windows Desktop (decimal format using Control Panel settings for decimal separator and number grouping symbols) 168u |
DIMLWD | 371 | Assigns lineweight to dimension lines. 0.0 • 2 -3 = Default (the LWDEFAULT value) • 2 -2 = BYBLOCK • 2 -1 = BYLAYER 168u |
DIMLWE | 372 | Assigns lineweight to extension lines. 0.0 • 2 -3 = Default (the LWDEFAULT value) • 2 -2 = BYBLOCK • 2 -1 = BYLAYER 168u |
DIMTMOVE | 279 | Sets dimension text movement rules. 0.0 • 2 0 = Moves the dimension line with dimension text • 2 1 = Adds a leader when dimension text is moved • 2 2 = Allows text to be moved freely without a leader 168u |
This image shows the default text locations created by BricsCAD for dimension variables dimtad and dimjust: [image]
The following DIMVARS are not documented in the DXF Reference by Autodesk.
DIMVAR | Code | Description |
DIMTFILL | 69 | Text fill 0=off; 1=background color; 2=custom color (see DIMTFILLCLR) |
DIMTFILLCLR | 70 | Text fill custom color as color index |
DIMFXLON | 290 | Extension line has fixed length if set to 1 |
DIMFXL | 49 | Length of extension line below dimension line if fixed (DIMFXLON is 1), DIMEXE defines the the length above the dimension line |
DIMJOGANG | 50 | Angle of oblique dimension line segment in jogged radius dimension |
DIMLTYPE_HANDLE | 345 | Specifies the LINETYPE of the dimension line. Handle to LTYPE table entry |
DIMLTEX1_HANDLE | 346 | Specifies the LINETYPE of the extension line 1. Handle to LTYPE table entry |
DIMLTEX2_HANDLE | 347 | Specifies the LINETYPE of the extension line 2. Handle to LTYPE table entry |
Prior to DXF R2007, some extended settings for the dimension and the extension lines are stored in the XDATA section by following entries, this is not documented by Autodesk:
1001 ACAD_DSTYLE_DIM_LINETYPE <<< linetype for dimension line 1070 380 <<< group code, which differs from R2007 DIMDLTYPE 1005 FFFF <<< handle to LTYPE entry 1001 ACAD_DSTYLE_DIM_EXT1_LINETYPE <<< linetype for extension line 1 1070 381 <<< group code, which differs from R2007 DIMLTEX1 1005 FFFF <<< handle to LTYPE entry 1001 ACAD_DSTYLE_DIM_EXT2_LINETYPE <<< linetype for extension line 1 1070 382 <<< group code, which differs from R2007 DIMLTEX2 1005 FFFF <<< handle to LTYPE entry 1001 ACAD_DSTYLE_DIMEXT_ENABLED <<< extension line fixed 1070 383 <<< group code, which differs from R2007 DIMEXFIX 1070 1 <<< fixed if 1 else 0 1001 ACAD_DSTYLE_DIMEXT_LENGTH <<< extension line fixed length 1070 378 <<< group code, which differs from R2007 DIMEXLEN 1040 1.33 <<< length of extension line below dimension line
This XDATA groups requires also an appropriate APPID entry in the APPID table. This feature is not supported by ezdxf.
TODO
SEE ALSO:
0 <<< start of table TABLE 2 <<< name of table "LAYER" LAYER 5 <<< handle of the TABLE 2 330 <<< owner tag is always "0" 0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of layers defined in this table, AutoCAD ignores this value 5 0 <<< 1. LAYER table entry LAYER ... <<< LAYER entity tags 0 <<< 2. LAYER table entry LAYER ... <<< LAYER entity tags 0 <<< end of TABLE ENDTAB
There are some quirks:
0 <<< LAYER table entry LAYER 5 <<< handle of LAYER 10 330 <<< owner handle, handle of LAYER table 2 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbLayerTableRecord 2 <<< layer name 0 <<< layer "0" 70 <<< flags 0 62 <<< color 7 <<< a negative value switches the layer off 420 <<< optional true color value 0 6 <<< linetype Continuous 290 <<< optional plot flag 1 370 <<< lineweight -3 390 <<< handle to plot style F 347 <<< material handle 47 348 <<< unknown1 0 1001 <<< XDATA section, APPID AcAecLayerStandard 1000 <<< unknown first value, here an empty string 1000 <<< layer description This layer has a description 1001 <<< APPID AcCmTransparency 1071 <<< layer transparency value 0
Some layer attributes can be overridden individually for any VIEWPORT entity. This overrides are stored as extension dictionary entries of the LAYER entity pointing to XRECORD entities in the objects section:
0 LAYER 5 9F 102 <<< APP data, extension dictionary {ACAD_XDICTIONARY 360 <<< handle to the xdict in the objects section B3 102 } 330 2 100 AcDbSymbolTableRecord 100 AcDbLayerTableRecord 2 LayerA ...
The extension DICTIONARY entity:
0 <<< entity type DICTIONARY 5 <<< handle B3 330 <<< owner handle 9F <<< the layer owns this dictionary 100 <<< subclass marker AcDbDictionary 280 <<< hard owned flag 1 281 <<< cloning type 1 <<< keep existing 3 <<< transparency override ADSK_XREC_LAYER_ALPHA_OVR 360 <<< handle to XRECORD E5 3 <<< color override ADSK_XREC_LAYER_COLOR_OVR 360 <<< handle to XRECORD B4 3 <<< linetype override ADSK_XREC_LAYER_LINETYPE_OVR 360 <<< handle to XRECORD DD 3 <<< lineweight override ADSK_XREC_LAYER_LINEWT_OVR 360 <<< handle to XRECORD E2
Transparency override XRECORD:
0 <<< entity type XRECORD 5 <<< handle E5 102 <<< reactors app data {ACAD_REACTORS 330 B3 <<< extension dictionary 102 } 330 <<< owner tag B3 <<< extension dictionary 100 <<< subclass marker AcDbXrecord 280 <<< cloning flag 1 <<< keep existing 102 <<< for each overridden VIEWPORT one entry {ADSK_LYR_ALPHA_OVERRIDE 335 <<< handle to VIEWPORT AC 440 <<< transparency override 33554661 102 }
Color override XRECORD:
0 XRECORD ... <<< like transparency XRECORD 102 <<< for each overridden VIEWPORT one entry {ADSK_LYR_COLOR_OVERRIDE 335 <<< handle to VIEWPORT AF 420 <<< color override -1023409925 <<< raw color value 102 }
Linetype override XRECORD:
0 XRECORD ... <<< like transparency XRECORD 102 <<< for each overridden VIEWPORT one entry {ADSK_LYR_LINETYPE_OVERRIDE 335 <<< handle to VIEWPORT AC 343 <<< linetype override DC <<< handle to LINETYPE table entry 102 }
Lineweight override XRECORD:
0 XRECORD ... <<< like transparency XRECORD 102 <<< for each overridden VIEWPORT one entry {ADSK_LYR_LINEWT_OVERRIDE 335 <<< handle to VIEWPORT AC 91 <<< lineweight override 13 <<< lineweight value 102 }
LAYER table entries are referenced by name:
The LTYPE table stores all line type definitions of a DXF drawing. Every line type used in the drawing has to have a table entry, or the DXF drawing is invalid for AutoCAD.
DXF R12 supports just simple line types, DXF R2000+ supports also complex line types with text or shapes included.
You have access to the line types table by the attribute Drawing.linetypes. The line type table itself is not stored in the entity database, but the table entries are stored in entity database, and can be accessed by its handle.
SEE ALSO:
0 <<< start of table TABLE 2 <<< table type LTYPE 70 <<< count of table entries, AutoCAD ignores this value 9 0 <<< 1. LTYPE table entry LTYPE <<< LTYPE data tags 0 <<< 2. LTYPE table entry LTYPE <<< LTYPE data tags and so on 0 <<< end of LTYPE table ENDTAB
0 <<< start of table TABLE 2 <<< table type LTYPE 5 <<< table handle 5F 330 <<< owner tag, tables have no owner 0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of table entiries, AutoCAD ignores this value 9 0 <<< 1. LTYPE table entry LTYPE <<< LTYPE data tags 0 <<< 2. LTYPE table entry LTYPE <<< LTYPE data tags and so on 0 <<< end of LTYPE table ENDTAB
ezdxf setup for line type “CENTER”:
dwg.linetypes.add("CENTER", description="Center ____ _ ____ _ ____ _ ____ _ ____ _ ____", pattern=[2.0, 1.25, -0.25, 0.25, -0.25], )
0 <<< line type table entry LTYPE 5 <<< handle of line type 1B1 330 <<< owner handle, handle of LTYPE table 5F 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbLinetypeTableRecord 2 <<< line type name CENTER 70 <<< flags 0 3 Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ 72 <<< signature tag 65 <<< ascii code for "A" 73 <<< count of pattern groups starting with a code 49 tag 4 <<< 4 pattern groups 40 <<< overall pattern length in drawing units 2.0 49 <<< 1. pattern group 1.25 <<< >0 line, <0 gap, =0 point 74 <<< type marker 0 <<< 0 for line group 49 <<< 2. pattern group -0.25 74 0 49 <<< 3. pattern group 0.25 74 0 49 <<< 4. pattern group -0.25 74 0
ezdxf setup for line type “GASLEITUNG”:
dwg.linetypes.add("GASLEITUNG", description="Gasleitung2 ----GAS----GAS----GAS----GAS----GAS----GAS--", length=1, pattern='A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25', )
0 LTYPE 5 614 330 5F 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbLinetypeTableRecord 2 GASLEITUNG 70 0 3 Gasleitung2 ----GAS----GAS----GAS----GAS----GAS----GAS-- 72 <<< signature tag 65 <<< ascii code for "A" 73 <<< count of pattern groups starting with a code 49 tag 3 <<< 3 pattern groups 40 <<< overall pattern length in drawing units 1 49 <<< 1. pattern group 0.5 <<< >0 line, <0 gap, =0 point 74 <<< type marker 0 <<< 0 for line group 49 <<< 2. pattern group -0.2 74 <<< type marker 2 <<< 2 for text group 75 <<< shape number in shape-file 0 <<< always 0 for text group 340 <<< handle to text style "STANDARD" 11 46 <<< scaling factor: "s" in pattern definition 0.1 50 <<< rotation angle: "r" and "u" in pattern definition 0.0 44 <<< shift x units: "x" in pattern definition = parallel to line direction -0.1 45 <<< shift y units: "y" in pattern definition = normal to line direction -0.05 9 <<< text GAS 49 <<< 3. pattern group -0.25 74 0
ezdxf setup for line type ‘GRENZE2’:
dwg.linetypes.new('GRENZE2', dxfattribs={ 'description': 'Grenze eckig ----[]-----[]----[]-----[]----[]--', 'length': 1.45, 'pattern': 'A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1', })
0 LTYPE 5 615 330 5F 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbLinetypeTableRecord 2 GRENZE2 70 0 3 Grenze eckig ----[]-----[]----[]-----[]----[]-- 72 <<< signature tag 65 <<< ascii code for "A" 73 <<< count of pattern groups starting with a code 49 tag 4 <<< 4 pattern groups 40 <<< overall pattern length in drawing units 1.45 49 <<< 1. pattern group 0.25 <<< >0 line, <0 gap, =0 point 74 <<< type marker 0 <<< 0 for line group 49 <<< 2. pattern group -0.1 74 <<< type marker 4 <<< 4 for shape group 75 <<< shape number in shape-file 132 340 <<< handle to shape-file entry "ltypeshp.shx" 616 46 <<< scaling factor: "s" in pattern definition 0.1 50 <<< rotation angle: "r" and "u" in pattern definition 0.0 44 <<< shift x units: "x" in pattern definition = parallel to line direction -0.1 45 <<< shift y units: "y" in pattern definition = normal to line direction 0.0 49 <<< 3. pattern group -0.1 74 0 49 <<< 4. pattern group 1.0 74 0
LTYPE table entries are referenced by name:
The STYLE table stores all text styles and shape-file definitions. The “STANDARD” entry must always exist.
Shape-files are also defined by a STYLE table entry, the bit 0 of the flags-tag is set to 1 and the name-tag is an empty string, the only important data is the font-tag with group code 3 which stores the associated SHX font file.
SEE ALSO:
0 <<< start of table TABLE 2 <<< table type STYLE 70 <<< count of table entries, AutoCAD ignores this value 1 0 <<< first table entry STYLE 2 <<< text style name Standard 70 <<< flags, see `STYLE`_ reference 0 40 <<< fixed text height; 0 if not fixed 0.0 41 <<< width factor 1.0 50 <<< oblique angle 0.0 71 <<< text generation flags; 2=backwards (mirror-x), 4=upside down (mirror-y) 0 42 <<< last height used 2.5 3 <<< font file name; SHX or TTF file name txt 4 <<< big font name; SHX file with unicode symbols; empty if none 0 <<< next text style STYLE ... 0 <<< end of STYLE table ENDTAB
0 <<< start of table TABLE 2 <<< table type STYLE 5 <<< table handle 5 330 <<< owner tag, tables have no owner 0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of table entries, AutoCAD ignores this value 1 0 <<< first table entry STYLE 5 <<< handle of text style 29 330 <<< owner handle, handle of STYLE table 5 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbTextStyleTableRecord 2 <<< text style name Standard 70 <<< flags, see `STYLE`_ reference 0 40 <<< fixed text height; 0 if not fixed 0.0 41 <<< width factor 1.0 50 <<< oblique angle 0.0 71 <<< text generation flags; 2=backwards (mirror-x), 4=upside down (mirror-y) 0 42 <<< last height used 2.5 3 <<< font file name; SHX or TTF file name txt 4 <<< big font name; SHX file with unicode symbols; empty if none 0 <<< next text style STYLE ... 0 <<< end of STYLE table ENDTAB
Additional information of the font-family, italic and bold style flags are stored in the XDATA section of the STYLE entity by the APPID “ACAD”:
0 STYLE ... 3 Arial.ttf 4 1001 <<< start of the XDATA section ACAD <<< APPID 1000 <<< font family name Arial 1071 <<< style flags, see table below 50331682
Flag | dec | hex |
ITALIC | 16777216 | 0x1000000 |
BOLD | 33554432 | 0x2000000 |
STYLE table entries are referenced by name:
TODO
The VIEW entry stores a named view of the model or a paperspace layout. This stored views makes parts of the drawing or some view points of the model in a CAD applications more accessible. This views have no influence to the drawing content or to the generated output by exporting PDFs or plotting on paper sheets, they are just for the convenience of CAD application users.
Using ezdxf you have access to the views table by the attribute Drawing.views. The views table itself is not stored in the entity database, but the table entries are stored in entity database, and can be accessed by its handle.
0 VIEW 2 <<< name of view VIEWNAME 70 <<< flags bit-coded: 1st bit -> (0/1 = modelspace/paperspace) 0 <<< modelspace 40 <<< view width in Display Coordinate System (DCS) 20.01 10 <<< view center point in DCS 40.36 <<< x value 20 <<< group code for y value 15.86 <<< y value 41 <<< view height in DCS 17.91 11 <<< view direction from target point, 3D vector 0.0 <<< x value 21 <<< group code for y value 0.0 <<< y value 31 <<< group code for z value 1.0 <<< z value 12 <<< target point in WCS 0.0 <<< x value 22 <<< group code for y value 0.0 <<< y value 32 <<< group code for z value 0.0 <<< z value 42 <<< lens (focal) length 50.0 <<< 50mm 43 <<< front clipping plane, offset from target 0.0 44 <<< back clipping plane, offset from target 0.0 50 <<< twist angle 0.0 71 <<< view mode 0
SEE ALSO:
Mostly the same structure as DXF R12, but with handle, owner tag and subclass markers.
0 <<< adding the VIEW table head, just for information TABLE 2 <<< table name VIEW 5 <<< handle of table, see owner tag of VIEW table entry 37C 330 <<< owner tag of table, always #0 0 100 <<< subclass marker AcDbSymbolTable 70 <<< VIEW table (max.) count, not reliable (ignore) 9 0 <<< first VIEW table entry VIEW 5 <<< handle 3EA 330 <<< owner, the VIEW table is the owner of the VIEW entry 37C <<< handle of the VIEW table 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbViewTableRecord 2 <<< view name, from here all the same as DXF R12 VIEWNAME 70 0 40 20.01 10 40.36 20 15.86 41 17.91 11 0.0 21 0.0 31 1.0 12 0.0 22 0.0 32 0.0 42 50.0 43 0.0 44 0.0 50 0.0 71 0 281 <<< render mode 0-6 (... too much options) 0 <<< 0= 2D optimized (classic 2D) 72 <<< UCS associated (0/1 = no/yes) 0 <<< 0 = no
DXF R2000+ supports additional features in the VIEW entry, see the VIEW table reference provided by Autodesk.
The VPORT table stores the modelspace viewport configurations. A viewport configuration is a tiled view of multiple viewports or just one viewport. [image]
In contrast to other tables the VPORT table can have multiple entries with the same name, because all VPORT entries of a multi-viewport configuration are having the same name - the viewport configuration name. The name of the actual displayed viewport configuration is '*ACTIVE', as always table entry names are case insensitive ('*ACTIVE' == '*Active').
The available display area in AutoCAD has normalized coordinates, the lower-left corner is (0, 0) and the upper-right corner is (1, 1) regardless of the true aspect ratio and available display area in pixels. A single viewport configuration has one VPORT entry '*ACTIVE' with the lower-left corner (0, 0) and the upper-right corner (1, 1).
The following statements refer to a 2D plan view: the view-target-point defines the origin of the DCS (Display Coordinate system), the view-direction vector defines the z-axis of the DCS, the view-center-point (in DCS) defines the point in modelspace translated to the center point of the viewport, the view height and the aspect-ratio defines how much of the modelspace is displayed. AutoCAD tries to fit the modelspace area into the available viewport space e.g. view height is 15 units and aspect-ratio is 2.0 the modelspace to display is 30 units wide and 15 units high, if the viewport has an aspect ratio of 1.0, AutoCAD displays 30x30 units of the modelspace in the viewport. If the modelspace aspect-ratio is 1.0 the modelspace to display is 15x15 units and fits properly into the viewport area.
But tests show that the translation of the view-center-point to the middle of the viewport not always work as I expected. (still digging…)
NOTE:
Multi-viewport configuration with three viewports.
0 <<< table start TABLE 2 <<< table type VPORT 70 <<< VPORT table (max.) count, not reliable (ignore) 3 0 <<< first VPORT entry VPORT 2 <<< VPORT (configuration) name *ACTIVE 70 <<< standard flags, bit-coded 0 10 <<< lower-left corner of viewport 0.45 <<< x value, virtual coordinates in range [0 - 1] 20 <<< group code for y value 0.0 <<< y value, virtual coordinates in range [0 - 1] 11 <<< upper-right corner of viewport 1.0 <<< x value, virtual coordinates in range [0 - 1] 21 <<< group code for y value 1.0 <<< y value, virtual coordinates in range [0 - 1] 12 <<< view center point (in DCS), ??? 13.71 <<< x value 22 <<< group code for y value 0.02 <<< y value 13 <<< snap base point (in DCS) 0.0 <<< x value 23 <<< group code for y value 0.0 <<< y value 14 <<< snap spacing X and Y 1.0 <<< x value 24 <<< group code for y value 1.0 <<< y value 15 <<< grid spacing X and Y 0.0 <<< x value 25 <<< group code for y value 0.0 <<< y value 16 <<< view direction from target point (in WCS), defines the z-axis of the DCS 1.0 <<< x value 26 <<< group code for y value -1.0 <<< y value 36 <<< group code for z value 1.0 <<< z value 17 <<< view target point (in WCS), defines the origin of the DCS 0.0 <<< x value 27 <<< group code for y value 0.0 <<< y value 37 <<< group code for z value 0.0 <<< z value 40 <<< view height 35.22 41 <<< viewport aspect ratio 0.99 42 <<< lens (focal) length 50.0 <<< 50mm 43 <<< front clipping planes, offsets from target point 0.0 44 <<< back clipping planes, offsets from target point 0.0 50 <<< snap rotation angle 0.0 51 <<< view twist angle 0.0 71 <<< view mode 0 72 <<< circle zoom percent 1000 73 <<< fast zoom setting 1 74 <<< UCSICON setting 3 75 <<< snap on/off 0 76 <<< grid on/off 0 77 <<< snap style 0 78 <<< snap isopair 0 0 <<< next VPORT entry VPORT 2 <<< VPORT (configuration) name *ACTIVE <<< same as first VPORT entry 70 0 10 0.0 20 0.5 11 0.45 21 1.0 12 8.21 22 9.41 ... ... 0 <<< next VPORT entry VPORT 2 <<< VPORT (configuration) name *ACTIVE <<< same as first VPORT entry 70 0 10 0.0 20 0.0 11 0.45 21 0.5 12 2.01 22 -9.33 ... ... 0 ENDTAB
Mostly the same structure as DXF R12, but with handle, owner tag and subclass markers.
0 <<< table start TABLE 2 <<< table type VPORT 5 <<< table handle 151F 330 <<< owner, table has no owner - always #0 0 100 <<< subclass marker AcDbSymbolTable 70 <<< VPORT table (max.) count, not reliable (ignore) 3 0 <<< first VPORT entry VPORT 5 <<< entry handle 158B 330 <<< owner, VPORT table is owner of VPORT entry 151F 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbViewportTableRecord 2 <<< VPORT (configuration) name *ACTIVE 70 <<< standard flags, bit-coded 0 10 <<< lower-left corner of viewport 0.45 <<< x value, virtual coordinates in range [0 - 1] 20 <<< group code for y value 0.0 <<< y value, virtual coordinates in range [0 - 1] 11 <<< upper-right corner of viewport 1.0 <<< x value, virtual coordinates in range [0 - 1] 21 <<< group code for y value 1.0 <<< y value, virtual coordinates in range [0 - 1] 12 <<< view center point (in DCS) 13.71 <<< x value 22 <<< group code for y value 0.38 <<< y value 13 <<< snap base point (in DCS) 0.0 <<< x value 23 <<< group code for y value 0.0 <<< y value 14 <<< snap spacing X and Y 1.0 <<< x value 24 <<< group code for y value 1.0 <<< y value 15 <<< grid spacing X and Y 0.0 <<< x value 25 <<< group code for y value 0.0 <<< y value 16 <<< view direction from target point (in WCS) 1.0 <<< x value 26 <<< group code for y value -1.0 <<< y value 36 <<< group code for z value 1.0 <<< z value 17 <<< view target point (in WCS) 0.0 <<< x value 27 <<< group code for y value 0.0 <<< y value 37 <<< group code for z value 0.0 <<< z value 40 <<< view height 35.22 41 <<< viewport aspect ratio 0.99 42 <<< lens (focal) length 50.0 <<< 50mm 43 <<< front clipping planes, offsets from target point 0.0 44 <<< back clipping planes, offsets from target point 0.0 50 <<< snap rotation angle 0.0 51 <<< view twist angle 0.0 71 <<< view mode 0 72 <<< circle zoom percent 1000 73 <<< fast zoom setting 1 74 <<< UCSICON setting 3 75 <<< snap on/off 0 76 <<< grid on/off 0 77 <<< snap style 0 78 <<< snap isopair 0 281 <<< render mode 1-6 (... too many options) 0 <<< 0 = 2D optimized (classic 2D) 65 <<< Value of UCSVP for this viewport. (0 = UCS will not change when this viewport is activated) 1 <<< 1 = then viewport stores its own UCS which will become the current UCS whenever the viewport is activated. 110 <<< UCS origin (3D point) 0.0 <<< x value 120 <<< group code for y value 0.0 <<< y value 130 <<< group code for z value 0.0 <<< z value 111 <<< UCS X-axis (3D vector) 1.0 <<< x value 121 <<< group code for y value 0.0 <<< y value 131 <<< group code for z value 0.0 <<< z value 112 <<< UCS Y-axis (3D vector) 0.0 <<< x value 122 <<< group code for y value 1.0 <<< y value 132 <<< group code for z value 0.0 <<< z value 79 <<< Orthographic type of UCS 0-6 (... too many options) 0 <<< 0 = UCS is not orthographic 146 <<< elevation 0.0 1001 <<< extended data - undocumented ACAD_NAV_VCDISPLAY 1070 3 0 <<< next VPORT entry VPORT 5 158C 330 151F 100 AcDbSymbolTableRecord 100 AcDbViewportTableRecord 2 <<< VPORT (configuration) name *ACTIVE <<< same as first VPORT entry 70 0 10 0.0 20 0.5 11 0.45 21 1.0 12 8.21 22 9.72 ... ... 0 <<< next VPORT entry VPORT 5 158D 330 151F 100 AcDbSymbolTableRecord 100 AcDbViewportTableRecord 2 <<< VPORT (configuration) name *ACTIVE <<< same as first VPORT entry 70 0 10 0.0 20 0.0 11 0.45 21 0.5 12 2.01 22 -8.97 ... ... 0 ENDTAB
The TABLES section of DXF R13 and later looks like this:
0 SECTION 2 <<< begin TABLES section TABLES 0 <<< first TABLE TABLE 2 <<< name of table "LTYPE" LTYPE 5 <<< handle of the TABLE 8 330 <<< owner handle is always "0" 0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of table entries 4 <<< do not rely on this value! 0 <<< first table entry LTYPE ... 0 <<< second table entry LTYPE ... 0 <<< end of TABLE ENDTAB 0 <<< next TABLE TABLE 2 <<< name of table "LAYER" LAYER 5 <<< handle of the TABLE 2 330 <<< owner handle is always "0" 0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of table entries 1 0 <<< first table entry LAYER ... 0 <<< end of TABLE ENDTAB 0 <<< end of SECTION ENDSEC
The TABLES section of DXF R12 and prior is a bit simpler and does not contain the BLOCK_RECORD table. The handles in DXF R12 and prior are optional and only present if the HEADER variable $HANDLING is 1.
0 SECTION 2 <<< begin TABLES section TABLES 0 <<< first TABLE TABLE 2 <<< name of table "LTYPE" LTYPE 5 <<< optional handle of the TABLE 8 70 <<< count of table entries 4 0 <<< first table entry LTYPE ... 0 <<< second table entry LTYPE ... 0 <<< end of TABLE ENDTAB 0 <<< next TABLE TABLE 2 <<< name of table "LAYER" LAYER 5 <<< optional handle of the TABLE 2 70 <<< count of table entries 1 0 <<< first table entry LAYER ... 0 <<< end of TABLE ENDTAB 0 <<< end of SECTION ENDSEC
The BLOCKS section contains all BLOCK definitions, beside the normal reusable BLOCKS used by the INSERT entity, all layouts, as there are the modelspace and all paperspace layouts, have at least a corresponding BLOCK definition in the BLOCKS section. The name of the modelspace BLOCK is “*Model_Space” (DXF R12: “$MODEL_SPACE”) and the name of the active paperspace BLOCK is “*Paper_Space” (DXF R12: “$PAPER_SPACE”), the entities of these two layouts are stored in the ENTITIES section, the inactive paperspace layouts are named by the scheme “*Paper_Spacennnn”, and the content of the inactive paperspace layouts are stored in their BLOCK definition in the BLOCKS section.
The content entities of blocks are stored between the BLOCK and the ENDBLK entity.
BLOCKS section structure:
0 <<< start of a SECTION SECTION 2 <<< start of BLOCKS section BLOCKS 0 <<< start of 1. BLOCK definition BLOCK ... <<< Block content ... 0 <<< end of 1. Block definition ENDBLK 0 <<< start of 2. BLOCK definition BLOCK ... <<< Block content ... 0 <<< end of 2. Block definition ENDBLK 0 <<< end of BLOCKS section ENDSEC
SEE ALSO:
TODO
Objects in the OBJECTS section are organized in a hierarchical tree order, starting with the named objects dictionary as the first entity in the OBJECTS section (Drawing.rootdict).
Not all entities in the OBJECTS section are included in this tree, Extension Dictionary and XRECORD data of graphical entities are also stored in the OBJECTS section.
SEE ALSO:
The MESH entity is the compact version of the PolyFaceMesh implemented by the Polyline entity . The entity stores the vertices, edges and faces in a single entity and was introduced in DXF version R13/R14. For more information about the top level stuff go to the Mesh class.
SEE ALSO:
The following DXF code represents this cube with subdivision level of 0: [image]
0 MESH <<< DXF type 5 <<< entity handle 2F 330 <<< block record handle of owner layout 17 100 AcDbEntity 8 0 <<< layer 62 6 <<< color 100 AcDbSubDMesh <<< subclass marker 71 2 <<< version 72 1 <<< blend crease, 1 is "on", 0 is "off" 91 0 <<< subdivision level is 0 92 8 <<< vertex count, 8 cube corners 10 <<< 1. vertex, x-axis 0.0 20 <<< y-axis 0.0 30 <<< z-axis 0.0 10 <<< 2. vertex 1.0 20 0.0 30 0.0 10 <<< 3. vertex 1.0 20 1.0 30 0.0 10 <<< 4. vertex 0.0 20 1.0 30 0.0 10 <<< 5. vertex 0.0 20 0.0 30 1.0 10 <<< 6. vertex 1.0 20 0.0 30 1.0 10 <<< 7. vertex 1.0 20 1.0 30 1.0 10 <<< 8. vertex 0.0 20 1.0 30 1.0 93 <<< size of face list 30 <<< size = count of group code 90 tags = 6 x 5 90 <<< vertex count of face 1 4 <<< MESH supports ngons, count = 3, 4, 5, 6 ... 90 0 <<< face 1, index of 1. vertex 90 3 <<< face 1, index of 2. vertex 90 2 <<< face 1, index of 3. vertex 90 1 <<< face 1, index of 4. vertex 90 4 <<< vertex count of face 2 90 4 <<< face 2, index of 1. vertex 90 5 <<< face 2, index of 2. vertex 90 6 <<< face 2, index of 3. vertex 90 7 <<< face 2, index of 4. vertex 90 4 <<< vertex count of face 3 90 0 <<< face 3, index of 1. vertex 90 1 <<< face 3, index of 2. vertex 90 5 <<< face 3, index of 3. vertex 90 4 <<< face 3, index of 4. vertex 90 4 <<< vertex count of face 4 90 1 <<< face 4, index of 1. vertex 90 2 <<< face 4, index of 2. vertex 90 6 <<< face 4, index of 3. vertex 90 5 <<< face 4, index of 4. vertex 90 4 <<< vertex count of face 5 90 3 <<< face 5, index of 1. vertex 90 7 <<< face 5, index of 2. vertex 90 6 <<< face 5, index of 3. vertex 90 2 <<< face 5, index of 4. vertex 90 4 <<< vertex count of face 6 90 0 <<< face 6, index of 1. vertex 90 4 <<< face 6, index of 2. vertex 90 7 <<< face 6, index of 3. vertex 90 3 <<< face 6, index of 4. vertex 94 <<< edge count, each edge has exact two group code 90 tags 4 <<< the real edge count not the group code 90 tags! 90 0 <<< edge 1, vertex 1 90 1 <<< edge 1, vertex 1 90 1 <<< edge 2, vertex 1 90 2 <<< edge 2, vertex 2 90 2 <<< edge 3, vertex 1 90 3 <<< edge 3, vertex 2 90 3 <<< edge 4, vertex 1 90 0 <<< edge 4, vertex 2 95 <<< edge crease count, has to match edge count! 4 140 3.0 <<< crease value for edge 1 140 3.0 <<< crease value for edge 2 140 3.0 <<< crease value for edge 3 140 3.0 <<< crease value for edge 4 90 <<< property overwrite??? 0
The edge and crease data have only a meaning if subdivision of the geometry will be applied! A crease value equal to the subdivision level prevents subdividing for the edge completely, a value between 0.0 and the subdivision level applies subdivision partially.
The cube with subdivision level of 3 and crease values of 3.0: [image]
Front view for better details: [image]
The cube with subdivision levels of 3 and crease values of 2.0: [image]
The cube with subdivision level of 3 and crease values of 1.0: [image]
The property overriding protocol is not documented in the DXF reference and currently I have no access to a CAD application which can created property overriding.
The MULTILEADER leader is a very complex entity and has also some weird and unique properties.
SEE ALSO:
Example for ezdxf.entities.MLeaderContext created by BricsCAD:
300 <str> CONTEXT_DATA{ 40 <float> 1.0 <<< content scale 10 <point> (x, y, z) <<< content base point 41 <float> 4.0 <<< text height 140 <float> 4.0 <<< arrowhead size 145 <float> 2.0 <<< landing gap size 174 <int> 1 <<< doc missing 175 <int> 1 <<< doc missing 176 <int> 0 <<< doc missing 177 <int> 0 <<< doc missing 290 <int> 1 <<< has_mtext_content <<< START MText Content tags: 304 <str> MTEXT content string 11 <point> (0.0, 0.0, 1.0) <<< extrusion vector 340 <hex> #A0 <<< text style as handle 12 <point> (x, y, z) <<< text location 13 <point> (1.0, 0.0, 0.0) <<< text direction 42 <float> 0.0 <<< text rotation 43 <float> 0.0 <<< text width 44 <float> 0.0 <<< text height 45 <float> 1.0 <<< text line space factor 170 <int> 1 <<< text line space style 90 <int> -1056964608 <<< text color (raw value) 171 <int> 1 <<< text attachment 172 <int> 1 <<< text flow direction 91 <int> -939524096 <<< text background color (raw value) 141 <float> 1.5 <<< text background scale factor 92 <int> 0 <<< text background transparency 291 <int> 0 <<< has_text_bg_color 292 <int> 0 <<< has_text_bg_fill 173 <int> 0 <<< text column type 293 <int> 0 <<< use text auto height 142 <float> 0.0 <<< text column width 143 <float> 0.0 <<< text column gutter width 294 <int> 0 <<< text column flow reversed 144 <float> missing <<< text column height (optional?) 295 <int> 0 <<< text use word break <<< END MText Content tags: 296 <int> 0 <<< has_block_content <<< START Block content tags <<< END Block content tags 110 <point> (0.0, 0.0, 0.0) <<< MLEADER plane origin point 111 <point> (1.0, 0.0, 0.0) <<< MLEADER plane x-axis direction 112 <point> (0.0, 1.0, 0.0) <<< MLEADER plane y-axis direction 297 <int> 0 <<< MLEADER normal reversed 302 <str> LEADER{ ... 303 <str> } 302 <str> LEADER{ ... 303 <str> } 272 <int> 9 <<< doc missing 273 <int> 9 <<< doc missing 301 <str> } <<< BricsCAD example for block content: 300 <str> CONTEXT_DATA{ 40 <float> 1.0 10 <point> (x, y, z) 41 <float> 4.0 140 <float> 4.0 145 <float> 2.0 174 <int> 1 175 <int> 1 176 <int> 0 177 <int> 0 290 <int> 0 <<< has_mtext_content 296 <int> 1 <<< has_block_content <<< START Block content tags 341 <hex> #94 <<< dxf.block_record_handle 14 <point> (0.0, 0.0, 1.0) <<< Block extrusion vector 15 <point> (x, y, z) <<< Block location 16 <point> (1.0, 1.0, 1.0) <<< Block scale vector, the x-, y- and z-axis scaling factors 46 <float> 0.0 <<< Block rotation in radians! 93 <int> -1056964608 <<< Block color (raw value) 47 <float> 1.0 <<< start of transformation matrix (16x47) 47 <float> 0.0 47 <float> 0.0 47 <float> 18.427396871473 47 <float> 0.0 47 <float> 1.0 47 <float> 0.0 47 <float> 0.702618780008 47 <float> 0.0 47 <float> 0.0 47 <float> 1.0 47 <float> 0.0 47 <float> 0.0 47 <float> 0.0 47 <float> 0.0 47 <float> 1.0 <<< end of transformation matrix <<< END Block content tags 110 <point> (0.0, 0.0, 0.0) <<< MLEADER plane origin point 111 <point> (1.0, 0.0, 0.0) <<< MLEADER plane x-axis direction 112 <point> (0.0, 1.0, 0.0) <<< MLEADER plane y-axis direction 297 <int> 0 <<< MLEADER normal reversed 302 <str> LEADER{ ... 303 <str> } 272 <int> 9 273 <int> 9 301 <str> } <<< Attribute content and other redundant block data is stored in the AcDbMLeader <<< subclass: 100 <ctrl> AcDbMLeader 270 <int> 2 <<< dxf.version 300 <str> CONTEXT_DATA{ <<< start context data ... 301 <str> } <<< end context data 340 <hex> #6D <<< dxf.style_handle 90 <int> 6816768 <<< dxf.property_override_flags ... <<< property overrides 292 <int> 0 <<< dxf.has_frame_text <<< mostly redundant block data: 344 <hex> #94 <<< dxf.block_record_handle 93 <int> -1056964608 <<< dxf.block_color (raw value) 10 <point> (1.0, 1.0, 1.0) <<< dxf.block_scale_vector 43 <float> 0.0 <<< dxf.block_rotation in radians! 176 <int> 0 <<< dxf.block_connection_type 293 <int> 0 <<< dxf.is_annotative <<< REPEAT: (optional) 94 <int> <<< arrow head index? 345 <hex> <<< arrow head handle <<< REPEAT: (optional) 330 <hex> #A3 <<< ATTDEF handle 177 <int> 1 <<< ATTDEF index 44 <float> 0.0 <<< ATTDEF width 302 <str> B <<< ATTDEF text (reused group code) ... common group codes 294, 178, 179, ...
The MTEXT entity stores multiline text in a single entity and was introduced in DXF version R13/R14. For more information about the top level stuff go to the MText class.
SEE ALSO:
The MTEXT entity does not establish an OCS. The entity has a text_direction attribute, which defines the local x-axis, the extrusion attribute defines the normal vector and the y-axis = extrusion cross x-axis.
The MTEXT entity can have also a rotation attribute (in degrees), the x-axis attribute has higher priority than the rotation attribute, but it is not clear how to convert the rotation attribute into a text_direction vector, but for most common cases, where only the rotation attribute is present, the extrusion is most likely the WCS z-axis and the rotation is the direction in the xy-plane.
The content text is divided across multiple tags of group code 3 and 1, the last line has the group code 1, each line can have a maximum line length of 255 bytes, but BricsCAD (and AutoCAD?) store only 249 bytes in single line and one byte is not always one char.
The text formatting is done by inline codes, see the MText class.
Information gathered by implementing the MTextEditor and the MTextParser classes:
complex example to create a numbered list with two items: "pxi-3,l4t4;1.^Ifirst item\P2.^Isecond item"
There is no reliable way to calculate the MTEXT height from the existing DXF attributes. The rect_height (group code 43) attribute is not required and seldom present. DXF R2007 introduced the defined_height attribute to store the defined column height of the MTEXT entity but only in column mode. MTEXT entities without columns, except MTEXT entities created with column type “No Columns”, store always 0.0 as defined column height. Which seems to mean: defined by the rendered text content.
The only way to calculate the MTEXT height is to replicate the rendering results of AutoCAD/BricsCAD by implementing a rendering engine for MTEXT.
In column mode the MTEXT height is stored for every column for DXF version before R2018. In DXF R2018+ the column heights are only stored if MTextColumns.auto_height is False. If MTextColumns.auto_height is True. But DXF R2018+ stores the MTEXT total width and height in explicit attributes.
The situation for width calculation is better than for the height calculation, but the attributes width and rect_width are not mandatory.
There is a difference between MTEXT entities with and without columns:
Without columns the attribute width (reference column width) contains the true entity width if present. A long word can overshoot this width! The rect_width attribute is seldom present.
For MTEXT with columns, the width attribute is maybe wrong, the correct width for a column is stored in the column_width attribute and the total_width attribute stores the total width of the MTEXT entity overall columns, see also following section “Column Support”.
The background fill support is available for DXF R2007+. The group code 90 defines the kind of background fill:
0 | off |
1 | color defined by group code 63, 421 or 431 |
2 | drawing window color |
3 | background (canvas) color |
16 | bit-flag text frame, see Open Design Alliance Specification 20.4.46 |
Group codes to define background fill attributes:
45 | scaling factor for the border around the text, the value should be in the range of [1, 5], where 1 fits exact the MText entity |
63 | set the background color by ACI. |
421 | set the background color as true-color value. |
431 | set the background color by color name - no idea how this works |
441 | set the transparency of the background fill, not supported by AutoCAD or BricsCAD. |
Group codes 45, 90 and 63 are required together if one of them is used. The group code 421 and 431 also requires the group code 63, even this value is ignored.
... <snip> 1 <str> eu feugiat nulla facilisis at vero eros et accumsan et iusto ... 73 <int> 1 44 <float> 1.0 90 <int> 1, b00000001 <<< use a color 63 <int> 1 <<< ACI color (red) 45 <float> 1.5 <<< bg scaling factor, relative to the char height 441 <int> 0 <<< ignored (optional) ... <snip>
The background scaling does not alter the width, column_width or total_width attributes. The background acquires additional space around the MTEXT entity.
Columns with background color: [image]
The MTEXT entity can have a text frame only, without a background filling, group code 90 has value 16. In this case all other background related tags are removed (45, 63, 421, 431, 441) and the scaling factor is 1.5 by default.
This XDATA exist only if the text frame flag in group code 90 is set and for DXF version < R2018!
... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_TEXT_BORDERS_BEGIN 1070 <int> 80 <<< group code for repeated flags 1070 <int> 16 <<< repeated group code 90? 1070 <int> 46 <<< group code for scaling factor, which is fixed? 1040 <float> 1.5 <<< scaling factor 1070 <int> 81 <<< group code for repeated flow direction? 1070 <int> 1 <<< flow direction? 1070 <int> 5 <<< group code for a handle, multiple entries possible 1005 <hex> #A8 <<< handle to the LWPOLYLINE text frame 1070 <int> 5 <<< group code for next handle 1005 <hex> #A9 <<< next handle ... 1000 <str> ACAD_MTEXT_TEXT_BORDERS_END
The newer versions of AutoCAD and BricsCAD get all the information they need from the MTEXT entity, but it seems that older versions could not handle the text frame property correct. Therefore AutoCAD and BricsCAD create a separated LWPOLYLINE entity for the text frame for DXF versions < R2018. The handle to this text frame entity is stored in the XDATA as group code 1005, see section above.
Because this LWPOLYLINE is not required ezdxf does not create such a text frame entity nor the associated XDATA and ezdxf also removes this data from loaded DXF files at the second loading stage.
CAD applications build multiple columns by linking 2 or more MTEXT entities together. In this case each column is a self-sufficient entity in DXF version R13 until R2013. The additional columns specifications are stored in the XDATA if the MTEXT which represents the first column.
DXF R2018 changed the implementation into a single MTEXT entity which contains all the content text at once and stores the column specification in an embedded object.
HINT:
There are two column types, the static type has the same column height for all columns, the dynamic type can have the same (auto) height or an individual height for each column.
Common facts about columns for all column types:
The column type defines how a CAD application should create the columns, this is not important for the file format, because the result of this calculation, the column count and the column height, is stored the DXF file.
Column Type in BricsCAD | Description | ||
Static | All columns have the same height. The “auto height” flag is 0. | ||
Dynamic (auto height) | Same as the static type, all columns have the same height. The “auto height” flag is 1. The difference to the static type is only important for interactive CAD applications. | ||
Dynamic (manual height) | same as the dynamic (auto height) type, but each column can have an individual height. | ||
No column | A regular MTEXT with “defined column height” attribute? | ||
Column Type | Defined Height | Auto Height | Column Heights |
Static | stored | False | not stored |
Dynamic auto | stored | True | not stored |
Dynamic manual | not stored | False | stored (last=0) |
For DXF versions < R2018 the column count is always given by the count of linked MTEXT columns. Caution: the column count stored in the XDATA section by group code 76 may not match the count of linked MTEXT entities and AutoCAD is OK with that! In DXF R2018+ this property is not available, because there are no linked MTEXT entities anymore.
R2018+: For the column types “static” and “dynamic manual” the correct column count is stored as group code 72. For the column type “dynamic auto” the stored column count is 0. It is possible to calculate the column count from the total width and the column width if the total width is correct like in AutoCAD and BricsCAD.
Example for a static column specification:
The column height is stored as the “defined column height” in XDATA (46) or the embedded object (41).
DXF R2000 example with a static column specification stored in XDATA:
0 MTEXT 5 <<< entity handle 9D 102 {ACAD_XDICTIONARY 360 9F 102 } 330 <<< block record handle of owner layout 1F 100 AcDbEntity 8 <<< layer 0 100 <<< begin of MTEXT specific data AcDbMText 10 <<< (10, 20, 30) insert location in WCS 285.917876152751 20 276.101821192053 30 0.0 40 <<< character height in drawing units 2.5 41 <<< reference column width, if not in column mode 62.694... <<< in column mode: the real column is defined in XDATA (48) 71 <<< attachment point 1 72 <<< text flow direction 1 3 <<< begin of text Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam ... 3 kimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit ... 3 ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ... 3 At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd ... 3 ore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio ... 1 <<< last text line and end of text euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. 73 <<< line spacing style 1 44 <<< line spacing factor 1.0 1001 AcadAnnotative 1000 AnnotativeData 1002 { 1070 1 1070 0 1002 } 1001 <<< AppID "ACAD" contains the column specification ACAD 1000 ACAD_MTEXT_COLUMN_INFO_BEGIN 1070 75 <<< group code column type 1070 1 <<< column type: 0=no column; 1=static columns; 2=dynamic columns 1070 79 <<< group code column auto height 1070 0 <<< flag column auto height 1070 76 <<< group code column count 1070 3 <<< column count 1070 78 <<< group code column flow reversed 1070 0 <<< flag column flow reversed 1070 48 <<< group code column width 1040 50.0 <<< column width in column mode 1070 49 <<< group code column gutter 1040 12.5 <<< column gutter width 1000 ACAD_MTEXT_COLUMN_INFO_END 1000 <<< linked MTEXT entities specification ACAD_MTEXT_COLUMNS_BEGIN 1070 47 <<< group code for column count, incl. the 1st column - this entity 1070 3 <<< column count 1005 1B4 <<< handle to 2nd column as MTEXT entity 1005 1B5 <<< handle to 3rd column as MTEXT entity 1000 ACAD_MTEXT_COLUMNS_END 1000 ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 46 <<< group code for defined column height 1040 150.0 <<< defined column height 1000 ACAD_MTEXT_DEFINED_HEIGHT_END
The linked column MTEXT #1B4 in a compressed representation:
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (348.417876152751, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid reference column width ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 150.0 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
The linked MTEXT has no column specification except the “defined column height” in the XDATA. The reference column width is not the real value of 50.0, see XDATA group code 48 in the main MTEXT #9D, instead the total width of 175.0 is stored at group code 41. This is problem if a renderer try to render this MTEXT as a standalone entity. The renderer has to fit the content into the column width by itself and without the correct column width, this will produce an incorrect result.
There exist no back link to the main MTEXT #9D. The linked MTEXT entities appear after the main MTEXT in the layout space, but there can be other entities located between these linked MTEXT entities.
The linked column MTEXT #1B5:
0 <ctrl> MTEXT 5 <hex> #1B5 ... <snip> 100 <ctrl> AcDbMText 10 <point> (410.917876152751, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid reference column width ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 150.0 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
The MTEXT entity in DXF R2018 contains all column information in a single entity. The text content of all three columns are stored in a continuous text string, the separation into columns has to be done by the renderer. The manual column break \N is not used to indicate automatic column breaks. The MTEXT renderer has to replicate the AutoCAD/BricsCAD rendering as exact as possible to achieve the same results, which is very hard without rendering guidelines or specifications.
The example from above in DXF R2018 with a static column specification stored in an embedded object:
0 MTEXT 5 <<< entity handle 9D 102 {ACAD_XDICTIONARY 360 9F 102 } 330 <<< block record handle of owner layout 1F 100 AcDbEntity 8 <<< layer 0 100 AcDbMText 10 <<< (10, 20, 30) insert location in WCS 285.917876152751 20 276.101821192053 30 0.0 40 <<< character height in drawing units 2.5 41 <<< reference column width, if not in column mode 62.694536423841 46 <<< defined column height 150.0 71 <<< attachment point 1 72 <<< text flow direction 1 3 <<< text content of all three columns Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam n... 3 imata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit... 3 a rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lor... 3 vero eos et accusam et justo duo dolores et ea rebum. Stet clita ka... 3 eu feugiat nulla facilisis at vero eros et accumsan et iusto odio s... 3 od tincidunt ut laoreet dolore magna aliquam erat volutpat. \P\PU... 3 e velit esse molestie consequat, vel illum dolore eu feugiat nulla ... 3 obis eleifend option congue nihil imperdiet doming id quod mazim pl... 3 m ad minim veniam, quis nostrud exerci tation ullamcorper suscipit ... 3 lisis. \P\PAt vero eos et accusam et justo duo dolores et ea rebu... 3 t labore et dolore magna aliquyam erat, sed diam voluptua. At vero ... 3 litr, At accusam aliquyam diam diam dolore dolores duo eirmod eos e... 1 ipsum dolor sit amet, consetetur 73 <<< line spacing style 1 44 <<< line spacing factor 1.0 101 <<< column specification as embedded object Embedded Object 70 <<< ??? 1 10 <<< (10, 20, 30) text direction vector (local x-axis) 1.0 20 0.0 30 0.0 11 <<< (11, 21, 31) repeated insert location of AcDbMText 285.917876152751 21 276.101821192053 31 0.0 40 <<< repeated reference column width 62.694536423841 41 <<< repeated defined column height 150.0 42 <<< extents (total) width 175.0 43 <<< extents (total) height, max. height if different column heights 150.0 71 <<< column type: 0=no column; 1=static columns; 2=dynamic columns 1 72 <<< column height count 3 44 <<< column width 50.0 45 <<< column gutter width 12.5 73 <<< flag column auto height 0 74 <<< flag reversed column flow 0 1001 AcadAnnotative 1000 AnnotativeData 1002 { 1070 1 1070 0 1002 }
Example for a dynamic column specification:
0 <ctrl> MTEXT 5 <hex> #A2 <<< entity handle ... <snip> 330 <hex> #1F <<< block record handle of owner layout 100 <ctrl> AcDbEntity 8 <str> 0 <<< layer 100 <ctrl> AcDbMText 10 <point> (-133.714579865783, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 62.694536423841 <<< reference column width, if not in column mode 71 <int> 1 <<< attachment point 72 <int> 1 <<< flag text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed dia... ... <snip> 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor 1001 <ctrl> AcadAnnotative ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_COLUMN_INFO_BEGIN 1070 <int> 75 <<< column type: 2=dynamic columns 1070 <int> 2 1070 <int> 79 <<< flag column auto height 1070 <int> 1 1070 <int> 76 <<< column count 1070 <int> 3 1070 <int> 78 <<< flag column flow reversed 1070 <int> 0 1070 <int> 48 <<< column width in column mode 1040 <float> 50.0 1070 <int> 49 <<< column gutter width 1040 <float> 12.5 1000 <str> ACAD_MTEXT_COLUMN_INFO_END 1000 <str> ACAD_MTEXT_COLUMNS_BEGIN 1070 <int> 47 <<< column count 1070 <int> 3 1005 <hex> #1B6 <<< handle to 2. column as MTEXT entity 1005 <hex> #1B7 <<< handle to 3. column as MTEXT entity 1000 <str> ACAD_MTEXT_COLUMNS_END 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 158.189308131867 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
The linked column MTEXT #1B6:
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (-71.214579865783, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid column width ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 158.189308131867 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
The linked column MTEXT #1B7:
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (-8.714579865783, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid column width ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 158.189308131867 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
0 <ctrl> MTEXT 5 <hex> #A2 <<< entity handle 102 <ctrl> {ACAD_XDICTIONARY 360 <hex> #A3 102 <ctrl> } 330 <hex> #1F <<< block record handle of owner layout 100 <ctrl> AcDbEntity 8 <str> 0 <<< layer 100 <ctrl> AcDbMText 10 <point> (-133.714579865783, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 62.694536423841 <<< reference column width, if not in column mode 46 <float> 158.189308131867 <<< defined column height 71 <int> 1 <<< attachment point 72 <int> 1 <<< text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam... ... <snip> text content of all three columns 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor 101 <ctrl> Embedded Object 70 <int> 1, b00000001 <<< ??? 10 <point> (1.0, 0.0, 0.0) <<< text direction vector (local x-axis) 11 <point> (-133.714579865783, 276.101821192053, 0.0) <<< repeated insert location 40 <float> 62.694536423841 <<< repeated reference column width 41 <float> 158.189308131867 <<< repeated defined column height 42 <float> 175.0 <<< extents (total) width 43 <float> 158.189308131867 <<< extents (total) height, max. height if different column heights 71 <int> 2 <<< column type: 2=dynamic columns 72 <int> 0 <<< column height count 44 <float> 50.0 <<< column width 45 <float> 12.5 <<< column gutter width 73 <int> 1 <<< flag column auto height 74 <int> 0 <<< flag reversed column flow 1001 <ctrl> AcadAnnotative 1000 <str> AnnotativeData 1002 <str> { 1070 <int> 1 1070 <int> 0 1002 <str> }
Example for a dynamic column specification with manual height definition for three columns with different column heights. None of the (linked) MTEXT entities does contain XDATA for the defined column height.
HINT:
0 <ctrl> MTEXT 5 <hex> #9C <<< entity handle 330 <hex> #1F <<< block record handle of owner layout 100 <ctrl> AcDbEntity 8 <str> 0 <<< layer 100 <ctrl> AcDbMText 10 <point> (69.806121185863, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 62.694536423841 <<< reference column width, if not in column mode 71 <int> 1 <<< attachment point 72 <int> 1 <<< flag text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ... ... <snip> 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_COLUMN_INFO_BEGIN 1070 <int> 75 <<< column type: 2=dynamic columns 1070 <int> 2 1070 <int> 79 <<< flag column auto height 1070 <int> 0 1070 <int> 76 <<< column count 1070 <int> 3 1070 <int> 78 <<< flag column flow reversed 1070 <int> 0 1070 <int> 48 <<< column width in column mode 1040 <float> 50.0 1070 <int> 49 <<< column gutter width 1040 <float> 12.5 1070 <int> 50 <<< column height count 1070 <int> 3 1040 <float> 164.802450331126 <<< column height 1. column 1040 <float> 154.311699779249 <<< column height 2. column 1040 <float> 0.0 <<< column height 3. column, takes the rest? 1000 <str> ACAD_MTEXT_COLUMN_INFO_END 1000 <str> ACAD_MTEXT_COLUMNS_BEGIN 1070 <int> 47 <<< column count 1070 <int> 3 1005 <hex> #1B2 <<< handle to 2. column as MTEXT entity 1005 <hex> #1B3 <<< handle to 3. column as MTEXT entity 1000 <str> ACAD_MTEXT_COLUMNS_END
The linked column MTEXT #1B2:
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (132.306121185863, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid reference column width ... <snip> 73 <int> 1 44 <float> 1.0
The linked column MTEXT #1B3:
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (194.806121185863, 276.101821192053, 0.0) 40 <float> 2.5 41 <float> 175.0 <<< invalid reference column width ... <snip> 73 <int> 1 44 <float> 1.0
HINT:
0 <ctrl> MTEXT 5 <hex> #9C <<< entity handle 330 <hex> #1F 100 <ctrl> AcDbEntity 8 <str> 0 <<< block record handle of owner layout 100 <ctrl> AcDbMText 10 <point> (69.806121185863, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 62.694536423841 <<< reference column width, if not in column mode 46 <float> 0.0 <<< defined column height 71 <int> 1 <<< attachment point 72 <int> 1 <<< text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam... ... <snip> text content of all three columns 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor 101 <ctrl> Embedded Object 70 <int> 1, b00000001 <<< ??? 10 <point> (1.0, 0.0, 0.0) <<< text direction vector (local x-axis) 11 <point> (69.806121185863, 276.101821192053, 0.0) <<< repeated insert location 40 <float> 62.694536423841 <<< repeated reference column width 41 <float> 0.0 <<< repeated defined column height 42 <float> 175.0 <<< extents (total) width 43 <float> 164.802450331126 <<< extents (total) height, max. height if different column heights 71 <int> 2 <<< column type: 2=dynamic columns 72 <int> 3 <<< column height count 44 <float> 50.0 <<< column width 45 <float> 12.5 <<< column gutter width 73 <int> 0 <<< flag column auto height 74 <int> 0 <<< flag reversed column flow 46 <float> 164.802450331126 <<< column height 1. column 46 <float> 154.311699779249 <<< column height 2. column 46 <float> 0.0 <<< column height 3. column, takes the rest?
I have no idea why this column type exist, but at least provides a reliable value for the MTEXT height by the “defined column height” attribute. The column type is not stored in the MTEXT entity and is therefore not detectable!
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (-344.497343455795, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 175.0 <<< reference column width 71 <int> 1 <<< attachment point 72 <int> 1 <<< flag text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam... ... <snip> text content of all three columns 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor ... <snip> 1001 <ctrl> ACAD 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_BEGIN 1070 <int> 46 <<< defined column height 1040 <float> 158.189308131867 1000 <str> ACAD_MTEXT_DEFINED_HEIGHT_END
Does not contain an embedded object.
0 <ctrl> MTEXT ... <snip> 100 <ctrl> AcDbMText 10 <point> (-334.691900433414, 276.101821192053, 0.0) <<< insert location in WCS 40 <float> 2.5 <<< character height in drawing units 41 <float> 175.0 <<< reference column width 46 <float> 158.189308131867 <<< defined column height 71 <int> 1 <<< attachment point 72 <int> 1 <<< flag text flow direction 3 <str> Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ... ... <snip> 73 <int> 1 <<< line spacing style 44 <float> 1.0 <<< line spacing factor 1001 <ctrl> AcadAnnotative ... <snip>
TODO
A BLOCK is a layout like the modelspace or a paperspace layout, with the similarity that all these layouts are containers for graphical DXF entities. This block definition can be referenced in other layouts by the INSERT entity. By using block references, the same set of graphical entities can be located multiple times at different layouts, this block references can be stretched and rotated without modifying the original entities. A block is referenced only by its name defined by the DXF tag (2, name), there is a second DXF tag (3, name2) for the block name, which is not further documented by Autodesk, just ignore it.
The (10, base_point) tag (in BLOCK defines a insertion point of the block, by ‘inserting’ a block by the INSERT entity, this point of the block is placed at the location defined by the (10, insert) tag in the INSERT entity, and it is also the base point for stretching and rotation.
A block definition can contain INSERT entities, and it is possible to create cyclic block definitions (a BLOCK contains a INSERT of itself), but this should be avoided, CAD applications will not load the DXF file at all or maybe just crash. This is also the case for all other kinds of cyclic definitions like: BLOCK “A” -> INSERT BLOCK “B” and BLOCK “B” -> INSERT BLOCK “A”.
SEE ALSO:
Block names has to be unique and they are case insensitive (“Test” == “TEST”). If there are two or more block definitions with the same name, AutoCAD merges these blocks into a single block with unpredictable properties of all these blocks. In my test with two blocks, the final block has the name of the first block and the base-point of the second block, and contains all entities of both blocks.
In DXF R12 the definition of a block is located in the BLOCKS section, no additional structures are needed. The definition starts with a BLOCK entity and ends with a ENDBLK entity. All entities between this two entities are the content of the block, the block is the owner of this entities like any layout.
As shown in the DXF file below (created by AutoCAD LT 2018), the BLOCK entity has no handle, but ezdxf writes also handles for the BLOCK entity and AutoCAD doesn’t complain.
DXF R12 BLOCKS structure:
0 <<< start of a SECTION SECTION 2 <<< start of BLOCKS section BLOCKS ... <<< modelspace and paperspace block definitions not shown, ... <<< see layout management ... 0 <<< start of a BLOCK definition BLOCK 8 <<< layer 0 2 <<< block name ArchTick 70 <<< flags 1 10 <<< base point, x 0.0 20 <<< base point, y 0.0 30 <<< base point, z 0.0 3 <<< second BLOCK name, same as (2, name) ArchTick 1 <<< xref name, if block is an external reference <<< empty string! 0 <<< start of the first entity of the BLOCK LINE 5 28E 8 0 62 0 10 500.0 20 500.0 30 0.0 11 500.0 21 511.0 31 0.0 0 <<< start of the second entity of the BLOCK LINE ... 0.0 0 <<< ENDBLK entity, marks the end of the BLOCK definition ENDBLK 5 <<< ENDBLK gets a handle by AutoCAD, but BLOCK didn't 2F2 8 <<< as every entity, also ENDBLK requires a layer (same as BLOCK entity!) 0 0 <<< start of next BLOCK entity BLOCK ... 0 <<< end BLOCK entity ENDBLK 0 <<< end of BLOCKS section ENDSEC
The overall organization in the BLOCKS sections remains the same, but additional tags in the BLOCK entity, have to be maintained.
Especially the concept of ownership is important. Since DXF R13 every graphic entity is associated to a specific layout and a BLOCK definition is also a layout. So all entities in the BLOCK definition, including the BLOCK and the ENDBLK entities, have an owner tag (330, ...), which points to a BLOCK_RECORD entry in the BLOCK_RECORD table. This BLOCK_RECORD is the main management structure for all layouts and is the real owner of the layout entities.
As you can see in the chapter about Layout Management Structures, this concept is also valid for modelspace and paperspace layouts, because these layouts are also BLOCKS, with the special difference, that the entities of the modelspace and the active paperspace layout are stored in the ENTITIES section. [image]
SEE ALSO:
DXF R13 BLOCKS structure:
0 <<< start of a SECTION SECTION 2 <<< start of BLOCKS section BLOCKS ... <<< modelspace and paperspace block definitions not shown, ... <<< see layout management 0 <<< start of BLOCK definition BLOCK 5 <<< even BLOCK gets a handle now ;) 23A 330 <<< owner tag, the owner of a BLOCK is a BLOCK_RECORD in the ... BLOCK_RECORD table 238 100 <<< subclass marker AcDbEntity 8 <<< layer of the BLOCK definition 0 100 <<< subclass marker AcDbBlockBegin 2 <<< BLOCK name ArchTick 70 <<< flags 0 10 <<< base point, x 0.0 20 <<< base point, y 0.0 30 <<< base point, z 0.0 3 <<< second BLOCK name, same as (2, name) ArchTick 1 <<< xref name, if block is an external reference <<< empty string! 0 <<< start of the first entity of the BLOCK LWPOLYLINE 5 239 330 <<< owner tag of LWPOLYLINE 238 <<< handle of the BLOCK_RECORD! 100 AcDbEntity 8 0 6 ByBlock 62 0 100 AcDbPolyline 90 2 70 0 43 0.15 10 -0.5 20 -0.5 10 0.5 20 0.5 0 <<< ENDBLK entity, marks the end of the BLOCK definition ENDBLK 5 <<< handle 23B 330 <<< owner tag, same BLOCK_RECORD as for the BLOCK entity 238 100 <<< subclass marker AcDbEntity 8 <<< ENDBLK requires the same layer as the BLOCK entity! 0 100 <<< subclass marker AcDbBlockEnd 0 <<< start of the next BLOCK BLOCK ... 0 ENDBLK ... 0 <<< end of the BLOCKS section ENDSEC
DXF R13 BLOCK_RECORD structure:
0 <<< start of a SECTION SECTION 2 <<< start of TABLES section TABLES 0 <<< start of a TABLE TABLE 2 <<< start of the BLOCK_RECORD table BLOCK_RECORD 5 <<< handle of the table 1 330 <<< owner tag of the table 0 <<< is always #0 100 <<< subclass marker AcDbSymbolTable 70 <<< count of table entries, not reliable 4 0 <<< start of first BLOCK_RECORD entry BLOCK_RECORD 5 <<< handle of BLOCK_RECORD, in ezdxf often referred to as "layout key" 1F 330 <<< owner of the BLOCK_RECORD is the BLOCK_RECORD table 1 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbBlockTableRecord 2 <<< name of the BLOCK or LAYOUT *Model_Space 340 <<< pointer to the associated LAYOUT object 4AF 70 <<< AC1021 (R2007) block insertion units 0 280 <<< AC1021 (R2007) block explodability 1 281 <<< AC1021 (R2007) block scalability 0 ... <<< paperspace not shown ... 0 <<< next BLOCK_RECORD BLOCK_RECORD 5 <<< handle of BLOCK_RECORD, in ezdxf often referred to as "layout key" 238 330 <<< owner of the BLOCK_RECORD is the BLOCK_RECORD table 1 100 <<< subclass marker AcDbSymbolTableRecord 100 <<< subclass marker AcDbBlockTableRecord 2 <<< name of the BLOCK ArchTick 340 <<< pointer to the associated LAYOUT object 0 <<< #0, because BLOCK doesn't have an associated LAYOUT object 70 <<< AC1021 (R2007) block insertion units 0 280 <<< AC1021 (R2007) block explodability 1 281 <<< AC1021 (R2007) block scalability 0 0 <<< end of BLOCK_RECORD table ENDTAB 0 <<< next TABLE TABLE ... 0 ENDTAB 0 <<< end of TABLES section ENDESC
Layouts are separated entity spaces, there are three different Layout types:
All layouts have at least a BLOCK definition in the BLOCKS section and since DXF R13 exist the BLOCK_RECORD table with an entry for every BLOCK in the BLOCKS section.
SEE ALSO:
The name of the modelspace BLOCK is “*Model_Space” (DXF R12: “$MODEL_SPACE”) and the name of the active paperspace BLOCK is “*Paper_Space” (DXF R12: “$PAPER_SPACE”), the entities of these two layouts are stored in the ENTITIES section, DXF R12 supports just one paperspace layout.
DXF R13+ supports multiple paperspace layouts, the active layout is still called “*Paper_Space”, the additional inactive paperspace layouts are named by the scheme “*Paper_Spacennnn”, where the first inactive paper space is called “*Paper_Space0”, the second “*Paper_Space1” and so on. A none consecutive numbering is tolerated by AutoCAD. The content of the inactive paperspace layouts are stored as BLOCK content in the BLOCKS section. These names are just the DXF internal layout names, each layout has an additional layout name which is displayed to the user by the CAD application.
A BLOCK definition and a BLOCK_RECORD is not enough for a proper layout setup, an LAYOUT entity in the OBJECTS section is also required. All LAYOUT entities are managed by a DICTIONARY entity, which is referenced as “ACAD_LAYOUT” entity in the root DICTIONARY of the DXF file.
NOTE:
Since DXF R2000 modelspace and paperspace layouts require the DXF LAYOUT entity.
0 LAYOUT 5 <<< handle 59 102 <<< extension dictionary (ignore) {ACAD_XDICTIONARY 360 1C3 102 } 102 <<< reactor (required?) {ACAD_REACTORS 330 1A <<< pointer to "ACAD_LAYOUT" DICTIONARY (layout management table) 102 } 330 <<< owner handle 1A <<< pointer to "ACAD_LAYOUT" DICTIONARY (same as reactor pointer) 100 <<< PLOTSETTINGS AcDbPlotSettings 1 <<< page setup name 2 <<< name of system printer or plot configuration file none_device 4 <<< paper size, part in braces should follow the schema ... (width_x_height_unit) unit is 'Inches' or 'MM' ... Letter\_(8.50_x_11.00_Inches) the part in front of the braces is ... ignored by AutoCAD 6 <<< plot view name 40 <<< size of unprintable margin on left side of paper in millimeters, ... defines also the plot origin-x 6.35 41 <<< size of unprintable margin on bottom of paper in millimeters, ... defines also the plot origin-y 6.35 42 <<< size of unprintable margin on right side of paper in millimeters 6.35 43 <<< size of unprintable margin on top of paper in millimeters 6.35 44 <<< plot paper size: physical paper width in millimeters 215.90 45 <<< plot paper size: physical paper height in millimeters 279.40 46 <<< X value of plot origin offset in millimeters, moves the plot origin-x 0.0 47 <<< Y value of plot origin offset in millimeters, moves the plot origin-y 0.0 48 <<< plot window area: X value of lower-left window corner 0.0 49 <<< plot window area: Y value of lower-left window corner 0.0 140 <<< plot window area: X value of upper-right window corner 0.0 141 <<< plot window area: Y value of upper-right window corner 0.0 142 <<< numerator of custom print scale: real world (paper) units, 1.0 ... for scale 1:50 1.0 143 <<< denominator of custom print scale: drawing units, 50.0 ... for scale 1:50 1.0 70 <<< plot layout flags, bit-coded (... too many options) 688 <<< b1010110000 = UseStandardScale(16)/PlotPlotStyle(32) ... PrintLineweights(128)/DrawViewportsFirst(512) 72 <<< plot paper units (0/1/2 for inches/millimeters/pixels), are ... pixels really supported? 0 73 <<< plot rotation (0/1/2/3 for 0deg/90deg counter-cw/upside-down/90deg cw) 1 <<< 90deg clockwise 74 <<< plot type 0-5 (... too many options) 5 <<< 5 = layout information 7 <<< current plot style name, e.g. 'acad.ctb' or 'acadlt.ctb' 75 <<< standard scale type 0-31 (... too many options) 16 <<< 16 = 1:1, also 16 if user scale type is used 147 <<< unit conversion factor 1.0 <<< for plot paper units in mm, else 0.03937... (1/25.4) for inches ... as plot paper units 76 <<< shade plot mode (0/1/2/3 for as displayed/wireframe/hidden/rendered) 0 <<< as displayed 77 <<< shade plot resolution level 1-5 (... too many options) 2 <<< normal 78 <<< shade plot custom DPI: 100-32767, Only applied when shade plot ... resolution level is set to 5 (Custom) 300 148 <<< paper image origin: X value 0.0 149 <<< paper image origin: Y value 0.0 100 <<< LAYOUT settings AcDbLayout 1 <<< layout name Layout1 70 <<< flags bit-coded 1 <<< 1 = Indicates the PSLTSCALE value for this layout when this ... layout is current 71 <<< Tab order ("Model" tab always appears as the first tab ... regardless of its tab order) 1 10 <<< minimum limits for this layout (defined by LIMMIN while this ... layout is current) -0.25 <<< x value, distance of the left paper margin from the plot ... origin-x, in plot paper units and by scale (e.g. x50 for 1:50) 20 <<< group code for y value -0.25 <<< y value, distance of the bottom paper margin from the plot ... origin-y, in plot paper units and by scale (e.g. x50 for 1:50) 11 <<< maximum limits for this layout (defined by LIMMAX while this ... layout is current) 10.75 <<< x value, distance of the right paper margin from the plot ... origin-x, in plot paper units and by scale (e.g. x50 for 1:50) 21 <<< group code for y value 8.25 <<< y value, distance of the top paper margin from the plot ... origin-y, in plot paper units and by scale (e.g. x50 for 1:50) 12 <<< insertion base point for this layout (defined by INSBASE while ... this layout is current) 0.0 <<< x value 22 <<< group code for y value 0.0 <<< y value 32 <<< group code for z value 0.0 <<< z value 14 <<< minimum extents for this layout (defined by EXTMIN while this ... layout is current), AutoCAD default is (1e20, 1e20, 1e20) 1.05 <<< x value 24 <<< group code for y value 0.80 <<< y value 34 <<< group code for z value 0.0 <<< z value 15 <<< maximum extents for this layout (defined by EXTMAX while this ... layout is current), AutoCAD default is (-1e20, -1e20, -1e20) 9.45 <<< x value 25 <<< group code for y value 7.20 <<< y value 35 <<< group code for z value 0.0 <<< z value 146 <<< elevation ??? 0.0 13 <<< UCS origin (3D Point) 0.0 <<< x value 23 <<< group code for y value 0.0 <<< y value 33 <<< group code for z value 0.0 <<< z value 16 <<< UCS X-axis (3D vector) 1.0 <<< x value 26 <<< group code for y value 0.0 <<< y value 36 <<< group code for z value 0.0 <<< z value 17 <<< UCS Y-axis (3D vector) 0.0 <<< x value 27 <<< group code for y value 1.0 <<< y value 37 <<< group code for z value 0.0 <<< z value 76 <<< orthographic type of UCS 0-6 (... too many options) 0 <<< 0 = UCS is not orthographic ??? 330 <<< ID/handle of required block table record 58 331 <<< ID/handle to the viewport that was last active in this layout ... when the layout was current 1B9 1001 <<< extended data (ignore) ...
And as it seems this is also not enough for a well defined LAYOUT, at least a “main” VIEWPORT entity with ID=1 is required for paperspace layouts, located in the entity space of the layout.
The modelspace layout requires (?) a VPORT entity in the VPORT table (group code 331 in the AcDbLayout subclass).
The “main” viewport for layout “Layout1” shown above. This viewport is located in the associated BLOCK definition called “*Paper_Space0”. Group code 330 in subclass AcDbLayout points to the BLOCK_RECORD of “*Paper_Space0”.
Remember: the entities of the active paperspace layout are located in the ENTITIES section, therefore “Layout1” is not the active paperspace layout.
The “main” VIEWPORT describes, how the application shows the paperspace layout on the screen, and I guess only AutoCAD needs this values. [image]
0 VIEWPORT 5 <<< handle 1B4 102 <<< extension dictionary (ignore) {ACAD_XDICTIONARY 360 1B5 102 } 330 <<< owner handle 58 <<< points to BLOCK_RECORD (same as group code 330 in AcDbLayout of ... "Layout1") 100 AcDbEntity 67 <<< paperspace flag 1 <<< 0 = modelspace; 1 = paperspace 8 <<< layer, 0 100 AcDbViewport 10 <<< Center point (in WCS) 5.25 <<< x value 20 <<< group code for y value 4.00 <<< y value 30 <<< group code for z value 0.0 <<< z value 40 <<< width in paperspace units 23.55 <<< VIEW size in AutoCAD, depends on the workstation configuration 41 <<< height in paperspace units 9.00 <<< VIEW size in AutoCAD, depends on the workstation configuration 68 <<< viewport status field -1/0/n 2 <<< >0 On and active. The value indicates the order of stacking for ... the viewports, where 1 is the active viewport, 2 is the next, and so forth 69 <<< viewport ID 1 <<< "main" viewport has always ID=1 12 <<< view center point in Drawing Coordinate System (DCS), defines ... the center point of the VIEW in relation to the LAYOUT origin 5.25 <<< x value 22 <<< group code for y value 4.00 <<< y value 13 <<< snap base point in modelspace 0.0 <<< x value 23 <<< group code for y value 0.0 <<< y value 14 <<< snap spacing in modelspace units 0.5 <<< x value 24 <<< group code for y value 0.5 <<< y value 15 <<< grid spacing in modelspace units 0.5 <<< x value 25 <<< group code for y value 0.5 <<< y value 16 <<< view direction vector from target (in WCS) 0.0 <<< x value 26 <<< group code for y value 0.0 <<< y value 36 <<< group code for z value 1.0 <<< z value 17 <<< view target point 0.0 <<< x value 27 <<< group code for y value 0.0 <<< y value 37 <<< group code for z value 0.0 <<< z value 42 <<< perspective lens length, focal length? 50.0 <<< 50mm 43 <<< front clip plane z value 0.0 <<< z value 44 <<< back clip plane z value 0.0 <<< z value 45 <<< view height (in modelspace units) 9.00 50 <<< snap angle 0.0 51 <<< view twist angle 0.0 72 <<< circle zoom percent 1000 90 <<< Viewport status bit-coded flags (... too many options) 819232 <<< b11001000000000100000 1 <<< plot style sheet name assigned to this viewport 281 <<< render mode (... too many options) 0 <<< 0 = 2D optimized (classic 2D) 71 <<< UCS per viewport flag 1 <<< 1 = This viewport stores its own UCS which will become the ... current UCS whenever the viewport is activated 74 <<< Display UCS icon at UCS origin flag 0 <<< this field is currently being ignored and the icon always ... represents the viewport UCS 110 <<< UCS origin (3D point) 0.0 <<< x value 120 <<< group code for y value 0.0 <<< y value 130 <<< group code for z value 0.0 <<< z value 111 <<< UCS X-axis (3D vector) 1.0 <<< x value 121 <<< group code for y value 0.0 <<< y value 131 <<< group code for z value 0.0 <<< z value 112 <<< UCS Y-axis (3D vector) 0.0 <<< x value 122 <<< group code for y value 1.0 <<< y value 132 <<< group code for z value 0.0 <<< z value 79 <<< Orthographic type of UCS (... too many options) 0 <<< 0 = UCS is not orthographic 146 <<< elevation 0.0 170 <<< shade plot mode (0/1/2/3 for as displayed/wireframe/hidden/rendered) 0 <<< as displayed 61 <<< frequency of major grid lines compared to minor grid lines 5 <<< major grid subdivided by 5 348 <<< visual style ID/handle (optional) 9F 292 <<< default lighting flag, on when no user lights are specified. 1 282 <<< Default lighting type (0/1 = one distant light/two distant lights) 1 <<< one distant light 141 <<< view brightness 0.0 142 <<< view contrast 0.0 63 <<< ambient light color (ACI), write only if not black color 250 421 <<< ambient light color (RGB), write only if not black color 3355443
A collection of AutoCAD behaviors determined experimentally. There may be mistakes and misunderstandings of the inner workings of the algorithms. Not all edge cases may have been considered.
Information about ezdxf internals.
Reformat code by Black with the default setting of 88 characters per line:
C:\> black <python-file>
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
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 !!!
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
DXF entities and objects can have different states:
Loading a DXF document from an external source, creates a new Drawing object. This loading process has two stages:
Parse SectionDict:
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().
The default constructor of each entity type creates a new virtual entity:
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:
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:
SEE ALSO:
The Modelspace, any Paperspace layout and BlockLayout objects have an EntitySpace container to store their entities.
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.
Required DXF tag interface:
Returns: DXFTag or inherited
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.
Collection of DXFTag as flat list. Low level tag container, only required for advanced stuff.
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.
Assumes that no XDATA block with the same appid already exist:
try: xdata = tags.get_xdata('EZDXF') except ValueError: xdata = tags.new_xdata('EZDXF')
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)
Store DXF tags in compact data structures as list or array.array to reduce memory usage.
SEE ALSO:
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.
Returns: list of DXFTags including list name and curly braces ‘{’ ‘}’ tags
Low level interface, if not sure use set_xdata_list() instead.
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:
Both AppIDs are not defined/stored in the AppID table!
SEE ALSO:
SEE ALSO:
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
e = ExampleCls(flag=True)
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:
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.
Manfred Moitzi
2011-2023, Manfred Moitzi
November 25, 2023 | 1.1.3 |