Provided by: python3-ezdxf_1.1.3-1_all bug

NAME

       ezdxf - ezdxf Documentation [image]

       Welcome! This is the documentation for ezdxf release 1.1.3, last updated Nov 25, 2023.

       • ezdxf is a Python package to create new DXF documents and read/modify/write existing DXF documents

       • MIT-License

       • the intended audience are programmers

       • requires at least Python 3.8

       • OS independent

       • tested with CPython and pypy3

       • has type annotations and passes mypy --ignore-missing-imports -p ezdxf successful

       • additional required packages for the core package without add-ons: typing_extensions, pyparsing, numpy,
         fontTools

       • read/write/new support for DXF versions: R12, R2000, R2004, R2007, R2010, R2013 and R2018

       • additional read-only support for DXF versions R13/R14 (upgraded to R2000)

       • additional read-only support for older DXF versions than R12 (upgraded to R12)

       • read/write support for ASCII DXF and Binary DXF

       • retains third-party DXF content

       • optional  C-extensions  for  CPython  are included in the binary wheels, available on PyPI for Windows,
         Linux and macOS

INCLUDED EXTENSIONS

       Additional packages required for these add-ons are not automatically installed during  the  basic  setup,
       for more information about the setup & dependencies visit the documentation.

       • drawing add-on to visualise and convert DXF files to images which can be saved as PNG, PDF or SVG files

       • r12writer add-on to write basic DXF entities direct and fast into a DXF R12 file or stream

       • iterdxf  add-on to iterate over DXF entities from the modelspace of huge DXF files (> 5GB) which do not
         fit into memory

       • importer add-on to import entities, blocks and table entries from another DXF document

       • dxf2code add-on to generate Python code for DXF structures loaded from DXF documents as starting  point
         for parametric DXF entity creation

       • acadctb add-on to read/write Plot Style Files (CTB/STB)pycsg add-on for Constructive Solid Geometry (CSG) modeling technique

       • MTextExplode add-on for exploding MTEXT entities into single-line TEXT entities

       • text2path add-on to convert text into outline paths

       • geo add-on to support the __geo_interface__meshex add-on for exchanging meshes with other tools as STL, OFF or OBJ files

       • openscad  add-on, an interface to OpenSCADodafc add-on, an interface to the ODA File Converter to read and write DWG files

       • hpgl2 add-on for converting HPGL/2 plot files to DXF, SVG and PDF

WEBSITE

       https://ezdxf.mozman.at/

DOCUMENTATION

       Documentation of development version at https://ezdxf.mozman.at/docs

       Documentation of latest release at http://ezdxf.readthedocs.io/

KNOWLEDGE GRAPH

       The  Knowledge  Graph  contains additional information beyond the documentation and is managed by logseq.
       The source data is included in the repository in the folder ezdxf/notes.  There is also a HTML export  on
       the website which gets regular updates.

RELEASE NOTES

       The release notes are included in the Knowledge Graph.

CHANGELOG

       The changelog is included in the Knowledge Graph.

SOURCE CODE & FEEDBACK

       Source Code: http://github.com/mozman/ezdxf.git

       Issue Tracker: http://github.com/mozman/ezdxf/issues

       Forum: https://github.com/mozman/ezdxf/discussions

QUESTIONS AND ANSWERS

       Please post questions at the forum or stack overflow to make answers available to other users as well.

INTRODUCTION

   What is ezdxf
       Ezdxf   is  a  Python interface to the DXF (drawing interchange file) format developed by Autodesk, ezdxf
       allows developers to read and modify existing DXF documents or create new DXF documents.

       The main objective in the development of ezdxf was to hide complex DXF details from  the  programmer  but
       still  support most capabilities of the DXF format. Nevertheless, a basic understanding of the DXF format
       is required, also to understand which tasks and goals are possible to accomplish by using the DXF format.

       Not all DXF features are supported yet, but additional features will be added in the future gradually.

       Ezdxf is also a replacement for the outdated dxfwrite and dxfgrabber packages but  with  different  APIs,
       for more information see also: What is the Relationship between ezdxf, dxfwrite and dxfgrabber?

   What ezdxf can’t doezdxf  is not a DXF converter: ezdxf can not convert between different DXF versions, if you are looking
         for an appropriate application, try the free ODAFileConverter from  the  Open  Design  Alliance,  which
         converts between different DXF version and also between the DXF and the DWG file format.

       • ezdxf  is not a CAD file format converter: ezdxf can not convert DXF files to other CAD formats such as
         DWG

       • ezdxf is not a CAD kernel and does not provide high level functionality for construction  work,  it  is
         just  an  interface  to  the DXF file format. If you are looking for a CAD kernel with Python scripting
         support, look at FreeCAD.

   Supported Python Versions
       Ezdxf requires at least Python 3.8 (determined by numpy) and  will  be  tested  with  the  latest  stable
       CPython version and the latest stable release of pypy3 during development.

       Ezdxf  is  written in pure Python with optional Cython implementations of some low level math classes and
       requires pyparsing, numpy, fontTools and  typing_extensions  as  additional  library  beside  the  Python
       Standard  Library.   Pytest is required to run the unit and integration tests. Data to run the stress and
       audit test can not be provided, because I don’t have the rights for publishing these DXF files.

   Supported Operating Systems
       Ezdxf is OS independent and runs on  all  platforms  which  provide  an  appropriate  Python  interpreter
       (>=3.8).

   Supported DXF Versions
                                          ──────────────────────────────────
                                            Version   AutoCAD Release
                                          ──────────────────────────────────
                                            AC1009    AutoCAD R12
                                          ──────────────────────────────────
                                            AC1012    AutoCAD R13 -> R2000
                                          ──────────────────────────────────
                                            AC1014    AutoCAD R14 -> R2000
                                          ──────────────────────────────────
                                            AC1015    AutoCAD R2000
                                          ──────────────────────────────────
                                            AC1018    AutoCAD R2004
                                          ──────────────────────────────────
                                            AC1021    AutoCAD R2007
                                          ──────────────────────────────────
                                            AC1024    AutoCAD R2010
                                          ──────────────────────────────────
                                            AC1027    AutoCAD R2013
                                          ──────────────────────────────────
                                            AC1032    AutoCAD R2018
                                          ┌─────────┬──────────────────────┐
                                          │         │                      │
       Ezdxf also reads older DXF versions│but saves│it as DXF R12.        │
                                          │         │                      │
--
SETUP & DEPENDENCIES                      │         │                      │
--

USAGE FOR BEGINNERS

       This  section shows the intended usage of the ezdxf package.  This is just a brief overview for new ezdxf
       users, follow the provided links for more detailed information.

       First import the package:

          import ezdxf

   Loading DXF Files
       ezdxf supports loading ASCII and binary DXF documents from a file:

          doc = ezdxf.readfile(filename)

       or from a zip-file:

          doc = ezdxf.readzip(zipfilename[, filename])

       Which loads the DXF document filename from the zip-file zipfilename or the first DXF file in the zip-file
       if filename is absent.

       It is also possible to read a DXF document from a stream by the ezdxf.read() function, but this is a more
       advanced feature, because this requires detection of the file encoding in advance.

       This works well with DXF documents from trusted sources  like  AutoCAD  or  BricsCAD.   For  loading  DXF
       documents with minor or major flaws use the ezdxf.recover module.

       SEE ALSO:
          Documentation  for ezdxf.readfile(), ezdxf.readzip() and ezdxf.read(), for more information about file
          management go to the Document Management section. For loading DXF  documents  with  structural  errors
          look at the ezdxf.recover module.

   Layouts and Blocks
       Layouts  are containers for DXF entities like LINE or CIRCLE. The most important layout is the modelspace
       labeled as “Model” in CAD applications which  represents  the  “world”  work  space.  Paperspace  layouts
       represents plottable sheets which contains often the framing and the tile block of a drawing and VIEWPORT
       entities as scaled and clipped “windows” into the modelspace.

       The  modelspace is always present and can not be deleted. The active paperspace is also always present in
       a new DXF document but can be deleted, in that  case  another  paperspace  layout  gets  the  new  active
       paperspace, but you can not delete the last paperspace layout.

       Getting the modelspace of a DXF document:

          msp = doc.modelspace()

       Getting a paperspace layout by the name as shown in the tab of a CAD application:

          psp = doc.paperspace("Layout1")

       A block is just another kind of entity space, which can be inserted multiple times into other layouts and
       blocks  by  the  INSERT  entity  also  called  block references, this is a very powerful and an important
       concept of the DXF format.

       Getting a block layout by the block name:

          blk = doc.blocks.get("NAME")

       All these layouts have factory functions to create graphical DXF entities for  their  entity  space,  for
       more information about creating entities see section: Create new DXF Entities

   Query DXF Entities
       As  said  in  the Layouts and Blocks section, all graphical DXF entities are stored in layouts, all these
       layouts can be iterated and do support the index operator e.g. layout[-1] returns the last entity.

       The main difference between iteration and index access is, that iteration filters destroyed entities, but
       the index operator returns also destroyed entities until these entities  are  purged  by  layout.purge(),
       more about this topic in section: Delete Entities.

       There are two advanced query methods: query() and groupby().

       Get all lines of layer "MyLayer":

          lines = msp.query('LINE[layer=="MyLayer"]')

       This returns an EntityQuery container, which also provides the same query() and groupby() methods.

       Get all lines categorized by a DXF attribute like color:

          all_lines_by_color = msp.query("LINE").groupby("color")
          lines_with_color_1 = all_lines_by_color.get(1, [])

       The  groupby()  method  returns  a  regular  Python  dict with colors as key and a regular Python list of
       entities as values (not an EntityQuery container).

       SEE ALSO:
          For more information go to the Tutorial for Getting Data from DXF Files

   Examine DXF Entities
       Each DXF entity has a dxf namespace attribute,  which  stores  the  named  DXF  attributes,  some  entity
       attributes and assets are only available from Python properties or methods outside the dxf namespace like
       the vertices of the LWPOLYLINE entity. More information about the DXF attributes of each entity can found
       in the documentation of the ezdxf.entities module.

       Get some basic DXF attributes:

          layer = entity.dxf.layer  # default is "0"
          color = entity.dxf.color  # default is 256 = BYLAYER

       Most DXF attributes have a default value, which will be returned if the DXF attribute is not present, for
       DXF attributes without a default value you can check if the attribute really exist:

          entity.dxf.hasattr("true_color")

       or use the get() method and provide a default value:

          entity.dxf.get("true_color", 0)

       SEE ALSO:Common graphical DXF attributes

          • Helper class ezdxf.gfxattribs.GfxAttribs for building DXF attribute dictionaries.

   Create a New DXF File
       Create new document for the latest supported DXF version:

          doc = ezdxf.new()

       Create a new DXF document for a specific DXF version, e.g. for DXF R12:

          doc = ezdxf.new("R12")

       The  ezdxf.new()  function  can  create  some  standard  resources, such as linetypes and text styles, by
       setting the argument setup to True:

          doc = ezdxf.new(setup=True)

       SEE ALSO:Tutorial for Creating DXF Drawings

          • Documentation for ezdxf.new(), for more  information  about  file  management  go  to  the  Document
            Management section.

   Create New DXF Entities
       The factory methods for creating new graphical DXF entities are located in the BaseLayout class and these
       factory methods are available for all entity containers:

          • ModelspacePaperspaceBlockLayout

       The usage is simple:

          msp = doc.modelspace()
          msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "MyLayer"})

       A few important/required DXF attributes are explicit method arguments, most additional DXF attributes are
       gives  as  a  regular  Python  dict  object  by  the keyword only argument dxfattribs.  The supported DXF
       attributes can be found in the documentation of the ezdxf.entities module.

       WARNING:
          Do not instantiate DXF entities by yourself and add them to layouts, always use the  provided  factory
          methods to create new graphical entities, this is the intended way to use ezdxf.

       SEE ALSO:Thematic Index of Layout Factory MethodsTutorial for Creating DXF DrawingsTutorial for Simple DXF EntitiesTutorial for LWPolylineTutorial for TextTutorial for MText and MTextEditorTutorial for Hatch

   Saving DXF Files
       Save the DXF document with a new name:

          doc.saveas("new_name.dxf")

       or with the same name as loaded:

          doc.save()

       SEE ALSO:
          Documentation   for   ezdxf.document.Drawing.save()   and  ezdxf.document.Drawing.saveas(),  for  more
          information about file management go to the Document Management section.

   Create New Blocks
       The block definitions of a DXF document are managed by the BlocksSection object:

          my_block = doc.blocks.new("MyBlock")

       SEE ALSO:
          Tutorial for Blocks

   Create Block References
       A block reference is just another DXF entity called INSERT.  The Insert entity is created by the  factory
       method: add_blockref():

          msp.add_blockref("MyBlock", (0, 0))

       SEE ALSO:
          See Tutorial for Blocks for more advanced features like using Attrib entities.

   Create New Layers
       A  layer  is  not an entity container, a layer is just another DXF attribute stored in the entity and the
       entity can inherit some properties from this Layer object.  Layer objects are stored in the  layer  table
       which is available as attribute doc.layers.

       You can create your own layers:

          my_layer = doc.layers.add("MyLayer")

       The  layer  object also controls the visibility of entities which references this layer, the on/off state
       of the layer is unfortunately stored as positive or negative color value which make the raw DXF attribute
       of layers useless, to change the color of a layer use the property Layer.color

          my_layer.color = 1

       To change the state of a layer use the provided methods of the Layer object, like on(),  off(),  freeze()
       or thaw():

          my_layer.off()

       SEE ALSO:
          Layers

   Delete Entities
       The safest way to delete entities is to delete the entity from the layout containing that entity:

          line = msp.add_line((0, 0), (1, 0))
          msp.delete_entity(line)

       This  removes  the  entity  immediately  from  the layout and destroys the entity.  The property is_alive
       returns False for a destroyed entity and all Python attributes are deleted, so line.dxf.color will  raise
       an AttributeError exception, because line does not have a dxf attribute anymore.

       Ezdxf also supports manually destruction of entities by calling the method destroy():

          line.destroy()

       Manually  destroyed  entities  are  not  removed  immediately from entities containers like Modelspace or
       EntityQuery, but iterating such a container will filter destroyed entities automatically, so a for  e  in
       msp:  ...  loop  will  never  yield  destroyed entities. The index operator and the len() function do not
       filter deleted entities, to avoid getting deleted entities call  the  purge()  method  of  the  container
       manually to remove deleted entities.

   Further InformationReference

BASIC CONCEPTS

       The  Basic  Concepts section teach the intended meaning of DXF attributes and structures without teaching
       the application of this information or the specific implementation by ezdxf, if you are looking for  more
       information  about  the  ezdxf internals look at the Reference section or if you want to learn how to use
       ezdxf go to the Tutorials section and for the solution of specific problems go to the Howto section.

   What is DXF?
       The common assumption is also the cite of Wikipedia:
          AutoCAD DXF (Drawing eXchange Format) is a CAD data file format developed  by  Autodesk  for  enabling
          data interoperability between AutoCAD and other applications.

          DXF  was originally introduced in December 1982 as part of AutoCAD 1.0, and was intended to provide an
          exact representation of the data in the AutoCAD native file format,  DWG  (Drawing).  For  many  years
          Autodesk  did  not  publish specifications making correct imports of DXF files difficult. Autodesk now
          publishes the DXF specifications online.

       The more precise cite from the DXF reference itself:
          The DXF™ format is a tagged data representation of  all  the  information  contained  in  an  AutoCAD®
          drawing  file.  Tagged  data means that each data element in the file is preceded by an integer number
          that is called a group code. A group code’s value indicates what type of data  element  follows.  This
          value also indicates the meaning of a data element for a given object (or record) type.  Virtually all
          user-specified information in a drawing file can be represented in DXF format.

       No mention of interoperability between AutoCAD and other applications.

       In  reality  the DXF format was designed to ensure AutoCAD cross-platform compatibility in the early days
       when different hardware platforms with different binary data formats were used.  The  name  DXF  (Drawing
       eXchange  Format)  may  suggest  an  universal  exchange  format,  but  it  is  not.  It  is based on the
       infrastructure installed by Autodesk products (fonts) and the implementation details of  AutoCAD  (MTEXT)
       or on licensed third party technologies (embedded ACIS entities).

       For  more  information  about  the AutoCAD history see the document: The Autodesk File - Bits of History,
       Words of Experience by John Walker, founder of Autodesk, Inc. and co-author of AutoCAD.

   DXF Reference Quality
       The DXF reference is by far no specification nor a standard like the W3C standard  for  SVG  or  the  ISO
       standard for PDF.

       The  reference  describes many but not all DXF entities and some basic concepts like the tag structure or
       the arbitrary axis algorithm.  But the  existing  documentation  (reference)  is  incomplete  and  partly
       misleading  or  wrong.  Also  missing  from  the  reference  are  some  important  parts like the complex
       relationship between the entities to create higher  order  structures  like  block  definitions,  layouts
       (model space & paper space) or dynamic blocks to name a few.

   Reliable CAD Applications
       Because of the suboptimal quality of the DXF reference not all DXF viewers, creators or processors are of
       equal  quality.  I  consider a CAD application as a reliable CAD application when the application creates
       valid DXF documents in the meaning and interpretation of Autodesk and a  reliable  DXF  viewer  when  the
       result matches in most parts the result of the free Trueview viewer provided by Autodesk.

       These are some applications which do fit the criteria of a reliable CAD application:

       • AutoCAD and Trueview

       • CAD applications based on the OpenDesignAlliance (ODA) SDK, see also ODA on wikipedia, even Autodesk is
         a  corporate member, see their blog post from 22 Sep 2020 at adsknews but only to use the ODA IFC tools
         and not to improve the DWG/DXF compatibility

       • BricsCAD (ODA based)

       • GstarCAD (ODA based)

       • ZWCAD (ODA based)

       Unfortunately, I cannot recommend any open source  applications  because  everyone  I  know  has  serious
       shortcomings,  at least as a DXF viewer, and I don’t trust them as a DXF creator either. To be clear, not
       even ezdxf (which is not a CAD application) is a reliable library in this sense - it just  keeps  getting
       better, but is far from reliable.

       HINT:
          Please  do  not  submit bug reports based on the use of LibreCAD or QCAD, these applications are in no
          way reliable regarding the DXF format and I will not waste my time on them.

   DXF Entities and Objects
       DXF entities are objects that make up the design data stored in a DXF file.

   Graphical Entities
       Graphical entities are visible  objects  stored  in  blocks,  modelspace-  or  paperspace  layouts.  They
       represent the various shapes, lines, and other elements that make up a 2D or 3D design.

       Some common types of DXF entities include:

       • LINE  and  POLYLINE:  These  are  the  basic building blocks of a DXF file. They represent straight and
         curved lines.

       • CIRCLE and ARC: These entities represent circles and portions of circles, respectively.

       • TEXT and MTEXT: DXF files can also contain text entities, which can be  used  to  label  parts  of  the
         design or provide other information.

       • HATCH:  DXF  files  can  also  include  hatch patterns, which are used to fill in areas with a specific
         pattern or texture.

       • DIMENSION: DXF files can also contain dimension entities, which provide  precise  measurements  of  the
         various elements in a design.

       • INSERT:  A block is a group of entities that can be inserted into a design multiple times by the INSERT
         entity, making it a useful way to reuse elements of a design.

       These entities are defined using specific codes and values in the  DXF  file  format,  and  they  can  be
       created and manipulated by ezdxf.

   Objects
       DXF objects are non-graphical entities and have no visual representation, they store administrative data,
       paperspace  layout definitions, style definitions for multiple entity types, custom data and objects. The
       OBJECTS section in DXF files serves as a container for these non-graphical objects.

       Some common DXF types of DXF objects include:

       • DICTIONARY: A dictionary object consists of a series of name-value pairs, where the name  is  a  string
         that  identifies  a specific object within the dictionary, and the value is a reference to that object.
         The objects themselves can be any type of DXF entity or custom object defined in the DXF file.

       • XRECORD entities are used to store custom application data in a DXF file.

       • the LAYOUT entity is a DXF entity that represents a single paper space layout  in  a  DXF  file.  Paper
         space  is the area in a CAD drawing that represents the sheet of paper or other physical media on which
         the design will be plotted or printed.

       • MATERIAL, MLINESTYLE, MLEADERSTYLE definitions stored in certain DICTIONARY objects.

       • A GROUP entity contains a list of handles that refer to other DXF entities in the drawing. The entities
         in the group can be of any type, including entities from the model space or paper space layouts.

   TagStorage
       The ezdxf package supports many but not all entity types, all  these  unsupported  types  are  stored  as
       TagStorage instances to preserve their data when exporting the edited DXF content by ezdxf.

   Access Entity Attributes
       All DXF attributes are stored in the entity namespace attribute dxf.

          print(entity.dxf.layer)

       Some  attributes  are mandatory others are optional in most cases a reasonable values will be returned as
       default value if the attribute is missing.

       SEE ALSO:
          Tutorial for Getting Data from DXF Files

   Where to Look for Entities
       The DXF document has an entity database where all entities which have a handle  are  stored  in  a  (key,
       value) storage. The query() method is often the easiest way to request data:

          for text in doc.entitydb.query("TEXT"):
              print(text.dxf.text)

       SEE ALSO:ezdxf.query module

          • ezdxf.entitydb module

       Graphical entities are stored in blocks, the modelspace or paperspace layouts.

       • The doc.modelspace() function returns the Modelspace instance

       • The doc.paperspace() returns a Paperspace instance

       • The doc.blocks attribute provides access to the BlocksSection

       The  query() method of the Drawing class which represents the DXF document, runs the query on all layouts
       and block definitions.

       Non-graphical entities are stored in the OBJECTS section:

       • The doc.objects attribute provides access to the ObjectsSection.

       Resource definitions like Layer, Linetype or Textstyle are stored in resource tables:

       • doc.layers: the LayerTabledoc.linetypes: the LinetypeTabledoc.styles: the TextstyleTabledoc.dimstyles: the DimStyleTable

       IMPORTANT:
          A layer assignment is just an attribute of a DXF entity, it’s not an entity container!

       SEE ALSO:

          • Basic concept of the Modelspace

          • Basic concept of Paperspace layouts

          • Basic concept of BlocksTutorial for Getting Data from DXF Files

   How to Create Entities
       The recommended way to create new DXF entities is to use the factory methods of  layouts  and  blocks  to
       create entities and add them to the entity space automatically.

       SEE ALSO:Thematic Index of Layout Factory Methods

          • Reference of the BaseLayout class

          • Tutorial for Simple DXF Entities

   AutoCAD Color Index (ACI)
       The  color  attribute  represents  an  ACI (AutoCAD Color Index).  AutoCAD and many other CAD application
       provides a default color table, but pen table would be the more correct term.  Each ACI entry defines the
       color value, the line weight and some other attributes to use for the pen. This pen table can  be  edited
       by  the  user  or  loaded  from an CTB or STB file.  Ezdxf provides functions to create (new()) or modify
       (ezdxf.acadctb.load()) plot styles files.

       DXF R12 and prior do not preserve the layout of a drawing very well, because of the lack  of  a  standard
       color  table  and  missing  DXF  structures  to define these color tables in the DXF file.  If a CAD user
       redefines an ACI color entry in a CAD application and does not provide this CTB or STB file, you can  not
       know  what  color  or  lineweight  was  used  intentionally.   This  got  better in later DXF versions by
       supporting additional DXF attributes like lineweight and true_color which can define these attributes  by
       distinct values.  [image]

       SEE ALSO:Plot Style Files (CTB/STB)ezdxf.colorsTutorial for Common Graphical Attributes

          • Autodesk Knowledge Network: About Setting the Color of Objects

          • BricsCAD Help Center: Entity Color

   True Color
       The  support for true color was added to the DXF file format in revision R2004.  The true color value has
       three components red, green and blue in the range from 0 to 255 and is stored as a 24-bit  value  in  the
       DXF  namespace  as true_color attribute and looks like this 0xRRGGBB as hex value.  For a more easy usage
       all graphical entities support the rgb property to get and set the true color as (r, g, b)  tuples  where
       the components must be in the range from 0 to 255.

          import ezdxf

          doc = ezdxf.new()
          msp = doc.modelspace()
          line = msp.add_line((0, 0), (10, 0))
          line.rgb = (255, 128, 32)

       The  true  color  value has higher precedence than the AutoCAD Color Index (ACI) value, if the attributes
       color and the true_color are present the entity will be rendered with the true color value.

       The true color value has the advantage that  it  defines  the  color  absolutely  and  unambiguously,  no
       unexpected  overwriting  is  possible.   The representation of the color is fixed and only depends on the
       calibration of the output medium: [image]

       SEE ALSO:ezdxf.colorsTutorial for Common Graphical Attributes

          • Autodesk Knowledge Network: About Setting the Color of Objects

          • BricsCAD Help Center: Entity Color

   Transparency
       The support for transparency was added to the DXF file format in revision R2004.   The  raw  transparency
       value  stored  as  32 bit value in the DXF namespace as transparency attribute, has a range from 0 to 255
       where 0 is fully transparent and 255 if opaque and has the top byte set to 0x02.  For a more  easy  usage
       all  graphical  entities support the transparency property to get and set the transparency as float value
       in the range frem 0.0 to 1.0 where 0.0 is opaque and 1.0 is fully transparent. The transparency value can
       be set explicit in the entity, by layer or by block.

          import ezdxf

          doc = ezdxf.new()
          msp = doc.modelspace()
          line = msp.add_line((0, 0), (10, 0))
          line.transparency = 0.5

       SEE ALSO:ezdxf.colorsTutorial for Common Graphical Attributes

          • Autodesk Knowledge Network: About Making Objects Transparent

          • BricsCAD Help Center: Entity Transparency

   Layers
       Every object has a layer as one of its properties. You may be familiar with layers - independent  drawing
       spaces that stack on top of each other to create an overall image - from using drawing programs. Most CAD
       programs  use  layers  as  the  primary  organizing principle for all the objects that you draw.  You use
       layers to organize objects into logical groups of  things  that  belong  together;  for  example,  walls,
       furniture, and text notes usually belong on three separate layers, for a couple of reasons:

       • Layers give you a way to turn groups of objects on and off - both on the screen and on the plot.

       • Layers provide the most efficient way of controlling object color and linetype

       Create  a  layer table entry Layer by Drawing.layers.add(), assign the layer properties such as color and
       linetype. Then assign those layers to other DXF entities by setting the DXF attribute layer to the  layer
       name as string.

       The  DXF  format  do not require a layer table entry for a layer. A layer without a layer table entry has
       the default linetype 'Continuous', a default color of 7 and a  lineweight  of  -3  which  represents  the
       default lineweight of 0.25mm in most circumstances.

   Layer Properties
       The  advantage  of  assigning properties to a layer is that entities can inherit this properties from the
       layer by using the string 'BYLAYER' as linetype string, 256 as color  or  -1  as  lineweight,  all  these
       values  are  the  default  values  for  new entities. DXF version R2004 and later also support inheriting
       true_color and transparency attributes from a layer.

   Layer Status
       The layer status is important for the visibility and the ability to select and edit DXF entities on  that
       layer in CAD applications.  Ezdxf does not care about the visual representation and works at the level of
       entity  spaces and the entity database and therefore all the layer states documented below are ignored by
       ezdxf.  This means if you iterate an entity space like the modelspace or the entity database you will get
       all entities from that entity space regardless the layer status.

       • ON: the layer is visible, entities on that layer are visible, selectable and editable

       • OFF: the layer is not visible, entities on that layer are not visible, not selectable and not editable

       • FROZEN: the layer is not visible, entities on that layer  are  not  visible,  not  selectable  and  not
         editable,  very  similar  to  the  OFF  status  but  layers can be frozen individually in VIEWPORTS and
         freezing layers may speed up some commands in CAD applications like ZOOM, PAN or REGEN.

       • LOCKED: the layer is visible, entities on that layer are visible but not selectable and not editable

   Deleting Layers
       Deleting a layer is not as simple as it might seem, especially if you are used to use a  CAD  application
       like  AutoCAD.  There  is no directory of locations where layers can be used and references to layers can
       occur even in third-party data.  Deleting the layer table entry removes only the  default  attributes  of
       that  layer and does not delete any layer references automatically. And because a layer can exist without
       a layer table entry, the layer exist as long as at least one layer reference to the layer exist.

   Renaming Layers
       Renaming a layer is also problematic because the DXF format stores the layer references in most cases  as
       text  strings,  so  renaming  the layer table entry just creates a new layer and all entities which still
       have a reference to the old layer now inherit their attributes from an undefined layer table  entry  with
       default settings.

   Viewport Overrides
       Most  of  the  layer properties can be overriden for each Viewport entity individually and this overrides
       are stored in layer table entry referenced by the handle of the VIEWPORT entity.  In contrast the  frozen
       status of layers is store in the VIEWPORT entity.

       SEE ALSO:Tutorial for LayersTutorial for Viewports in Paperspace

          • Autodesk Knowledge Network: About Layers

          • BricsCAD Help Center: Working with Layers

   Linetypes
       The linetype defines the rendering pattern of linear graphical entities like LINE, ARC, CIRCLE and so on.
       The  linetype  of an entity can be specified by the DXF attribute linetype, this can be an explicit named
       linetype or the entity can inherit its linetype from the assigned layer by setting linetype to 'BYLAYER',
       which is also the default value. CONTINUOUS is the  default  linetype  for  layers  with  an  unspecified
       linetype.

       Ezdxf  creates  several standard linetypes, if the argument setup is True when calling new(), this simple
       linetypes are supported by all DXF versions:

          doc = ezdxf.new('R2007', setup=True)
       [image]

       In DXF R13 Autodesk introduced complex linetypes which can contain text or shapes.

       SEE ALSO:Tutorial for Common Graphical AttributesTutorial for Creating Linetype Pattern

          • Autodesk Knowledge Network: About Linetypes

          • BricsCAD Help Center: Entity Linetype

   Linetype Scaling
       Global linetype scaling can be changed by setting the header variable doc.header['$LTSCALE'] =  2,  which
       stretches the line pattern by factor 2.

       The  linetype  scaling  for  a  single entity can be set by the DXF attribute ltscale, which is supported
       since DXF R2000.

   Lineweights
       The lineweight attribute represents the lineweight as integer value in millimeters * 100, e.g.  0.25mm  =
       25,  independently  from the unit system used in the DXF document.  The lineweight attribute is supported
       by DXF R2000 and newer.

       Only certain values are valid, they are stored in ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS: 0, 5,  9,  13,
       15, 18, 20, 25, 30, 35, 40, 50, 53, 60, 70, 80, 90, 100, 106, 120, 140, 158, 200, 211.

       Values < 0 have a special meaning and can be imported as constants from ezdxf.lldxf.const
                                             ┌────┬────────────────────┐
                                             │ -1 │ LINEWEIGHT_BYLAYER │
                                             ├────┼────────────────────┤
                                             │ -2 │ LINEWEIGHT_BYBLOCK │
                                             ├────┼────────────────────┤
                                             │ -3 │ LINEWEIGHT_DEFAULT │
                                             └────┴────────────────────┘

       The  validator  function:  ezdxf.lldxf.validator.is_valid_lineweight()  returns True for valid lineweight
       values otherwise False.

       Sample script which shows all valid lineweights: valid_lineweights.dxf

       You have to enable the option to show lineweights in your CAD application or viewer to see the effect  on
       screen,  which  is  disabled  by  default, the same has to be done in the page setup options for plotting
       lineweights.

       Setting the HEADER variable $LWDISPLAY to 1, activates support for displaying lineweights on screen:

          # activate on screen lineweight display
          doc.header["$LWDISPLAY"] = 1
       [image]

       The lineweight value can be overridden by CTB or STB files.

       SEE ALSO:

          • Autodesk Knowledge Network: About Lineweights

          • BricsCAD Help Center: Entity Lineweight

   Coordinate Systems
       AutoLISP Reference to Coordinate Systems provided by Autodesk.

       To brush up you knowledge about vectors, watch the YouTube tutorials of 3Blue1Brown about Linear Algebra.

   WCS
       World coordinate system - the reference coordinate system.  All  other  coordinate  systems  are  defined
       relative  to  the WCS, which never changes. Values measured relative to the WCS are stable across changes
       to other coordinate systems.

   UCS
       User coordinate system - the working coordinate system defined by the user to make drawing tasks  easier.
       All  points  passed  to  AutoCAD  commands,  including those returned from AutoLISP routines and external
       functions, are points in the current UCS. As far as I know, all  coordinates  stored  in  DXF  files  are
       always WCS or OCS never UCS.

       User  defined  coordinate  systems  are  not just helpful for interactive CAD, therefore ezdxf provides a
       converter class UCS to translate coordinates from UCS into WCS and vice versa, but always remember: store
       only WCS or OCS coordinates in DXF files, because there is no method to determine which UCS was active or
       used to create UCS coordinates.

       SEE ALSO:

          • Table entry UCSezdxf.math.UCS - converter between WCS and UCS

   OCS
       Object coordinate system  are coordinates relative to the object itself.  The main  goal  of  OCS  is  to
       place  2D elements in 3D space and the OCS is defined by the extrusion vector of the entity.  As long the
       extrusion vector is (0, 0, 1) (the WCS z-axis) the OCS is coincident to the  WCS,  which  means  the  OCS
       coordinates are equal to the WCS coordinates, most of the time this is true for 2D entities.

       OCS entities: ARC, CIRCLE, TEXT, LWPOLYLINE, HATCH, SOLID, TRACE, INSERT, IMAGE

       Because  ezdxf  is  just an interface to DXF, it does not automatically convert OCS into WCS, this is the
       domain of the user/application. These lines convert the center of a 3D circle from OCS to WCS:

          ocs = circle.ocs()
          wcs_center = ocs.to_wcs(circle.dxf.center)

       SEE ALSO:Object Coordinate System (OCS) - deeper insights into OCS

          • ezdxf.math.OCS - converter between WCS and OCS

   DCS
       Display coordinate system - the coordinate system into which objects  are  transformed  before  they  are
       displayed.  The  origin  of  the  DCS  is the point stored in the AutoCAD system variable TARGET, and its
       z-axis is the viewing direction. In other words, a viewport is always a  plan  view  of  its  DCS.  These
       coordinates  can  be  used to determine where something will be displayed to the AutoCAD user. Ezdxf does
       not use or support DCS in any way.

   Object Coordinate System (OCS)DXF Reference for OCS provided by Autodesk.

       The points associated with each entity are expressed in terms  of  the  entity’s  own  object  coordinate
       system (OCS). The OCS was referred to as ECS in previous releases of AutoCAD.

       With  OCS, the only additional information needed to describe the entity’s position in 3D space is the 3D
       vector describing the z-axis of the OCS (often referenced as extrusion vector), and the elevation  value,
       which is the distance of the entity xy-plane to the WCS/OCS origin.

       For  a given z-axis (extrusion) direction, there are an infinite number of coordinate systems, defined by
       translating the origin in 3D space and by rotating the x- and y-axis around the z-axis. However, for  the
       same z-axis direction, there is only one OCS. It has the following properties:

       • Its origin coincides with the WCS origin.

       • The  orientation of the x- and y-axis within the xy-plane are calculated in an arbitrary but consistent
         manner. AutoCAD performs this calculation using the arbitrary axis algorithm (see below).

       • Because of the Arbitrary Axis Algorithm the OCS can only represent a right-handed coordinate system!

       The following entities do not lie in a particular plane. All points are expressed in  world  coordinates.
       Of  these  entities, only lines and points can be extruded. Their extrusion direction can differ from the
       world z-axis.

       • LinePoint3DFacePolyline (3D)

       • Vertex (3D)

       • PolymeshPolyfaceViewport

       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.

       • CircleArcSolidTraceTextAttribAttdefShapeInsertPolyline (2D)

       • Vertex (2D)

       • LWPolylineHatchImage

       Some of a Dimension’s points are expressed in WCS and some in OCS.

   Elevation
       Elevation group code 38:

       Exists  only  in output from versions prior to R11. Otherwise, Z coordinates are supplied as part of each
       of the entity’s defining points.

   Arbitrary Axis AlgorithmDXF Reference for Arbitrary Axis Algorithm provided by Autodesk.

       The arbitrary axis algorithm is used by AutoCAD internally to  implement  the  arbitrary  but  consistent
       generation of object coordinate systems for all entities that use object coordinates.

       Given  a unit-length vector to be used as the z-axis of a coordinate system, the arbitrary axis algorithm
       generates a corresponding x-axis for the coordinate system. The y-axis  follows  by  application  of  the
       right-hand rule.

       We are looking for the arbitrary x- and y-axis to go with the normal Az (the arbitrary z-axis). They will
       be called Ax and Ay (using Vec3):

          Az = Vec3(entity.dxf.extrusion).normalize()  # normal (extrusion) vector
          if (abs(Az.x) < 1/64.) and (abs(Az.y) < 1/64.):
               Ax = Vec3(0, 1, 0).cross(Az).normalize()  # the cross-product operator
          else:
               Ax = Vec3(0, 0, 1).cross(Az).normalize()  # the cross-product operator
          Ay = Az.cross(Ax).normalize()

   WCS to OCS
          def wcs_to_ocs(point):
              px, py, pz = Vec3(point)  # point in WCS
              x = px * Ax.x + py * Ax.y + pz * Ax.z
              y = px * Ay.x + py * Ay.y + pz * Ay.z
              z = px * Az.x + py * Az.y + pz * Az.z
              return Vec3(x, y, z)

   OCS to WCS
          Wx = wcs_to_ocs((1, 0, 0))
          Wy = wcs_to_ocs((0, 1, 0))
          Wz = wcs_to_ocs((0, 0, 1))

          def ocs_to_wcs(point):
              px, py, pz = Vec3(point)  # point in OCS
              x = px * Wx.x + py * Wx.y + pz * Wx.z
              y = px * Wy.x + py * Wy.y + pz * Wy.z
              z = px * Wz.x + py * Wz.y + pz * Wz.z
              return Vec3(x, y, z)

   DXF Units
       The DXF reference has no explicit information how to handle units in DXF, any information in this section
       is  based  on experiments with BricsCAD and may differ in other CAD applications, BricsCAD tries to be as
       compatible with AutoCAD as possible. Therefore, this information should also apply to AutoCAD.

       Please open an issue on github if you have any corrections or additional information about this topic.

   Length Units
       Any length or coordinate value in DXF is unitless in the  first  place,  there  is  no  unit  information
       attached  to  the  value.  The  unit  information  comes from the context where a DXF entity is used. The
       document/modelspace get the unit information from the header variable  $INSUNITS,  paperspace  and  block
       layouts  get  their  unit  information  from the attribute units.  The modelspace object has also a units
       property, but this value do not represent the modelspace units, this value is always set to 0 “unitless”.

       Get and set  document/modelspace units as enum by the Drawing property units:

          import ezdxf
          from ezdxf import units

          doc = ezdxf.new()
          # Set centimeter as document/modelspace units
          doc.units = units.CM
          # which is a shortcut (including validation) for
          doc.header['$INSUNITS'] = units.CM

   Block Units
       As said each block definition can have independent units,  but  there  is  no  implicit  unit  conversion
       applied, not in CAD applications and not in ezdxf.

       When  inserting  a  block  reference  (INSERT) into the modelspace or another block layout with different
       units, the scaling factor between these units must be applied explicit as DXF attributes (xscale,  …)  of
       the  Insert  entity,  e.g.  modelspace in meters and block in centimeters, x-, y- and z-scaling has to be
       0.01:

          doc.units = units.M
          my_block = doc.blocks.new('MYBLOCK')
          my_block.units = units.CM
          block_ref = msp.add_block_ref('MYBLOCK')
          # Set uniform scaling for x-, y- and z-axis
          block_ref.set_scale(0.01)

       Use helper function conversion_factor() to calculate the scaling factor between units:

          factor = units.conversion_factor(doc.units, my_block.units)
          # factor = 100 for 1m is 100cm
          # scaling factor = 1 / factor
          block_ref.set_scale(1.0/factor)

       HINT:
          It is never a good idea to use different measurement system in one project, ask the NASA  about  their
          Mars  Climate  Orbiter from 1999.  The same applies for units of the same measurement system, just use
          one unit like meters or inches.

   Angle Units
       Angles are always in degrees (360 deg = full circle)  in  counter-clockwise  orientation,  unless  stated
       explicit otherwise.

   Display Format
       How  values  are shown in the CAD GUI is controlled by the header variables $LUNITS and $AUNITS, but this
       has no meaning for values stored in DXF files.

   $INSUNITS
       The most important setting is the header variable $INSUNITS, this variable defines the drawing units  for
       the modelspace and therefore for the DXF document if no further settings are applied.

       The  modelspace  LAYOUT  entity  has  a  property units as any layout like object, but it seem to have no
       meaning for the modelspace, BricsCAD set this property always to 0, which means unitless.

       The most common units are 6 for meters and 1 for inches.

          doc.header['$INSUNITS'] = 6
                                            ┌────┬───────────────────────┐
                                            │ 0  │ Unitless              │
                                            ├────┼───────────────────────┤
                                            │ 1  │ Inches, units.IN      │
                                            ├────┼───────────────────────┤
                                            │ 2  │ Feet, units.FT        │
                                            ├────┼───────────────────────┤
                                            │ 3  │ Miles, units.MI       │
                                            ├────┼───────────────────────┤
                                            │ 4  │ Millimeters, units.MM │
                                            ├────┼───────────────────────┤
                                            │ 5  │ Centimeters, units.CM │
                                            ├────┼───────────────────────┤
                                            │ 6  │ Meters, units.M       │
                                            ├────┼───────────────────────┤
                                            │ 7  │ Kilometers, units.KM  │
                                            ├────┼───────────────────────┤
                                            │ 8  │ Microinches           │
                                            ├────┼───────────────────────┤
                                            │ 9  │ Mils                  │
                                            ├────┼───────────────────────┤
                                            │ 10 │ Yards, units.YD       │
                                            ├────┼───────────────────────┤
                                            │ 11 │ Angstroms             │
                                            ├────┼───────────────────────┤
                                            │ 12 │ Nanometers            │
                                            ├────┼───────────────────────┤
                                            │ 13 │ Microns               │
                                            ├────┼───────────────────────┤
                                            │ 14 │ Decimeters, units.DM  │
                                            ├────┼───────────────────────┤
                                            │ 15 │ Decameters            │
                                            ├────┼───────────────────────┤
                                            │ 16 │ Hectometers           │
                                            ├────┼───────────────────────┤
                                            │ 17 │ Gigameters            │
                                            ├────┼───────────────────────┤
                                            │ 18 │ Astronomical units    │
                                            ├────┼───────────────────────┤
                                            │ 19 │ Light years           │
                                            ├────┼───────────────────────┤
                                            │ 20 │ Parsecs               │
                                            ├────┼───────────────────────┤
                                            │ 21 │ US Survey Feet        │
                                            ├────┼───────────────────────┤
                                            │ 22 │ US Survey Inch        │
                                            ├────┼───────────────────────┤
                                            │ 23 │ US Survey Yard        │
                                            ├────┼───────────────────────┤
                                            │ 24 │ US Survey Mile        │
                                            └────┴───────────────────────┘

       See also enumeration ezdxf.enums.InsertUnits.

   $MEASUREMENT
       The header variable $MEASUREMENT controls whether the current  drawing  uses  imperial  or  metric  hatch
       pattern and linetype files:

       This  setting  is  independent  from  $INSUNITS,  it is possible to set the drawing units to inch and use
       metric linetypes and hatch pattern.

       In BricsCAD the base scaling of linetypes and hatch pattern is defined by  the  $MEASUREMENT  value,  the
       value of $INSUNITS is ignored.

          doc.header['$MEASUREMENT'] = 1
                                                   ┌───┬─────────┐
                                                   │ 0 │ English │
                                                   ├───┼─────────┤
                                                   │ 1 │ Metric  │
                                                   └───┴─────────┘

       See also enumeration ezdxf.enums.Measurement

   $LUNITS
       The  header  variable  $LUNITS  defines  how CAD applications display linear values in the GUI and has no
       meaning for ezdxf:

          doc.header['$LUNITS'] = 2
                                              ┌───┬───────────────────┐
                                              │ 1 │ Scientific        │
                                              ├───┼───────────────────┤
                                              │ 2 │ Decimal (default) │
                                              ├───┼───────────────────┤
                                              │ 3 │ Engineering       │
                                              ├───┼───────────────────┤
                                              │ 4 │ Architectural     │
                                              ├───┼───────────────────┤
                                              │ 5 │ Fractional        │
                                              └───┴───────────────────┘

       See also enumeration ezdxf.enums.LengthUnits

   $AUNITS
       The header variable $AUNITS defines how CAD applications display angular values in the  GUI  and  has  no
       meaning  for  ezdxf,  DXF  angles  are  always stored as degrees in counter-clockwise orientation, unless
       stated explicit otherwise:

          doc.header['$AUNITS'] = 0
                                           ───────────────────────────────
                                             0   Decimal degrees
                                           ───────────────────────────────
                                             1   Degrees/minutes/seconds
                                           ───────────────────────────────
                                             2   Grad
                                           ───────────────────────────────
                                             3   Radians
                                           ┌───┬─────────────────────────┐
                                           │   │                         │
--

TUTORIALS

   Tutorial for Getting Data from DXF Files
       This tutorial shows how to get data from an existing DXF document.  If you are a new user of ezdxf,  read
       also the tutorial Usage for Beginners.

       Loading the DXF file:

          import sys
          import ezdxf

          try:
              doc = ezdxf.readfile("your_dxf_file.dxf")
          except IOError:
              print(f"Not a DXF file or a generic I/O error.")
              sys.exit(1)
          except ezdxf.DXFStructureError:
              print(f"Invalid or corrupted DXF file.")
              sys.exit(2)

       This  works  well for DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files with
       minor or major flaws look at the ezdxf.recover module.

       SEE ALSO:Document ManagementUsage for Beginners

   Layouts
       The term layout is used as a synonym for an arbitrary entity space which can contain  DXF  entities  like
       LINE, CIRCLE, TEXT and so on. Each DXF entity can only reside in exact one layout.

       There are three different layout types:

       • Modelspace: the common construction space

       • Paperspace: used to to create print layouts

       • BlockLayout: reusable elements, every block has its own entity space

       A DXF document consist of exact one modelspace and at least one paperspace.  DXF R12 has only one unnamed
       paperspace the later DXF versions support more than one paperspace and each paperspace has a name.

   Getting the modelspace layout
       The  modelspace contains the “real” world representation of the drawing subjects in real world units. The
       modelspace has the fixed name “Model” and the DXF document has a special getter method modelspace().

          msp = doc.modelspace()

   Iterate over DXF entities of a layout
       This code shows how to iterate over all DXF entities in modelspace:

          # helper function
          def print_entity(e):
              print("LINE on layer: %s\n" % e.dxf.layer)
              print("start point: %s\n" % e.dxf.start)
              print("end point: %s\n" % e.dxf.end)

          # iterate over all entities in modelspace
          msp = doc.modelspace()
          for e in msp:
              if e.dxftype() == "LINE":
                  print_entity(e)

          # entity query for all LINE entities in modelspace
          for e in msp.query("LINE"):
              print_entity(e)

       All layout objects supports the standard Python iterator protocol and the in operator.

   Access DXF attributes of an entity
       The e.dxftype() method returns the DXF type, the DXF type is always an uppercase string like "LINE".  All
       DXF attributes of an entity are grouped in the namespace attribute dxf:

          e.dxf.layer  # layer of the entity as string
          e.dxf.color  # color of the entity as integer

       See Common graphical DXF attributes

       If  a  DXF  attribute  is not set (the DXF attribute does not exist), a DXFValueError will be raised. The
       get() method returns a default value in this case or None if no default value is specified:

          # If DXF attribute 'paperspace' does not exist, the entity defaults
          # to modelspace:
          p = e.dxf.get("paperspace", 0)

       or check beforehand if the attribute exist:

          if e.dxf.hasattr("paperspace"):
              ...

       An unsupported DXF attribute raises a DXFAttributeError, to check if an  attribute  is  supported  by  an
       entity use:

          if e.dxf.is_supported("paperspace"):
              ...

   Getting a paperspace layout
          paperspace = doc.paperspace("layout0")

       The  code above retrieves the paperspace named layout0, the usage of the Paperspace object is the same as
       of the modelspace object.  DXF R12 provides only one paperspace, therefore the  paperspace  name  in  the
       method  call doc.paperspace("layout0") is ignored or can be left off.  For newer DXF versions you can get
       a list of the available layout names by the methods layout_names() and layout_names_in_taborder().

   Retrieve entities by query language
       Ezdxf provides a flexible query language for DXF entities.  All layout types have  a  query()  method  to
       start an entity query or use the ezdxf.query.new() function.

       The  query  string  is  the  combination  of  two queries, first the required entity query and second the
       optional attribute query, enclosed in square brackets: "EntityQuery[AttributeQuery]"

       The entity query is a whitespace separated list of DXF entity names or the special name *. Where *  means
       all DXF entities, all DXF names have to be uppercase. The * search can exclude entity types by adding the
       entity name with a preceding ! (e.g. * !LINE, search all entities except lines).

       The  attribute  query  is  used  to  select DXF entities by its DXF attributes. The attribute query is an
       addition to the entity query and matches only if the entity already match the entity query. The attribute
       query is a boolean expression, supported operators: and, or, !.

       SEE ALSO:
          Entity Query String

       Get all LINE entities from the modelspace:

          msp = doc.modelspace()
          lines = msp.query("LINE")

       The result container EntityQuery also provides the query() method to further refine the  query,  such  as
       retrieving all LINE entities at layer construction:

          construction_lines = lines.query('*[layer=="construction"]')

       The  *  is  a wildcard for all DXF types, in this case you could also use LINE instead of *, * works here
       because the source just contains LINE entities.

       This could be executed as a single query:

          lines = msp.query('LINE[layer=="construction"]')

       An advanced query for getting all modelspace entities at layer construction, but excluding entities  with
       linetype DASHED:

          not_dashed_entities = msp.query('*[layer=="construction" and linetype!="DASHED"]')

   Extended EntityQuery Features
       The  EntityQuery  class  has  properties  and  overloaded  operators  to build extended queries by Python
       features instead of a query string.

       Same task as in the previous section but using features of the EntityQuery container:

          # The overloaded rational operators return an EntityQuery object and not a bool value!
          lines = msp.query("LINES").layer == "construction"
          not_dashed_lines = lines.linetype != "DASHED"

       SEE ALSO:
          Extended EntityQuery Features

   Retrieve entities by groupby() function
       The groupby() function searches and group entities by a user defined criteria.  As an example let’s group
       all entities from modelspace by layer, the result will be a dict with layer names as dict-key and a  list
       of all entities from the modelspace matching this layer as dict-value:

          from ezdxf.groupby import groupby
          group = groupby(entities=msp, dxfattrib="layer")

       The entities argument can be any container or generator which yields DXF entities:

          group = msp.groupby(dxfattrib="layer")

          for layer, entities in group.items():
              print(f'Layer "{layer}" contains following entities:')
              for entity in entities:
                  print(f"    {entity}")
              print("-"*40)

       The  previous  example  shows how to group entities by a single DXF attribute.  For a more advanced query
       create a custom key function, which accepts a DXF entity as argument and  returns  a  hashable  value  as
       dict-key or None to exclude the entity.

       The  following  example  shows how to group entities by layer and color, the dict-key is a (layer, color)
       tuple and the dict-value is a list of entities with matching DXF attributes:

          def layer_and_color_key(entity):
              # return None to exclude entities from the result container
              if entity.dxf.layer == "0":  # exclude entities from default layer "0"
                  return None
              else:
                  return entity.dxf.layer, entity.dxf.color

          group = msp.groupby(key=layer_and_color_key)
          for key, entities in group.items():
              print(f'Grouping criteria "{key}" matches following entities:')
              for entity in entities:
                  print(f"    {entity}")
              print("-"*40)

       The groupby() function catches DXFAttributeError exceptions while processing entities and  excludes  this
       entities  from  the  result.   There  is no need to worry about DXF entities which do not support certain
       attributes, they will be excluded automatically.

       SEE ALSO:
          groupby() documentation

   Tutorial for Creating DXF Drawings
       Create a new DXF document by the ezdxf.new() function:

          import ezdxf

          # create a new DXF R2010 document
          doc = ezdxf.new("R2010")

          # add new entities to the modelspace
          msp = doc.modelspace()
          # add a LINE entity
          msp.add_line((0, 0), (10, 0))
          # save the DXF document
          doc.saveas("line.dxf")

       New entities are always added to layouts, a layout can be the modelspace, a paperspace layout or a  block
       layout.

       SEE ALSO:
          Thematic Index of Layout Factory Methods

   Predefined Resources
       Ezdxf  creates  new  DXF documents with as little content as possible, this means only the resources that
       are absolutely necessary are created.  The ezdxf.new() function can create some standard resources,  such
       as linetypes and text styles, by setting the argument setup to True.

          import ezdxf

          doc = ezdxf.new("R2010", setup=True)
          msp = doc.modelspace()
          msp.add_line((0, 0), (10, 0), dxfattribs={"linetype": "DASHED"})

       The  defined  standard  linetypes  are shown in the basic concept section for Linetypes and the available
       text styles are shown in the Tutorial for Text.

       IMPORTANT:
          To see the defined text styles in a DXF viewer or CAD application, the applications have to know where
          the referenced TTF fonts can be found.  This configuration is not possible by ezdxf and has to be done
          for each application as described in their documentation.

          See also: Font Resources

   Simple DXF R12 drawings
       The r12writer add-on creates simple DXF R12 drawings with a restricted set of DXF  types:  LINE,  CIRCLE,
       ARC, TEXT, POINT, SOLID, 3DFACE and POLYLINE.

       The  advantage  of  the  r12writer  is the speed and the small memory footprint, all entities are written
       directly to a file or stream without creating a document structure in memory.

       SEE ALSO:
          r12writer

   Tutorial for Common Graphical Attributes
       The graphical attributes color, linetype, lineweight, true_color, transparency, ltscale and invisible are
       available for all graphical DXF entities and are located in the DXF namespace attribute dxf  of  the  DXF
       entities.   All  these  attributes  are  optional  and  all except for true_color and transparency have a
       default value.

       Not all of these attributes are supported by all DXF versions. This table shows the minimum required  DXF
       version for each attribute:
                                      ┌───────┬────────────────────────────────┐
                                      │ R12   │ color, linetype                │
                                      ├───────┼────────────────────────────────┤
                                      │ R2000 │ lineweight, ltscale, invisible │
                                      ├───────┼────────────────────────────────┤
                                      │ R2004 │ true_color, transparency       │
                                      └───────┴────────────────────────────────┘

   Color
       Please read the section about the AutoCAD Color Index (ACI) to understand the basics.

       The usage of the color attribute is very straight forward. Setting the value is:

          entity.dxf.color = 1

       and getting the value looks like this:

          value = entity.dxf.color

       The  color  attribute  has  a  default  value  of  256,  which  means take the color defined by the layer
       associated to the entity. The ezdxf.colors module defines some constants for often used color values:

          entity.dxf.color = ezdxf.colors.RED

       The ezdxf.colors.aci2rgb() function converts the ACI value to the RGB value  of  the  default  modelspace
       palette.

       SEE ALSO:

          • Basics about AutoCAD Color Index (ACI)ezdxf.colors module

   True Color
       Please read the section about True Color to understand the basics.

       The easiest way is to use the rgb property to set and get the true color values as RGB tuples:

          entity.rgb = (255, 128, 16)

       The rgb property return None if the true_color attribute is not present:

          rgb = entity.rgb
          if rgb is not None:
              r, g, b = rgb

       Setting  and  getting  the  true_color DXF attribute directly is possible and the ezdxf.colors module has
       helper function to convert RGB tuples to 24-bit value and back:

          entity.dxf.true_color = ezdxf.colors.rgb2int(255, 128, 16)

       The true_color attribute is optional does not have a default value and therefore it is not  safe  to  use
       the attribute directly, check if the attribute exists beforehand:

          if entity.dxf.hasattr("true_color"):
              r, g, b = ezdxf.colors.int2rgb(entity.dxf.true_color)

       or  use  the get() method of the dxf namespace attribute to get a default value if the attribute does not
       exist:

          r, g, b = ezdxf.colors.int2rgb(entity.dxf.get("true_color", 0)

       SEE ALSO:

          • Basics about True Colorezdxf.colors module

   Transparency
       Please read the section about Transparency to understand the basics.

       It’s recommended to use the transparency  property  of  the  DXFGraphic  base  class.   The  transparency
       property is a float value in the range from 0.0 to 1.0 where 0.0 is opaque and 1.0 if fully transparent:

          entity.transparency = 0.5

       or set the values of the DXF attribute by constants defined in the ezdxf.colors module:

          entity.dxf.transparency = ezdxf.colors.TRANSPARENCY_50

       The  default  setting  for  transparency  in  CAD  applications  is always transparency by layer, but the
       transparency property in ezdxf has a default value of  0.0  (opaque),  so  there  are  additional  entity
       properties  to  check  if the transparency value should be taken from the associated entity layer or from
       the parent block:

          if entity.is_transparency_by_layer:
              ...
          elif entity.is_transparency_by_block:
              ...
          else:
              ...

       The top level entity attribute transparency does not support setting transparency by layer or block:

          from ezdxf import colors

          ...

          # set transparency by layer by removing the DXF attribute "transparency":
          entity.dxf.discard("transparency")

          # set transparency by block:
          entity.dxf.transparency = colors.TRANSPARENCY_BYBLOCK

          # there are also some handy constants in the colors module:
          # TRANSPARENCY_10 upto TRANSPARENCY_90 in steps of 10
          entity.dxf.transparency = colors.TRANSPARENCY_30  # set 30% transparency
          entity.dxf.transparency = colors.OPAQUE

       SEE ALSO:

          • Basics about Transparencyezdxf.colors module

   Linetype
       Please read the section about Linetypes to understand the basics.

       The linetype attribute contains the name of the linetype as string and can be set by  the  dxf  namespace
       attribute directly:

          entity.dxf.linetype = "DASHED"  # linetype DASHED must exist!

       The  linetype  attribute is optional and has a default value of “BYLAYER”, so the attribute can always be
       used without any concerns:

          name = entity.dxf.linetype

       WARNING:
          Make sure the linetype you assign to an entity is really  defined  in  the  linetype  table  otherwise
          AutoCAD  will  not  open the DXF file. There are no implicit checks for that by ezdxf but you can call
          the audit() method of the DXF document explicitly to validate the document before exporting.

       Ezdxf creates new DXF documents with as little content as possible, this means only  the  resources  that
       are  absolutely  necessary  are  created.  The ezdxf.new() function can create some standard linetypes by
       setting the argument setup to True:

          doc = ezdxf.new("R2010", setup=True)

       SEE ALSO:

          • Basics about LinetypesTutorial for Creating Linetype Pattern

   Lineweight
       Please read the section about Lineweights to understand the basics.

       The lineweight attribute contains the lineweight as an integer value and can be set by the dxf  namespace
       attribute directly:

          entity.dxf.lineweight = 25

       The  lineweight  value  is  the  line  width in millimeters times 100 e.g.  0.25mm = 25, but only certain
       values are valid for more information go to section: Lineweights.

       Values < 0 have a special meaning and can be imported as constants from ezdxf.lldxf.const
                                             ┌────┬────────────────────┐
                                             │ -1 │ LINEWEIGHT_BYLAYER │
                                             ├────┼────────────────────┤
                                             │ -2 │ LINEWEIGHT_BYBLOCK │
                                             ├────┼────────────────────┤
                                             │ -3 │ LINEWEIGHT_DEFAULT │
                                             └────┴────────────────────┘

       The lineweight attribute is optional and has a default value of -1, so the attribute can always  be  used
       without any concerns:

          lineweight = entity.dxf.lineweight

       IMPORTANT:
          You  have to enable the option to show lineweights in your CAD application or viewer to see the effect
          on screen, which is disabled by default, the same has to  be  done  in  the  page  setup  options  for
          plotting lineweights.

          # activate on screen lineweight display
          doc.header["$LWDISPLAY"] = 1

       SEE ALSO:

          • Basics about Lineweights

   Linetype Scale
       The  ltscale  attribute  scales the linetype pattern by a float value and can be set by the dxf namespace
       attribute directly:

          entity.dxf.ltscale = 2.0

       The ltscale attribute is optional and has a default value of 1.0, so the attribute  can  always  be  used
       without any concerns:

          scale = entity.dxf.ltscale

       SEE ALSO:

          • Basics about Linetypes

   Invisible
       The invisible attribute an boolean value (0/1) which defines if an entity is invisible or visible and can
       be set by the dxf namespace attribute directly:

          entity.dxf.invisible = 1

       The  invisible  attribute  is  optional and has a default value of 0, so the attribute can always be used
       without any concerns:

          is_invisible = bool(entity.dxf.invisible)

   GfxAttribs
       When adding new entities to an entity space like the  modelspace  or  a  block  definition,  the  factory
       methods  expect the graphical DXF attributes by the argument dxfattribs. This object can be a Python dict
       where the key is the DXF attribute name and  the  value  is  the  attribute  value,  or  better  use  the
       GfxAttribs object which has some additional validation checks and support for code completions by IDEs:

          import ezdxf
          from ezdxf.gfxattribs import GfxAttribs

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

          line = msp.add_line(
              (0, 0), (10, 10), dxfattribs=GfxAttribs(layer="0", rgb=(25, 128, 16))
          )

       SEE ALSO:ezdxf.gfxattribs module

   Tutorial for Layers
       If you are not familiar with the concept of layers, please read this first: Concept of Layers

       Reminder: a layer definition is not required for using a layer!

   Create a Layer Definition
          import ezdxf

          doc = ezdxf.new(setup=True)  # setup required line types
          msp = doc.modelspace()
          doc.layers.add(name="MyLines", color=7, linetype="DASHED")

       The  advantage  of assigning a linetype and a color to a layer is that entities on this layer can inherit
       this properties by using "BYLAYER" as linetype string and 256 as color, both values  are  default  values
       for new entities so you can leave off these assignments:

          msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "MyLines"})

       The new created line will be drawn with color 7 and linetype "DASHED".

   Moving an Entity to a Different Layer
       Moving an entity to a different layer is a simple assignment of the new layer name to the layer attribute
       of the entity.

          line = msp.add_line((0, 0), (10, 0), dxfattribs={"layer": "MyLines"})
          # move the entity to layer "OtherLayer"
          line.dxf.layer = "OtherLayer"

   Changing Layer State
       Get the layer definition object from the layer table:

          my_lines = doc.layers.get('MyLines')

       Check the state of the layer:

          my_lines.is_off()  # True if layer is off
          my_lines.is_on()   # True if layer is on
          my_lines.is_locked()  # True if layer is locked
          layer_name = my_lines.dxf.name  # get the layer name

       Change the state of the layer:

          # switch layer off, entities at this layer will not shown in CAD applications/viewers
          my_lines.off()

          # lock layer, entities at this layer are not editable in CAD applications
          my_lines.lock()

       Get/set  the  color  of  a  layer  by  property Layer.color, because the DXF attribute Layer.dxf.color is
       misused for switching the layer on and off, the layer is off if the color value is negative.

       Changing the layer properties:

          my_lines.dxf.linetype = "DOTTED"
          my_lines.color = 13  # preserves on/off state of layer

       SEE ALSO:
          For all methods and attributes see class Layer.

   Check Available Layers
       The LayerTable object supports some standard Python protocols:

          # iteration
          for layer in doc.layers:
              if layer.dxf.name != "0":
                  layer.off()  # switch all layers off except layer "0"

          # check for existing layer definition
          if "MyLines" in doc.layers:
              layer = doc.layers.get("MyLines")

          layer_count = len(doc.layers) # total count of layer definitions

   Renaming a Layer
       The Layer class has a method for renaming the layer, but has same limitations, not all places where layer
       references can occur are documented, third-party entities are black-boxes with unknown content and  layer
       references could be stored in the extended data section of any DXF entity or in a XRECORD entity, so some
       references  may  reference  a non-existing layer definition after the renaming, at least these references
       are still valid, because a layer definition is not required for using a layer.

          my_lines = doc.layers.get("MyLines")
          my_lines.rename("YourLines")

   Deleting a Layer Definition
       Delete a layer definition:

          doc.layers.remove("MyLines")

       This just deletes the layer definition, all DXF entities referencing this  layer  still  exist,  if  they
       inherit any properties from the deleted layer they will now get the default layer properties.

       WARNING:
          The behavior of entities referencing the layer by handle is unknown and may break the DXF document.

   Deleting All Entities From a Layer
       Because  of  all  these  uncertainties  about  layer  references  mentioned  above, deleting all entities
       referencing a certain layer from a DXF document is not implemented as an API call!

       Nonetheless deleting all graphical entities from the DXF document which do reference a certain  layer  by
       the layer attribute is a safe procedure:

          key_func = doc.layers.key
          layer_key = key_func("MyLines")
          # The trashcan context-manager is a safe way to delete entities from the
          # entities database while iterating.
          with doc.entitydb.trashcan() as trash:
              for entity in doc.entitydb.values():
                  if not entity.dxf.hasattr("layer"):
                      continue
                  if layer_key == key_func(entity.dxf.layer):
                      # safe destruction while iterating
                      trash.add(entity.dxf.handle)

   Tutorial for Creating Linetype Pattern
       Simple line type example: [image]

       You  can  define  your  own  linetypes.  A linetype definition has a name, a description and line pattern
       elements:

          elements = [total_pattern_length, elem1, elem2, ...]

       total_pattern_length
              Sum of all linetype elements (absolute values)

       elem   if elem > 0 it is a line, if elem < 0 it is gap, if elem == 0.0 it is a dot

       Create a new linetype definition:

          import ezdxf
          from ezdxf.tools.standards import linetypes  # some predefined linetypes

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

          my_line_types = [
              (
                  "DOTTED",
                  "Dotted .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .",
                  [0.2, 0.0, -0.2],
              ),
              (
                  "DOTTEDX2",
                  "Dotted (2x) .    .    .    .    .    .    .    . ",
                  [0.4, 0.0, -0.4],
              ),
              (
                  "DOTTED2",
                  "Dotted (.5) . . . . . . . . . . . . . . . . . . . ",
                  [0.1, 0.0, -0.1],
              ),
          ]
          for name, desc, pattern in my_line_types:
              if name not in doc.linetypes:
                  doc.linetypes.add(
                      name=name,
                      pattern=pattern,
                      description=desc,
                  )

       Setup some predefined linetypes:

          for name, desc, pattern in linetypes():
              if name not in doc.linetypes:
                  doc.linetypes.add(
                      name=name,
                      pattern= pattern,
                      description=desc,
                  )

   Check Available Linetypes
       The linetypes object supports some standard Python protocols:

          # iteration
          print("available linetypes:")
          for lt in doc.linetypes:
              print(f"{lt.dxf.name}: {lt.dxf.description}")

          # check for existing linetype
          if "DOTTED" in doc.linetypes:
              pass

          count = len(doc.linetypes) # total count of linetypes

   Removing Linetypes
       WARNING:
          Ezdxf does not check if a linetype is still in use and deleting a  linetype  which  is  still  in  use
          generates  an  invalid  DXF  file.  The  audit  process  audit()  of the DXF document removes linetype
          attributes referencing non existing linetypes.

       You can delete a linetype:

          doc.layers.remove("DASHED")

       This just removes the linetype definition, the linetype attribute of DXF entities  may  still  refer  the
       removed linetype definition “DASHED” and AutoCAD will not open DXF files including undefined linetypes.

   Tutorial for Creating Complex Linetype Pattern
       In DXF R13 Autodesk introduced complex linetypes, containing TEXT or SHAPES in line types.

       Complex linetype example with text: [image]

       Complex line type example with shapes: [image]

       For  easy  usage  the  pattern  string  for  complex  line types is mostly the same string as the pattern
       definition strings in AutoCAD “.lin” files.

       Example for complex line type TEXT:

          doc = ezdxf.new("R2018")  # DXF R13 or later is required

          doc.linetypes.add(
              name="GASLEITUNG2",
              # linetype definition string from acad.lin:
              pattern='A,.5,-.2,["GAS",STANDARD,S=.1,U=0.0,X=-0.1,Y=-.05],-.25',
              description= "Gasleitung2 ----GAS----GAS----GAS----GAS----GAS----",
              length=1,  # required for complex line types
          })

       The pattern always starts with an “A”, the following float values have the same  meaning  as  for  simple
       linetypes,  a  value  > 0 is a line, a value < 0 is a gap, and a 0 is a point, the opening square bracket
       “[” starts the complex part of the linetype pattern.

       The text after the “[” defines the complex linetype:

       • A text in quotes (e.g. “GAS”) defines a complex TEXT linetype and represents the pattern text itself.

       • A text without quotes is a SHAPE name (in “.lin” files) and defines a complex SHAPE linetype. Ezdxf can
         not translate this SHAPE name from the “.lin” file into the required shape file index, so *YOU have  to
         translate  this  SHAPE  name  into  the  shape file index, e.g. saving the file with AutoCAD as DXF and
         searching for the DXF linetype definition, see example below and the DXF Internals: LTYPE Table.

       For complex TEXT linetypes the second parameter is the text style, for complex SHAPE linetypes the second
       parameter is the shape file name, the shape file has to be in the same directory as the DXF  file  or  in
       one of the CAD application support paths.

       The meaning of the following comple linetype parameters are shown in the table below:
                                  ┌────────┬───────────────────────────────────────┐
                                  │ S      │ scaling  factor,  always  > 0, if S=0 │
                                  │        │ the TEXT or SHAPE is not visible      │
                                  ├────────┼───────────────────────────────────────┤
                                  │ R or U │ rotation   relative   to   the   line │
                                  │        │ direction                             │
                                  ├────────┼───────────────────────────────────────┤
                                  │ X      │ x-direction offset (along the line)   │
                                  ├────────┼───────────────────────────────────────┤
                                  │ Y      │ y-direction  offset (perpendicular to │
                                  │        │ the line)                             │
                                  └────────┴───────────────────────────────────────┘

       These parameters are case insensitive and the closing square bracket “]” ends the  complex  part  of  the
       linetype pattern.

       The  fine  tuning  of  this  parameters is a try an error process, for complex TEXT linetypes the scaling
       factor (e.g. the STANDARD text style) sets the text height (e.g. “S=0.1” sets  the  text  height  to  0.1
       units),  by shifting in y-direction by half of the scaling factor, the text is vertically centered to the
       line. For the x-direction it seems to be a good practice to place a gap in front of the  text  and  after
       the text, find x shifting value and gap sizes by try and error. The overall length is at least the sum of
       all line and gap definitions (absolute values).

       Example for complex line type SHAPE:

          doc.linetypes.add("GRENZE2",
              # linetype definition in acad.lin:
              # A,.25,-.1,[BOX,ltypeshp.shx,x=-.1,s=.1],-.1,1
              # replacing BOX by shape index 132 (got index from an AutoCAD file),
              # ezdxf can't get shape index from ltypeshp.shx
              pattern="A,.25,-.1,[132,ltypeshp.shx,x=-.1,s=.1],-.1,1",
              description="Grenze eckig ----[]-----[]----[]-----[]----[]--",
              length= 1.45,  # required for complex line types
          })

       Complex  line  types with shapes only work if the associated shape file (e. g.  ltypeshp.shx) and the DXF
       file are in the same directory or the shape file is placed in one of the CAD application support folders.

   Tutorial for Simple DXF Entities
       These are basic graphical entities located in an entity space like the modelspace or a  block  definition
       and only support the common graphical attributes.

       The  entities  in  the following examples are always placed in the xy-plane of the WCS aka the 2D drawing
       space.  Some of these entities can only be placed outside the xy-plane in 3D space by utilizing the  OCS,
       but  this  feature  is beyond the scope of this tutorial, for more information about that go to: Tutorial
       for OCS/UCS Usage.

       Prelude to all following examples:

          import ezdxf
          from ezdxf.gfxattribs import GfxAttribs

          doc = ezdxf.new()
          doc.layers.new("ENTITY", color=1)
          msp = doc.modelspace()
          attribs = GfxAttribs(layer="ENTITY")

       SEE ALSO:Tutorial for Creating DXF DrawingsTutorial for Layersezdxf.gfxattribs module

   Point
       The Point entity marks a 3D point in the WCS:

          point = msp.add_point((10, 10), dxfattribs=attribs)

       All Point entities have the same styling stored in the header variable $PDMODE, for more information read
       the reference of class Point.

       SEE ALSO:

          • Reference of class PointTutorial for Common Graphical Attributes

   Line
       The Line entity is a 3D line with a start- and an end point in the WCS:

          line = msp.add_line((0, 0), (10, 10), dxfattribs=attribs)

       SEE ALSO:

          • Reference of class LineTutorial for Common Graphical Attributesezdxf.math.ConstructionLine

   Circle
       The Circle entity is an OCS entity defined by a center point and a radius:

          circle = msp.add_circle((10, 10), radius=3, dxfattribs=attribs)

       SEE ALSO:

          • Reference of class CircleTutorial for Common Graphical Attributesezdxf.math.ConstructionCircle

   Arc
       The Arc entity is an OCS entity defined by a center point, a  radius  a  start-   and  an  end  angle  in
       degrees:

          arc = msp.add_arc((10, 10), radius=3, start_angle=30, end_angle=120, dxfattribs=attribs)

       The  arc  goes  always  in  counter-clockwise  orientation around the z-axis more precisely the extrusion
       vector of OCS, but this is beyond the scope of this tutorial.

       The  helper  class  ezdxf.math.ConstructionArc  provides  constructors  to  create  arcs  from  different
       scenarios:

       • from_2p_angle: arc from 2 points and an angle

       • from_2p_radius: arc from 2 points and a radius

       • from_3p: arc from 3 points

       This example creates an arc from point (10, 0) to point (0, 0) passing the point (5, 3):

          from ezdxf.math import ConstructionArc


          # -x-x-x- snip -x-x-x-
          arc = ConstructionArc.from_3p(
              start_point=(10, 0), end_point=(0, 0), def_point=(5, 3)
          )
          arc.add_to_layout(msp, dxfattribs=attribs)

       SEE ALSO:

          • Reference of class ArcTutorial for Common Graphical Attributesezdxf.math.ConstructionArc

   Ellipse
       The  Ellipse  entity  requires  DXF  R2000 or newer and is a true WCS entity. The ellipse is defined by a
       center point, a vector for the major axis, the ratio between major- and minor axis and the start- and end
       parameter in radians:

          ellipse = msp.add_ellipse(
              (10, 10), major_axis=(5, 0), ratio=0.5, start_param=0, end_param=math.pi, dxfattribs=attribs
          )

       When placed in 3D space the extrusion vector defines the normal vector of the ellipse plane and the minor
       axis is the extrusion vector cross the major axis.

       SEE ALSO:

          • Reference of class EllipseTutorial for Common Graphical Attributesezdxf.math.ConstructionEllipse

   Further TutorialsTutorial for LWPolylineTutorial for SplineTutorial for TextTutorial for MText and MTextEditorTutorial for HatchTutorial for MultiLeaderTutorial for Mesh

   Tutorial for Blocks
       If you are not familiar with the concept of blocks, please read this first: Concept of Blocks

   Create a Block
       Blocks are managed as BlockLayout objects by the BlocksSection object, every drawing has only one  blocks
       section referenced by attribute Drawing.blocks.

          import ezdxf
          import random  # needed for random placing points

          def get_random_point():
              """Returns random x, y coordinates."""
              x = random.randint(-100, 100)
              y = random.randint(-100, 100)
              return x, y

          # Create a new drawing in the DXF format of AutoCAD 2010
          doc = ezdxf.new('R2010')

          # Create a block with the name 'FLAG'
          flag = doc.blocks.new(name='FLAG')

          # Add DXF entities to the block 'FLAG'.
          # The default base point (= insertion point) of the block is (0, 0).
          flag.add_lwpolyline([(0, 0), (0, 5), (4, 3), (0, 3)])  # the flag symbol as 2D polyline
          flag.add_circle((0, 0), .4, dxfattribs={'color': 2})  # mark the base point with a circle

   Block References (Insert)
       A block reference can be created by adding an Insert entity to any of these layout types:

          • ModelspacePaperspaceBlockLayout

       A block reference can be scaled and rotated individually.  Lets add some random flags to the modelspace:

          # Get the modelspace of the drawing.
          msp = doc.modelspace()

          # Get 50 random placing points.
          placing_points = [get_random_point() for _ in range(50)]

          for point in placing_points:
              # Every flag has a different scaling and a rotation of -15 deg.
              random_scale = 0.5 + random.random() * 2.0
              # Add a block reference to the block named 'FLAG' at the coordinates 'point'.
              msp.add_blockref('FLAG', point, dxfattribs={
                  'xscale': random_scale,
                  'yscale': random_scale,
                  'rotation': -15
              })

          # Save the drawing.
          doc.saveas("blockref_tutorial.dxf")

       Query all block references of block FLAG:

          for flag_ref in msp.query('INSERT[name=="FLAG"]'):
              print(str(flag_ref))

       When  adding  a  block reference to a layout with different units, the scaling factor between these units
       should be applied as scaling attributes (xscale, …) e.g. modelspace in meters and block  in  centimeters,
       xscale has to be 0.01.

   Block Attributes
       A  block  attribute  (Attrib)  is a text annotation attached to a block reference with an associated tag.
       Attributes are often used to add information to blocks  which  can  be  evaluated  and  exported  by  CAD
       applications.   An  attribute  can  be  added to a block reference by the Insert.add_attrib() method, the
       ATTRIB entity is geometrically not related to the block  reference,  so  insertion  point,  rotation  and
       scaling of the attribute have to be calculated by the user, but helper tools for that do exist.

   Using Attribute Definitions
       Another way to add attributes to block references is using attribute templates (AttDef). First create the
       attribute  definition  in the block definition, then add the block reference by add_blockref() and attach
       and fill attributes automatically by the add_auto_attribs() method to the block  reference.  This  method
       has  the advantage that all attributes are placed relative to the block base point with the same rotation
       and scaling as the block reference, but non-uniform scaling is not handled very well.

       The add_auto_blockref() method handles non-uniform scaling better by wrapping the block reference and its
       attributes into an anonymous block and let the CAD application do the transformation work.   This  method
       has the disadvantage of a more complex evaluation of attached attributes

       Using attribute definitions (AttDef templates):

          # Define some attributes for the block 'FLAG', placed relative
          # to the base point, (0, 0) in this case.
          flag.add_attdef('NAME', (0.5, -0.5), dxfattribs={'height': 0.5, 'color': 3})
          flag.add_attdef('XPOS', (0.5, -1.0), dxfattribs={'height': 0.25, 'color': 4})
          flag.add_attdef('YPOS', (0.5, -1.5), dxfattribs={'height': 0.25, 'color': 4})

          # Get another 50 random placing points.
          placing_points = [get_random_point() for _ in range(50)]

          for number, point in enumerate(placing_points):
              # values is a dict with the attribute tag as item-key and
              # the attribute text content as item-value.
              values = {
                  'NAME': "P(%d)" % (number + 1),
                  'XPOS': "x = %.3f" % point[0],
                  'YPOS': "y = %.3f" % point[1]
              }

              # Every flag has a different scaling and a rotation of +15 deg.
              random_scale = 0.5 + random.random() * 2.0
              blockref = msp.add_blockref('FLAG', point, dxfattribs={
                  'rotation': 15
              }).set_scale(random_scale)
              blockref.add_auto_attribs(values)

          # Save the drawing.
          doc.saveas("auto_blockref_tutorial.dxf")

   Get/Set Attributes of Existing Block References
       See the howto: Get/Set Block Reference Attributes

   Evaluate Wrapped Block References
       As mentioned above the evaluation of block references wrapped into anonymous blocks is complex:

          # Collect all anonymous block references starting with '*U'
          anonymous_block_refs = modelspace.query('INSERT[name ? "^\*U.+"]')

          # Collect the references of the 'FLAG' block
          flag_refs = []
          for block_ref in anonymous_block_refs:
              # Get the block layout of the anonymous block
              block = doc.blocks.get(block_ref.dxf.name)
              # Find all block references to 'FLAG' in the anonymous block
              flag_refs.extend(block.query('INSERT[name=="FLAG"]'))

          # Evaluation example: collect all flag names.
          flag_numbers = [
              flag.get_attrib_text("NAME")
              for flag in flag_refs
              if flag.has_attrib("NAME")
          ]

          print(flag_numbers)

   Exploding Block References
       This  is an advanced feature and the results may not be perfect.  A non-uniform scaling lead to incorrect
       results for text entities (TEXT, MTEXT, ATTRIB) and some other entities  like  HATCH  with  circular-  or
       elliptic  path  segments.  The “exploded” entities are added to the same layout as the block reference by
       default.

          for flag_ref in msp.query('INSERT[name=="FLAG"]'):
              flag_ref.explode()

   Examine Entities of Block References
       To just examine the content entities of a  block  reference  use  the  virtual_entities()  method.   This
       methods  yields  “virtual”  entities  with  properties  identical to “exploded” entities but they are not
       stored in the entity database, have no handle and are not assigned to any layout.

          for flag_ref in msp.query('INSERT[name=="FLAG"]'):
              for entity in flag_ref.virtual_entities():
                  if entity.dxftype() == "LWPOLYLINE":
                      print(f"Found {str(entity)}.")

   Tutorial for LWPolyline
       The LWPolyline (lightweight polyline) was introduced in DXF R13/14 and it is defined as a single  graphic
       entity, which differs from the old-style Polyline entity, which is defined as a group of sub-entities. It
       is  recommended  to  prefer  the LWPOLYLINE over the 2D POLYLINE entity because it requires less space in
       memory and in DXF files and displays faster in AutoCAD.

       IMPORTANT:
          The LWPOLYLINE is a planar element, therefore the (x, y) point coordinates are located in the OCS  and
          the  z-axis  is  stored in the LWPolyline.dxf.elevation attribute.  The method vertices_in_wcs returns
          the polyline vertices as WCS coordinates.

       Create a simple polyline:

          import ezdxf

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

          points = [(0, 0), (3, 0), (6, 3), (6, 6)]
          msp.add_lwpolyline(points)

          doc.saveas("lwpolyline1.dxf")

       Append multiple points to a polyline:

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

          line = msp.query("LWPOLYLINE").first
          if line is not None:
              line.append_points([(8, 7), (10, 7)])

          doc.saveas("lwpolyline2.dxf")

       The index operator [] always returns polyline points as 5-tuple (x, y,  start_width,  end_width,  bulge),
       the start_width, end_width and bulge values are 0 if not present:

          first_point = line[0]
          x, y, start_width, end_width, bulge = first_point

       The  context  manager  points()  can  be used to edit polyline points, this method was introduced because
       accessing individual points was very slow in early versions of ezdxf, in current versions  of  ezdxf  the
       direct  access  by  the  index  operator  []  is  very fast and using the context manager is not required
       anymore, but the context manager still exist and has the advantage of supporting an  user  defined  point
       format:

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

          line = msp.query("LWPOLYLINE").first

          with line.points("xyseb") as points:
              # points is a standard Python list
              # existing points are 5-tuples, but new points can be
              # set as (x, y, [start_width, [end_width, [bulge]]]) tuple
              # set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).

              # delete last 2 points
              del points[-2:]
              # adding two points
              points.extend([(4, 7), (0, 7)])

          doc.saveas("lwpolyline3.dxf")

       Each line segment can have a different start- and end width, if omitted start- and end width is 0:

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

          # point format = (x, y, [start_width, [end_width, [bulge]]])
          # set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).

          points = [(0, 0, .1, .15), (3, 0, .2, .25), (6, 3, .3, .35), (6, 6)]
          msp.add_lwpolyline(points)

          doc.saveas("lwpolyline4.dxf")

       The  first  point  carries  the start- and end-width of the first segment, the second point of the second
       segment and so on, the start- and end width value of the last point is used for the  closing  segment  if
       the  polyline  is  closed  else  these  values  are  ignored.  Start- and end width only works if the DXF
       attribute dxf.const_width is unset, delete it to be sure it’s unset:

          # no exception will be raised if const_width is already unset:
          del line.dxf.const_width

       LWPolyline can also have curved elements, they are defined by the Bulge value:

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

          # point format = (x, y, [start_width, [end_width, [bulge]]])
          # set start_width, end_width to 0 to be ignored (x, y, 0, 0, bulge).

          points = [(0, 0, 0, .05), (3, 0, .1, .2, -.5), (6, 0, .1, .05), (9, 0)]
          msp.add_lwpolyline(points)

          doc.saveas("lwpolyline5.dxf")
       [image]

       The curved segment is drawn from the point which defines the bulge value  to  the  following  point,  the
       curved  segment is always an arc. The bulge value defines the ratio of the arc sagitta (segment height h)
       to half line segment length (point distance), a bulge value of 1 defines a semicircle.  The curve  is  on
       the right side of the line for a bulge value > 0, and on the left side of the line for a bulge value < 0.

       Helper functions to handle bulge values: Bulge Related Functions

       The user defined point format, default is xyseb:

          • x = x coordinate

          • y = y coordinate

          • s = start width

          • e = end width

          • b = bulge value

          • v = (x, y) as tuple

          msp.add_lwpolyline([(0, 0, 0), (10, 0, 1), (20, 0, 0)], format="xyb")
          msp.add_lwpolyline([(0, 10, 0), (10, 10, .5), (20, 10, 0)], format="xyb")
       [image]

   Tutorial for Text
       Add a simple one line text entity by factory function add_text().

          import ezdxf
          from ezdxf.enums import TextEntityAlignment

          # The TEXT entity is a DXF primitive and is supported in all DXF versions.
          # The argument setup=True creates standard linetypes and text styles in the
          # new DXF document.
          doc = ezdxf.new("R12", setup=True)
          msp = doc.modelspace()

          # Use method set_placement() to define the TEXT alignment, because the
          # relations between the DXF attributes 'halign', 'valign', 'insert' and
          # 'align_point' are tricky.
          msp.add_text("A Simple Text").set_placement(
              (2, 3),
              align=TextEntityAlignment.MIDDLE_RIGHT
          )

          # Using a predefined text style:
          msp.add_text(
              "Text Style Example: Liberation Serif",
              height=0.35,
              dxfattribs={"style": "LiberationSerif"}
          ).set_placement((2, 6), align=TextEntityAlignment.LEFT)

          doc.saveas("simple_text.dxf")

       Alignments defined by the enum TextEntityAlignment:
                             ┌────────────┬─────────────┬───────────────┬──────────────┐
                             │ Vert/Horiz │ Left        │ Center        │ Right        │
                             ├────────────┼─────────────┼───────────────┼──────────────┤
                             │ Top        │ TOP_LEFTTOP_CENTERTOP_RIGHT    │
                             ├────────────┼─────────────┼───────────────┼──────────────┤
                             │ Middle     │ MIDDLE_LEFTMIDDLE_CENTERMIDDLE_RIGHT │
                             ├────────────┼─────────────┼───────────────┼──────────────┤
                             │ Bottom     │ BOTTOM_LEFTBOTTOM_CENTERBOTTOM_RIGHT │
                             ├────────────┼─────────────┼───────────────┼──────────────┤
                             │ Baseline   │ LEFTCENTERRIGHT        │
                             └────────────┴─────────────┴───────────────┴──────────────┘

       Special alignments are ALIGNED and FIT, they require a second alignment point, the text is justified with
       the vertical alignment Baseline on the virtual line between these two points.
                                ┌───────────┬───────────────────────────────────────┐
                                │ Alignment │ Description                           │
                                ├───────────┼───────────────────────────────────────┤
                                │ ALIGNED   │ Text  is  stretched  or compressed to │
                                │           │ fit exactly between p1 and p2 and the │
                                │           │ text  height  is  also  adjusted   to │
                                │           │ preserve height/width ratio.          │
                                ├───────────┼───────────────────────────────────────┤
                                │ FIT       │ Text  is  stretched  or compressed to │
                                │           │ fit exactly between  p1  and  p2  but │
                                │           │ only  the text width is adjusted, the │
                                │           │ text height is fixed  by  the  height │
                                │           │ attribute.                            │
                                ├───────────┼───────────────────────────────────────┤
                                │ MIDDLE    │ also  a  special  adjustment, but the │
                                │           │ result   is   the   same    as    for │
                                │           │ MIDDLE_CENTER.                        │
                                └───────────┴───────────────────────────────────────┘

   Standard Text Styles
       Setup some standard text styles and linetypes by argument setup=True:

          doc = ezdxf.new('R12', setup=True)

       Replaced all proprietary font declarations in setup_styles() (ARIAL, ARIAL_NARROW, ISOCPEUR and TIMES) by
       open source fonts, this is also the style name (e.g. {'style': 'OpenSans-Italic'}): [image]

       IMPORTANT:
          To see the defined text styles in a DXF viewer or CAD application, the applications have to know where
          the referenced TTF fonts can be found.  This configuration is not possible by ezdxf and has to be done
          for each application as described in their documentation.

          See also: Font Resources

   New Text Style
       Creating a new text style is simple:

          doc.styles.new("myStandard", dxfattribs={"font" : "OpenSans-Regular.ttf"})

       Getting  the  correct font name is often not that simple, especially on Windows.  This shows the required
       steps to get the font name for Open Sans:

          • open font folder c:\windows\fonts

          • select and open the font-family Open Sans

          • right-click on Open Sans Standard and select Properties

          • on top of the first tab you see the font name: 'OpenSans-Regular.ttf'

       The style name has to be unique in the DXF document, otherwise ezdxf  will  raise  an  DXFTableEntryError
       exception.  To  replace  an existing entry, delete the existing entry by doc.styles.remove(name), and add
       the replacement entry.

   3D Text
       It is possible to place the 2D Text entity into 3D space by using the OCS, for further  information  see:
       Tutorial for OCS/UCS Usage and Tutorial for UCS Based Transformations.

   Tutorial for MText and MTextEditor
       The  MText entity is a multi line entity with extended formatting possibilities and requires at least DXF
       version R2000, to use all features (e.g. background fill) DXF R2007 is required.

       IMPORTANT:
          The rendering result of the MTEXT entity depends on the DXF viewer or CAD application and  can  differ
          between different applications. These differences have the greatest impact on line wrapping, which can
          cause columns of text to have different heights in different applications!

          In  order  for  the  text to look similar in different programs, the formatting should be as simple as
          possible or omitted altogether.

       Prolog code:

          import ezdxf

          doc = ezdxf.new("R2007", setup=True)
          msp = doc.modelspace()

          lorem_ipsum = """
          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
          sed do eiusmod tempor incididunt ut labore et dolore magna
          aliqua. Ut enim ad minim veniam, quis nostrud exercitation
          ullamco laboris nisi ut aliquip ex ea commodo consequat.
          Duis aute irure dolor in reprehenderit in voluptate velit
          esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
          occaecat cupidatat non proident, sunt in culpa qui officia
          deserunt mollit anim id est laborum.
          """

   Adding a MTEXT entity
       The MTEXT entity can be added to  any  layout  (modelspace,  paperspace  or  block)  by  the  add_mtext()
       function.

          # store MTEXT entity for additional manipulations
          mtext = msp.add_mtext(lorem_ipsum, dxfattribs={"style": "OpenSans"})

       This  adds  a  MTEXT  entity  with  text style “OpenSans”.  The MTEXT content can be accessed by the text
       attribute, this attribute can be edited like any Python string:

          mtext.text += "Append additional text to the MTEXT entity."
          # even shorter with __iadd__() support:
          mtext += "Append additional text to the MTEXT entity."
       [image]

       The MText entity has an alias MText.dxf.text for the MText.text attribute for compatibility to  the  Text
       entity.

       IMPORTANT:
          Line  endings  “\n”  will be replaced by the MTEXT line endings “\P” at DXF export, but not vice versa
          “\P” by “\n” at DXF file loading.

   Text placement
       The location of the MTEXT entity is defined by the MText.dxf.insert  and  the  MText.dxf.attachment_point
       attributes  in  WCS  coordinates.  The attachment_point defines the text alignment relative to the insert
       location, default value is 1.

       Attachment point constants defined in ezdxf.lldxf.const:
                                        ┌────────────────────────────┬───────┐
                                        │ MText.dxf.attachment_point │ Value │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_TOP_LEFT             │ 1     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_TOP_CENTER           │ 2     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_TOP_RIGHT            │ 3     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_MIDDLE_LEFT          │ 4     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_MIDDLE_CENTER        │ 5     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_MIDDLE_RIGHT         │ 6     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_BOTTOM_LEFT          │ 7     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_BOTTOM_CENTER        │ 8     │
                                        ├────────────────────────────┼───────┤
                                        │ MTEXT_BOTTOM_RIGHT         │ 9     │
                                        └────────────────────────────┴───────┘

       The MTEXT entity has a method for setting insert, attachment_point and rotation attributes by  one  call:
       set_location()

   Character height
       The  character  height  is defined by the DXF attribute MText.dxf.char_height in drawing units, which has
       also consequences for the line spacing of the MTEXT entity:

          mtext.dxf.char_height = 0.5

       The character height can be changed inline, see also MTEXT formatting and MText Inline Codes.

   Text rotation (direction)
       The MText.dxf.rotation attribute defines the text rotation as angle between the x-axis and the horizontal
       direction of the  text  in  degrees.   The  MText.dxf.text_direction  attribute  defines  the  horizontal
       direction of MTEXT as vector in WCS.  Both attributes can be present at the same entity, in this case the
       MText.dxf.text_direction attribute has the higher priority.

       The  MTEXT  entity  has  two  methods  to  get/set rotation: get_rotation() returns the rotation angle in
       degrees independent from definition as angle or direction, and set_rotation() set the rotation  attribute
       and removes the text_direction attribute if present.

   Defining a wrapping border
       The  wrapping  border  limits the text width and forces a line break for text beyond this border. Without
       attribute dxf.width (or setting 0) the lines are wrapped only at the regular line endings “ \P” or  “\n”,
       setting  the reference column width forces additional line wrappings at the given width.  The text height
       can not be limited, the text always occupies as much space as needed.

          mtext.dxf.width = 60
       [image]

   MTEXT formatting
       MTEXT supports inline formatting by special codes: MText Inline Codes

          mtext.text = "{\\C1;red text} - {\\C3;green text} - {\\C5;blue text}"
       [image]

       See also the support class MTextEditor.

   Stacked text
       MTEXT supports stacked text:

          # the space ' ' in front of 'Lower' and the ';' behind 'Lower' are necessary
          # combined with vertical center alignment
          mtext.text = "\\A1;\\SUpper^ Lower; - \\SUpper/ Lower;} - \\SUpper# Lower;"
       [image]

       See also the support class MTextEditor.

   Background color (filling)
       The MTEXT entity can have a background filling:

       • AutoCAD Color Index (ACI)

       • true color value as (r, g, b) tuple

       • color name as string, use special name 'canvas' to use the canvas background color

       Because of the complex dependencies ezdxf provides a method to set all required DXF attributes at once:

          mtext.set_bg_color(2, scale=1.5)

       The parameter scale determines how much border there is around the text, the value is based on  the  text
       height, and should be in the range of 1 - 5, where 1 fits exact the MTEXT entity.  [image]

   MTextEditor
       WARNING:
          The  MTextEditor assembles just the inline code, which has to be parsed and rendered by the target CAD
          application, ezdxf has no influence to that result.

          Keep inline formatting as simple as possible, don’t test the limits of its capabilities, this will not
          work across different CAD applications and keep the formatting in a logic manner like, do  not  change
          paragraph properties in the middle of a paragraph.

          There is no official documentation for the inline codes!

       The MTextEditor class provides a floating interface to build MText content in an easy way.

       This  example  only  shows  the  connection  between  MText  and the MTextEditor, and shows no additional
       features to the first example of this tutorial:

   Init Editor
          import ezdxf
          from ezdxf.tools.text import MTextEditor

          doc = ezdxf.new("R2007", setup=True)
          msp = doc.modelspace()

          lorem_ipsum = """
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, ... see prolog code
          """

          # create a new editor object with an initial text:
          editor = MTextEditor(lorem_ipsum)

          # get the MTEXT content string from the editor by the str() function:
          mtext = msp.add_mtext(str(editor), dxfattribs={"style": "OpenSans"})

       Tutorial Prolog:

          # use constants defined in MTextEditor:
          NP = MTextEditor.NEW_PARAGRAPH

          ATTRIBS = {
              "char_height": 0.7,
              "style": "OpenSans",
              "width": 10,
          }
          editor = MTextEditor("using colors:" + NP)

   Set Text Color
       There are three ways to change the color inline:

       • by color name “red”, “green”, “blue”, “yellow”, “cyan”, “magenta”, “white”

       • by AutoCAD Color Index (ACI)

       • by RGB values

          # RED: set color by name - red, green, blue, yellow, cyan, magenta, white
          editor.color("red").append("RED" + NP)
          # RED: the color stays the same until the next change
          editor.append("also RED" + NP)

          # GREEN: change color by ACI (AutoCAD Color Index)
          editor.aci(3).append("GREEN" + NP)

          # BLUE: change color by RGB tuples
          editor.rgb((0, 0, 255)).append("BLUE" + NP)

          # add the MTEXT entity to the model space:
          msp.add_mtext(str(editor), attribs)
       [image]

   Changing Text Height
       The MtextEditor.height() method set the text height as absolute value in drawing units (text height = cap
       height):

          attribs = dict(ATTRIBS)
          attribs["width"] = 40.0
          editor = MTextEditor("changing text height absolute: default height is 0.7" + NP)
          # doubling the default height = 1.4
          editor.height(1.4)
          editor.append("text height: 1.4" + NP)
          editor.height(3.5).append("text height: 3.5" + NP)
          editor.height(0.7).append("back to default height: 0.7" + NP)
          msp.add_mtext(str(editor), attribs)
       [image]

       The MtextEditor.scale_height() method set the text height by a relative factor,  the  MtextEditor  object
       does  not  keep track of current text height, you have to do this by yourself. The initial text height is
       MText.dxf.char_height:

          attribs = dict(ATTRIBS)
          attribs["width"] = 40.0
          editor = MTextEditor("changing text height relative: default height is 0.7" + NP)
          # this is the default text height in the beginning:
          current_height = attribs["char_height"]
          # The text height can only be changed by a factor:
          editor.scale_height(2)  # scale by 2 = 1.4
          # keep track of the actual height:
          current_height *= 2
          editor.append("text height: 1.4" + NP)
          # to set an absolute height, calculate the required factor:
          desired_height = 3.5
          factor = desired_height / current_height
          editor.scale_height(factor).append("text height: 3.5" + NP)
          current_height = desired_height
          # and back to 0.7
          editor.scale_height(0.7 / current_height).append("back to default height: 0.7" + NP)
          msp.add_mtext(str(editor), attribs).set_location(insert=location)

   Changing Font
       The font name for changing MText fonts inline is the font family name!  The font family name is the  name
       shown  in  font  selection  widgets in desktop applications: “Arial”, “Times New Roman”, “Comic Sans MS”.
       The font has to be installed at the  target  system,  else  then  CAD  default  font  will  be  used,  in
       AutoCAD/BricsCAD is this the font defined for the text style “Standard”.

       IMPORTANT:
          The  DXF/DWG  format  is  not  optimal  for  preserving text layouts across multiple systems, and it’s
          getting really bad across different CAD applications.

          attribs = dict(ATTRIBS)
          attribs["width"] = 15.0
          editor = MTextEditor("changing fonts:" + NP)
          editor.append("Default: Hello World!" + NP)
          editor.append("SimSun: ")
          # change font in a group to revert back to the default font at the end:
          simsun_editor = MTextEditor().font("SimSun").append("你好,世界" + NP)
          # reverts the font back at the end of the group:
          editor.group(str(simsun_editor))
          # back to default font OpenSans:
          editor.append("Times New Roman: ")
          # change font outside of a group until next font change:
          editor.font("Times New Roman").append("Привет мир!" + NP)
          # If the font does not exist, a replacement font will be used:
          editor.font("Does not exist").append("This is the replacement font!")
          msp.add_mtext(str(editor), attribs)
       [image]

   Set Paragraph Properties
       The paragraph properties are set by the  paragraph()  method  and  a  ParagraphProperties  object,  which
       bundles all paragraph properties in a named tuple.

       Each paragraph can have its own properties for:

       • indentation arguments:

            • indent is the left indentation of the first line

            • left  is the left side indentation of the paragraph

            • right is the right side indentation of the paragraph

       • text adjustment: align, by enum MTextParagraphAlignment

            • MTextParagraphAlignment.LEFT

            • MTextParagraphAlignment.RIGHT

            • MTextParagraphAlignment.CENTER

            • MTextParagraphAlignment.JUSTIFIED

            • MTextParagraphAlignment.DISTRIBUTED

       • tabulator stops: tab_stops, a tuple of tabulator stops

       Indentation   and   tabulator   stops   are  multiples  of  the  default  MText  text  height  stored  in
       MText.dxf.char_height. Calculate the drawing units for indentation and tabulator  stops,  by  multiplying
       the indentation value by the char_height value.

       Mtext paragraphs are separated by new paragraph “\P” characters.

          # import support classes:
          from ezdxf.tools.text import ParagraphProperties, MTextParagraphAlignment

          attribs = dict(ATTRIBS)
          attribs["char_height"] = 0.25
          attribs["width"] = 7.5
          editor = MTextEditor("Indent the first line:" + NP)
          props = ParagraphProperties(
              indent=1,  # indent first line = 1x0.25 drawing units
              align=MTextParagraphAlignment.JUSTIFIED
          )
          editor.paragraph(props)
          editor.append(lorem_ipsum)
          msp.add_mtext(str(editor), attribs)
       [image]

       The first line indentation “indent” is relative to the “left” indentation.

          # import support classes:
          from ezdxf.tools.text import ParagraphProperties, MTextParagraphAlignment

          attribs = dict(ATTRIBS)
          attribs["char_height"] = 0.25
          attribs["width"] = 7.5
          editor = MTextEditor("Indent left paragraph side:" + NP)
          indent = 0.7  # 0.7 * 0.25 = 0.175 drawing units
          props = ParagraphProperties(
              # first line indentation is relative to "left", this reverses the
              # left indentation:
              indent=-indent,  # first line
              # indent left paragraph side:
              left=indent,
              align=MTextParagraphAlignment.JUSTIFIED
          )
          editor.paragraph(props)
          editor.append(" ".join(lorem_ipsum(100)))
          msp.add_mtext(str(editor), attribs).set_location(insert=location)
       [image]

   Bullet List
       There  are  no  special  commands  to build bullet list, the list is build of indentation and a tabulator
       stop. Each list item needs a marker  as  an  arbitrary  string.  For  more  information  about  paragraph
       indentation and tabulator stops see also chapter Set Paragraph Properties.

          attribs = dict(ATTRIBS)
          attribs["char_height"] = 0.25
          attribs["width"] = 7.5
          bullet = "•"  # alt + numpad 7
          editor = MTextEditor("Bullet List:" + NP)
          editor.bullet_list(
              indent=1,
              bullets=[bullet] * 3,  # each list item needs a marker
              content=[
                  "First item",
                  "Second item",
                  " ".join(lorem_ipsum(30)),
              ])
          msp.add_mtext(str(editor), attribs)
       [image]

   Numbered List
       There  are  no  special commands to build numbered list, the list is build of indentation and a tabulator
       stop. There is no automatic numbering, but therefore the absolute freedom for using any  string  as  list
       marker.   For  more  information  about  paragraph  indentation  and tabulator stops see also chapter Set
       Paragraph Properties.

          attribs = dict(ATTRIBS)
          attribs["char_height"] = 0.25
          attribs["width"] = 7.5
          editor = MTextEditor("Numbered List:" + NP)
          editor.bullet_list(
              indent=1,
              bullets=["1.", "2.", "3."],
              content=[
                  "First item",
                  "Second item",
                  " ".join(lorem_ipsum(30)),
              ])
          msp.add_mtext(str(editor), attribs)
       [image]

   Stacked Text
       MText supports stacked text (fractions) as a single inline code, which means it is not possible to change
       any property inside the fraction.  This example shows a fraction with scaled down text height, placed  in
       a group to revert the text height afterwards:

          editor = MTextEditor("Stacked text:" + NP)

          stack = MTextEditor().scale_height(0.6).stack("1", "2", "^")
          editor.append("over: ").group(str(stack)).append(NP)

          stack = MTextEditor().scale_height(0.6).stack("1", "2", "/")
          editor.append("fraction: ").group(str(stack)).append(NP)

          stack = MTextEditor().scale_height(0.6).stack("1", "2", "#")
          editor.append("slanted: ").group(str(stack)).append(NP)

          # Additional formatting in numerator and denominator is not supported
          # by AutoCAD or BricsCAD, switching the color inside the stacked text
          # to red does not work:
          numerator = MTextEditor().color("red").append("1")
          stack = MTextEditor().scale_height(0.6).stack(str(numerator), "2", "#")
          editor.append("color red: ").group(str(stack)).append(NP)

          msp.add_mtext(str(editor), attribs)
       [image]

       SEE ALSO:MTextEditor example code on github.

          • Documentation of MTextEditor

   Tutorial for Spline
       Background information about B-spline at Wikipedia.

   Splines from fit points
       Splines can be defined by fit points only, this means the curve passes all given fit points.  AutoCAD and
       BricsCAD generates required control points and knot values by itself, if only fit points are present.

       Create a simple spline:

          doc = ezdxf.new("R2000")

          fit_points = [(0, 0, 0), (750, 500, 0), (1750, 500, 0), (2250, 1250, 0)]
          msp = doc.modelspace()
          spline = msp.add_spline(fit_points)
       [image]

       Append a fit point to a spline:

          # fit_points, control_points, knots and weights are list-like containers:
          spline.fit_points.append((2250, 2500, 0))
       [image]

       You  can  set  additional  control points, but if they do not fit the auto-generated AutoCAD values, they
       will be ignored and don’t mess around with knot values.

          doc = ezdxf.readfile("AutoCAD_generated.dxf")

          msp = doc.modelspace()
          spline = msp.query("SPLINE").first

          # fit_points, control_points, knots and weights are list-like objects:
          spline.fit_points.append((2250, 2500, 0))

       As far as I have tested, this approach works without  complaints  from  AutoCAD,  but  for  the  case  of
       problems remove invalid data from the SPLINE entity:

          # current control points do not match spline defined by fit points
          spline.control_points = []

          # count of knots is not correct:
          # count of knots = count of control points + degree + 1
          spline.knots = []

          # same for weights, count of weights == count of control points
          spline.weights = []

   Splines by control points
       Creating  splines from fit points is the easiest way, but this method is also the least accurate, because
       a spline is defined by control points and knot values, which are generated for the case of  a  definition
       by  fit  points, and the worst fact is that for every given set of fit points exist an infinite number of
       possible splines as solution.

       AutoCAD (and BricsCAD) uses an unknown proprietary algorithm to generate control points and  knot  values
       from  fit points.  Therefore splines generated from fit points by ezdxf do not match splines generated by
       AutoCAD (BricsCAD).

       To ensure the same spline geometry for all CAD applications, the spline has  to  be  defined  by  control
       points.   The method add_spline_control_frame() adds a spline passing the given fit points by calculating
       the control points by the Global Curve Interpolation algorithm.  There  is  also  a  low  level  function
       ezdxf.math.global_bspline_interpolation() which calculates the control points from fit points.

          msp.add_spline_control_frame(fit_points, method='uniform', dxfattribs={'color': 1})
          msp.add_spline_control_frame(fit_points, method='chord', dxfattribs={'color': 3})
          msp.add_spline_control_frame(fit_points, method='centripetal', dxfattribs={'color': 5})

       • black curve: AutoCAD/BricsCAD spline generated from fit points

       • red curve: spline curve interpolation, “uniform” method

       • green curve: spline curve interpolation, “chord” method

       • blue curve: spline curve interpolation, “centripetal” method
       [image]

   Open Spline
       Add  and  open  (clamped)  spline defined by control points with the method add_open_spline(). If no knot
       values are given, an open uniform knot vector will be generated. A clamped B-spline starts at  the  first
       control point and ends at the last control point.

          control_points = [(0, 0, 0), (1250, 1560, 0), (3130, 610, 0), (2250, 1250, 0)]
          msp.add_open_spline(control_points)
       [image]

   Rational Spline
       Rational  B-splines  have a weight for every control point, which can raise or lower the influence of the
       control point, default weight = 1, to lower the influence set a weight < 1 to raise the influence  set  a
       weight > 1.  The count of weights has to be always equal to the count of control points.

       Example to raise the influence of the first control point:

          msp.add_closed_rational_spline(control_points, weights=[3, 1, 1, 1])
       [image]

   Spline properties
       Check  if  spline is a closed curve or close/open spline, for a closed spline the last point is connected
       to the first point:

          if spline.closed:
              # this spline is closed
              pass

          # close spline
          spline.closed = True

          # open spline
          spline.closed = False

       Set start- and end tangent for splines defined by fit points:

          spline.dxf.start_tangent = (0, 1, 0)
          spline.dxf.end_tangent = (1, 0, 0)

       Get data count as stored in DXF attributes:

          count = spline.dxf.n_fit_points
          count = spline.dxf.n_control_points
          count = spline.dxf.n_knots

       Get data count from existing data:

          count = spline.fit_point_count
          count = spline.control_point_count
          count = spline.knot_count

   Tutorial for Polyface
       The Polyface entity represents a 3D mesh build of vertices and faces and is  just  an  extended  POLYLINE
       entity  with  a  complex VERTEX structure. The Polyface entity was used in DXF R12 and older DXF versions
       and is still supported by newer DXF versions. The  new  Mesh  entity  stores  the  same  data  much  more
       efficient but requires DXF R2000 or newer. The Polyface entity supports only triangles and quadrilaterals
       as faces, the Mesh entity supports also n-gons.

       Its  recommended  to use the MeshBuilder objects to create 3D meshes and render them as POLYFACE entities
       by the render_polymesh() method into a layout:

          import ezdxf
          from ezdxf import colors
          from ezdxf.gfxattribs import GfxAttribs
          from ezdxf.render import forms

          cube = forms.cube().scale_uniform(10).subdivide(2)
          red = GfxAttribs(color=colors.RED)
          green = GfxAttribs(color=colors.GREEN)
          blue = GfxAttribs(color=colors.BLUE)

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

          # render as MESH entity
          cube.render_mesh(msp, dxfattribs=red)
          cube.translate(20)

          # render as POLYFACE a.k.a. POLYLINE entity
          cube.render_polyface(msp, dxfattribs=green)
          cube.translate(20)

          # render as a bunch of 3DFACE entities
          cube.render_3dfaces(msp, dxfattribs=blue)

          doc.saveas("meshes.dxf")
       [image]

       WARNING:
          If the mesh contains n-gons the render methods for POLYFACE and 3DFACES  subdivides  the  n-gons  into
          triangles, which does not work for concave faces.

       The usage of the MeshBuilder object is also recommended for inspecting Polyface entities:

       • MeshBuilder.vertices is a sequence of 3D points as ezdxf.math.Vec3 objects

       • a face in MeshBuilder.faces is a sequence of indices into the MeshBuilder.vertices sequence

          import ezdxf
          from ezdxf.render import MeshBuilder

          def process(mesh):
              # vertices is a sequence of 3D points
              vertices = mses.vertices
              # a face is a sequence of indices into the vertices sequence
              faces = mesh.faces
              ...

          doc = ezdxf.readfile("meshes.dxf")
          msp = doc.modelspace()
          for polyline in msp.query("POLYLINE"):
              if polyline.is_poly_face_mesh:
                  mesh = MeshBuilder.from_polyface(polyline)
                  process(mesh)

       SEE ALSO:
          Tutorial for Mesh

   Tutorial for Mesh
       The Mesh entity is a 3D object in WCS build up from vertices and faces.

       Create a cube mesh by directly accessing the base data structures:

          import ezdxf

          # 8 corner vertices
          cube_vertices = [
              (0, 0, 0),
              (1, 0, 0),
              (1, 1, 0),
              (0, 1, 0),
              (0, 0, 1),
              (1, 0, 1),
              (1, 1, 1),
              (0, 1, 1),
          ]

          # 6 cube faces
          cube_faces = [
              [0, 1, 2, 3],
              [4, 5, 6, 7],
              [0, 1, 5, 4],
              [1, 2, 6, 5],
              [3, 2, 6, 7],
              [0, 3, 7, 4]
          ]

          # MESH requires DXF R2000 or later
          doc = ezdxf.new("R2000")
          msp = doc.modelspace()
          mesh = msp.add_mesh()
          # do not subdivide cube, 0 is the default value
          mesh.dxf.subdivision_levels = 0
          with mesh.edit_data() as mesh_data:
              mesh_data.vertices = cube_vertices
              mesh_data.faces = cube_faces

          doc.saveas("cube_mesh_1.dxf")

       Create a cube mesh by assembling single faces using the edit_data() context manager of the Mesh class and
       the helper class MeshData:

          import ezdxf

          # 8 corner vertices
          p = [
              (0, 0, 0),
              (1, 0, 0),
              (1, 1, 0),
              (0, 1, 0),
              (0, 0, 1),
              (1, 0, 1),
              (1, 1, 1),
              (0, 1, 1),
          ]

          # MESH requires DXF R2000 or later
          doc = ezdxf.new("R2000")
          msp = doc.modelspace()
          mesh = msp.add_mesh()

          with mesh.edit_data() as mesh_data:
              mesh_data.add_face([p[0], p[1], p[2], p[3]])
              mesh_data.add_face([p[4], p[5], p[6], p[7]])
              mesh_data.add_face([p[0], p[1], p[5], p[4]])
              mesh_data.add_face([p[1], p[2], p[6], p[5]])
              mesh_data.add_face([p[3], p[2], p[6], p[7]])
              mesh_data.add_face([p[0], p[3], p[7], p[4]])
              # optional call optimize(): minimizes the vertex count
              mesh_data.optimize()

          doc.saveas("cube_mesh_2.dxf")

       Its  recommended  to  use the MeshBuilder objects to create 3D meshes and render them as MESH entities by
       the render_mesh() method into a layout:

          import ezdxf
          from ezdxf import colors
          from ezdxf.gfxattribs import GfxAttribs
          from ezdxf.render import forms

          cube = forms.cube().scale_uniform(10).subdivide(2)
          red = GfxAttribs(color=colors.RED)
          green = GfxAttribs(color=colors.GREEN)
          blue = GfxAttribs(color=colors.BLUE)

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

          # render as MESH entity
          cube.render_mesh(msp, dxfattribs=red)
          cube.translate(20)

          # render as POLYFACE a.k.a. POLYLINE entity
          cube.render_polyface(msp, dxfattribs=green)
          cube.translate(20)

          # render as a bunch of 3DFACE entities
          cube.render_3dfaces(msp, dxfattribs=blue)

          doc.saveas("meshes.dxf")
       [image]

       There exist some tools to manage meshes:

       • ezdxf.render.MeshBuilder: The MeshBuilder classes are helper tools to manage meshes buildup by vertices
         and faces.

       • ezdxf.render.MeshTransformer: Same functionality as MeshBuilder but supports inplace transformation.

       • ezdxf.render.MeshDiagnose: A diagnose  tool  which  can  be  used  to  analyze  and  detect  errors  of
         MeshBuilder objects like topology errors for closed surfaces.

       • ezdxf.render.FaceOrientationDetector:  A  helper  class  for  face  orientation  and face normal vector
         detection

       The ezdxf.render.forms module provides function to create basic geometries like cube, cone, sphere and so
       on and functions to create meshes from profiles by extrusion, rotation or sweeping.

       This example shows how to sweep a gear profile along a helix:

          import ezdxf
          from ezdxf.render import forms

          doc = ezdxf.new()
          doc.layers.add("MESH", color=ezdxf.colors.YELLOW)
          msp = doc.modelspace()
          # sweeping a gear-profile
          gear = forms.gear(
              8, top_width=0.01, bottom_width=0.02, height=0.02, outside_radius=0.1
          )
          helix = path.helix(radius=2, pitch=1, turns=6)
          # along a helix spine
          sweeping_path = helix.flattening(0.1)
          mesh = forms.sweep(gear, sweeping_path, close=True, caps=True)
          # and render as MESH entity
          mesh.render_mesh(msp, dxfattribs={"layer": "MESH"})
          doc.saveas("gear_along_helix.dxf")
       [image]

   Tutorial for Hatch
   Create hatches with one boundary path
       The simplest form of the Hatch entity has one polyline path with only straight lines as boundary path:

          import ezdxf

          # hatch requires DXF R2000 or later
          doc = ezdxf.new("R2000")
          msp = doc.modelspace()

          # by default a solid fill hatch with fill color=7 (white/black)
          hatch = msp.add_hatch(color=2)

          # every boundary path is a 2D element
          # vertex format for the polyline path is: (x, y[, bulge])
          # there are no bulge values in this example
          hatch.paths.add_polyline_path(
              [(0, 0), (10, 0), (10, 10), (0, 10)], is_closed=True
          )

          doc.saveas("solid_hatch_polyline_path.dxf")

       But like all polyline entities the polyline path can also have bulge values:

          import ezdxf

          # hatch requires the DXF R2000 or later
          doc = ezdxf.new("R2000")
          msp = doc.modelspace()

          # by default a solid fill hatch with fill color=7 (white/black)
          hatch = msp.add_hatch(color=2)

          # every boundary path is a 2D element
          # vertex format for the polyline path is: (x, y[, bulge])
          # bulge value 1 = an arc with diameter=10 (= distance to next vertex * bulge value)
          # bulge value > 0 ... arc is right of line
          # bulge value < 0 ... arc is left of line
          hatch.paths.add_polyline_path(
              [(0, 0, 1), (10, 0), (10, 10, -0.5), (0, 10)], is_closed=True
          )

          doc.saveas("solid_hatch_polyline_path_with_bulge.dxf")

       The most flexible way to define a boundary path is the edge path. An edge path can  have  multiple  edges
       and each edge can be one of the following elements:

          • line EdgePath.add_line()

          • arc EdgePath.add_arc()

          • ellipse EdgePath.add_ellipse()

          • spline EdgePath.add_spline()

       Create a solid hatch with an edge path (ellipse) as boundary path:

          import ezdxf

          # hatch requires the DXF R2000 or later
          doc = ezdxf.new("R2000")
          msp = doc.modelspace()

          # important: major axis >= minor axis (ratio <= 1.)
          # minor axis length = major axis length * ratio
          msp.add_ellipse((0, 0), major_axis=(0, 10), ratio=0.5)

          # by default a solid fill hatch with fill color=7 (white/black)
          hatch = msp.add_hatch(color=2)

          # every boundary path is a 2D element
          edge_path = hatch.paths.add_edge_path()
          # each edge path can contain line, arc, ellipse and spline elements
          # important: major axis >= minor axis (ratio <= 1.)
          edge_path.add_ellipse((0, 0), major_axis=(0, 10), ratio=0.5)

          doc.saveas("solid_hatch_ellipse.dxf")

   Create hatches with multiple boundary paths (islands)
       The DXF attribute hatch_style defines the island detection style:
                                    ┌───┬───────────────────────────────────────┐
                                    │ 0 │ nested - altering filled and unfilled │
                                    │   │ areas                                 │
                                    ├───┼───────────────────────────────────────┤
                                    │ 1 │ outer  -  area  between  external and │
                                    │   │ outermost path is filled              │
                                    ├───┼───────────────────────────────────────┤
                                    │ 2 │ ignore - external path is filled      │
                                    └───┴───────────────────────────────────────┘

          hatch = msp.add_hatch(
              color=1,
              dxfattribs={
                  "hatch_style": ezdxf.const.HATCH_STYLE_NESTED,
                  # 0 = nested: ezdxf.const.HATCH_STYLE_NESTED
                  # 1 = outer: ezdxf.const.HATCH_STYLE_OUTERMOST
                  # 2 = ignore: ezdxf.const.HATCH_STYLE_IGNORE
              },
          )

          # The first path has to set flag: 1 = external
          # flag const.BOUNDARY_PATH_POLYLINE is added (OR) automatically
          hatch.paths.add_polyline_path(
              [(0, 0), (10, 0), (10, 10), (0, 10)],
              is_closed=True,
              flags=ezdxf.const.BOUNDARY_PATH_EXTERNAL,
          )

       This is also the result for all 4 paths and hatch_style set to 2 (ignore).  [image]

          # The second path has to set flag: 16 = outermost
          hatch.paths.add_polyline_path(
              [(1, 1), (9, 1), (9, 9), (1, 9)],
              is_closed=True,
              flags=ezdxf.const.BOUNDARY_PATH_OUTERMOST,
          )

       This is also the result for all 4 paths and hatch_style set to 1 (outer).  [image]

          # The third path has to set flag: 0 = default
          hatch.paths.add_polyline_path(
              [(2, 2), (8, 2), (8, 8), (2, 8)],
              is_closed=True,
              flags=ezdxf.const.BOUNDARY_PATH_DEFAULT,
          )

       [image]

          # The forth path has to set flag: 0 = default, and so on
          hatch.paths.add_polyline_path(
              [(3, 3), (7, 3), (7, 7), (3, 7)],
              is_closed=True,
              flags=ezdxf.const.BOUNDARY_PATH_DEFAULT,
          )

          doc.saveas(OUTDIR / "solid_hatch_islands_04.dxf")

       [image]

       The expected result of combinations of various hatch_style values and paths flags,  or  the  handling  of
       overlapping paths is not documented by the DXF reference, so don’t ask me, ask Autodesk or just try it by
       yourself and post your experience in the forum.

   Example for Edge Path Boundary
          hatch = msp.add_hatch(color=1)

          # 1. polyline path
          hatch.paths.add_polyline_path(
              [
                  (240, 210, 0),
                  (0, 210, 0),
                  (0, 0, 0.0),
                  (240, 0, 0),
              ],
              is_closed=1,
              flags=ezdxf.const.BOUNDARY_PATH_EXTERNAL,
          )
          # 2. edge path
          edge_path = hatch.paths.add_edge_path(flags=ezdxf.const.BOUNDARY_PATH_OUTERMOST)
          edge_path.add_spline(
              control_points=[
                  (126.658105895725, 177.0823706957212),
                  (141.5497003747484, 187.8907860433995),
                  (205.8997365206943, 154.7946313459515),
                  (113.0168862297068, 117.8189380884978),
                  (202.9816918983783, 63.17222935389572),
                  (157.363511042264, 26.4621294342132),
                  (144.8204003260554, 28.4383294369643),
              ],
              knot_values=[
                  0.0,
                  0.0,
                  0.0,
                  0.0,
                  55.20174685732758,
                  98.33239645153571,
                  175.1126541251052,
                  213.2061566683142,
                  213.2061566683142,
                  213.2061566683142,
                  213.2061566683142,
              ],
          )
          edge_path.add_arc(
              center=(152.6378550678883, 128.3209356351659),
              radius=100.1880612627354,
              start_angle=94.4752130054052,
              end_angle=177.1345242028005,
          )
          edge_path.add_line(
              (52.57506282464041, 123.3124200796114),
              (126.658105895725, 177.0823706957212),
          )

       [image]

   Associative Boundary Paths
       A HATCH entity can be associative to a base geometry, which means if the base geometry is edited in a CAD
       application  the  HATCH  get  the  same  modification.   Because  ezdxf  is  not  a CAD application, this
       association is not maintained nor verified by ezdxf, so if you modify the base  geometry  afterwards  the
       geometry  of  the  boundary  path  is  not updated and no verification is done to check if the associated
       geometry matches the boundary path, this opens many possibilities to create invalid DXF files:  USE  WITH
       CARE.

       This example associates a LWPOLYLINE entity to the hatch created from the LWPOLYLINE vertices:

          # Create base geometry
          lwpolyline = msp.add_lwpolyline(
              [(0, 0, 0), (10, 0, 0.5), (10, 10, 0), (0, 10, 0)],
              format="xyb",
              close=True,
          )

          hatch = msp.add_hatch(color=1)
          path = hatch.paths.add_polyline_path(
              # get path vertices from associated LWPOLYLINE entity
              lwpolyline.get_points(format="xyb"),
              # get closed state also from associated LWPOLYLINE entity
              is_closed=lwpolyline.closed,
          )

          # Set association between boundary path and LWPOLYLINE
          hatch.associate(path, [lwpolyline])

       An EdgePath needs associations to all geometry entities forming the boundary path.

   Predefined Hatch Pattern
       Use predefined hatch pattern by name:

          hatch.set_pattern_fill("ANSI31", scale=0.5)
       [image]

       SEE ALSO:
          Tutorial for Hatch Pattern Definition

   Tutorial for Hatch Pattern Definition
       A  hatch  pattern  consist of one or more hatch lines. A hatch line defines a set of lines which have the
       same orientation an the same line pattern. All the lines defined by a hatch line are parallel and have  a
       constant  distance  to  each  other.  The  origin  defines the start point of the hatch line and also the
       starting point of the line pattern. The direction defines the angle between the WCS x-axis and the  hatch
       line. The offset is a 2D vector which will be added consecutively the the origin for each new hatch line.
       The  line  pattern  has the same format as as the simple linetype pattern (Tutorial for Creating Linetype
       Pattern).

       IMPORTANT:
          The hatch pattern must be defined for a hatch scaling factor of 1.0 and a hatch rotation  angle  of  0
          degrees!

       The  first  example  creates  a  simple pattern of horizontal solid lines with a vertical distance of 0.5
       drawing units.

          import ezdxf

          doc = ezdxf.new("R2010")
          msp = doc.modelspace()
          hatch = msp.add_hatch()
          hatch.set_pattern_fill(
              "MyPattern",
              color=7,
              angle=0,
              scale=1.0,
              style=0,  # normal hatching style
              pattern_type=0,  # user-defined
              # pattern definition as list of:
              # [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
              # line pattern is a solid line
              definition=[[0, (0, 0), (0, 0.5), []]],

          )
          points = [(0, 0), (10, 0), (10, 10), (0, 10)]
          hatch.paths.add_polyline_path(points)
          msp.add_lwpolyline(points, close=True, dxfattribs={"color": 1})
          doc.saveas("user_defined_hatch_pattern.dxf")
       [image]

       The next example shows how the offset value works:

          # -x-x-x- snip -x-x-x-
          hatch = msp.add_hatch()
          hatch.set_pattern_fill(
              "MyPattern",
              color=7,
              angle=0,
              scale=1.0,
              style=0,  # normal hatching style
              pattern_type=0,  # user-defined
              # the line pattern is a dashed line:  - - - -
              # the offset is 1 unit vertical and 0.3 units horizontal
              # [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
              definition=[[0, (0, 0), (0.3, 1), [1, -1]]],

          )
          # -x-x-x- snip -x-x-x-
       [image]

       The next example combines two parallel hatch lines, the origin defines how the  hatch  lines  are  offset
       from each other:

          # -x-x-x- snip -x-x-x-
          hatch = msp.add_hatch()
          hatch.set_pattern_fill(
              "MyPattern",
              color=7,
              angle=0,
              scale=1.0,
              style=0,  # normal hatching style
              pattern_type=0,  # user-defined
              # [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
              definition=[
                  [0, (0, 0), (0.3, 1), [1, -1]],  # dashed line
                  [0, (0, 0.5), (0, 1), []],  # solid line
              ],
          )
          # -x-x-x- snip -x-x-x-
       [image]

       The  next  example  combines two hatch lines with different angles.  The origins can be the same for this
       example. The Vec2 class is used to calculate the offset value for a normal distance of 0.7 drawing  units
       between the slanted lines:

          from ezdxf.math import Vec2

          # -x-x-x- snip -x-x-x-
          hatch = msp.add_hatch()
          # offset vector for a normal distance of 0.7 for a 45 deg slanted hatch line
          offset = Vec2.from_deg_angle(45 + 90, length=0.7)
          hatch.set_pattern_fill(
              "MyPattern",
              color=7,
              angle=0,
              scale=1.0,
              style=0,  # normal hatching style
              pattern_type=0,  # user-defined
              # [angle in degree, origin as 2d vector, offset as 2d vector, line pattern]
              definition=[
                  [0, (0, 0), (0, 1), [1, -1]],  # horizontal dashed line
                  [45, (0, 0), offset, []],  # slanted solid line
              ],
          )
          # -x-x-x- snip -x-x-x-
       [image]

   Tutorial for Image and ImageDef
       This example shows how to use a raster image in a DXF document.  Each IMAGE entity requires an associated
       IMAGEDEF  entity  in  the  objects section, which stores the filename of the linked image and the size in
       pixels.  Multiple IMAGE entities can share the same IMAGEDEF entity.

       IMPORTANT:
          The raster image is NOT embedded in the DXF file!

          import ezdxf

          # The IMAGE entity requires the DXF R2000 format or later.
          doc = ezdxf.new("R2000")

          # The IMAGEDEF entity is like a block definition, it just defines the image.
          my_image_def = doc.add_image_def(
              filename="mycat.jpg", size_in_pixel=(640, 360)
          )

          msp = doc.modelspace()
          # The IMAGE entity is like the INSERT entity, it's just an image reference,
          # and there can be multiple references to the same picture in a DXF document.

          # 1st image reference
          msp.add_image(
              insert=(2, 1),
              size_in_units=(6.4, 3.6),
              image_def=my_image_def,
              rotation=0
          )
          # 2nd image reference
          msp.add_image(
              insert=(4, 5),
              size_in_units=(3.2, 1.8),
              image_def=my_image_def,
              rotation=30
          )

          # Get existing image definitions from the OBJECTS section:
          image_defs = doc.objects.query("IMAGEDEF")

          doc.saveas("dxf_with_cat.dxf")

   Tutorial for Underlay and UnderlayDefinition
       This example shows hot to insert a a PDF, DWF, DWFx or DGN file as drawing underlay. Each UNDERLAY entity
       requires an associated UNDERLAYDEF entity in the objects section, which stores the filename of the linked
       document and the parameters of the underlay. Multiple UNDERLAY entities can share  the  same  UNDERLAYDEF
       entity.

       IMPORTANT:
          The underlay file is NOT embedded into the DXF file:

          import ezdxf

          doc = ezdxf.new('AC1015')  # underlay requires the DXF R2000 format or later
          my_underlay_def = doc.add_underlay_def(filename='my_underlay.pdf', name='1')
          # The (PDF)DEFINITION entity is like a block definition, it just defines the underlay
          # 'name' is misleading, because it defines the page/sheet to be displayed
          # PDF: name is the page number to display
          # DGN: name='default' ???
          # DWF: ????

          msp = doc.modelspace()
          # add first underlay
          msp.add_underlay(my_underlay_def, insert=(2, 1, 0), scale=0.05)
          # The (PDF)UNDERLAY entity is like the INSERT entity, it creates an underlay reference,
          # and there can be multiple references to the same underlay in a drawing.

          msp.add_underlay(my_underlay_def, insert=(4, 5, 0), scale=.5, rotation=30)

          # get existing underlay definitions, Important: UNDERLAYDEFs resides in the objects section
          pdf_defs = doc.objects.query('PDFDEFINITION')  # get all pdf underlay defs in drawing

          doc.saveas("dxf_with_underlay.dxf")

   Tutorial for MultiLeader
       A multileader object typically consists of an arrowhead, a horizontal landing (a.k.a. “dogleg”), a leader
       line or curve, and either a MTEXT object or a BLOCK.

       Factory methods of the BaseLayout class to create new MultiLeader entities:

          • add_multileader_mtext()add_multileader_block()

       Because of the complexity of the MULTILEADER entity, the factory method add_multileader_mtext() returns a
       MultiLeaderMTextBuilder  instance  to  build  a new entity and the factory method add_multileader_block()
       returns a MultiLeaderBlockBuilder instance.

       Due of the lack of good documentation it’s not  possible  to  support  all  combinations  of  MULTILEADER
       properties  with  decent  quality,  so  stick  to  recipes and hints shown in this tutorial to get usable
       results otherwise, you will enter uncharted territory.

       The rendering result of  the  MULTILEADER  entity  is  highly  dependent  on  the  CAD  application.  The
       MULTILEADER  entity  does  not  have  a pre-rendered anonymous block of DXF primitives like all DIMENSION
       entities, so results may vary from CAD application to CAD  application.  The  general  support  for  this
       entity  is  only  good  in  Autodesk  products  other  CAD  applications  often  struggle  when rendering
       MULTILEADERS, even my preferred testing application BricsCAD has rendering issues.

       IMPORTANT:
          MULTILEADER support has flaws in many CAD applications except Autodesk products!

       SEE ALSO:ezdxf.render.MultiLeaderBuilder classes

          • ezdxf.entities.MultiLeader class

          • ezdxf.entities.MLeaderStyle class

          • ezdxf.tools.text.MTextEditor class

          • MULTILEADER Internals

   MTEXT Quick Draw
       Full Python script: mtext_quick_leader.py

       The quick_leader() method of a MTEXT - MULTILEADER entity constructs the geometry parameters  in  reverse
       manner, starting from a given target point:

       DXF document setup:

              doc = ezdxf.new(setup=True)
              # Create a new custom MLEADERSTYLE:
              mleaderstyle = doc.mleader_styles.duplicate_entry("Standard", "EZDXF")
              # The required TEXT style "OpenSans" was created by ezdxf.new() because setup is True:
              mleaderstyle.set_mtext_style("OpenSans")
              msp = doc.modelspace()

       Draw a red circle to mark the target point:

              target_point = Vec2(40, 15)
              msp.add_circle(
                  target_point, radius=0.5, dxfattribs=GfxAttribs(color=colors.RED)
              )

       Create four horizontal placed MULTILEADER entities pointing at the target point, the first segment of the
       leader line is determined by an angle in this example pointing away from the target point:

              for angle in [45, 135, 225, -45]:
                  ml_builder = msp.add_multileader_mtext("EZDXF")
                  ml_builder.quick_leader(
                      f"angle={angle}°\n2nd text line",
                      target=target_point,
                      segment1=Vec2.from_deg_angle(angle, 14),
                  )

       [image]

       The  content  is  automatically  aligned  to  the end of the leader line. The first segment is a relative
       vector to the target point and the optional second segment vector is relative to the  end  of  the  first
       segment.  The default connection type is horizontal but can be changed to vertical:

       A smaller text size is required:

              mleaderstyle = doc.mleader_styles.duplicate_entry("Standard", "EZDXF")
              mleaderstyle.set_mtext_style("OpenSans")
              mleaderstyle.dxf.char_height = 2.0  # set the default char height of MTEXT

       Adding vertical placed MULTILEADER entities:

              for angle in [45, 135, 225, -45]:
                  ml_builder = msp.add_multileader_mtext("EZDXF")
                  ml_builder.quick_leader(
                      f"angle={angle}°\n2nd text line",
                      target=target_point,
                      segment1=Vec2.from_deg_angle(angle, 14),
                      connection_type=mleader.VerticalConnection.center_overline,
                  )

       This  example  already  shows  the  limitation  caused  by  different  text  renderings  in  various  CAD
       applications. The ezdxf text measurement by matplotlib is different  to  AutoCAD  and  BricsCAD  and  the
       result is a misalignment of the overline and the leader line.

       The DXF file shown in BricsCAD: [image]

       The same DXF file shown with the ezdxf view command (drawing add-on): [image]

       My  advice  is to avoid vertical placed MULTILEADER entities at all and for horizontal placed MULTILEADER
       entities avoid styles including an “underline” or an “overline”.

       The quick_leader() method is not very customizable for ease of use,  but  follows  the  settings  of  the
       associated MLeaderStyle.

       The following sections show how to have more control when adding MULTILEADER entities.

   Create MTEXT Content
       Full Python script: mtext_content.py

       This section shows how to create a MULTILEADER entity with MTEXT content the manual way with full control
       over all settings.

       For  good results the MTEXT alignment should match the leader connection side, e.g. if you attach leaders
       to the left side also align the MTEXT to the left side, for leaders attached at the right side, align the
       MTEXT to the right side and if you attach leaders at both sides one side will fit better than  the  other
       or maybe a center aligned MTEXT is a good solution, for further details see section MTEXT Alignment.

       The first example uses the default connection type of the MLEADERSTYLE “Standard” which is “middle of the
       top  line” for left and right attached leaders. The render UCS for this example is the WCS to keep things
       simple.

       Create a new MULTILEADER entity.

              ml_builder = msp.add_multileader_mtext("Standard")

       Set MTEXT content, text style and alignment.

              ml_builder.set_content(
                  "Line1\nLine2",
                  style="OpenSans",
                  alignment=mleader.TextAlignment.left,  # set MTEXT alignment!
              )

       Add the first leader on the left side.  The leader points always  to  the  first  given  vertex  and  all
       vertices are given in render UCS coordinates (= WCS in this example).

              ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])

       More than one vertex per leader can be used:

              ml_builder.add_leader_line(
                  mleader.ConnectionSide.left,
                  [Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
              )

       The insert point of the build() method is the alignment point for the MTEXT content.

              ml_builder.build(insert=Vec2(5, 0))

       The “dogleg” settings are defined by the MLEADERSTYLE “Standard”.  [image]

       This example shows a leader attached to the right side and the MTEXT aligned to the right side.

              ml_builder = msp.add_multileader_mtext("Standard")
              ml_builder.set_content(
                  "Line1\nLine2",
                  style="OpenSans",
                  alignment=mleader.TextAlignment.right,  # set MTEXT alignment!
              )
              ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
              ml_builder.build(insert=Vec2(15, 0))

       [image]

       This example shows two leaders attached to both sides and the MTEXT aligned to the left side, which shows
       that  the  right  landing gap (space between text and start of vertex) is bigger than the gap on the left
       size. This is due to the different text size calculations  from  AutoCAD/BricsCAD  and  Matplotlib.   The
       longer the text, the greater the error.

              ml_builder = msp.add_multileader_mtext("Standard")
              ml_builder.set_content(
                  "Line1\nLine1",
                  style="OpenSans",
                  alignment=mleader.TextAlignment.left,  # set MTEXT alignment!
              )
              ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])
              ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
              ml_builder.build(insert=Vec2(5, 0))

       [image]

       A centered MTEXT alignment gives a more even result.

              ml_builder = msp.add_multileader_mtext("Standard")
              ml_builder.set_content(
                  "First Line\n2. Line",
                  style="OpenSans",
                  alignment=mleader.TextAlignment.center,  # set MTEXT alignment!
              )
              ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(-20, -15)])
              ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(40, -15)])
              ml_builder.build(insert=Vec2(10, 0))

       [image]

       But  even  this  has its disadvantages, the attachment calculation is always based on the bounding box of
       the MTEXT content.  [image]

   MTEXT Connection Types
       There are four connection sides defined by the enum ezdxf.render.ConnectionSide:

          • left

          • right

          • top

          • bottom

       The MultiLeader entity supports as the name says multiple leader lines, but all have to have a horizontal
       (left/right) connection side or a vertical  (top/bottom)  connection  side,  it’s  not  possible  to  mix
       left/right and top/bottom connection sides. This is determined by the DXF format.

       There  are different connection types available for the horizontal and the vertical connection sides. All
       leaders connecting to the same side have the  same  connection  type.  The  horizontal  connection  sides
       support following connection types, defined by the enum ezdxf.render.HorizontalConnection:

          • by_style

          • top_of_top_line

          • middle_of_top_line

          • middle_of_text

          • middle_of_bottom_line

          • bottom_of_bottom_line

          • bottom_of_bottom_line_underline (not recommended)

          • bottom_of_top_line_underline (not recommended)

          • bottom_of_top_line

          • bottom_of_top_line_underline_all (not recommended)

       The   vertical   connection   sides   support   following   connection   types,   defined   by  the  enum
       ezdxf.render.VerticalConnection:

          • by_style

          • center

          • center_overline (not recommended)

       The connection type for each side can be set by the method set_connection_types(), the  default  for  all
       sides is by_style:

              ml_builder.set_connection_types(
                  left=mleader.HorizontalConnection.middle_of_top_line,
                  right=mleader.HorizontalConnection.middle_of_bottom_line,
              )

       [image]

       HINT:
          As  shown  in  the  quick draw section using connection types including underlines or overlines do not
          render well in AutoCAD/BricsCAD because of the different text  measurement  of  matplotlib,  therefore
          it’s not recommended to use any of these connection types when creating MULTILEADERS by ezdxf.

   MTEXT Alignment
       In  contrast  to the standalone MTEXT entity supports the MTEXT content entity only three text alignments
       defined by the enum ezdxf.render.TextAlignment.

          • left

          • center

          • right

       The MTEXT alignment is set as argument alignment of the set_content() method and the alignment  point  is
       the insert point of the build() method.

   Create BLOCK Content
       Full Python script: block_content.py

       This section shows how to create a MULTILEADER entity with BLOCK content the manual way with full control
       over all settings.

       The  BLOCK  content consist of a BLOCK layout and optional ATTDEF entities which defines the location and
       DXF attributes of dynamically created ATTRIB entities.

       Create the BLOCK content, the full create_square_block() function can be found  in  the  block_content.py
       script.

              block = create_square_block(
                  doc, size=8.0, margin=0.25, base_point=base_point
              )

       Create the MULTILEADER and set the content:

              ml_builder = msp.add_multileader_block(style="Standard")
              ml_builder.set_content(
                  name=block.name, alignment=mleader.BlockAlignment.insertion_point
              )

       Set the BLOCK attribute content as text:

              ml_builder.set_attribute("ONE", "Data1")
              ml_builder.set_attribute("TWO", "Data2")

       Add some leader lines to the left and right side of the BLOCK:

       Construction  plane  of the entity is defined by a render UCS.  The leader lines vertices are expected in
       render UCS coordinates, which means relative to the UCS origin and this example  shows  the  simple  case
       where the UCS is the WCS which is also the default setting.

              ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(x2, y1)])
              ml_builder.add_leader_line(mleader.ConnectionSide.right, [Vec2(x2, y2)])
              ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(x1, y1)])
              ml_builder.add_leader_line(mleader.ConnectionSide.left, [Vec2(x1, y2)])

       Last step is to build the final MULTILEADER entity.  This example uses the alignment type insertion_point
       where the insert point of the build() method is the base point of the BLOCK:

              ml_builder.build(insert=Vec2(5, 2), rotation=30)

       [image]

       The  result is shown in BricsCAD as expected, although BricsCAD shows “Center extents” as attachment type
       in the properties dialog instead of the correct attachment type “Insertion point”.

   BLOCK Connection Types
       There are four connection sides defined by the enum ezdxf.render.ConnectionSide:

          • left

          • right

          • top

          • bottom

       The connection point for leader lines is always the center of the side of  the  block  bounding  box  the
       leader is connected to and has the same limitation as for the MTEXT content, it’s not possible to mix the
       connection sides left/right and top/bottom.

       The connection side is set when adding the leader line by the add_leader_line() method.

       Unfortunately  BricsCAD  has  an error in version 22.2.03 and renders all connection types as left/right,
       this is top/bottom connection shown in Autodesk TrueView 2022: [image]

       The top/bottom connection type does not support the “dogleg” feature.

   BLOCK Alignment
       There are two alignments types, defined by the enum ezdxf.render.BlockAlignment

          • center_extents

          • insertion_point

       The alignment is set by the set_content() method.

       The alignment type center_extent inserts the BLOCK with the center of the  bounding  box  at  the  insert
       point of the build() method. The insert point is (5, 2) in this example: [image]

       The same MULTILEADER with alignment type insert_point: [image]

   BLOCK Scaling
       The BLOCK content can be scaled independently from the overall scaling of the MULTILEADER entity:

       The block scaling factor is set by the set_content() method:

          ml_builder.set_content(
              name=block.name, scale=2.0, alignment=mleader.BlockAlignment.center_extents
          )

       This  is  the  first example with a block scaling factor of 2. The BLOCK and the attached ATTRIB entities
       are scaled but not the arrows.  [image]

   BLOCK Rotation
       The rotation around the render UCS z-axis in degrees is applied by the build() method:

          ml_builder.build(insert=Vec2(5, 2), rotation=30)

       This is the first example with a rotation of 30 degrees. The BLOCK, the attached ATTRIB entities and  the
       last connection lines (“dogleg”) are rotated.  [image]

   BLOCK Attributes
       BLOCK  attributes  are  defined  as  ATTDEF  entities  in  the BLOCK layout. This ATTDEF entities will be
       replaced by ATTRIB entities at the rendering process of the CAD application.  Only the text  content  and
       the  text  width  factor  can  be changed for each MULTILEADER entity individually by the set_attribute()
       method. The ATTDEF is addressed by it’s DXF tag attribute:

          ml_builder.set_attribute("ONE", "Data1")
          ml_builder.set_attribute("TWO", "Data2")

   Leader Properties
   “Dogleg” Properties
       The “dogleg” is the last line segment from the last leader vertex to the MULTILEADER content for polyline
       leaders.  [image]

       The length of the dogleg and the landing gap size is set by the set_connection_properties().

   Polyline Leader
       A polygon leader line has only straight line segments and is added by the add_leader_line():

          ml_builder.add_leader_line(
              mleader.ConnectionSide.left,
              [Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
          )
       [image]

       All leader line vertices have render UCS coordinates and the start- and end-vertex  of  the  “dogleg”  is
       calculated automatically.

   Spline Leader
       A  spline leader line has a single curved line as leader line and is also added by the add_leader_line().
       This is spline leader has the same vertices as the previous created polyline leader:

          ml_builder.set_leader_properties(leader_type=mleader.LeaderType.splines)
          ml_builder.add_leader_line(
              mleader.ConnectionSide.left,
              [Vec2(-20, 15), Vec2(-10, 15), Vec2(-15, 11), Vec2(-10, 7)],
          )
       [image]

       The spline leader has no “dogleg” and spline leaders and polyline leaders can not be mixed  in  a  single
       MULTILEADER entity.

       The leader type is set by the set_leader_properties() method.

       The LeaderType enum:

          • none

          • straight_lines

          • splines

   Line Styling
       The leader color, linetype and lineweight is set by the set_leader_properties() method:

          ml_builder.set_leader_properties(
              color=colors.MAGENTA,
              linetype="DASHEDX2",
              lineweight=70,
          )
       [image]

       All leader lines have the same properties.

   Arrowheads
       The arrow head is set by the set_arrow_properties() method:

          from ezdxf.render import ARROWS
          ml_builder.set_arrow_properties(name=ARROWS.closed_blank, size=8.0)
       [image]

       All  leader lines have the same arrow head and size.  The available arrow heads are defined in the ARROWS
       object.

   Overall Scaling
       The overall scaling has to be applied by the set_overall_scaling() method and scales the MTEXT  or  BLOCK
       content and the arrows.

   Setup MLEADERSTYLE
       The  MLeaderStyle  stores  many  of the MULTILEADER settings but most of them are copied to the MULTILINE
       entity at initialization.  So changing the MLEADERSTYLE style afterwards has  little  to  no  effect  for
       existing MULTILEADER entities.

       Create a new MLEADERSTYLE called “MY_STYLE” and set the MTEXT style to “OpenSans”:

          my_style = doc.mleader_styles.duplicate_entry("Standard", "MY_STYLE")
          my_style.set_mtext_style("OpenSans")

       The  style  for  a  MULTILEADER is set at the add_multileader_mtext() and add_multileader_block() factory
       methods.

   Tutorial for Viewports in Paperspace
       This tutorial is based on the example script viewports_in_paperspace.py.  The script  creates  DXF  files
       for  the  version  R12  and  for R2000+, but the export for DXF R12 has a wrong papersize in BricsCAD and
       wrong margins in Autodesk DWG Trueview. I don’t know why this happens and I don’t waste my  time  to  fix
       this.

       IMPORTANT:
          If  you  need  paperspace  layouts  use  DXF  version  R2000  or  newer because the export of the page
          dimensions does not work for DXF R12!

       The scripts creates three flat geometries in the xy-plane of the WCS and a 3D  mesh  as  content  of  the
       modelspace: [image]

   Page Setup
       The  paperspace  layout  feature  lacks  documentation  in  the DXF reference, there is no information in
       practice on how it is used, so most of the information here is assumptions  gathered  through  trail  and
       error.

       The  page_setup()  method  defines the properties of the paper sheet itself.  The units of the modelspace
       and the paperspace are not related and can even have different unit systems (imperial,  meters),  but  to
       keep things simple it’s recommended to use the same unit system for both spaces.

          layout.page_setup(size=(24, 18), margins=(1, 1, 1, 1), units="inch")

       The  size argument defines the overall paper size in rotation mode 0, it seems to be the best practice to
       define the paper extents in landscape mode and rotate the paper by the rotate argument afterwards.

       Choices for the rotation argument:
                                          ┌───┬──────────────────────────────┐
                                          │ 0 │ no rotation                  │
                                          ├───┼──────────────────────────────┤
                                          │ 1 │ 90 degrees counter-clockwise │
                                          ├───┼──────────────────────────────┤
                                          │ 2 │ upside-down                  │
                                          ├───┼──────────────────────────────┤
                                          │ 3 │ 90 degrees clockwise         │
                                          └───┴──────────────────────────────┘

       The scale argument reflects the relationship between paper unit and  drawing  unit  in  paperspace.  It’s
       recommended  to let this scale at the default value of 1:1 and draw lines and text in paperspace with the
       same units as you defined the paper size.

       SEE ALSO:

          • AutoCAD: About Plotting and About Setting the Plot Scale

          • BricsCAD: General Procedure for Printing

   Drawing in Paperspace
       You can add DXF entities to the paperspace like to any other layout space.  The coordinate origin (0,  0)
       is in the left bottom corner of the canvas which is the paper size minus the margins. You can draw beyond
       this limits but CAD applications may not print that content.

       HINT:
          By writing this tutorial I noticed that changing the printer/plotter and the paper size does shift the
          layout  content, because all paper sizes are defined without margins. Maybe it’s preferable to set all
          margins to zero.

          I added the helper method page_setup() to the Drawing class and an example simple_page_setup.py how to
          use it.

   Adding Viewports
       The Viewport entity is a window to the modelspace to display the content of the modelspace in  paperspace
       with  an  arbitrary  scaling  and  rotation.   The  VIEWPORT  entity  will be added by the factory method
       add_viewport(), the center argument defines the center and the size argument defines the width and height
       of the of the VIEWPORT in paperspace. The source of the modelspace to display is defined by the arguments
       view_center_point and view_height.  [image]

   Scaling Factor
       The scaling factor of the VIEWPORT is not an explicit value, the factor is defined by the relation of the
       VIEWPORT height of the size argument and the view_height argument.

       If both values are equal the scaling is 1:1

          paperspace.add_viewport(
              center=(14.5, 2.5),
              size=(5, 5),
              view_center_point=(12.5, 7.5),
              view_height=5,
          )

       If the view_height is 5x larger than the VIEWPORT height the scaling is 1:5

          paperspace.add_viewport(
              center=(8.5, 2.5),
              size=(5, 5),
              view_center_point=(10, 5),
              view_height=25,
          )

   View Direction
       The default view direction is the top down view, but can  be  changed  to  any  view  by  the  attributes
       view_target_point and  view_direction_vector of the dxf namespace.

          vp = paperspace.add_viewport(
              center=(16, 10), size=(4, 4), view_center_point=(0, 0), view_height=30
          )
          vp.dxf.view_target_point = (40, 40, 0)
          vp.dxf.view_direction_vector = (-1, -1, 1)

   Viewport Frame
       The  VIEWPORT  frame (borderlines) are shown in paperspace by default.  The VIEWPORT entity does not have
       an attribute to change this.  The visibility of the VIEWPORT frame is controlled by the layer assigned to
       the VIEWPORT entity which is the layer “VIEWPORTS” by default in ezdxf.  Turning off this layer hides the
       frames of the VIEWPORT entities on this layer, to do that the layer “VIEWPORTS” have to be created by the
       library user:

          vp_layer = doc.layers.add("VIEWPORTS")
          vp_layer.off()

   Freeze Layers
       Each VIEWPORT can have individual frozen layers, which means the layers are not visible in this VIEWPORT.
       To freeze layers in a VIEWPORT assign the names of the  frozen  layers  as  a  list-like  object  to  the
       frozen_layers attribute of the VIEWPORT entity:

          vp.frozen_layers = ["Layer0", "Layer1"]

       IMPORTANT:
          AutoCAD  and  BricsCAD  do  not crash if the layer names do not have layer table entries and the layer
          names are case insensitive as all table names.

       SEE ALSO:

          • Basic concept of LayersLayer

   Override Layer Properties
       Each VIEWPORT can override layer properties individually. These overrides are stored in the Layer  entity
       and  referenced  by  the  handle  of  the VIEWPORT. This procedure is a bit more complex and shown in the
       example file viewports_override_layer_attributes.py.

       1. get the Layer object

       2. get the LayerOverrides object from the layer

       3. override the properties of the VIEWPORT

       4. commit changes

          layer = doc.layers.get("Layer0")
          override = layer.get_vp_overrides()
          override.set_linetype(vp.dxf.handle, "DASHED")
          override.commit()

       Supported property overrides:

          • ACI color

          • true color

          • transparency

          • linetype

          • lineweight

       SEE ALSO:

          • Basic concept of Layers

          • Basic concept of AutoCAD Color Index (ACI)

          • Basic concept of True Color

          • Basic concept of Transparency

          • Basic concept of Linetypes

          • Basic concept of LineweightsLayerLayerOverrides

   Tutorial for OCS/UCS Usage
       For OCS/UCS usage is a basic understanding of vector math required, for a brush  up,  watch  the  YouTube
       tutorials of 3Blue1Brown about Linear Algebra.

       Second read the Coordinate Systems introduction please.

       SEE ALSO:
          The  free  online  book  3D  Math Primer for Graphics and Game Development is a very good resource for
          learning vector math and other graphic related topics, it is easy to read for beginners and especially
          targeted to programmers.

       For WCS there is not much to say as, it is what it is: the main world coordinate system,  and  a  drawing
       unit  can  have  any  real  world  unit  you  want.   Autodesk added some mechanism to define a scale for
       dimension and text entities, but because I am not an AutoCAD user, I am not familiar with it, and further
       more I think this is more an AutoCAD topic than a DXF topic.

   Object Coordinate System (OCS)
       The OCS is used to place planar 2D entities in 3D space. ALL points of a planar entity lay  in  the  same
       plane,  this  is  also  true  if  the  plane  is located in 3D space by an OCS. There are three basic DXF
       attributes that gives a 2D entity its spatial form.

   Extrusion
       The extrusion vector defines the OCS, it is a normal vector to the base plane of a  planar  entity.  This
       base  plane  is always located in the origin of the WCS.  But there are some entities like Ellipse, which
       have an extrusion vector, but do not establish an OCS.  For this entities the  extrusion  vector  defines
       only  the  extrusion  direction  and  thickness  defines the extrusion distance, but all other points and
       directions in WCS.

   Elevation
       The elevation value defines the z-axis value for all points of a planar entity, this is an OCS value, and
       defines the distance of the entity plane from the base plane.

       This value exists only in output from DXF versions prior to R11 as separated DXF  attribute  (group  code
       38).   In DXF R12 and later, the elevation value is supplied as z-axis value of each point. But as always
       in DXF, this simple rule does not apply to all entities: LWPolyline  and  Hatch  have  an  DXF  attribute
       elevation as a 3D point, where the z-values of this point is the elevation height and the x-value and the
       y-value are 0.

   Thickness
       Defines the extrusion distance for an entity.

       NOTE:
          There  is  a new edition of this tutorial using UCS based transformation, which are available in ezdxf
          v0.11 and later: Tutorial for UCS Based Transformations

          This edition shows the hard way to accomplish the transformations by low level operations.

   Placing 2D Circle in 3D Space
       The colors of the system axis follow the AutoCAD standard:

          • red is x-axis

          • green is y-axis

          • blue is z-axis

          import ezdxf
          from ezdxf.math import OCS

          doc = ezdxf.new('R2010')
          msp = doc.modelspace()

          # For this example the OCS is rotated around x-axis about 45 degree
          # OCS z-axis: x=0, y=1, z=1
          # extrusion vector must not normalized here
          ocs = OCS((0, 1, 1))
          msp.add_circle(
              # You can place the 2D circle in 3D space
              # but you have to convert WCS into OCS
              center=ocs.from_wcs((0, 2, 2)),
              # center in OCS: (0.0, 0.0, 2.82842712474619)
              radius=1,
              dxfattribs={
                  # here the extrusion vector should be normalized,
                  # which is granted by using the ocs.uz
                  'extrusion': ocs.uz,
                  'color': 1,
              })
          # mark center point of circle in WCS
          msp.add_point((0, 2, 2), dxfattribs={'color': 1})

       The following image shows the 2D circle in 3D space in AutoCAD Left and Front view.  The blue line  shows
       the  OCS  z-axis  (extrusion  direction),  elevation is the distance from the origin to the center of the
       circle in this case 2.828, and you see that the x- and y-axis of the OCS and the  WCS  are  not  aligned.
       [image: circle in ocs as side view] [image] [image: circle in ocs as front view] [image]

   Placing LWPolyline in 3D Space
       For simplicity of calculation I use the UCS class in this example to place a 2D pentagon in 3D space.

          # The center of the pentagon should be (0, 2, 2), and the shape is
          # rotated around x-axis about 45 degree, to accomplish this I use an
          # UCS with z-axis (0, 1, 1) and an x-axis parallel to WCS x-axis.
          ucs = UCS(
              origin=(0, 2, 2),  # center of pentagon
              ux=(1, 0, 0),  # x-axis parallel to WCS x-axis
              uz=(0, 1, 1),  # z-axis
          )
          # calculating corner points in local (UCS) coordinates
          points = [Vec3.from_deg_angle((360 / 5) * n) for n in range(5)]
          # converting UCS into OCS coordinates
          ocs_points = list(ucs.points_to_ocs(points))

          # LWPOLYLINE accepts only 2D points and has an separated DXF attribute elevation.
          # All points have the same z-axis (elevation) in OCS!
          elevation = ocs_points[0].z

          msp.add_lwpolyline(
              points=ocs_points,
              format='xy',  # ignore z-axis
              close=True,
              dxfattribs={
                  'elevation': elevation,
                  'extrusion': ucs.uz,
                  'color': 1,
              })

       The  following  image  shows  the 2D pentagon in 3D space in AutoCAD Left, Front and Top view.  The three
       lines from the center of the pentagon show the UCS, the three colored lines in the origin show  the  OCS,
       the white lines in the origin show the WCS.

       The z-axis of the UCS and the OCS pointing in the same direction (extrusion direction), and the x-axis of
       the  UCS  and the WCS pointing also in the same direction.  The elevation is the distance from the origin
       to the center of the pentagon and all points of the pentagon have the same elevation, and  you  see  that
       the  y-axis  of  the  UCS,  the  OCS  and the WCS are not aligned.  [image: pentagon in ucs as side view]
       [image] [image: pentagon in ucs as front view] [image]

   Using UCS to Place 3D Polyline
       It is much simpler to use a 3D Polyline to create the 3D pentagon.  The  UCS  class  is  handy  for  this
       example and all kind of 3D operations.

          # Using an UCS simplifies 3D operations, but UCS definition can happen later
          # calculating corner points in local (UCS) coordinates without Vec3 class
          angle = math.radians(360 / 5)
          corners_ucs = [(math.cos(angle * n), math.sin(angle * n), 0) for n in range(5)]

          # let's do some transformations
          tmatrix = Matrix44.chain(  # creating a transformation matrix
              Matrix44.z_rotate(math.radians(15)),  # 1. rotation around z-axis
              Matrix44.translate(0, .333, .333),  # 2. translation
          )
          transformed_corners_ucs = tmatrix.transform_vertices(corners_ucs)

          # transform UCS into WCS
          ucs = UCS(
              origin=(0, 2, 2),  # center of pentagon
              ux=(1, 0, 0),  # x-axis parallel to WCS x-axis
              uz=(0, 1, 1),  # z-axis
          )
          corners_wcs = list(ucs.points_to_wcs(transformed_corners_ucs))

          msp.add_polyline3d(
              points=corners_wcs,
              close=True,
          )

          # add lines from center to corners
          center_wcs = ucs.to_wcs((0, .333, .333))
          for corner in corners_wcs:
              msp.add_line(center_wcs, corner, dxfattribs={'color': 1})

          ucs.render_axis(msp)

       [image: 3d poyline with UCS] [image]

   Placing 2D Text in 3D Space
       The  problem  of  placing text in 3D space is the text rotation, which is always counter clockwise around
       the OCS z-axis, and 0 degree is the direction  of  the  positive  OCS  x-axis,  and  the  OCS  x-axis  is
       calculated by the Arbitrary Axis Algorithm.

       Calculate  the  OCS rotation angle by converting the TEXT rotation angle (in UCS or WCS) into a vector or
       begin with text direction as vector, transform this direction vector into OCS and convert the OCS  vector
       back   into   an   angle   in   the   OCS   xy-plane  (see  example),  this  procedure  is  available  as
       UCS.to_ocs_angle_deg() or UCS.to_ocs_angle_rad().

       AutoCAD supports thickness for the TEXT entity only for .shx fonts and not for true type fonts.

          # Thickness for text works only with shx fonts not with true type fonts
          doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'})

          ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
          # calculation of text direction as angle in OCS:
          # convert text rotation in degree into a vector in UCS
          text_direction = Vec3.from_deg_angle(-45)
          # transform vector into OCS and get angle of vector in xy-plane
          rotation = ucs.to_ocs(text_direction).angle_deg

          text = msp.add_text(
              text="TEXT",
              dxfattribs={
                  # text rotation angle in degrees in OCS
                  'rotation': rotation,
                  'extrusion': ucs.uz,
                  'thickness': .333,
                  'color': 1,
                  'style': 'TXT',
              })
          # set text position in OCS
          text.set_pos(ucs.to_ocs((0, 0, 0)), align='MIDDLE_CENTER')

       [image: text in ucs as top view] [image] [image: text in ucs as front view] [image]

       HINT:
          For calculating OCS angles from an UCS, be aware that 2D  entities,  like  TEXT  or  ARC,  are  placed
          parallel to the xy-plane of the UCS.

   Placing 2D Arc in 3D Space
       Here  we  have  the  same  problem  as  for placing text, you need the start- and end angle of the arc in
       degrees in the OCS, and this example also shows a shortcut for calculating the OCS angles.

          ucs = UCS(origin=(0, 2, 2), ux=(1, 0, 0), uz=(0, 1, 1))
          msp.add_arc(
              center=ucs.to_ocs((0, 0)),
              radius=1,
              start_angle=ucs.to_ocs_angle_deg(45),
              end_angle=ucs.to_ocs_angle_deg(270),
              dxfattribs={
                  'extrusion': ucs.uz,
                  'color': 1,
              })
          center = ucs.to_wcs((0, 0))
          msp.add_line(
              start=center,
              end=ucs.to_wcs(Vec3.from_deg_angle(45)),
              dxfattribs={'color': 1},
          )
          msp.add_line(
              start=center,
              end=ucs.to_wcs(Vec3.from_deg_angle(270)),
              dxfattribs={'color': 1},
          )

       [image: arc in ucs as top view] [image] [image: arc in ucs as front view] [image]

   Placing Block References in 3D Space
       Despite the fact that block references (Insert) can contain true 3D  entities  like  Line  or  Mesh,  the
       Insert entity uses the same placing principe as Text or Arc shown in the previous chapters.

       Placement  by  OCS  coordinates  and  rotation  about the OCS z-axis, can be achieved the same way as for
       generic 2D entities.  The DXF attribute Insert.dxf.rotation rotates a block reference  around  the  block
       z-axis,  which  is  located  in  the  Block.dxf.base_point.  To rotate the block reference around the WCS
       x-axis, a transformation of the block z-axis into the WCS x-axis is required by rotating the block z-axis
       90 degree counter-clockwise around y-axis by using an UCS:

       This is just an excerpt of the important parts, see the whole code of insert.py at github.

          # rotate UCS around an arbitrary axis:
          def ucs_rotation(ucs: UCS, axis: Vec3, angle: float):
              # new in ezdxf v0.11: UCS.rotate(axis, angle)
              t = Matrix44.axis_rotate(axis, math.radians(angle))
              ux, uy, uz = t.transform_vertices([ucs.ux, ucs.uy, ucs.uz])
              return UCS(origin=ucs.origin, ux=ux, uy=uy, uz=uz)

          doc = ezdxf.new('R2010', setup=True)
          blk = doc.blocks.new('CSYS')
          setup_csys(blk)
          msp = doc.modelspace()

          ucs = ucs_rotation(UCS(), axis=Y_AXIS, angle=90)
          # transform insert location to OCS
          insert = ucs.to_ocs((0, 0, 0))
          # rotation angle about the z-axis (= WCS x-axis)
          rotation = ucs.to_ocs_angle_deg(15)
          msp.add_blockref('CSYS', insert, dxfattribs={
             'extrusion': ucs.uz,
             'rotation': rotation,
          })

       [image] [image]

       To rotate a block reference around another axis than the block z-axis,  you  have  to  find  the  rotated
       z-axis  (extrusion  vector) of the rotated block reference, following example rotates the block reference
       around the block x-axis by 15 degrees:

          # t is a transformation matrix to rotate 15 degree around the x-axis
          t = Matrix44.axis_rotate(axis=X_AXIS, angle=math.radians(15))
          # transform block z-axis into new UCS z-axis (= extrusion vector)
          uz = Vec3(t.transform(Z_AXIS))
          # create new UCS at the insertion point, because we are rotating around the x-axis,
          # ux is the same as the WCS x-axis and uz is the rotated z-axis.
          ucs = UCS(origin=(1, 2, 0), ux=X_AXIS, uz=uz)
          # transform insert location to OCS, block base_point=(0, 0, 0)
          insert = ucs.to_ocs((0, 0, 0))
          # for this case a rotation around the z-axis is not required
          rotation = 0
          blockref = msp.add_blockref('CSYS', insert, dxfattribs={
              'extrusion': ucs.uz,
              'rotation': rotation,
          })

       [image] [image]

       The next example shows how to translate a block references with an already established OCS:

          # translate a block references with an established OCS
          translation = Vec3(-3, -1, 1)
          # get established OCS
          ocs = blockref.ocs()
          # get insert location in WCS
          actual_wcs_location = ocs.to_wcs(blockref.dxf.insert)
          # translate location
          new_wcs_location = actual_wcs_location + translation
          # convert WCS location to OCS location
          blockref.dxf.insert = ocs.from_wcs(new_wcs_location)

       Setting a new insert location is the same procedure without adding a translation vector,  just  transform
       the new insert location into the OCS.  [image] [image]

       The  next  operation  is  to rotate a block reference with an established OCS, rotation axis is the block
       y-axis, rotation angle is -90 degrees. First transform block y-axis  (rotation  axis)  and  block  z-axis
       (extrusion vector) from OCS into WCS:

          # rotate a block references with an established OCS around the block y-axis about 90 degree
          ocs = blockref.ocs()
          # convert block y-axis (= rotation axis) into WCS vector
          rotation_axis = ocs.to_wcs((0, 1, 0))
          # convert local z-axis (=extrusion vector) into WCS vector
          local_z_axis = ocs.to_wcs((0, 0, 1))

       Build transformation matrix and transform extrusion vector and build new UCS:

          # build transformation matrix
          t = Matrix44.axis_rotate(axis=rotation_axis, angle=math.radians(-90))
          uz = t.transform(local_z_axis)
          uy = rotation_axis
          # the block reference origin stays at the same location, no rotation needed
          wcs_insert = ocs.to_wcs(blockref.dxf.insert)
          # build new UCS to convert WCS locations and angles into OCS
          ucs = UCS(origin=wcs_insert, uy=uy, uz=uz)

       Set new OCS attributes, we also have to set the rotation attribute even though we do not rotate the block
       reference  around  the  local  z-axis, the new block x-axis (0 deg) differs from OCS x-axis and has to be
       adjusted:

          # set new OCS
          blockref.dxf.extrusion = ucs.uz
          # set new insert
          blockref.dxf.insert = ucs.to_ocs((0, 0, 0))
          # set new rotation: we do not rotate the block reference around the local z-axis,
          # but the new block x-axis (0 deg) differs from OCS x-axis and has to be adjusted
          blockref.dxf.rotation = ucs.to_ocs_angle_deg(0)

       [image] [image]

       And here is the point, where my math knowledge ends, for more advanced CAD operation  you  have  to  look
       elsewhere.

   Tutorial for UCS Based Transformations
       The  ezdxf  version  v0.13  introduced a transformation interface for DXF primitives, which makes working
       with OCS/UCS much easier.  This is a new edition of the Tutorial for OCS/UCS Usage.  Please read the  old
       tutorial for the basics about the OCS.

       For  this  tutorial  we  don’t  have  to  worry  about  the  OCS  and  the extrusion vector, this is done
       automatically by the transform() method of each DXF entity.

   Placing 2D Circle in 3D Space
       To recreate the situation of the old tutorial instantiate a new  UCS  and  rotate  it  around  the  local
       x-axis.   Use UCS coordinates to place the 2D CIRCLE in 3D space and transform the UCS coordinates to the
       WCS.

          import math
          import ezdxf
          from ezdxf.math import UCS

          doc = ezdxf.new('R2010')
          msp = doc.modelspace()

          ucs = UCS()  # New default UCS
          # All rotation angles in radians, and rotation
          # methods always return a new UCS.
          ucs = ucs.rotate_local_x(math.radians(-45))
          circle = msp.add_circle(
              # Use UCS coordinates to place the 2d circle in 3d space
              center=(0, 0, 2),
              radius=1,
              dxfattribs={'color': 1}
          )
          circle.transform(ucs.matrix)

          # mark center point of circle in WCS
          msp.add_point((0, 0, 2), dxfattribs={'color': 1}).transform(ucs.matrix)

       [image: circle in ucs as side view] [image] [image: circle in ucs as front view] [image]

   Placing LWPolyline in 3D Space
       Simplified LWPOLYLINE example:

          # The center of the pentagon should be (0, 2, 2), and the shape is
          # rotated around x-axis about -45 degree
          ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))

          msp.add_lwpolyline(
              # calculating corner points in UCS coordinates
              points=(Vec3.from_deg_angle((360 / 5) * n) for n in range(5)),
              format='xy',  # ignore z-axis
              close=True,
              dxfattribs={
                  'color': 1,
              }
          ).transform(ucs.matrix)

       The 2D pentagon in 3D space in BricsCAD Left and Front view.  [image:  pentagon  in  ucs  as  side  view]
       [image] [image: pentagon in ucs as front view] [image]

   Using UCS to Place 3D Polyline
       Simplified  POLYLINE  example:  Using a first UCS to transform the POLYLINE and a second UCS to place the
       POLYLINE in 3D space.

          # using an UCS simplifies 3D operations, but UCS definition can happen later
          # calculating corner points in local (UCS) coordinates without Vec3 class
          angle = math.radians(360 / 5)
          corners_ucs = [(math.cos(angle * n), math.sin(angle * n), 0) for n in range(5)]

          # let's do some transformations by UCS
          transformation_ucs = UCS().rotate_local_z(math.radians(15))  # 1. rotation around z-axis
          transformation_ucs.shift((0, .333, .333))  # 2. translation (inplace)
          corners_ucs = list(transformation_ucs.points_to_wcs(corners_ucs))

          location_ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
          msp.add_polyline3d(
              points=corners_ucs,
              close=True,
              dxfattribs={
                  'color': 1,
              }
          ).transform(location_ucs.matrix)

          # Add lines from the center of the POLYLINE to the corners
          center_ucs = transformation_ucs.to_wcs((0, 0, 0))
          for corner in corners_ucs:
              msp.add_line(
                  center_ucs, corner, dxfattribs={'color': 1}
              ).transform(location_ucs.matrix)

       [image: 3d poyline with UCS] [image]

   Placing 2D Text in 3D Space
       The problem with the text rotation in the old tutorial disappears with the new UCS  based  transformation
       method:

       AutoCAD supports thickness for the TEXT entity only for .shx fonts and not for true type fonts.

          # thickness for text works only with shx fonts not with true type fonts
          doc.styles.new('TXT', dxfattribs={'font': 'romans.shx'})

          ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))
          text = msp.add_text(
              text="TEXT",
              dxfattribs={
                  # text rotation angle in degrees in UCS
                  'rotation': -45,
                  'thickness': .333,
                  'color': 1,
                  'style': 'TXT',
              }
          )
          # set text position in UCS
          text.set_pos((0, 0, 0), align='MIDDLE_CENTER')
          text.transform(ucs.matrix)

       [image: text in ucs as top view] [image] [image: text in ucs as front view] [image]

   Placing 2D Arc in 3D Space
       Same as for the text example, OCS angle transformation can be ignored:

          ucs = UCS(origin=(0, 2, 2)).rotate_local_x(math.radians(-45))

          CENTER = (0, 0)
          START_ANGLE = 45
          END_ANGLE = 270

          msp.add_arc(
              center=CENTER,
              radius=1,
              start_angle=START_ANGLE,
              end_angle=END_ANGLE,
              dxfattribs={'color': 6},
          ).transform(ucs.matrix)

          msp.add_line(
              start=CENTER,
              end=Vec3.from_deg_angle(START_ANGLE),
              dxfattribs={'color': 6},
          ).transform(ucs.matrix)

          msp.add_line(
              start=CENTER,
              end=Vec3.from_deg_angle(END_ANGLE),
              dxfattribs={'color': 6},
          ).transform(ucs.matrix)

       [image: arc in ucs as top view] [image] [image: arc in ucs as front view] [image]

   Placing Block References in 3D Space
       Despite  the  fact  that  block  references  (INSERT) can contain true 3D entities like LINE or MESH, the
       INSERT entity uses the same placing principe as TEXT or ARC shown in the previous sections.

       To rotate the block reference 15 degrees around the WCS x-axis, we  place  the  block  reference  in  the
       origin  of  the  UCS, and rotate the UCS 90 degrees around its local y-axis, to align the UCS z-axis with
       the WCS x-axis:

       This is just an excerpt of the important parts, see the whole code of insert.py at github.

          doc = ezdxf.new('R2010', setup=True)
          blk = doc.blocks.new('CSYS')
          setup_csys(blk)
          msp = doc.modelspace()

          ucs = UCS().rotate_local_y(angle=math.radians(90))
          msp.add_blockref(
              'CSYS',
              insert=(0, 0),
              # rotation around the block z-axis (= WCS x-axis)
              dxfattribs={'rotation': 15},
          ).transform(ucs.matrix)

       [image] [image]

       A more simple approach is to ignore the rotate attribute at all and just rotate the  UCS.   To  rotate  a
       block  reference  around any axis rather than the block z-axis, rotate the UCS into the desired position.
       The following example rotates the block reference around the block x-axis by 15 degrees:

          ucs = UCS(origin=(1, 2, 0)).rotate_local_x(math.radians(15))
          blockref = msp.add_blockref('CSYS', insert=(0, 0, 0))
          blockref.transform(ucs.matrix)

       [image] [image]

       The next example shows how to translate a block references with an already established OCS:

          # New UCS at the translated location, axis aligned to the WCS
          ucs = UCS((-3, -1, 1))
          # Transform an already placed block reference, including
          # the transformation of the established OCS.
          blockref.transform(ucs.matrix)

       [image] [image]

       The next operation is to rotate a block reference with an established OCS, rotation  axis  is  the  block
       y-axis,  rotation  angle is -90 degrees. The idea is to create an UCS in the origin of the already placed
       block reference, UCS axis aligned to the block axis and resetting the block reference  parameters  for  a
       new WCS transformation.

          # Get UCS at the block reference insert location, UCS axis aligned
          # to the block axis.
          ucs = blockref.ucs()
          # Rotate UCS around the local y-axis.
          ucs = ucs.rotate_local_y(math.radians(-90))

       Reset  block reference parameters, this places the block reference in the UCS origin and aligns the block
       axis to the UCS axis, now we do a new transformation from UCS to WCS:

          # Reset block reference parameters to place block reference in
          # UCS origin, without any rotation and OCS.
          blockref.reset_transformation()

          # Transform block reference from UCS to WCS
          blockref.transform(ucs.matrix)

       [image] [image]

   Tutorial for Linear Dimensions
       The Dimension entity is the generic entity for all dimension types,  but  unfortunately  AutoCAD  is  not
       willing  to show a dimension line defined only by this dimension entity, it also needs an anonymous block
       which contains the dimension line shape constructed by DXF primitives like LINE and TEXT  entities,  this
       representation is called the dimension line rendering in this documentation, beside the fact that this is
       not  a  real  graphical  rendering.   BricsCAD is a much more friendly CAD application, which do show the
       dimension entity without the graphical rendering as block, which was very  useful  for  testing,  because
       there  is  no documentation how to apply all the dimension style variables (more than 80).  This seems to
       be the reason why dimension lines are rendered so differently by many CAD application.

       Don’t expect to get the same rendering results by ezdxf as you get from AutoCAD. Ezdxf  tries  to  be  as
       close  to  the  results  rendered  by  BricsCAD,  but  it  is  not  possible to implement all the various
       combinations of dimension style parameters, which often affect one another.

       NOTE:
          Ezdxf does not consider all DIMSTYLE variables, so  the  rendering  results  are  different  from  CAD
          applications.

       Text  rendering  is  another  problem, because ezdxf has no real rendering engine.  Some font properties,
       like the real text width, which is only available to ezdxf if the Matplotlib  package  is  installed  and
       this  value  may  also  vary  slightly  for different CAD applications.  Without access to the Matplotlib
       package the text properties in ezdxf are based on  an  abstract  monospaced  font  and  are  bigger  than
       required by true type fonts.

       Not  all  DIMENSION  and DIMSTYLE features are supported by all DXF versions, especially DXF R12 does not
       support many features, but in this case the required  rendering  of  dimension  lines  is  an  advantage,
       because  if the application just shows the rendered block, all features which can be used in DXF R12 will
       be displayed, but these features will disappear  if  the  dimension  line  will  be  edited  in  the  CAD
       application.  Ezdxf writes only the supported DIMVARS of the used DXF version to avoid invalid DXF files.
       So it is not that critical to know all the supported features of a DXF version,  except  for  limits  and
       tolerances,  ezdxf  uses  the  advanced  features of the MTEXT entity to create limits and tolerances and
       therefore they are not supported (displayed) in DXF R12 files.

       SEE ALSO:

          • Graphical reference of many DIMVARS and some advanced information: DIMSTYLE Table

          • Source code file standards.py shows how to create your own DIMSTYLES.

          • The Script dimension_linear.py shows examples for linear dimensions.

   Horizontal Dimension
          import ezdxf

          # Create a DXF R2010 document:
          # Use argument setup=True to setup the default dimension styles.
          doc = ezdxf.new("R2010", setup=True)

          # Add new dimension entities to the modelspace:
          msp = doc.modelspace()

          # Add a LINE entity for visualization, not required to create the DIMENSION
          # entity:
          msp.add_line((0, 0), (3, 0))

          # Add a horizontal linear DIMENSION entity:
          dim = msp.add_linear_dim(
              base=(3, 2),  # location of the dimension line
              p1=(0, 0),  # 1st measurement point
              p2=(3, 0),  # 2nd measurement point
              dimstyle="EZDXF",  # default dimension style
          )

          # Necessary second step to create the BLOCK entity with the dimension geometry.
          # Additional processing of the DIMENSION entity could happen between adding
          # the entity and the rendering call.
          dim.render()
          doc.saveas("dim_linear_horiz.dxf")
       [image]

       The example above creates a horizontal Dimension entity.  The default dimension style “EZDXF” is  defined
       as:

       • 1 drawing unit = 1m

       • measurement text height = 0.25 (drawing scale = 1:100)

       • the length factor dimlfac = 100, which creates a measurement text in cm.

       • arrow is “ARCHTICK”, arrow size dimasz = 0.175

       Every  dimension  style  which  does  not exist will be replaced by the dimension style “Standard” at DXF
       export by save() or saveas() (e.g. dimension style setup was not initiated).

       The base point defines the location of the dimension line, ezdxf accepts any point on the dimension line,
       the point p1 defines the start  point  of  the  first  extension  line,  which  also  defines  the  first
       measurement  point  and  the  point  p2  defines the start point of the second extension line, which also
       defines the second measurement point.

       The return value dim is not a dimension entity,  instead  a  DimStyleOverride  object  is  returned,  the
       dimension entity is stored as attribute dim.dimension.

   Vertical and Rotated Dimension
       Argument  angle  defines  the  angle  of  the dimension line in relation to the x-axis of the WCS or UCS,
       measurement is the distance between first and second measurement point in direction of angle.

          # assignment to dim is not necessary, if no additional processing happens
          msp.add_linear_dim(base=(3, 2), p1=(0, 0), p2=(3, 0), angle=-30).render()
          doc.saveas("dim_linear_rotated.dxf")
       [image]

       For a vertical dimension set argument angle to 90 degree, but in this example the vertical distance would
       be 0.

   Aligned Dimension
       An aligned dimension line is parallel to the line defined  by  the  definition  points  p1  and  p2.  The
       placement  of  the  dimension line is defined by the argument distance, which is the distance between the
       definition line and the dimension line. The distance of the dimension line is orthogonal to the base line
       in counter clockwise orientation.

          msp.add_line((0, 2), (3, 0))
          dim = msp.add_aligned_dim(p1=(0, 2), p2=(3, 0), distance=1)
          doc.saveas("dim_linear_aligned.dxf")
       [image]

   Dimension Style Override
       Many dimension styling options are defined by the associated DimStyle entity.  But often you wanna change
       just a few settings without creating a new dimension style, therefore the DXF format has  a  protocol  to
       store  this  changed  settings  in  the dimension entity itself.  This protocol is supported by ezdxf and
       every factory function which creates dimension entities supports the override  argument.   This  override
       argument  is  a  simple  Python  dictionary (e.g.  override = {"dimtad": 4}, place measurement text below
       dimension line).

       The overriding protocol is managed by  the  DimStyleOverride  object,  which  is  returned  by  the  most
       dimension factory functions.

   Placing Measurement Text
       The  default location of the measurement text depends on various DimStyle parameters and is applied if no
       user defined text location is defined.

   Default Text Locations
       “Horizontal direction”  means  in  direction  of  the  dimension  line  and  “vertical  direction”  means
       perpendicular to the dimension line direction.

       The “horizontal” location of the measurement text is defined by dimjust:
                                    ┌───┬───────────────────────────────────────┐
                                    │ 0 │ Center of dimension line              │
                                    ├───┼───────────────────────────────────────┤
                                    │ 1 │ Left side of the dimension line, near │
                                    │   │ first extension line                  │
                                    ├───┼───────────────────────────────────────┤
                                    │ 2 │ Right  side  of  the  dimension line, │
                                    │   │ near second extension line            │
                                    ├───┼───────────────────────────────────────┤
                                    │ 3 │ Over first extension line             │
                                    ├───┼───────────────────────────────────────┤
                                    │ 4 │ Over second extension line            │
                                    └───┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2), p1=(0, 0), p2=(3, 0), override={"dimjust": 1}
          ).render()
       [image]

       The “vertical” location of the measurement text relative to the dimension line is defined by dimtad:
                                    ┌───┬───────────────────────────────────────┐
                                    │ 0 │ Center, it is possible to adjust  the │
                                    │   │ vertical location by dimtvp           │
                                    ├───┼───────────────────────────────────────┤
                                    │ 1 │ Above                                 │
                                    ├───┼───────────────────────────────────────┤
                                    │ 2 │ Outside, handled like Above by ezdxf  │
                                    ├───┼───────────────────────────────────────┤
                                    │ 3 │ JIS, handled like Above by ezdxf      │
                                    ├───┼───────────────────────────────────────┤
                                    │ 4 │ Below                                 │
                                    └───┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2), p1=(0, 0), p2=(3, 0), override={"dimtad": 4}
          ).render()
       [image]

       The distance between text and dimension line is defined by dimgap.

       The  DimStyleOverride  object  has  a method set_text_align() to set the default text location in an easy
       way, this is also the reason for the 2 step creation process of dimension entities:

          dim = msp.add_linear_dim(base=(3, 2), p1=(0, 0), p2=(3, 0))
          dim.set_text_align(halign="left", valign="center")
          dim.render()
                                  ┌────────┬───────────────────────────────────────┐
                                  │ halign │ “left”, “right”, “center”,  “above1”, │
                                  │        │ “above2”                              │
                                  ├────────┼───────────────────────────────────────┤
                                  │ valign │ “above”, “center”, “below”            │
                                  └────────┴───────────────────────────────────────┘

       Run  function example_for_all_text_placings_R2007() in the example script dimension_linear.py to create a
       DXF file with all text placings supported by ezdxf.

   User Defined Text Locations
       Beside the default location, it is possible to locate the measurement text freely.

   Location Relative to Origin
       The user defined text location can be set by the argument location in most  dimension  factory  functions
       and always references the midpoint of the measurement text:

          msp.add_linear_dim(
              base=(3, 2), p1=(3, 0), p2=(6, 0), location=(4, 4)
          ).render()
       [image]

       The location is relative to the origin of the active coordinate system or WCS if no UCS is defined in the
       render() method, the user defined location can also be set by user_location_override().

   Location Relative to Center of Dimension Line
       The  method  set_location() has additional features for linear dimensions.  Argument leader = True adds a
       simple leader from the measurement text to the center of the dimension line and argument relative =  True
       places the measurement text relative to the center of the dimension line.

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_location(location=(-1, 1), leader=True, relative=True)
          dim.render()
       [image]

   Location Relative to Default Location
       The  method  shift_text()  shifts  the measurement text away from the default text location. The shifting
       directions are aligned to the text direction, which is the direction of the dimension line in most cases,
       dh (for delta horizontal) shifts the text parallel to the text direction, dv (for delta vertical)  shifts
       the text perpendicular to the text direction. This method does not support leaders.

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.shift_text(dh=1, dv=1)
          dim.render()
       [image]

   Overriding Text Rotation
       All  factory  methods  supporting  the argument text_rotation can override the measurement text rotation.
       The user defined rotation is relative to the render UCS x-axis (default is WCS).

   Measurement Text Formatting and Styling
   Text Properties
                                 ┌──────────┬───────────────────────────────────────┐
                                 │ DIMVAR   │ Description                           │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimtxsty │ Specifies  the  text  style  of   the │
                                 │          │ dimension as Textstyle name.          │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimtxt   │ Text height in drawing units.         │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimclrt  │ Measurement  text  color  as  AutoCAD │
                                 │          │ Color Index (ACI).                    │
                                 └──────────┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimtxsty": "Standard",
                  "dimtxt": 0.35,
                  "dimclrt": 1,
              }
          ).render()
       [image]

   Background Filling
       Background fillings are supported since DXF R2007, and ezdxf uses the  MTEXT  entity  to  implement  this
       feature,  so setting background filling in DXF R12 has no effect. The DIMVAR dimtfill defines the kind of
       background filling and the DIMVAR dimtfillclr defines the fill color.
                               ┌─────────────┬───────────────────────────────────────┐
                               │ DIMVAR      │ Description                           │
                               ├─────────────┼───────────────────────────────────────┤
                               │ dimtfill    │ Enables background filling if  bigger │
                               │             │ than 0                                │
                               ├─────────────┼───────────────────────────────────────┤
                               │ dimtfillclr │ Fill  color  as  AutoCAD  Color Index │
                               │             │ (ACI), if dimtfill is 2               │
                               └─────────────┴───────────────────────────────────────┘
                                     ┌──────────┬──────────────────────────────┐
                                     │ dimtfill │ Description                  │
                                     ├──────────┼──────────────────────────────┤
                                     │ 0        │ disabled                     │
                                     ├──────────┼──────────────────────────────┤
                                     │ 1        │ canvas color                 │
                                     ├──────────┼──────────────────────────────┤
                                     │ 2        │ color defined by dimtfillclr │
                                     └──────────┴──────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimtfill": 2,
                  "dimtfillclr": 1,
              }
          ).render()
       [image]

   Text Formattingdecimal places: dimdec defines the number of decimal places  displayed  for  the  primary  units  of  a
         dimension. (DXF R2000)

       • decimal  point  character:  dimdsep  defines  the  decimal  point  as ASCII code, get the ASCII code by
         ord('.')rounding: dimrnd, rounds all dimensioning distances to the specified value, for instance, if dimrnd  is
         set to 0.25, all distances round to the nearest 0.25 unit. If dimrnd is set to 1.0, all distances round
         to  the  nearest  integer.  For  more  information look at the documentation of the ezdxf.math.xround()
         function.

       • zero trimming: dimzin, ezdxf supports only a subset of values:

            • 4 to suppress leading zeros

            • 8 to suppress trailing zeros

            • 12 as the combination of both

       • measurement factor: scale measurement by factor dimlfac, e.g. to get the dimensioning text in cm for  a
         DXF file where 1 drawing unit represents 1m, set dimlfac to 100.

       • text  template:  dimpost,  “<>”  represents  the  measurement  text, e.g. “~<>cm” produces “~300cm” for
         measurement in previous example.

       To       set       this       values       the       ezdxf.entities.DimStyle.set_text_format()        and
       ezdxf.entities.DimStyleOverride.set_text_format() methods are very recommended.

   Overriding Measurement Text
       This feature allows overriding the real measurement text by a custom measurement text, the text is stored
       as string in the Dimension entity as attribute text.  Special values of the text attribute are: one space
       “ “ to suppress the measurement text at all, an empty string “”  or “<>” to display the real measurement.

       All  factory  functions  have  an  explicit  text  argument,  which always replaces the text value in the
       dxfattribs dict.

          msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0), text=">1m").render()
       [image]

   Dimension Line Properties
       The dimension line color is defined by the DIMVAR dimclrd as AutoCAD Color Index (ACI), dimclrd and  also
       defines  the  color  of  the  arrows.  The  linetype  is  defined by dimltype and requires DXF R2007. The
       lineweight is defined by dimlwd and requires DXF R2000, see  also  the  lineweight  reference  for  valid
       values.   The  dimdle  is  the extension of the dimension line beyond the extension lines, this dimension
       line extension is not supported for all arrows.
                                 ┌──────────┬───────────────────────────────────────┐
                                 │ DIMVAR   │ Description                           │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimclrd  │ dimension line and  arrows  color  as │
                                 │          │ AutoCAD Color Index (ACI)             │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimltype │ linetype of dimension line            │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimlwd   │ line weight of dimension line         │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimdle   │ extension   of   dimension   line  in │
                                 │          │ drawing units                         │
                                 └──────────┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimclrd": 1,  # red
                  "dimdle": 0.25,
                  "dimltype": "DASHED2",
                  "dimlwd": 35,  # 0.35mm line weight
              }
          ).render()
       [image]

       DimStyleOverride() method:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_dimline_format(
              color=1, linetype="DASHED2", lineweight=35, extension=0.25
          )
          dim.render()

   Extension Line Properties
       The extension line color is defined by the DIMVAR dimclre as AutoCAD Color Index (ACI).  The linetype for
       the first and the second extension line is defined by dimltex1 and dimltex2 and requires DXF R2007.   The
       lineweight  is  defined  by  dimlwe  and  required DXF R2000, see also the lineweight reference for valid
       values.

       The dimexe is the extension of the extension line beyond the  dimension  line,  and  dimexo  defines  the
       offset of the extension line from the measurement point.
                                 ┌──────────┬───────────────────────────────────────┐
                                 │ DIMVAR   │ Description                           │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimclre  │ extension line color as AutoCAD Color │
                                 │          │ Index (ACI)                           │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimltex1 │ linetype of first extension line      │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimltex2 │ linetype of second extension line     │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimlwe   │ line weight of extension line         │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimexe   │ extension  beyond  dimension  line in │
                                 │          │ drawing units                         │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimexo   │ offset   of   extension   line   from │
                                 │          │ measurement point                     │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimfxlon │ set  to  1  to  enable  fixed  length │
                                 │          │ extension line                        │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimfxl   │ length of fixed length extension line │
                                 │          │ in drawing units                      │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimse1   │ suppress first extension line if 1    │
                                 ├──────────┼───────────────────────────────────────┤
                                 │ dimse2   │ suppress second extension line if 1   │
                                 └──────────┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimclre": 1,   # red
                  "dimltex1": "DASHED2",
                  "dimltex2": "CENTER2",
                  "dimlwe": 35,   # 0.35mm line weight
                  "dimexe": 0.3,  # length above dimension line
                  "dimexo": 0.1,  # offset from measurement point
              }
          ).render()
       [image]

       DimStyleOverride() methods:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_extline_format(color=1, lineweight=35, extension=0.3, offset=0.1)
          dim.set_extline1(linetype="DASHED2")
          dim.set_extline2(linetype="CENTER2")
          dim.render()

       Fixed length extension lines are supported in DXF R2007, set dimfxlon to 1 and dimfxl defines the  length
       of the extension line starting at the dimension line.

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimfxlon": 1,  # fixed length extension lines
                  "dimexe": 0.2,  # length above dimension line
                  "dimfxl": 0.4,  # length below dimension line
              }
          ).render()
       [image]

       DimStyleOverride() method:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_extline_format(extension=0.2, fixed_length=0.4)
          dim.render()

       To  suppress  extension  lines  set  dimse1  to 1 to suppress the first extension line and dimse2 to 1 to
       suppress the second extension line.

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimse1": 1,  # suppress first extension line
                  "dimse2": 1,  # suppress second extension line
                  "dimblk": ezdxf.ARROWS.closed_filled,  # arrows just looks better
              }
          ).render()
       [image]

       DimStyleOverride() methods:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_arrows(blk=ezdxf.ARROWS.closed_filled)
          dim.set_extline1(disable=True)
          dim.set_extline2(disable=True)
          dim.render()

   Arrows
       “Arrows” mark then beginning and the end of a dimension line, and most of them do not look like arrows.

       DXF distinguish between the simple tick (a slanted line) and arrows as blocks.

       To use a simple tick as “arrow” set dimtsz to a value greater than 0, this also disables arrow blocks  as
       side effect:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_tick(size=0.25)
          dim.render()

       Ezdxf  uses  the  “ARCHTICK”  block  at  double size to render the tick (AutoCAD and BricsCad just draw a
       simple line), so there is no advantage of using the tick instead of an arrow.

       Using arrows:

          dim = msp.add_linear_dim(base=(3, 2), p1=(3, 0), p2=(6, 0))
          dim.set_arrow(blk="OPEN_30", size=0.25)
          dim.render()
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ DIMVAR  │ Description                           │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ dimtsz  │ tick size in drawing units, set to  0 │
                                 │         │ to use arrows                         │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ dimblk  │ set both arrow block names at once    │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ dimblk1 │ first arrow block name                │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ dimblk2 │ second arrow block name               │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ dimasz  │ arrow size in drawing units           │
                                 └─────────┴───────────────────────────────────────┘

          msp.add_linear_dim(
              base=(3, 2),
              p1=(3, 0),
              p2=(6, 0),
              override={
                  "dimtsz": 0,  # set tick size to 0 to enable arrow usage
                  "dimasz": 0.25,  # arrow size in drawing units
                  "dimblk": "OPEN_30",  # arrow block name
              }
          ).render()

       The dimension line extension (dimdle) works only for a few arrow blocks and the simple tick:

       • “ARCHTICK”

       • “OBLIQUE”

       • “NONE”

       • “SMALL”

       • “DOTSMALL”

       • “INTEGRAL”

   Arrow Shapes
       [image]

   Arrow Names
       The arrow names are stored as attributes in the ezdxf.ARROWS object.
                                    ─────────────────────────────────────────────
                                      closed_filled           “” (empty string)
                                    ─────────────────────────────────────────────
                                      dot                     “DOT”
                                    ─────────────────────────────────────────────
                                      dot_small               “DOTSMALL”
                                    ─────────────────────────────────────────────
                                      dot_blank               “DOTBLANK”
                                    ─────────────────────────────────────────────
                                      origin_indicator        “ORIGIN”
                                    ─────────────────────────────────────────────
                                      origin_indicator_2      “ORIGIN2”
                                    ─────────────────────────────────────────────
                                      open                    “OPEN”
                                    ─────────────────────────────────────────────
                                      right_angle             “OPEN90”
                                    ─────────────────────────────────────────────
                                      open_30                 “OPEN30”
                                    ─────────────────────────────────────────────
                                      closed                  “CLOSED”
                                    ─────────────────────────────────────────────
                                      dot_smallblank          “SMALL”
                                    ─────────────────────────────────────────────
                                      none                    “NONE”
                                    ─────────────────────────────────────────────
                                      oblique                 “OBLIQUE”
                                    ─────────────────────────────────────────────
                                      box_filled              “BOXFILLED”
                                    ─────────────────────────────────────────────
                                      box                     “BOXBLANK”
                                    ─────────────────────────────────────────────
                                      closed_blank            “CLOSEDBLANK”
                                    ─────────────────────────────────────────────
                                      datum_triangle_filled   “DATUMFILLED”
                                    ─────────────────────────────────────────────
                                      datum_triangle          “DATUMBLANK”
                                    ─────────────────────────────────────────────
                                      integral                “INTEGRAL”
                                    ─────────────────────────────────────────────
                                      architectural_tick      “ARCHTICK”
                                    ─────────────────────────────────────────────
                                      ez_arrow                “EZ_ARROW”
                                    ─────────────────────────────────────────────
                                      ez_arrow_blank          “EZ_ARROW_BLANK”
                                    ─────────────────────────────────────────────
                                      ez_arrow_filled         “EZ_ARROW_FILLED”
                                    ┌───────────────────────┬───────────────────┐
                                    │                       │                   │
   Tolerances and Limits            │                       │                   │
--

EXTERNAL REFERENCES (XREF)

       New in version 1.1.

       Attached XREFs are links to the modelspace of a specified drawing file. Changes made  to  the  referenced
       drawing are automatically reflected in the current drawing when it’s opened or if the XREF is reloaded.

       XREFs  can  be nested within other XREFs: that is, you can attach an XREF that contains another XREF. You
       can attach as many copies of an XREF as you want, and each copy can have a different position, scale, and
       rotation.

       You can also overlay an XREF on your drawing. Unlike an attached XREF, an overlaid XREF is  not  included
       when the drawing is itself attached or overlaid as an XREF to another drawing.

   DXF Files as Attached XREFs
       IMPORTANT:
          AutoCAD  can  only  display  DWG  files  as  attached  XREFs  but  ezdxf  can  only  create DXF files.
          Consequently, any DXF file attached as an XREF to a DXF document must be converted to DWG in order  to
          be  viewed  in  AutoCAD.   Fortunately,  other  CAD applications are more cooperative, BricsCAD has no
          problem displaying DXF files as XREFs, although it is not possible to attach a DXF file as an XREF  in
          the BricsCAD application itself.

       The ezdxf.xref module provides an interface for working with XREFs.

          • attach() - attach a DXF/DWG file as XREF

          • detach() - detach a BLOCK definition as XREF

          • embed() - embed an XREF as a BLOCK definition

          • dxf_info() - scans a DXF file for basic settings and properties

       For  loading the content of DWG files is a loading function required, which loads the DWG file as Drawing
       document. The odafc add-on module provides such a function: readfile()

       SEE ALSO:Tutorial for External References

   XREF Structures
       An XREF is a normal block definition located in the BLOCKS section with special flags set and a  filename
       to  the  referenced  DXF/DWG  file  and  without  any content, the block content is the modelspace of the
       referenced file.  An XREF can be referenced (inserted) by one or multiple INSERT entities.

       Find block definitions in the BLOCKS section:

          for block_layout in doc.blocks:
              block = block_layout.block  # the BLOCK entity
              if block.is_xref:
                  handle_xref(block_layout)
              elif block.is_xref_overlay:
                  handle_xref_overlay(block_layout)

       Find XREF references in modelspace:

          for insert in msp.query("INSERT"):
              if insert.is_xref:
                  handle_xref_reference(insert)
                  # ... or get the XREF definition
                  block_layout = insert.block()
                  if block_layout is not None:
                      handle_xref_definition(block_layout)

       Use the helper function define() to create your own XREF definition, the attach() creates this definition
       automatically and raises an exception if the block already exists.

   Supported Entities
       The current implementation supports only copyable and transformable DXF entities,  these  are  all  basic
       entity  types  as  LINE,  CIRCLE,  … and block references and their associated required table entries and
       objects from the OBJECTS section.

       Unsupported are all ACIS based entities, the ACAD_TABLE entity, preserved unknown entities wrapped  in  a
       DXFTagStorage  class,  proxy  entities  and  objects.  Support for these entities may be added in a later
       version of ezdxf.  Unsupported entities are ignored and do not raise exceptions.

       Most document features stored in the HEADER and OBJECTS sections are not supported by  this  module  like
       GROUPS, LAYER_FILTER, GEODATA, SUN.

   Importing Data and Resources
       The ezdxf.xref module replaces the Importer add-on.

       The  basic  functionality  of  the  ezdxf.xref module is loading data from external files including their
       required resources, which is an often requested feature by users for importing data from other DXF  files
       into the current document.

       The  Importer  add-on  was  very limited and removed many resources, where the ezdxf.xref module tries to
       preserve as much information as possible.

          • load_modelspace() - loads the modelspace content from another DXF document

          • load_paperspace() - loads a paperspace layout from another DXF document

          • write_block() - writes entities into the modelspace of a new DXF document

          • Loader - low level loading interface

   High Level Functions
       ezdxf.xref.attach(doc: Drawing, *, block_name: str, filename: str, insert: UVec = (0, 0, 0), scale: float
       = 1.0, rotation: float = 0.0, overlay=False) -> Insert
              Attach the file filename to the host document as external reference (XREF) and creates  a  default
              block  reference  for  the  XREF  in  the  modelspace  of  the  document.   The function raises an
              XrefDefinitionError exception if the block definition already exist, but an XREF can  be  inserted
              multiple times by adding additional block references:

                 msp.add_blockref(block_name, insert=another_location)

              IMPORTANT:
                 If  the XREF has different drawing units than the host document, the scale factor between these
                 units must be applied as a uniform scale factor to the block reference!  Unfortunately the XREF
                 drawing units can only be detected by scanning the HEADER section of a document by the function
                 dxf_info() and is therefore not done automatically by this function.  Advice:  always  use  the
                 same units for all drawings of a project!

              Parametersdoc – host DXF document

                     • block_name – name of the XREF definition block

                     • filename – file name of the XREF

                     • insert – location of the default block reference

                     • scale – uniform scaling factor

                     • rotation – rotation angle in degrees

                     • overlay – creates an XREF overlay if True and an XREF attachment otherwise

              Returns
                     default block reference for the XREF

              Return type
                     Insert

              Raises XrefDefinitionError – block with same name exist

              New in version 1.1.

       ezdxf.xref.define(doc: Drawing, block_name: str, filename: str, overlay=False) -> None
              Add an external reference (xref) definition to a document.

              XREF attachment types:

              • attached: the XREF that’s inserted into this drawing is also present in a document to which this
                document is inserted as an XREF.

              • overlay:  the XREF that’s inserted into this document is not present in a document to which this
                document is inserted as an XREF.

              Parametersdoc – host document

                     • block_name – name of the xref block

                     • filename – external reference filename

                     • overlay – creates an XREF overlay if True and an XREF attachment otherwise

              Raises XrefDefinitionError – block with same name exist

              New in version 1.1.

       ezdxf.xref.detach(block: BlockLayout, *, xref_filename: str | PathLike, overlay=False) -> Drawing
              Write the content of block into the modelspace of a new DXF  document  and  convert  block  to  an
              external   reference   (XREF).    The   new  DXF  document  has  to  be  written  by  the  caller:
              xref_doc.saveas(xref_filename).  This way it is possible to convert the DXF document to DWG by the
              odafc add-on if necessary:

                 xref_doc = xref.detach(my_block, "my_block.dwg")
                 odafc.export_dwg(xref_doc, "my_block.dwg")

              It’s recommended to clean up the entity database of the host document afterwards:

                 doc.entitydb.purge()

              The function does not create any block references. These references should already  exist  and  do
              not need to be changed since references to blocks and XREFs are the same.

              Parametersblock – block definition to detach

                     • xref_filename – name of the external referenced file

                     • overlay – creates an XREF overlay if True and an XREF attachment otherwise

              New in version 1.1.

       ezdxf.xref.dxf_info(filename: str | PathLike) -> DXFInfo
              Scans  the  HEADER  section  of  a  DXF  document  and  returns  a  DXFInfo object, which contains
              information about the DXF version, text encoding, drawing units and insertion base point.

              Raises IOError – not a DXF file or a generic IO error

       ezdxf.xref.embed(xref: BlockLayout, *, load_fn: Callable[[str], Drawing] | None = None, search_paths:
       Iterable[Path | str] = tuple(), conflict_policy=ConflictPolicy.XREF_PREFIX) -> None
              Loads the modelspace of the XREF as content into a block layout.

              The loader function loads the XREF as Drawing object, by default the function ezdxf.readfile()  is
              used  to load DXF files. To load DWG files use the readfile() function from the ezdxf.addons.odafc
              add-on. The ezdxf.recover.readfile() function is very robust for reading DXF files with errors.

              If the XREF path isn’t absolute the XREF is searched in the folder of the host DXF document and in
              the search_path folders.

              ParametersxrefBlockLayout of the XREF document

                     • load_fn – function to load the content of the XREF as Drawing object

                     • search_paths – list of folders to search for XREFS, default is the  folder  of  the  host
                       document or the current directory if no filepath is set

                     • conflict_policy – how to resolve name conflicts

              RaisesXrefDefinitionError – argument xref is not a XREF definition

                     • FileNotFoundError – XREF file not found

                     • DXFVersionError – cannot load a XREF with a newer DXF version than the host
                           document, try the odafc add-on to downgrade the XREF
                           document or upgrade the host document

              New in version 1.1.

       ezdxf.xref.load_modelspace(sdoc: Drawing, tdoc: Drawing, filter_fn: Callable[[DXFEntity], bool] | None =
       None, conflict_policy=ConflictPolicy.KEEP) -> None
              Loads  the  modelspace  content of the source document into the modelspace of the target document.
              The filter function filter_fn gets every source entity as input  and  returns  True  to  load  the
              entity or False otherwise.

              Parameterssdoc – source document

                     • tdoc – target document

                     • filter_fn – optional function to filter entities from the source modelspace

                     • conflict_policy – how to resolve name conflicts

              New in version 1.1.

       ezdxf.xref.load_paperspace(psp: Paperspace, tdoc: Drawing, filter_fn: Callable[[DXFEntity], bool] | None
       = None, conflict_policy=ConflictPolicy.KEEP) -> None
              Loads  the  paperspace  layout  psp  into the target document.  The filter function filter_fn gets
              every source entity as input and returns True to load the entity or False otherwise.

              Parameterspsp – paperspace layout to load

                     • tdoc – target document

                     • filter_fn – optional function to filter entities from the source paperspace layout

                     • conflict_policy – how to resolve name conflicts

              New in version 1.1.

       ezdxf.xref.write_block(entities: Sequence[DXFEntity], *, origin: UVec = (0, 0, 0)) -> Drawing
              Write entities into the modelspace of a new DXF document.

              This function is called “write_block” because the new DXF document can  be  used  as  an  external
              referenced block.  This function is similar to the WBLOCK command in CAD applications.

              Virtual entities are not supported, because each entity needs a real database- and owner handle.

              Parametersentities – DXF entities to write

                     • origin  – block origin, defines the point in the modelspace which will be inserted at the
                       insert location of the block reference

              Raises EntityError – virtual entities are not supported

              New in version 1.1.

   Conflict Policy
       class ezdxf.xref.ConflictPolicy(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              These conflict policies define how to handle resource name conflicts.

              New in version 1.1.

              KEEP   Keeps the existing resource name of the target document and ignore the  resource  from  the
                     source document.

              XREF_PREFIX
                     This policy handles the resource import like CAD applications by always renaming the loaded
                     resources  to <xref>$0$<name>, where xref is the name of source document, the $0$ part is a
                     number to create a unique resource name and <name> is the name of the resource itself.

              NUM_PREFIX
                     This policy renames the loaded resources to $0$<name> only if the resource  <name>  already
                     exists.  The $0$ prefix is a number to create a unique resource name and <name> is the name
                     of the resource itself.

   Low Level Loading Interface
       The Loader class is the basic building block for loading entities and resources. The class manages a list
       of loading commands which is executed at once by calling the Loader.execute() method. It is important  to
       execute  the commands at once to get a consistent renaming of resources when using resource name prefixes
       otherwise the loaded resources would get a new  unique  name  at  each  loading  process  even  when  the
       resources are loaded from the same document.

       class ezdxf.xref.Loader(sdoc: Drawing, tdoc: Drawing, conflict_policy=ConflictPolicy.KEEP)
              Load entities and resources from the source DXF document sdoc into the target DXF document.

              Parameterssdoc – source DXF document

                     • tdoc – target DXF document

                     • conflict_policyConflictPolicy

              load_modelspace(target_layout: BaseLayout | None = None, filter_fn: Callable[[DXFEntity], bool] |
              None = None) -> None
                     Loads  the  content  of  the  modelspace of the source document into a layout of the target
                     document, the modelspace of the target document is the default target  layout.  The  filter
                     function  filter_fn  is  used to skip source entities, the function should return False for
                     entities to ignore and True otherwise.

                     Parameterstarget_layout – target layout can be any layout: modelspace, paperspace layout  or
                              block layout.

                            • filter_fn – function to filter source entities

              load_paperspace_layout(psp: Paperspace, filter_fn: Callable[[DXFEntity], bool] | None = None) ->
              None
                     Loads  a  paperspace  layout  as  a  new  paperspace layout into the target document.  If a
                     paperspace layout with same name already exists the layout will  be  renamed  to   “<layout
                     name> (2)” or “<layout name> (3)” and so on.  The filter function filter_fn is used to skip
                     source  entities,  the  function  should  return  False  for  entities  to  ignore and True
                     otherwise.

                     The content of the modelspace which may be displayed through a VIEWPORT entity will not  be
                     loaded!

                     Parameterspsp – the source paperspace layout

                            • filter_fn – function to filter source entities

              load_paperspace_layout_into(psp: Paperspace, target_layout: BaseLayout, filter_fn:
              Callable[[DXFEntity], bool] | None = None) -> None
                     Loads  the  content  of a paperspace layout into an existing layout of the target document.
                     The filter function filter_fn is used to skip source entities, the function  should  return
                     False for entities to ignore and True otherwise.

                     The  content of the modelspace which may be displayed through a VIEWPORT entity will not be
                     loaded!

                     Parameterspsp – the source paperspace layout

                            • target_layout – target layout can be any layout: modelspace, paperspace layout  or
                              block layout.

                            • filter_fn – function to filter source entities

              load_block_layout(block_layout: BlockLayout) -> None
                     Loads  a block layout (block definition) as a new block layout into the target document. If
                     a block layout with the same name exists the conflict policy will be applied.  This  method
                     cannot load modelspace or paperspace layouts.

                     Parameters
                            block_layout – the source block layout

              load_block_layout_into(block_layout: BlockLayout, target_layout: BaseLayout) -> None
                     Loads  the  content  of  a  block  layout (block definition) into an existing layout of the
                     target document.  This method cannot load the content of modelspace or paperspace layouts.

                     Parametersblock_layout – the source block layout

                            • target_layout – target layout can be any layout: modelspace, paperspace layout  or
                              block layout.

              load_layers(names: Sequence[str]) -> None
                     Loads  the layers defined by the argument names into the target document.  In the case of a
                     name conflict the conflict policy will be applied.

              load_linetypes(names: Sequence[str]) -> None
                     Loads the linetypes defined by the argument names into the target document.  In the case of
                     a name conflict the conflict policy will be applied.

              load_text_styles(names: Sequence[str]) -> None
                     Loads the TEXT styles defined by the argument names into the target document.  In the  case
                     of a name conflict the conflict policy will be applied.

              load_dim_styles(names: Sequence[str]) -> None
                     Loads  the  DIMENSION styles defined by the argument names into the target document. In the
                     case of a name conflict the conflict policy will be applied.

              load_mline_styles(names: Sequence[str]) -> None
                     Loads the MLINE styles defined by the argument names into the target document. In the  case
                     of a name conflict the conflict policy will be applied.

              load_mleader_styles(names: Sequence[str]) -> None
                     Loads the MULTILEADER styles defined by the argument names into the target document. In the
                     case of a name conflict the conflict policy will be applied.

              load_materials(names: Sequence[str]) -> None
                     Loads  the MATERIALS defined by the argument names into the target document. In the case of
                     a name conflict the conflict policy will be applied.

              execute(xref_prefix: str = '') -> None
                     Execute all loading commands. The xref_prefix string is used as XREF name when the conflict
                     policy ConflictPolicy.XREF_PREFIX is applied.

HOWTO

       The Howto section show how to accomplish specific tasks with ezdxf in  a  straight  forward  way  without
       teaching  basics  or internals, if you are looking for more information about the ezdxf internals look at
       the Reference section or if you want to learn how to use ezdxf go to the  Tutorials  section  or  to  the
       Basic Concepts section.

   General Document
       General preconditions:

          import sys
          import ezdxf

          try:
              doc = ezdxf.readfile("your_dxf_file.dxf")
          except IOError:
              print(f"Not a DXF file or a generic I/O error.")
              sys.exit(1)
          except ezdxf.DXFStructureError:
              print(f"Invalid or corrupted DXF file.")
              sys.exit(2)
          msp = doc.modelspace()

       This  works well with DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files with
       minor or major flaws look at the ezdxf.recover module.

   Load DXF Files with Structure Errors
       If you know the files you will process have most likely minor  or  major  flaws,  use  the  ezdxf.recover
       module:

          import sys
          from ezdxf import recover

          try:  # low level structure repair:
              doc, auditor = recover.readfile(name)
          except IOError:
              print(f"Not a DXF file or a generic I/O error.")
              sys.exit(1)
          except ezdxf.DXFStructureError:
              print(f"Invalid or corrupted DXF file: {name}.")
              sys.exit(2)

          # DXF file can still have unrecoverable errors, but this is maybe
          # just a problem when saving the recovered DXF file.
          if auditor.has_errors:
              print(f"Found unrecoverable errors in DXF file: {name}.")
              auditor.print_error_report()

       For more loading scenarios follow the link: ezdxf.recover

   Set/Get Header Variables
       ezdxf has an interface to get and set HEADER variables:

          doc.header["VarName"] = value
          value = doc.header["VarName"]

       SEE ALSO:
          HeaderSection and online documentation from Autodesk for available header variables.

   Set DXF Drawing Units
       The  header  variable  $INSUNITS  defines  the drawing units for the modelspace and therefore for the DXF
       document if no further settings are applied. The most common units are 6 for meters and 1 for inches.

       Use this HEADER variables to setup the default units for CAD applications  opening  the  DXF  file.  This
       setting  is  not  relevant  for ezdxf API calls, which are unitless for length values and coordinates and
       decimal degrees for angles (in most cases).

       Sets drawing units:

          doc.header["$INSUNITS"] = 6

       For more information see section DXF Units.

   Create More Readable DXF Files (DXF Pretty Printer)
       DXF files are plain text files, you can open this files with  every  text  editor  which  handles  bigger
       files. But it is not really easy to get quick the information you want.

       Create a more readable HTML file (DXF Pretty Printer):

          # Call as executable script from the command line:
          ezdxf pp FILE [FILE ...]

          # Call as module on Windows:
          py -m ezdxf pp FILE [FILE ...]

          # Call as module on Linux/Mac
          python3 -m ezdxf pp FILE [FILE ...]

       This  creates  a  HTML file with a nicer layout than a plain text file, and handles are links between DXF
       entities, this simplifies the navigation between the DXF entities.

          usage: ezdxf pp [-h] [-o] [-r] [-x] [-l] FILE [FILE ...]

          positional arguments:
            FILE             DXF files pretty print

          optional arguments:
            -h, --help       show this help message and exit
            -o, --open       open generated HTML file with the default web browser
            -r, --raw        raw mode - just print tags, no DXF structure interpretation
            -x, --nocompile  don't compile points coordinates into single tags (only in
                             raw mode)
            -l, --legacy     legacy mode - reorders DXF point coordinates

       IMPORTANT:
          This does not render the graphical content of the DXF file to a HTML canvas element.

   Calculate Extents for the Modelspace
       Since ezdxf v0.16 exist a ezdxf.bbox module to calculate bounding boxes for  DXF  entities.  This  module
       makes the extents calculation very easy, but read the documentation for the bbox module to understand its
       limitations.

          import ezdxf
          from ezdxf import bbox

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

          extents = bbox.extents(msp)

       The returned extents is a ezdxf.math.BoundingBox object.

   Set Initial View/Zoom for the Modelspace
       To show an arbitrary location of the modelspace centered in the CAD application window, set the '*Active'
       VPORT  to  this  location.  The  DXF attribute dxf.center defines the location in the modelspace, and the
       dxf.height specifies the area of the modelspace to view. Shortcut function:

          doc.set_modelspace_vport(height=10, center=(10, 10))

       SEE ALSO:
          The ezdxf.zoom module is another way to set the initial modelspace view.

       Setting the initial view to the extents of all entities in the modelspace:

          import ezdxf
          from ezdxf import zoom

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

       Setting the initial view to the extents of just some entities:

          lines = msp.query("LINES")
          zoom.objects(lines)

       The zoom module also works for paperspace layouts.

       IMPORTANT:
          The zoom module uses the bbox module to calculate the  bounding  boxes  for  DXF  entities.  Read  the
          documentation  for  the bbox module to understand its limitations and the bounding box calculation for
          large documents can take a while!

   Hide the UCS Icon
       The visibility of the UCS icon is controlled by the DXF ucs_icon attribute of the VPort entity:

          • bit 0: 0=hide, 1=show

          • bit 1: 0=display in lower left corner, 1=display at origin

       The state of the UCS icon can be set in conjunction with the initial VPort of the model space, this  code
       turns off the UCS icon:

          doc.set_modelspace_vport(10, center=(10, 10), dxfattribs={"ucs_icon": 0})

       Alternative: turn off UCS icons for all VPort entries in the active viewport configuration:

          for vport in doc.viewports.get_config("*Active"):
              vport.dxf.ucs_icon = 0

   Show Lineweights in DXF Viewers
       By default lines and curves are shown without lineweights in DXF viewers.  By setting the header variable
       $LWDISPLAY to 1 the DXF viewer should display lineweights, if supported by the viewer.

          doc.header["$LWDISPLAY"] = 1

   Add ezdxf Resources to Existing DXF Document
       Add all ezdxf specific resources (line types, text- and dimension styles) to an existing DXF document:

          import ezdxf
          from ezdxf.tools.standards import setup_drawing

          doc = ezdxf.readfile("your.dxf")
          setup_drawing(doc, topics="all")

   Set Logging Level of ezdxf
       Set  the logging level of the ezdxf package to a higher level to minimize logging messages from ezdxf. At
       level ERROR only severe errors will be logged and WARNING, INFO and DEBUG messages will be suppressed:

          import logging

          logging.getLogger("ezdxf").setLevel(logging.ERROR)

   DXF Viewer
   A360 Viewer Problems
       AutoDesk web service A360 seems to be more picky than the AutoCAD desktop applications, may be  it  helps
       to use the latest DXF version supported by ezdxf, which is DXF R2018 (AC1032) in the year of writing this
       lines (2018).

   DXF Entities Are Not Displayed in the Viewer
       ezdxf  does  not  automatically  locate  the main viewport of the modelspace at the entities, you have to
       perform the “Zoom to Extends” command, here in TrueView 2020: [image]

       And here in the Autodesk Online Viewer: [image]

       Add this line to your code to relocate the main viewport, adjust the center (in  modelspace  coordinates)
       and the height (in drawing units) arguments to your needs:

          doc.set_modelspace_vport(height=10, center=(0, 0))

   Show IMAGES/XREFS on Loading in AutoCAD
       If  you  are  adding XREFS and IMAGES with relative paths to existing drawings and they do not show up in
       AutoCAD immediately, change the HEADER variable $PROJECTNAME='' to (not really) solve this problem.   The
       ezdxf templates for DXF R2004 and later have $PROJECTNAME='' as default value.

       Thanks to David Booth:
          If the filename in the IMAGEDEF contains the full path (absolute in AutoCAD) then it shows on loading,
          otherwise it won’t display (reports as unreadable) until you manually reload using XREF manager.

          A  workaround  (to show IMAGES on loading) appears to be to save the full file path in the DXF or save
          it as a DWG.

       Thanks to Zac Luzader:
          Has anyone else noticed that very short simple image file names seem to avoid  this  problem?  Once  I
          ensured  that  the  image  file’s  name  was short and had no special characters (letters, numbers and
          underscores only) the problem seemed to go away.  I didn’t rigorously analyze the behavior as its very
          time consuming.

          Also: You can safely put the image in a subdirectory  and  use  a  relative  path.  The  name  of  the
          subdirectory  does  not seem to trigger this problem, provided that the image file name itself is very
          short and simple.

          Also pro tip: The XRef manager exists in DWG TrueView 2023, but access to it is only possible  if  you
          have  a  completely  broken  reference. Create a DXF with a reference to a non-existent file, then the
          error dialog will let you open the XRef Manager.  Once it is open you can pin it and it will  be  open
          next time, even if you have no broken references.

       SEE ALSO:
          Discussion on github: Images don’t show in AutoCAD until 

   Set Initial View/Zoom for the Modelspace
       See section “General Document”: Set Initial View/Zoom for the Modelspace

   Show Lineweights in DXF Viewers
       By default lines and curves are shown without lineweights in DXF viewers.  By setting the header variable
       $LWDISPLAY to 1 the DXF viewer should display lineweights, if supported by the viewer.

          doc.header["$LWDISPLAY"] = 1

   DXF Content
       General preconditions:

          import sys
          import ezdxf

          try:
              doc = ezdxf.readfile("your_dxf_file.dxf")
          except IOError:
              print(f'Not a DXF file or a generic I/O error.')
              sys.exit(1)
          except ezdxf.DXFStructureError:
              print(f'Invalid or corrupted DXF file.')
              sys.exit(2)
          msp = doc.modelspace()

   Get/Set Entity Color
       The entity color is stored as ACI (AutoCAD Color Index):

          aci = entity.dxf.color

       Default value is 256 which means BYLAYER:

          layer = doc.layers.get(entity.dxf.layer)
          aci = layer.get_color()

       The  special  get_color()  method  is required, because the color attribute Layer.dxf.color is misused as
       layer on/off flag, a negative color value means the layer is off.

       ACI value 0 means BYBLOCK, which means the color from the block reference (INSERT entity).

       Set color as ACI value as int in range [0, 256]:

          entity.dxf.color = 1

       The ACI value 7 has a special meaning, it is white on dark backgrounds and white on light backgrounds.

   Get/Set Entity RGB Color
       RGB true color values are supported since DXF R13 (AC1012), the 24-bit RGB value is stored as integer  in
       the DXF attribute true_color:

          # 24 bit binary value: 0bRRRRRRRRGGGGGGGGBBBBBBBB or hex value: 0xRRGGBB
          # set true color value to red
          entity.dxf.true_color = 0xFF0000

       Use the helper functions from the ezdxf.colors module for RGB integer value handling:

          from ezdxf import colors

          entity.dxf.true_color = colors.rgb2int((0xFF, 0, 0))
          r, g, b = colors.int2rgb(entity.dxf.true_color)

       The  RGB  values of the AutoCAD default colors are not officially documented, but an accurate translation
       table is included in ezdxf:

          # Warning: ACI value 256 (BYLAYER) raises an IndexError!
          rgb24 = colors.DXF_DEFAULT_COLORS[aci]
          print(f"RGB Hex Value: #{rgb24:06X}")
          r, g, b = colors.int2rgb(rgb24)
          print(f"RGB Channel Values: R={r:02X} G={g:02X} b={b:02X}")

       If color and true_color values are set, BricsCAD and AutoCAD use the true_color value  as  display  color
       for the entity.

   Get/Set True Color as RGB-Tuple
       Get/Set the true color value as (r, g, b)-tuple by the rgb property of the DXFGraphic entity:

          # set true color value to red
          entity.rgb = (0xFF, 0, 0)

          # get true color values
          r, g, b = entity.rgb

   Get/Set Block Reference Attributes
       Block  references  (Insert) can have attached attributes (Attrib), these are simple text annotations with
       an associated tag appended to the block reference.

       Iterate over all appended attributes:

          # get all INSERT entities with entity.dxf.name == "Part12"
          blockrefs = msp.query('INSERT[name=="Part12"]')
          if len(blockrefs):
              entity = blockrefs[0]  # process first entity found
              for attrib in entity.attribs:
                  if attrib.dxf.tag == "diameter":  # identify attribute by tag
                      attrib.dxf.text = "17mm"  # change attribute content

       Get attribute by tag:

          diameter = entity.get_attrib('diameter')
          if diameter is not None:
              diameter.dxf.text = "17mm"

   Adding XDATA to Entities
       Adding XDATA as list of tuples (group code, value) by set_xdata(), overwrites data if already present:

          doc.appids.new('YOUR_APPID')  # IMPORTANT: create an APP ID entry

          circle = msp.add_circle((10, 10), 100)
          circle.set_xdata(
              'YOUR_APPID',
              [
                  (1000, 'your_web_link.org'),
                  (1002, '{'),
                  (1000, 'some text'),
                  (1002, '{'),
                  (1071, 1),
                  (1002, '}'),
                  (1002, '}')
              ])

       For group code meaning see DXF reference section DXF Group Codes  in  Numerical  Order  Reference,  valid
       group codes are in the range 1000 - 1071.

       Method get_xdata() returns the extended data for an entity as Tags object.

       SEE ALSO:
          Tutorial: Storing Custom Data in DXF Files

   Get Overridden DIMSTYLE Values from DIMENSION
       In  general  the  Dimension  styling  and  config attributes are stored in the Dimstyle entity, but every
       attribute can be overridden for each  DIMENSION  entity  individually,  get  overwritten  values  by  the
       DimstyleOverride object as shown in the following example:

          for dimension in msp.query('DIMENSION'):
              dimstyle_override = dimension.override()  # requires v0.12
              dimtol = dimstyle_override['dimtol']
              if dimtol:
                  print(f'{str(dimension)} has tolerance values:')
                  dimtp = dimstyle_override['dimtp']
                  dimtm = dimstyle_override['dimtm']
                  print(f'Upper tolerance: {dimtp}')
                  print(f'Lower tolerance: {dimtm}')

       The  DimstyleOverride  object  returns  the  value  of  the  underlying  DIMSTYLE objects if the value in
       DIMENSION was not overwritten, or None if the value was neither defined in DIMSTYLE nor in DIMENSION.

   Override DIMSTYLE Values for DIMENSION
       Same as above, the DimstyleOverride object supports also overriding DIMSTYLE values.  But just overriding
       this values have no effect  on  the  graphical  representation  of  the  DIMENSION  entity,  because  CAD
       applications  just show the associated anonymous block which contains the graphical representation on the
       DIMENSION entity as simple DXF entities. Call  the  render  method  of  the  DimstyleOverride  object  to
       recreate  this  graphical  representation  by  ezdxf,  but ezdxf does not support all DIMENSION types and
       DIMVARS yet, and results will differ from AutoCAD or BricsCAD renderings.

          dimstyle_override = dimension.override()
          dimstyle_override.set_tolerance(0.1)

          # delete associated geometry block
          del doc.blocks[dimension.dxf.geometry]

          # recreate geometry block
          dimstyle_override.render()

   How to Change the HATCH Pattern Origin Point
       This code sets the origin of the first pattern line to the given origin and the origins of all  remaining
       pattern lines relative to the first pattern line origin.

          from ezdxf.entities import Hatch, Pattern
          from ezdxf.math import Vec2

          def shift_pattern_origin(hatch: Hatch, offset: Vec2):
              if isinstance(hatch.pattern, Pattern):
                  for pattern_line in hatch.pattern.lines:
                      pattern_line.base_point += offset

          def reset_pattern_origin_of_first_pattern_line(hatch: Hatch, origin: Vec2):
              if isinstance(hatch.pattern, Pattern) and len(hatch.pattern.lines):
                  first_pattern_line = hatch.pattern.lines[0]
                  offset = origin - first_pattern_line.base_point
                  shift_pattern_origin(hatch, offset)

       SEE ALSO:

          • Discussion #769

   How to Get the Length of a Spline or Polyline
       There  exist  no  analytical  function to calculate the length of a B-spline, you have to approximate the
       curve and calculate the length of the polyline.  The construction tool ezdxf.math.ConstructionPolyline is
       may be useful for that.

          import ezdxf
          from ezdxf.math import ConstructionPolyline

          doc = ezdxf.new()
          msp = doc.modelspace()
          fit_points = [(0, 0, 0), (750, 500, 0), (1750, 500, 0), (2250, 1250, 0)]

          spline = msp.add_spline(fit_points)
          # Adjust the max. sagitta distance to your needs or run the calculation in a loop
          # reducing the distance until the difference to the previous run is smaller
          # than your expected precision:
          polyline = ConstructionPolyline(spline.flattening(distance=0.1))
          print(f"approximated length = {polyline.length:.2f}")

   How to Resolve DXF Properties
       Graphical properties of DXF entities (color, lineweight, …) are sometimes hard to resolve because of  the
       complex possibilities to inherit properties from layers or blocks, or overriding them by ctb files.

       The drawing add-on provides the RenderContext class that can be used to resolve properties of entities in
       the context of their use:

          import ezdxf
          from ezdxf.addons.drawing.properties import RenderContext

          doc = ezdxf.new()
          doc.layers.add("LINE", color=ezdxf.colors.RED)
          msp = doc.modelspace()
          line = msp.add_line((0, 0), (1, 0), dxfattribs={"layer": "LINE"})

          ctx = RenderContext(doc)
          ctx.set_current_layout(msp)
          print(f"resolved RGB value: {ctx.resolve_color(line)}")

       Output:

          resolved RGB value: #ff0000

       This  works  in most simple cases, resolving properties of objects in viewports or nested blocks requires
       additional information that is beyond the scope of a simple guide.

   How to Find XREF Definitions
       XREFs are normal block definitions and can be found in the BLOCKS section:

          for block_layout in doc.blocks:
              block = block_layout.block  # the BLOCK entity
              if block.is_xref:
                  handle_xref(block_layout)
              elif block.is_xref_overlay:
                  handle_xref_overlay(block_layout)

       SEE ALSO:

          • documentation of the ezdxf.xref module

          • ezdxf.layouts.BlockLayout

   How to Find XREF References
       An XREF reference is a block reference (INSERT entity) to the block definition of the XREF:

          for insert in msp.query("INSERT"):
              if insert.is_xref:
                  handle_xref_reference(insert)
                  # ... or get the XREF definition
                  block_layout = insert.block()
                  if block_layout is not None:
                      block = block_layout.block
                      if block.is_xref:
                          handle_xref(block_layout)
                      elif block.is_xref_overlay:
                          handle_xref_overlay(block_layout)

       Like any normal block, an XREF can be inserted multiple times.

       SEE ALSO:

          • documentation of the ezdxf.xref module

          • ezdxf.layouts.BlockLayout

   Fonts
   Rendering SHX Fonts
       The SHX font format is not documented nor supported by many libraries/packages like  Matplotlib  and  Qt,
       therefore  only  SHX  fonts  which  have  corresponding  TTF-fonts can be rendered by these backends. The
       mapping from/to SHX/TTF fonts is hard coded in the source code file: fonts.py

       Since ezdxf v1.1 is the rendering of SHX fonts supported if the path to  these  fonts  is  added  to  the
       support_dirs in the Config Files.

   Rebuild Font Manager Cache
       If  you  wanna use new installed fonts which are not included in the current cache file of ezdxf you have
       to rebuild the cache file:

          import ezdxf
          from ezdxf.fonts import fonts

          fonts.build_system_font_cache()

       or call the ezdxf launcher to do that:

          ezdxf --fonts

   Drawing Add-on
       This section consolidates the FAQ about the drawing add-on from the github forum.

   All Backends
   How to Set Background and Foreground Colors
       Override the default background and foreground colors.  The foreground color is the AutoCAD  Color  Index
       (ACI)  7,  which  is  white/black  depending  on  the  background  color.  If the foreground color is not
       specified, the foreground color is white for dark backgrounds  and  black  for  light  backgrounds.   The
       required color format is a hex string “#RRGGBBAA”.

          from ezdxf.addons.drawing.properties import LayoutProperties


          # -x-x-x snip -x-x-x-
          fig: plt.Figure = plt.figure()
          ax: plt.Axes = fig.add_axes((0, 0, 1, 1))
          ctx = RenderContext(doc)

          # get the modelspace properties
          msp_properties = LayoutProperties.from_layout(msp)

          # set light gray background color and black foreground color
          msp_properties.set_colors("#eaeaea")
          out = MatplotlibBackend(ax)

          # override the layout properties and render the modelspace
          Frontend(ctx, out).draw_layout(
              msp,
              finalize=True,
              layout_properties=msp_properties,
          )
          fig.savefig("image.png")

       A light background “#eaeaea” has a black foreground color by default: [image]

       A dark background “#0a0a0a” has a white foreground color by default:


          # -x-x-x snip -x-x-x-
          msp_properties.set_colors("#0a0a0a")

          # -x-x-x snip -x-x-x-
       [image]

   How to Set a Transparent Background Color
       The  override color include an alpha transparency “#RRGGBBAA” value. An alpha value of “00” is opaque and
       “ff” is fully transparent.  A transparent background color still defines the foreground color!

       HINT:
          The savefig() function of the matplotlib backend requires the transparent argument to be set  to  True
          to support transparency.

       A light and fully transparent background “#eaeaeaff” has a black foreground color by default:


          # -x-x-x snip -x-x-x-
          msp_properties.set_colors("#eaeaeaff")


          # -x-x-x snip -x-x-x-
          fig.savefig("image.png", transparent=True)
       [image]

       A dark and fully transparent background “#0a0a0aff” has a white foreground color by default:


          # -x-x-x snip -x-x-x-
          msp_properties.set_colors("#0a0a0aff")


          # -x-x-x snip -x-x-x-
          fig.savefig("image.png", transparent=True)
       [image]

   How to Exclude DXF Entities from Rendering
       • If all unwanted entities are on the same layer switch off the layer.

       • If the document is not saved later, you can delete the entities or set them invisible.

       • Filter the unwanted entities by a filter function.

       The  argument filter_func of the Frontend.draw_layout() method expects a function which takes a graphical
       DXF entity as input and returns True if the entity should be rendered or False to exclude the entity from
       rendering.

       This filter function excludes all DXF entities with an ACI color value of 2:

          from ezdxf.entities import DXFGraphic

          def my_filter(e: DXFGraphic) -> bool:
              return e.dxf.color != 2


          # -x-x-x snip -x-x-x-
          Frontend(ctx, out).draw_layout(msp, finalize=True, filter_func=my_filter)

       IMPORTANT:
          Not all attributes have a default value if the attribute does not exist.  If you are  not  sure  about
          this, use the get() method:

              def my_filter(e: DXFGraphic) -> bool:
                  return e.dxf.get("color", 7) != 2

   How to Override Properties of DXF Entities
       Create a custom Frontend class and override the the override_properties() method:

          class MyFrontend(Frontend):
              def override_properties(self, entity: DXFGraphic, properties: Properties) -> None:
                  # remove alpha channel from all entities, "#RRGGBBAA"
                  properties.color = properties.color[:7]


          # -x-x-x snip -x-x-x-
          MyFrontend(ctx, out).draw_layout(msp, finalize=True)

       SEE ALSO:ezdxf.addons.drawing.properties.Properties

   Matplotlib Backend
       SEE ALSO:

          • Matplotlib package: https://matplotlib.org/stable/api/matplotlib_configuration_api.htmlFigure API: https://matplotlib.org/stable/api/figure_api.htmlAxes API: https://matplotlib.org/stable/api/axis_api.html

   How to Get the Pixel Coordinates of DXF Entities
       SEE ALSO:

          • Source: https://github.com/mozman/ezdxf/discussions/219

       Transformation from modelspace coordinates to image coordinates:

          import matplotlib.pyplot as plt
          from PIL import Image, ImageDraw

          import ezdxf
          from ezdxf.math import Matrix44
          from ezdxf.addons.drawing import RenderContext, Frontend
          from ezdxf.addons.drawing.matplotlib import MatplotlibBackend

          def get_wcs_to_image_transform(
              ax: plt.Axes, image_size: tuple[int, int]
          ) -> Matrix44:
              """Returns the transformation matrix from modelspace coordinates to image
              coordinates.
              """

              x1, x2 = ax.get_xlim()
              y1, y2 = ax.get_ylim()
              data_width, data_height = x2 - x1, y2 - y1
              image_width, image_height = image_size
              return (
                  Matrix44.translate(-x1, -y1, 0)
                  @ Matrix44.scale(
                      image_width / data_width, -image_height / data_height, 1.0
                  )
                  # +1 to counteract the effect of the pixels being flipped in y
                  @ Matrix44.translate(0, image_height + 1, 0)
              )

          # create the DXF document
          doc = ezdxf.new()
          msp = doc.modelspace()
          msp.add_lwpolyline([(0, 0), (1, 0), (1, 1), (0, 1)], close=True)
          msp.add_line((0, 0), (1, 1))

          # export the pixel image
          fig: plt.Figure = plt.figure()
          ax: plt.Axes = fig.add_axes([0, 0, 1, 1])
          ctx = RenderContext(doc)
          out = MatplotlibBackend(ax)
          Frontend(ctx, out).draw_layout(msp, finalize=True)
          fig.savefig("cad.png")
          plt.close(fig)

          # reload the pixel image by Pillow (PIL)
          img = Image.open("cad.png")
          draw = ImageDraw.Draw(img)

          # add some annotations to the pixel image by using modelspace coordinates
          m = get_wcs_to_image_transform(ax, img.size)
          a, b, c = (
              (v.x, v.y)  # draw.line() expects tuple[float, float] as coordinates
              # transform modelspace coordinates to image coordinates
              for v in m.transform_vertices([(0.25, 0.75), (0.75, 0.25), (1, 1)])
          )
          draw.line([a, b, c, a], fill=(255, 0, 0))

          # show the image by the default image viewer
          img.show()

   How to Get Modelspace Coordinates from Pixel Coordinates
       This is the reverse operation of the previous how-to: How to Get the Pixel Coordinates of DXF Entities

       SEE ALSO:

          • Full example script: wcs_to_image_coordinates.py

          • Source: https://github.com/mozman/ezdxf/discussions/269

          def get_image_to_wcs_transform(
              ax: plt.Axes, image_size: tuple[int, int]
          ) -> Matrix44:
              m = get_wcs_to_image_transform(ax, image_size)
              m.inverse()
              return m


          # -x-x-x snip -x-x-x-
          img2wcs = get_image_to_wcs_transform(ax, img.size)
          print(f"0.25, 0.75 == {img2wcs.transform(a).round(2)}")
          print(f"0.75, 0.25 == {img2wcs.transform(b).round(2)}")
          print(f"1.00, 1.00 == {img2wcs.transform(c).round(2)}")

   How to Export a Specific Area of the Modelspace
       This code exports the specified modelspace area from (5, 3) to (7, 8) as a 2x5 inch PNG image to maintain
       the aspect ratio of the source area.

       Use case: render only a specific area of the modelspace.

       SEE ALSO:

          • Full example script: export_specific_area.py

          • Source: https://github.com/mozman/ezdxf/discussions/451


          # -x-x-x snip -x-x-x-
          # export the pixel image
          fig: plt.Figure = plt.figure()
          ax: plt.Axes = fig.add_axes([0, 0, 1, 1])
          ctx = RenderContext(doc)
          out = MatplotlibBackend(ax)
          Frontend(ctx, out).draw_layout(msp, finalize=True)

          # setting the export area:
          xmin, xmax = 5, 7
          ymin, ymax = 3, 8
          ax.set_xlim(xmin, xmax)
          ax.set_ylim(ymin, ymax)

          # set the output size to get the expected aspect ratio:
          fig.set_size_inches(xmax - xmin, ymax - ymin)
          fig.savefig("x5y3_to_x7y8.png")
          plt.close(fig)

   How to Render Without Margins
       To remove the empty space at the image borders set the margins of the Axes object to zero:

          ax.margins(0)
          fig.savefig("image_without_margins.png")
          plt.close(fig)

       SEE ALSO:

          • Matplotlib docs about margins

   How to Set the Pixel Count per Drawing Unit
       This  code  exports the modelspace with an extent of 5 x 3 drawing units with 100 pixels per drawing unit
       as a 500 x 300 pixel image.

       Use case: render the content with a fixed number of pixels for a drawing unit, e.g. a drawing unit  of  1
       inch should be rendered by 100 pixels.

       SEE ALSO:

          • Full example script: export_image_pixel_size.py

          • Source: https://github.com/mozman/ezdxf/discussions/357


          # -x-x-x snip -x-x-x-
          def set_pixel_density(fig: plt.Figure, ax: plt.Axes, ppu: int):
              """Argument `ppu` is pixels per drawing unit."""
              xmin, xmax = ax.get_xlim()
              width = xmax - xmin
              ymin, ymax = ax.get_ylim()
              height = ymax - ymin
              dpi = fig.dpi
              width_inch = width * ppu / dpi
              height_inch = height * ppu / dpi
              fig.set_size_inches(width_inch, height_inch)


          # -x-x-x snip -x-x-x-
          # export image with 100 pixels per drawing unit = 500x300 pixels
          set_pixel_density(fig, ax, 100)
          fig.savefig("box_500x300.png")
          plt.close(fig)

   How to Export a Specific Image Size in Pixels
       This code exports the modelspace with an extent of 5 x 3 drawing units as a 1000 x 600 pixel Image.

       Use case: render the content with a fixed image size in pixels.

       SEE ALSO:

          • Full example script: export_image_pixel_size.py

          • Source: https://github.com/mozman/ezdxf/discussions/357


          # -x-x-x snip -x-x-x-
          def set_pixel_size(fig: plt.Figure, size: tuple[int, int]):
              x, y = size
              fig.set_size_inches(x / fig.dpi, y / fig.dpi)


          # -x-x-x snip -x-x-x-
          # export image with a size of 1000x600 pixels
          set_pixel_size(fig, (1000, 600))
          fig.savefig("box_1000x600.png")
          plt.close(fig)

   How to Set the Page Size in Inches
       The page- or image size in inches is set by the set_size_inches() method of the Figure class. The content
       within the Axes limits will be scaled to fill the page.

       Use  case:  render  the whole content to a PDF document with a specific paper size without worrying about
       scale.

          fig.set_size_inches(8, 11)

   How to Render at a Specific Scale
       This code exports the modelspace at a specific scale and paper size.

       Use case: render the content to a PDF document with a specific paper size and scale, but not all  content
       may be rendered.

       SEE ALSO:

          • Full example script: render_to_scale.py

          • Source: https://github.com/mozman/ezdxf/discussions/665


          # -x-x-x snip -x-x-x-
          def render_limits(
              origin: tuple[float, float],
              size_in_inches: tuple[float, float],
              scale: float,
          ) -> tuple[float, float, float, float]:
              """Returns the final render limits in drawing units.

              Args:
                   origin: lower left corner of the modelspace area to render
                   size_in_inches: paper size in inches
                   scale: render scale, e.g. scale=100 means 1:100, 1m is
                       rendered as 0.01m or 1cm on paper

              """
              min_x, min_y = origin
              max_x = min_x + size_in_inches[0] * scale
              max_y = min_y + size_in_inches[1] * scale
              return min_x, min_y, max_x, max_y

          def export_to_scale(
              paper_size: tuple[float, float] = (8.5, 11),
              origin: tuple[float, float] = (0, 0),
              scale: float = 1,
              dpi: int = 300,
          ):
              """Render the modelspace content with to a specific paper size and scale.

              Args:
                  paper_size: paper size in inches
                  origin: lower left corner of the modelspace area to render
                  scale: render scale, e.g. scale=100 means 1:100, 1m is
                      rendered as 0.01m or 1cm on paper
                  dpi: pixel density on paper as dots per inch

              """

              # -x-x-x snip -x-x-x-
              ctx = RenderContext(doc)
              fig: plt.Figure = plt.figure(dpi=dpi)
              ax: plt.Axes = fig.add_axes([0, 0, 1, 1])

              # disable all margins
              ax.margins(0)

              # get the final render limits in drawing units:
              min_x, min_y, max_x, max_y = render_limits(
                  origin, paper_size, scale
              )

              ax.set_xlim(min_x, max_x)
              ax.set_ylim(min_y, max_y)

              out = MatplotlibBackend(ax)
              # finalizing invokes auto-scaling by default!
              Frontend(ctx, out).draw_layout(msp, finalize=False)

              # set output size in inches:
              fig.set_size_inches(paper_size[0], paper_size[1], forward=True)

              fig.savefig(f"image_scale_1_{scale}.pdf", dpi=dpi)
              plt.close(fig)

   How to Control the Line Width
       The  DXF  lineweight  attribute  defines the line width as absolute width on the output medium (e.g. 25 =
       0.25mm) and therefore depends only on the DPI (dots per  inch)  setting  of  the  Figure  class  and  the
       savefig() method.

       There are two additional settings in the Configuration class which influences the line width:

       • min_lineweight sets the minimum line width in 1/300 inch - a value of 300 is a line width of 1 inch

       • lineweight_scaling, multiply the line width by a this factor

       The  following table shows the line width in pixels for all valid DXF lineweights for a resolution of 72,
       100, 200 and 300 dpi: [image]

       SEE ALSO:
          Discussion: https://github.com/mozman/ezdxf/discussions/797

FAQ

       These are the old FAQ until late 2023, new FAQs will only be added to the Knowledge Graph.

   What is the Relationship between ezdxf, dxfwrite and dxfgrabber?
       In 2010 I started my first Python package for creating DXF documents called dxfwrite, this package  can’t
       read  DXF files and writes only the DXF R12 (AC1009) version.  While dxfwrite works fine, I wanted a more
       versatile package, that can read and write DXF files and maybe also supports newer DXF formats  than  DXF
       R12.

       This  was the start of the ezdxf package in 2011, but the progress was so slow, that I created a spin off
       in 2012 called dxfgrabber, which implements only the reading part of ezdxf, which I needed  for  my  work
       and  I  wasn’t sure if ezdxf will ever be usable. Luckily in 2014 the first usable version of ezdxf could
       be released. The ezdxf package has all the features of dxfwrite and dxfgrabber and much more, but with  a
       different API. So ezdxf is not a drop-in replacement for dxfgrabber or dxfwrite.

       Since  ezdxf  can  do all the things that dxfwrite and dxfgrabber can do, I focused on the development of
       ezdxf, dxfwrite and dxfgrabber are in maintenance-only mode and will  not  get  any  new  features,  just
       bugfixes.

       There  are  no  advantages  of  dxfwrite  over  ezdxf,  dxfwrite  has a smaller memory footprint, but the
       r12writer add-on does the same job as dxfwrite without any in-memory structures by writing  direct  to  a
       stream  or  file  and  there  is  also  no advantage of dxfgrabber over ezdxf for ordinary DXF files, the
       smaller memory footprint of dxfgrabber is not noticeable and for really big files the iterdxf add-on does
       a better job.

   Imported ezdxf package has no content. (readfile, new)
       1. AttributeError: partially initialized module ‘ezdxf’ has no attribute ‘readfile’ (most likely due to a
          circular import)

          Did you name your file/script “ezdxf.py”? This causes problems with circular  imports.  Renaming  your
          file/script should solve this issue.

       2. AttributeError: module ‘ezdxf’ has no attribute ‘readfile’

          This  could  be  a  hidden  permission  error,  for more information about this issue read Petr Zemeks
          article: https://blog.petrzemek.net/2020/11/17/when-you-import-a-python-package-and-it-is-empty/

   How to add/edit ACIS based entities like 3DSOLID, REGION or SURFACE?
       The BODY, 3DSOLID, SURFACE, REGION and so on, are stored as ACIS data embedded in the DXF file. The  ACIS
       data  is  stored as SAT (text) format in the entity itself for DXF R2000-R2010 and as SAB (binary) format
       in the ACDSDATA section for DXF R2013+. Ezdxf can read SAT and SAB data, but only write SAT data.

       The ACIS data is a proprietary format from Spatial Inc., and there exist no free available  documentation
       or  open source libraries to create or edit SAT or SAB data, and also ezdxf provides no functionality for
       creating or editing ACIS data.

       The ACIS support provided by ezdxf is only useful for users which  have  access  to  the  ACIS  SDK  from
       Spatial Inc..

   Are OLE/OLE2 entities supported?
       TLDR; NO!

       The  Wikipedia  definition of OLE: Object Linking & Embedding (OLE) is a proprietary technology developed
       by Microsoft that allows embedding and linking to documents and other objects. For developers, it brought
       OLE Control Extension (OCX), a way to develop and use custom user  interface  elements.  On  a  technical
       level,  an  OLE object is any object that implements the IOleObject interface, possibly along with a wide
       range of other interfaces, depending on the object’s needs.

       Therefore ezdxf does not support this entities in any way,  this  only  work  on  Windows  and  with  the
       required editing application installed.  The binary data stored in the OLE objects cannot be used without
       the editing application.

       In  my  opinion, using OLE objects in a CAD drawing is a very bad design decision that can and will cause
       problems opening these files in the future,  even  in  AutoCAD  on  Windows  when  the  required  editing
       application is no longer available or the underlying technology is no longer supported.

       All  of  this is unacceptable for a data storage format that should be accessed for many years or decades
       (e.g. construction drawings for buildings or bridges).

   Rendering SHX fonts
       The SHX font format is not documented nor supported by many libraries/packages like  Matplotlib  and  Qt,
       therefore  only  SHX fonts which have corresponding TTF-fonts can be rendered by these backends. See also
       how-tos about Fonts

   Drawing Add-on
       There is a dedicated how-to section for the Drawing Add-on.

   Is the AutoCAD command XYZ available?
       TLDR; Would you expect Photoshop features from a JPG library?

       The package is designed as an interface to the DXF format and  therefore  does  not  offer  any  advanced
       features  of  interactive  CAD  applications.  First,  some  tasks are difficult to perform without human
       guidance, and second, in complex situations, it’s not that easy to tell a “headless” system what  exactly
       to do, so it’s very likely that not many users would ever use these features, despite the fact that a lot
       of time and effort would have to be spent on development, testing and long-term support.

REFERENCE

       The DXF Reference is online available at Autodesk.

       Quoted from the original DXF 12 Reference which is not available on the web:
          Since  the  AutoCAD  drawing  database  (.dwg  file)  is  written  in  a  compact  format that changes
          significantly as new features are added to AutoCAD, we do not document its format and do not recommend
          that you attempt to write programs to read it directly. To assist in  interchanging  drawings  between
          AutoCAD  and  other  programs,  a  Drawing  Interchange  file  format  (DXF)  has  been  defined.  All
          implementations of AutoCAD accept this format and are able to convert it to and  from  their  internal
          drawing file representation.

   DXF Document
   Document Management
   Create New Drawings
       ezdxf.new(dxfversion='AC1027', setup=False, units=6) -> Drawing
              Create a new Drawing from scratch, dxfversion can be either “AC1009” the official DXF version name
              or “R12” the AutoCAD release name.

              new() can create drawings for following DXF versions:
                                                ┌─────────┬─────────────────┐
                                                │ Version │ AutoCAD Release │
                                                ├─────────┼─────────────────┤
                                                │ AC1009  │ AutoCAD R12     │
                                                ├─────────┼─────────────────┤
                                                │ AC1015  │ AutoCAD R2000   │
                                                ├─────────┼─────────────────┤
                                                │ AC1018  │ AutoCAD R2004   │
                                                ├─────────┼─────────────────┤
                                                │ AC1021  │ AutoCAD R2007   │
                                                ├─────────┼─────────────────┤
                                                │ AC1024  │ AutoCAD R2010   │
                                                ├─────────┼─────────────────┤
                                                │ AC1027  │ AutoCAD R2013   │
                                                ├─────────┼─────────────────┤
                                                │ AC1032  │ AutoCAD R2018   │
                                                └─────────┴─────────────────┘

              The units argument defines th document and modelspace units. The header variable $MEASUREMENT will
              be  set  according to the given units, 0 for inch, feet, miles, … and 1 for metric units. For more
              information go to module ezdxf.units

              Parametersdxfversion – DXF version specifier as string, default is “AC1027” respectively “R2013”

                     • setup –

                       setup default styles, False for no setup, True to setup everything or a list of topics as
                       strings, e.g. [“linetypes”, “styles”] to setup only some topics:
                                       ───────────────────────────────────────────────────────
                                       │ Topic        │ Description                          │
                                       ├──────────────┼──────────────────────────────────────┤
                                       │ linetypes    │ setup line types                     │
                                       ├──────────────┼──────────────────────────────────────┤
                                       │ styles       │ setup text styles                    │
                                       ├──────────────┼──────────────────────────────────────┤
                                       │ dimstyles    │ setup default ezdxf dimension styles │
                                       ├──────────────┼──────────────────────────────────────┤
                                       │ visualstyles │ setup 25 standard visual styles      │
                                       └──────────────┴──────────────────────────────────────┘

                     • units – document and modelspace units, default is 6 for meters

   Open Drawings
       Open DXF drawings from file system or text stream, byte stream usage is not supported.

       DXF files prior to R2007 requires file encoding defined by header variable $DWGCODEPAGE,  DXF  R2007  and
       later requires an UTF-8 encoding.

       ezdxf supports reading of files for following DXF versions:
                            ┌──────────┬─────────┬──────────────┬────────────────────────┐
                            │ Version  │ Release │ Encoding     │ Remarks                │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ < AC1009 │         │ $DWGCODEPAGE │ pre     AutoCAD    R12 │
                            │          │         │              │ upgraded to AC1009     │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1009   │ R12     │ $DWGCODEPAGE │ AutoCAD R12            │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1012   │ R13     │ $DWGCODEPAGE │ AutoCAD  R13  upgraded │
                            │          │         │              │ to AC1015              │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1014   │ R14     │ $DWGCODEPAGE │ AutoCAD  R14  upgraded │
                            │          │         │              │ to AC1015              │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1015   │ R2000   │ $DWGCODEPAGE │ AutoCAD R2000          │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1018   │ R2004   │ $DWGCODEPAGE │ AutoCAD R2004          │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1021   │ R2007   │ UTF-8        │ AutoCAD R2007          │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1024   │ R2010   │ UTF-8        │ AutoCAD R2010          │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1027   │ R2013   │ UTF-8        │ AutoCAD R2013          │
                            ├──────────┼─────────┼──────────────┼────────────────────────┤
                            │ AC1032   │ R2018   │ UTF-8        │ AutoCAD R2018          │
                            └──────────┴─────────┴──────────────┴────────────────────────┘

       ezdxf.readfile(filename: str | PathLike, encoding: str | None = None, errors: str = 'surrogateescape') ->
       Drawing
              Read the DXF document filename from the file-system.

              This is the preferred method to load existing  ASCII  or  Binary  DXF  files,  the  required  text
              encoding will be detected automatically and decoding errors will be ignored.

              Override  encoding  detection  by setting argument encoding to the estimated encoding. (use Python
              encoding names like in the open() function).

              If this function struggles to load the DXF document and raises a DXFStructureError exception,  try
              the ezdxf.recover.readfile() function to load this corrupt DXF document.

              Parametersfilename – filename of the ASCII- or Binary DXF document

                     • encoding  –  use None for auto detect (default), or set a specific encoding like “utf-8”,
                       argument is ignored for Binary DXF files

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesIOError – not a DXF file or file does not exist

                     • DXFStructureError – for invalid or corrupted DXF structures

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       ezdxf.read(stream: TextIO) -> Drawing
              Read a DXF document from a text-stream. Open stream in text mode (mode='rt') and set correct  text
              encoding, the stream requires at least a readline() method.

              Since  DXF  version  R2007  (AC1021)  file  encoding  is  always  “utf-8”, use the helper function
              dxf_stream_info() to detect the required  text  encoding  for  prior  DXF  versions.  To  preserve
              possible binary data in use errors='surrogateescape' as error handler for the import stream.

              If  this function struggles to load the DXF document and raises a DXFStructureError exception, try
              the ezdxf.recover.read() function to load this corrupt DXF document.

              Parameters
                     stream – input text stream opened with correct encoding

              Raises DXFStructureError – for invalid or corrupted DXF structures

       ezdxf.readzip(zipfile: str | PathLike, filename: str | None = None, errors: str = 'surrogateescape') ->
       Drawing
              Load a DXF document specified by filename from a zip archive, or if filename is None the first DXF
              document in the zip archive.

              Parameterszipfile – name of the zip archive

                     • filename – filename of DXF file, or None to load the first  DXF  document  from  the  zip
                       archive.

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesIOError – not a DXF file or file does not exist or
                           if filename is None - no DXF file found

                     • DXFStructureError – for invalid or corrupted DXF structures

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       ezdxf.decode_base64(data: bytes, errors: str = 'surrogateescape') -> Drawing
              Load a DXF document from base64 encoded binary data, like uploaded data to web applications.

              Parametersdata – DXF document base64 encoded binary data

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesDXFStructureError – for invalid or corrupted DXF structures

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       HINT:
          This  works  well  with DXF files from trusted sources like AutoCAD or BricsCAD, for loading DXF files
          with minor or major flaws look at the ezdxf.recover module.

   Save Drawings
       Save the DXF document to the file system by Drawing methods save() or saveas().  Write the  DXF  document
       to  a  text  stream with write(), the text stream requires at least a write() method. Get required output
       encoding for text streams by property Drawing.output_encoding

   Drawing Settings
       The HeaderSection stores meta data like modelspace extensions, user  name  or  saving  time  and  current
       application  settings,  like actual layer, text style or dimension style settings. These settings are not
       necessary to process DXF  data  and  therefore  many  of  this  settings  are  not  maintained  by  ezdxf
       automatically.

   Header variables set at new
                               ┌──────────────────┬───────────────────────────────────┐
                               │ $ACADVER         │ DXF version                       │
                               ├──────────────────┼───────────────────────────────────┤
                               │ $TDCREATE        │ date/time at creating the drawing │
                               ├──────────────────┼───────────────────────────────────┤
                               │ $FINGERPRINTGUID │ every drawing gets a GUID         │
                               └──────────────────┴───────────────────────────────────┘

   Header variables updated at saving
                                ┌──────────────┬─────────────────────────────────────┐
                                │ $TDUPDATE    │ actual date/time at saving          │
                                ├──────────────┼─────────────────────────────────────┤
                                │ $HANDSEED    │ next available handle as hex string │
                                ├──────────────┼─────────────────────────────────────┤
                                │ $DWGCODEPAGE │ encoding setting                    │
                                ├──────────────┼─────────────────────────────────────┤
                                │ $VERSIONGUID │ every saved version gets a new GUID │
                                └──────────────┴─────────────────────────────────────┘

       SEE ALSO:

          • Howto: Set/Get Header Variables

          • Howto: Set DXF Drawing Units

   Ezdxf Metadata
       Store  internal  metadata  like ezdxf version and creation time for a new created document as metadata in
       the DXF file. Only standard DXF features are used to store meta data and this meta data is  preserved  by
       Autodesk products, BricsCAD and of course ezdxf. Other 3rd party DXF libraries may remove this meta data.

       For DXF R12 the meta data is stored as XDATA by AppID EZDXF in the model space BLOCK entity in the BLOCKS
       section.

       For  DXF  R2000+  the meta data is stored in the “root” DICTIONARY in the OBJECTS section as a DICTIONARY
       object by the key EZDXF_META.

       The MetaData object has a dict-like interface and can also store custom metadata:

          metadata = doc.ezdxf_metadata()

          # set data
          metadata["MY_CUSTOM_META_DATA"] = "a string with max. length of 254"

          # get data, raises a KeyError() if key not exist
          value = metadata["MY_CUSTOM_META_DATA"]

          # get data, returns an empty string if key not exist
          value = metadata.get("MY_CUSTOM_META_DATA")

          # delete entry, raises a KeyError() if key not exist
          del metadata["MY_CUSTOM_META_DATA"]

          # discard entry, does not raise a KeyError() if key not exist
          metadata.discard("MY_CUSTOM_META_DATA")

       Keys and values are limited to strings with a max. length of 254 characters and line ending  \n  will  be
       replaced by \P.

       Keys used by ezdxf:

          • WRITTEN_BY_EZDXF: ezdxf version and UTC time in ISO format

          • CREATED_BY_EZDXF: ezdxf version and UTC time in ISO format

       Example of the ezdxf marker string: 0.16.4b1 @ 2021-06-12T07:35:34.898808+00:00

       class ezdxf.document.MetaData

              abstract MetaData.__contains__(key: str) -> bool
                     Returns key in self.

              abstract MetaData.__getitem__(key: str) -> str
                     Returns the value for self[key].

                     Raises KeyErrorkey does not exist

              MetaData.get(key: str, default: str = '') -> str
                     Returns the value for key. Returns default if key not exist.

              abstract MetaData.__setitem__(key: str, value: str) -> None
                     Set self[key] to value.

              abstract MetaData.__delitem__(key: str) -> None
                     Delete self[key].

                     Raises KeyErrorkey does not exist

              MetaData.discard(key: str) -> None
                     Remove key, does not raise an exception if key not exist.

   Drawing Class
       The Drawing class is the central management structure of a DXF document.

   Access LayoutsDrawing.modelspace()Drawing.paperspace()

   Access Resources
       • Application ID Table: Drawing.appids

       • Block Definition Table: Drawing.blocks

       • Dimension Style Table: Drawing.dimstyles

       • Layer Table: Drawing.layers

       • Linetype Table: Drawing.linetypes

       • MLeader Style Table: Drawing.mleader_styles

       • MLine Style Table: Drawing.mline_styles

       • Material Table: Drawing.materials

       • Text Style Table: Drawing.styles

       • UCS Table: Drawing.ucs

       • VPort Table: Drawing.viewports

       • View Table: Drawing.views

       • Classes Section: Drawing.classes

       • Object Section: Drawing.objects

       • Entity Database: Drawing.entitydb

       • Entity Groups: Drawing.groups

       • Header Variables: Drawing.header

   Drawing Class
       class ezdxf.document.Drawing
              The Drawing class is the central management structure of a DXF document.

              dxfversion
                     Actual DXF version like 'AC1009', set by ezdxf.new() or ezdxf.readfile().

                     For supported DXF versions see Document Management

              acad_release
                     The AutoCAD release name like 'R12' or 'R2000' for actual dxfversion.

              encoding
                     Text  encoding of Drawing, the default encoding for new drawings is 'cp1252'. Starting with
                     DXF R2007 (AC1021), DXF files are written as UTF-8 encoded text files,  regardless  of  the
                     attribute encoding.  The text encoding can be changed to encodings listed below.

                     see also: DXF File Encoding
                                                   ┌───────────┬────────────────┐
                                                   │ supported │ encodings      │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp874'   │ Thai           │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp932'   │ Japanese       │
                                                   ├───────────┼────────────────┤
                                                   │ 'gbk'     │ UnifiedChinese │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp949'   │ Korean         │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp950'   │ TradChinese    │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1250'  │ CentralEurope  │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1251'  │ Cyrillic       │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1252'  │ WesternEurope  │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1253'  │ Greek          │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1254'  │ Turkish        │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1255'  │ Hebrew         │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1256'  │ Arabic         │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1257'  │ Baltic         │
                                                   ├───────────┼────────────────┤
                                                   │ 'cp1258'  │ Vietnam        │
                                                   └───────────┴────────────────┘

              output_encoding
                     Returns required output encoding for saving to filesystem or encoding to binary data.

              filename
                     Drawing filename, if loaded by ezdxf.readfile() else None.

              rootdict
                     Reference to the root dictionary of the OBJECTS section.

              header Reference to the HeaderSection, get/set drawing settings as header variables.

              entities
                     Reference to the EntitySection of the drawing, where all graphical entities are stored, but
                     only  from modelspace and the active paperspace layout. Just for your information: Entities
                     of other paperspace layouts are stored as BlockLayout in the BlocksSection.

              objects
                     Reference to the objects section, see also ObjectsSection.

              blocks Reference to the blocks section, see also BlocksSection.

              tables Reference to the tables section, see also TablesSection.

              classes
                     Reference to the classes section, see also ClassesSection.

              layouts
                     Reference to the layout manager, see also Layouts.

              groups Collection of all groups, see also GroupCollection.

                     requires DXF R13 or later

              layers Shortcut for Drawing.tables.layers

                     Reference to the layers table, where you can create, get and remove layers, see also  Table
                     and Layer

              styles Shortcut for Drawing.tables.styles

                     Reference to the styles table, see also Textstyle.

              dimstyles
                     Shortcut for Drawing.tables.dimstyles

                     Reference to the dimstyles table, see also DimStyle.

              linetypes
                     Shortcut for Drawing.tables.linetypes

                     Reference to the linetypes table, see also Linetype.

              views  Shortcut for Drawing.tables.views

                     Reference to the views table, see also View.

              viewports
                     Shortcut for Drawing.tables.viewports

                     Reference to the viewports table, see also VPort.

              ucs    Shortcut for Drawing.tables.ucs

                     Reference to the ucs table, see also UCSTableEntry.

              appids Shortcut for Drawing.tables.appids

                     Reference to the appids table, see also AppID.

              materials
                     MaterialCollection of all Material objects.

              mline_styles
                     MLineStyleCollection of all MLineStyle objects.

              mleader_styles
                     MLeaderStyleCollection of all MLeaderStyle objects.

              units  Get and set the document/modelspace base units as enum, for more information read this: DXF
                     Units.

              get_abs_filepath = <function Drawing.get_abs_filepath>

              save(encoding: str | None = None, fmt: str = 'asc') -> None
                     Write  drawing  to  file-system  by using the filename attribute as filename. Override file
                     encoding by argument encoding, handle with care, but this option allows you to  create  DXF
                     files for applications that handle file encoding different from AutoCAD.

                     Parametersencoding – override default encoding as Python encoding string like 'utf-8'fmt'asc' for ASCII DXF (default) or 'bin' for Binary DXF

              saveas(filename: PathLike | str, encoding: str | None = None, fmt: str = 'asc') -> None
                     Set  Drawing  attribute filename to filename and write drawing to the file system. Override
                     file encoding by argument encoding, handle with care, but this option allows you to  create
                     DXF files for applications that handles file encoding different than AutoCAD.

                     Parametersfilename – file name as string

                            • encoding – override default encoding as Python encoding string like 'utf-8'fmt'asc' for ASCII DXF (default) or 'bin' for Binary DXF

              write(stream: TextIO | BinaryIO, fmt: str = 'asc') -> None
                     Write  drawing  as  ASCII DXF to a text stream or as Binary DXF to a binary stream. For DXF
                     R2004 (AC1018) and prior open stream with drawing encoding and  mode='wt'.  For  DXF  R2007
                     (AC1021)  and  later  use  encoding='utf-8', or better use the later added Drawing property
                     output_encoding which returns the correct encoding automatically. The correct and  required
                     error handler is errors='dxfreplace'!

                     If  writing  to  a  StringIO  stream, use Drawing.encode() to encode the result string from
                     StringIO.get_value():

                        binary = doc.encode(stream.get_value())

                     Parametersstream – output text stream or binary stream

                            • fmt – “asc” for ASCII DXF (default) or “bin” for binary DXF

              encode_base64() -> bytes
                     Returns DXF document as base64 encoded binary data.

              encode(s: str) -> bytes
                     Encode string s with correct encoding and error handler.

              query(query: str = '*') -> EntityQuery
                     Entity query over all layouts and blocks, excluding the OBJECTS section  and  the  resource
                     tables of the TABLES section.

                     Parameters
                            query – query string

                     SEE ALSO:
                        Entity Query String and Retrieve entities by query language

              groupby(dxfattrib='', key=None) -> dict
                     Groups  DXF  entities  of  all  layouts and blocks (excluding the OBJECTS section) by a DXF
                     attribute or a key function.

                     Parametersdxfattrib – grouping DXF attribute like “layer”

                            • key – key function, which accepts a DXFEntity as argument and returns  a  hashable
                              grouping key or None to ignore this entity.

                     SEE ALSO:
                        groupby() documentation

              modelspace() -> Modelspace
                     Returns  the  modelspace  layout,  displayed as “Model” tab in CAD applications, defined by
                     block record named “*Model_Space”.

              paperspace(name: str = '') -> Paperspace
                     Returns paperspace layout name or the active paperspace if no name is given.

                     Parameters
                            name – paperspace name or empty string for the active paperspace

                     Raises KeyError – if the modelspace was acquired or layout name does not exist

              layout(name: str = '') -> Layout
                     Returns paperspace layout name or the first layout in tab-order if no name is given.

                     Parameters
                            name – paperspace name or empty string for the first paperspace in tab-order

                     Raises KeyError – layout name does not exist

              active_layout() -> Paperspace
                     Returns the active paperspace layout, defined by block record name “*Paper_Space”.

              layout_names() -> Iterable[str]
                     Returns all layout names in arbitrary order.

              layout_names_in_taborder() -> Iterable[str]
                     Returns all layout names in tab-order, “Model” is always the first name.

              new_layout(name, dxfattribs=None) -> Paperspace
                     Create a new paperspace layout name. Returns a Paperspace object. DXF R12 (AC1009) supports
                     only one paperspace layout, only the active paperspace layout is saved, other  layouts  are
                     dismissed.

                     Parametersname – unique layout name

                            • dxfattribs – additional DXF attributes for the DXFLayout entity

                     Raises DXFValueError – paperspace layout name already exist

              page_setup(name: str = 'Layout1', fmt: str = 'ISO A3', landscape=True) -> Paperspace
                     Creates  a new paperspace layout if name does not exist or reset the existing layout.  This
                     method requires DXF R2000 or newer.  The paper format name fmt defines one of the following
                     paper sizes, measures in landscape orientation:
                                                ┌─────────┬───────┬───────┬────────┐
                                                │ Name    │ Units │ Width │ Height │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ISO A0  │ mm    │ 1189  │ 841    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ISO A1  │ mm    │ 841   │ 594    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ISO A2  │ mm    │ 594   │ 420    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ISO A3  │ mm    │ 420   │ 297    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ISO A4  │ mm    │ 297   │ 210    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ANSI A  │ inch  │ 11    │ 8.5    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ANSI B  │ inch  │ 17    │ 11     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ANSI C  │ inch  │ 22    │ 17     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ANSI D  │ inch  │ 34    │ 22     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ANSI E  │ inch  │ 44    │ 34     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ARCH C  │ inch  │ 24    │ 18     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ARCH D  │ inch  │ 36    │ 24     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ARCH E  │ inch  │ 48    │ 36     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ ARCH E1 │ inch  │ 42    │ 30     │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ Letter  │ inch  │ 11    │ 8.5    │
                                                ├─────────┼───────┼───────┼────────┤
                                                │ Legal   │ inch  │ 14    │ 8.5    │
                                                └─────────┴───────┴───────┴────────┘

                     The layout uses the associated units of the paper format as drawing units, has  no  margins
                     or offset defined and the scale of the paperspace layout is 1:1.

                     Parametersname – paperspace layout name

                            • fmt – paper format

                            • landscapeTrue for landscape orientation, False for portrait orientation

              delete_layout(name: str) -> None
                     Delete  paper  space layout name and all entities owned by this layout.  Available only for
                     DXF R2000 or later, DXF R12 supports only one paperspace, and it can’t be deleted.

              add_image_def(filename: str, size_in_pixel: tuple[int, int], name=None)
                     Add an image definition to the objects section.

                     Add an ImageDef entity to the drawing (objects section). filename is the image file name as
                     relative or absolute path and size_in_pixel is the image size in pixel as (x, y) tuple.  To
                     avoid  dependencies to external packages, ezdxf can not determine the image size by itself.
                     Returns a ImageDef entity which is needed  to  create  an  image  reference.  name  is  the
                     internal image name, if set to None, name is auto-generated.

                     Absolute  image  paths  works best for AutoCAD but not perfect, you have to update external
                     references manually in AutoCAD, which is not possible in TrueView.  If  the  drawing  units
                     differ from 1 meter, you also have to use: set_raster_variables().

                     Parametersfilename – image file name (absolute path works best for AutoCAD)

                            • size_in_pixel – image size in pixel as (x, y) tuple

                            • name  –  image  name  for  internal use, None for using filename as name (best for
                              AutoCAD)

                     SEE ALSO:
                        Tutorial for Image and ImageDef

              set_raster_variables(frame: int = 0, quality: int = 1, units: str = 'm')
                     Set raster variables.

                     Parametersframe – 0 = do not show image frame; 1 = show image frame

                            • quality – 0 = draft; 1 = high

                            • units –

                              units for inserting images. This defines the real world unit for one drawing  unit
                              for the purpose of inserting and scaling images with an associated resolution.
                                                       ──────────────────────────────
                                                         mm   Millimeter
                                                       ──────────────────────────────
                                                         cm   Centimeter
                                                       ──────────────────────────────
                                                         m    Meter (ezdxf default)
                                                       ──────────────────────────────
                                                         km   Kilometer
                                                       ──────────────────────────────
                                                         in   Inch
                                                       ──────────────────────────────
                                                         ft   Foot
                                                       ──────────────────────────────
                                                         yd   Yard
                                                       ──────────────────────────────
                                                         mi   Mile
                                                       ┌────┬───────────────────────┐
                                                       │    │                       │
                                                       │    │                       │
              set_wipeout_variables(frame=0)           │    │                       │
                     Set wipeout variables.            │    │                       │
                                                       │    │                       │
                     Parameters                        │    │                       │
--

LAUNCHER

       The command line script ezdxf launches various sub-commands:
                               ┌─────────────┬───────────────────────────────────────┐
                               │ pp          │ DXF pretty printer,  replacement  for │
                               │             │ the previous dxfpp command            │
                               ├─────────────┼───────────────────────────────────────┤
                               │ audit       │ Audit and repair DXF files            │
                               ├─────────────┼───────────────────────────────────────┤
                               │ draw        │ Draw  and  convert  DXF  files by the │
                               │             │ Matplotlib backend                    │
                               ├─────────────┼───────────────────────────────────────┤
                               │ view        │ PyQt DXF file viewer                  │
                               ├─────────────┼───────────────────────────────────────┤
                               │ browse      │ PyQt DXF structure  browser  for  DXF │
                               │             │ debugging and curious people          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ browse-acis │ PyQt  ACIS entity content browser for │
                               │             │ SAT/SAB debugging                     │
                               ├─────────────┼───────────────────────────────────────┤
                               │ strip       │ Strip  comments  and   THUMBNAILIMAGE │
                               │             │ section from DXF files                │
                               ├─────────────┼───────────────────────────────────────┤
                               │ config      │ Manage config files                   │
                               ├─────────────┼───────────────────────────────────────┤
                               │ info        │ Show  information  and optional stats │
                               │             │ of DXF files as loaded by ezdxf       │
                               ├─────────────┼───────────────────────────────────────┤
                               │ hpgl        │ View and/or convert HPGL/2 plot files │
                               │             │ to DXF, SVG or PDF                    │
                               └─────────────┴───────────────────────────────────────┘

       The help option -h is supported by the main script and all sub-commands:

          C:\> ezdxf -h
          usage: ezdxf [-h] [-V] [-v] [--config CONFIG] [--log LOG]
                       {pp,audit,draw,view,browse,browse-acis,strip,config} ...

          Command launcher for the Python package "ezdxf":
          https://pypi.org/project/ezdxf/

          positional arguments:
            {pp,audit,draw,view,browse,strip}
              pp                  pretty print DXF files as HTML file
              audit               audit and repair DXF files
              draw                draw and convert DXF files by Matplotlib
              view                view DXF files by the PyQt viewer
              browse              browse DXF file structure
              browse-acis         browse ACIS structures in DXF files
              strip               strip comments from DXF files
              config              manage config files
              info                show information and optional stats of DXF files loaded by ezdxf,
                                  this may not represent the original content of the file, use the
                                  browse command to see the original content

          optional arguments:
            -h, --help            show this help message and exit
            -V, --version         show version and exit
            -f, --fonts           rebuild system font cache and print all fonts found
            -v, --verbose         give more output
            --config CONFIG       path to a config file
            --log LOG             path to a verbose appending log

       NOTE:
          The ezdxf script  is the only executable script installed on the user system.

   System
       ezdxf -V shows the ezdxf and Python version your are running and if the C-extensions are used.

          ezdxf 1.1.0b1 from c:\source\ezdxf.git\src\ezdxf
          Python version: 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
          using C-extensions: yes

       ezdxf -f rebuilds the system font cache and shows all fonts found.

   Pretty Printer
       Pretty print the DXF text content as HTML file and open the file in the default web browser:

          C:\> ezdxf pp -o gear.dxf
       [image]

       Print help:

          C:\> ezdxf pp -h
          usage: ezdxf pp [-h] [-o] [-r] [-x] [-l] [-s SECTIONS] FILE [FILE ...]

          positional arguments:
            FILE                  DXF files pretty print

          optional arguments:
            -h, --help            show this help message and exit
            -o, --open            open generated HTML file by the default web browser
            -r, --raw             raw mode, no DXF structure interpretation
            -x, --nocompile       don't compile points coordinates into single tags (only in raw mode)
            -l, --legacy          legacy mode, reorder DXF point coordinates
            -s SECTIONS, --sections SECTIONS
                                  choose sections to include and their order, h=HEADER, c=CLASSES,
                                  t=TABLES, b=BLOCKS, e=ENTITIES, o=OBJECTS

   Audit
       Audit and recover the DXF file “gear.dxf” and save the recovered version as “gear.rec.dxf”:

          C:\> ezdxf audit -s gear.dxf

          auditing file: gear.dxf
          No errors found.
          Saved recovered file as: gear.rec.dxf

       Print help:

          C:\> ezdxf audit -h
          usage: ezdxf audit [-h] [-s] FILE [FILE ...]

          positional arguments:
            FILE        audit DXF files

          optional arguments:
            -h, --help  show this help message and exit
            -s, --save  save recovered files with extension ".rec.dxf"

   Draw
       Convert the DXF file “gear.dxf” into a SVG file by the Matplotlib backend:

          C:\> ezdxf draw -o gear.svg gear.dxf

       The “gear.svg” created by the Matplotlib backend: [image]

       Show all output formats supported by the Matplotlib backend on your system. This output may vary:

          C:\> ezdxf draw --formats
          eps: Encapsulated Postscript
          jpg: Joint Photographic Experts Group
          jpeg: Joint Photographic Experts Group
          pdf: Portable Document Format
          pgf: PGF code for LaTeX
          png: Portable Network Graphics
          ps: Postscript
          raw: Raw RGBA bitmap
          rgba: Raw RGBA bitmap
          svg: Scalable Vector Graphics
          svgz: Scalable Vector Graphics
          tif: Tagged Image File Format
          tiff: Tagged Image File Format

       Print help:

          C:\> ezdxf draw -h
          usage: ezdxf draw [-h] [--formats] [-l LAYOUT] [--all-layers-visible]
                            [--all-entities-visible] [-o OUT] [--dpi DPI] [-v]
                            [FILE]

          positional arguments:
            FILE                  DXF file to view or convert

          optional arguments:
            -h, --help            show this help message and exit
            --formats             show all supported export formats and exit
            -l LAYOUT, --layout LAYOUT
                                  select the layout to draw, default is "Model"
            --all-layers-visible  draw all layers including the ones marked as invisible
            --all-entities-visible
                                  draw all entities including the ones marked as
                                  invisible (some entities are individually marked as
                                  invisible even if the layer is visible)
            -o OUT, --out OUT     output filename for export
            --dpi DPI             target render resolution, default is 300
            -v, --verbose         give more output

   View
       View the DXF file “gear.dxf” by the PyQt backend:

          C:\> ezdxf view gear.dxf
       [image]

       Print help:

          C:\> ezdxf view -h
          usage: ezdxf view [-h] [-l LAYOUT] [--lwscale LWSCALE] [FILE]

          positional arguments:
            FILE                  DXF file to view

          optional arguments:
            -h, --help            show this help message and exit
            -l LAYOUT, --layout LAYOUT
                                  select the layout to draw, default is "Model"
            --lwscale LWSCALE     set custom line weight scaling, default is 0 to
                                  disable line weights at all

   Browse
       Browse the internal structure of a DXF file like a file system:

          C:\> ezdxf browse gear.dxf
       [image]

          C:\> ezdxf browse -h
          usage: ezdxf browse [-h] [-l LINE] [-g HANDLE] [FILE]

          positional arguments:
            FILE                  DXF file to browse

          optional arguments:
            -h, --help            show this help message and exit
            -l LINE, --line LINE  go to line number
            -g HANDLE, --handle HANDLE
                                  go to entity by HANDLE, HANDLE has to be a hex value without
                                  any prefix like 'fefe'

       The browse command stores options in the config file, e.g. for the Notepad++ on Windows:

          [browse-command]

          text_editor = "C:\Program Files\Notepad++\notepad++.exe" "{filename}" -n{num}
          icon_size = 32

       text_editor is a simple format string: text_editor.format(filename="test.dxf", num=100)

       Quote commands including spaces and always quote the filename argument!

       For xed on Linux Mint use (note: absolute path to executable):

          [browse-command]

          text_editor = /usr/bin/xed "{filename}" +{num}
          icon_size = 32

       For gedit on Linux use (untested):

          [browse-command]

          text_editor = /usr/bin/gedit +{num} "{filename}"
          icon_size = 32

       The browse command opens a DXF structure browser to investigate the  internals  of  a  DXF  file  without
       interpreting  the  content. The functionality of the DXF browser is similar to the DXF Pretty Printer (pp
       command), but without the disadvantage of creating giant HTML files.  The  intended  usage  is  debugging
       invalid  DXF  files,  which  can  not  be  loaded by the ezdxf.readfile() or the ezdxf.recover.readfile()
       functions.

   Line Numbers
       The low level tag loader ignores DXF comments (group code 999). If there are comments in the DXF file the
       line numbers displayed in the DXF browser are not synchronized,  use  the  strip  command  beforehand  to
       remove all comments from the DXF file in order to keep the line numbers synchronized.

   GUI Features
       The  tree  view  on the left shows the outline of the DXF file. The number in round brackets on the right
       side of each item shows the count of structure entities within the structure layer, the  value  in  angle
       brackets on the left side is the entity handle.

       The right list view shows the entity content as DXF tags.  Structure tags (data type <ctrl>) are shown in
       blue,  a  double  click  on a reference handle (datatype <ref>) jumps to the referenced entity, reference
       handles of non-existent targets are shown in red.

       Clicking on the first structure tag in the list opens the DXF  reference  provided  by  Autodesk  in  the
       standard web browser.

   Auto Reload
       The  browser  automatically  displays  a  dialog for reloading DXF files if they have been modified by an
       external application.

   Menus and ShortcutsFile MenuOpen DXF file… Ctrl+OReload DXF file Ctrl+ROpen in Text Editor Ctrl+T, open the DXF file in the associated text  editor  at  the  current
                  location

                • Export DXF Entity… Ctrl+E, export the current DXF entity shown in the list view as text file

                • Copy  selected  DXF  Tags  to  Clipboard  Ctrl+C,  copy the current selected DXF tags into the
                  clipboard

                • Copy DXF Entity to Clipboard Ctrl+Shift+C, copy all DXF tags of the current DXF  entity  shown
                  in the list view into the clipboard

                • Quit Ctrl+QNavigate MenuGo to Handle… Ctrl+GGo to Line… Ctrl+LFind Text… Ctrl+F, opens the find text dialog

                • Next Entity Ctrl+Right, go to the next entity in the DXF structure

                • Previous Entity Ctrl+Right, go to the previous entity in the DXF structure

                • Show Entity in TreeView Ctrl+Down, expand the left tree view to the currently displayed entity
                  in the list view - this does not happen automatically for performance reasons

                • Entity History Back Alt+LeftEntity History Forward Alt+RightGo to HEADERS Section Shift+HGo to BLOCKS Section Shift+BGo to ENTITIES Section Shift+EGo to OBJECTS Section Shift+OBookmarks MenuStore Bookmark… Ctrl+Shift+B, store current location as named bookmark

                • Go to Bookmark… Ctrl+B, go to stored location

   Browse-ACIS
       Show and export the SAT or SAB content of ACIS entities:

          C:\> ezdxf browse-acis 3dsolid.dxf
       [image]

       The  DXF  format  stores  modern solid geometry as SAT data for DXF R2000 - R2010 and as SAB data for DXF
       R2013 and later. This command shows the content of this entities and also let you export the raw data for
       further processing.

   Entity View
       The entity view is a read-only text editor, it’s possible to select and copy parts of the text  into  the
       clipboard.   To  improve  the  readability  all ACIS entities get automatically an id because AutoCAD and
       BricsCAD use relative references for ACIS data export and do not assign entity ids.  The id is  shown  as
       decimal number in parenthesis after the entity name. The ~ character is a shortcut for a null-pointer.

          C:\>ezdxf browse-acis -h
          usage: ezdxf browse-acis [-h] [-g HANDLE] [FILE]

          positional arguments:
            FILE                  DXF file to browse

          options:
            -h, --help            show this help message and exit
            -g HANDLE, --handle HANDLE
                                  go to entity by HANDLE, HANDLE has to be a hex value
                                  without any prefix like 'fefe'

   Menus and ShortcutsFile MenuOpen DXF file… Ctrl+OReload DXF file Ctrl+RExport Current Entity View… Ctrl+E, Export the parsed content of the entity view as text file

                • Export  Raw SAT/SAB Data… Ctrl+W, export the raw SAT data as text file and the raw SAB data as
                  a binary file for further processing

                • Quit Ctrl+Q

   Strip
       Strip comment tags (group code 999) from ASCII DXF files  and  can  remove  the  THUMBNAILIMAGE  section.
       Binary DXF files are not supported.

          C:\> ezdxf strip -h
          usage: ezdxf strip [-h] [-b] [-v] FILE [FILE ...]

          positional arguments:
            FILE           DXF file to process, wildcards "*" and "?" are supported

          optional arguments:
            -h, --help       show this help message and exit
            -b, --backup     make a backup copy with extension ".bak" from the DXF file,
                             overwrites existing backup files
            -t, --thumbnail  strip THUMBNAILIMAGE section
            -v, --verbose    give more output

   Config
       Manage config files.

          C:\> ezdxf config -h
          usage: ezdxf config [-h] [-p] [-w FILE] [--home] [--reset]

          optional arguments:
            -h, --help   show this help message and exit
            -p, --print  print configuration
            -w FILE, --write FILE
                         write configuration
            --home       create config file 'ezdxf.ini' in the user home directory
                         '~/.config/ezdxf', $XDG_CONFIG_HOME is supported if set

            --reset      factory reset, delete default config files 'ezdxf.ini'

   Info
       Show  information and optional stats of DXF files as loaded by ezdxf, this may not represent the original
       content of the file, use the browse command to see the original content. The  upgrade  is  necessary  for
       very  old  DXF versions prior to R12 and for the “special” versions R13 and R14. The -s option shows some
       statistics about the DXF content like entity count or table  count.  Use  the  -v  option  show  more  of
       everything.

          C:\> ezdxf info -h
          usage: ezdxf info [-h] [-v] [-s] FILE [FILE ...]

          positional arguments:
            FILE           DXF file to process, wildcards "*" and "?" are supported

          options:
            -h, --help     show this help message and exit
            -v, --verbose  give more output
            -s, --stats    show content stats

       This  is  the  verbose  output  for  an  old DXF R10 file and shows that the loading process created some
       required structures which do not exist in DXF R10 files, like  the  BLOCK_RECORD  table  or  the  OBJECTS
       section:

          C:\> ezdxf info -v -s test_R10.dxf

          Filename: "test_R10.dxf"
          Loaded content was upgraded from DXF Version AC1006 (R10)
          Release: R12
          DXF Version: AC1009
          Maintenance Version: <undefined>
          Codepage: ANSI_1252
          Encoding: cp1252
          Unit system: Imperial
          Modelspace units: Unitless
          $LASTSAVEDBY: <undefined>
          $HANDSEED: 0
          $FINGERPRINTGUID: {9EADDC7C-5982-4C68-B770-8A62378C2B90}
          $VERSIONGUID: {49336E63-D99B-45EC-803C-4D2BD03A7DE0}
          $USERI1=0
          $USERI2=0
          $USERI3=0
          $USERI4=0
          $USERI5=0
          $USERR1=0.0
          $USERR2=0.0
          $USERR3=0.0
          $USERR4=0.0
          $USERR5=0.0
          File was not created by ezdxf >= 0.16.4
          File was not written by ezdxf >= 0.16.4
          Content stats:
          LAYER table entries: 18
            0
            Defpoints
            LYR_00
            LYR_01
            LYR_02
            LYR_03
            LYR_04
            LYR_05
            LYR_06
            LYR_07
            LYR_08
            LYR_09
            LYR_10
            LYR_11
            LYR_12
            LYR_13
            LYR_14
            LYR_15
          LTYPE table entries: 13
            BORDER
            ByBlock
            ByLayer
            CENTER
            CONTINUOUS
            CUTTING
            DASHDOT
            DASHED
            DIVIDE
            DOT
            HIDDEN
            PHANTOM
            STITCH
          STYLE table entries: 1
            STANDARD
          DIMSTYLE table entries: 1
            Standard
          APPID table entries: 1
            ACAD
          UCS table entries: 0
          VIEW table entries: 0
          VPORT table entries: 1
            *Active
          BLOCK_RECORD table entries: 2
            *Model_Space
            *Paper_Space
          Entities in modelspace: 78
            ARC (2)
            CIRCLE (2)
            LINE (74)
          Entities in OBJECTS section: 20
            ACDBDICTIONARYWDFLT (1)
            ACDBPLACEHOLDER (1)
            DICTIONARY (11)
            LAYOUT (2)
            MATERIAL (3)
            MLEADERSTYLE (1)
            MLINESTYLE (1)

   Show Version & Configuration
       Show the ezdxf version and configuration:

          C:\> ezdxf -Vv

          ezdxf v0.16.5b0 @ d:\source\ezdxf.git\src\ezdxf
          Python version: 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)]
          using C-extensions: yes
          using Matplotlib: yes

          Configuration:
          [core]
          default_dimension_text_style = OpenSansCondensed-Light
          test_files = D:\Source\dxftest
          font_cache_directory =
          load_proxy_graphics = true
          store_proxy_graphics = true
          log_unprocessed_tags = false
          filter_invalid_xdata_group_codes = true
          write_fixed_meta_data_for_testing = false
          disable_c_ext = false

          [browse-command]
          text_editor = "C:\Program Files\Notepad++\notepad++.exe" "{filename}" -n{num}

          Environment Variables:
          EZDXF_DISABLE_C_EXT=
          EZDXF_TEST_FILES=D:\Source\dxftest
          EZDXF_CONFIG_FILE=

          Existing Configuration Files:
          C:\Users\manfred\.config\ezdxf\ezdxf.ini

       SEE ALSO:
          Documentation of the ezdxf.options module and the Environment Variables.

   HPGL/2 Viewer/Converter
       New in version 1.1.

       The hpgl command shows and/or converts HPGL/2 plot files to DXF, SVG or PDF.

   DXF
       The  page  content  is created at the origin of the modelspace and 1 drawing unit is 1 plot unit (1 plu =
       0.025mm) unless scaling values are provided.

       The content of HPGL files is intended to be  plotted  on  white  paper,  so  the  appearance  on  a  dark
       background  in  modelspace  is  not  very  clear. To fix this, the --map_black_to_white option maps black
       fillings and lines to white.

       All entities are mapped to a layer named  COLOR_<#> according to the pen number.  In order to process the
       content better, it is also possible to assign the DXF elements an ACI color value according  to  the  pen
       number  through  the  --aci  option,  but then the RGB color is lost because the RGB color always has the
       higher priority over the ACI value.

       The first paperspace layout “Layout0” is set up to print the entire modelspace on one sheet, the size  of
       the page is the size of the original plot file in millimeters.

   SVG
       The  plot  units  are  mapped 1:1 to viewBox units and the size of image is the size of the original plot
       file in millimeters.

   PDF
       The plot units are converted to PDF units (1/72 inch) so the size of image is the size  of  the  original
       plot file in millimeters.

   All Formats
       HPGL/2’s  merge control works at the pixel level and cannot be replicated by DXF, but to prevent fillings
       from obscuring text, the filled polygons are sorted by luminance - this can be forced or disabled by  the
       --merge_control option.

       Some  plot  files  that  contain pure HPGL/2 code do not contain the escape sequence “Enter HPGL/2 mode”,
       without this sequence the HPGL/2 parser cannot recognize the beginning of the HPGL/2  code.  The  --force
       option  inserts  the  “Enter HPGL/2 mode” escape sequence into the data stream, regardless of whether the
       file is an HPGL/2 plot file or not, so be careful.

          C:\> ezdxf hpgl -h
          usage: ezdxf hpgl [-h] [-e FORMAT] [-r {0,90,180,270}] [-x SX] [-y SY] [-m {0,1,2}]
                            [-f] [--aci] [--map_black_to_white]
                            [FILE]

          positional arguments:
            FILE                  view and/or convert HPGL/2 plot files, wildcards (*, ?)
                                  supported in command line mode

          options:
            -h, --help            show this help message and exit
            -e FORMAT, --export FORMAT
                                  convert HPGL/2 plot file to SVG, PDF or DXF from the
                                  command line (no gui)
            -r {0,90,180,270}, --rotate {0,90,180,270}
                                  rotate page about 90, 180 or 270 degrees (no gui)
            -x SX, --scale_x SX   scale page in x-axis direction, use negative values to
                                  mirror page, (no gui)
            -y SY, --scale_y SY   scale page in y-axis direction, use negative values to
                                  mirror page (no gui)
            -m {0,1,2}, --merge_control {0,1,2}
                                  provides control over the order of filled polygons, 0=off
                                  (print order), 1=luminance (order by luminance), 2=auto
                                  (default)
            -f, --force           inserts the mandatory 'enter HPGL/2 mode' escape sequence
                                  into the data stream; use this flag when no HPGL/2 data was
                                  found and you are sure the file is a HPGL/2 plot file
            --aci                 use pen numbers as ACI colors (DXF only)
            --map_black_to_white  map black RGB plot colors to white RGB, does not affect ACI
                                  colors (DXF only)

          Note that plot files are intended to be plotted on white paper.

RENDERING

       The ezdxf.render subpackage provides helpful utilities to create complex forms.

       • create complex meshes as Mesh entity.

       • render complex curves like bezier curves, euler spirals or splines as Polyline entity

       • vertex generators for simple and complex forms like circle, ellipse or euler spiral

       Content

   Spline
       class ezdxf.render.Spline(points: Iterable[UVec] | None = None, segments: int = 100)
              This class can be used to render B-splines into DXF R12 files as approximated  Polyline  entities.
              The advantage of this class over the R12Spline class is, that this is a real 3D curve, which means
              that  the  B-spline  vertices do have to be located in a flat plane, and no UCS class is needed to
              place the curve in 3D space.

              SEE ALSO:
                 The newer BSpline class provides the advanced vertex interpolation method flattening().

              __init__(points: Iterable[UVec] | None = None, segments: int = 100)

                     Parameterspoints – spline definition points

                            • segments – count of line segments for approximation, vertex count is segments + 1

              subdivide(segments: int = 4) -> None
                     Calculate overall segment count, where segments is the sub-segment  count,  segments  =  4,
                     means 4 line segments between two definition points e.g. 4 definition points and 4 segments
                     = 12 overall segments, useful for fit point rendering.

                     Parameters
                            segments – sub-segments count between two definition points

              render_as_fit_points(layout: BaseLayout, degree: int = 3, method: str = 'chord', dxfattribs: dict
              | None = None) -> None
                     Render a B-spline as 2D/3D Polyline, where the definition points are fit points.

                        • 2D spline vertices uses: add_polyline2d()

                        • 3D spline vertices uses: add_polyline3d()

                     ParameterslayoutBaseLayout object

                            • degree – degree of B-spline (order = degree + 1)

                            • method   –  “uniform”,  “distance”/”chord”,  “centripetal”/”sqrt_chord”  or  “arc”
                              calculation method for parameter t

                            • dxfattribs – DXF attributes for Polyline

              render_open_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
                     Render an open uniform B-spline as 3D Polyline.  Definition points are control points.

                     ParameterslayoutBaseLayout object

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

              render_uniform_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
                     Render a uniform B-spline as 3D Polyline.  Definition points are control points.

                     ParameterslayoutBaseLayout object

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

              render_closed_bspline(layout: BaseLayout, degree: int = 3, dxfattribs=None) -> None
                     Render a closed uniform B-spline as 3D Polyline.  Definition points are control points.

                     ParameterslayoutBaseLayout object

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

              render_open_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
              dxfattribs=None) -> None
                     Render a rational open uniform BSpline as  3D  Polyline.   Definition  points  are  control
                     points.

                     ParameterslayoutBaseLayout object

                            • weights  –  list  of  weights, requires a weight value (float) for each definition
                              point.

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

              render_uniform_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
              dxfattribs=None) -> None
                     Render a rational uniform B-spline as 3D Polyline.  Definition points are control points.

                     ParameterslayoutBaseLayout object

                            • weights – list of weights, requires a weight value  (float)  for  each  definition
                              point.

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

              render_closed_rbspline(layout: BaseLayout, weights: Iterable[float], degree: int = 3,
              dxfattribs=None) -> None
                     Render a rational B-spline as 3D Polyline.  Definition points are control points.

                     ParameterslayoutBaseLayout object

                            • weights  –  list  of  weights, requires a weight value (float) for each definition
                              point.

                            • degree – degree of B-spline (order = degree + 1)

                            • dxfattribs – DXF attributes for Polyline

   R12Spline
       class ezdxf.render.R12Spline(control_points: Iterable[UVec], degree: int = 2, closed: bool = True)
              DXF R12 supports 2D B-splines, but Autodesk do not document the usage in the  DXF  Reference.  The
              base entity for splines in DXF R12 is the POLYLINE entity. The spline itself is always in a plane,
              but  as any 2D entity, the spline can be transformed into the 3D object by elevation and extrusion
              (OCS, UCS).

              This way it was possible to store the spline  parameters  in  the  DXF  R12  file,  to  allow  CAD
              applications to modify the spline parameters and rerender the B-spline afterward again as polyline
              approximation.  Therefore,  the result is not better than an approximation by the Spline class, it
              is also just a POLYLINE entity, but maybe someone need exact this tool in the future.

              __init__(control_points: Iterable[UVec], degree: int = 2, closed: bool = True)

                     Parameterscontrol_points – B-spline control frame vertices

                            • degree – degree of B-spline, only 2 and 3 is supported

                            • closedTrue for closed curve

              render(layout: BaseLayout, segments: int = 40, ucs: UCS | None = None, dxfattribs=None) ->
              Polyline
                     Renders the B-spline into layout as 2D Polyline entity. Use an UCS to place the  2D  spline
                     in the 3D space, see approximate() for more information.

                     ParameterslayoutBaseLayout object

                            • segments – count of line segments for approximation, vertex count is segments + 1

                            • ucsUCS definition, control points in ucs coordinates.

                            • dxfattribs – DXF attributes for Polyline

              approximate(segments: int = 40, ucs: UCS | None = None) -> list[UVec]
                     Approximate  the  B-spline  by a polyline with segments line segments.  If ucs is not None,
                     ucs defines an UCS, to transform the curve into OCS. The control points are placed xy-plane
                     of the UCS, don’t use z-axis coordinates, if so make sure all control points are in a plane
                     parallel to the OCS base plane (UCS xy-plane), else the result is unpredictable and depends
                     on the CAD application used to open the DXF file - it may crash.

                     Parameterssegments – count of line segments for approximation, vertex count is segments + 1

                            • ucsUCS definition, control points in ucs coordinates

                     Returns
                            list of vertices in OCS as Vec3 objects

   Bezier
       class ezdxf.render.Bezier
              Render a bezier curve as 2D/3D Polyline.

              The Bezier class is implemented with multiple segments, each  segment  is  an  optimized  4  point
              bezier  curve,  the  4 control points of the curve are: the start point (1) and the end point (4),
              point (2) is start point + start vector and point (3) is end point + end vector. Each segment  has
              its own approximation count.

              SEE ALSO:
                 The new ezdxf.path package provides many advanced construction tools based on the Path class.

              start(point: UVec, tangent: UVec) -> None
                     Set start point and start tangent.

                     Parameterspoint – start point

                            • tangent  –  start tangent as vector, example: (5, 0, 0) means a horizontal tangent
                              with a length of 5 drawing units

              append(point: UVec, tangent1: UVec, tangent2: UVec | None = None, segments: int = 20)
                     Append a control point with two control tangents.

                     Parameterspoint – control point

                            • tangent1 – first tangent as vector “left” of the control point

                            • tangent2 – second tangent as vector “right”  of  the  control  point,  if  omitted
                              tangent2 = -tangent1segments  –  count  of line segments for the polyline approximation, count of line
                              segments from the previous control point to the appended control point.

              render(layout: BaseLayout, force3d: bool = False, dxfattribs=None) -> None
                     Render Bezier curve as 2D/3D Polyline.

                     ParameterslayoutBaseLayout object

                            • force3d – force 3D polyline rendering

                            • dxfattribs – DXF attributes for Polyline

   EulerSpiral
       class ezdxf.render.EulerSpiral(curvature: float = 1)
              Render an euler spiral as a 3D Polyline or a Spline entity.

              This is a parametric curve, which always starts at the origin (0, 0).

              __init__(curvature: float = 1)

                     Parameters
                            curvature – Radius of curvature

              render_polyline(layout: BaseLayout, length: float = 1, segments: int = 100, matrix: Matrix44 |
              None = None, dxfattribs=None)
                     Render curve as Polyline.

                     ParameterslayoutBaseLayout object

                            • length – length measured along the spiral curve from its initial position

                            • segments – count of line segments to use, vertex count is segments + 1

                            • matrix – transformation matrix as Matrix44dxfattribs – DXF attributes for Polyline

                     Returns
                            Polyline

              render_spline(layout: BaseLayout, length: float = 1, fit_points: int = 10, degree: int = 3,
              matrix: Matrix44 | None = None, dxfattribs=None)
                     Render curve as Spline.

                     ParameterslayoutBaseLayout object

                            • length – length measured along the spiral curve from its initial position

                            • fit_points – count of spline fit points to use

                            • degree – degree of B-spline

                            • matrix – transformation matrix as Matrix44dxfattribs – DXF attributes for Spline

                     Returns
                            Spline

   Random Paths
       Random path generators for testing purpose.

       ezdxf.render.random_2d_path(steps: int = 100, max_step_size: float = 1.0, max_heading: float = math.pi /
       2, retarget: int = 20) -> Iterable[Vec2]
              Returns a random 2D path as iterable of Vec2 objects.

              Parameterssteps – count of vertices to generate

                     • max_step_size – max step size

                     • max_heading – limit heading angle change per step to ± max_heading/2 in radians

                     • retarget – specifies steps before changing global walking target

       ezdxf.render.random_3d_path(steps: int = 100, max_step_size: float = 1.0, max_heading: float = math.pi /
       2.0, max_pitch: float = math.pi / 8.0, retarget: int = 20) -> Iterable[Vec3]
              Returns a random 3D path as iterable of Vec3 objects.

              Parameterssteps – count of vertices to generate

                     • max_step_size – max step size

                     • max_heading – limit heading angle change per step to ± max_heading/2, rotation about  the
                       z-axis in radians

                     • max_pitch – limit pitch angle change per step to ± max_pitch/2, rotation about the x-axis
                       in radians

                     • retarget – specifies steps before changing global walking target

   Forms
          This module provides functions to create 2D and 3D forms as vertices or mesh objects.

          2D Forms

          • box()circle()ellipse()euler_spiral()gear()ngon()square()star()turtle()

          3D Forms

          • cone_2p()cone()cube()cylinder()cylinder_2p()helix()sphere()torus()

          3D Form Builder

          • extrude()extrude_twist_scale()from_profiles_linear()from_profiles_spline()rotation_form()sweep()sweep_profile()

   2D Forms
          Basic 2D shapes as iterable of Vec3.

       ezdxf.render.forms.box(sx: float = 1.0, sy: float = 1.0, center=False) -> tuple[Vec3, Vec3, Vec3, Vec3]
              Returns  4  vertices  for a box with a width of sx by and a height of sy. The center of the box in
              (0, 0) if center is True otherwise the lower left corner is (0, 0), upper  right  corner  is  (sx,
              sy).

       ezdxf.render.forms.circle(count: int, radius: float = 1, elevation: float = 0, close: bool = False) ->
       Iterable[Vec3]
              Create  polygon  vertices  for  a circle with the given radius and approximated by count vertices,
              elevation is the z-axis for all vertices.

              Parameterscount – count of polygon vertices

                     • radius – circle radius

                     • elevation – z-axis for all vertices

                     • close – yields first vertex also as last vertex if True.

              Returns
                     vertices in counter-clockwise orientation as Vec3 objects

       ezdxf.render.forms.ellipse(count: int, rx: float = 1, ry: float = 1, start_param: float = 0, end_param:
       float = math.tau, elevation: float = 0) -> Iterable[Vec3]
              Create polygon vertices for an ellipse with given rx as x-axis radius  and  ry  as  y-axis  radius
              approximated  by  count vertices, elevation is the z-axis for all vertices.  The ellipse goes from
              start_param to end_param in counter clockwise orientation.

              Parameterscount – count of polygon vertices

                     • rx – ellipse x-axis radius

                     • ry – ellipse y-axis radius

                     • start_param – start of ellipse in range [0, 2π]

                     • end_param – end of ellipse in range [0, 2π]

                     • elevation – z-axis for all vertices

              Returns
                     vertices in counter clockwise orientation as Vec3 objects

       ezdxf.render.forms.euler_spiral(count: int, length: float = 1, curvature: float = 1, elevation: float =
       0) -> Iterable[Vec3]
              Create polygon vertices for an euler spiral of a given length and radius of curvature. This  is  a
              parametric curve, which always starts at the origin (0, 0).

              Parameterscount – count of polygon vertices

                     • length – length of curve in drawing units

                     • curvature – radius of curvature

                     • elevation – z-axis for all vertices

              Returns
                     vertices as Vec3 objects

       ezdxf.render.forms.gear(count: int, top_width: float, bottom_width: float, height: float, outside_radius:
       float, elevation: float = 0, close: bool = False) -> Iterable[Vec3]
              Returns the corner vertices of a gear shape (cogwheel).

              WARNING:
                 This function does not create correct gears for mechanical engineering!

              Parameterscount – teeth count >= 3

                     • top_width – teeth width at outside radius

                     • bottom_width – teeth width at base radius

                     • height – teeth height; base radius = outside radius - height

                     • outside_radius – outside radius

                     • elevation – z-axis for all vertices

                     • close – yields first vertex also as last vertex if True.

              Returns
                     vertices in counter clockwise orientation as Vec3 objects

       ezdxf.render.forms.ngon(count: int, length: float | None = None, radius: float | None = None, rotation:
       float = 0.0, elevation: float = 0.0, close: bool = False) -> Iterable[Vec3]
              Returns  the  corner  vertices  of  a regular polygon.  The polygon size is determined by the edge
              length or the circum radius argument. If both are given length has the higher priority.

              Parameterscount – count of polygon corners >= 3

                     • length – length of polygon side

                     • radius – circum radius

                     • rotation – rotation angle in radians

                     • elevation – z-axis for all vertices

                     • close – yields first vertex also as last vertex if True.

              Returns
                     vertices as Vec3 objects

       ezdxf.render.forms.square(size: float = 1.0, center=False) -> tuple[Vec3, Vec3, Vec3, Vec3]
              Returns 4 vertices for a square with a side length of the given size.  The center of the square in
              (0, 0) if center is True otherwise the lower left corner is (0, 0), upper right corner  is  (size,
              size).

       ezdxf.render.forms.star(count: int, r1: float, r2: float, rotation: float = 0.0, elevation: float = 0.0,
       close: bool = False) -> Iterable[Vec3]
              Returns the corner vertices for a star shape.

              The  shape  has  count  spikes,  r1  defines the radius of the “outer” vertices and r2 defines the
              radius of the “inner” vertices, but this does not mean that r1 has to be greater than r2.

              Parameterscount – spike count >= 3

                     • r1 – radius 1

                     • r2 – radius 2

                     • rotation – rotation angle in radians

                     • elevation – z-axis for all vertices

                     • close – yields first vertex also as last vertex if True.

              Returns
                     vertices as Vec3 objects

       ezdxf.render.forms.turtle(commands: str, start=Vec2(0, 0), angle: float = 0) -> Iterator[Vec2]
              Returns the 2D vertices of a polyline created by turtle-graphic like commands:

              • <length> - go <length> units forward in current direction and yield vertex

              • r<angle> - turn right <angle> in degrees, a missing angle is 90 deg

              • l<angle> - turn left <angle> in degrees, a missing angle is 90 deg

              • @<x>,<y> - go relative <x>,<y> and yield vertex

              The command string "10 l 10 l 10" returns the 4 corner vertices of a square with a side length  of
              10 drawing units.

              Parameterscommands – command string, commands are separated by spaces

                     • start – starting point, default is (0, 0)

                     • angle – starting direction, default is 0 deg

   3D Forms
       Create 3D forms as MeshTransformer objects.

       ezdxf.render.forms.cube(center: bool = True) -> MeshTransformer
              Create a cube as MeshTransformer object.

              Parameters
                     center – ‘mass’ center of cube, (0, 0, 0) if True, else first corner at (0, 0, 0)

              Returns: MeshTransformer

       ezdxf.render.forms.cone(count: int = 16, radius: float = 1.0, apex: UVec = (0, 0, 1), *, caps=True) ->
       MeshTransformer
              Create a cone as MeshTransformer object, the base center is fixed in the origin (0, 0, 0).

              Parameterscount – edge count of basis_vector

                     • radius – radius of basis_vector

                     • apex – tip of the cone

                     • caps – add a bottom face as ngon if True

       ezdxf.render.forms.cone_2p(count: int = 16, radius: float = 1.0, base_center: UVec = (0, 0, 0), apex:
       UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
              Create  a  cone  as  MeshTransformer object from two points, base_center is the center of the base
              circle and apex as the tip of the cone.

              Parameterscount – edge count of basis_vector

                     • radius – radius of basis_vector

                     • base_center – center point of base circle

                     • apex – tip of the cone

                     • caps – add a bottom face as ngon if True

              Raises ValueError – the cone orientation cannot be detected (base center == apex)

       ezdxf.render.forms.cylinder(count: int = 16, radius: float = 1.0, top_radius: float | None = None,
       top_center: UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
              Create a cylinder as MeshTransformer object, the base center is fixed in the origin (0, 0, 0).

              Parameterscount – profiles edge count

                     • radius – radius for bottom profile

                     • top_radius – radius for top profile, if None top_radius == radius

                     • top_center – location vector for the center of the top profile

                     • caps – close hull with top- and  bottom faces (ngons)

       ezdxf.render.forms.cylinder_2p(count: int = 16, radius: float = 1, base_center: UVec = (0, 0, 0),
       top_center: UVec = (0, 0, 1), *, caps=True) -> MeshTransformer
              Creates a cylinder as MeshTransformer object from two points, base_center is  the  center  of  the
              base circle and, top_center the center of the top circle.

              Parameterscount – cylinder profile edge count

                     • radius – radius for bottom profile

                     • base_center – center of base circle

                     • top_center – center of top circle

                     • caps – close hull with top- and  bottom faces (ngons)

              Raises ValueError – the cylinder orientation cannot be detected (base center == top center)

       ezdxf.render.forms.helix(radius: float, pitch: float, turns: float, resolution: int = 16, ccw=True) ->
       Iterator[Vec3]
              Yields  the vertices of a helix.  The center of the helix is always (0, 0), a positive pitch value
              creates a helix along the +z-axis, a negative value along the -z-axis.

              Parametersradius – helix radius

                     • pitch – the height of one complete helix turn

                     • turns – count of turns

                     • resolution – vertices per turn

                     • ccw – creates a counter-clockwise turning (right-handed) helix if True

       ezdxf.render.forms.sphere(count: int = 16, stacks: int = 8, radius: float = 1, *, quads=True) ->
       MeshTransformer
              Create a sphere as MeshTransformer object, the center of the sphere is always at (0, 0, 0).

              Parameterscount – longitudinal slices

                     • stacks – latitude slices

                     • radius – radius of sphere

                     • quads – use quadrilaterals as faces if True else triangles

       ezdxf.render.forms.torus(major_count: int = 16, minor_count: int = 8, major_radius=1.0, minor_radius=0.1,
       start_angle: float = 0.0, end_angle: float = math.tau, *, caps=True) -> MeshTransformer
              Create a torus as MeshTransformer object, the center of the torus is always  at  (0,  0,  0).  The
              major_radius has to be bigger than the minor_radius.

              Parametersmajor_count – count of circles

                     • minor_count – count of circle vertices

                     • major_radius – radius of the circle center

                     • minor_radius – radius of circle

                     • start_angle – start angle of torus in radians

                     • end_angle – end angle of torus in radians

                     • caps – close hull with start- and end faces (ngons) if the torus is open

   3D Form Builder
       ezdxf.render.forms.extrude(profile: Iterable[UVec], path: Iterable[UVec], close=True, caps=False) ->
       MeshTransformer
              Extrude  a  profile  polygon  along  a  path  polyline,  the  vertices  of  profile  should  be in
              counter-clockwise order.  The sweeping profile will not be rotated at extrusion!

              Parametersprofile – sweeping profile as list of (x, y, z) tuples in counter-clockwise order

                     • path – extrusion path as list of (x, y, z) tuples

                     • close – close profile polygon if Truecaps – close hull with top- and bottom faces (ngons)

              Returns: MeshTransformer

       ezdxf.render.forms.extrude_twist_scale(profile: Iterable[UVec], path: Iterable[UVec], *, twist: float =
       0.0, scale: float = 1.0, step_size: float = 1.0, close=True, caps=False, quads=True) -> MeshTransformer
              Extrude a  profile  polygon  along  a  path  polyline,  the  vertices  of  profile  should  be  in
              counter-clockwise  order.   This implementation can scale and twist the sweeping profile along the
              extrusion path. The path segment points are fix  points,  the  max_step_size  is  used  to  create
              intermediate  profiles  between  this fix points. The max_step_size is adapted for each segment to
              create equally spaced distances.  The twist angle is the rotation angle in radians and  the  scale
              argument defines the scale factor of the final profile.  The twist angle and scaling factor of the
              intermediate profiles will be linear interpolated between the start and end values.

              Parametersprofile – sweeping profile as list of (x, y, z) tuples in counter-clockwise order

                     • path – extrusion path as list of (x, y, z) tuples

                     • twist – rotate sweeping profile up to the given end rotation angle in radians

                     • scale – scale sweeping profile gradually from 1.0 to given value

                     • step_size  – rough distance between automatically created intermediate profiles, the step
                       size is adapted to the distances between the path segment points, a value od 0.0 disables
                       creating intermediate profiles

                     • close – close profile polygon if Truecaps – close hull with top- and  bottom faces (ngons)

                     • quads – use quads for “sweeping” faces if True else triangles, the top and  bottom  faces
                       are always ngons

              Returns: MeshTransformer

       ezdxf.render.forms.from_profiles_linear(profiles: Sequence[Sequence[Vec3]], *, close=True, quads=True,
       caps=False) -> MeshTransformer
              Returns a MeshTransformer instance from linear connected profiles.

              Parametersprofiles – list of profiles

                     • close – close profile polygon if Truequads – use quadrilaterals as connection faces if True else triangles

                     • caps – close hull with top- and bottom faces (ngons)

       ezdxf.render.forms.from_profiles_spline(profiles: Sequence[Sequence[Vec3]], subdivide: int = 4, *,
       close=True, quads=True, caps=False) -> MeshTransformer
              Returns  a  MeshTransformer  instance by spline interpolation between given profiles.  Requires at
              least 4 profiles. A subdivide value of 4, means, create 4 face loops between two profiles, without
              interpolation two profiles create one face loop.

              Parametersprofiles – list of profiles

                     • subdivide – count of face loops

                     • close – close profile polygon if Truequads – use quadrilaterals as connection faces if True else triangles

                     • caps – close hull with top- and bottom faces (ngons)

       ezdxf.render.forms.rotation_form(count: int, profile: Iterable[UVec], angle: float = math.tau, axis: UVec
       = (1, 0, 0), *, caps=False) -> MeshTransformer
              Returns a MeshTransformer instance created by rotating a profile around an axis.

              Parameterscount – count of rotated profiles

                     • profile – profile to rotate as list of vertices

                     • angle – rotation angle in radians

                     • axis – rotation axis

                     • caps – close hull with start- and end faces (ngons)

       ezdxf.render.forms.sweep(profile: Iterable[UVec], sweeping_path: Iterable[UVec], *, close=True,
       quads=True, caps=True) -> MeshTransformer
              Returns the mesh from sweeping a profile along a 3D path, where  the  sweeping  path  defines  the
              final location in the WCS.

              The  profile  is  defined in a reference system. The origin of this reference system will be moved
              along the sweeping path where the z-axis of the reference  system  is  pointing  into  the  moving
              direction.

              Returns the mesh as ezdxf.render.MeshTransformer object.

              Parametersprofile  –  sweeping  profile  defined  in  the reference system as iterable of (x, y, z)
                       coordinates in counter-clockwise order

                     • sweeping_path – the sweeping path defined in the WCS as iterable of (x, y, z) coordinates

                     • close – close sweeping profile if Truequads – use quadrilaterals as connection faces if True else triangles

                     • caps – close hull with top- and bottom faces (ngons)

       ezdxf.render.forms.sweep_profile(profile: Iterable[UVec], sweeping_path: Iterable[UVec]) ->
       list[Sequence[Vec3]]
              Returns the intermediate profiles of sweeping a profile along a 3D path where  the  sweeping  path
              defines the final location in the WCS.

              The  profile  is  defined in a reference system. The origin of this reference system will be moved
              along the sweeping path where the z-axis of the reference  system  is  pointing  into  the  moving
              direction.

              Returns the start-, end- and all intermediate profiles along the sweeping path.

   MeshBuilder
       The  MeshBuilder  classes  are helper tools to manage meshes buildup by vertices and faces.  The vertices
       are stored in a vertices list as Vec3 instances.  The faces are stored as a sequence  of  vertex  indices
       which  is  the location of the vertex in the vertex list. A single MeshBuilder class can contain multiple
       separated meshes at the same time.

       The method MeshBuilder.render_mesh() renders the content as a single  DXF  Mesh  entity,  which  supports
       ngons, ngons are polygons with more than 4 vertices. This entity requires at least DXF R2000.

       The  method  MeshBuilder.render_polyface()  renders  the  content  as a single DXF Polyface entity, which
       supports only triangles and quadrilaterals. This entity is supported by DXF R12.

       The method MeshBuilder.render_3dfaces() renders each face of the mesh as a  single   DXF  Face3d  entity,
       which supports only triangles and quadrilaterals. This entity is supported by DXF R12.

       The  MeshTransformer  class  is often used as an interface object to transfer mesh data between functions
       and moduls, like for the mesh exchange add-on meshex.

       The basic MeshBuilder class does not support transformations.

       class ezdxf.render.MeshBuilder

              vertices
                     List of vertices as Vec3 or (x, y, z) tuple

              faces  List of faces as list of vertex indices,  where a vertex index is the index of  the  vertex
                     in  the vertices list. A face requires at least three vertices, Mesh supports ngons, so the
                     count of vertices is not limited.

              add_face(vertices: Iterable[UVec]) -> None
                     Add a face as vertices list to the mesh. A face requires at least 3 vertices,  each  vertex
                     is a (x, y, z) tuple or Vec3 object. The new vertex indices are stored as face in the faces
                     list.

                     Parameters
                            vertices  –  list  of at least 3 vertices [(x1, y1, z1), (x2, y2, z2), (x3, y3, y3),
                            ...]

              add_mesh(vertices: list[Vec3] | None = None, faces: list[Sequence[int]] | None = None, mesh=None)
              -> None
                     Add another mesh to this mesh.

                     A mesh can be a MeshBuilder, MeshVertexMerger or Mesh object  or  requires  the  attributes
                     vertices and faces.

                     Parametersvertices – list of vertices, a vertex is a (x, y, z) tuple or Vec3 object

                            • faces – list of faces, a face is a list of vertex indices

                            • mesh – another mesh entity

              add_vertices(vertices: Iterable[UVec]) -> Sequence[int]
                     Add  new  vertices  to the mesh, each vertex is a (x, y, z) tuple or a Vec3 object, returns
                     the indices of the vertices added to the vertices list.

                     e.g. adding 4 vertices to an  empty  mesh,  returns  the  indices  (0,  1,  2,  3),  adding
                     additional 4 vertices returns the indices (4, 5, 6, 7).

                     Parameters
                            vertices – list of vertices, vertex as (x, y, z) tuple or Vec3 objects

                     Returns
                            indices of the vertices added to the vertices list

                     Return type
                            tuple

              bbox() -> BoundingBox
                     Returns the BoundingBox of the mesh.

              copy() Returns a copy of mesh.

              diagnose() -> MeshDiagnose
                     Returns the MeshDiagnose object for this mesh.

              face_normals() -> Iterator[Vec3]
                     Yields all face normals, yields the NULLVEC instance for degenerated faces.

              face_orientation_detector(reference: int = 0) -> FaceOrientationDetector
                     Returns  a  FaceOrientationDetector  or  short  fod  instance.   The forward orientation is
                     defined by the reference face which is 0 by default.

                     The fod can check if all faces are reachable from the reference face and if all faces  have
                     the same orientation. The fod can be reused to unify the face orientation of the mesh.

              faces_as_vertices() -> Iterator[list[Vec3]]
                     Yields all faces as list of vertices.

              flip_normals() -> None
                     Flips the normals of all faces by reversing the vertex order inplace.

              classmethod from_builder(other: MeshBuilder)
                     Create  new  mesh  from  other  mesh  builder,  faster  than  from_mesh() but supports only
                     MeshBuilder and inherited classes.

              classmethod from_mesh(other: MeshBuilder | Mesh) -> T
                     Create new mesh from other mesh as class method.

                     Parameters
                            othermesh of type MeshBuilder and inherited or DXF  Mesh  entity  or  any  object
                            providing attributes vertices, edges and faces.

              classmethod from_polyface(other: Polymesh | Polyface) -> T
                     Create new mesh from a  Polyface or Polymesh object.

              get_face_vertices(index: int) -> Sequence[Vec3]
                     Returns the face index as sequence of Vec3 objects.

              get_face_normal(index: int) -> Vec3
                     Returns  the  normal  vector  of  the  face index as Vec3, returns the NULLVEC instance for
                     degenerated  faces.

              merge_coplanar_faces(passes: int = 1) -> MeshTransformer
                     Returns a new MeshBuilder object with merged adjacent coplanar faces.

                     The faces have to share at least two vertices and  have  to  have  the  same  clockwise  or
                     counter-clockwise vertex order.

                     The current implementation is not very capable!

              mesh_tessellation(max_vertex_count: int = 4) -> MeshTransformer
                     Returns a new MeshTransformer instance, where each face has no more vertices than the given
                     max_vertex_count.

                     The  fast  mode  uses a shortcut for faces with less than 6 vertices which may not work for
                     concave faces!

              normalize_faces() -> None
                     Removes duplicated vertex indices from faces and stores all faces as open faces, where  the
                     last vertex is not coincident with the first vertex.

              open_faces() -> Iterator[Sequence[int]]
                     Yields  all faces as sequence of integers where the first vertex is not coincident with the
                     last vertex.

              optimize_vertices(precision: int = 6) -> MeshTransformer
                     Returns a new mesh with optimized vertices. Coincident vertices are merged together and all
                     faces are open faces (first vertex != last vertex). Uses  internally  the  MeshVertexMerger
                     class to merge vertices.

              render_3dfaces(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs:
              UCS | None = None)
                     Render mesh as Face3d entities into layout.

                     ParameterslayoutBaseLayout object

                            • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}matrix – transformation matrix of type Matrix44ucs – transform vertices by UCS to WCS

              render_mesh(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs: UCS |
              None = None)
                     Render mesh as Mesh entity into layout.

                     ParameterslayoutBaseLayout object

                            • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}matrix – transformation matrix of type Matrix44ucs – transform vertices by UCS to WCS

              render_normals(layout: GenericLayoutType, length: float = 1, relative=True, dxfattribs=None)
                     Render  face  normals  as  Line  entities  into layout, useful to check orientation of mesh
                     faces.

                     ParameterslayoutBaseLayout object

                            • length – visual length of normal, use length < 0  to  point  normals  in  opposite
                              direction

                            • relative – scale length relative to face size if Truedxfattribs – dict of DXF attributes e.g. {'layer': 'normals', 'color': 6}

              render_polyface(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs:
              UCS | None = None)
                     Render mesh as Polyface entity into layout.

                     ParameterslayoutBaseLayout object

                            • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}matrix – transformation matrix of type Matrix44ucs – transform vertices by UCS to WCS

              separate_meshes() -> list[MeshTransformer]
                     A  single  MeshBuilder  instance can store multiple separated meshes. This function returns
                     this separated meshes as multiple MeshTransformer instances.

              subdivide(level: int = 1, quads=True) -> MeshTransformer
                     Returns a new MeshTransformer object with all faces subdivided.

                     Parameterslevel – subdivide levels from 1 to max of 5

                            • quads – create quad faces if True else create triangles

              subdivide_ngons(max_vertex_count=4) -> Iterator[Sequence[Vec3]]
                     Yields all faces as sequence of Vec3 instances,  where  all  ngons  which  have  more  than
                     max_vertex_count  vertices  gets  subdivided.   In  contrast  to the tessellation() method,
                     creates this method a new vertex in the centroid of  the  face.  This  can  create  a  more
                     regular tessellation but only works reliable for convex faces!

              tessellation(max_vertex_count: int = 4) -> Iterator[Sequence[Vec3]]
                     Yields  all  faces  as  sequence of Vec3 instances, each face has no more vertices than the
                     given max_vertex_count. This method uses the “ear  clipping”  algorithm  which  works  with
                     concave faces too and does not create any additional vertices.

              unify_face_normals(*, fod: FaceOrientationDetector | None = None) -> MeshTransformer
                     Returns  a  new  MeshTransformer object with unified face normal vectors of all faces.  The
                     forward direction (not necessarily outwards) is defined by the face-normals of the majority
                     of the faces.  This function can not process non-manifold meshes (more than two  faces  are
                     connected by a single edge) or multiple disconnected meshes in a single MeshBuilder object.

                     It is possible to pass in an existing FaceOrientationDetector instance as argument fod.

                     RaisesNonManifoldError – non-manifold mesh

                            • MultipleMeshesError – the MeshBuilder object contains multiple disconnected meshes

              unify_face_normals_by_reference(reference: int = 0, *, force_outwards=False, fod:
              FaceOrientationDetector | None = None) -> MeshTransformer
                     Returns  a  new  MeshTransformer object with unified face normal vectors of all faces.  The
                     forward direction (not necessarily outwards) is defined by the reference face, which is the
                     first face of the mesh by default.  This function can not process non-manifold meshes (more
                     than two faces are connected by a single edge) or multiple disconnected meshes in a  single
                     MeshBuilder object.

                     The  outward  direction  of  all  face  normals  can  be  forced  by  stetting the argument
                     force_outwards to True but this works only for closed surfaces, and it’s time-consuming!

                     It is not possible to check for a closed surface as long the face normal  vectors  are  not
                     unified.  But it can be done afterward by the attribute MeshDiagnose.is_closed_surface() to
                     see if the result is trustworthy.

                     It is possible to pass in an existing FaceOrientationDetector instance as argument fod.

                     Parametersreference – index of the reference face

                            • force_outwards – forces face-normals to point outwards, this works only for closed
                              surfaces, and it’s time-consuming!

                            • fodFaceOrientationDetector instance

                     Raises ValueError – non-manifold mesh or the MeshBuilder object
                                contains multiple disconnected meshes

   MeshTransformer
       Same functionality as MeshBuilder but supports inplace transformation.

       class ezdxf.render.MeshTransformer
              Subclass of MeshBuilder

              transform(matrix: Matrix44)
                     Transform mesh inplace by applying the transformation matrix.

                     Parameters
                            matrix – 4x4 transformation matrix as Matrix44 object

              translate(dx: float | UVec = 0, dy: float = 0, dz: float = 0)
                     Translate mesh inplace.

                     Parametersdx – translation in x-axis or translation vector

                            • dy – translation in y-axis

                            • dz – translation in z-axis

              scale(sx: float = 1, sy: float = 1, sz: float = 1)
                     Scale mesh inplace.

                     Parameterssx – scale factor for x-axis

                            • sy – scale factor for y-axis

                            • sz – scale factor for z-axis

              scale_uniform(s: float)
                     Scale mesh uniform inplace.

                     Parameters
                            s – scale factor for x-, y- and z-axis

              rotate_x(angle: float)
                     Rotate mesh around x-axis about angle inplace.

                     Parameters
                            angle – rotation angle in radians

              rotate_y(angle: float)
                     Rotate mesh around y-axis about angle inplace.

                     Parameters
                            angle – rotation angle in radians

              rotate_z(angle: float)
                     Rotate mesh around z-axis about angle inplace.

                     Parameters
                            angle – rotation angle in radians

              rotate_axis(axis: UVec, angle: float)
                     Rotate mesh around an arbitrary axis located in the origin (0, 0, 0) about angle.

                     Parametersaxis – rotation axis as Vec3

                            • angle – rotation angle in radians

   MeshVertexMerger
       Same functionality as MeshBuilder,  but  created  meshes  with  unique  vertices  and  no  doublets,  but
       MeshVertexMerger  needs  extra  memory  for  bookkeeping  and also does not support transformations.  The
       location of the merged vertices is the location of the first vertex with the same key.

       This  class  is  intended  as  intermediate  object  to  create  compact  meshes  and  convert  them   to
       MeshTransformer objects to apply transformations:

          mesh = MeshVertexMerger()

          # create your mesh
          mesh.add_face(...)

          # convert mesh to MeshTransformer object
          return MeshTransformer.from_builder(mesh)

       class ezdxf.render.MeshVertexMerger(precision: int = 6)
              Subclass of MeshBuilder

              Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping.

              MeshVertexMerger  creates  a key for every vertex by rounding its components by the Python round()
              function and a given precision value. Each vertex with the same key gets the  same  vertex  index,
              which  is  the  index  of  first  vertex  with this key, so all vertices with the same key will be
              located at the location of this first vertex. If you want an average location of all vertices with
              the same key use the MeshAverageVertexMerger class.

              Parameters
                     precision – floating point precision for vertex rounding

   MeshAverageVertexMerger
       This is an extended version of MeshVertexMerger.  The location of the  merged  vertices  is  the  average
       location  of  all  vertices  with  the  same  key,  this  needs extra memory and runtime in comparison to
       MeshVertexMerger and this class also does not support transformations.

       class ezdxf.render.MeshAverageVertexMerger(precision: int = 6)
              Subclass of MeshBuilder

              Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping and runtime  for
              calculation of average vertex location.

              MeshAverageVertexMerger  creates  a  key for every vertex by rounding its components by the Python
              round() function and a given precision value. Each vertex with the same key gets the  same  vertex
              index,  which  is  the index of first vertex with this key, the difference to the MeshVertexMerger
              class is the calculation of the average location for all vertices with the same  key,  this  needs
              extra  memory  to  keep track of the count of vertices for each key and extra runtime for updating
              the vertex location each time a vertex with an existing key is added.

              Parameters
                     precision – floating point precision for vertex rounding

       class ezdxf.render.mesh.EdgeStat(count: int, balance: int)
              Named tuple of edge statistics.

              count  how often the edge (a, b) is used in faces as (a, b) or (b, a)

              balance
                     count of edges (a, b) - count of edges (b, a) and should be 0 in “healthy” closed surfaces,
                     if the balance is not 0, maybe doubled coincident faces  exist  or  faces  may  have  mixed
                     clockwise and counter-clockwise vertex orders

   MeshBuilder Helper Classes
       class ezdxf.render.MeshDiagnose
              Diagnose  tool which can be used to analyze and detect errors of MeshBuilder objects like topology
              errors for closed surfaces.  The object contains cached values, which do not get  updated  if  the
              source mesh will be changed!

              NOTE:
                 There   exist   no   tools   in   ezdxf  to  repair  broken  surfaces,  but  you  can  use  the
                 ezdxf.addons.meshex addon to exchange meshes with the open source tool MeshLab.

              Create an instance of this tool by the MeshBuilder.diagnose() method.

              property bbox: BoundingBox
                     Returns the BoundingBox of the mesh. (cached data)

              property edge_stats: Dict[Tuple[int, int], EdgeStat]
                     Returns the edge statistics as a dict. The dict-key is the edge  as  tuple  of  two  vertex
                     indices  (a,  b)  where  a is always smaller than b. The dict-value is an EdgeStat tuple of
                     edge count and edge balance, see EdgeStat  for  the  definition  of  edge  count  and  edge
                     balance. (cached data)

              property euler_characteristic: int
                     Returns the Euler characteristic: https://en.wikipedia.org/wiki/Euler_characteristic

                     This number is always 2 for convex polyhedra.

              property face_normals: Sequence[Vec3]
                     Returns all face normal vectors  as sequence. The NULLVEC instance is used as normal vector
                     for degenerated faces. (cached data)

              property faces: Sequence[Sequence[int]]
                     Sequence of faces as Sequence[int]

              property is_closed_surface: bool
                     Returns True if the mesh has a closed surface.  This method does not require a unified face
                     orientation.  If multiple separated meshes are present the state is only True if all meshes
                     have a closed surface. (cached data)

                     Returns False for non-manifold meshes.

              property is_edge_balance_broken: bool
                     Returns  True  if  the  edge  balance is broken, this indicates a topology error for closed
                     surfaces. A non-broken edge balance reflects that each edge connects two faces,  where  the
                     edge  is  clockwise oriented in the first face and counter-clockwise oriented in the second
                     face.  A broken edge balance indicates possible topology  errors  like  mixed  face  vertex
                     orientations  or  a  non-manifold  mesh where an edge connects more than two faces. (cached
                     data)

              property is_manifold: bool
                     Returns True if all edges have an edge count < 3. (cached data)

                     A non-manifold mesh has edges with 3 or more connected faces.

              property n_edges: int
                     Returns the unique edge count. (cached data)

              property n_faces: int
                     Returns the face count.

              property n_vertices: int
                     Returns the vertex count.

              property vertices: Sequence[Vec3]
                     Sequence of mesh vertices as Vec3 instances

              centroid() -> Vec3
                     Returns the centroid of all vertices. (center of mass)

              estimate_face_normals_direction() -> float
                     Returns the estimated face-normals direction as float value in the range [-1.0, 1.0] for  a
                     closed surface.

                     This  heuristic  works  well  for  simple  convex  hulls  but  struggles  with more complex
                     structures like a torus (doughnut).

                     A counter-clockwise (ccw) vertex arrangement for outward pointing faces is  assumed  but  a
                     clockwise (cw) arrangement works too but the return values are reversed.

                     The  closer  the  value  to 1.0 (-1.0 for cw) the more likely all normals pointing outwards
                     from the surface.

                     The closer the value to -1.0 (1.0 for cw) the more likely all normals pointing inwards from
                     the surface.

                     There are no exact confidence values if all faces pointing outwards, here some examples for
                     surfaces created by ezdxf.render.forms functions:

                        • cube() returns 1.0

                        • cylinder() returns 0.9992

                        • sphere() returns 0.9994

                        • cone() returns 0.9162

                        • cylinder() with all hull faces pointing outwards but  caps  pointing  inwards  returns
                          0.7785  but the property is_edge_balance_broken returns True which indicates the mixed
                          vertex orientation

                        • and the estimation of 0.0469 for a torus() is barely usable

              has_non_planar_faces() -> bool
                     Returns True if any face is non-planar.

              surface_area() -> float
                     Returns the surface area.

              total_edge_count() -> int
                     Returns the total edge count of all faces, shared edges are  counted  separately  for  each
                     face.  In  closed  surfaces  this count should be 2x the unique edge count n_edges. (cached
                     data)

              unique_edges() -> Iterable[Tuple[int, int]]
                     Yields the unique edges of the mesh as int 2-tuples. (cached data)

              volume() -> float
                     Returns the volume of a closed surface or 0 otherwise.

                     WARNING:
                        The face vertices have to be in counter-clockwise order, this requirement is not checked
                        by this method.

                        The result is not  correct  for  multiple  separated  meshes  in  a  single  MeshBuilder
                        object!!!

       class ezdxf.render.FaceOrientationDetector(mesh: MeshBuilder, reference: int = 0)
              Helper   class   for   face   orientation  and  face  normal  vector  detection.  Use  the  method
              MeshBuilder.face_orientation_detector() to create an instance.

              The face orientation detector classifies the  faces  of  a  mesh  by  their  forward  or  backward
              orientation.   The  forward orientation is defined by a reference face, which is the first face of
              the mesh by default and this orientation is not necessarily outwards.

              This class has some overlapping features with MeshDiagnose but it has  a  longer  setup  time  and
              needs more memory than MeshDiagnose.

              Parametersmesh – source mesh as MeshBuilder object

                     • reference – index of the reference face

              is_manifold
                     True  if  all  edges  have  an edge count < 3. A non-manifold mesh has edges with 3 or more
                     connected faces.

              property all_reachable: bool
                     Returns True if  all  faces  are  reachable  from  the  reference  face  same  as  property
                     is_single_mesh.

              property count: tuple[int, int]
                     Returns the count of forward and backward oriented faces.

              property backward_faces: Iterator[Sequence[int]]
                     Yields all backward oriented faces.

              property forward_faces: Iterator[Sequence[int]]
                     Yields all forward oriented faces.

              property has_uniform_face_normals: bool
                     Returns True if all reachable faces are forward oriented according to the reference face.

              property is_closed_surface: bool
                     Returns True if the mesh has a closed surface.  This method does not require a unified face
                     orientation.  If multiple separated meshes are present the state is only True if all meshes
                     have a closed surface.

                     Returns False for non-manifold meshes.

              property is_single_mesh: bool
                     Returns True if only a single mesh is present same as property all_reachable.

              classify_faces(reference: int = 0) -> None
                     Detect the forward and backward oriented faces.

                     The forward and backward orientation has to be defined by a reference face.

              is_reference_face_pointing_outwards() -> bool
                     Returns  True  if  the normal vector of the reference face is pointing outwards. This works
                     only for meshes  with  unified  faces  which  represent  a  closed  surfaces,  and  it’s  a
                     time-consuming calculation!

   Trace
       This module provides tools to create banded lines like LWPOLYLINE with width information.  Path rendering
       as quadrilaterals: Trace, Solid or Face3d.

       class ezdxf.render.trace.TraceBuilder
              Sequence of 2D banded lines like polylines with start- and end width or curves with start- and end
              width.

              NOTE:
                 Accepts 3D input, but z-axis is ignored. The TraceBuilder is a 2D only object and uses only the
                 OCS coordinates!

              abs_tol
                     Absolute tolerance for floating point comparisons

              append(trace: AbstractTrace) -> None
                     Append a new trace.

              close()
                     Close multi traces by merging first and last trace, if linear traces.

              faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
                     Yields all faces as 4-tuples of Vec2 objects in OCS.

              faces_wcs(ocs: OCS, elevation: float) -> Iterable[Sequence[Vec3]]
                     Yields all faces as 4-tuples of Vec3 objects in WCS.

              virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
              Iterable[Quadrilateral]
                     Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.

                     If  a  document  is  given,  the  doc attribute of the new entities will be set and the new
                     entities will be automatically added to the entity database of that document.

                     NOTE:
                        The TraceBuilder is a 2D only object and uses only the OCS coordinates!

                     Parametersdxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”

                            • dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities

                            • doc – associated document

              classmethod from_polyline(polyline: DXFGraphic, segments: int = 64) -> TraceBuilder
                     Create a complete trace from a LWPOLYLINE or a 2D POLYLINE entity,  the  trace  consist  of
                     multiple sub-traces if bulge values are present. Uses only the OCS coordinates!

                     ParameterspolylineLWPolyline or 2D Polylinesegments  –  count  of segments for bulge approximation, given count is for a full
                              circle, partial arcs have proportional less segments, but at least 3

              __len__()

              __getitem__()

       class ezdxf.render.trace.LinearTrace
              Linear 2D banded lines like polylines with start- and end width.

              Accepts 3D input, but z-axis is ignored.

              abs_tol
                     Absolute tolerance for floating point comparisons

              is_started
                     True if at least one station exist.

              add_station(point: UVec, start_width: float, end_width: float | None = None) -> None
                     Add a trace station (like a vertex) at location point, start_width is the width of the next
                     segment starting at this station, end_width is the end width of the next segment.

                     Adding the last location again, replaces the actual last location e.g.   adding  lines  (a,
                     b),  (b,  c),  creates only 3 stations (a, b, c), this is very important to connect to/from
                     splines.

                     Parameterspoint – 2D location (vertex), z-axis of 3D vertices is ignored.

                            • start_width – start width of next segment

                            • end_width – end width of next segment

              faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
                     Yields all faces as 4-tuples of Vec2 objects.

                     First and last miter is 90 degrees if the path is not closed, otherwise the intersection of
                     first and last segment is taken into account, a closed path has to have explicit  the  same
                     last and first vertex.

              virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
              Iterable[Quadrilateral]
                     Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.

                     If  a  document  is  given,  the  doc attribute of the new entities will be set and the new
                     entities will be automatically added to the entity database of that document.

                     Parametersdxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”

                            • dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities

                            • doc – associated document

       class ezdxf.render.trace.CurvedTrace
              2D banded curves like arcs or splines with start- and end width.

              Represents always only one curved entity and all miter of  curve  segments  are  perpendicular  to
              curve tangents.

              Accepts 3D input, but z-axis is ignored.

              faces() -> Iterable[Tuple[Vec2, Vec2, Vec2, Vec2]]
                     Yields all faces as 4-tuples of Vec2 objects.

              virtual_entities(dxftype='TRACE', dxfattribs=None, doc: Drawing | None = None) ->
              Iterable[Quadrilateral]
                     Yields faces as SOLID, TRACE or 3DFACE entities with DXF attributes given in dxfattribs.

                     If  a  document  is  given,  the  doc attribute of the new entities will be set and the new
                     entities will be automatically added to the entity database of that document.

                     Parametersdxftype – DXF type as string, “SOLID”, “TRACE” or “3DFACE”

                            • dxfattribs – DXF attributes for SOLID, TRACE or 3DFACE entities

                            • doc – associated document

              classmethod from_arc(arc: ConstructionArc, start_width: float, end_width: float, segments: int =
              64) -> CurvedTrace
                     Create curved trace from an arc.

                     ParametersarcConstructionArc object

                            • start_width – start width

                            • end_width – end width

                            • segments – count of segments for full circle (360 degree)  approximation,  partial
                              arcs have proportional less segments, but at least 3

                     Raises ValueError – if arc.radius <= 0

              classmethod from_spline(spline: BSpline, start_width: float, end_width: float, segments: int) ->
              CurvedTrace
                     Create curved trace from a B-spline.

                     ParameterssplineBSpline object

                            • start_width – start width

                            • end_width – end width

                            • segments – count of segments for approximation

   Point Rendering
       Helper function to render Point entities as DXF primitives.

       ezdxf.render.point.virtual_entities(point: Point, pdsize: float = 1, pdmode: int = 0) -> list[DXFGraphic]
              Yields  point  graphic  as  DXF  primitives  LINE and CIRCLE entities.  The dimensionless point is
              rendered as zero-length line!

              Check for this condition:

                 e.dxftype() == 'LINE' and e.dxf.start.isclose(e.dxf.end)

              if the rendering engine can’t handle zero-length lines.

              Parameterspoint – DXF POINT entity

                     • pdsize – point size in drawing units

                     • pdmode – point styling mode, see Point class

       SEE ALSO:
          Go to ezdxf.entities.Point class documentation for more information about POINT styling modes.

   MultiLeaderBuilder
       These are helper classes to build MultiLeader entities in an easy way.  The MultiLeader  entity  supports
       two kinds of content, for each exist a specialized builder class:

       • MultiLeaderMTextBuilder for MText content

       • MultiLeaderBlockBuilder for Block content

       The usual steps of the building process are:

          1. create entity by a factory method

                 • add_multileader_mtext()add_multileader_block()

          2. set the content

                 • MultiLeaderMTextBuilder.set_content()MultiLeaderBlockBuilder.set_content()MultiLeaderBlockBuilder.set_attribute()

          3. set properties

                 • MultiLeaderBuilder.set_arrow_properties()MultiLeaderBuilder.set_connection_properties()MultiLeaderBuilder.set_connection_types()MultiLeaderBuilder.set_leader_properties()MultiLeaderBuilder.set_mleader_style()MultiLeaderBuilder.set_overall_scaling()

          4. add one or more leader lines

                 • MultiLeaderBuilder.add_leader_line()

          5. finalize building process

                 • MultiLeaderBuilder.build()

       The Tutorial for MultiLeader shows how to use these helper classes in more detail.

       class ezdxf.render.MultiLeaderBuilder
              Abstract base class to build MultiLeader entities.

              property context: MLeaderContext
                     Returns the context entity MLeaderContext.

              property multileader: MultiLeader
                     Returns the MultiLeader entity.

              add_leader_line(side: ConnectionSide, vertices: Iterable[Vec2]) -> None
                     Add leader as iterable of vertices in render UCS coordinates (WCS by default).

                     NOTE:
                        Vertical (top, bottom) and horizontal attachment sides (left, right) can not be mixed in
                        a single entity - this is a limitation of the MULTILEADER entity.

                     Parametersside – connection side where to attach the leader line

                            • vertices – leader vertices

              build(insert: Vec2, rotation: float = 0.0, ucs: UCS | None = None) -> None
                     Compute  the  required  geometry  data. The construction plane is the xy-plane of the given
                     render UCS.

                     Parametersinsert – insert location for the content in render UCS coordinates

                            • rotation – content rotation angle around the render UCS z-axis in degrees

                            • ucs – the render UCS, default is the WCS

              set_arrow_properties(name: str = '', size: float = 0.0)
                     Set leader arrow properties all leader lines have the same arrow type.

                     The MULTILEADER entity is able to support multiple arrows, but this seems to be unsupported
                     by CAD applications and is therefore also not supported by the builder classes.

              set_connection_properties(landing_gap: float = 0.0, dogleg_length: float = 0.0)
                     Set the properties how to connect the leader line to the content.

                     The landing gap is the space between the content and the start  of  the  leader  line.  The
                     “dogleg”  is  the  first  line  segment  of the leader in the “horizontal” direction of the
                     content.

              set_connection_types(left=HorizontalConnection.by_style, right=HorizontalConnection.by_style,
              top=VerticalConnection.by_style, bottom=VerticalConnection.by_style)
                     Set the connection type for each connection side.

              set_leader_properties(color: int | RGB = colors.BYBLOCK, linetype: str = 'BYBLOCK', lineweight:
              int = const.LINEWEIGHT_BYBLOCK, leader_type=LeaderType.straight_lines)
                     Set leader line properties.

                     Parameterscolor – line color as AutoCAD Color Index (ACI) or RGB tuple

                            • linetype – as name string, e.g. “BYLAYER”

                            • lineweight – as integer value, see: Lineweightsleader_type – straight lines of spline type

              set_mleader_style(style: MLeaderStyle)
                     Reset base properties by MLeaderStyle properties. This also resets the content!

              set_overall_scaling(scale: float)
                     Set the overall scaling factor for the whole entity, except for the leader line vertices!

                     Parameters
                            scale – scaling factor > 0.0

   MultiLeaderMTextBuilder
       Specialization of MultiLeaderBuilder to build MultiLeader with MTEXT content.

       class ezdxf.render.MultiLeaderMTextBuilder

              set_content(content: str, color: int | RGB | None = None, char_height: float = 0.0, alignment:
              TextAlignment = TextAlignment.left, style: str = '')
                     Set MTEXT content.

                     Parameterscontent – MTEXT content as string

                            • color – block color as AutoCAD Color Index (ACI) or RGB tuple

                            • char_height – initial char height in drawing units

                            • alignmentTextAlignment - left, center, right

                            • style – name of Textstyle as string

              quick_leader(content: str, target: Vec2, segment1: Vec2, segment2: Vec2 | None = None,
              connection_type: HorizontalConnection | VerticalConnection =
              HorizontalConnection.middle_of_top_line, ucs: UCS | None = None) -> None
                     Creates a quick MTEXT leader. The target point defines where the  leader  points  to.   The
                     segment1  is the first segment of the leader line relative to the target point, segment2 is
                     an optional second line segment relative to the first line  segment.   The  connection_type
                     defines  the  type  of  connection  (horizontal or vertical) and the MTEXT alignment (left,
                     center or right).  Horizontal connections  are  always  left  or  right  aligned,  vertical
                     connections are always center aligned.

                     Parameterscontent – MTEXT content string

                            • target – leader target point as Vec2segment1 – first leader line segment as relative distance to insertsegment2  – optional second leader line segment as relative distance to first line
                              segment

                            • connection_type – one of HorizontalConnection or VerticalConnectionucs – the rendering UCS, default is the WCS

   MultiLeaderBlockBuilder
       Specialization of MultiLeaderBuilder to build MultiLeader with BLOCK content.

       class ezdxf.render.MultiLeaderBlockBuilder

              property block_layout: BlockLayout
                     Returns the block layout.

              property extents: BoundingBox
                     Returns the bounding box of the block.

              set_content(name: str, color: int | RGB = colors.BYBLOCK, scale: float = 1.0,
              alignment=BlockAlignment.center_extents)
                     Set BLOCK content.

                     Parametersname – the block name as string

                            • color – block color as AutoCAD Color Index (ACI) or RGB tuple

                            • scale – the block scaling, not to be confused with overall scaling

                            • alignment – the block insertion point or the center of extents

              set_attribute(tag: str, text: str, width: float = 1.0)
                     Add BLOCK attributes based on an ATTDEF entity in the block definition. All  properties  of
                     the  new  created  ATTRIB  entity  are  defined by the template ATTDEF entity including the
                     location.

                     Parameterstag – attribute tag name

                            • text – attribute content string

                            • width – width factor

   Enums
       class ezdxf.render.LeaderType(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              The leader type.

              none

              straight_lines

              splines

       class ezdxf.render.ConnectionSide(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              The leader connection side.

              Vertical (top, bottom) and horizontal attachment sides (left, right) can not be mixed in a  single
              entity - this is a limitation of the MULTILEADER entity.

              left

              right

              top

              bottom

       class ezdxf.render.HorizontalConnection(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              The horizontal leader connection type.

              by_style

              top_of_top_line

              middle_of_top_line

              middle_of_text

              middle_of_bottom_line

              bottom_of_bottom_line

              bottom_of_bottom_line_underline

              bottom_of_top_line_underline

              bottom_of_top_line

              bottom_of_top_line_underline_all

       class ezdxf.render.VerticalConnection(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              The vertical leader connection type.

              by_style

              center

              center_overline

       class ezdxf.render.TextAlignment(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              The MText alignment type.

              left

              center

              right

       class ezdxf.render.BlockAlignment(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              The Block alignment type.

              center_extents

              insertion_point

   Arrows
       This  module  provides  support  for  the  AutoCAD  standard  arrow  heads  used in DIMENSION, LEADER and
       MULTILEADER entities. Library user don’t have to use the ARROWS objects directly,  but  should  know  the
       arrow names stored in it as attributes. The arrow names should be accessed that way:

          import ezdxf

          arrow = ezdxf.ARROWS.closed_filled

       ezdxf.render.arrows.ARROWS
              Single instance of _Arrows to work with.

       class ezdxf.render.arrows._Arrows
              Management object for standard arrows.

              __acad__
                     Set of AutoCAD standard arrow names.

              __ezdxf__
                     Set of arrow names special to ezdxf.

              architectural_tick
                     [image]

              closed_filled
                     [image]

              dot    [image]

              dot_small
                     [image]

              dot_blank
                     [image]

              origin_indicator
                     [image]

              origin_indicator_2
                     [image]

              open   [image]

              right_angle
                     [image]

              open_30
                     [image]

              closed [image]

              dot_smallblank
                     [image]

              none   [image]

              oblique
                     [image]

              box_filled
                     [image]

              box    [image]

              closed_blank
                     [image]

              datum_triangle_filled
                     [image]

              datum_triangle
                     [image]

              integral
                     [image]

              ez_arrow
                     [image]

              ez_arrow_blank
                     [image]

              ez_arrow_filled
                     [image]

              is_acad_arrow(item: str) -> bool
                     Returns True if item is a standard AutoCAD arrow.

              is_ezdxf_arrow(item: str) -> bool
                     Returns True if item is a special ezdxf arrow.

              insert_arrow(layout: GenericLayoutType, name: str, insert: UVec = NULLVEC, size: float = 1.0,
              rotation: float = 0, *, dxfattribs=None) -> Vec2
                     Insert arrow as block reference into layout.

              render_arrow(layout: GenericLayoutType, name: str, insert: UVec = NULLVEC, size: float = 1.0,
              rotation: float = 0, *, dxfattribs=None) -> Vec2
                     Render arrow as basic DXF entities into layout.

              virtual_entities(name: str, insert: UVec = NULLVEC, size: float = 0.625, rotation: float = 0, *,
              dxfattribs=None) -> Iterator[DXFGraphic]
                     Returns all arrow components as virtual DXF entities.

   Hatching
       This module provides rendering support for hatch patterns as used in Hatch and MPolygon entities.

   High Level Functions
       ezdxf.render.hatching.hatch_entity(polygon: DXFPolygon, filter_text_boxes=True, jiggle_origin: bool =
       True) -> Iterator[tuple[Vec3, Vec3]]
              Yields  the  hatch pattern of the given HATCH or MPOLYGON entity as 3D lines.  Each line is a pair
              of Vec3 instances as start- and end vertex, points are represented as lines of zero length,  which
              means the start vertex is equal to the end vertex.

              The  function yields nothing if polygon has a solid- or gradient filling or does not have a usable
              pattern assigned.

              ParameterspolygonHatch or MPolygon entity

                     • filter_text_boxes – ignore text boxes if Truejiggle_origin – move pattern line origins a small amount to avoid intersections in corner
                       points which causes errors in patterns

       ezdxf.render.hatching.hatch_polygons(baseline: HatchBaseLine, polygons: Sequence[Sequence[Vec2]],
       terminate: Callable[[], bool] | None = None) -> Iterator[Line]
              Yields all pattern lines for all hatch lines generated by the  given  HatchBaseLine,  intersecting
              the  given  2D  polygons as Line instances.  The polygons should represent a single entity with or
              without holes, the order of the polygons  and  their  winding  orientation  (cw  or  ccw)  is  not
              important. Entities which do not intersect or overlap should be handled separately!

              Each polygon is a sequence of Vec2 instances, they are treated as closed polygons even if the last
              vertex is not equal to the first vertex.

              The hole detection is done by a simple inside/outside counting algorithm and far from perfect, but
              is able to handle ordinary polygons well.

              The  terminate function WILL BE CALLED PERIODICALLY AND should return True to terminate execution.
              This can be used to implement a timeout, which can be required if  using  a  very  small  hatching
              distance, especially if you get the data from untrusted sources.

              ParametersbaselineHatchBaseLinepolygons  –  multiple  sequences  of  Vec2  instances  of  a  single entity, the order of
                       exterior- and hole paths and the  winding  orientation  (cw  or  ccw)  of  paths  is  not
                       important

                     • terminate  –  callback  function  which  is called periodically and should return True to
                       terminate the hatching function

       ezdxf.render.hatching.hatch_paths(baseline: HatchBaseLine, paths: Sequence[Path], terminate: Callable[[],
       bool] | None = None) -> Iterator[Line]
              Yields all pattern lines for all hatch lines generated by the  given  HatchBaseLine,  intersecting
              the  given  2D  Path  instances  as  Line  instances.  The paths are handled as projected into the
              xy-plane the z-axis of path vertices will be ignored if present.

              Same as the hatch_polygons() function, but  for  Path  instances  instead  of  polygons  build  of
              vertices.  This  function does not flatten the paths into vertices, instead the real intersections
              of the Bézier curves and the hatch lines are calculated.

              For more information see the docs of the hatch_polygons() function.

              ParametersbaselineHatchBaseLinepaths – sequence of Path instances of a single entity, the order of  exterior-  and  hole
                       paths and the winding orientation (cw or ccw) of the paths is not important

                     • terminate  –  callback  function  which  is called periodically and should return True to
                       terminate the hatching function

   Classes
       class ezdxf.render.hatching.HatchBaseLine(origin: Vec2, direction: Vec2, offset: Vec2, line_pattern:
       list[float] | None = None, min_hatch_line_distance=MIN_HATCH_LINE_DISTANCE)
              A hatch baseline defines the source line for hatching a geometry.  A complete hatch pattern  of  a
              DXF entity can consist of one or more hatch baselines.

              Parametersorigin – the origin of the hatch line as Vec2 instance

                     • direction – the hatch line direction as Vec2 instance, must not (0, 0)

                     • offset – the offset of the hatch line origin to the next or to the previous hatch line

                     • line_pattern – line pattern as sequence of floats, see also PatternRenderermin_hatch_line_distance   –   minimum   hatch   line   distance   to  render,  raises  an
                       DenseHatchingLinesError exception if the distance between hatch  lines  is  smaller  than
                       this value

              RaisesHatchLineDirectionError – hatch baseline has no direction, (0, 0) vector

                     • DenseHatchingLinesError – hatching lines are too narrow

              hatch_line(distance: float) -> HatchLine
                     Returns the HatchLine at the given signed distance.

              pattern_renderer(distance: float) -> PatternRenderer
                     Returns the PatternRenderer for the given signed distance.

              signed_distance(point: Vec2) -> float
                     Returns the signed normal distance of the given point from this hatch baseline.

       class ezdxf.render.hatching.HatchLine(origin: Vec2, direction: Vec2, distance: float)
              Represents a single hatch line.

              Parametersorigin – the origin of the hatch line as Vec2 instance

                     • direction – the hatch line direction as Vec2 instance, must not (0, 0)

                     • distance – the normal distance to the base hatch line as float

              intersect_line(a: Vec2, b: Vec2, dist_a: float, dist_b: float) -> Intersection
                     Returns  the  Intersection  of  this hatch line and the line defined by the points a and b.
                     The arguments dist_a and dist_b are the signed normal distances of the points a and b  from
                     the  hatch  baseline.   The normal distances from the baseline are easy to calculate by the
                     HatchBaseLine.signed_distance() method and allow  a  fast  intersection  calculation  by  a
                     simple point interpolation.

                     Parametersa – start point of the line as Vec2 instance

                            • b – end point of the line as Vec2 instance

                            • dist_a – normal distance of point a to the hatch baseline as float

                            • dist_b – normal distance of point b to the hatch baseline as float

              intersect_cubic_bezier_curve(curve: Bezier4P) -> Sequence[Intersection]
                     Returns 0 to 3 Intersection points of this hatch line with a cubic Bèzier curve.

                     Parameters
                            curve – the cubic Bèzier curve as ezdxf.math.Bezier4P instance

       class ezdxf.render.hatching.PatternRenderer(hatch_line: HatchLine, pattern: Sequence[float])
              The  hatch  pattern  of  a  DXF  entity  has  one  or more HatchBaseLine instances with an origin,
              direction, offset and line pattern.  The PatternRenderer for a certain distance from the  baseline
              has to be acquired from the HatchBaseLine by the pattern_renderer() method.

              The  origin  of  the  hatch line is the starting point of the line pattern. The offset defines the
              origin of the adjacent hatch line and doesn’t have to be orthogonal to the hatch line direction.

              Line Pattern

              The line pattern is a sequence of floats, where a value > 0.0 is a dash, a value < 0.0  is  a  gap
              and value of 0.0 is a point.

              Parametershatch_lineHatchLinepattern – the line pattern as sequence of float values

              render(start: Vec2, end: Vec2) -> Iterator[tuple[Vec2, Vec2]]
                     Yields the pattern lines as pairs of Vec2 instances from the start- to the end point on the
                     hatch  line.   For  points  the  start- and end point are the same Vec2 instance and can be
                     tested by the is operator.

                     The start- and end points should be located collinear at the hatch line of  this  instance,
                     otherwise the points a projected onto this hatch line.

       class ezdxf.render.hatching.Intersection(type: IntersectionType = IntersectionType.NONE, p0: Vec2 =
       Vec2(nan, nan), p1: Vec2 = Vec2(nan, nan))
              Represents an intersection.

              type   intersection type as IntersectionType instance

              p0     (first) intersection point as Vec2 instance

              p1     second intersection point as Vec2 instance, only if type is COLLINEAR

       class ezdxf.render.hatching.IntersectionType(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)

              NONE   no intersection

              REGULAR
                     regular intersection point at a polygon edge or a Bèzier curve

              START  intersection point at the start vertex of a polygon edge

              END    intersection point at the end vertex of a polygon edge

              COLLINEAR
                     intersection is collinear to a polygon edge

       class ezdxf.render.hatching.Line(start: 'Vec2', end: 'Vec2', distance: 'float')

              start  start point as Vec2 instance

              end    end point as Vec2 instance

              distance
                     signed normal distance to the HatchBaseLine

   Helper Functions
       ezdxf.render.hatching.hatch_boundary_paths(polygon: DXFPolygon, filter_text_boxes=True) -> list[Path]
              Returns  the  hatch  boundary  paths  as ezdxf.path.Path instances of HATCH and MPOLYGON entities.
              Ignores text boxes if argument filter_text_boxes is True.

       ezdxf.render.hatching.hatch_line_distances(point_distances: Sequence[float], normal_distance: float) ->
       list[float]
              Returns all hatch line distances in the range of the given point distances.

       ezdxf.render.hatching.pattern_baselines(polygon: DXFPolygon, min_hatch_line_distance: float =
       MIN_HATCH_LINE_DISTANCE, *, jiggle_origin: bool = False) -> Iterator[HatchBaseLine]
              Yields the hatch pattern baselines of HATCH and MPOLYGON entities as HatchBaseLine instances.  Set
              jiggle_origin to True to move pattern line origins a small amount to avoid intersections in corner
              points which causes errors in patterns.

   Exceptions
       class ezdxf.render.hatching.HatchingError
              Base exception class of the hatching module.

       class ezdxf.render.hatching.HatchLineDirectionError
              Hatching direction is undefined or a (0, 0) vector.

       class ezdxf.render.hatching.DenseHatchingLinesError
              Very small hatching distance which creates too many hatching lines.

ADD-ONS

   Drawing / Export Add-on
       This add-on provides the functionality to render a DXF document to produce a rasterized or vector-graphic
       image which can be saved to a file or viewed interactively depending on the backend being used.

       The module provides two example scripts in the folder examples/addons/drawing which can be  run  to  save
       rendered images to files or view an interactive visualisation.

          $ ./draw_cad.py --supported_formats
          # will list the file formats supported by the matplotlib backend.
          # Many formats are supported including vector graphics formats
          # such as pdf and svg

          $ ./draw_cad.py <my_file.dxf> --out image.png

          # draw a layout other than the model space
          $ ./draw_cad.py <my_file.dxf> --layout Layout1 --out image.png

          # opens a GUI application to view CAD files
          $ ./cad_viewer.py

       SEE ALSO:
          How-to section for the FAQ about the Drawing Add-on.

   Design
       The  implementation  of the drawing add-on is divided into a frontend and multiple backends. The frontend
       handles the translation of DXF features  and  properties  into  simplified  structures,  which  are  then
       processed by the backends.

   Common Limitations to all Backends
       • rich text formatting of the MTEXT entity is close to AutoCAD but not pixel perfect

       • relative size of POINT entities cannot be replicated exactly

       • rendering of ACIS entities is not supported

       • no 3D rendering engine, therefore:

            • 3D entities are projected into the xy-plane and 3D text is not supported

            • only top view rendering of the modelspace

            • VIEWPORTS are always rendered as top view

            • no visual style support

       • only basic support for:

         • infinite lines (rendered as lines with a finite length)

         • OLE2FRAME entities (rendered as rectangles)

         • vertical text (will render as horizontal text)

         • rendering of additional MTEXT columns may be incorrect

   MatplotlibBackend
       The MatplotlibBackend is used by the Draw command of the ezdxf launcher.

       Example for the usage of the Matplotlib backend:

          import sys
          import matplotlib.pyplot as plt
          from ezdxf import recover
          from ezdxf.addons.drawing import RenderContext, Frontend
          from ezdxf.addons.drawing.matplotlib import MatplotlibBackend

          # Safe loading procedure (requires ezdxf v0.14):
          try:
              doc, auditor = recover.readfile('your.dxf')
          except IOError:
              print(f'Not a DXF file or a generic I/O error.')
              sys.exit(1)
          except ezdxf.DXFStructureError:
              print(f'Invalid or corrupted DXF file.')
              sys.exit(2)

          # The auditor.errors attribute stores severe errors,
          # which may raise exceptions when rendering.
          if not auditor.has_errors:
              fig = plt.figure()
              ax = fig.add_axes([0, 0, 1, 1])
              ctx = RenderContext(doc)
              out = MatplotlibBackend(ax)
              Frontend(ctx, out).draw_layout(doc.modelspace(), finalize=True)
              fig.savefig('your.png', dpi=300)

       Simplified render workflow but with less control:

          from ezdxf import recover
          from ezdxf.addons.drawing import matplotlib

          # Exception handling left out for compactness:
          doc, auditor = recover.readfile('your.dxf')
          if not auditor.has_errors:
              matplotlib.qsave(doc.modelspace(), 'your.png')

   PyQtBackend
       class ezdxf.addons.drawing.pyqt.PyQtBackend(scene=None)
              Backend  which  uses the PySide6 package to implement an interactive viewer. The PyQt5 package can
              be used as fallback if the PySide6 package is not available.

              Parameters
                     scene -- drawing canvas of type QtWidgets.QGraphicsScene, if None  a  new  canvas  will  be
                     created

       The PyQtBackend is used by the View command of the ezdxf launcher.

       SEE ALSO:
          The  qtviewer.py  module implements the core of a simple DXF viewer and the cad_viewer.py example is a
          skeleton to show how to launch the CADViewer class.

   Recorder
       New in version 1.1.

       This is a special backend which records the output of the Frontend class  in  compact  numpy  arrays  and
       these  recordings  and  can  be  played by a Player instance on one or more backends.  The recorded numpy
       arrays support measurement of bounding boxes and transformations which is for some backends a requirement
       to place the DXF content on size limited pages.

       class ezdxf.addons.drawing.recorder.Recorder
              Records the output of the Frontend class.

              The class implements the BackendInterface but does not record  enter_entity(),  exit_entity()  and
              clear() events.

              player() -> Player
                     Returns  a  Player  instance  with  the  original recordings! Make a copy of this player to
                     protect the original recordings from being modified:

                        safe_player = recorder.player().copy()

       class ezdxf.addons.drawing.recorder.Player
              Plays the recordings of the Recorder backend on another backend.

              bbox() -> BoundingBox2d
                     Returns the bounding box of all records as BoundingBox2d.

              copy() -> Self
                     Returns a copy of the player with non-shared recordings.

              crop_rect(p1: UVec, p2: UVec, distance: float) -> None
                     Crop recorded shapes inplace by a rectangle defined by two points.

                     The argument distance defines the approximation  precision  for  paths  which  have  to  be
                     approximated  as  polylines  for  cropping  but only paths which are really get cropped are
                     approximated, paths that are fully inside the crop box will not be approximated.

                     Parametersp1 -- first corner of the clipping rectangle

                            • p2 -- second corner of the clipping rectangle

                            • distance -- maximum distance from the center of the curve to  the  center  of  the
                              line  segment between two approximation points to determine if a segment should be
                              subdivided.

              recordings() -> Iterator[tuple[RecordType, BackendProperties, Any]]
                     Yields all recordings as (RecordType, BackendProperties, Data) tuples.

                     The content of the Data field is determined by the enum RecordType:

                     • RecordType.POINTS returns a NumpyPoints2d instance, len() == 1 is a point, len() == 2  is
                       a line, len() > 2 is a filled polygon

                     • RecordType.SOLID_LINES  returns  a  NumpyPoints2d  instance  where  each  pair  (n,  n+1)
                       represents the start- and end point of a line

                     • RecordType.PATH: returns a NumpyPath2d instance that represents a linear 2D path

                     • RecordType.FILLED_PATHS returns a tuple (exterior_paths, holes), where exterior_paths and
                       holes are tuples of NumpyPath2d.

              replay(backend: BackendInterface, override: Callable[[BackendProperties], Override] | None = None)
              -> None
                     Replay the recording on another backend that implements the BackendInterface. The  optional
                     override function can be used to override the properties and state of data records, it gets
                     the BackendProperties as input and must return an Override instance.

              transform(m: Matrix44) -> None
                     Transforms the recordings inplace by a transformation matrix m of type Matrix44.

       class ezdxf.addons.drawing.recorder.Override(properties: BackendProperties, is_visible: bool = True)
              Represents the override state for a data record.

              properties
                     original or modified BackendProperties

                     Type   ezdxf.addons.drawing.properties.BackendProperties

              is_visible
                     override visibility e.g. switch layers on/off

                     Type   bool

       class ezdxf.addons.drawing.recorder.RecordType(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              Enum, determines the data record type.

              POINTS

              SOLID_LINES

              PATH

              FILLED_PATHS

   Layout
       New in version 1.1.

       The  Layout  class builds the page layout and the matrix to transform the DXF content to page coordinates
       according to the layout Settings.  The DXF coordinate transformation is required for PDF and HPGL/2 which
       expects the output coordinates in the first quadrant and SVG which has an inverted y-axis.

       The Layout class uses following classes and enums for configuration:

       • Page - page definition

       • Margins - page margins definition

       • Settings  - configuration settings

       • Units  - enum for page units

       class ezdxf.addons.drawing.layout.Page(width: float, height: float, units: Units = Units.mm, margins:
       Margins = (0, 0, 0, 0), max_width: float = 0.0, max_height: float = 0.0)
              Page definition class

              width  page width, 0 for auto-detect

                     Type   float

              height page height, 0 for auto-detect

                     Type   float

              units  page units as enum Units

                     Type   ezdxf.addons.drawing.layout.Units

              margins
                     page margins in page units

                     Type   ezdxf.addons.drawing.layout.Margins

              max_width
                     limit width for auto-detection, 0 for unlimited

                     Type   float

              max_height
                     limit height for auto-detection, 0 for unlimited

                     Type   float

              property is_landscape: bool
                     Returns True if the page has landscape orientation.

              property is_portrait: bool
                     Returns True if the page has portrait orientation. (square is portrait)

              to_landscape() -> None
                     Converts the page to landscape orientation.

              to_portrait() -> None
                     Converts the page to portrait orientation.

       class ezdxf.addons.drawing.layout.Margins(top: float, right: float, bottom: float, left: float)
              Page margins definition class

              top

                     Type   float

              left

                     Type   float

              bottom

                     Type   float

              right

                     Type   float

              classmethod all(margin: float) -> Self
                     Returns a page margins definition class with four equal margins.

              classmethod all2(top_bottom: float, left_right: float) -> Self
                     Returns a page margins definition class with equal top-bottom and left-right margins.

              scale(factor: float) -> Self

       class ezdxf.addons.drawing.layout.PageAlignment(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              Page alignment of content as enum.

              TOP_LEFT

              TOP_CENTER

              TOP_RIGHT

              MIDDLE_LEFT

              MIDDLE_CENTER

              MIDDLE_RIGHT

              BOTTOM_LEFT

              BOTTOM_CENTER

              BOTTOM_RIGHT

       class ezdxf.addons.drawing.layout.Settings(content_rotation: int = 0, fit_page: bool = True, scale: float
       = 1.0, page_alignment: PageAlignment = PageAlignment.MIDDLE_CENTER, crop_at_margins: bool = False,
       max_stroke_width: float = 0.001, min_stroke_width: float = 0.05, fixed_stroke_width: float = 0.15,
       output_coordinate_space: float = 1000000)
              The Layout settings.

              content_rotation
                     Rotate content about 0, 90,  180 or 270 degrees

                     Type   int

              fit_page
                     Scale content to fit the page.

                     Type   bool

              page_alignment
                     Supported by backends that use the Page class to define  the  size  of  the  output  media,
                     default alignment is PageAlignment.MIDDLE_CENTER

                     Type   ezdxf.addons.drawing.layout.PageAlignment

              crop_at_margins
                     crops  the  content  at the page margins if True, when supported by the backend, default is
                     False

                     Type   bool

              scale  Factor to scale the DXF units of model- or paperspace, to represent  1mm  in  the  rendered
                     output drawing. Only uniform scaling is supported.

                     e.g.  scale  1:100  and  DXF  units  are meters, 1m = 1000mm corresponds 10mm in the output
                     drawing = 10 / 1000 = 0.01;

                     e.g. scale 1:1; DXF units are mm = 1 / 1 = 1.0 the default value

                     The value is ignored if the page size is defined and the content  fits  the  page  and  the
                     value is also used to determine missing page sizes (width or height).

                     Type   float

              max_stroke_width
                     Used for LineweightPolicy.RELATIVE policy, max_stroke_width is defined as percentage of the
                     content extents, e.g. 0.001 is 0.1% of max(page-width, page-height)

                     Type   float

              min_stroke_width
                     Used  for  LineweightPolicy.RELATIVE  policy,  min_stroke_width is defined as percentage of
                     max_stroke_width, e.g. 0.05 is 5% of max_stroke_width

                     Type   float

              fixed_stroke_width
                     Used  for  LineweightPolicy.RELATIVE_FIXED  policy,  fixed_stroke_width   is   defined   as
                     percentage of max_stroke_width, e.g. 0.15 is 15% of max_stroke_width

                     Type   float

              output_coordinate_space
                     expert   feature   to  map  the  DXF  coordinates  to  the  output  coordinate  system  [0,
                     output_coordinate_space]

                     Type   float

       class ezdxf.addons.drawing.layout.Units(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              Page units as enum.

              inch   25.4 mm

              px     1/96 inch

              pt     1/72 inch

              mm

              cm

   SVGBackend
       New in version 1.1.

       class ezdxf.addons.drawing.svg.SVGBackend
              This is a native SVG rendering backend and does not require any external packages  to  render  SVG
              images other than the core dependencies.  This backend support content cropping at page margins.

              get_xml_root_element(page: Page, *, settings: Settings = layout.Settings(), render_box:
              BoundingBox2d | None = None) -> Element

              get_string(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d | None
              = None, xml_declaration=True) -> str
                     Returns the XML data as unicode string.

                     Parameterspage -- page definition, see Pagesettings -- layout settings, see Settingsrender_box -- set explicit region to render, default is content bounding box

                            • xml_declaration  -- inserts the "<?xml version='1.0' encoding='utf-8'?>" string in
                              front of the <svg> element

       Usage:

          from ezdxf.addons.drawing import Frontend, RenderContext
          from ezdxf.addons.drawing import layout, svg

          doc = ezdxf.readfile("your.dxf")
          msp = doc.modelspace()
          backend = svg.SVGBackend()
          Frontend(RenderContext(doc), backend).draw_layout(msp)

          with open("your.svg", "wt") as fp:
              fp.write(backend.get_string(layout.Page(0, 0))

   PyMuPdfBackend
       New in version 1.1.

       class ezdxf.addons.drawing.pymupdf.PyMuPdfBackend
              This backend uses the PyMuPdf package to create PDF,  PNG,  PPM  and  PBM  output.   This  backend
              support content cropping at page margins.

              PyMuPDF  is  licensed  under  the AGPL. Sorry, but it's the best package for the job I've found so
              far.

              Install package:

                 pip install pymupdf

              get_pdf_bytes(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d |
              None = None) -> bytes
                     Returns the PDF document as bytes.

                     Parameterspage -- page definition, see Pagesettings -- layout settings, see Settingsrender_box -- set explicit region to render, default is content bounding box

              get_pixmap_bytes(page: Page, *, fmt='png', settings: Settings = layout.Settings(), dpi: int = 96,
              alpha=False, render_box: BoundingBox2d | None = None) -> bytes
                     Returns a pixel image as bytes, supported image formats:
                                            ┌─────┬────────────────────────────────────┐
                                            │ png │ Portable Network Graphics          │
                                            ├─────┼────────────────────────────────────┤
                                            │ ppm │ Portable Pixmap (no alpha channel) │
                                            ├─────┼────────────────────────────────────┤
                                            │ pbm │ Portable Bitmap (no alpha channel) │
                                            └─────┴────────────────────────────────────┘

                     Parameterspage -- page definition, see Pagefmt -- image format

                            • settings -- layout settings, see Settingsdpi -- output resolution in dots per inch

                            • alpha -- add alpha channel (transparency)

                            • render_box -- set explicit region to render, default is content bounding box

       Usage:

          import ezdxf
          from ezdxf.addons.drawing import Frontend, RenderContext
          from ezdxf.addons.drawing import layout, pymupdf

          doc = ezdxf.readfile("your.dxf")
          msp = doc.modelspace()
          backend = pymupdf.PyMuPdfBackend()
          Frontend(RenderContext(doc), backend).draw_layout(msp)

          with open("your.pdf", "wb") as fp:
              fp.write(backend.get_pdf_bytes(layout.Page(0, 0))

       Load the output of the PyMuPdfBackend into the Image class of the Pillow package for  further  processing
       or to output additional image formats:

          import io
          from PIL import Image

          ...  # see above

          # the ppm format is faster to process than png
          fp = io.BytesIO(backend.get_pixmap_bytes(layout.Page(0, 0), fmt="ppm", dpi=300))
          image = Image.open(fp, formats=["ppm"])

   PlotterBackend
       New in version 1.1.

       class ezdxf.addons.drawing.hpgl2.PlotterBackend
              The  PlotterBackend creates HPGL/2 plot files for output on raster plotters. This backend does not
              need any additional packages.  This backend support content cropping at page margins.

              The plot files are tested by the plot file viewer ViewCompanion Standard but not on real  hardware
              - please use with care and give feedback.

              get_bytes(page: Page, *, settings: Settings = layout.Settings(), render_box: BoundingBox2d | None
              = None, curves=True, decimal_places: int = 1, base=64) -> bytes
                     Returns the HPGL/2 data as bytes.

                     Parameterspage -- page definition, see Pagesettings -- layout settings, see Settingsrender_box -- set explicit region to render, default is content bounding box

                            • curves -- use Bèzier curves for HPGL/2 output

                            • decimal_places  --  HPGL/2  output  precision, less decimal places creates smaller
                              files but for the price of imprecise curves (text)

                            • base -- base for polyline encoding, 32 for 7 bit encoding or 64 for 8 bit encoding

              compatible(page: Page, settings: Settings = layout.Settings()) -> bytes
                     Returns the HPGL/2 data as  7-bit  encoded  bytes  curves  as  approximated  polylines  and
                     coordinates  are rounded to integer values.  Has often the smallest file size and should be
                     compatible to all output devices but has a low quality text rendering.

              low_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
                     Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier curves and coordinates are
                     rounded to integer values.  Has a smaller file size than  normal  quality  and  the  output
                     device must support 8-bit encoding and Bèzier curves.

              normal_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
                     Returns the HPGL/2 data as 8-bit encoded bytes, curves as Bézier curves and coordinates are
                     floats  rounded  to  one  decimal place.  Has a smaller file size than high quality and the
                     output device must support 8-bit encoding, Bèzier curves and fractional coordinates.

              high_quality(page: Page, settings: Settings = layout.Settings()) -> bytes
                     Returns the HPGL/2 data as 8-bit  encoded  bytes  and  all  curves  as  Bézier  curves  and
                     coordinates  are  floats  rounded to two decimal places.  Has the largest file size and the
                     output device must support 8-bit encoding, Bèzier curves and fractional coordinates.

       Usage:

          import ezdxf
          from ezdxf.addons.drawing import Frontend, RenderContext
          from ezdxf.addons.drawing import layout, hpgl2

          doc = ezdxf.readfile("your.dxf")
          psp = doc.paperspace("Layout1")
          backend = hpgl2.PlotterBackend()
          Frontend(RenderContext(doc), backend).draw_layout(psp)
          page = layout.Page.from_dxf_layout(psp)

          with open("your.plt", "wb") as fp:
              fp.write(backend.normal_quality(page)

       You can check the output by the HPGL/2 viewer:

          ezdxf hpgl your.plt

   DXFBackend
       New in version 1.1.

       class ezdxf.addons.drawing.dxf.DXFBackend(layout: BaseLayout, color_mode: ColorMode = ColorMode.RGB)
              The DXFBackend creates simple DXF files of  POINT,  LINE,  LWPOLYLINE  and  HATCH  entities.  This
              backend does ot need any additional packages.

              Parameterslayout -- a DXF BaseLayoutcolor_mode -- see ColorMode

       class ezdxf.addons.drawing.dxf.ColorMode(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              This enum is used to define the color output mode of the DXFBackend.

              ACI    the color is set as AutoCAD Color Index (ACI) and assigned by layer

              RGB    the color is set as RGB true color value

       Render a paperspace layout into modelspace:

          import ezdxf
          from ezdxf.addons.drawing import Frontend, RenderContext
          from ezdxf.addons.drawing import layout, dxf

          doc = ezdxf.readfile("your.dxf")
          layout1 = doc.paperspace("Layout1")
          output_doc = ezdxf.new()
          output_msp = output_doc.modelspace()

          backend = dxf.DXFBackend(output_msp)
          Frontend(RenderContext(doc), backend).draw_layout(layout1)

          output_doc.saveas("layout1_in_modelspace.dxf")

   Configuration
       Additional  options  for  the  drawing  add-on  can  be  passed  by  the  config argument of the Frontend
       constructor __init__(). Not every option will be supported by all backends.

       Usage:

          my_config = Configuration(lineweight_scaling=2)

       class ezdxf.addons.drawing.config.Configuration(pdsize: int | None = None, pdmode: int | None = None,
       measurement: Measurement | None = None, show_defpoints: bool = False, proxy_graphic_policy:
       ProxyGraphicPolicy = ProxyGraphicPolicy.SHOW, line_policy: LinePolicy = LinePolicy.ACCURATE,
       hatch_policy: HatchPolicy = HatchPolicy.NORMAL, infinite_line_length: float = 20, lineweight_scaling:
       float = 1.0, min_lineweight: float | None = None, min_dash_length: float = 0.1, max_flattening_distance:
       float = 0.01, circle_approximation_count: int = 128, hatching_timeout: float = 30.0,
       min_hatch_line_distance: float = 0.0001, color_policy: ColorPolicy = ColorPolicy.COLOR, custom_fg_color:
       str = '#000000', background_policy: BackgroundPolicy = BackgroundPolicy.DEFAULT, custom_bg_color: str =
       '#ffffff', lineweight_policy: LineweightPolicy = LineweightPolicy.ABSOLUTE, text_policy: TextPolicy =
       TextPolicy.FILLING)
              Configuration options for the drawing add-on.

              pdsize the size to draw POINT entities (in drawing units) set to None to  use  the  $PDSIZE  value
                     from the dxf document header
                                          ┌──────┬───────────────────────────────────────┐
                                          │ 0    │ 5% of draw area height                │
                                          ├──────┼───────────────────────────────────────┤
                                          │ <0   │ Specifies   a   percentage   of   the │
                                          │      │ viewport size                         │
                                          ├──────┼───────────────────────────────────────┤
                                          │ >0   │ Specifies an absolute size            │
                                          ├──────┼───────────────────────────────────────┤
                                          │ None │ use the $PDMODE value  from  the  dxf │
                                          │      │ document header                       │
                                          └──────┴───────────────────────────────────────┘

                     Type   int | None

              pdmode point styling mode (see POINT documentation)

                     see Point class documentation

                     Type   int | None

              measurement
                     whether to use metric or imperial units as enum ezdxf.enums.Measurement
                                          ┌──────┬───────────────────────────────────────┐
                                          │ 0    │ use imperial units (in, ft, yd, ...)  │
                                          ├──────┼───────────────────────────────────────┤
                                          │ 1    │ use metric units (ISO meters)         │
                                          ├──────┼───────────────────────────────────────┤
                                          │ None │ use  the  $MEASUREMENT value from the │
                                          │      │ dxf document header                   │
                                          └──────┴───────────────────────────────────────┘

                     Type   ezdxf.enums.Measurement | None

              show_defpoints
                     whether to show or filter out POINT entities on the defpoints layer

                     Type   bool

              proxy_graphic_policy
                     the action to take when a proxy graphic is encountered

                     Type   ezdxf.addons.drawing.config.ProxyGraphicPolicy

              line_policy
                     the method to use when drawing styled lines (eg dashed, dotted etc)

                     Type   ezdxf.addons.drawing.config.LinePolicy

              hatch_policy
                     the method to use when drawing HATCH entities

                     Type   ezdxf.addons.drawing.config.HatchPolicy

              infinite_line_length
                     the length to use when drawing infinite lines

                     Type   float

              lineweight_scaling
                     multiplies every lineweight by this factor; set this factor to 0.0 for a  constant  minimum
                     line  width  defined  by  the  min_lineweight  setting for all lineweights; the correct DXF
                     lineweight often looks too thick in SVG, so setting a factor < 1  can  improve  the  visual
                     appearance

                     Type   float

              min_lineweight
                     the minimum line width in 1/300 inch; set to None for let the backend choose.

                     Type   float | None

              min_dash_length
                     the minimum length for a dash when drawing a styled line (default value is arbitrary)

                     Type   float

              max_flattening_distance
                     Max  flattening  distance  in drawing units see Path.flattening documentation.  The backend
                     implementation should calculate an appropriate value, like 1 screen- or paper pixel on  the
                     output medium, but converted into drawing units. Sets Path() approximation accuracy

                     Type   float

              circle_approximation_count
                     Approximate  a  full  circle by n segments, arcs have proportional less segments. Only used
                     for approximation of arcs in banded polylines.

                     Type   int

              hatching_timeout
                     hatching timeout for a single entity, very dense hatching patterns can cause  a  very  long
                     execution time, the default timeout for a single entity is 30 seconds.

                     Type   float

              min_hatch_line_distance
                     minimum hatch line distance to render, narrower pattern lines are rendered as solid filling

                     Type   float

              color_policy

                     Type   ezdxf.addons.drawing.config.ColorPolicy

              custom_fg_color
                     Used  for  ColorPolicy.custom  policy,  custom foreground color as "#RRGGBBAA" color string
                     (RGB+alpha)

                     Type   str

              background_policy

                     Type   ezdxf.addons.drawing.config.BackgroundPolicy

              custom_bg_color
                     Used for BackgroundPolicy.custom policy,  custom  background  color  as  "#RRGGBBAA"  color
                     string (RGB+alpha)

                     Type   str

              lineweight_policy

                     Type   ezdxf.addons.drawing.config.LineweightPolicy

              text_policy

                     Type   ezdxf.addons.drawing.config.TextPolicy

              with_changes()
                     Returns a new frozen Configuration object with modified values.

   BackgroundPolicy
       class ezdxf.addons.drawing.config.BackgroundPolicy(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              This enum is used to define the background color.

              DEFAULT
                     as resolved by the Frontend class

              WHITE  white background

              BLACK  black background

              OFF    fully transparent background

              CUSTOM custom background color by Configuration.custom_bg_color

   ColorPolicy
       class ezdxf.addons.drawing.config.ColorPolicy(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              This enum is used to define how to determine the line/fill color.

              COLOR  as resolved by the Frontend class

              COLOR_SWAP_BW
                     as resolved by the Frontend class but swaps black and white

              COLOR_NEGATIVE
                     invert all colors

              MONOCHROME
                     maps all colors to gray scale in range [0%, 100%]

              MONOCHROME_DARK_BG
                     maps all colors to gray scale in range [30%, 100%], brightens colors for dark backgrounds

              MONOCHROME_LIGHT_BG
                     maps all colors to gray scale in range [0%, 70%], darkens colors for light backgrounds

              BLACK  maps all colors to black

              WHITE  maps all colors to white

              CUSTOM maps all colors to custom color Configuration.custom_fg_color

   HatchPolicy
       class ezdxf.addons.drawing.config.HatchPolicy(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              The action to take when a HATCH entity is encountered

              NORMAL render pattern and solid fillings

              IGNORE do not show HATCH entities at all

              SHOW_OUTLINE
                     show only the outline of HATCH entities

              SHOW_SOLID
                     show HATCH entities as solid filling regardless of the pattern

   LinePolicy
       class ezdxf.addons.drawing.config.LinePolicy(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)

              SOLID  draw all lines as solid regardless of the linetype style

              ACCURATE
                     render styled lines as accurately as possible

   LineweightPolicy
       class ezdxf.addons.drawing.config.LineweightPolicy(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              This enum is used to define how to determine the lineweight.

              ABSOLUTE
                     in mm as resolved by the Frontend class

              RELATIVE
                     lineweight is relative to page size

              RELATIVE_FIXED
                     fixed lineweight relative to page size for all strokes

   ProxyGraphicPolicy
       class ezdxf.addons.drawing.config.ProxyGraphicPolicy(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              The action to take when an entity with a proxy graphic is encountered

              NOTE:
                 To  get  proxy  graphics  support  proxy  graphics  have  to  be  loaded: Set the global option
                 ezdxf.options.load_proxy_graphics to True, which is the default value.

                 This can not prevent drawing proxy graphic inside of blocks, because this is beyond the  domain
                 of the drawing add-on!

              IGNORE do not display proxy graphics (skip_entity will be called instead)

              SHOW   if the entity cannot be rendered directly (e.g. if not implemented) but a proxy is present:
                     display the proxy

              PREFER display proxy graphics even for entities where direct rendering is available

   TextPolicy
       class ezdxf.addons.drawing.config.TextPolicy(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              This enum is used to define the text rendering.

              FILLING
                     text is rendered as solid filling (default)

              OUTLINE
                     text is rendered as outline paths

              REPLACE_RECT
                     replace text by a rectangle

              REPLACE_FILL
                     replace text by a filled rectangle

              IGNORE ignore text at all

   Properties
       class ezdxf.addons.drawing.properties.Properties
              An  implementation agnostic representation of DXF entity properties like color and linetype. These
              properties represent the actual values after resolving all DXF specific rules like "by layer", "by
              block" and so on.

              color  The actual color value of the DXF entity as "#RRGGBB" or "#RRGGBBAA" string. An alpha value
                     of "00" is opaque and "ff" is fully transparent.

              rgb    RGB values extract from the color value as tuple of integers.

              luminance
                     Perceived luminance calculated from the color value as float in the range [0.0, 1.0].

              linetype_name
                     The actual linetype name as string like "CONTINUOUS"

              linetype_pattern
                     The simplified DXF linetype pattern as tuple of floats, all  line  elements  and  gaps  are
                     values  greater  than  0.0  and  0.0  represents  a point. Line or point elements do always
                     alternate with gap elements: line-gap-line-gap-point-gap and the pattern always ends with a
                     gap.  The continuous line is an empty tuple.

              linetype_scale
                     The scaling factor as float to apply to the linetype_pattern.

              lineweight
                     The absolute lineweight to render in mm as float.

              is_visible
                     Visibility flag as bool.

              layer  The actual layer name the entity resides on as UPPERCASE string.

              font   The FontFace used for text rendering or None.

              filling
                     The actual Filling properties of the entity or None.

              units  The actual drawing units as InsertUnits enum.

   LayerProperties
       class ezdxf.addons.drawing.properties.LayerProperties
              Actual layer properties, inherits from class Properties.

              is_visible
                     Modified meaning: whether entities belonging to this layer should be drawn

              layer  Modified meaning: stores real layer name (mixed case)

   LayoutProperties
       class ezdxf.addons.drawing.properties.LayoutProperties
              Actual layout properties.

              name   Layout name as string

              units  Layout units as InsertUnits enum.

              property LayoutProperties.background_color: str
                     Returns the default layout background color.

              property LayoutProperties.default_color: str
                     Returns the default layout foreground color.

              property LayoutProperties.has_dark_background: bool
                     Returns True if the actual background-color is "dark".

              LayoutProperties.set_colors(bg: str, fg: str | None = None) -> None
                     Setup default layout colors.

                     Required color format "#RRGGBB" or including alpha transparency "#RRGGBBAA".

   RenderContext
       class ezdxf.addons.drawing.properties.RenderContext(doc: Drawing | None = None, *, ctb: str = '',
       export_mode: bool = False)
              The render context for the given DXF document. The RenderContext resolves the  properties  of  DXF
              entities from the context they reside in to actual values like RGB colors, transparency, linewidth
              and so on.

              A  given  ctb file (plot style file) overrides the default properties for all layouts, which means
              the plot style table stored in the layout is always ignored.

              Parametersdoc -- DXF document

                     • ctb -- path to a plot style table

                     • export_mode -- Whether to render the document as it would look when exported (plotted) by
                       a CAD application to a file such as pdf, or whether to render the document  as  it  would
                       appear inside a CAD application.

              resolve_aci_color(aci: int, resolved_layer: str) -> str
                     Resolve the aci color as hex color string: "#RRGGBB"

              resolve_all(entity: DXFGraphic) -> Properties
                     Resolve all properties of entity.

              resolve_color(entity: DXFGraphic, *, resolved_layer: str | None = None) -> str
                     Resolve the rgb-color of entity as hex color string: "#RRGGBB" or "#RRGGBBAA".

              resolve_filling(entity: DXFGraphic) -> Filling | None
                     Resolve filling properties (SOLID, GRADIENT, PATTERN) of entity.

              resolve_font(entity: DXFGraphic) -> FontFace | None
                     Resolve the text style of entity to a font name.  Returns None for the default font.

              resolve_layer(entity: DXFGraphic) -> str
                     Resolve the layer of entity, this is only relevant for entities inside of block references.

              resolve_layer_properties(layer: Layer) -> LayerProperties
                     Resolve layer properties.

              resolve_linetype(entity: DXFGraphic, *, resolved_layer: str | None = None) -> tuple[str,
              Sequence[float]]
                     Resolve  the  linetype of entity. Returns a tuple of the linetype name as upper-case string
                     and the simplified linetype pattern as tuple of floats.

              resolve_lineweight(entity: DXFGraphic, *, resolved_layer: str | None = None) -> float
                     Resolve the lineweight of entity in mm.

                     DXF stores the lineweight in mm times 100 (e.g. 0.13mm = 13).  The smallest line weight  is
                     0  and  the  biggest  line  weight  is 211.  The DXF/DWG format is limited to a fixed value
                     table, see: ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS

                     CAD applications draw lineweight 0mm as an undefined small value, to  prevent  backends  to
                     draw nothing for lineweight 0mm the smallest return value is 0.01mm.

              resolve_units() -> InsertUnits

              resolve_visible(entity: DXFGraphic, *, resolved_layer: str | None = None) -> bool
                     Resolve the visibility state of entity. Returns True if entity is visible.

              set_current_layout(layout: Layout, ctb: str = '')
                     Set the current layout and update layout specific properties.

              set_layer_properties_override(func: Callable[[Sequence[LayerProperties]], None] | None = None)
                     The  function  func is called with the current layer properties as argument after resetting
                     them, so the function can override the layer properties.

       The RenderContext class can be used isolated from the drawing add-on to resolve DXF properties.

   Frontend
       class ezdxf.addons.drawing.frontend.Frontend(ctx: RenderContext, out: BackendInterface, config:
       Configuration = Configuration.defaults(), bbox_cache: ezdxf.bbox.Cache = None)
              Drawing frontend for 2D backends, responsible for decomposing entities into graphic primitives and
              resolving entity properties.

              By passing the bounding box cache of the modelspace entities can speed  up  paperspace  rendering,
              because the frontend can filter entities which are not visible in the VIEWPORT. Even passing in an
              empty cache can speed up rendering time when multiple viewports need to be processed.

              Parametersctx -- the properties relevant to rendering derived from a DXF document

                     • out -- the 2D backend to draw to

                     • config -- settings to configure the drawing frontend and backend

                     • bbox_cache  -- bounding box cache of the modelspace entities or an empty cache which will
                       be filled dynamically when rendering multiple viewports or None to disable  bounding  box
                       caching at all

              log_message(message: str)
                     Log given message - override to alter behavior.

              skip_entity(entity: DXFEntity, msg: str) -> None
                     Called for skipped entities - override to alter behavior.

              override_properties(entity: DXFGraphic, properties: Properties) -> None
                     The  override_properties() filter can change the properties of an entity independent of the
                     DXF attributes.

                     This filter has access to the DXF attributes by  the  entity  object,  the  current  render
                     context,  and the resolved properties by the properties object. It is recommended to modify
                     only the properties object in this filter.

              draw_layout(layout: Layout, finalize: bool = True, *, filter_func: Callable[[DXFGraphic], bool] |
              None = None, layout_properties: LayoutProperties | None = None) -> None
                     Draw all entities of the given layout.

                     Draws the entities of the layout in the default or redefined  redraw-order  and  calls  the
                     finalize()  method  of the backend if requested.  The default redraw order is the ascending
                     handle order not the order the entities are stored in the layout.

                     The method skips invisible entities and  entities  for  which  the  given  filter  function
                     returns False.

                     Parameterslayout -- layout to draw of type Layoutfinalize  --  True  if  the  finalize()  method  of  the  backend should be called
                              automatically

                            • filter_func -- function to filter DXf entities, the function should  return  False
                              if a given entity should be ignored

                            • layout_properties -- override the default layout properties

   BackendInterface
       class ezdxf.addons.drawing.backend.BackendInterface
              Public interface definition for 2D rendering backends.

              For more information read the source code: backend.py

   Backend
       class ezdxf.addons.drawing.backend.Backend
              Abstract base class for concrete backend implementations and implements some default features.

              For more information read the source code: backend.py

   Details
       The  rendering  is performed in two stages. The frontend traverses the DXF document structure, converting
       each encountered entity into primitive drawing commands.  These commands  are  fed  to  a  backend  which
       implements the interface: Backend.

       Although the resulting images will not be pixel-perfect with AutoCAD (which was taken as the ground truth
       when developing this add-on) great care has been taken to achieve similar behavior in some areas:

       • The  algorithm  for determining color should match AutoCAD. However, the color palette is not stored in
         the DXF file, so the chosen colors may be different  to  what  is  expected.  The  RenderContext  class
         supports  passing  a  plot  style table (CTB-file) as custom color palette but uses the same palette as
         AutoCAD by default.

       • Text rendering is quite accurate, text positioning, alignment and  word  wrapping  are  very  faithful.
         Differences  may  occur  if a different font from what was used by the CAD application but even in that
         case, for supported backends, measurements are taken of the font being used to match text as closely as
         possible.

       • Visibility determination (based on which layers are visible) should match AutoCAD

       SEE ALSO:draw_cad.py for a simple use of this module

          • cad_viewer.py for an advanced use of this module

          • Notes on Rendering DXF Content for additional behaviours documented during the development  of  this
            add-on.

   Geo Interface
   Intended Usage
       The  intended usage of the ezdxf.addons.geo module is as tool to work with geospatial data in conjunction
       with dedicated geospatial applications and libraries and the module can  not  and  should  not  replicate
       their functionality.

       The  only  reimplemented  feature  is  the  most  common  WSG84  EPSG:3395 World Mercator projection, for
       everything else use the dedicated packages like:

       • pyproj - Cartographic projections and coordinate transformations library.

       • Shapely - Manipulation and analysis of geometric objects in the Cartesian plane.

       • PyShp - The Python Shapefile Library (PyShp) reads and writes ESRI Shapefiles in pure Python.

       • GeoJSON - GeoJSON interface for Python.

       • GDAL - Tools for programming and manipulating the GDAL Geospatial Data Abstraction Library.

       • Fiona - Fiona is GDAL’s neat and nimble vector API for Python programmers.

       • QGIS - A free and open source geographic information system.

       • and many more …

       This module provides support for the  __geo_interface__: https://gist.github.com/sgillies/2217756

       Which is also supported by Shapely, for  supported  types  see  the  GeoJSON  Standard  and  examples  in
       Appendix-A.

       SEE ALSO:
          Tutorial  for  the  Geo  Add-on  for  loading  GPX  data  into DXF files with an existing geo location
          reference and exporting DXF entities as GeoJSON data.

   Proxy From Mapping
       The GeoProxy represents a __geo_interface__ mapping, create a  new  proxy  by  GeoProxy.parse()  from  an
       external  __geo_interface__  mapping.   GeoProxy.to_dxf_entities()  returns  new  DXF  entities from this
       mapping.  Returns “Point” as Point entity,  “LineString” as LWPolyline  entity  and  “Polygon”  as  Hatch
       entity  or  as  separated  LWPolyline  entities  (or  both)  and  new  in  v0.16.6 as MPolygon.  Supports
       “MultiPoint”,     “MultiLineString”,     “MultiPolygon”,     “GeometryCollection”,     “Feature”      and
       “FeatureCollection”.  Add new DXF entities to a layout by the Layout.add_entity() method.

   Proxy From DXF Entity
       The proxy() function or the constructor GeoProxy.from_dxf_entities() creates a new GeoProxy object from a
       single  DXF  entity  or from an iterable of DXF entities, entities without a corresponding representation
       will be approximated.

       Supported DXF entities are:

       • POINT as “Point”

       • LINE as “LineString”

       • LWPOLYLINE as “LineString” if open and “Polygon” if closed

       • POLYLINE as “LineString” if open and “Polygon” if closed, supports only 2D and 3D  polylines,  POLYMESH
         and POLYFACE are not supported

       • SOLID, TRACE, 3DFACE as “Polygon”

       • CIRCLE, ARC, ELLIPSE and SPLINE by approximation as “LineString” if open and “Polygon” if closed

       • HATCH and MPOLYGON as “Polygon”, holes are supported

       WARNING:
          This  module  does  no  extensive  validity checks for “Polygon” objects and because DXF has different
          requirements for HATCH boundary paths than the GeoJSON Standard, it  is  possible  to  create  invalid
          “Polygon”  objects.   It  is recommended to check critical objects by a sophisticated geometry library
          like Shapely.

   Module Functions
       ezdxf.addons.geo.proxy(entity: DXFGraphic | Iterable[DXFGraphic], distance: float =
       MAX_FLATTENING_DISTANCE, force_line_string: bool = False) -> GeoProxy
              Returns a GeoProxy object.

              Parametersentity – a single DXF entity or iterable of DXF entities

                     • distance – maximum flattening distance for curve approximations

                     • force_line_string  –  by  default  this  function  returns  Polygon  objects  for  closed
                       geometries   like  CIRCLE,  SOLID,  closed  POLYLINE  and  so  on,  by  setting  argument
                       force_line_string to True, this entities will be returned as LineString objects.

       ezdxf.addons.geo.dxf_entities(geo_mapping: MutableMapping[str, Any], polygon=PolygonConversion.HATCH,
       dxfattribs=None, *, post_process: Callable[[DXFGraphic, MutableMapping[str, Any]], None] | None = None)
       -> Iterator[DXFGraphic]
              Returns __geo_interface__ mappings as DXF entities.

              The enum polygon determines the method to convert polygons, use PolygonConversion.HATCH for  Hatch
              entity,  PolygonConversion.POLYLINE  for  LWPolyline  or  PolygonConversion.HATCH_AND_POLYLINE for
              both.  Option PolygonConversion.POLYLINE returns for the exterior path and each hole  a  separated
              LWPolyline entity. The Hatch entity supports holes, but has no explicit borderline.

              Yields Hatch always before LWPolyline entities.

              PolygonConversion.MPOLYGON  support  was  added  in  v0.16.6,  which  is like a Hatch entity  with
              additional borderlines, but the MPOLYGON entity  is  not  a  core  DXF  entity  and  DXF  viewers,
              applications  and  libraries  my  not  support  this  entity.  The DXF attribute color defines the
              borderline color and fill_color the color of the solid filling.

              The returned DXF entities can be added to a layout by the Layout.add_entity() method.

              Parametersgeo_mapping__geo__interface__  mapping  as  dict  or  a   Python   object   with   a
                       __geo__interface__ property

                     • polygon – see PolygonConversiondxfattribs – dict with additional DXF attributes

                     • post_process  –  post  process  function  of type PostProcesFunc that get the created DXF
                       entity and the geo mapping as input, see reference implementation assign_layers()

       ezdxf.addons.geo.gfilter(entities: Iterable[DXFGraphic]) -> Iterator[DXFGraphic]
              Filter DXF entities from iterable  entities,  which  are  incompatible  to  the  __geo_reference__
              interface.

   GeoProxy Class
       class ezdxf.addons.geo.GeoProxy(geo_mapping: MutableMapping[str, Any], places: int = 6)
              Stores the __geo_interface__ mapping in a parsed and compiled form.

              Stores coordinates as Vec3 objects and represents “Polygon” always as tuple (exterior, holes) even
              without holes.

              The  GeoJSON specification recommends 6 decimal places for latitude and longitude which equates to
              roughly 10cm of precision. You may need slightly more for certain applications, 9  decimal  places
              would be sufficient for professional survey-grade GPS coordinates.

              Parametersgeo_mapping – parsed and compiled __geo_interface__ mapping

                     • places – decimal places to round for __geo_interface__ export

              __geo_interface__
                     Returns the __geo_interface__ compatible mapping as dict.

              geotype
                     Property returns the top level entity type or None.

              classmethod parse(geo_mapping: MutableMapping[str, Any]) -> Self
                     Parse  and  compile  a  __geo_interface__  mapping  as  dict  or  a  Python  object  with a
                     __geo_interface__ property, does some basic syntax checks, converts  all  coordinates  into
                     Vec3 objects, represents “Polygon” always as tuple (exterior, holes) even without holes.

              classmethod from_dxf_entities(entity: DXFGraphic | Iterable[DXFGraphic], distance: float =
              MAX_FLATTENING_DISTANCE, force_line_string: bool = False) -> GeoProxy
                     Constructor from a single DXF entity or an iterable of DXF entities.

                     Parametersentity – DXF entity or entities

                            • distance – maximum flattening distance for curve approximations

                            • force_line_string  –  by  default this function returns Polygon objects for closed
                              geometries like CIRCLE, SOLID, closed POLYLINE and  so  on,  by  setting  argument
                              force_line_string to True, this entities will be returned as LineString objects.

              to_dxf_entities(polygon=PolygonConversion.HATCH, dxfattribs=None, *, post_process:
              Callable[[DXFGraphic, MutableMapping[str, Any]], None] | None = None) -> Iterator[DXFGraphic]
                     Returns stored __geo_interface__ mappings as DXF entities.

                     The  polygon  argument determines the method to convert polygons, use 1 for Hatch entity, 2
                     for LWPolyline or 3 for both.  Option 2 returns for the  exterior  path  and  each  hole  a
                     separated  LWPolyline  entity.  The  Hatch  entity  supports  holes,  but  has  no explicit
                     borderline.

                     Yields Hatch always before LWPolyline entities.

                     MPolygon support was added in v0.16.6, which  is  like  a  Hatch  entity   with  additional
                     borderlines, but the MPOLYGON entity is not a core DXF entity and DXF viewers, applications
                     and  libraries  my  not support this entity. The DXF attribute color defines the borderline
                     color and fill_color the color of the solid filling.

                     The returned DXF entities can be added to a layout by the Layout.add_entity() method.

                     Parameterspolygon – see PolygonConversiondxfattribs – dict with additional DXF attributes

                            • post_process – post process function of type PostProcesFunc that get  the  created
                              DXF   entity   and   the  geo  mapping  as  input,  see  reference  implementation
                              assign_layers()

              copy() -> GeoProxy
                     Returns a deep copy.

              __iter__() -> Iterator[MutableMapping[str, Any]]
                     Iterate over all geometry entities.

                     Yields  only  “Point”,  “LineString”,  “Polygon”,   “MultiPoint”,   “MultiLineString”   and
                     “MultiPolygon”  objects,  returns  the content of “GeometryCollection”, “FeatureCollection”
                     and “Feature” as geometry objects (“Point”, …).

              wcs_to_crs(crs: Matrix44) -> None
                     Transform all coordinates recursive from WCS coordinates into Coordinate  Reference  System
                     (CRS) by transformation matrix crs inplace.

                     The  CRS  is  defined  by the GeoData entity, get the GeoData entity from the modelspace by
                     method get_geodata().  The CRS transformation matrix  can  be  acquired  form  the  GeoData
                     object by get_crs_transformation() method:

                        doc = ezdxf.readfile('file.dxf')
                        msp = doc.modelspace()
                        geodata = msp.get_geodata()
                        if geodata:
                            matrix, axis_ordering = geodata.get_crs_transformation()

                     If  axis_ordering  is False the CRS is not compatible with the __geo_interface__ or GeoJSON
                     (see chapter 3.1.1).

                     Parameters
                            crs – transformation matrix of type Matrix44

              crs_to_wcs(crs: Matrix44) -> None
                     Transform all coordinates recursive from CRS into WCS coordinates by transformation  matrix
                     crs inplace, see also GeoProxy.wcs_to_crs().

                     Parameters
                            crs – transformation matrix of type Matrix44

              globe_to_map(func: Callable[[Vec3], Vec3] | None = None) -> None
                     Transform  all coordinates recursive from globe representation in longitude and latitude in
                     decimal degrees into 2D map representation in meters.

                     Default  is  WGS84  EPSG:4326  (GPS)   to   WGS84   EPSG:3395   World   Mercator   function
                     wgs84_4326_to_3395().

                     Use the pyproj package to write a custom projection function as needed.

                     Parameters
                            func  –  custom transformation function, which takes one Vec3 object as argument and
                            returns the result as a Vec3 object.

              map_to_globe(func: Callable[[Vec3], Vec3] | None = None) -> None
                     Transform all coordinates recursive  from  2D  map  representation  in  meters  into  globe
                     representation as longitude and latitude in decimal degrees.

                     Default   is   WGS84   EPSG:3395   World   Mercator   to   WGS84   EPSG:4326  GPS  function
                     wgs84_3395_to_4326().

                     Use the pyproj package to write a custom projection function as needed.

                     Parameters
                            func – custom transformation function, which takes one Vec3 object as  argument  and
                            returns the result as a Vec3 object.

              apply(func: Callable[[Vec3], Vec3]) -> None
                     Apply the transformation function func recursive to all coordinates.

                     Parameters
                            func – transformation function as Callable[[Vec3], Vec3]

              filter(func: Callable[[GeoProxy], bool]) -> None
                     Removes  all  mappings  for  which  func()  returns False.  The function only has to handle
                     Point, LineString and Polygon entities, other entities like MultiPolygon are  divided  into
                     separate entities also any collection.

   Helper Functions
       ezdxf.addons.geo.wgs84_4326_to_3395(location: Vec3) -> Vec3
              Transform  WGS84  EPSG:4326 location given as latitude and longitude in decimal degrees as used by
              GPS into World Mercator cartesian 2D coordinates in meters EPSG:3395.

              Parameters
                     locationVec3 object, x-attribute represents the longitude value (East-West)  in  decimal
                     degrees and the y-attribute represents the latitude value (North-South) in decimal degrees.

       ezdxf.addons.geo.wgs84_3395_to_4326(location: Vec3, tol: float = 1e-6) -> Vec3
              Transform WGS84 World Mercator EPSG:3395 location given as cartesian 2D coordinates x, y in meters
              into WGS84 decimal degrees as longitude and latitude EPSG:4326 as used by GPS.

              ParameterslocationVec3 object, z-axis is ignored

                     • tol – accuracy for latitude calculation

       ezdxf.addons.geo.dms2dd(d: float, m: float = 0, s: float = 0) -> float
              Convert degree, minutes, seconds into decimal degrees.

       ezdxf.addons.geo.dd2dms(dd: float) -> tuple[float, float, float]
              Convert decimal degrees into degree, minutes, seconds.

       ezdxf.addons.geo.assign_layers(entity: DXFGraphic, mapping: MutableMapping[str, Any]) -> None
              Reference implementation for a post_process() function.

              SEE ALSO:
                 dxf_entities()

          def assign_layers(entity: DXFGraphic, mapping: GeoMapping) -> None:
              properties = mapping.get("properties)
              if properties is None:
                  return
              layer = properties.get("layer")
              if layer:
                  entity.dxf.layer = layer

   Types
       class ezdxf.addons.geo.PolygonConversion(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              Polygon conversion types as IntEnum.

              HATCH

              POLYLINE

              HATCH_AND_POLYLINE

              MPOLYGON

       ezdxf.addons.geo.GeoMapping
              alias of MutableMapping[str, Any]

       ezdxf.addons.geo.PostProcessFunc
              alias of Callable[[DXFGraphic, MutableMapping[str, Any]], None]

   Importer
       This  add-on  is  meant  to  import  graphical entities from another DXF drawing and their required table
       entries like LAYER, LTYPE or STYLE.

       Because of complex extensibility of the DXF format and the lack of sufficient documentation, I decided to
       remove most of the possible source  drawing  dependencies  from  imported  entities,  therefore  imported
       entities  may not look the same as the original entities in the source drawing, but at least the geometry
       should be the same and the DXF file does not break.

       Removed data which could contain source drawing dependencies: Extension Dictionaries, AppData and XDATA.

       WARNING:
          DON’T EXPECT PERFECT RESULTS!

       The Importer supports following data import:

          • entities which are really safe to import: LINE, POINT, CIRCLE,  ARC,  TEXT,  SOLID,  TRACE,  3DFACE,
            SHAPE,  POLYLINE,  ATTRIB,  ATTDEF,  INSERT, ELLIPSE, MTEXT, LWPOLYLINE, SPLINE, HATCH, MESH, XLINE,
            RAY, DIMENSION, LEADER, VIEWPORT

          • table and table entry import is restricted to LAYER, LTYPE, STYLE, DIMSTYLE

          • import of BLOCK definitions is supported

          • import of paper space layouts is supported

       Import of DXF objects from the OBJECTS section is not supported.

       DIMSTYLE override for entities DIMENSION and LEADER is not supported.

       Example:

          import ezdxf
          from ezdxf.addons import Importer

          sdoc = ezdxf.readfile('original.dxf')
          tdoc = ezdxf.new()

          importer = Importer(sdoc, tdoc)

          # import all entities from source modelspace into modelspace of the target drawing
          importer.import_modelspace()

          # import all paperspace layouts from source drawing
          importer.import_paperspace_layouts()

          # import all CIRCLE and LINE entities from source modelspace into an arbitrary target layout.
          # create target layout
          tblock = tdoc.blocks.new('SOURCE_ENTS')
          # query source entities
          ents = sdoc.modelspace().query('CIRCLE LINE')
          # import source entities into target block
          importer.import_entities(ents, tblock)

          # This is ALWAYS the last & required step, without finalizing the target drawing is maybe invalid!
          # This step imports all additional required table entries and block definitions.
          importer.finalize()

          tdoc.saveas('imported.dxf')

       class ezdxf.addons.importer.Importer(source: Drawing, target: Drawing)
              The Importer class is central element for importing data from other DXF documents.

              Parameterssource – source Drawingtarget – target Drawing

              source source DXF document

              target target DXF document

              used_layers
                     Set of used layer names as string, AutoCAD accepts layer names without a LAYER table entry.

              used_linetypes
                     Set of used linetype names as string, these linetypes require a TABLE entry or AutoCAD will
                     crash.

              used_styles
                     Set of used text style names, these text styles require  a  TABLE  entry  or  AutoCAD  will
                     crash.

              used_dimstyles
                     Set  of used dimension style names, these dimension styles require a TABLE entry or AutoCAD
                     will crash.

              finalize() -> None
                     Finalize the import by importing required table  entries  and  BLOCK  definitions,  without
                     finalization  the  target document is maybe invalid for AutoCAD. Call the finalize() method
                     as last step of the import process.

              import_block(block_name: str, rename=True) -> str
                     Import one BLOCK definition from source document.

                     If the BLOCK already exist the BLOCK will be renamed if argument rename is True,  otherwise
                     the  existing  BLOCK in the target document will be used instead of the BLOCK in the source
                     document.  Required name resolving for imported block references (INSERT), will be done  in
                     the Importer.finalize() method.

                     To  replace an existing BLOCK in the target document, just delete it before importing data:
                     target.blocks.delete_block(block_name, safe=False)

                     Parametersblock_name – name of BLOCK to import

                            • rename – rename BLOCK if a BLOCK with  the  same  name  already  exist  in  target
                              document

                     Returns: (renamed) BLOCK name

                     Raises ValueError – BLOCK in source document not found (defined)

              import_blocks(block_names: Iterable[str], rename=False) -> None
                     Import all BLOCK definitions from source document.

                     If  a  BLOCK  already exist the BLOCK will be renamed if argument rename is True, otherwise
                     the existing BLOCK in the target document will be used instead of the BLOCK from the source
                     document.  Required name resolving for imported BLOCK references (INSERT), will be done  in
                     the Importer.finalize() method.

                     Parametersblock_names – names of BLOCK definitions to import

                            • rename  –  rename  BLOCK  if  a  BLOCK  with the same name already exist in target
                              document

                     Raises ValueError – BLOCK in source document not found (defined)

              import_entities(entities: Iterable[DXFEntity], target_layout: BaseLayout | None = None) -> None
                     Import all entities into target_layout  or  the  modelspace  of  the  target  document,  if
                     target_layout is None.

                     Parametersentities – Iterable of DXF entities

                            • target_layout  –  any  layout  (modelspace,  paperspace  or block) from the target
                              document

                     Raises DXFStructureErrortarget_layout is not a layout of target document

              import_entity(entity: DXFEntity, target_layout: BaseLayout | None = None) -> None
                     Imports a single DXF entity into target_layout or the modelspace of the target document, if
                     target_layout is None.

                     Parametersentity – DXF entity to import

                            • target_layout – any layout (modelspace,  paperspace  or  block)  from  the  target
                              document

                     Raises DXFStructureErrortarget_layout is not a layout of target document

              import_modelspace(target_layout: BaseLayout | None = None) -> None
                     Import  all  entities  from  source  modelspace into target_layout or the modelspace of the
                     target document, if target_layout is None.

                     Parameters
                            target_layout – any  layout  (modelspace,  paperspace  or  block)  from  the  target
                            document

                     Raises DXFStructureErrortarget_layout is not a layout of target document

              import_paperspace_layout(name: str) -> Layout
                     Import paperspace layout name into the target document.

                     Recreates  the  source  paperspace  layout  in  the  target  document,  renames  the target
                     paperspace if a paperspace with same name already exist and imports all entities  from  the
                     source paperspace into the target paperspace.

                     Parameters
                            name – source paper space name as string

                     Returns: new created target paperspace Layout

                     RaisesKeyError – source paperspace does not exist

                            • DXFTypeError – invalid modelspace import

              import_paperspace_layouts() -> None
                     Import  all  paperspace layouts and their content into the target document.  Target layouts
                     will be renamed if a layout with the same name already exist. Layouts will be  imported  in
                     original tab order.

              import_shape_files(fonts: set[str]) -> None
                     Import  shape  file table entries from the source document into the target document.  Shape
                     file entries are stored in the styles table but without a name.

              import_table(name: str, entries: str | Iterable[str] = '*', replace=False) -> None
                     Import specific table entries from the source document into the target document.

                     Parametersname – valid table names are “layers”, “linetypes” and “styles”

                            • entries – Iterable of table names as strings, or a single table name  or  “*”  for
                              all table entries

                            • replaceTrue  to replace the already existing table entry else ignore existing
                              entries

                     Raises TypeError – unsupported table type

              import_tables(table_names: str | Iterable[str] = '*', replace=False) -> None
                     Import DXF tables from the source document into the target document.

                     Parameterstable_names – iterable of tables names as strings,  or  a  single  table  name  as
                              string or “*” for all supported tables

                            • replaceTrue  to  replace  already existing table entries else ignore existing
                              entries

                     Raises TypeError – unsupported table type

              recreate_source_layout(name: str) -> Layout
                     Recreate source paperspace layout name in the target document.  The layout will be  renamed
                     if  name  already  exist  in the target document. Returns target modelspace for layout name
                     “Model”.

                     Parameters
                            name – layout name as string

                     Raises KeyError – if source layout name not exist

   dxf2code
       Translate DXF entities and structures into Python source code.

       Short example:

          import ezdxf
          from ezdxf.addons.dxf2code import entities_to_code, block_to_code

          doc = ezdxf.readfile('original.dxf')
          msp = doc.modelspace()
          source = entities_to_code(msp)

          # create source code for a block definition
          block_source = block_to_code(doc.blocks['MyBlock'])

          # merge source code objects
          source.merge(block_source)

          with open('source.py', mode='wt') as f:
              f.write(source.import_str())
              f.write('\n\n')
              f.write(source.code_str())
              f.write('\n')

       ezdxf.addons.dxf2code.entities_to_code(entities: Iterable[DXFEntity], layout: str = 'layout', ignore:
       Iterable[str] | None = None) -> Code
              Translates DXF entities into Python source code to recreate this entities by ezdxf.

              Parametersentities – iterable of DXFEntity

                     • layout – variable name of the layout (model space or block) as string

                     • ignore – iterable of entities types to ignore as strings like ['IMAGE', 'DIMENSION']

              Returns
                     Code

       ezdxf.addons.dxf2code.block_to_code(block: BlockLayout, drawing: str = 'doc', ignore: Iterable[str] |
       None = None) -> Code
              Translates a BLOCK into Python source code to recreate the BLOCK by ezdxf.

              Parametersblock – block definition layout

                     • drawing – variable name of the drawing as string

                     • ignore – iterable of entities types to ignore as strings like [‘IMAGE’, ‘DIMENSION’]

              Returns
                     Code

       ezdxf.addons.dxf2code.table_entries_to_code(entities: Iterable[DXFEntity], drawing='doc') -> Code

       ezdxf.addons.dxf2code.black(code: str, line_length=88, fast: bool = True) -> str
              Returns the source code as a single string formatted by Black

              Requires the installed Black formatter:

                 pip3 install black

              Parameterscode – source code

                     • line_length – max. source code line length

                     • fastTrue for fast mode, False to check that the reformatted code is valid

              Raises ImportError – Black is not available

       class ezdxf.addons.dxf2code.Code
              Source code container.

              code   Source code line storage, store lines without line ending \\n

              imports
                     source code line storage for global imports, store lines without line ending \\n

              layers Layers used by the generated source code, AutoCAD accepts layer names without a LAYER table
                     entry.

              linetypes
                     Linetypes used by the generated source code, these  linetypes  require  a  TABLE  entry  or
                     AutoCAD will crash.

              styles Text  styles  used by the generated source code, these text styles require a TABLE entry or
                     AutoCAD will crash.

              dimstyles
                     Dimension styles  used by the generated source code, these dimension styles require a TABLE
                     entry or AutoCAD will crash.

              blocks Blocks used by the generated source code, these blocks require a BLOCK  definition  in  the
                     BLOCKS section or AutoCAD will crash.

              code_str(indent: int = 0) -> str
                     Returns the source code as a single string.

                     Parameters
                            indent – source code indentation count by spaces

              black_code_str(line_length=88) -> str
                     Returns the source code as a single string formatted by Black

                     Parameters
                            line_length – max. source code line length

                     Raises ImportError – Black is not available

              import_str(indent: int = 0) -> str
                     Returns required imports as a single string.

                     Parameters
                            indent – source code indentation count by spaces

              merge(code: Code, indent: int = 0) -> None
                     Add another Code object.

              add_import(statement: str) -> None
                     Add import statement, identical import statements are merged together.

              add_line(code: str, indent: int = 0) -> None
                     Add a single source code line without line ending \n.

              add_lines(code: Iterable[str], indent: int = 0) -> None
                     Add multiple source code lines without line ending \n.

   iterdxf
       This add-on allows iterating over entities of the modelspace of really big (> 5GB) DXF files which do not
       fit into memory by only loading one entity at the time. Only ASCII DXF files are supported.

       The  entities  are  regular DXFGraphic objects with access to all supported DXF attributes, this entities
       can be written to new DXF files created by the IterDXF.export()  method.   The  new  add_foreign_entity()
       method allows also to add this entities to new regular ezdxf drawings (except for the INSERT entity), but
       resources  like  linetype  and  style  are  removed,  only  layer will be preserved but only with default
       attributes like color 7 and linetype CONTINUOUS.

       The following example shows how to split a big DXF files into several separated DXF files which  contains
       only LINE, TEXT or POLYLINE entities.

          from ezdxf.addons import iterdxf

          doc = iterdxf.opendxf('big.dxf')
          line_exporter = doc.export('line.dxf')
          text_exporter = doc.export('text.dxf')
          polyline_exporter = doc.export('polyline.dxf')
          try:
              for entity in doc.modelspace():
                  if entity.dxftype() == 'LINE':
                      line_exporter.write(entity)
                  elif entity.dxftype() == 'TEXT':
                      text_exporter.write(entity)
                  elif entity.dxftype() == 'POLYLINE':
                      polyline_exporter.write(entity)
          finally:
              line_exporter.close()
              text_exporter.close()
              polyline_exporter.close()
              doc.close()

       Supported DXF types:

       3DFACE,  ARC,  ATTDEF,  ATTRIB,  CIRCLE,  DIMENSION,  ELLIPSE, HATCH, HELIX, IMAGE, INSERT, LEADER, LINE,
       LWPOLYLINE, MESH, MLEADER, MLINE, MTEXT, POINT, POLYLINE, RAY, SHAPE, SOLID, SPLINE, TEXT, TRACE, VERTEX,
       WIPEOUT, XLINE

       Transfer simple entities to another DXF document, this works for  some  supported  entities,  except  for
       entities  with  strong dependencies to the original document like INSERT look at add_foreign_entity() for
       all supported types:

          newdoc = ezdxf.new()
          msp = newdoc.modelspace()
          # line is an entity from a big source file
          msp.add_foreign_entity(line)
          # and so on ...
          msp.add_foreign_entity(lwpolyline)
          msp.add_foreign_entity(mesh)
          msp.add_foreign_entity(polyface)

       Transfer MESH and POLYFACE (dxftype for POLYFACE and POLYMESH is  POLYLINE!)  entities  into  a  new  DXF
       document by the MeshTransformer class:

          from ezdxf.render import MeshTransformer

          # mesh is MESH from a big source file
          t = MeshTransformer.from_mesh(mesh)
          # create a new MESH entity from MeshTransformer
          t.render(msp)

          # polyface is POLYFACE from a big source file
          t = MeshTransformer.from_polyface(polyface)
          # create a new POLYMESH entity from MeshTransformer
          t.render_polyface(msp)

       Another  way  to  import  entities from a big source file into new DXF documents is to split the big file
       into smaller parts and use the Importer add-on for a more safe entity import.

       ezdxf.addons.iterdxf.opendxf(filename: Path | str, errors: str = 'surrogateescape') -> IterDXF
              Open DXF file for iterating, be sure to open valid DXF files, no  DXF  structure  checks  will  be
              applied.

              Use this function to split up big DXF files as shown in the example above.

              Parametersfilename – DXF filename of a seekable DXF file.

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesDXFStructureError – invalid or incomplete DXF file

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       ezdxf.addons.iterdxf.modelspace(filename: Path | str, types: Iterable[str] | None = None, errors: str =
       'surrogateescape') -> Iterable[DXFGraphic]
              Iterate over all modelspace entities as DXFGraphic objects of a seekable file.

              Use  this  function to iterate “quick” over modelspace entities of a DXF file, filtering DXF types
              may speed up things if many entity types will be skipped.

              Parametersfilename – filename of a seekable DXF file

                     • types – DXF types like ['LINE', '3DFACE'] which should  be  returned,  None  returns  all
                       supported types.

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesDXFStructureError – invalid or incomplete DXF file

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       ezdxf.addons.iterdxf.single_pass_modelspace(stream: BinaryIO, types: Iterable[str] | None = None, errors:
       str = 'surrogateescape') -> Iterable[DXFGraphic]
              Iterate over all modelspace entities as DXFGraphic objects in a single pass.

              Use this function to ‘quick’ iterate over modelspace entities of a not seekable binary DXF stream,
              filtering DXF types may speed up things if many entity types will be skipped.

              Parametersstream – (not seekable) binary DXF stream

                     • types  –  DXF  types  like  ['LINE', '3DFACE'] which should be returned, None returns all
                       supported types.

                     • errors –

                       specify decoding error handler

                       • ”surrogateescape” to preserve possible binary data (default)

                       • ”ignore” to use the replacement char U+FFFD “�” for invalid data

                       • ”strict” to raise an UnicodeDecodeError exception for invalid data

              RaisesDXFStructureError – Invalid or incomplete DXF file

                     • UnicodeDecodeError – if errors is “strict” and a decoding error occurs

       class ezdxf.addons.iterdxf.IterDXF

              export(name: Path | str) -> IterDXFWriter
                     Returns a companion object to export parts from the source DXF file into another DXF  file,
                     the new file will have the same HEADER, CLASSES, TABLES, BLOCKS and OBJECTS sections, which
                     guarantees all necessary dependencies are present in the new file.

                     Parameters
                            name – filename, no special requirements

              modelspace(types: Iterable[str] | None = None) -> Iterable[DXFGraphic]
                     Returns  an  iterator  for all supported DXF entities in the modelspace. These entities are
                     regular DXFGraphic objects but without a valid document assigned. It is not possible to add
                     these entities to other ezdxf documents.

                     It is only possible to recreate the objects by factory functions base on attributes of  the
                     source  entity.   For MESH, POLYMESH and POLYFACE it is possible to use the MeshTransformer
                     class to render (recreate) this objects as new entities in another document.

                     Parameters
                            types – DXF types like ['LINE', '3DFACE'] which should be returned, None returns all
                            supported types.

              close()
                     Safe closing source DXF file.

       class ezdxf.addons.iterdxf.IterDXFWriter

              write(entity: DXFGraphic)
                     Write a DXF entity from the source DXF file to the export file.

                     Don’t write entities from different documents than the source DXF  file,  dependencies  and
                     resources  will not match, maybe it will work once, but not in a reliable way for different
                     DXF documents.

              close()
                     Safe closing of exported DXF file. Copying of OBJECTS section happens only at  closing  the
                     file, without closing the new DXF file is invalid.

   ODA File Converter Support
       Use an installed ODA File Converter for converting between different versions of .dwg, .dxb and .dxf.

       WARNING:
          Execution  of  an  external  application  is  a  big  security  issue! Especially when the path to the
          executable can be altered.

          To avoid this problem delete the ezdxf.addons.odafc.py module.

   Install ODA File Converter
       The ODA File Converter has to be installed by the user, the application  is  available  for  Windows  XP,
       Windows 7 or later, Mac OS X, and Linux in 32/64-bit RPM and DEB format.

   AppImage Support
       The  option  “unix_exec_path”  defines  an  executable for Linux and macOS, this executable overrides the
       default command ODAFileConverter.  Assign an absolute path to the executable  to  that  key  and  if  the
       executable is not found the add-on falls back to the ODAFileConverter command.

       The  option  “unix_exec_path”  also  adds  support  for  AppImages  provided by the Open Design Alliance.
       Download the AppImage file and store it in a folder of your  choice  (e.g.  ~/Apps)  and  make  the  file
       executable:

          chmod a+x ~/Apps/ODAFileConverter_QT5_lnxX64_8.3dll_23.9.AppImage

       Add the absolute path as config option “unix_exec_path” to the “odafc-addon” section:

          [odafc-addon]
          win_exec_path = "C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"
          unix_exec_path = "/home/<your user name>/Apps/ODAFileConverter_QT5_lnxX64_8.3dll_23.9.AppImage"

       This  overrides  the default command ODAFileConverter and if the executable is not found the add-on falls
       back to the ODAFileConverter command.

       SEE ALSO:
          For more information about config files see section: Global Options Object

   Suppressed GUI
       On Windows the GUI of the ODA File Converter is suppressed, on Linux you may have  to  install  the  xvfb
       package to prevent this, for macOS is no solution known.

   Supported DXF and DWG Versions
       ODA  File  Converter  version  strings,  you  can use any of this strings to specify a version, 'R..' and
       'AC....' strings will be automatically mapped to 'ACAD....' strings:
                                        ┌──────────┬───────────────┬─────────┐
                                        │ ODAFC    │ ezdxf         │ Version │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD9    │ not supported │ AC1004  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD10   │ not supported │ AC1006  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD12   │ R12           │ AC1009  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD13   │ R13           │ AC1012  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD14   │ R14           │ AC1014  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2000 │ R2000         │ AC1015  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2004 │ R2004         │ AC1018  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2007 │ R2007         │ AC1021  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2010 │ R2010         │ AC1024  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2013 │ R2013         │ AC1027  │
                                        ├──────────┼───────────────┼─────────┤
                                        │ ACAD2018 │ R2018         │ AC1032  │
                                        └──────────┴───────────────┴─────────┘

   Config
       On Windows  the  path  to  the  ODAFileConverter.exe  executable  is  stored  in  the  config  file  (see
       ezdxf.options) in the “odafc-addon” section as key “win_exec_path”, the default entry is:

          [odafc-addon]
          win_exec_path = "C:\Program Files\ODA\ODAFileConverter\ODAFileConverter.exe"
          unix_exec_path =

       On  Linux  and  macOS  the  ODAFileConverter command is located by the shutil.which() function but can be
       overridden since version 1.0 by the key “linux_exec_path”.

   Usage
          from ezdxf.addons import odafc

          # Load a DWG file
          doc = odafc.readfile('my.dwg')

          # Use loaded document like any other ezdxf document
          print(f'Document loaded as DXF version: {doc.dxfversion}.')
          msp = doc.modelspace()
          ...

          # Export document as DWG file for AutoCAD R2018
          odafc.export_dwg(doc, 'my_R2018.dwg', version='R2018')

       ezdxf.addons.odafc.win_exec_path
              Path to installed ODA File  Converter  executable  on  Windows  systems,  default  is  "C:\Program
              Files\ODA\ODAFileConverter\ODAFileConverter.exe".

       ezdxf.addons.odafc.unix_exec_path
              Absolute  path  to  a  Linux or macOS executable if set, otherwise an empty string and the default
              command ODAFileConverter is used.

       ezdxf.addons.odafc.is_installed() -> bool
              Returns True if the ODAFileConverter is installed.

       ezdxf.addons.odafc.readfile(filename: str | PathLike, version: str | None = None, *, audit: bool = False)
       -> Drawing | None
              Uses an installed ODA File Converter to convert a DWG/DXB/DXF file into a temporary DXF  file  and
              load this file by ezdxf.

              Parametersfilename – file to load by ODA File Converter

                     • version  –  load  file as specific DXF version, by default the same version as the source
                       file or if not detectable the latest by ezdxf supported version.

                     • audit – audit source file before loading

              RaisesFileNotFoundError – source file not found

                     • odafc.UnknownODAFCError – conversion failed for unknown reasons

                     • odafc.UnsupportedVersion – invalid DWG version specified

                     • odafc.UnsupportedFileFormat – unsupported file extension

                     • odafc.ODAFCNotInstalledError – ODA File Converter not installed

       ezdxf.addons.odafc.export_dwg(doc: Drawing, filename: str | PathLike, version: str | None = None, *,
       audit: bool = False, replace: bool = False) -> None
              Uses an installed ODA File Converter to export the DXF document doc as a DWG file.

              A temporary DXF file will be created and converted to DWG by the ODA File Converter. If version is
              not specified the DXF version of the source document is used.

              Parametersdocezdxf DXF document as Drawing object

                     • filename – output DWG filename, the extension will be set to “.dwg”

                     • version – DWG version to export, by default the same version as the source document.

                     • audit – audit source file by ODA File Converter at exporting

                     • replace – replace existing DWG file if True

              RaisesFileExistsError – target file already exists, and argument replace is
                           FalseFileNotFoundError – parent directory of target file does not exist

                     • odafc.UnknownODAFCError – exporting DWG failed for unknown reasons

                     • odafc.ODAFCNotInstalledError – ODA File Converter not installed

       ezdxf.addons.odafc.convert(source: str | PathLike, dest: str | PathLike = '', *, version='R2018',
       audit=True, replace=False)
              Convert source file to dest file.

              The file extension defines the target format e.g.  convert("test.dxf",  "Test.dwg")  converts  the
              source  file  to a DWG file.  If dest is an empty string the conversion depends on the source file
              format and is DXF to DWG or DWG to DXF.  To convert DXF to DXF an explicit destination filename is
              required: convert("r12.dxf", "r2013.dxf", version="R2013")

              Parameterssource – source file

                     • dest – destination file, an empty string uses the source filename with the  extension  of
                       the target format e.g. “test.dxf” -> “test.dwg”

                     • version – output DXF/DWG version e.g. “ACAD2018”, “R2018”, “AC1032”

                     • audit – audit files

                     • replace – replace existing destination file

              RaisesFileNotFoundError – source file or destination folder does not exist

                     • FileExistsError – destination file already exists and argument replace
                           is Falseodafc.UnsupportedVersion – invalid DXF version specified

                     • odafc.UnsupportedFileFormat – unsupported file extension

                     • odafc.UnknownODAFCError – conversion failed for unknown reasons

                     • odafc.ODAFCNotInstalledError – ODA File Converter not installed

   R12 Export
       New in version 1.1.

       This  module  exports any DXF file as a simple DXF R12 file. Many complex entities will be converted into
       DXF primitives.  This exporter is intended for creating a simple file format as an input format for other
       software such as laser cutters. In order to get a file that can be edited well in a CAD application,  the
       results of the ODA file converter are much better.

   Usage
          import ezdxf
          from ezdxf.addons import r12export

          doc = ezdxf.readfile("any.dxf")
          r12export.saveas(doc, "r12.dxf")

   Converted Entity Types
                               ┌─────────────┬───────────────────────────────────────┐
                               │ LWPOLYLINE  │ translated to POLYLINE                │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MESH        │ translated to POLYLINE (PolyfaceMesh) │
                               ├─────────────┼───────────────────────────────────────┤
                               │ SPLINE      │ flattened to POLYLINE                 │
                               ├─────────────┼───────────────────────────────────────┤
                               │ ELLIPSE     │ flattened to POLYLINE                 │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MTEXT       │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ LEADER      │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MLEADER     │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MULTILEADER │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MLINE       │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ HATCH       │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ MPOLYGON    │ exploded into DXF primitives          │
                               ├─────────────┼───────────────────────────────────────┤
                               │ ACAD_TABLE  │ export of pre-rendered BLOCK content  │
                               └─────────────┴───────────────────────────────────────┘

       For proxy- or unknown entities the available proxy graphic will be exported as DXF primitives.

   Limitations
       • Explosion of MTEXT into DXF primitives is not perfect

       • Pattern rendering for complex HATCH entities has issues

       • Solid fill rendering for complex HATCH entities has issues

   ODA File Converter
       The  advantage  of  the  r12export  module  is that the ODA file converter isn’t needed, but the ODA file
       converter will produce a much better result:

          from ezdxf.addons import odafc

          odafc.convert("any.dxf", "r12.dxf", version="R12")

   Functions
                                 ┌─────────┬───────────────────────────────────────┐
                                 │ write   │ Write a DXF document as  DXF  version │
                                 │         │ R12 to a text stream.                 │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ saveas  │ Write  a  DXF document as DXF version │
                                 │         │ R12 to a file.                        │
                                 ├─────────┼───────────────────────────────────────┤
                                 │ convert │ Export and reload DXF document as DXF │
                                 │         │ version R12.                          │
                                 └─────────┴───────────────────────────────────────┘

       ezdxf.addons.r12export.write(doc: Drawing, stream: TextIO, *, max_sagitta: float = MAX_SAGITTA) -> None
              Write a DXF document as DXF version R12 to a text stream. The max_sagitta argument determines  the
              accuracy of the curve flatting for SPLINE and ELLIPSE entities.

              Parametersdoc – DXF document to export

                     • stream – output stream, use doc.encoding as encoding

                     • max_sagitta  –  maximum  distance  from the center of the curve to the center of the line
                       segment between two approximation points to determine if a segment should be subdivided.

       ezdxf.addons.r12export.saveas(doc: Drawing, filepath: str | PathLike, *, max_sagitta: float =
       MAX_SAGITTA) -> None
              Write a DXF document as DXF version R12  to  a  file.  The  max_sagitta  argument  determines  the
              accuracy of the curve flatting for SPLINE and ELLIPSE entities.

              Parametersdoc – DXF document to export

                     • filepath – output filename

                     • max_sagitta  –  maximum  distance  from the center of the curve to the center of the line
                       segment between two approximation points to determine if a segment should be subdivided.

       ezdxf.addons.r12export.convert(doc: Drawing, *, max_sagitta: float = MAX_SAGITTA) -> Drawing
              Export and reload DXF document as DXF version R12.

              Writes the DXF document into a temporary file at the file-system and  reloads  this  file  by  the
              ezdxf.readfile() function.

   r12writer
       The  fast  file/stream  writer creates simple DXF R12 drawings with just an ENTITIES section. The HEADER,
       TABLES and BLOCKS sections are not present except FIXED-TABLES are written. Only LINE, CIRCLE, ARC, TEXT,
       POINT, SOLID, 3DFACE and POLYLINE entities are supported. FIXED-TABLES is a  predefined  TABLES  section,
       which will be written, if the init argument fixed_tables of R12FastStreamWriter is True.

       The  R12FastStreamWriter  writes  the  DXF  entities  as strings direct to the stream without creating an
       in-memory drawing and therefore the processing is very fast.

       Because of the lack of a BLOCKS section, BLOCK/INSERT can not be used.  Layers  can  be  used,  but  this
       layers  have  a  default  setting  color  =  7  (black/white) and linetype = 'Continuous'. If writing the
       FIXED-TABLES, some predefined text styles and line  types  are  available,  else  text  style  is  always
       'STANDARD' and line type is always 'ByLayer'.

       If using FIXED-TABLES, following predefined line types are available:

       • CONTINUOUS

       • CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____

       • CENTERX2 ________  __  ________  __  ________

       • CENTER2 ____ _ ____ _ ____ _ ____ _ ____

       • DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ _

       • DASHEDX2 ____  ____  ____  ____  ____  ____

       • DASHED2 _ _ _ _ _ _ _ _ _ _ _ _ _ _

       • PHANTOM ______  __  __  ______  __  __  ______

       • PHANTOMX2 ____________    ____    ____    ____________

       • PHANTOM2 ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___

       • DASHDOT __ . __ . __ . __ . __ . __ . __ . __

       • DASHDOTX2 ____  .  ____  .  ____  .  ____

       • DASHDOT2 _ . _ . _ . _ . _ . _ . _ . _

       • DOT .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .

       • DOTX2 .    .    .    .    .    .    .    .

       • DOT2 . . . . . . . . . . . . . . . . . . .

       • DIVIDE __ . . __ . . __ . . __ . . __ . . __

       • DIVIDEX2 ____  . .  ____  . .  ____  . .  ____

       • DIVIDE2 _ . _ . _ . _ . _ . _ . _ . _

       If using FIXED-TABLES, following predefined text styles are available:

       • OpenSans

       • OpenSansCondensed-Light

   Tutorial
       A simple example with different DXF entities:

          from random import random
          from ezdxf.addons import r12writer

          with r12writer("quick_and_dirty_dxf_r12.dxf") as dxf:
              dxf.add_line((0, 0), (17, 23))
              dxf.add_circle((0, 0), radius=2)
              dxf.add_arc((0, 0), radius=3, start=0, end=175)
              dxf.add_solid([(0, 0), (1, 0), (0, 1), (1, 1)])
              dxf.add_point((1.5, 1.5))

              # 2d polyline, new in v0.12
              dxf.add_polyline_2d([(5, 5), (7, 3), (7, 6)])

              # 2d polyline with bulge value, new in v0.12
              dxf.add_polyline_2d([(5, 5), (7, 3, 0.5), (7, 6)], format='xyb')

              # 3d polyline only, changed in v0.12
              dxf.add_polyline([(4, 3, 2), (8, 5, 0), (2, 4, 9)])

              dxf.add_text("test the text entity", align="MIDDLE_CENTER")

       A simple example of writing really many entities in a short time:

          from random import random
          from ezdxf.addons import r12writer

          MAX_X_COORD = 1000.0
          MAX_Y_COORD = 1000.0
          CIRCLE_COUNT = 1000000

          with r12writer("many_circles.dxf") as dxf:
              for i in range(CIRCLE_COUNT):
                  dxf.add_circle((MAX_X_COORD*random(), MAX_Y_COORD*random()), radius=2)

       Show all available line types:

          import ezdxf

          LINETYPES = [
              'CONTINUOUS', 'CENTER', 'CENTERX2', 'CENTER2',
              'DASHED', 'DASHEDX2', 'DASHED2', 'PHANTOM', 'PHANTOMX2',
              'PHANTOM2', 'DASHDOT', 'DASHDOTX2', 'DASHDOT2', 'DOT',
              'DOTX2', 'DOT2', 'DIVIDE', 'DIVIDEX2', 'DIVIDE2',
          ]

          with r12writer('r12_linetypes.dxf', fixed_tables=True) as dxf:
              for n, ltype in enumerate(LINETYPES):
                  dxf.add_line((0, n), (10, n), linetype=ltype)
                  dxf.add_text(ltype, (0, n+0.1), height=0.25, style='OpenSansCondensed-Light')

   Reference
       ezdxf.addons.r12writer.r12writer(stream: TextIO | BinaryIO | str, fixed_tables=False, fmt='asc') ->
       R12FastStreamWriter
              Context manager for writing DXF entities to a stream/file. stream can be any file like object with
              a  write() method or just a string for writing DXF entities to the file system. If fixed_tables is
              True, a standard TABLES section is written in front of the ENTITIES section  and  some  predefined
              text styles and line types can be used.

              Set  argument  fmt  to “asc” to write ASCII DXF file (default) or “bin” to write Binary DXF files.
              ASCII DXF require a TextIO stream and Binary DXF require a BinaryIO stream.

       class ezdxf.addons.r12writer.R12FastStreamWriter(stream: TextIO, fixed_tables=False)
              Fast stream writer to create simple DXF R12 drawings.

              Parametersstream – a file like object with a write() method.

                     • fixed_tables – if fixed_tables is True, a standard TABLES section is written in front  of
                       the ENTITIES section and some predefined text styles and line types can be used.

              close() -> None
                     Writes the DXF tail. Call is not necessary when using the context manager r12writer().

              add_line(start: Sequence[float], end: Sequence[float], layer: str = '0', color: int | None = None,
              linetype: str | None = None) -> None
                     Add a LINE entity from start to end.

                     Parametersstart – start vertex as (x, y[, z]) tuple

                            • end – end vertex as  as (x, y[, z]) tuple

                            • layer  –  layer  name as string, without a layer definition the assigned color = 7
                              (black/white) and line type is 'Continuous'.

                            • color – color as AutoCAD Color Index (ACI) in the  range  from  0  to  256,  0  is
                              ByBlock  and  256  is  ByLayer,  default  is  ByLayer  which  is  always color = 7
                              (black/white) without a layer definition.

                            • linetype – line type as string, if FIXED-TABLES are written some  predefined  line
                              types   are  available,  else  line  type  is  always  ByLayer,  which  is  always
                              'Continuous' without a LAYERS table.

              add_circle(center: Sequence[float], radius: float, layer: str = '0', color: int | None = None,
              linetype: str | None = None) -> None
                     Add a CIRCLE entity.

                     Parameterscenter – circle center point as (x, y) tuple

                            • radius – circle radius as float

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_arc(center: Sequence[float], radius: float, start: float = 0, end: float = 360, layer: str =
              '0', color: int | None = None, linetype: str | None = None) -> None
                     Add an ARC entity. The arc goes counter-clockwise from start angle to end angle.

                     Parameterscenter – arc center point as (x, y) tuple

                            • radius – arc radius as float

                            • start – arc start angle in degrees as float

                            • end – arc end angle in degrees as float

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_point(location: Sequence[float], layer: str = '0', color: int | None = None, linetype: str |
              None = None) -> None
                     Add a POINT entity.

                     Parameterslocation – point location as (x, y [,z]) tuple

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_3dface(vertices: Iterable[Sequence[float]], invisible: int = 0, layer: str = '0', color: int |
              None = None, linetype: str | None = None) -> None
                     Add a 3DFACE entity. 3DFACE is a spatial area with 3 or 4 vertices, all vertices have to be
                     in the same plane.

                     Parametersvertices – iterable of 3 or 4 (x, y, z) vertices.

                            • invisible –

                              bit coded flag to define the invisible edges,

                              1. edge = 1

                              2. edge = 2

                              3. edge = 4

                              4. edge = 8

                              Add edge values to set multiple edges invisible, 1. edge + 3. edge = 1 +  4  =  5,
                              all edges = 15

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_solid(vertices: Iterable[Sequence[float]], layer: str = '0', color: int | None = None,
              linetype: str | None = None) -> None
                     Add  a  SOLID  entity.  SOLID  is  a  solid filled area with 3 or 4 edges and SOLID is a 2D
                     entity.

                     Parametersvertices – iterable of 3 or 4 (x, y[, z]) tuples, z-axis will be ignored.

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_polyline_2d(points: Iterable[Sequence], format: str = 'xy', closed: bool = False, start_width:
              float = 0, end_width: float = 0, layer: str = '0', color: int | None = None, linetype: str | None
              = None) -> None
                     Add a 2D POLYLINE entity with start width, end width and bulge value support.

                     Format codes:
                                              ┌───┬──────────────────────────────────┐
                                              │ x │ x-coordinate                     │
                                              ├───┼──────────────────────────────────┤
                                              │ y │ y-coordinate                     │
                                              ├───┼──────────────────────────────────┤
                                              │ s │ start width                      │
                                              ├───┼──────────────────────────────────┤
                                              │ e │ end width                        │
                                              ├───┼──────────────────────────────────┤
                                              │ b │ bulge value                      │
                                              ├───┼──────────────────────────────────┤
                                              │ v │ (x, y) tuple (z-axis is ignored) │
                                              └───┴──────────────────────────────────┘

                     Parameterspoints – iterable of (x, y,  [start_width,  [end_width,  [bulge]]])  tuple,  value
                              order according to the format string, unset values default to 0format – format: format string, default is 'xy'closedTrue creates a closed polyline

                            • start_width – default start width, default is 0end_width – default end width, default is 0layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_polyline(vertices: Iterable[Sequence[float]], closed: bool = False, layer: str = '0', color:
              int | None = None, linetype: str | None = None) -> None
                     Add a 3D POLYLINE entity.

                     Parametersvertices – iterable of (x, y[, z]) tuples, z-axis is 0 by default

                            • closedTrue creates a closed polyline

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_polyface(vertices: Iterable[Sequence[float]], faces: Iterable[Sequence[int]], layer: str =
              '0', color: int | None = None, linetype: str | None = None) -> None
                     Add  a POLYFACE entity. The POLYFACE entity supports only faces of maximum 4 vertices, more
                     indices will be ignored. A simple square would be:

                        v0 = (0, 0, 0)
                        v1 = (1, 0, 0)
                        v2 = (1, 1, 0)
                        v3 = (0, 1, 0)
                        dxf.add_polyface(vertices=[v0, v1, v2, v3], faces=[(0, 1, 2, 3)])

                     All 3D form functions of the ezdxf.render.forms module return  MeshBuilder  objects,  which
                     provide the required vertex and face lists.

                     See sphere example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py

                     Parametersvertices – iterable of (x, y, z) tuples

                            • faces – iterable of 3 or 4 vertex indices, indices have to be 0-based

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_polymesh(vertices: Iterable[Sequence[float]], size: tuple[int, int], closed=(False, False),
              layer: str = '0', color: int | None = None, linetype: str | None = None) -> None
                     Add  a  POLYMESH entity. A POLYMESH is a mesh of m rows and n columns, each mesh vertex has
                     its own x-, y- and z coordinates. The mesh can be closed  in  m-  and/or  n-direction.  The
                     vertices  have  to  be  in column order:  (m0, n0), (m0, n1), (m0, n2), (m1, n0), (m1, n1),
                     (m1, n2), …

                     See example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py

                     Parametersvertices – iterable of (x, y, z) tuples, in column order

                            • size – mesh dimension as (m, n)-tuple, requirement: len(vertices) == m*nclosed – (m_closed, n_closed) tuple, for closed mesh in m and/or n direction

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()linetype – line type as string see add_line()

              add_text(text: str, insert: Sequence[float] = (0, 0), height: float = 1.0, width: float = 1.0,
              align: str = 'LEFT', rotation: float = 0.0, oblique: float = 0.0, style: str = 'STANDARD', layer:
              str = '0', color: int | None = None) -> None
                     Add a one line TEXT entity.

                     Parameterstext – the text as string

                            • insert – insert location as (x, y) tuple

                            • height – text height in drawing units

                            • width – text width as factor

                            • align – text alignment, see table below

                            • rotation – text rotation in degrees as float

                            • oblique – oblique in degrees as float, vertical = 0 (default)

                            • style – text style name as string, if FIXED-TABLES  are  written  some  predefined
                              text styles are available, else text style is always 'STANDARD'.

                            • layer – layer name as string see add_line()color – color as AutoCAD Color Index (ACI) see add_line()
                                    ┌────────────┬─────────────┬───────────────┬──────────────┐
                                    │ Vert/Horiz │ Left        │ Center        │ Right        │
                                    ├────────────┼─────────────┼───────────────┼──────────────┤
                                    │ Top        │ TOP_LEFTTOP_CENTERTOP_RIGHT    │
                                    ├────────────┼─────────────┼───────────────┼──────────────┤
                                    │ Middle     │ MIDDLE_LEFTMIDDLE_CENTERMIDDLE_RIGHT │
                                    ├────────────┼─────────────┼───────────────┼──────────────┤
                                    │ Bottom     │ BOTTOM_LEFTBOTTOM_CENTERBOTTOM_RIGHT │
                                    ├────────────┼─────────────┼───────────────┼──────────────┤
                                    │ Baseline   │ LEFTCENTERRIGHT        │
                                    └────────────┴─────────────┴───────────────┴──────────────┘

                     The special alignments ALIGNED and FIT are not available.

   text2path
       Tools  to  convert  text  strings  and text based DXF entities into outer- and inner linear paths as Path
       objects. At the moment only the TEXT and the ATTRIB entity can be converted into paths and hatches.

       New in version 1.1: Text rendering is done by the fontTools package, which is a hard dependency of ezdxf.
       Support for stroke fonts, these are the basic vector fonts included in CAD applications, like .shx,  .shp
       or .lff fonts was added but these fonts cannot be rendered as HATCH entities.

       The  required  font  files  are  not  included  with ezdxf as they are copyrighted or, in the case of the
       LibreCAD font format, licensed under the “GPL v2 and later”.  Set the paths to such stroke fonts  in  the
       config file, see option ezdxf.options.support_dirs:

          [core]
          support_dirs =
              "C:\Program Files\Bricsys\BricsCAD V23 en_US\Fonts",
              ~/shx_fonts,
              ~/shp_fonts,
              ~/lff_fonts,

       Don’t expect a 100% match compared to CAD applications but the results with fontTools are better than the
       previous Matplotlib renderings.

   Text Alignments
       The text alignments are enums of type ezdxf.enums.TextEntityAlignment
                              ┌──────────┬─────────────┬───────────────┬──────────────┐
                              │ Vertical │ Left        │ Center        │ Right        │
                              ├──────────┼─────────────┼───────────────┼──────────────┤
                              │ Top      │ TOP_LEFT    │ TOP_CENTER    │ TOP_RIGHT    │
                              ├──────────┼─────────────┼───────────────┼──────────────┤
                              │ Middle   │ MIDDLE_LEFT │ MIDDLE_CENTER │ MIDDLE_RIGHT │
                              ├──────────┼─────────────┼───────────────┼──────────────┤
                              │ Bottom   │ BOTTOM_LEFT │ BOTTOM_CENTER │ BOTTOM_RIGHT │
                              ├──────────┼─────────────┼───────────────┼──────────────┤
                              │ Baseline │ LEFT        │ CENTER        │ RIGHT        │
                              └──────────┴─────────────┴───────────────┴──────────────┘

       The  vertical  middle  alignments (MIDDLE_XXX), center the text vertically in the middle of the uppercase
       letter “X” (cap height).

       Special alignments, where the horizontal alignment is always in the center of the text:

       • ALIGNED: text is scaled to match the given length, scales x- and y-direction by the same factor.

       • FIT: text is scaled to match the given length, but scales only in x-direction.

       • MIDDLE: insertion point is the center of the total height  (cap  height  +  descender  height)  without
         scaling, the length argument is ignored.

   Font Face Definition
       A  font  face  is  defined  by  the  Matplotlib  compatible  FontFace  object by font-family, font-style,
       font-stretch and font-weight.

       SEE ALSO:Font AnatomyFont Properties

   String Functions
       ezdxf.addons.text2path.make_path_from_str(s: str, font: FontFace, size: float = 1.0,
       align=TextEntityAlignment.LEFT, length: float = 0, m: Matrix44 = None) -> Path
              Convert a single line string s into a Multi-Path object.  The text  size  is  the  height  of  the
              uppercase  letter  “X”  (cap  height).  The paths are aligned about the insertion point at (0, 0).
              BASELINE means the bottom of the letter “X”.

              Parameterss – text to convert

                     • font – font face definition as FontFace object

                     • size – text size (cap height) in drawing units

                     • align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFTlength – target length for the ALIGNED and FIT alignments

                     • m – transformation Matrix44

       ezdxf.addons.text2path.make_paths_from_str(s: str, font: FontFace, size: float = 1.0,
       align=TextEntityAlignment.LEFT, length: float = 0, m: Matrix44 = None) -> list[Path]
              Convert a single line string s into a list of Path objects. All paths are returned as  a  list  of
              Single-Path  objects.   The text size is the height of the uppercase letter “X” (cap height).  The
              paths are aligned about the insertion point at (0, 0).  BASELINE means the bottom  of  the  letter
              “X”.

              Parameterss – text to convert

                     • font – font face definition as FontFace object

                     • size – text size (cap height) in drawing units

                     • align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFTlength – target length for the ALIGNED and FIT alignments

                     • m – transformation Matrix44

       ezdxf.addons.text2path.make_hatches_from_str(s: str, font: FontFace, size: float = 1.0,
       align=TextEntityAlignment.LEFT, length: float = 0, dxfattribs=None, m: Matrix44 = None) -> list[Hatch]
              Convert a single line string s into a list of virtual Hatch entities.  The text size is the height
              of  the uppercase letter “X” (cap height).  The paths are aligned about the insertion point at (0,
              0).  The HATCH entities are aligned to this insertion point. BASELINE  means  the  bottom  of  the
              letter “X”.

              IMPORTANT:
                 Returns an empty list for .shx, .shp and .lff fonts a.k.a. stroke fonts.

              Parameterss – text to convert

                     • font – font face definition as FontFace object

                     • size – text size (cap height) in drawing units

                     • align – alignment as ezdxf.enums.TextEntityAlignment, default is LEFTlength – target length for the ALIGNED and FIT alignments

                     • dxfattribs – additional DXF attributes

                     • m – transformation Matrix44

   Entity Functions
       class ezdxf.addons.text2path.Kind(value, names=None, *, module=None, qualname=None, type=None, start=1,
       boundary=None)
              The Kind enum defines the DXF types to create as bit flags, e.g. 1+2 to get HATCHES as filling and
              SPLINES and POLYLINES as outline:
                                    ┌─────┬─────────────┬──────────────────────────────┐
                                    │ Int │ Enum        │ Description                  │
                                    ├─────┼─────────────┼──────────────────────────────┤
                                    │ 1   │ HATCHES     │ Hatch entities as filling    │
                                    ├─────┼─────────────┼──────────────────────────────┤
                                    │ 2   │ SPLINES     │ Spline   and   3D   Polyline │
                                    │     │             │ entities as outline          │
                                    ├─────┼─────────────┼──────────────────────────────┤
                                    │ 4   │ LWPOLYLINES │ LWPolyline    entities    as │
                                    │     │             │ approximated     (flattened) │
                                    │     │             │ outline                      │
                                    └─────┴─────────────┴──────────────────────────────┘

       ezdxf.addons.text2path.virtual_entities(entity: Text | Attrib, kind: int = Kind.HATCHES) -> EntityQuery
              Convert the text content of DXF entities TEXT and ATTRIB  into  virtual  SPLINE  and  3D  POLYLINE
              entities or approximated LWPOLYLINE entities as outlines, or as HATCH entities as fillings.

              Returns the virtual DXF entities as an EntityQuery object.

              Parametersentity – TEXT or ATTRIB entity

                     • kind – kind of entities to create as bit flags, see enum Kind

       ezdxf.addons.text2path.explode(entity: Text | Attrib, kind: int = Kind.HATCHES, target=None) ->
       EntityQuery
              Explode  the  text entity into virtual entities, see virtual_entities(). The source entity will be
              destroyed.

              The target layout is given by the target argument, if target is None, the  target  layout  is  the
              source layout of the text entity.

              Returns the created DXF entities as an EntityQuery object.

              Parametersentity – TEXT or ATTRIB entity to explode

                     • kind – kind of entities to create as bit flags, see enum Kindtarget  –  target  layout  for  new created DXF entities, None for the same layout as the
                       source entity.

       ezdxf.addons.text2path.make_path_from_entity(entity: Text | Attrib) -> Path
              Convert text content from DXF entities TEXT and ATTRIB into a Multi-Path object.   The  paths  are
              located at the location of the source entity.

       ezdxf.addons.text2path.make_paths_from_entity(entity: Text | Attrib) -> list[Path]
              Convert  text content from DXF entities TEXT and ATTRIB into a list of Path objects. All paths are
              returned as a list of Single-Path objects.  The paths are located at the location  of  the  source
              entity.

   MTextExplode
       This  tool  is  meant  to  explode MTEXT entities into single line TEXT entities by replicating the MTEXT
       layout as close as possible. This tool requires the optional Matplotlib package to create usable results,
       nonetheless it also works without Matplotlib, but then uses a mono-spaced replacement font for text  size
       measuring which leads to very inaccurate results.

       The supported MTEXT features are:

       • changing text color

       • text strokes: underline, overline and strike through

       • changing text size, width and oblique

       • changing font faces

       • stacked text (fractions)

       • multi-column support

       • background color

       • text frame

       The tool requires an initialized DXF document io implement all these features by creating additional text
       styles.  When  exploding  multiple  MTEXT  entities,  they  can  share  this  new  text  styles. Call the
       MTextExplode.finalize() method just once after all MTEXT entities are processed to  create  the  required
       text styles, or use MTextExplode as context manager by using the with statement, see examples below.

       There are also many limitations:

       • A 100% accurate result cannot be achieved.

       • Character tracking is not supported.

       • Tabulator stops have only limited support for LEFT and JUSTIFIED aligned paragraphs to support numbered
         and bullet lists. An excessive use of tabs will lead to incorrect results.

       • The DISTRIBUTED alignment will be replaced by the JUSTIFIED alignment.

       • Text flow is always “left to right”.

       • The  line  spacing  mostly corresponds to the “EXACT” style, except for stacked text (fractions), which
         corresponds more to the “AT LEAST” style, but not precisely. This behavior maybe will  improve  in  the
         future.

       • FIELDS are not evaluated by ezdxf.

       class ezdxf.addons.MTextExplode(layout, doc=None, spacing_factor=1.0)
              The  MTextExplode class is a tool to disassemble MTEXT entities into single line TEXT entities and
              additional LINE entities if required to emulate strokes.

              The layout argument defines the target layout  for “exploded”  parts  of  the  MTEXT  entity.  Use
              argument  doc  if  the  target  layout  has  no  DXF  document assigned like virtual layouts.  The
              spacing_factor argument is an advanced tuning parameter to scale the size of space chars.

              explode(mtext: MText, destroy=True)
                     Explode mtext and destroy the source entity if argument destroy is True.

              finalize()
                     Create required text styles. This method is called automatically if the class  is  used  as
                     context manager. This method does not work with virtual layouts if no document was assigned
                     at initialization!

       Example to explode all MTEXT entities in the DXF file “mtext.dxf”:

          import ezdxf
          from ezdxf.addons import MTextExplode

          doc = ezdxf.readfile("mtext.dxf")
          msp = doc.modelspace()
          with MTextExplode(msp) as xpl:
              for mtext in msp.query("MTEXT"):
                  xpl.explode(mtext)
          doc.saveas("xpl_mtext.dxf")

       Explode all MTEXT entities into the block “EXPLODE”:

          import ezdxf
          from ezdxf.addons import MTextExplode

          doc = ezdxf.readfile("mtext.dxf")
          msp = doc.modelspace()
          blk = doc.blocks.new("EXPLODE")
          with MTextExplode(blk) as xpl:
              for mtext in msp.query("MTEXT"):
                  xpl.explode(mtext)
          msp.add_block_ref("EXPLODE", (0, 0))
          doc.saveas("xpl_into_block.dxf")

   HPGL/2 Converter Add-on
       New in version 1.1.

       The hpgl2 add-on provides tools to process and convert HPGL/2 plot files.

   What are HPGL/2 Plot Files?
       The  Hewlett-Packard  Graphics  Language  (HPGL)  is  a  vector graphics language originally developed by
       Hewlett-Packard in the 1970s. HPGL is widely used for controlling pen plotters and other output  devices,
       and it has become a de facto standard for communicating between computers and output devices in the field
       of computer-aided design (CAD) and drafting.

       HPGL  is a command-driven language that consists of a series of commands that control the movement of the
       plotter pen, the selection of pens and other output parameters, and the drawing of geometric shapes  such
       as  lines, arcs, circles, and text. The language is interpreted by the plotter or other output device and
       translated into physical pen movements on the drawing surface.

       HPGL has evolved over the years, and various extensions have been added to support more complex  graphics
       operations  and to improve compatibility with other graphics languages.  Despite the development of newer
       graphics languages and file formats, HPGL  remains  a  widely  used  format  for  vector-based  graphics,
       particularly in the engineering and architectural fields.

   The Goal of This Add-on
       An  HPGL/2  plot  file  contains  all  of the data generated by a CAD application that has been sent to a
       plotter to print an engineering drawing. In the past, the only way to access this data was to view it  on
       a  plotter  or  an  specialized  application,  which  could be expensive and impractical for many people.
       However, this module provides functions and classes to convert  HPGL/2  plot  files  into  modern  vector
       graphic formats such as PDF and SVG and of course DXF, allowing the data to be viewed and processed using
       a wide range of software tools.

       IMPORTANT:
          The Python module PyMuPDF is required for the PDF export: https://pypi.org/project/PyMuPDF/

       The  Plotter  class  in the hpgl2 add-on supports only the most commonly used commands of HPGL/2. This is
       because many CAD applications use only a small  subset  of  HPGL/2  to  create  their  output,  typically
       consisting  of  polylines  and  filled  polygons.  For more information on the supported commands, please
       refer to the documentation for the Plotter class.

       To use the HPGL2 add-on, the entry point is the ezdxf.addons.hpgl2.api module.  This module contains  the
       public interface of the add-on and should be imported in the following way:

          from ezdxf.addons.hpgl2 import api as hpgl2

          with open("hpgl2.plt", "rb") as fp:
              data = fp.read()
          doc = hpgl2.to_dxf(data, color_mode=hpgl2.ColorMode.ACI)
          doc.saveas("hpgl2_as.dxf")

   High Level Functions
                                ┌───────────┬───────────────────────────────────────┐
                                │ to_dxf    │ Exports  the  HPGL/2  commands of the │
                                │           │ byte stream b as a DXF document.      │
                                ├───────────┼───────────────────────────────────────┤
                                │ to_svg    │ Exports the HPGL/2  commands  of  the │
                                │           │ byte stream b as SVG string.          │
                                ├───────────┼───────────────────────────────────────┤
                                │ to_pdf    │ Exports  the  HPGL/2  commands of the │
                                │           │ byte stream b as PDF data.            │
                                ├───────────┼───────────────────────────────────────┤
                                │ to_pixmap │ Exports the HPGL/2  commands  of  the │
                                │           │ byte stream b as pixel image.         │
                                └───────────┴───────────────────────────────────────┘

       ezdxf.addons.hpgl2.api.to_dxf(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
       False, color_mode=ColorMode.RGB, merge_control: MergeControl = MergeControl.AUTO) -> Drawing
              Exports the HPGL/2 commands of the byte stream b as a DXF document.

              The  page  content is created at the origin of the modelspace and 1 drawing unit is 1 plot unit (1
              plu = 0.025mm) unless scaling values are provided.

              The content of HPGL files is intended to be plotted on white paper, therefore a white filling will
              be added as background in color mode RGB.

              All entities are assigned to a layer according to the pen number with the name  scheme  PEN_<###>.
              In  order  to  be  able to process the file better, it is also possible to assign the ACI color by
              layer by setting the argument color_mode to ColorMode.ACI, but then the RGB color is lost  because
              the RGB color has always the higher priority over the ACI.

              The first paperspace layout “Layout1” of the DXF document is set up to print the entire modelspace
              on one sheet, the size of the page is the size of the original plot file in millimeters.

              HPGL/2’s  merge  control  works at the pixel level and cannot be replicated by DXF, but to prevent
              fillings from obscuring text, the filled polygons are sorted by luminance - this can be forced  or
              disabled by the argument merge_control, see also MergeControl enum.

              Parametersb – plot file content as bytes

                     • rotation – rotation angle of 0, 90, 180 or 270 degrees

                     • mirror_x – mirror in x-axis direction

                     • mirror_y – mirror in y-axis direction

                     • color_mode  –  the color mode controls how color values are assigned to DXF entities, see
                       ColorModemerge_control – how to order filled polygons, see MergeControl

              Returns: DXF document as instance of class Drawing

       ezdxf.addons.hpgl2.api.to_svg(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
       False, merge_control=MergeControl.AUTO) -> str
              Exports the HPGL/2 commands of the byte stream b as SVG string.

              The plot units are mapped 1:1 to viewBox units and the size of image is the size of  the  original
              plot file in millimeters.

              HPGL/2’s  merge  control  works at the pixel level and cannot be replicated by the backend, but to
              prevent fillings from obscuring text, the filled polygons are sorted by luminance -  this  can  be
              forced or disabled by the argument merge_control, see also MergeControl enum.

              Parametersb – plot file content as bytes

                     • rotation – rotation angle of 0, 90, 180 or 270 degrees

                     • mirror_x – mirror in x-axis direction

                     • mirror_y – mirror in y-axis direction

                     • merge_control – how to order filled polygons, see MergeControl

              Returns: SVG content as str

       ezdxf.addons.hpgl2.api.to_pdf(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
       False, merge_control=MergeControl.AUTO) -> bytes
              Exports the HPGL/2 commands of the byte stream b as PDF data.

              The  plot units (1 plu = 0.025mm) are converted to PDF units (1/72 inch) so the image has the size
              of the original plot file.

              HPGL/2’s merge control works at the pixel level and cannot be replicated by the  backend,  but  to
              prevent  fillings  from  obscuring text, the filled polygons are sorted by luminance - this can be
              forced or disabled by the argument merge_control, see also MergeControl enum.

              Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/

              Parametersb – plot file content as bytes

                     • rotation – rotation angle of 0, 90, 180 or 270 degrees

                     • mirror_x – mirror in x-axis direction

                     • mirror_y – mirror in y-axis direction

                     • merge_control – how to order filled polygons, see MergeControl

              Returns: PDF content as bytes

       ezdxf.addons.hpgl2.api.to_pixmap(b: bytes, *, rotation: int = 0, mirror_x: bool = False, mirror_y: bool =
       False, merge_control=MergeControl.AUTO, fmt: str = 'png', dpi: int = 96) -> bytes
              Exports the HPGL/2 commands of the byte stream b as pixel image.

              Supported image formats:
                                              ┌─────┬───────────────────────────┐
                                              │ png │ Portable Network Graphics │
                                              ├─────┼───────────────────────────┤
                                              │ ppm │ Portable Pixmap           │
                                              ├─────┼───────────────────────────┤
                                              │ pbm │ Portable Bitmap           │
                                              └─────┴───────────────────────────┘

              The plot units (1 plu = 0.025mm) are converted to dot per inch (dpi) so the image has the size  of
              the original plot file.

              HPGL/2’s  merge  control  works at the pixel level and cannot be replicated by the backend, but to
              prevent fillings from obscuring text, the filled polygons are sorted by luminance -  this  can  be
              forced or disabled by the argument merge_control, see also MergeControl enum.

              Python module PyMuPDF is required: https://pypi.org/project/PyMuPDF/

              Parametersb – plot file content as bytes

                     • rotation – rotation angle of 0, 90, 180 or 270 degrees

                     • mirror_x – mirror in x-axis direction

                     • mirror_y – mirror in y-axis direction

                     • merge_control – how to order filled polygons, see MergeControlfmt – image format

                     • dpi – output resolution in dots per inch

              Returns: image content as bytes

       class ezdxf.addons.hpgl2.api.ColorMode
              The color mode controls how color values are assigned to DXF entities

              ACI    Use  the  pen  number  as AutoCAD Color Index (ACI) for DXF entities, ignores the RGB color
                     values

              RGB    Use the pen number as AutoCAD Color Index  (ACI)  but  also  set  the  RGB  color  for  DXF
                     entities,  RGB  color  values  have always higher priority than the ACI when displaying DXF
                     content.

       class ezdxf.addons.hpgl2.api.MergeControl
              Merge control enumeration.

              NONE   export filled polygons in print order

              LUMINANCE
                     sort filled polygons by luminance

              AUTO   guess best order of filled polygons

   The Low Level Functions and Classes
       ezdxf.addons.hpgl2.api.hpgl2_commands(s: bytes) -> list[Command]
              Low level plot file parser, extracts the HPGL/2 from the byte stream b.

              IMPORTANT:
                 This parser expects the “Enter HPGL/2 mode” escape sequence to recognize HPGL/2  commands.  The
                 sequence looks like this: [ESC]%1B, multiple variants of this sequence are supported.

       The  HPGL/2  commands  are often mixed with the Printer Command Language (PCL) and/or the Raster Transfer
       Language (RTL) commands in a single plot file.

       Some plot files that contain pure HPGL/2 code do not contain the escape  sequence  “Enter  HPGL/2  mode”,
       without  this  sequence  the  HPGL/2  parser  cannot  recognize the beginning of the HPGL/2 code. Add the
       ENTER_HPGL2_MODE sequence in front of the bytes stream to switch on the HPGL/2  manually,  regardless  of
       whether the file is an HPGL/2 plot file or not, so be careful:

          commands = hpgl2_commands(hpgl2.ENTER_HPGL2_MODE + data)

       class ezdxf.addons.hpgl2.api.Interpreter(plotter: Plotter)
              The Interpreter is the frontend for the Plotter class.  The run() methods interprets the low level
              HPGL  commands  from  the  hpgl2_commands()  parser  and sends the commands to the virtual plotter
              device, which sends his output to a low level Backend class.

              Most CAD application send a very restricted subset of commands to plotters, mostly just  polylines
              and  filled  polygons.  Implementing the whole HPGL/2 command set is not worth the effort - unless
              reality proofs otherwise.

              Not implemented commands:

                 • the whole character group - text is send as filled polygons or polylines

                 • configuration group: IN, DF, RO, IW - the plotter is initialized by creating  a  new  plotter
                   and page rotation is handled by the add-on itself

                 • polygon group: EA, ER, EW, FA, RR, WG, the rectangle and wedge commands

                 • line  and fill attributes group: LA, RF, SM, SV, TR, UL, WU, linetypes and hatch patterns are
                   decomposed into simple lines by CAD applications

              Parameters
                     plotter – virtual Plotter device

              errors List of error messages occurred during the interpretation of the HPGL/2 commands.

              not_implemented_commands
                     List of all unsupported/ignored commands from the input stream.

              run(commands: list[Command]) -> None
                     Interprets the low level HPGL commands from  the  hpgl2_commands()  parser  and  sends  the
                     commands to the virtual plotter device.

              disable_commands(commands: Iterable[str]) -> None
                     Disable  commands manually, like the scaling command [“SC”, “IP”, “IR”].  This is a feature
                     for experts, because disabling commands which changes  the  pen  location  may  distort  or
                     destroy the plotter output.

       class ezdxf.addons.hpgl2.api.Plotter(backend: Backend)
              The Plotter class represents a virtual plotter device.

              The  HPGL/2  commands  send  by  the  Interpreter  are  processed into simple polylines and filled
              polygons and send to low level Backend.

              HPGL/2 uses a units system called “Plot Units”:

              • 1 plot unit (plu) = 0.025mm

              • 40 plu = 1 mm

              • 1016 plu = 1 inch

              The Plotter device does not support font rendering and page rotation (RO).  The  scaling  commands
              IP, RP, SC are supported.

   Recorder
       class ezdxf.addons.hpgl2.api.Recorder
              The Recorder class records the output of the Plotter class.

              All input coordinates are page coordinates:

              • 1 plot unit (plu) = 0.025mm

              • 40 plu = 1 mm

              • 1016 plu = 1 inch

              player() -> Player
                     Returns  a  Player  instance  with  the  original recordings. Make a copy of this player to
                     protect the original recordings from being modified:

                        safe_player = recorder.player().copy()

              draw_polyline(properties: Properties, points: Sequence[Vec2]) -> None
                     Draws a polyline from a sequence points. The input coordinates are page coordinates in plot
                     units. The points sequence can contain 0 or more points!

                     Parametersproperties – display Properties for the polyline

                            • points – sequence of ezdxf.math.Vec2 instances

              draw_paths(properties: Properties, paths: Sequence[Path], filled: bool) -> None
                     Draws filled or outline paths from the sequence of paths. The input  coordinates  are  page
                     coordinates  in plot units. The paths sequence can contain 0 or more single Path instances.
                     Draws outline paths if Properties.FillType is NONE and filled paths otherwise.

                     Parametersproperties – display Properties for the filled polygon

                            • paths – sequence of single ezdxf.path.Path instances

                            • filled – draw filled paths if True otherwise outline paths

   Player
       class ezdxf.addons.hpgl2.api.Player(records: list[DataRecord], properties: dict[int, Properties])
              This class replays the recordings of the Recorder class on another backend. The class  can  modify
              the recorded output.

              copy() -> Self
                     Returns a new Player instance with a copy of recordings.

              recordings() -> Iterator[tuple[RecordType, Properties, Any]]
                     Yields all recordings as (RecordType, Properties, Data) tuples.

                     The content of the Data field is determined by the enum RecordType:

                     • RecordType.POLYLINE returns a NumpyPoints2d instance

                     • RecordType.FILLED_POLYGON returns a tuple of NumpyPath2d instances

              replay(backend: Backend) -> None
                     Replay the recording on another backend.

              bbox() -> BoundingBox2d
                     Returns the bounding box of all recorded polylines and polygons as BoundingBox2d.

              transform(m: Matrix44) -> None
                     Transforms the recordings by a transformation matrix m of type Matrix44.

              sort_filled_paths() -> None
                     Sort filled paths by descending luminance (from light to dark).

                     This  also  changes  the  plot  order  in  the way that all filled paths are plotted before
                     polylines and outline paths.

   Properties
       class ezdxf.addons.hpgl2.properties.Properties
              Consolidated display properties.

              pen_index
                     pen index as int

              pen_color
                     pen color as RGB tuple

              pen_width
                     pen width in millimeters (float)

              fill_type
                     FillType of filled polygons

              fill_method
                     FillMethod of filled polygons

              fill_hatch_line_angle
                     fill hatch line angle in degrees

              fill_hatch_line_spacing
                     fill hatch line distance in plotter units

              fill_shading_density
                     fill shading density in percent from 0 to 100.

              resolve_pen_color() -> RGB
                     Returns the final RGB pen color.

              resolve_fill_color() -> RGB
                     Returns the final RGB fill color.

       class ezdxf.addons.hpgl2.properties.FillType(value, names=None, *, module=None, qualname=None, type=None,
       start=1, boundary=None)
              Fill type enumeration.

              NONE

              SOLID

              HATCHING

              CROSS_HATCHING

              SHADING

       class ezdxf.addons.hpgl2.properties.FillMethod(value, names=None, *, module=None, qualname=None,
       type=None, start=1, boundary=None)
              Fill method enumeration.

              EVEN_ODD

              NONE_ZERO_WINDING

   Exceptions
       class ezdxf.addons.hpgl2.api.Hpgl2Error
              Base exception for the hpgl2 add-on.

       class ezdxf.addons.hpgl2.api.Hpgl2DataNotFound
              No HPGL/2 data was found, maybe the “Enter HPGL/2 mode” escape sequence is missing.

       class ezdxf.addons.hpgl2.api.EmptyDrawing
              The HPGL/2 commands do not produce any content.

   PyCSG
       Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean  operations  like  union  and
       intersection  to  combine  3D  solids.  This  library  implements  CSG operations on meshes elegantly and
       concisely using BSP trees, and is meant to serve  as  an  easily  understandable  implementation  of  the
       algorithm. All edge cases involving overlapping coplanar polygons in both solids are correctly handled.

       Example for usage:

          import ezdxf
          from ezdxf.render.forms import cube, cylinder_2p
          from ezdxf.addons.pycsg import CSG

          # create new DXF document
          doc = ezdxf.new()
          msp = doc.modelspace()

          # create same geometric primitives as MeshTransformer() objects
          cube1 = cube()
          cylinder1 = cylinder_2p(count=32, base_center=(0, -1, 0), top_center=(0, 1, 0), radius=.25)

          # build solid union
          union = CSG(cube1) + CSG(cylinder1)
          # convert to mesh and render mesh to modelspace
          union.mesh().render(msp, dxfattribs={'color': 1})

          # build solid difference
          difference = CSG(cube1) - CSG(cylinder1)
          # convert to mesh, translate mesh and render mesh to modelspace
          difference.mesh().translate(1.5).render(msp, dxfattribs={'color': 3})

          # build solid intersection
          intersection = CSG(cube1) * CSG(cylinder1)
          # convert to mesh, translate mesh and render mesh to modelspace
          intersection.mesh().translate(2.75).render(msp, dxfattribs={'color': 5})

          doc.saveas('csg.dxf')
       [image: Cube vs Cylinder] [image]

       This  CSG  kernel supports only meshes as MeshBuilder objects, which can be created from and converted to
       DXF Mesh entities.

       This CSG kernel is not compatible with ACIS objects like Solid3d, Body, Surface or Region.

       NOTE:
          This is a pure Python implementation, don’t expect great performance and the implementation  is  based
          on an unbalanced BSP tree, so in the case of RecursionError, increase the recursion limit:

              import sys

              actual_limit = sys.getrecursionlimit()
              # default is 1000, increasing too much may cause a seg fault
              sys.setrecursionlimit(10000)

              ...  # do the CSG stuff

              sys.setrecursionlimit(actual_limit)

       CSG  works  also  with  spheres,  but  with  really  bad  runtime behavior and most likely RecursionError
       exceptions, and use quadrilaterals as body faces to reduce face count by setting argument quads to True.

          import ezdxf

          from ezdxf.render.forms import sphere, cube
          from ezdxf.addons.pycsg import CSG

          doc = ezdxf.new()
          doc.set_modelspace_vport(6, center=(5, 0))
          msp = doc.modelspace()

          cube1 = cube().translate(-.5, -.5, -.5)
          sphere1 = sphere(count=32, stacks=16, radius=.5, quads=True)

          union = (CSG(cube1) + CSG(sphere1)).mesh()
          union.render(msp, dxfattribs={'color': 1})

          subtract = (CSG(cube1) - CSG(sphere1)).mesh().translate(2.5)
          subtract.render(msp, dxfattribs={'color': 3})

          intersection = (CSG(cube1) * CSG(sphere1)).mesh().translate(4)
          intersection.render(msp, dxfattribs={'color': 5})
       [image: Cube vs Sphere] [image]

       Hard Core CSG - Menger Sponge Level 3 vs Sphere

       Required runtime on an old Xeon E5-1620 Workstation @ 3.60GHz, with default recursion limit  of  1000  on
       Windows 10:

          • CPython 3.8.1 64bit: ~60 seconds,

          • pypy3  [PyPy  7.2.0]  32bit:  ~6 seconds, and using __slots__ reduced runtime below 5 seconds, yes -
            pypy is worth a look for long running scripts!

          from ezdxf.render.forms import sphere
          from ezdxf.addons import MengerSponge
          from ezdxf.addons.pycsg import CSG

          doc = ezdxf.new()
          doc.layers.new('sponge', dxfattribs={'color': 5})
          doc.layers.new('sphere', dxfattribs={'color': 6})

          doc.set_modelspace_vport(6, center=(5, 0))
          msp = doc.modelspace()

          sponge1 = MengerSponge(level=3).mesh()
          sphere1 = sphere(count=32, stacks=16, radius=.5, quads=True).translate(.25, .25, 1)

          subtract = (CSG(sponge1, meshid=1) - CSG(sphere1, meshid=2))
          # get mesh result by id
          subtract.mesh(1).render(msp, dxfattribs={'layer': 'sponge'})
          subtract.mesh(2).render(msp, dxfattribs={'layer': 'sphere'})
       [image: Menger Sponge vs Sphere] [image]

   CSG Class
       class ezdxf.addons.pycsg.CSG(mesh: MeshBuilder, meshid: int = 0)
              Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean operations like  union
              and intersection to combine 3D solids. This class implements CSG operations on meshes.

              New  3D solids are created from MeshBuilder objects and results can be exported as MeshTransformer
              objects to ezdxf by method mesh().

              Parametersmeshezdxf.render.MeshBuilder or inherited object

                     • meshid – individual mesh ID to separate result meshes, 0 is default

              mesh(meshid: int = 0) -> MeshTransformer
                     Returns a ezdxf.render.MeshTransformer object.

                     Parameters
                            meshid – individual mesh ID, 0 is default

              union(other: CSG) -> CSG
                     Return a new CSG solid representing space in either this  solid  or  in  the  solid  other.
                     Neither this solid nor the solid other are modified:

                        A.union(B)

                        +-------+            +-------+
                        |       |            |       |
                        |   A   |            |       |
                        |    +--+----+   =   |       +----+
                        +----+--+    |       +----+       |
                             |   B   |            |       |
                             |       |            |       |
                             +-------+            +-------+

              __add__()

                        union = A + B

              subtract(other: CSG) -> CSG
                     Return a new CSG solid representing space in this solid but not in the solid other. Neither
                     this solid nor the solid other are modified:

                        A.subtract(B)

                        +-------+            +-------+
                        |       |            |       |
                        |   A   |            |       |
                        |    +--+----+   =   |    +--+
                        +----+--+    |       +----+
                             |   B   |
                             |       |
                             +-------+

              __sub__()

                        difference = A - B

              intersect(other: CSG) -> CSG
                     Return  a  new CSG solid representing space both this solid and in the solid other. Neither
                     this solid nor the solid other are modified:

                        A.intersect(B)

                        +-------+
                        |       |
                        |   A   |
                        |    +--+----+   =   +--+
                        +----+--+    |       +--+
                             |   B   |
                             |       |
                             +-------+

              __mul__()

                        intersection = A * B

              inverse() -> CSG
                     Return a new CSG solid with solid and empty space switched. This solid is not modified.

   License
       • Original implementation csg.js, Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT
         license.

       • Python port pycsg, Copyright (c) 2012 Tim Knip (http://www.floorplanner.com), under the MIT license.

       • Additions by Alex Pletzer (Pennsylvania State University)

       • Integration as ezdxf add-on, Copyright (c) 2020, Manfred Moitzi, MIT License.

   Plot Style Files (CTB/STB)
       CTB and STB files store plot styles used by AutoCAD and BricsCAD for printing and plotting.

       If the plot style table is attached to a Paperspace or the Modelspace, a change of a plot  style  affects
       any  object  that  uses  that  plot style. CTB files contain color dependent plot style tables, STB files
       contain named plot style tables.

       SEE ALSO:Using plot style tables in AutoCADAutoCAD Plot Style Table EditorBricsCAD Plot Style Table Editor

          • AUTODESK KNOWLEDGE NETWORK: How to install CTB files in AutoCAD

       ezdxf.addons.acadctb.load(filename: str | PathLike) -> ColorDependentPlotStyles | NamedPlotStyles
              Load the CTB or STB file filename from file system.

       ezdxf.addons.acadctb.new_ctb() -> ColorDependentPlotStyles
              Create a new CTB file.

       ezdxf.addons.acadctb.new_stb() -> NamedPlotStyles
              Create a new STB file.

   ColorDependentPlotStyles
       Color dependent plot style table (CTB file), table entries are PlotStyle objects.

       class ezdxf.addons.acadctb.ColorDependentPlotStyles

              description
                     Custom description of plot style file.

              scale_factor
                     Specifies the factor by which to scale non-ISO linetypes and fill patterns.

              apply_factor
                     Specifies whether or not you want to apply the scale_factor.

              custom_lineweight_display_units
                     Set 1 for showing lineweight in inch in AutoCAD CTB  editor  window,  but  lineweights  are
                     always defined in millimeters.

              lineweights
                     Lineweights table as array.array

              __getitem__(aci: int) -> PlotStyle
                     Returns PlotStyle for AutoCAD Color Index (ACI) aci.

              __iter__()
                     Iterable of all plot styles.

              new_style(aci: int, data: dict | None = None) -> PlotStyle
                     Set aci to new attributes defined by data dict.

                     ParametersaciAutoCAD Color Index (ACI)datadict  of  PlotStyle  attributes: description, color, physical_pen_number,
                              virtual_pen_number,   screen,   linepattern_size,   linetype,   adaptive_linetype,
                              lineweight, end_style, join_style, fill_style

              get_lineweight(aci: int)
                     Returns the assigned lineweight for PlotStyle aci in millimeter.

              get_lineweight_index(lineweight: float) -> int
                     Get index of lineweight in the lineweight table or append lineweight to lineweight table.

              get_table_lineweight(index: int) -> float
                     Returns lineweight in millimeters of lineweight table entry index.

                     Parameters
                            index – lineweight table index = PlotStyle.lineweight

                     Returns
                            lineweight in mm or 0.0 for use entity lineweight

              set_table_lineweight(index: int, lineweight: float) -> int
                     Argument index is the lineweight table index, not the AutoCAD Color Index (ACI).

                     Parametersindex – lineweight table index = PlotStyle.lineweightlineweight – in millimeters

              save() Save CTB file as filename to the file system.

              write(stream: BinaryIO) -> None
                     Compress and write CTB file to binary stream.

   NamedPlotStyles
       Named plot style table (STB file), table entries are PlotStyle objects.

       class ezdxf.addons.acadctb.NamedPlotStyles

              description
                     Custom description of plot style file.

              scale_factor
                     Specifies the factor by which to scale non-ISO linetypes and fill patterns.

              apply_factor
                     Specifies whether or not you want to apply the scale_factor.

              custom_lineweight_display_units
                     Set  1  for  showing  lineweight  in inch in AutoCAD CTB editor window, but lineweights are
                     always defined in millimeters.

              lineweights
                     Lineweights table as array.array

              __getitem__(name: str) -> PlotStyle
                     Returns PlotStyle by name.

              __delitem__(name: str) -> None
                     Delete plot style name. Plot style 'Normal' is not deletable.

              __iter__() -> Iterable[str]
                     Iterable of all plot style names.

              new_style(name: str, data: dict | None = None, localized_name: str | None = None) -> PlotStyle
                     Create new class:PlotStyle name by attribute dict data, replaces  existing  class:PlotStyle
                     objects.

                     Parametersname – plot style name

                            • localized_name – name shown in plot style editor, uses name if Nonedatadict  of  PlotStyle  attributes: description, color, physical_pen_number,
                              virtual_pen_number,   screen,   linepattern_size,   linetype,   adaptive_linetype,
                              lineweight, end_style, join_style, fill_style

              get_lineweight(name: str)
                     Returns the assigned lineweight for PlotStyle name in millimeter.

              get_lineweight_index(lineweight: float) -> int
                     Get index of lineweight in the lineweight table or append lineweight to lineweight table.

              get_table_lineweight(index: int) -> float
                     Returns lineweight in millimeters of lineweight table entry index.

                     Parameters
                            index – lineweight table index = PlotStyle.lineweight

                     Returns
                            lineweight in mm or 0.0 for use entity lineweight

              set_table_lineweight(index: int, lineweight: float) -> int
                     Argument index is the lineweight table index, not the AutoCAD Color Index (ACI).

                     Parametersindex – lineweight table index = PlotStyle.lineweightlineweight – in millimeters

              save() Save STB file as filename to the file system.

              write()
                     Compress and write STB file to binary stream.

   PlotStyle
       class ezdxf.addons.acadctb.PlotStyle

              index  Table index (0-based). (int)

              aci    AutoCAD  Color  Index  (ACI)  in range from 1 to 255. Has no meaning for named plot styles.
                     (int)

              description
                     Custom description of plot style. (str)

              physical_pen_number
                     Specifies physical plotter pen, valid range from 1 to 32 or AUTOMATIC. (int)

              virtual_pen_number
                     Only used by non-pen plotters and only if they are configured for virtual pens. valid range
                     from 1 to 255 or AUTOMATIC. (int)

              screen Specifies the color intensity of the plot on the paper, valid range is from 0 to 100. (int)

                     If you select 100 the drawing will plotted with its full  color  intensity.  In  order  for
                     screening to work, the dithering option must be active.

              linetype
                     Overrides the entity linetype, default value is OBJECT_LINETYPE. (bool)

              adaptive_linetype
                     True  if  a  complete  linetype  pattern is more important than a correct linetype scaling,
                     default is True. (bool)

              linepattern_size
                     Line pattern size, default = 0.5. (float)

              lineweight
                     Overrides the entity lineWEIGHT, default value is OBJECT_LINEWEIGHT. This is an index  into
                     the UserStyles.lineweights table. (int)

              end_style
                     Line end cap style, see table below, default is END_STYLE_OBJECT (int)

              join_style
                     Line join style, see table below, default is JOIN_STYLE_OBJECT (int)

              fill_style
                     Line fill style, see table below, default is FILL_STYLE_OBJECT (int)

              dithering
                     Depending  on  the capabilities of your plotter, dithering approximates the colors with dot
                     patterns. When this option is False, the colors are mapped to the nearest color,  resulting
                     in a smaller range of colors when plotting.

                     Dithering  is  available  only whether you select the object’s color or assign a plot style
                     color.

              grayscale
                     Plot colors in grayscale. (bool)

   Default Line Weights
                                                    ┌────┬──────┐
                                                    │ #  │ [mm] │
                                                    ├────┼──────┤
                                                    │ 0  │ 0.00 │
                                                    ├────┼──────┤
                                                    │ 1  │ 0.05 │
                                                    ├────┼──────┤
                                                    │ 2  │ 0.09 │
                                                    ├────┼──────┤
                                                    │ 3  │ 0.10 │
                                                    ├────┼──────┤
                                                    │ 4  │ 0.13 │
                                                    ├────┼──────┤
                                                    │ 5  │ 0.15 │
                                                    ├────┼──────┤
                                                    │ 6  │ 0.18 │
                                                    ├────┼──────┤
                                                    │ 7  │ 0.20 │
                                                    ├────┼──────┤
                                                    │ 8  │ 0.25 │
                                                    ├────┼──────┤
                                                    │ 9  │ 0.30 │
                                                    ├────┼──────┤
                                                    │ 10 │ 0.35 │
                                                    ├────┼──────┤
                                                    │ 11 │ 0.40 │
                                                    ├────┼──────┤
                                                    │ 12 │ 0.45 │
                                                    ├────┼──────┤
                                                    │ 13 │ 0.50 │
                                                    ├────┼──────┤
                                                    │ 14 │ 0.53 │
                                                    ├────┼──────┤
                                                    │ 15 │ 0.60 │
                                                    ├────┼──────┤
                                                    │ 16 │ 0.65 │
                                                    ├────┼──────┤
                                                    │ 17 │ 0.70 │
                                                    ├────┼──────┤
                                                    │ 18 │ 0.80 │
                                                    ├────┼──────┤
                                                    │ 19 │ 0.90 │
                                                    ├────┼──────┤
                                                    │ 20 │ 1.00 │
                                                    ├────┼──────┤
                                                    │ 21 │ 1.06 │
                                                    ├────┼──────┤
                                                    │ 22 │ 1.20 │
                                                    ├────┼──────┤
                                                    │ 23 │ 1.40 │
                                                    ├────┼──────┤
                                                    │ 24 │ 1.58 │
                                                    ├────┼──────┤
                                                    │ 25 │ 2.00 │
                                                    ├────┼──────┤
                                                    │ 26 │ 2.11 │
                                                    └────┴──────┘

   Predefined Values
       ezdxf.addons.acadctb.AUTOMATIC

       ezdxf.addons.acadctb.OBJECT_LINEWEIGHT

       ezdxf.addons.acadctb.OBJECT_LINETYPE

       ezdxf.addons.acadctb.OBJECT_COLOR

       ezdxf.addons.acadctb.OBJECT_COLOR2

   Line End Style
       [image]
                                              ┌───────────────────┬───┐
                                              │ END_STYLE_BUTT    │ 0 │
                                              ├───────────────────┼───┤
                                              │ END_STYLE_SQUARE  │ 1 │
                                              ├───────────────────┼───┤
                                              │ END_STYLE_ROUND   │ 2 │
                                              ├───────────────────┼───┤
                                              │ END_STYLE_DIAMOND │ 3 │
                                              ├───────────────────┼───┤
                                              │ END_STYLE_OBJECT  │ 4 │
                                              └───────────────────┴───┘

   Line Join Style
       [image]
                                              ┌────────────────────┬───┐
                                              │ JOIN_STYLE_MITER   │ 0 │
                                              ├────────────────────┼───┤
                                              │ JOIN_STYLE_BEVEL   │ 1 │
                                              ├────────────────────┼───┤
                                              │ JOIN_STYLE_ROUND   │ 2 │
                                              ├────────────────────┼───┤
                                              │ JOIN_STYLE_DIAMOND │ 3 │
                                              ├────────────────────┼───┤
                                              │ JOIN_STYLE_OBJECT  │ 5 │
                                              └────────────────────┴───┘

   Fill Style
       [image]
                                         ┌────────────────────────────┬────┐
                                         │ FILL_STYLE_SOLID           │ 64 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_CHECKERBOARD    │ 65 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_CROSSHATCH      │ 66 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_DIAMONDS        │ 67 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_HORIZONTAL_BARS │ 68 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_SLANT_LEFT      │ 69 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_SLANT_RIGHT     │ 70 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_SQUARE_DOTS     │ 71 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_VERICAL_BARS    │ 72 │
                                         ├────────────────────────────┼────┤
                                         │ FILL_STYLE_OBJECT          │ 73 │
                                         └────────────────────────────┴────┘

   Linetypes
       [image] [image]
                                    ─────────────────────────────────────────────
                                      Linetype name                       Value
                                    ─────────────────────────────────────────────
                                      Solid                               0
                                    ─────────────────────────────────────────────
                                      Dashed                              1
                                    ─────────────────────────────────────────────
                                      Dotted                              2
                                    ─────────────────────────────────────────────
                                      Dash Dot                            3
                                    ─────────────────────────────────────────────
                                      Short Dash                          4
                                    ─────────────────────────────────────────────
                                      Medium Dash                         5
                                    ─────────────────────────────────────────────
                                      Long Dash                           6
                                    ─────────────────────────────────────────────
                                      Short Dash x2                       7
                                    ─────────────────────────────────────────────
                                      Medium Dash x2                      8
                                    ─────────────────────────────────────────────
                                      Long Dash x2                        9
                                    ─────────────────────────────────────────────
                                      Medium Lang Dash                    10
                                    ─────────────────────────────────────────────
                                      Medium Dash Short Dash Short Dash   11
                                    ─────────────────────────────────────────────
                                      Long Dash Short Dash                12
                                    ─────────────────────────────────────────────
                                      Long Dash Dot Dot                   13
                                    ─────────────────────────────────────────────
                                      Long Dash Dot                       14
                                    ─────────────────────────────────────────────
                                      Medium Dash Dot Short Dash Dot      15
                                    ─────────────────────────────────────────────
                                      Sparse Dot                          16
                                    ─────────────────────────────────────────────
                                      ISO Dash                            17
                                    ─────────────────────────────────────────────
                                      ISO Dash Space                      18
                                    ─────────────────────────────────────────────
                                      ISO Long Dash Dot                   19
                                    ─────────────────────────────────────────────
                                      ISO Long Dash Double Dot            20
                                    ─────────────────────────────────────────────
                                      ISO Long Dash Triple Dot            21
                                    ─────────────────────────────────────────────
                                      ISO Dot                             22
                                    ─────────────────────────────────────────────
                                      ISO Long Dash Short Dash            23
                                    ─────────────────────────────────────────────
                                      ISO Long Dash Double Short Dash     24
                                    ─────────────────────────────────────────────
                                      ISO Dash Dot                        25
                                    ─────────────────────────────────────────────
                                      ISO Double Dash Dot                 26
                                    ─────────────────────────────────────────────
                                      ISO Dash Double Dot                 27
                                    ─────────────────────────────────────────────
                                      ISO Double Dash Double Dot          28
                                    ─────────────────────────────────────────────
                                      ISO Dash Triple Dot                 29
                                    ─────────────────────────────────────────────
                                      ISO Double Dash Triple Dot          30
                                    ─────────────────────────────────────────────
                                      Use entity linetype                 31
                                    ┌───────────────────────────────────┬───────┐
                                    │                                   │       │
   Showcase Forms                   │                                   │       │
   MengerSponge                     │                                   │       │
       Build a 3D Menger sponge.    │                                   │       │
                                    │                                   │       │
--

DXF INTERNALS

DXF Reference provided by Autodesk.

       • DXF Developer Documentation provided by Autodesk.

   Basic DXF Structures
   DXF File Encoding
   DXF R2004 and prior
       Drawing files of DXF R2004 (AC1018) and prior are saved as ASCII files  with  the  encoding  set  by  the
       header variable $DWGCODEPAGE, which is ANSI_1252 by default if $DWGCODEPAGE is not set.

       Characters  used  in  the  drawing which do not exist in the chosen ASCII encoding are encoded as unicode
       characters with the schema \U+nnnn. see Unicode table

   Known $DWGCODEPAGE encodings
                                       ┌───────────┬────────┬────────────────┐
                                       │ DXF       │ Python │ Name           │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_874  │ cp874  │ Thai           │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_932  │ cp932  │ Japanese       │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_936  │ gbk    │ UnifiedChinese │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_949  │ cp949  │ Korean         │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_950  │ cp950  │ TradChinese    │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1250 │ cp1250 │ CentralEurope  │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1251 │ cp1251 │ Cyrillic       │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1252 │ cp1252 │ WesternEurope  │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1253 │ cp1253 │ Greek          │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1254 │ cp1254 │ Turkish        │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1255 │ cp1255 │ Hebrew         │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1256 │ cp1256 │ Arabic         │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1257 │ cp1257 │ Baltic         │
                                       ├───────────┼────────┼────────────────┤
                                       │ ANSI_1258 │ cp1258 │ Vietnam        │
                                       └───────────┴────────┴────────────────┘

   DXF R2007 and later
       Starting with DXF R2007 (AC1021) the drawing file is UTF-8 encoded, the header variable  $DWGCODEPAGE  is
       still in use, but I don’t know, if the setting still has any meaning.

       Encoding characters in the unicode schema \U+nnnn is still functional.

       SEE ALSO:
          String value encoding

   DXF Tags
       A  Drawing  Interchange  File is simply an ASCII text file with a file type of .dxf and special formatted
       text. The basic file structure are DXF tags, a DXF tag consist of a DXF group code as an integer value on
       its own line and a the DXF value on the following line.  In the ezdxf  documentation  DXF  tags  will  be
       written as (group code, value).

       With the introduction of extended symbol names in DXF R2000, the 255-character limit for strings has been
       increased  to  2049 single-byte characters not including the newline at the end of the line.  Nonetheless
       its safer to use only strings with 255 and less characters, because its not clear if this  fact  is  true
       for  ALL  string  group  codes  or only for symbols like layer- or text style names and not all 3rd party
       libraries may handle this fact correct. The MTEXT content and binary data is still  divided  into  chunks
       with less than 255 characters.

       Group codes are indicating the value type:
                                ┌────────────┬───────────────────────────────────────┐
                                │ Group Code │ Value Type                            │
                                ├────────────┼───────────────────────────────────────┤
                                │ 0-9        │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 10-39      │ Double precision 3D point value       │
                                ├────────────┼───────────────────────────────────────┤
                                │ 40-59      │ Double-precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 60-79      │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 90-99      │ 32-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 100        │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 102        │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 105        │ String representing hexadecimal (hex) │
                                │            │ handle value                          │
                                ├────────────┼───────────────────────────────────────┤
                                │ 110-119    │ Double precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 120-129    │ Double precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 130-139    │ Double precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 140-149    │ Double        precision        scalar │
                                │            │ floating-point value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 160-169    │ 64-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 170-179    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 210-239    │ Double-precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 270-279    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 280-289    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 290-299    │ Boolean flag value                    │
                                ├────────────┼───────────────────────────────────────┤
                                │ 300-309    │ Arbitrary text string                 │
                                ├────────────┼───────────────────────────────────────┤
                                │ 310-319    │ String  representing  hex  value   of │
                                │            │ binary chunk                          │
                                ├────────────┼───────────────────────────────────────┤
                                │ 320-329    │ Arbitrary pointer, hex object ID, not │
                                │            │ translated  during  INSERT  and  XREF │
                                │            │ operations                            │
                                ├────────────┼───────────────────────────────────────┤
                                │ 330-339    │ Soft-pointer,    hex    object    ID, │
                                │            │ translated  during  INSERT  and  XREF │
                                │            │ operations                            │
                                ├────────────┼───────────────────────────────────────┤
                                │ 340-349    │ Hard-pointer,    hex    object    ID, │
                                │            │ translated  during  INSERT  and  XREF │
                                │            │ operations                            │
                                ├────────────┼───────────────────────────────────────┤
                                │ 350-359    │ Soft-owner, hex object ID, translated │
                                │            │ during INSERT and XREF operations     │
                                ├────────────┼───────────────────────────────────────┤
                                │ 360-369    │ Hard-owner, hex object ID, translated │
                                │            │ during INSERT and XREF operations     │
                                ├────────────┼───────────────────────────────────────┤
                                │ 370-379    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 380-389    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 390-399    │ String representing hex handle value  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 400-409    │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 410-419    │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 420-429    │ 32-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 430-439    │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 440-449    │ 32-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 450-459    │ Long                                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 460-469    │ Double-precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 470-479    │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 480-481    │ Hard-pointer,    hex    object    ID, │
                                │            │ translated  during  INSERT  and  XREF │
                                │            │ operations                            │
                                ├────────────┼───────────────────────────────────────┤
                                │ 999        │ Comment (string)                      │
                                ├────────────┼───────────────────────────────────────┤
                                │ 1000-1009  │ String                                │
                                ├────────────┼───────────────────────────────────────┤
                                │ 1010-1059  │ Double-precision floating-point value │
                                ├────────────┼───────────────────────────────────────┤
                                │ 1060-1070  │ 16-bit integer value                  │
                                ├────────────┼───────────────────────────────────────┤
                                │ 1071       │ 32-bit integer value                  │
                                └────────────┴───────────────────────────────────────┘

       Explanation for some important group codes:
                              ┌───────────────┬───────────────────────────────────────┐
                              │ Group Code    │ Meaning                               │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 0             │ DXF structure tag,  entity  start/end │
                              │               │ or table entries                      │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 1             │ The primary text value for an entity  │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 2             │ A  name:  Attribute  tag, Block name, │
                              │               │ and so on. Also used  to  identify  a │
                              │               │ DXF section or table name.            │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 3-4           │ Other textual or name values          │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 5             │ Entity handle as hex string (fixed)   │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 6             │ Line type name (fixed)                │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 7             │ Text style name (fixed)               │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 8             │ Layer name (fixed)                    │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 9             │ Variable  name  identifier (used only │
                              │               │ in HEADER section of the DXF file)    │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 10            │ Primary X coordinate (start point  of │
                              │               │ a  Line  or  Text entity, center of a │
                              │               │ Circle, etc.)                         │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 11-18         │ Other X coordinates                   │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 20            │ Primary  Y  coordinate.   2n   values │
                              │               │ always  correspond  to  1n values and │
                              │               │ immediately follow them in  the  file │
                              │               │ (expected by ezdxf!)                  │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 21-28         │ Other Y coordinates                   │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 30            │ Primary   Z   coordinate.  3n  values │
                              │               │ always correspond to 1n and 2n values │
                              │               │ and immediately follow  them  in  the │
                              │               │ file (expected by ezdxf!)             │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 31-38         │ Other Z coordinates                   │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 39            │ This  entity’s  thickness  if nonzero │
                              │               │ (fixed)                               │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 40-48         │ Float  values  (text  height,   scale │
                              │               │ factors, etc.)                        │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 49            │ Repeated  value  - multiple 49 groups │
                              │               │ may appear in one entity for variable │
                              │               │ length  tables  (such  as  the   dash │
                              │               │ lengths  in  the  LTYPE  table). A 7x │
                              │               │ group always appears before the first │
                              │               │ 49 group to specify the table length  │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 50-58         │ Angles in degree                      │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 62            │ Color number (fixed)                  │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 66            │ “Entities follow” flag (fixed),  only │
                              │               │ in INSERT and POLYLINE entities       │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 67            │ Identifies   whether   entity  is  in │
                              │               │ modelspace (0) or paperspace (1)      │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 68            │ Identifies whether viewport is on but │
                              │               │ fully off screen, is not  active,  or │
                              │               │ is off                                │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 69            │ Viewport identification number        │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 70-78         │ Integer values such as repeat counts, │
                              │               │ flag bits, or modes                   │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 105           │ DIMSTYLE  entity handle as hex string │
                              │               │ (fixed)                               │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 210, 220, 230 │ X, Y, and Z components  of  extrusion │
                              │               │ direction (fixed)                     │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 310           │ Proxy   entity   graphics  as  binary │
                              │               │ encoded data                          │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 330           │ Owner handle as hex string            │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 347           │ MATERIAL handle as hex string         │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 348           │ VISUALSTYLE  handle as hex string     │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 370           │ Lineweight  in  mm  times  100  (e.g. │
                              │               │ 0.13mm = 13).                         │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 390           │ PLOTSTYLE handle as hex string        │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 420           │ True color value as 0x00RRGGBB 24-bit │
                              │               │ value                                 │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 430           │ Color name as string                  │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 440           │ Transparency  value  0x020000TT  0  = │
                              │               │ fully transparent / 255 = opaque      │
                              ├───────────────┼───────────────────────────────────────┤
                              │ 999           │ Comments                              │
                              └───────────────┴───────────────────────────────────────┘

       For explanation of all group codes see: DXF Group Codes in Numerical Order Reference provided by Autodesk

   Extended Data
       DXF R2018 Reference

       Extended data (XDATA) is created by AutoLISP or ObjectARX applications but  any  other  application  like
       ezdxf  can  also  define  XDATA.  If  an  entity  contains  extended data, it follows the entity’s normal
       definition.

       But  extended  group  codes  (>=1000)  can  appear  before  the  XDATA  section,  an   example   is   the
       BLOCKBASEPOINTPARAMETER entity in AutoCAD Civil 3D or AutoCAD Map 3D.
                             ┌──────────────────┬───────────────────────────────────────┐
                             │ Group Code       │ Description                           │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1000             │ Strings in extended data can be up to │
                             │                  │ 255  bytes  long (with the 256th byte │
                             │                  │ reserved for the null character)      │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1001             │ (fixed) Registered  application  name │
                             │                  │ (ASCII  string  up  to 31 bytes long) │
                             │                  │ for XDATA                             │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1002             │ (fixed)  An  extended  data   control │
                             │                  │ string  can  be  either  '{'  or '}'. │
                             │                  │ These braces enable  applications  to │
                             │                  │ organize  their  data  by subdividing │
                             │                  │ the data into  lists.  Lists  can  be │
                             │                  │ nested.                               │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1003             │ Name of the layer associated with the │
                             │                  │ extended data                         │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1004             │ Binary   data   is   organized   into │
                             │                  │ variable-length chunks.  The  maximum │
                             │                  │ length of each chunk is 127 bytes. In │
                             │                  │ ASCII   DXF  files,  binary  data  is │
                             │                  │ represented   as    a    string    of │
                             │                  │ hexadecimal  digits,  two  per binary │
                             │                  │ byte                                  │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1005             │ Database Handle of  entities  in  the │
                             │                  │ drawing  database,  see  also:  About │
                             │                  │ 1005 Group Codes                      │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1010, 1020, 1030 │ Three real values, in the order X, Y, │
                             │                  │ Z. They can be used  as  a  point  or │
                             │                  │ vector   record   that  will  not  be │
                             │                  │ modified at any transformation of the │
                             │                  │ entity.                               │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1011, 1021, 1031 │ a WCS point that  is  moved,  scaled, │
                             │                  │ rotated  and  mirrored along with the │
                             │                  │ entity                                │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1012, 1012, 1022 │ a WCS displacement  that  is  scaled, │
                             │                  │ rotated  and  mirrored along with the │
                             │                  │ entity, but is not moved              │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1013, 1023, 1033 │ a WCS direction that is  rotated  and │
                             │                  │ mirrored  along  with the entity, but │
                             │                  │ is not moved or scaled                │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1040             │ A real value                          │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1041             │ Distance, a real value that is scaled │
                             │                  │ along with the parent entity          │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1042             │ Scale Factor, also a real value  that │
                             │                  │ is scaled along with the parent.  The │
                             │                  │ difference  between  a distance and a │
                             │                  │ scale factor is application-defined   │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1070             │ A 16-bit integer (signed or unsigned) │
                             ├──────────────────┼───────────────────────────────────────┤
                             │ 1071             │ A 32-bit signed (long) integer        │
                             └──────────────────┴───────────────────────────────────────┘

       The (1001, …) tag indicates the beginning of extended data. In  contrast  to  normal  entity  data,  with
       extended data the same group code can appear multiple times, and order is important.

       Extended  data is grouped by registered application name. Each registered application group begins with a
       (1001, APPID) tag, with the  application  name  as  APPID  string  value.  Registered  application  names
       correspond to APPID symbol table entries.

       An  application  can  use  as many APPID names as needed. APPID names are permanent, although they can be
       purged if they aren’t currently used in the drawing.  Each APPID name can have  no  more  than  one  data
       group  attached  to  each  entity.  Within an application group, the sequence of extended data groups and
       their meaning is defined by the application.

   String value encoding
       String values stored in a DXF file is plain ASCII or UTF-8, AutoCAD also supports CIF (Common Interchange
       Format) and MIF (Maker Interchange Format) encoding. The UTF-8 format is only supported in DXF R2007  and
       later.

       Ezdxf on import converts all strings into Python unicode strings without encoding or decoding CIF/MIF.

       String  values  containing  Unicode  characters are represented with control character sequences \U+nnnn.
       (e.g. r'TEST\U+7F3A\U+4E4F\U+89E3\U+91CA\U+6B63THIS\U+56FE')

       To support the DXF unicode encoding ezdxf registers an encoding codec dxf_backslash_replace,  defined  in
       ezdxf.lldxf.encoding().

       String values can be stored with these dxf group codes:

       • 0 - 9

       • 100 - 101

       • 300 - 309

       • 410 - 419

       • 430 - 439

       • 470 - 479

       • 999 - 1003

   Multi tag text (MTEXT)
       If  the  text string is less than 250 characters, all characters appear in tag (1, …). If the text string
       is longer than 250 characters, the string is divided into 250-character chunks, which appear  in  one  or
       more  (3,  …)  tags.  If  (3,  …)  tags  are  used, the last group is a (1, …) tag and has fewer than 250
       characters:

          3
          ... TwoHundredAndFifty Characters ....
          3
          ... TwoHundredAndFifty Characters ....
          1
          less than TwoHundredAndFifty Characters

       As far I know this is only supported by the MTEXT entity.

       SEE ALSO:
          DXF File Encoding

   DXF R13 and later tag structure
       With the introduction of DXF R13 Autodesk added additional group codes and DXF tag structures to the  DXF
       Standard.

   Subclass Markers
       Subclass  markers  (100,  Subclass  Name)  divides  DXF objects into several sections. Group codes can be
       reused in different sections. A subclass ends with the following subclass marker or at the  beginning  of
       xdata or the end of the object. See Subclass Marker Example in the DXF Reference.

   Quote about group codes from the DXF reference
          Some  group  codes  that  define an entity always appear; others are optional and appear only if their
          values differ from the defaults.

          Do not write programs that rely on the order given here. The end of an entity is indicated by the next
          0 group, which begins the next entity or indicates the end of the section.

          Note: Accommodating DXF files from future releases of AutoCAD will be easier if  you  write  your  DXF
          processing  program in a table-driven way, ignore undefined group codes, and make no assumptions about
          the order of group codes in an entity. With each new AutoCAD release, new group codes will be added to
          entities to accommodate additional features.

   Usage of group codes in subclasses twice
       Some later entities entities contains the same group code twice for different purposes, so order  in  the
       sense of which one comes first is important.  (e.g. ATTDEF group code 280)

   Tag order is sometimes important especially for AutoCAD
       In  LWPOLYLINE  the order of tags is important, if the count tag is not the first tag in the AcDbPolyline
       subclass, AutoCAD will not close the polyline when the close flag is set, by the way  other  applications
       like BricsCAD ignores the tag order and renders the polyline always correct.

   Extension Dictionary
       The  extension  dictionary  is  an  optional  sequence that stores the handle of a DICTIONARY object that
       belongs to the current object, which in turn may contain entries.  This  facility  allows  attachment  of
       arbitrary database objects to any database object. Any object or entity may have this section.

       The extension dictionary tag sequence:

          102
          {ACAD_XDICTIONARY
          360
          Hard-owner ID/handle to owner dictionary
          102
          }

   Persistent Reactors
       Persistent reactors are an optional sequence that stores object handles of objects registering themselves
       as reactors on the current object. Any object or entity may have this section.

       The persistent reactors tag sequence:

          102
          {ACAD_REACTORS
          330
          first Soft-pointer ID/handle to owner dictionary
          330
          second Soft-pointer ID/handle to owner dictionary
          ...
          102
          }

   Application-Defined Codes
       Starting  at  DXF  R13,  DXF  objects  can  contain  application-defined  codes  outside  of  XDATA. This
       application-defined codes can contain any tag except (0, …) and (102, ‘{…’). “{YOURAPPID” means the APPID
       string with an preceding “{”. The application defined data tag sequence:

          102
          {YOURAPPID
          ...
          102
          }

       (102, 'YOURAPPID}') is also a valid closing tag:

          102
          {YOURAPPID
          ...
          102
          YOURAPPID}

       All groups defined with a beginning (102, …) appear in  the  DXF  reference  before  the  first  subclass
       marker,  I  don’t  know  if these groups can appear after the first or any subclass marker. Ezdxf accepts
       them at any position, and by default ezdxf adds new app data in front of the first subclass marker to the
       first tag section of an DXF object.

       Exception XRECORD: Tags with group code 102 and a value string without a  preceding  “{”  or  the  scheme
       “YOURAPPID}”, should be treated as usual group codes.

   Embedded Objects
       The  concept  of  embedded  objects was introduced with AutoCAD 2018 (DXF version AC1032) and this is the
       only information I found about it at the Autodesk knowledge base: Embedded and Encapsulated Objects

       Quote from Embedded and Encapsulated Objects:
          For DXF filing, the embedded object must be filed out and in after all the data of  the  encapsulating
          object has been filed out and in.

          A  separator  is  needed  between the encapsulating object’s data and the subsequent embedded object’s
          data. The separator must be similar in function to the group 0 or 100 in that it must cause the  filer
          to  stop  reading  data.   The  normal  DXF  group code 0 cannot be used because DXF proxies use it to
          determine when to stop reading data. The group code 100 could have been used, but it might have caused
          confusion when manually reading a DXF file, and there was a  need  to  distinguish  when  an  embedded
          object  is  about to be written out in order to do some internal bookkeeping. Therefore, the DXF group
          code 101 was introduced.

       Hard facts:

       • Only used in ATTRIB, ATTDEF (embedded MTEXT) and MTEXT (columns) in DXF R2018.

       • Embedded object start with (101, “Embedded Object”) tag

       • Embedded object is appended to the encapsulated object

       • Embedded object tags can contain any group code except the DXF structure tag (0, …)

       Unconfirmed assumptions:

       • The embedded object is written before the Extended Data. No examples for  entities  including  embedded
         objects and XDATA at the same time.

       • XDATA sections replaced by embedded objects, at least for the MTEXT entity

       • The encapsulating object can contain more than one embedded object.

       • Embedded objects separated by (101, “Embedded Object”) tags

       • every entity can contain embedded objects

       Real world example from an AutoCAD 2018 file:

          100       <<< start of encapsulating object
          AcDbMText
          10
          2762.148
          20
          2327.073
          30
          0.0
          40
          2.5
          41
          18.852
          46
          0.0
          71
          1
          72
          5
          1
          {\fArial|b0|i0|c162|p34;CHANGE;\P\P\PTEXT}
          73
          1
          44
          1.0
          101       <<< start of embedded object
          Embedded Object
          70
          1
          10
          1.0
          20
          0.0
          30
          0.0
          11
          2762.148
          21
          2327.073
          31
          0.0
          40
          18.852
          41
          0.0
          42
          15.428
          43
          15.043
          71
          2
          72
          1
          44
          18.852
          45
          12.5
          73
          0
          74
          0
          46
          0.0

   Handles
       A handle is an arbitrary but in your DXF file unique hex value as string like ‘10FF’.  It is common to to
       use uppercase letters for hex numbers. Handle can have up to 16 hexadecimal digits (8 bytes).

       For  DXF R10 until R12 the usage of handles was optional. The header variable $HANDLING set to 1 indicate
       the usage of handles, else $HANDLING is 0 or missing.

       For DXF R13 and later the usage of handles is mandatory and the header variable $HANDLING was removed.

       The $HANDSEED variable in the header section should be greater than the biggest handle used  in  the  DXF
       file,  so  a  CAD  application can assign handle values starting with the $HANDSEED value. But as always,
       don’t rely on the header variable it could be wrong, AutoCAD ignores this value.

   Handle Definition
       Entity handle definition is always the (5, ...), except for entities of the DIMSTYLE  table  (105,  ...),
       because the DIMSTYLE entity has also a group code 5 tag for DIMBLK.

   Handle Pointer
       A pointer is a reference to a DXF object in the same DXF file. There are four types of pointers:

       • Soft-pointer handle

       • Hard-pointer handle

       • Soft-owner handle

       • Hard-owner handle

       Also,  a group code range for “arbitrary” handles is defined to allow convenient storage of handle values
       that are unchanged at any operation (AutoCAD).

   Pointer and Ownership
       A pointer is a reference that indicates usage, but not possession or responsibility, for another  object.
       A  pointer reference means that the object uses the other object in some way, and shares access to it. An
       ownership reference means that an owner object is responsible for the objects for which it has  an  owner
       handle.  An object can have any number of pointer references associated with it, but it can have only one
       owner.

   Hard and Soft References
       Hard references, whether they are pointer or owner, protect an object from being purged.  Soft references
       do not.

       In AutoCAD, block definitions and complex entities are hard owners of their elements.  A symbol table and
       dictionaries  are  soft  owners  of their elements. Polyline entities are hard owners of their vertex and
       seqend entities. Insert entities are hard owners of their attrib and seqend entities.

       When establishing a reference to another object, it is recommended  that  you  think  about  whether  the
       reference should protect an object from the PURGE command.

       A hard- and soft pointers will be translated during INSERT and XREF operations.

   Arbitrary Handles
       Arbitrary  handles  are  distinct  in  that  they  are  not  translated to session-persistent identifiers
       internally, or to entity names in AutoLISP, and so on. They are stored as handles. When handle values are
       translated in drawing-merge operations, arbitrary handles are ignored.

       In all environments, arbitrary handles can be exchanged for entity names of the current drawing by  means
       of  the handent functions. A common usage of arbitrary handles is to refer to objects in external DXF and
       DWG files.

   About 1005 Group Codes
       (1005, ...) xdata have the same behavior and semantics as  soft  pointers,  which  means  that  they  are
       translated  whenever  the  host  object  is  merged into a different drawing. However, 1005 items are not
       translated to session-persistent identifiers or internal entity names in AutoLISP and ObjectARX. They are
       stored as handles.

       When a drawing with handles and extended data handles is imported  into  another  drawing  using  INSERT,
       INSERT  ,  XREF  Bind,  XBIND,  or  partial OPEN, the extended data handles are **translated* in the same
       manner as their corresponding entity handles, thus maintaining their binding. This is also  done  in  the
       EXPLODE  block  operation  or for any other AutoCAD operation. When AUDIT detects an extended data handle
       that doesn’t match the handle of an entity in the drawing file, it is considered an error.  If  AUDIT  is
       fixing entities, it sets the handle to “0”

   DXF File Structure
       A  DXF  File  is simply an ASCII text file with a file type of .dxf and special formatted text. The basic
       file structure are DXF tags, a DXF tag consist of a DXF group code as an integer value on  its  own  line
       and  a the DXF value on the following line. In the ezdxf documentation DXF tags will be written as (group
       code, value). There exist a binary DXF format, but it seems that it is not often used  and  for  reducing
       file size, zipping is much more efficient.  ezdxf does support reading binary encoded DXF files.

       SEE ALSO:
          For more information about DXF tags see: DXF Tags

       A  usual  DXF file is organized in sections, starting with the DXF tag (0, ‘SECTION’) and ending with the
       DXF tag (0, ‘ENDSEC’). The (0, ‘EOF’) tag signals the end of file.

       1. HEADER: General information about the drawing is  found  in  this  section  of  the  DXF  file.   Each
          parameter has a variable name starting with ‘$’ and an associated value. Has to be the first section.

       2. CLASSES: Holds the information for application defined classes. (DXF R13 and later)

       3. TABLES:: Contains several tables for style and property definitions.

          • Linetype table (LTYPE)

          • Layer table (LAYER)

          • Text Style table (STYLE)

          • View  table  (VIEW):  (IMHO)  layout  of the CAD working space, only interesting for interactive CAD
            applications

          • Viewport configuration table (VPORT): The VPORT table is unique  in  that  it  may  contain  several
            entries with the same name (indicating a multiple-viewport configuration). The entries corresponding
            to  the  active viewport configuration all have the name *ACTIVE. The first such entry describes the
            current viewport.

          • Dimension Style table (DIMSTYLE)

          • User Coordinate System table (UCS) (IMHO) only interesting for interactive CAD applications

          • Application Identification table (APPID): Table of names for  all  applications  registered  with  a
            drawing.

          • Block Record table (BLOCK_RECORD) (DXF R13 and Later)

       4. BLOCKS:  Contains  all  block definitions. The block name *Model_Space or *MODEL_SPACE is reserved for
          the drawing modelspace and the block name *Paper_Space or *PAPER_SPACE  is  reserved  for  the  active
          paperspace  layout.   Both  block  definitions are empty, the content of the modelspace and the active
          paperspace is stored in the ENTITIES section. The entities of other  layouts  are  stored  in  special
          block definitions called *Paper_Spacennn, nnn is an arbitrary but unique number.

       5. ENTITIES: Contains all graphical entities of the modelspace and the active paperspace layout. Entities
          of other layouts are stored in the BLOCKS sections.

       6. OBJECTS: Contains all non-graphical objects of the drawing (DXF R13 and later)

       7. THUMBNAILIMAGE:  Contains  a preview image of the DXF file, it is optional and can usually be ignored.
          (DXF R13 and later)

       8. ACDSDATA: (DXF R2013 and later) No information in the DXF reference about this section

       9. END OF FILE

       For further information read the original DXF Reference.

       Structure of a usual DXF R12 file:

          0           <<< Begin HEADER section, has to be the first section
          SECTION
          2
          HEADER
                      <<< Header variable items go here
          0           <<< End HEADER section
          ENDSEC
          0           <<< Begin TABLES section
          SECTION
          2
          TABLES
          0
          TABLE
          2
          VPORT
          70          <<< viewport table maximum item count
                      <<< viewport table items go here
          0
          ENDTAB
          0
          TABLE
          2
          APPID, DIMSTYLE, LTYPE, LAYER, STYLE, UCS, VIEW, or VPORT
          70          <<< Table maximum item count, a not reliable value and ignored by AutoCAD
                      <<< Table items go here
          0
          ENDTAB
          0           <<< End TABLES section
          ENDSEC
          0           <<< Begin BLOCKS section
          SECTION
          2
          BLOCKS
                      <<< Block definition entities go here
          0           <<< End BLOCKS section
          ENDSEC
          0           <<< Begin ENTITIES section
          SECTION
          2
          ENTITIES
                      <<< Drawing entities go here
          0           <<< End ENTITIES section
          ENDSEC
          0           <<< End of file marker (required)
          EOF

   Minimal DXF Content
   DXF R12
       Contrary to the previous chapter, the DXF R12 format  (AC1009)  and  prior  requires  just  the  ENTITIES
       section:

          0
          SECTION
          2
          ENTITIES
          0
          ENDSEC
          0
          EOF

   DXF R13/R14 and later
       DXF version R13/14 and later needs much more DXF content than DXF R12.

       Required sections: HEADER, CLASSES, TABLES, ENTITIES, OBJECTS

       The HEADER section requires two entries:

       • $ACADVER

       • $HANDSEED

       The CLASSES section can be empty, but some DXF entities requires class definitions to work in AutoCAD.

       The TABLES section requires following tables:

       • VPORT entry *ACTIVE is not required! Empty table is ok for AutoCAD.

       • LTYPE with at least the following line types defined:

         • BYBLOCK

         • BYLAYER

         • CONTINUOUS

       • LAYER with at least an entry for layer ‘0’

       • STYLE with at least an entry for style STANDARD

       • VIEW can be empty

       • UCS can be empty

       • APPID with at least an entry for ACAD

       • DIMSTYLE with at least an entry for style STANDARD

       • BLOCK_RECORDS with two entries:

         • *MODEL_SPACE

         • *PAPER_SPACE

       The BLOCKS section requires two BLOCKS:

       • *MODEL_SPACE

       • *PAPER_SPACE

       The ENTITIES section can be empty.

       The OBJECTS section requires following entities:

       • DICTIONARY - the root dict - one entry named ACAD_GROUP

       • DICTIONARY ACAD_GROUP can be empty

       Minimal DXF to download: https://github.com/mozman/ezdxf/tree/master/examples_dxf

   Data Model
   Database Objects
       (from the DXF Reference)

       AutoCAD  drawings  consist  largely  of structured containers for database objects. Database objects each
       have the following features:

          • A handle whose value is unique to the drawing/DXF file, and is constant  for  the  lifetime  of  the
            drawing. This format has existed since AutoCAD Release 10, and as of AutoCAD Release 13, handles are
            always enabled.

          • An optional XDATA table, as entities have had since AutoCAD Release 11.

          • An optional persistent reactor table.

          • An  optional  ownership pointer to an extension dictionary which, in turn, owns subobjects placed in
            it by an application.

       Symbol tables and symbol table records are database objects and, thus, have a handle.  They can also have
       xdata and persistent reactors in their DXF records.

   DXF R12 Data Model
       The DXF R12 data model is identical to the file structure:

          • HEADER section: common settings for the DXF drawing

          • TABLES section: definitions for LAYERS, LINETYPE, STYLES ….

          • BLOCKS section: block definitions and its content

          • ENTITIES section: modelspace and paperspace content

       References are realized by simple names. The INSERT entity references the BLOCK definition by  the  BLOCK
       name, a TEXT entity defines the associated STYLE and LAYER by its name and so on, handles are not needed.
       Layout  association  of graphical entities in the ENTITIES section by the paper_space tag (67, 0 or 1), 0
       or missing tag means modelspace, 1 means paperspace. The content of BLOCK definitions is enclosed by  the
       BLOCK and the ENDBLK entity, no additional references are needed.

       A  clean and simple file structure and data model, which seems to be the reason why the DXF R12 Reference
       (released 1992) is still a widely used file format and Autodesk/AutoCAD supports the  format  by  reading
       and writing DXF R12 files until today (DXF R13/R14 has no writing support by AutoCAD!).

       TODO: list of available entities

       SEE ALSO:
          More information about the DXF DXF File Structure

   DXF R13+ Data Model
       With  the DXF R13 file format, handles are mandatory and they are really used for organizing the new data
       structures introduced with DXF R13.

       The HEADER section is still the same with just more available settings.

       The new CLASSES section contains AutoCAD specific data, has to be written like AutoCAD it does, but  must
       not be understood.

       The TABLES section got a new BLOCK_RECORD table - see Block Management Structures for more information.

       The  BLOCKS  sections  is mostly the same, but with handles, owner tags and new ENTITY types.  Not active
       paperspace layouts store their content also in the BLOCKS section - see Layout Management Structures  for
       more information.

       The ENTITIES section is also mostly same, but with handles, owner tags and new ENTITY types.

       TODO: list of new available entities

       And the new OBJECTS section - now its getting complicated!

       Most  information  about  the OBJECTS section is just guessed or gathered by trail and error, because the
       documentation of the OBJECTS section and its objects in the DXF reference provided by  Autodesk  is  very
       shallow.   This  is  also  the  reason  why  I  started  the DXF Internals section, may be it helps other
       developers to start one or two steps above level zero.

       The OBJECTS sections stores all the non-graphical entities of the DXF  drawing.   Non-graphical  entities
       from  now  on  just  called  ‘DXF  objects’  to  differentiate  them from graphical entities, just called
       ‘entities’. The OBJECTS section follows commonly the ENTITIES section, but this is not mandatory.

       DXF R13 introduces several new DXF objects, which resides exclusive in the OBJECTS  section,  taken  from
       the  DXF  R14  reference,  because  I have no access to the DXF R13 reference, the DXF R13 reference is a
       compiled .hlp file which can’t be read on Windows 10 or later, this  a  perfect  example  for  not  using
       closed (proprietary) data formats ;):

          • DICTIONARY: a general structural entity as a <name: handle> container

          • ACDBDICTIONARYWDFLT: a DICTIONARY with a default value

          • DICTIONARYVAR: used by AutoCAD to store named values in the database

          • ACAD_PROXY_OBJECT: proxy object for entities created by other applications than AutoCAD

          • GROUP: groups graphical entities without the need of a BLOCK definition

          • IDBUFFER: just a list of references to objects

          • IMAGEDEF: IMAGE definition structure, required by the IMAGE entity

          • IMAGEDEF_REACTOR: also required by the IMAGE entity

          • LAYER_INDEX: container for LAYER names

          • MLINESTYLE

          • OBJECT_PTR

          • RASTERVARIABLES

          • SPATIAL_INDEX: is always written out empty to a DXF file. This object can be ignored.

          • SPATIAL_FILTER

          • SORTENTSTABLE: control for regeneration/redraw order of entities

          • XRECORD:  used to store and manage arbitrary data. This object is similar in concept to XDATA but is
            not limited by size or order. Not supported by R13c0 through R13c3.

       Still missing the LAYOUT object, which is mandatory in DXF R2000 to manage multiple paperspace layouts. I
       don’t know how DXF R13/R14 manages multiple layouts or if they even support this  feature,  but  I  don’t
       care  much  about  DXF  R13/R14, because AutoCAD has no write support for this two formats anymore. Ezdxf
       tries to upgrade this two DXF versions to DXF R2000 with the advantage of only two different data  models
       to support: DXF R12 and DXF R2000+

       New objects introduced by DXF R2000:

          • LAYOUT: management object for modelspace and multiple paperspace layouts

          • ACDBPLACEHOLDER: surprise - just a place holder

       New objects in DXF R2004:

          • DIMASSOC

          • LAYER_FILTER

          • MATERIAL

          • PLOTSETTINGS

          • VBA_PROJECT

       New objects in DXF R2007:

          • DATATABLE

          • FIELD

          • LIGHTLIST

          • RENDER

          • RENDERENVIRONMENT

          • MENTALRAYRENDERSETTINGS

          • RENDERGLOBAL

          • SECTION

          • SUNSTUDY

          • TABLESTYLE

          • UNDERLAYDEFINITION

          • VISUALSTYLE

          • WIPEOUTVARIABLES

       New objects in DXF R2013:

          • GEODATA

       New objects in DXF R2018:

          • ACDBNAVISWORKSMODELDEF

       Undocumented objects:

          • SCALE

          • ACDBSECTIONVIEWSTYLE

          • FIELDLIST

   Objects Organisation
       Many objects in the OBJECTS section are organized in a tree-like structure of DICTIONARY objects.

       Starting  point for this data structure is the ‘root’ DICTIONARY with several entries to other DICTIONARY
       objects.  The root DICTIONARY has to be the first object in the OBJECTS section.   The  management  dicts
       for  GROUP  and  LAYOUT  objects  are  really important, but IMHO most of the other management tables are
       optional and for the most use cases not necessary.  Ezdxf creates only these entries in the root dict and
       most of them pointing to an empty DICTIONARY:

          • ACAD_COLOR: points to an empty DICTIONARY

          • ACAD_GROUP: required

          • ACAD_LAYOUT: required

          • ACAD_MATERIAL: points to an empty DICTIONARY

          • ACAD_MLEADERSTYLE: points to an empty DICTIONARY

          • ACAD_MLINESTYLE: points to an empty DICTIONARY

          • ACAD_PLOTSETTINGS: points to an empty DICTIONARY

          • ACAD_PLOTSTYLENAME: required, points to ACDBDICTIONARYWDFLT with one entry: ‘Normal’

          • ACAD_SCALELIST: points to an empty DICTIONARY

          • ACAD_TABLESTYLE: points to an empty DICTIONARY

          • ACAD_VISUALSTYLE: points to an empty DICTIONARY

   Root DICTIONARY content for DXF R2018
          0
          SECTION
          2       <<< start of the OBJECTS section
          OBJECTS
          0       <<< root DICTIONARY has to be the first object in the OBJECTS section
          DICTIONARY
          5       <<< handle
          C
          330     <<< owner tag
          0       <<< always #0, has no owner
          100
          AcDbDictionary
          281     <<< hard owner flag
          1
          3       <<< first entry
          ACAD_CIP_PREVIOUS_PRODUCT_INFO
          350     <<< handle to target (pointer)
          78B     <<< points to a XRECORD with product info about the creator application
          3       <<< entry with unknown meaning, if I should guess: something with about colors ...
          ACAD_COLOR
          350
          4FB     <<< points to a DICTIONARY
          3       <<< entry with unknown meaning
          ACAD_DETAILVIEWSTYLE
          350
          7ED     <<< points to a DICTIONARY
          3       <<< GROUP management, mandatory in all DXF versions
          ACAD_GROUP
          350
          4FC     <<< points to a DICTIONARY
          3       <<< LAYOUT management, mandatory if more than the *active* paperspace is used
          ACAD_LAYOUT
          350
          4FD     <<< points to a DICTIONARY
          3       <<< MATERIAL management
          ACAD_MATERIAL
          350
          4FE     <<< points to a DICTIONARY
          3       <<< MLEADERSTYLE management
          ACAD_MLEADERSTYLE
          350
          4FF     <<< points to a DICTIONARY
          3       <<< MLINESTYLE management
          ACAD_MLINESTYLE
          350
          500     <<< points to a DICTIONARY
          3       <<< PLOTSETTINGS management
          ACAD_PLOTSETTINGS
          350
          501     <<< points to a DICTIONARY
          3       <<< plot style name management
          ACAD_PLOTSTYLENAME
          350
          503     <<< points to a ACDBDICTIONARYWDFLT
          3       <<< SCALE management
          ACAD_SCALELIST
          350
          504     <<< points to a DICTIONARY
          3       <<< entry with unknown meaning
          ACAD_SECTIONVIEWSTYLE
          350
          7EB     <<< points to a DICTIONARY
          3       <<< TABLESTYLE management
          ACAD_TABLESTYLE
          350
          505     <<< points to a DICTIONARY
          3       <<< VISUALSTYLE management
          ACAD_VISUALSTYLE
          350
          506     <<< points to a DICTIONARY
          3       <<< entry with unknown meaning
          ACDB_RECOMPOSE_DATA
          350
          7F3
          3       <<< entry with unknown meaning
          AcDbVariableDictionary
          350
          7AE     <<< points to a DICTIONARY with handles to DICTIONARYVAR objects
          0
          DICTIONARY
          ...
          ...
          0
          ENDSEC

   DXF Structures
   DXF Sections
   HEADER Section
       In DXF R12 and prior the HEADER section was optional, but since DXF R13 the HEADER section is  mandatory.
       The overall structure is:

          0           <<< Begin HEADER section
          SECTION
          2
          HEADER
          9
          $ACADVER    <<< Header variable items go here
          1
          AC1009
          ...
          0
          ENDSEC      <<< End HEADER section

       A header variable has a name defined by a (9, Name) tag and following value tags.

       SEE ALSO:
          Documentation of ezdxf HeaderSection class.

          DXF Reference: Header Variables

   CLASSES Section
       The  CLASSES  section contains CLASS definitions which are only important for Autodesk products, some DXF
       entities require a class definition or AutoCAD will not open the DXF file.

       The CLASSES sections was introduced with DXF AC1015 (AutoCAD Release R13).

       SEE ALSO:
          DXF Reference: About the DXF CLASSES Section

          Documentation of ezdxf ClassesSection class.

       The CLASSES section in DXF files holds the information for application-defined  classes  whose  instances
       appear  in  the  BLOCKS,  ENTITIES,  and  OBJECTS  sections  of the database.  It is assumed that a class
       definition is permanently fixed in the class hierarchy.  All fields are required.

       Update 2019-03-03:

       Class names are not unique, Autodesk Architectural Desktop 2007 uses the same name,  but  with  different
       CPP  class  names  in the CLASS section, so storing classes in a dictionary by name as key caused loss of
       class entries in ezdxf, using a tuple of (name, cpp_class_name) as storage key solved the problem.

   CLASS Entities
       SEE ALSO:
          DXF Reference: Group Codes for the CLASS entity

       CLASS entities have no handle and therefore ezdxf does not store the CLASS entity in the drawing entities
       database!

          0
          SECTION
          2           <<< begin CLASSES section
          CLASSES
          0           <<< first CLASS entity
          CLASS
          1           <<< class DXF entity name; THIS ENTRY IS MAYBE NOT UNIQUE
          ACDBDICTIONARYWDFLT
          2           <<< C++ class name; always unique
          AcDbDictionaryWithDefault
          3           <<< application name
          ObjectDBX Classes
          90          <<< proxy capabilities flags
          0
          91          <<< instance counter for custom class, since DXF version AC1018 (R2004)
          0           <<< no problem if the counter is wrong, AutoCAD doesn't care about
          280         <<< was-a-proxy flag: 1= class was not loaded when this DXF file was created
          0           <<< 0= otherwise
          281         <<< is-an-entity flag: 1= instances reside in the BLOCKS or ENTITIES section
          0           <<< 0= instances may appear only in the OBJECTS section
          0           <<< next CLASS entity
          CLASS
          ...
          0           <<< end of CLASSES section
          ENDSEC

   TABLES Section
       The TABLES section contains the resource tables of a DXF document.

   APPID Table
       The APPID table stores unique application identifiers. These identifiers are used to mark sub-sections in
       the XDATA section of DXF entities. AutoCAD will not load DXF files which uses AppIDs without an entry  in
       the AppIDs table and the “ACAD” entry must always exist.

       Some known AppIDs:
                          ┌──────────────────────┬──────────┬──────────────────────────────┐
                          │ APPID                │ Used by  │ Description                  │
                          ├──────────────────────┼──────────┼──────────────────────────────┤
                          │ ACAD                 │ Autodesk │ various use cases            │
                          ├──────────────────────┼──────────┼──────────────────────────────┤
                          │ AcAecLayerStandard   │ Autodesk │ layer description            │
                          ├──────────────────────┼──────────┼──────────────────────────────┤
                          │ AcCmTransparency     │ Autodesk │ layer transparency           │
                          ├──────────────────────┼──────────┼──────────────────────────────┤
                          │ HATCHBACKGROUNDCOLOR │ Autodesk │ background color for pattern │
                          │                      │          │ fillings                     │
                          ├──────────────────────┼──────────┼──────────────────────────────┤
                          │ EZDXF                │ ezdxf    │ meta data                    │
                          └──────────────────────┴──────────┴──────────────────────────────┘

       SEE ALSO:

          • DXF Reference: TABLES Section

          • DXF Reference: APPID Table

          • AppID class

   Table Structure DXF R12
          0           <<< start of table
          TABLE
          2           <<< table type
          APPID
          70          <<< count of table entries, AutoCAD ignores this value
          3
          0           <<< 1. table entry
          APPID
          2           <<< unique application identifier
          ACAD
          70          <<< flags, see `APPID`_ reference
          0           <<< in common cases always 0
          0           <<< next table entry
          APPID
          ...
          0           <<< end of APPID table
          ENDTAB

   Table Structure DXF R2000+
          0           <<< start of table
          TABLE
          2           <<< table type
          APPID
          5           <<< table handle
          3
          330         <<< owner tag, tables have no owner
          0
          100         <<< subclass marker
          AcDbSymbolTable
          70          <<< count of table entries, AutoCAD ignores this value
          3
          0           <<< first table entry
          APPID
          5           <<< handle of appid
          2A
          330         <<< owner handle, handle of APPID table
          3
          100         <<< subclass marker
          AcDbSymbolTableRecord
          100         <<< subclass marker
          AcDbRegAppTableRecord
          2           <<< unique application identifier
          ACAD
          70          <<< flags, see `APPID`_ reference
          0           <<< in common cases always 0
          0           <<< next table entry
          APPID
          ...
          0           <<< end of APPID table
          ENDTAB

   Name References
       APPID table entries are referenced by name:

          • XDATA section of DXF entities

   BLOCK_RECORD Table
       Block records are essential elements for the entities management, each layout (modelspace and paperspace)
       and  every block definition has a block record entry. This block record is the hard owner of the entities
       of layouts, each entity has an owner handle which points to a block record of the layout.

   DIMSTYLE Table
       The DIMSTYLE table stores all dimension style definitions of a DXF drawing.

       You have access to the dimension styles table by the attribute Drawing.dimstyles.

       SEE ALSO:

          • DXF Reference: TABLES Section

          • DXF Reference: DIMSTYLE Table

   Table Structure DXF R12
          0           <<< start of table
          TABLE
          2           <<< set table type
          DIMSTYLE
          70          <<< count of line types defined in this table, AutoCAD ignores this value
          9
          0           <<< 1. DIMSTYLE table entry
          DIMSTYLE
                      <<< DIMSTYLE data tags
          0           <<< 2. DIMSTYLE table entry
          DIMSTYLE
                      <<< DIMSTYLE data tags and so on
          0           <<< end of DIMSTYLE table
          ENDTAB

   DIMSTYLE Entry DXF R12
   DIMSTYLE Variables DXF R12
       Source: CADDManager Blog [image] [image]
                                  ──────────────────────────────────────────────────
                                    DIMVAR     Code   Description
                                  ──────────────────────────────────────────────────
                                    DIMALT     170    Controls  the   display   of
                                                      alternate      units      in
                                                      dimensions.
                                  ──────────────────────────────────────────────────
                                    DIMALTD    171    Controls   the   number   of
                                                      decimal  places in alternate
                                                      units. If DIMALT  is  turned
                                                      on,  DIMALTD sets the number
                                                      of digits displayed  to  the
                                                      right  of  the decimal point
                                                      in       the       alternate
                                                      measurement.
                                  ──────────────────────────────────────────────────
                                    DIMALTF    143    Controls  the multiplier for
                                                      alternate units.  If  DIMALT
                                                      is    turned   on,   DIMALTF
                                                      multiplies linear dimensions
                                                      by a  factor  to  produce  a
                                                      value in an alternate system
                                                      of  measurement. The initial
                                                      value represents the  number
                                                      of millimeters in an inch.
                                  ──────────────────────────────────────────────────
                                    DIMAPOST   4      Specifies  a  text prefix or
                                                      suffix  (or  both)  to   the
                                                      alternate          dimension
                                                      measurement for all types of
                                                      dimensions  except  angular.
                                                      For instance, if the current
                                                      units   are   Architectural,
                                                      DIMALT  is  on,  DIMALTF  is
                                                      25.4    (the    number    of
                                                      millimeters    per    inch),
                                                      DIMALTD is 2, and DIMPOST is
                                                      set  to  “mm”, a distance of
                                                      10 units would be  displayed
                                                      as 10”[254.00mm].
                                  ──────────────────────────────────────────────────
                                    DIMASZ     41     Controls    the    size   of
                                                      dimension  line  and  leader
                                                      line     arrowheads.    Also
                                                      controls the  size  of  hook
                                                      lines.   Multiples   of  the
                                                      arrowhead   size   determine
                                                      whether  dimension lines and
                                                      text should fit between  the
                                                      extension  lines.  DIMASZ is
                                                      also used to scale arrowhead
                                                      blocks  if  set  by  DIMBLK.
                                                      DIMASZ  has  no  effect when
                                                      DIMTSZ is other than zero.
                                  ──────────────────────────────────────────────────
                                    DIMBLK     5      Sets  the  arrowhead   block
                                                      displayed  at  the  ends  of
                                                      dimension lines.
                                  ──────────────────────────────────────────────────
                                    DIMBLK1    6      Sets the arrowhead  for  the
                                                      first  end  of the dimension
                                                      line when DIMSAH is 1.
                                  ──────────────────────────────────────────────────
                                    DIMBLK2    7      Sets the arrowhead  for  the
                                                      second  end of the dimension
                                                      line when DIMSAH is 1.
                                  ──────────────────────────────────────────────────
                                    DIMCEN     141    Controls drawing  of  circle
                                                      or   arc  center  marks  and
                                                      centerlines      by      the
                                                      DIMCENTER,  DIMDIAMETER, and
                                                      DIMRADIUS   commands.    For
                                                      DIMDIAMETER  and  DIMRADIUS,
                                                      the  center  mark  is  drawn
                                                      only   if   you   place  the
                                                      dimension line  outside  the
                                                      circle or arc.

                                                             • 0   =    No  center
                                                               marks or lines  are
                                                               drawn

                                                             • <0   =  Centerlines
                                                               are drawn

                                                             • >0 =  Center  marks
                                                               are drawn
                                  ──────────────────────────────────────────────────
                                    DIMCLRD    176    Assigns  colors to dimension
                                                      lines,    arrowheads,    and
                                                      dimension leader lines.

                                                             • 0 =  BYBLOCK

                                                             • 1-255 = ACI AutoCAD
                                                               Color Index

                                                             • 256 =  BYLAYER
                                  ──────────────────────────────────────────────────
                                    DIMCLRE    177    Assigns  colors to dimension
                                                      extension lines, values like
                                                      DIMCLRD
                                  ──────────────────────────────────────────────────
                                    DIMCLRT    178    Assigns colors to  dimension
                                                      text, values like DIMCLRD
                                  ──────────────────────────────────────────────────
                                    DIMDLE     46     Sets    the   distance   the
                                                      dimension    line    extends
                                                      beyond  the  extension  line
                                                      when  oblique  strokes   are
                                                      drawn instead of arrowheads.
                                  ──────────────────────────────────────────────────
                                    DIMDLI     43     Controls  the spacing of the
                                                      dimension lines in  baseline
                                                      dimensions.  Each  dimension
                                                      line  is  offset  from   the
                                                      previous one by this amount,
                                                      if   necessary,   to   avoid
                                                      drawing  over  it.   Changes
                                                      made  with  DIMDLI  are  not
                                                      applied     to      existing
                                                      dimensions.
                                  ──────────────────────────────────────────────────
                                    DIMEXE     44     Specifies  how far to extend
                                                      the  extension  line  beyond
                                                      the dimension line.
                                  ──────────────────────────────────────────────────
                                    DIMEXO     42     Specifies  how far extension
                                                      lines are offset from origin
                                                      points.  With   fixed-length
                                                      extension  lines, this value
                                                      determines    the    minimum
                                                      offset.
                                  ──────────────────────────────────────────────────
                                    DIMGAP     147    Sets the distance around the
                                                      dimension   text   when  the
                                                      dimension  line  breaks   to
                                                      accommodate  dimension text.
                                                      Also sets  the  gap  between
                                                      annotation  and  a hook line
                                                      created  with   the   LEADER
                                                      command.   If  you  enter  a
                                                      negative    value,    DIMGAP
                                                      places   a  box  around  the
                                                      dimension text.

                                                      DIMGAP is also used  as  the
                                                      minimum length for pieces of
                                                      the dimension line. When the
                                                      default   position  for  the
                                                      dimension      text       is
                                                      calculated,      text     is
                                                      positioned    inside     the
                                                      extension   lines   only  if
                                                      doing    so    breaks    the
                                                      dimension   lines  into  two
                                                      segments at least as long as
                                                      DIMGAP.  Text  placed  above
                                                      or  below the dimension line
                                                      is  moved  inside  only   if
                                                      there   is   room   for  the
                                                      arrowheads, dimension  text,
                                                      and a margin between them at
                                                      least  as large as DIMGAP: 2
                                                      * (DIMASZ + DIMGAP).
                                  ──────────────────────────────────────────────────
                                    DIMLFAC    144    Sets  a  scale  factor   for
                                                      linear             dimension
                                                      measurements.   All   linear
                                                      dimension         distances,
                                                      including radii,  diameters,
                                                      and     coordinates,     are
                                                      multiplied by DIMLFAC before
                                                      being converted to dimension
                                                      text.  Positive  values   of
                                                      DIMLFAC   are   applied   to
                                                      dimensions      in      both
                                                      modelspace  and  paperspace;
                                                      negative values are  applied
                                                      to paperspace only.

                                                      DIMLFAC applies primarily to
                                                      nonassociative    dimensions
                                                      (DIMASSOC set 0 or  1).  For
                                                      nonassociative dimensions in
                                                      paperspace,  DIMLFAC must be
                                                      set  individually  for  each
                                                      layout      viewport      to
                                                      accommodate         viewport
                                                      scaling.

                                                      DIMLFAC  has  no  effect  on
                                                      angular dimensions,  and  is
                                                      not  applied  to  the values
                                                      held in  DIMRND,  DIMTM,  or
                                                      DIMTP.
                                  ──────────────────────────────────────────────────
                                    DIMLIM     72     Generates  dimension  limits
                                                      as the default text. Setting
                                                      DIMLIM to  On  turns  DIMTOL
                                                      off.

                                                             • 0    =    Dimension
                                                               limits   are    not
                                                               generated        as
                                                               default text

                                                             • 1    =    Dimension
                                                               limits          are
                                                               generated        as
                                                               default text
                                  ──────────────────────────────────────────────────
                                    DIMPOST    3      Specifies  a  text prefix or
                                                      suffix  (or  both)  to   the
                                                      dimension measurement.

                                                      For  example, to establish a
                                                      suffix for millimeters,  set
                                                      DIMPOST to mm; a distance of
                                                      19.2    units    would    be
                                                      displayed  as  19.2  mm.  If
                                                      tolerances  are  turned  on,
                                                      the suffix is applied to the
                                                      tolerances as well as to the
                                                      main dimension.

                                                      Use   “<>”    to    indicate
                                                      placement  of  the  text  in
                                                      relation  to  the  dimension
                                                      value.  For  example,  enter
                                                      “<>mm”  to  display  a   5.0
                                                      millimeter  radial dimension
                                                      as “5.0mm”. If  you  entered
                                                      mm “<>”, the dimension would
                                                      be displayed as “mm 5.0”.
                                  ──────────────────────────────────────────────────
                                    DIMRND     45     Rounds    all   dimensioning
                                                      distances to  the  specified
                                                      value.

                                                      For  instance,  if DIMRND is
                                                      set to 0.25,  all  distances
                                                      round  to  the  nearest 0.25
                                                      unit. If you set  DIMRND  to
                                                      1.0,  all distances round to
                                                      the  nearest  integer.  Note
                                                      that  the  number  of digits
                                                      edited  after  the   decimal
                                                      point    depends    on   the
                                                      precision  set  by   DIMDEC.
                                                      DIMRND  does  not  apply  to
                                                      angular dimensions.
                                  ──────────────────────────────────────────────────
                                    DIMSAH     173    Controls  the   display   of
                                                      dimension   line   arrowhead
                                                      blocks.

                                                             • 0 =  Use  arrowhead
                                                               blocks    set    by
                                                               DIMBLK

                                                             • 1 =  Use  arrowhead
                                                               blocks    set    by
                                                               DIMBLK1 and DIMBLK2
                                  ──────────────────────────────────────────────────
                                    DIMSCALE   40     Sets   the   overall   scale
                                                      factor       applied      to
                                                      dimensioning variables  that
                                                      specify sizes, distances, or
                                                      offsets.  Also  affects  the
                                                      leader  objects   with   the
                                                      LEADER command.

                                                      Use  MLEADERSCALE  to  scale
                                                      multileader objects  created
                                                      with the MLEADER command.

                                                             • 0.0  = A reasonable
                                                               default  value   is
                                                               computed  based  on
                                                               the scaling between
                                                               the  current  model
                                                               space  viewport and
                                                               paperspace. If  you
                                                               are  in  paperspace
                                                               or  modelspace  and
                                                               not    using    the
                                                               paperspace feature,
                                                               the scale factor is
                                                               1.0.

                                                             • >0 = A scale factor
                                                               is  computed   that
                                                               leads  text  sizes,
                                                               arrowhead    sizes,
                                                               and   other  scaled
                                                               distances  to  plot
                                                               at    their    face
                                                               values.

                                                             DIMSCALE   does   not
                                                             affect       measured
                                                             lengths, coordinates,
                                                             or angles.

                                                             Use    DIMSCALE    to
                                                             control  the  overall
                                                             scale of  dimensions.
                                                             However,    if    the
                                                             current     dimension
                                                             style  is annotative,
                                                             DIMSCALE           is
                                                             automatically  set to
                                                             zero     and      the
                                                             dimension   scale  is
                                                             controlled   by   the
                                                             CANNOSCALE     system
                                                             variable.    DIMSCALE
                                                             cannot  be  set  to a
                                                             non-zero  value  when
                                                             using      annotative
                                                             dimensions.
                                  ──────────────────────────────────────────────────
                                    DIMSE1     75     Suppresses  display  of  the
                                                      first extension line.

                                                             • 0  = Extension line
                                                               is not suppressed

                                                             • 1 = Extension  line
                                                               is suppressed
                                  ──────────────────────────────────────────────────
                                    DIMSE2     76     Suppresses  display  of  the
                                                      second extension line.

                                                             • 0 = Extension  line
                                                               is not suppressed

                                                             • 1  = Extension line
                                                               is suppressed
                                  ──────────────────────────────────────────────────
                                    DIMSOXD    175    Suppresses arrowheads if not
                                                      enough  space  is  available
                                                      inside the extension lines.

                                                             • 0  = Arrowheads are
                                                               not suppressed

                                                             • 1 = Arrowheads  are
                                                               suppressed

                                                             If  not  enough space
                                                             is  available  inside
                                                             the  extension  lines
                                                             and  DIMTIX  is   on,
                                                             setting DIMSOXD to On
                                                             suppresses        the
                                                             arrowheads. If DIMTIX
                                                             is off,  DIMSOXD  has
                                                             no effect.
                                  ──────────────────────────────────────────────────
                                    DIMTAD     77     Controls     the    vertical
                                                      position of text in relation
                                                      to the dimension line.

                                                             • 0  =  Centers   the
                                                               dimension      text
                                                               between         the
                                                               extension lines.

                                                             • 1   =   Places  the
                                                               dimension      text
                                                               above the dimension
                                                               line   except  when
                                                               the dimension  line
                                                               is  not  horizontal
                                                               and text inside the
                                                               extension lines  is
                                                               forced   horizontal
                                                               (DIMTIH =  1).  The
                                                               distance  from  the
                                                               dimension  line  to
                                                               the baseline of the
                                                               lowest line of text
                                                               is    the   current
                                                               DIMGAP value.

                                                             • 2  =   Places   the
                                                               dimension  text  on
                                                               the  side  of   the
                                                               dimension      line
                                                               farthest away  from
                                                               the        defining
                                                               points.

                                                             • 3  =   Places   the
                                                               dimension  text  to
                                                               conform to Japanese
                                                               Industrial
                                                               Standards (JIS).

                                                             • 4  =   Places   the
                                                               dimension      text
                                                               below the dimension
                                                               line.
                                  ──────────────────────────────────────────────────
                                    DIMTFAC    146    Specifies a scale factor for
                                                      the text height of fractions
                                                      and     tolerance     values
                                                      relative  to  the  dimension
                                                      text  height,  as   set   by
                                                      DIMTXT.

                                                      For  example,  if DIMTFAC is
                                                      set to 1.0, the text  height
                                                      of  fractions and tolerances
                                                      is the same  height  as  the
                                                      dimension  text.  If DIMTFAC
                                                      is set to 0.7500,  the  text
                                                      height   of   fractions  and
                                                      tolerances is three-quarters
                                                      the size of dimension text.
                                  ──────────────────────────────────────────────────
                                    DIMTIH     73     Controls  the  position   of
                                                      dimension  text  inside  the
                                                      extension  lines   for   all
                                                      dimension    types    except
                                                      Ordinate.

                                                             • 0  =  Aligns   text
                                                               with  the dimension
                                                               line

                                                             • 1  =   Draws   text
                                                               horizontally
                                  ──────────────────────────────────────────────────
                                    DIMTIX     174    Draws text between extension
                                                      lines.

                                                             • 0 = Varies with the
                                                               type  of dimension.
                                                               For   linear    and
                                                               angular dimensions,
                                                               text    is   placed
                                                               inside          the
                                                               extension  lines if
                                                               there is sufficient
                                                               room.  For   radius
                                                               and        diameter
                                                               dimensions      hat
                                                               don’t   fit  inside
                                                               the circle or  arc,
                                                               DIMTIX    has    no
                                                               effect  and  always
                                                               forces   the   text
                                                               outside the  circle
                                                               or arc.

                                                             • 1 = Draws dimension
                                                               text   between  the
                                                               extension     lines
                                                               even  if  it  would
                                                               ordinarily       be
                                                               placed      outside
                                                               those lines
                                  ──────────────────────────────────────────────────
                                    DIMTM      48     Sets the minimum (or  lower)
                                                      tolerance      limit     for
                                                      dimension text  when  DIMTOL
                                                      or   DIMLIM  is  on.   DIMTM
                                                      accepts  signed  values.  If
                                                      DIMTOL  is  on and DIMTP and
                                                      DIMTM are set  to  the  same
                                                      value,  a tolerance value is
                                                      drawn. If  DIMTM  and  DIMTP
                                  │          │      │ values   differ,  the  upper │
                                  │          │      │ tolerance is drawn above the │
                                  │          │      │ lower, and a  plus  sign  is │
                                  │          │      │ added  to the DIMTP value if │
                                  │          │      │ it is positive.  For  DIMTM, │
                                  │          │      │ the    program    uses   the │
                                  │          │      │ negative of  the  value  you │
                                  │          │      │ enter  (adding  a minus sign │
                                  │          │      │ if you  specify  a  positive │
                                  │          │      │ number  and  a  plus sign if │
                                  │          │      │ you   specify   a   negative │
                                  │          │      │ number).                     │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTOFL  │ 172  │ Controls whether a dimension │
                                  │          │      │ line  is  drawn  between the │
                                  │          │      │ extension  lines  even  when │
                                  │          │      │ the  text is placed outside. │
                                  │          │      │ For  radius   and   diameter │
                                  │          │      │ dimensions  (when  DIMTIX is │
                                  │          │      │ off), draws a dimension line │
                                  │          │      │ inside the circle or arc and │
                                  │          │      │ places the text, arrowheads, │
                                  │          │      │ and leader outside.          │
                                  │          │      │                              │
                                  │          │      │        • 0 = Does  not  draw │
                                  │          │      │          dimension     lines │
                                  │          │      │          between         the │
                                  │          │      │          measured     points │
                                  │          │      │          when arrowheads are │
                                  │          │      │          placed outside  the │
                                  │          │      │          measured points     │
                                  │          │      │                              │
                                  │          │      │        • 1 = Draws dimension │
                                  │          │      │          lines  between  the │
                                  │          │      │          measured     points │
                                  │          │      │          even           when │
                                  │          │      │          arrowheads      are │
                                  │          │      │          placed  outside the │
                                  │          │      │          measured points     │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTOH   │ 74   │ Controls  the  position   of │
                                  │          │      │ dimension  text  outside the │
                                  │          │      │ extension lines.             │
                                  │          │      │                              │
                                  │          │      │        • 0  =  Aligns   text │
                                  │          │      │          with  the dimension │
                                  │          │      │          line                │
                                  │          │      │                              │
                                  │          │      │        • 1  =   Draws   text │
                                  │          │      │          horizontally        │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTOL   │ 71   │ Appends     tolerances    to │
                                  │          │      │ dimension   text.    Setting │
                                  │          │      │ DIMTOL  to  on  turns DIMLIM │
                                  │          │      │ off.                         │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTP    │ 47   │ Sets the maximum (or  upper) │
                                  │          │      │ tolerance      limit     for │
                                  │          │      │ dimension text  when  DIMTOL │
                                  │          │      │ or   DIMLIM  is  on.   DIMTP │
                                  │          │      │ accepts  signed  values.  If │
                                  │          │      │ DIMTOL  is  on and DIMTP and │
                                  │          │      │ DIMTM are set  to  the  same │
                                  │          │      │ value,  a tolerance value is │
                                  │          │      │ drawn. If  DIMTM  and  DIMTP │
                                  │          │      │ values   differ,  the  upper │
                                  │          │      │ tolerance is drawn above the │
                                  │          │      │ lower and  a  plus  sign  is │
                                  │          │      │ added  to the DIMTP value if │
                                  │          │      │ it is positive.              │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTSZ   │ 142  │ Specifies   the   size    of │
                                  │          │      │ oblique     strokes    drawn │
                                  │          │      │ instead  of  arrowheads  for │
                                  │          │      │ linear, radius, and diameter │
                                  │          │      │ dimensioning.                │
                                  │          │      │                              │
                                  │          │      │        • 0      =      Draws │
                                  │          │      │          arrowheads.         │
                                  │          │      │                              │
                                  │          │      │        • >0 = Draws  oblique │
                                  │          │      │          strokes  instead of │
                                  │          │      │          arrowheads.     The │
                                  │          │      │          size of the oblique │
                                  │          │      │          strokes          is │
                                  │          │      │          determined by  this │
                                  │          │      │          value multiplied by │
                                  │          │      │          the DIMSCALE value  │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTVP   │ 145  │ Controls     the    vertical │
                                  │          │      │ position of  dimension  text │
                                  │          │      │ above or below the dimension │
                                  │          │      │ line.  The  DIMTVP  value is │
                                  │          │      │ used when DIMTAD  =  0.  The │
                                  │          │      │ magnitude  of  the  vertical │
                                  │          │      │ offset  of   text   is   the │
                                  │          │      │ product  of  the text height │
                                  │          │      │ and DIMTVP.  Setting  DIMTVP │
                                  │          │      │ to   1.0  is  equivalent  to │
                                  │          │      │ setting  DIMTAD  =  1.   The │
                                  │          │      │ dimension   line  splits  to │
                                  │          │      │ accommodate the text only if │
                                  │          │      │ the absolute value of DIMTVP │
                                  │          │      │ is less than 0.7.            │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMTXT   │ 140  │ Specifies  the   height   of │
                                  │          │      │ dimension  text,  unless the │
                                  │          │      │ current  text  style  has  a │
                                  │          │      │ fixed height.                │
                                  ├──────────┼──────┼──────────────────────────────┤
                                  │ DIMZIN   │ 78   │ Controls  the suppression of │
                                  │          │      │ zeros in  the  primary  unit │
                                  │          │      │ value.   Values  0-3  affect │
                                  │          │      │ feet-and-inch     dimensions │
                                  │          │      │ only:                        │
                                  │          │      │                              │
                                  │          │      │        • 0 = Suppresses zero │
                                  │          │      │          feet  and precisely │
                                  │          │      │          zero inches         │
                                  │          │      │                              │
                                  │          │      │        • 1 =  Includes  zero │
                                  │          │      │          feet  and precisely │
                                  │          │      │          zero inches         │
                                  │          │      │                              │
                                  │          │      │        • 2 =  Includes  zero │
                                  │          │      │          feet and suppresses │
                                  │          │      │          zero inches         │
                                  │          │      │                              │
                                  │          │      │        • 3  =  Includes zero │
                                  │          │      │          inches          and │
                                  │          │      │          suppresses     zero │
                                  │          │      │          feet                │
                                  │          │      │                              │
                                  │          │      │        • 4   (Bit    3)    = │
                                  │          │      │          Suppresses  leading │
                                  │          │      │          zeros  in   decimal │
                                  │          │      │          dimensions     (for │
                                  │          │      │          example,     0.5000 │
                                  │          │      │          becomes .5000)      │
                                  │          │      │                              │
                                  │          │      │        • 8    (Bit    4)   = │
                                  │          │      │          Suppresses trailing │
                                  │          │      │          zeros  in   decimal │
                                  │          │      │          dimensions     (for │
                                  │          │      │          example,    12.5000 │
                                  │          │      │          becomes 12.5)       │
                                  │          │      │                              │
                                  │          │      │        • 12   (Bit   3+4)  = │
                                  │          │      │          Suppresses     both │
                                  │          │      │          leading         and │
                                  │          │      │          trailing zeros (for │
                                  │          │      │          example,     0.5000 │
                                  │          │      │          becomes .5)         │
                                  └──────────┴──────┴──────────────────────────────┘

   Table Structure DXF R2000+
          0           <<< start of table
          TABLE
          2           <<< set table type
          DIMSTYLE
          5           <<< DIMSTYLE table handle
          5F
          330         <<< owner tag, tables has no owner
          0
          100         <<< subclass marker
          AcDbSymbolTable
          70          <<< count of dimension styles defined in this table, AutoCAD ignores this value
          9
          0           <<< 1. DIMSTYLE table entry
          DIMSTYLE
                      <<< DIMSTYLE data tags
          0           <<< 2. DIMSTYLE table entry
          DIMSTYLE
                      <<< DIMSTYLE data tags and so on
          0           <<< end of DIMSTYLE table
          ENDTAB

   Additional DIMSTYLE Variables DXF R13/14
       Source: CADDManager Blog
                            ─────────────────────────────────────────────────────────────
                              DIMVAR            code   Description
                            ─────────────────────────────────────────────────────────────
                              DIMADEC           179    Controls   the   number   of
                                                       precision  places  displayed
                                                       in angular dimensions.
                            ─────────────────────────────────────────────────────────────
                              DIMALTTD          274    Sets  the  number of decimal
                                                       places  for  the   tolerance
                                                       values   in   the  alternate
                                                       units of a dimension.
                            ─────────────────────────────────────────────────────────────
                              DIMALTTZ          286    Controls   suppression    of
                                                       zeros in tolerance values.
                            ─────────────────────────────────────────────────────────────
                              DIMALTU           273    Sets  the  units  format for
                                                       alternate   units   of   all
                                                       dimension  substyles  except
                                                       Angular.
                            ─────────────────────────────────────────────────────────────
                              DIMALTZ           285    Controls the suppression  of
                                                       zeros   for  alternate  unit
                                                       dimension  values.   DIMALTZ
                                                       values       0-3      affect
                                                       feet-and-inch     dimensions
                                                       only.
                            ─────────────────────────────────────────────────────────────
                              DIMAUNIT          275    Sets  the  units  format for
                                                       angular dimensions.

                                                              • 0 = Decimal degrees

                                                              • 1                 =
                                                                Degrees/minutes/seconds

                                                              • 2 = Grad

                                                              • 3 = Radians
                            ─────────────────────────────────────────────────────────────
                              DIMBLK_HANDLE     342    defines  DIMBLK as handle to the
                                                       BLOCK RECORD entry
                            ─────────────────────────────────────────────────────────────
                              DIMBLK1_HANDLE    343    defines DIMBLK1 as handle to the
                                                       BLOCK RECORD entry
                            ─────────────────────────────────────────────────────────────
                              DIMBLK2_HANDLE    344    defines DIMBLK2 as handle to the
                                                       BLOCK RECORD entry
                            ─────────────────────────────────────────────────────────────
                              DIMDEC            271    Sets  the  number   of   decimal
                                                       places displayed for the primary
                                                       units   of   a   dimension.  The
                                                       precision is based on the  units
                                                       or   angle   format   you   have
                                                       selected.
                            ─────────────────────────────────────────────────────────────
                              DIMDSEP           278    Specifies   a   single-character
                                                       decimal  separator  to  use when
                                                       creating dimensions  whose  unit
                                                       format    is    decimal.    When
                                                       prompted,   enter    a    single
                                                       character at the Command prompt.
                                                       If  dimension  units  is  set to
                                                       Decimal, the  DIMDSEP  character
                                                       is  used  instead of the default
                                                       decimal point. If DIMDSEP is set
                                                       to NULL (default value, reset by
                                                       entering a period), the  decimal
                                                       point  is  used as the dimension
                                                       separator.
                            ─────────────────────────────────────────────────────────────
                              DIMJUST           280    Controls     the      horizontal
                                                       positioning of dimension text.

                                                              • 0  = Positions the text
                                                                above   the   dimension
                                                                line                and
                                                                center-justifies     it
                                                                between  the  extension
                                                                lines

                                                              • 1 = Positions the  text
                                                                next   to   the   first
                                                                extension line

                                                              • 2 = Positions the  text
                                                                next   to   the  second
                                                                extension line

                                                              • 3 = Positions the  text
                                                                above  and aligned with
                                                                the   first   extension
                                                                line

                                                              • 4   =   =Positions  the
                                                                text above and  aligned
                                                                with     the     second
                                                                extension line
                            ─────────────────────────────────────────────────────────────
                              DIMSD1            281    Controls  suppression   of   the
                                                       first    dimension    line   and
                                                       arrowhead.   When   turned   on,
                                                       suppresses  the  display  of the
                                                       dimension  line  and   arrowhead
                                                       between the first extension line
                                                       and the text.

                                                              • 0   =  First  dimension
                                                                line is not suppressed

                                                              • 1  =  First   dimension
                                                                line is suppressed
                            ─────────────────────────────────────────────────────────────
                              DIMSD2            282    Controls   suppression   of  the
                                                       second   dimension   line    and
                                                       arrowhead.   When   turned   on,
                                                       suppresses the  display  of  the
                                                       dimension   line  and  arrowhead
                                                       between  the  second   extension
                                                       line and the text.

                                                              • 0  =  Second  dimension
                                                                line is not suppressed

                                                              • 1  =  Second  dimension
                                                                line is suppressed
                            ─────────────────────────────────────────────────────────────
                              DIMTDEC           272    Sets   the   number  of  decimal
                                                       places to display  in  tolerance
                                                       values  for the primary units in
                                                       a   dimension.    This    system
                                                       variable  has  no  effect unless
                                                       DIMTOL is set to On. The default
                                                       for DIMTOL is Off.
                            ─────────────────────────────────────────────────────────────
                              DIMTOLJ           283    Sets the vertical  justification
                                                       for tolerance values relative to
                                                       the   nominal   dimension  text.
                                                       This  system  variable  has   no
                                                       effect  unless  DIMTOL is set to
                                                       On. The default  for  DIMTOL  is
                                                       Off.

                                                              • 0 = Bottom

                                                              • 1 = Middle

                                                              • 2 = Top
                            ─────────────────────────────────────────────────────────────
                              DIMTXSTY_HANDLE   340    Specifies  the text style of the
                                                       dimension  as  handle  to  STYLE
                                                       table entry
                            ─────────────────────────────────────────────────────────────
                              DIMTZIN           284    Controls   the   suppression  of
                                                       zeros in tolerance values.

                                                       Values 0-3 affect  feet-and-inch
                                                       dimensions only.

                                                              • 0   =  Suppresses  zero
                                                                feet and precisely zero
                                                                inches

                                                              • 1 = Includes zero  feet
                                                                and    precisely   zero
                                                                inches

                                                              • 2 = Includes zero  feet
                                                                and   suppresses   zero
                                                                inches

                                                              • 3   =   Includes   zero
                                                                inches  and  suppresses
                                                                zero feet

                                                              • 4 = Suppresses  leading
                                                                zeros     in    decimal
                                                                dimensions         (for
                                                                example, 0.5000 becomes
                                                                .5000)

                                                              • 8 = Suppresses trailing
                                                                zeros     in    decimal
                                                                dimensions         (for
                                                                example,        12.5000
                                                                becomes 12.5)

                                                              • 12  =  Suppresses  both
                                                                leading   and  trailing
                                                                zeros   (for   example,
                                                                0.5000 becomes .5)
                            ─────────────────────────────────────────────────────────────
                              DIMUPT            288    Controls       options       for
                                                       user-positioned text.

                                                              • 0  =  Cursor   controls
                                                                only the dimension line
                                                                location

                                                              • 1   =  Cursor  controls
                                                                both the text  position
                                                                and  the dimension line
                                                                location
                            ┌─────────────────┬──────┬──────────────────────────────────┐
                            │                 │      │                                  │
--

DEVELOPER GUIDES

       Information about ezdxf internals.

   Source Code Formatting
       Reformat code by Black with the default setting of 88 characters per line:

          C:\> black <python-file>

   Type Annotations
       The  use  of  type  annotations  is encouraged. New modules should pass mypy without errors in non-strict
       mode. Using # type: ignore is fine  in  tricky  situations  -  type  annotations  should  be  helpful  in
       understanding the code and not be a burden.

       The following global options are required to pass mypy without error messages:

          [mypy]
          python_version = 3.7
          ignore_missing_imports = True

       Read this to learn where mypy searches for config files.

       Use  the  mypy  command  line  option --ignore-missing-imports and -p to check the whole package from any
       location in the file system:

          PS D:\Source\ezdxf.git> mypy --ignore-missing-imports -p ezdxf
          Success: no issues found in 255 source files

   Design
       The Package Design for Developers section shows the structure of the ezdxf package  for  developers  with
       more  experience,  which  want  to have more insight into the package an maybe want to develop add-ons or
       want contribute to the ezdxf package.  !!! UNDER CONSTRUCTION !!!

   Package Design for Developers
       A DXF document is divided into several sections, this sections are managed by  the  Drawing  object.  For
       each section exist a corresponding attribute in the Drawing object:
                                           ┌──────────┬──────────────────┐
                                           │ Section  │ Attribute        │
                                           ├──────────┼──────────────────┤
                                           │ HEADER   │ Drawing.header   │
                                           ├──────────┼──────────────────┤
                                           │ CLASSES  │ Drawing.classes  │
                                           ├──────────┼──────────────────┤
                                           │ TABLES   │ Drawing.tables   │
                                           ├──────────┼──────────────────┤
                                           │ BLOCKS   │ Drawing.blocks   │
                                           ├──────────┼──────────────────┤
                                           │ ENTITIES │ Drawing.entities │
                                           ├──────────┼──────────────────┤
                                           │ OBJECTS  │ Drawing.objects  │
                                           └──────────┴──────────────────┘

       Resource  entities  (LAYER, STYLE, LTYPE, …) are stored in tables in the TABLES section. A table owns the
       table entries, the owner handle of table entry is the handle of the table. Each table has a  shortcut  in
       the Drawing object:
                                       ┌──────────────┬───────────────────────┐
                                       │ Table        │ Attribute             │
                                       ├──────────────┼───────────────────────┤
                                       │ APPID        │ Drawing.appids        │
                                       ├──────────────┼───────────────────────┤
                                       │ BLOCK_RECORD │ Drawing.block_records │
                                       ├──────────────┼───────────────────────┤
                                       │ DIMSTYLE     │ Drawing.dimstyles     │
                                       ├──────────────┼───────────────────────┤
                                       │ LAYER        │ Drawing.layers        │
                                       ├──────────────┼───────────────────────┤
                                       │ LTYPE        │ Drawing.linetypes     │
                                       ├──────────────┼───────────────────────┤
                                       │ STYLE        │ Drawing.styles        │
                                       ├──────────────┼───────────────────────┤
                                       │ UCS          │ Drawing.ucs           │
                                       ├──────────────┼───────────────────────┤
                                       │ VIEW         │ Drawing.views         │
                                       ├──────────────┼───────────────────────┤
                                       │ VPORT        │ Drawing.viewports     │
                                       └──────────────┴───────────────────────┘

       Graphical  entities  are  stored  in  layouts:  Modelspace, Paperspace layouts and BlockLayout.  The core
       management object of this layouts is the BLOCK_RECORD entity (BlockRecord), the BLOCK_RECORD is the  real
       owner  of  the  entities,  the  owner  handle  of  the entities is the handle of the BLOCK_RECORD and the
       BLOCK_RECORD also owns and manages the entity space of the layout which  contains  all  entities  of  the
       layout.

       For more information about layouts see also: Layout Management Structures

       For more information about blocks see also: Block Management Structures

       Non-graphical  entities (objects) are stored in the OBJECTS section.  Every object has a parent object in
       the OBJECTS section, most likely a DICTIONARY object, and is stored in the entity space  of  the  OBJECTS
       section.

       For more information about the OBJECTS section see also: OBJECTS Section

       All  table  entries,  DXF  entities  and  DXF  objects  are stored in the entities database accessible as
       Drawing.entitydb. The entity database is a simple key, value storage, key is the entity handle, value  is
       the DXF object.

       For more information about the DXF data model see also: Data Model

   Terminology
   States
       DXF entities and objects can have different states:

       UNBOUND
              Entity is not stored in the Drawing entity database and DXF attribute handle is None and attribute
              doc can be None

       BOUND  Entity  is stored in the Drawing entity database, attribute doc has a reference to Drawing and DXF
              attribute handle is not None

       UNLINKED
              Entity is not linked to a layout/owner, DXF attribute owner is None

       LINKED Entity is linked to a layout/owner, DXF attribute owner is not None

       Virtual Entity
              State: UNBOUND & UNLINKED

       Unlinked Entity
              State: BOUND & UNLINKED

       Bound Entity
              State: BOUND & LINKED

   Actions
       NEW    Create a new DXF document

       LOAD   Load a DXF document from an external source

       CREATE Create DXF structures from NEW or LOAD data

       DESTROY
              Delete DXF structures

       BIND   Bind an entity to a Drawing, set entity state to BOUND & UNLINKED and  check  or  create  required
              resources

       UNBIND unbind …

       LINK   Link  an  entity  to  an  owner/layout.   This makes an entity to a real DXF entity, which will be
              exported at the saving process. Any DXF entity can only  be  linked  to  one  parent  entity  like
              DICTIONARY or BLOCK_RECORD.

       UNLINK unlink …

   Loading a DXF Document
       Loading  a  DXF  document from an external source, creates a new Drawing object. This loading process has
       two stages:

   First Loading Stage
       • LOAD content from external source as SectionDict: loader.load_dxf_structure()

       • LOAD tag structures as DXFEntity objects: loader.load_dxf_entities()

       • BIND entities: loader.load_and_bind_dxf_content(); Special handling of the BIND  process,  because  the
         Drawing is not full initialized, a complete validation is not possible at this stage.

   Second Loading Stage
       Parse SectionDict:

       • CREATE sections: HEADER, CLASSES, TABLES, BLOCKS and OBJECTS

       • CREATE layouts: Blocks, Layouts

       • LINK entities to a owner/layout

       The  ENTITIES section is a relict from older DXF versions and has to be exported including the modelspace
       and active paperspace entities, but all entities reside  in  a  BLOCK  definition,  even  modelspace  and
       paperspace layouts are only BLOCK definitions and ezdxf has no explicit ENTITIES section.

       Source  Code:  as  developer  start  your  journey  at ezdxf.document.Drawing.read(), which has no public
       documentation, because package-user should use ezdxf.read() and ezdxf.readfile().

   New DXF Document
   Creating New DXF Entities
       The default constructor of each entity type creates a new virtual entity:

       • DXF attribute owner is None

       • DXF attribute handle is None

       • Attribute doc is None

       The DXFEntity.new() constructor creates entities with given owner, handle and doc attributes, if  doc  is
       not  None  and  entity  is  not already bound to a document, the new() constructor automatically bind the
       entity to the given document doc.

       There exist only two scenarios:

       1. UNBOUND: doc is None and handle is None

       2. BOUND: doc is not None and handle is not None

   Factory functionsnew(), create a new virtual DXF object/entity

       • load(), load (create) virtual DXF object/entity from DXF tags

       • bind(), bind an entity to a document, create required resources  if  necessary  (e.g.  ImageDefReactor,
         SEQEND) and raise exceptions for non-existing resources.

         • Bind  entity  loaded  from an external source to a document, all referenced resources must exist, but
           try to repair as many flaws as possible because errors were created by another  application  and  are
           not the responsibility of the package-user.

         • Bind  an  entity from another DXF document, all invalid resources will be removed silently or created
           (e.g. SEQEND). This is a simple import from another document without  resource  import,  for  a  more
           advanced import including resources exist the importer add-on.

         • Bootstrap  problem  for  binding  loaded  table entries and objects in the OBJECTS section! Can’t use
           Auditor to repair this objects, because the DXF document is not fully initialized.

       • is_bound() returns True if entity is bound to document docunbind() function to remove an entity from a document and set state to a virtual entity,  which  should
         also UNLINK the entity from layout, because an layout can not store a virtual entity.

       • cls(), returns the class

       • register_entity(), registration decorator

       • replace_entity(), registration decorator

   Class Interfaces
   DXF Entities
       • NEW constructor to create an entity from scratch

       • LOAD constructor to create an entity loaded from an external source

       • DESTROY  interface  to  kill  an  entity, set entity state to dead, which means entity.is_alive returns
         False. All entity iterators like EntitySpace, EntityQuery,  and  EntityDB  must  filter  (ignore)  dead
         entities.  Calling DXFEntity.destroy() is a regular way to delete entities.

       • LINK  an entity to a layout by BlockRecord.link(), which set the owner handle to BLOCK_RECORD handle (=
         layout key) and add the entity to the entity space of the BLOCK_RECORD  and  set/clear  the  paperspace
         flag.

   DXF Objects
       • NEW, LOAD, DESTROY see DXF entities

       • LINK:  Linking  an  DXF  object means adding the entity to a parent object in the OBJECTS section, most
         likely a DICTIONARY object, and adding the object to the entity  space  of  the  OBJECTS  section,  the
         root-dict  is  the  only entity in the OBJECTS section which has an invalid owner handle “0”. Any other
         object with an invalid or destroyed owner is an  orphaned  entity.   The  audit  process  destroys  and
         removes orphaned objects.

       • Extension  dictionaries  (ACAD_XDICTIONARY)  are DICTIONARY objects located in the OBJECTS sections and
         can reference/own other entities of the OBJECTS section.

       • The root-dictionary is the only entity in the OBJECTS section which has an invalid  owner  handle  “0”.
         Any other object with an invalid or destroyed owner is an orphaned entity.

   Layouts
       • LINK interface to link an entity to a layout

       • UNLINK interface to remove an entity from a layout

   Database
       • BIND interface to add an entity to the database of a document

       • delete_entity() interface, same as UNBIND and DESTROY an entity

   Internal Data Structures
   Entity Database
       The  EntityDB is a simple key/value database to store DXFEntity objects by it’s handle, every Drawing has
       its own EntityDB, stored in the Drawing attribute entitydb.

       Every DXF entity/object, except tables and sections, are represented as  DXFEntity  or  inherited  types,
       this entities are stored in the EntityDB, database-key is the dxf.handle as plain hex string.

       All iterators like keys(), values(), items() and __iter__() do not yield destroyed entities.

       WARNING:
          The get() method and the index operator [], return destroyed entities and entities from the trashcan.

       class ezdxf.entitydb.EntityDB

              __getitem__(handle: str) -> DXFEntity
                     Get entity by handle, does not filter destroyed entities nor entities in the trashcan.

              __setitem__(handle: str, entity: DXFEntity) -> None
                     Set entity for handle.

              __delitem__(handle: str) -> None
                     Delete entity by handle. Removes entity only from database, does not destroy the entity.

              __contains__(item: str | DXFEntity) -> bool
                     True if database contains handle.

              __len__() -> int
                     Count of database items.

              __iter__() -> Iterator[str]
                     Iterable of all handles, does filter destroyed entities but not entities in the trashcan.

              get(handle: str) -> DXFEntity | None
                     Returns entity for handle or None if no entry exist, does not filter destroyed entities.

              next_handle() -> str
                     Returns next unique handle.

              keys() -> Iterable[str]
                     Iterable of all handles, does filter destroyed entities.

              values() -> Iterable[DXFEntity]
                     Iterable of all entities, does filter destroyed entities.

              items() -> Iterable[Tuple[str, DXFEntity]]
                     Iterable of all (handle, entities) pairs, does filter destroyed entities.

              add(entity: DXFEntity) -> None
                     Add  entity  to  database, assigns a new handle to the entity if entity.dxf.handle is None.
                     Adding the same entity multiple times is possible and creates only a single database entry.

              new_trashcan() -> Trashcan
                     Returns a new trashcan, empty trashcan manually by: : func:Trashcan.clear().

              trashcan() -> Trashcan
                     Returns a new trashcan in context manager mode,  trashcan  will  be  emptied  when  leaving
                     context.

              purge() -> None
                     Remove all destroyed entities from database, but does not empty the trashcan.

              query(query: str = '*') -> EntityQuery
                     Entity query over all entities in the DXF document.

                     Parameters
                            query – query string

                     SEE ALSO:
                        Entity Query String and Retrieve entities by query language

   Entity Space
       class ezdxf.entitydb.EntitySpace(entities: Iterable[DXFEntity] | None = None)
              An  EntitySpace  is  a  collection of DXFEntity objects, that stores only  references to DXFEntity
              objects.

              The Modelspace, any Paperspace layout and BlockLayout objects have  an  EntitySpace  container  to
              store their entities.

              __iter__() -> Iterable[DXFEntity]
                     Iterable of all entities, filters destroyed entities.

              __getitem__(index) -> DXFEntity
                     Get entity at index item

                     EntitySpace  has  a  standard  Python list like interface, therefore index can be any valid
                     list indexing or slicing term, like a single index layout[-1] to get the last entity, or an
                     index slice layout[:10] to get the first 10 or fewer entities as list[DXFEntity]. Does  not
                     filter destroyed entities.

              __len__() -> int
                     Count of entities including destroyed entities.

              has_handle(handle: str) -> bool
                     True if handle is present, does filter destroyed entities.

              purge()
                     Remove all destroyed entities from entity space.

              add(entity: DXFEntity) -> None
                     Add entity.

              extend(entities: Iterable[DXFEntity]) -> None
                     Add multiple entities.

              remove(entity: DXFEntity) -> None
                     Remove entity.

              clear() -> None
                     Remove all entities.

   DXF Types
       Required DXF tag interface:

          • property code: group code as int

          • property value: tag value of unspecific type

          • dxfstr(): returns the DXF string

          • clone(): returns a deep copy of tag

   DXFTag Factory Functions
       ezdxf.lldxf.types.dxftag(code: int, value: Any) -> DXFTag
              DXF tag factory function.

              Parameterscode – group code

                     • value – tag value

              Returns: DXFTag or inherited

       ezdxf.lldxf.types.tuples_to_tags(iterable: Iterable[tuple[int, Any]]) -> Iterable[DXFTag]
              Returns an iterable if DXFTag or inherited, accepts an iterable of (code, value) tuples as input.

   DXFTag
       class ezdxf.lldxf.types.DXFTag(code: int, value: Any)
              Immutable DXFTag class.

              Parameterscode – group code as int

                     • value – tag value, type depends on group code

              code   group code as int (do not change)

              value  tag value (read-only property)

              __eq__(other) -> bool
                     True if other and self has same content for code and value.

              __getitem__(index: int)
                     Returns code for index 0 and value for index 1, emulates a tuple.

              __hash__()
                     Hash support, DXFTag can be used in sets and as dict key.

              __iter__()
                     Returns (code, value) tuples.

              __repr__() -> str
                     Returns representation string 'DXFTag(code, value)'.

              __str__() -> str
                     Returns content string '(code, value)'.

              clone() -> DXFTag
                     Returns  a  clone  of  itself,  this  method  is  necessary  for  the more complex (and not
                     immutable) DXF tag types.

              dxfstr() -> str
                     Returns the DXF string e.g. '  0\nLINE\n'

   DXFBinaryTag
       class ezdxf.lldxf.types.DXFBinaryTag(DXFTag)
              Immutable BinaryTags class - immutable by design, not by implementation.

              dxfstr() -> str
                     Returns the DXF string for all vertex components.

              tostring() -> str
                     Returns binary value as single hex-string.

   DXFVertex
       class ezdxf.lldxf.types.DXFVertex(DXFTag)
              Represents a 2D or 3D vertex, stores only the group code of the x-component of the vertex, because
              the y-group-code is x-group-code + 10 and z-group-code id x-group-code+20, this  is  a  rule  that
              ALWAYS applies.  This tag is immutable by design, not by implementation.

              Parameterscode – group code of x-component

                     • value – sequence of x, y and optional z values

              dxfstr() -> str
                     Returns the DXF string for all vertex components.

              dxftags() -> Iterable[DXFTag]
                     Returns all vertex components as single DXFTag objects.

   NONE_TAG
       ezdxf.lldxf.types.NONE_TAG
              Special tag representing a none existing tag.

   Tags
       A  list of DXFTag, inherits from Python standard list.  Unlike the statement in the DXF Reference “Do not
       write programs that rely on the order given here”, tag order is sometimes essential and some group  codes
       may appear multiples times in one entity. At the worst case (Material: normal map shares group codes with
       diffuse map) using same group codes with different meanings.

       class ezdxf.lldxf.tags.Tags
              Subclass of list.

              Collection of DXFTag as flat list. Low level tag container, only required for advanced stuff.

              classmethod from_text(text: str) -> Tags
                     Constructor from DXF string.

              dxftype() -> str
                     Returns DXF type of entity, e.g. 'LINE'.

              get_handle() -> str
                     Get DXF handle. Raises DXFValueError if handle not exist.

                     Returns
                            handle as plain hex string like 'FF00'

                     Raises DXFValueError – no handle found

              replace_handle(new_handle: str) -> None
                     Replace existing handle.

                     Parameters
                            new_handle – new handle as plain hex string e.g. 'FF00'

              has_tag(code: int) -> bool
                     Returns True if a DXFTag with given group code is present.

                     Parameters
                            code – group code as int

              has_embedded_objects() -> bool

              get_first_tag(code: int, default=DXFValueError) -> DXFTag
                     Returns  first  DXFTag  with given group code or default, if default != DXFValueError, else
                     raises DXFValueError.

                     Parameterscode – group code as int

                            • default – return value for default case or raises DXFValueError

              get_first_value(code: int, default=DXFValueError) -> Any
                     Returns value of first DXFTag with given group code or default if default != DXFValueError,
                     else raises DXFValueError.

                     Parameterscode – group code as int

                            • default – return value for default case or raises DXFValueError

              find_all(code: int) -> List[DXFTag]
                     Returns a list of DXFTag with given group code.

                     Parameters
                            code – group code as int

              filter(codes: Iterable[int]) -> Iterable[DXFTag]
                     Iterate and filter tags by group codes.

                     Parameters
                            codes – group codes to filter

              collect_consecutive_tags(codes: Iterable[int], start: int = 0, end: int = None) -> Tags
                     Collect all consecutive tags with group code in codes, start and end  delimits  the  search
                     range. A tag code not in codes ends the process.

                     Parameterscodes – iterable of group codes

                            • start – start index as int

                            • end – end index as int, None for end index = len(self)

                     Returns
                            collected tags as Tags

              tag_index(code: int, start: int = 0, end: int | None = None) -> int
                     Return index of first DXFTag with given group code.

                     Parameterscode – group code as int

                            • start – start index as int

                            • end – end index as int, None for end index = len(self)

              update(tag: DXFTag)
                     Update  first  existing  tag  with  same group code as tag, raises DXFValueError if tag not
                     exist.

              set_first(tag: DXFTag)
                     Update first existing tag with group code tag.code or append tag.

              remove_tags(codes: Iterable[int]) -> None
                     Remove all tags inplace with group codes specified in codes.

                     Parameters
                            codes – iterable of group codes as int

              remove_tags_except(codes: Iterable[int]) -> None
                     Remove all tags inplace except those with group codes specified in codes.

                     Parameters
                            codes – iterable of group codes

              pop_tags(codes: Iterable[int]) -> Iterable[DXFTag]
                     Pop tags with group codes specified in codes.

                     Parameters
                            codes – iterable of group codes

              classmethod strip(tags: Tags, codes: Iterable[int]) -> Tags
                     Constructor from tags, strips all tags with group codes in codes from tags.

                     Parameterstags – iterable of DXFTagcodes – iterable of group codes as int

       ezdxf.lldxf.tags.group_tags(tags: Iterable[DXFTag], splitcode: int = 0) -> Iterable[Tags]
              Group of tags starts with a SplitTag and ends before the next SplitTag.  A SplitTag is a tag  with
              code == splitcode, like (0, ‘SECTION’) for splitcode == 0.

              Parameterstags – iterable of DXFTagsplitcode – group code of split tag

       class ezdxf.lldxf.extendedtags.ExtendedTags(tags: Iterable[DXFTag] = None, legacy=False)
              Represents the extended DXF tag structure introduced with DXF R13.

              Args:  tags: iterable of DXFTag legacy: flag for DXF R12 tags

              appdata
                     Application defined data as list of Tags

              subclasses
                     Subclasses as list of Tags

              xdata  XDATA as list of Tags

              embedded_objects
                     embedded objects as list of Tags

              noclass
                     Short cut to access first subclass.

              get_handle() -> str
                     Returns handle as hex string.

              dxftype() -> str
                     Returns DXF type as string like “LINE”.

              replace_handle(handle: str) -> None
                     Replace the existing entity handle by a new value.

              legacy_repair()
                     Legacy (DXF R12) tags handling and repair.

              clone() -> ExtendedTags
                     Shallow copy.

              flatten_subclasses()
                     Flatten subclasses in legacy mode (DXF R12).

                     There  exists  DXF  R12  with subclass markers, technical incorrect but works if the reader
                     ignore subclass marker tags, unfortunately ezdxf tries to use  this  subclass  markers  and
                     therefore R12 parsing by ezdxf does not work without removing these subclass markers.

                     This   method   removes   all   subclass   markers   and   flattens   all  subclasses  into
                     ExtendedTags.noclass.

              get_subclass(name: str, pos: int = 0) -> Tags
                     Get subclass name.

                     Parametersname – subclass name as string like “AcDbEntity”

                            • pos – start searching at subclass pos.

              has_xdata(appid: str) -> bool
                     True if has XDATA for appid.

              get_xdata(appid: str) -> Tags
                     Returns XDATA for appid as Tags.

              set_xdata(appid: str, tags: IterableTags) -> None
                     Set tags as XDATA for appid.

              new_xdata(appid: str, tags: 'IterableTags' = None) -> Tags
                     Append a new XDATA block.

                     Assumes that no XDATA block with the same appid already exist:

                        try:
                            xdata = tags.get_xdata('EZDXF')
                        except ValueError:
                            xdata = tags.new_xdata('EZDXF')

              has_app_data(appid: str) -> bool
                     True if has application defined data for appid.

              get_app_data(appid: str) -> Tags
                     Returns application defined data for appid as Tags including marker tags.

              get_app_data_content(appid: str) -> Tags
                     Returns application defined data for appid as Tags without first and last marker tag.

              set_app_data_content(appid: str, tags: IterableTags) -> None
                     Set application defined data for appid for already exiting data.

              new_app_data(appid: str, tags: 'IterableTags' = None, subclass_name: str = None) -> Tags
                     Append a new application defined data to subclass subclass_name.

                     Assumes that no app data block with the same appid already exist:

                        try:
                            app_data = tags.get_app_data('{ACAD_REACTORS', tags)
                        except ValueError:
                            app_data = tags.new_app_data('{ACAD_REACTORS', tags)

              classmethod from_text(text: str, legacy: bool = False) -> ExtendedTags
                     Create ExtendedTags from DXF text.

   Packed DXF Tags
       Store DXF tags in compact data structures as list or array.array to reduce memory usage.

       class ezdxf.lldxf.packedtags.TagList(data: Iterable = None)
              Store data in a standard Python list.

              Args:  data: iterable of DXF tag values.

              values Data storage as list.

              clone() -> TagList
                     Returns a deep copy.

              classmethod from_tags(tags: Tags, code: int) -> TagList
                     Setup list from iterable tags.

                     Parameterstags – tag collection as Tagscode – group code to collect

              clear() -> None
                     Delete all data values.

       class ezdxf.lldxf.packedtags.TagArray(data: Iterable = None)
              TagArray is a subclass of TagList, which store data in an array.array.  Array type is  defined  by
              class variable DTYPE.

              Args:  data: iterable of DXF tag values.

              DTYPE  array.array type as string

              values Data storage as array.array

              set_values(values: Iterable) -> None
                     Replace data by values.

       class ezdxf.lldxf.packedtags.VertexArray(data: Iterable = None)
              Store vertices in an array.array('d').  Vertex size is defined by class variable VERTEX_SIZE.

              Args:  data: iterable of vertex values as linear list e.g. [x1, y1, x2, y2, x3, y3, ...].

              VERTEX_SIZE
                     Size of vertex (2 or 3 axis).

              __len__() -> int
                     Count of vertices.

              __getitem__(index: int)
                     Get vertex at index, extended slicing supported.

              __setitem__(index: int, point: Sequence[float]) -> None
                     Set vertex point at index, extended slicing not supported.

              __delitem__(index: int) -> None
                     Delete vertex at index, extended slicing supported.

              __iter__() -> Iterator[Sequence[float]]
                     Returns iterable of vertices.

              __str__() -> str
                     String representation.

              insert(pos: int, point: Sequence[float])
                     Insert point in front of vertex at index pos.

                     Parameterspos – insert position

                            • point – point as tuple

              append(point: Sequence[float]) -> None
                     Append point.

              extend(points: Iterable[Sequence[float]]) -> None
                     Extend array by points.

              set(points: Iterable[Sequence[float]]) -> None
                     Replace all vertices by points.

              clear() -> None
                     Delete all vertices.

              clone() -> VertexArray
                     Returns a deep copy.

              classmethod from_tags(tags: Iterable[DXFTag], code: int = 10) -> VertexArray
                     Setup point array from iterable tags.

                     Parameterstags – iterable of DXFVertexcode – group code to collect

              export_dxf(tagwriter: AbstractTagWriter, code=10)

   XData
       class ezdxf.entities.xdata.XData
              Internal management class for XDATA.

              SEE ALSO:

                 • XDATA user reference: Extended Data (XDATA)

                 • Wrapper class to store a list in XDATA: XDataUserList

                 • Wrapper class to store a dict in XDATA: XDataUserDict

                 • Tutorial: Storing Custom Data in DXF Files

                 • DXF Internals: Extended DataDXF R2018 Reference

              __contains__(appid: str) -> bool
                     Returns True if  DXF tags for appid exist.

              add(appid: str, tags: Iterable[tuple[int, Any] | DXFTag]) -> None
                     Add  a  list of DXF tags for appid. The tags argument is an iterable of (group code, value)
                     tuples, where the group code has to be an integer value. The mandatory XDATA marker  (1001,
                     appid) is added automatically if front of the tags if missing.

                     Each entity can contain only one list of tags for each appid.  Adding a second list of tags
                     for the same appid replaces the existing list of tags.

                     The  valid  XDATA group codes are restricted to some specific values in the range from 1000
                     to 1071, for more information see also the internals about Extended Data.

              get(appid: str) -> Tags
                     Returns the DXF tags as Tags list stored by appid.

                     Raises DXFValueError – no data for appid exist

              discard(appid)
                     Delete DXF tags for appid. None existing appids are silently ignored.

              has_xlist(appid: str, name: str) -> bool
                     Returns True if list name from XDATA appid exists.

                     Parametersappid – APPID

                            • name – list name

              get_xlist(appid: str, name: str) -> list[tuple]
                     Get list name from XDATA appid.

                     Parametersappid – APPID

                            • name – list name

                     Returns: list of DXFTags including list name and curly braces ‘{’ ‘}’ tags

                     RaisesDXFKeyError – XDATA appid does not exist

                            • DXFValueError – list name does not exist

              set_xlist(appid: str, name: str, tags: Iterable) -> None
                     Create new list name of XDATA appid with xdata_tags  and  replaces  list  name  if  already
                     exists.

                     Parametersappid – APPID

                            • name – list name

                            • tags – list content as DXFTags or (code, value) tuples, list name and curly braces
                              ‘{’ ‘}’ tags will be added

              discard_xlist(appid: str, name: str) -> None
                     Deletes list name from XDATA appid. Ignores silently if XDATA appid or list name not exist.

                     Parametersappid – APPID

                            • name – list name

              replace_xlist(appid: str, name: str, tags: Iterable) -> None
                     Replaces  list  name  of existing XDATA appid by tags. Appends new list if list name do not
                     exist, but raises DXFValueError if XDATA appid do not exist.

                     Low level interface, if not sure use set_xdata_list() instead.

                     Parametersappid – APPID

                            • name – list name

                            • tags – list content as DXFTags or (code, value) tuples, list name and curly braces
                              ‘{’ ‘}’ tags will be added

                     Raises DXFValueError – XDATA appid do not exist

              transform(m: Matrix44) -> None
                     Transform XDATA tags with group codes 1011, 1012, 1013, 1041 and  1042  inplace.  For  more
                     information see Extended Data Internals.

   Application-Defined Data (AppData)
       Starting at DXF R13, DXF objects can contain application-defined codes (AppData) outside of XDATA.

       All  AppData  is  defined  with a beginning (102, “{APPID”) tag and according to the DXF reference appear
       should appear before the first subclass marker.

       There are two known use cases of this data structure in Autodesk products:

       • ACAD_REACTORS, store handles to persistent reactors in a DXF entity

       • ACAD_XDICTIONARY, store handle to the extension dictionary of a DXF entity

       Both AppIDs are not defined/stored in the AppID table!

       class ezdxf.entities.appdata.AppData
              Internal management class for Application defined data.

              SEE ALSO:

                 • User reference: Application-Defined Data (AppData)

                 • Internals about Application-Defined Codes tags

              __contains__(appid: str) -> bool
                     Returns True if application-defined data exist for appid.

              __len__() -> int
                     Returns the count of AppData.

              add(appid: str, data: Iterable[Sequence]) -> None
                     Add application-defined tags for appid.  Adds first tag (102, “{APPID”) if not exist.  Adds
                     last tag (102, “}” if not exist.

              get(appid: str) -> Tags
                     Get application-defined data for appid as Tags container.  The first tag  is  always  (102,
                     “{APPID”).  The last tag is always (102, “}”).

              set(tags: Tags) -> None
                     Store  raw  application-defined  data  tags.  The first tag has to be (102, “{APPID”).  The
                     last tag has to be (102, “}”).

              discard(appid: str)
                     Delete application-defined data for appid without raising and error if appid doesn’t exist.

   Reactors
       class ezdxf.entities.appdata.Reactors
              Internal management class for persistent reactor handles. Handles are stored as hex  strings  like
              "ABBA".

              SEE ALSO:

                 • User reference: Reactors

                 • Internals about Persistent Reactors tags

              __contains__(handle: str) -> bool
                     Returns True if handle is registered.

              __len__() -> int
                     Returns count of registered handles.

              __iter__() -> Iterator[str]
                     Returns an iterator for all registered handles.

              add(handle: str) -> None
                     Add a single handle.

              get() -> list[str]
                     Returns all registered handles as sorted list.

              set(handles: Iterable[str] | None) -> None
                     Reset all handles.

              discard(handle: str)
                     Discard a single handle.

   Documentation Guide
   Formatting Guide
       This section is only for myself, because of the long pauses between develop iterations, I often forget to
       be consistent in documentation formatting.

       Documentation is written with Sphinx and reSturcturedText.

       Started  integration  of  documentation  into  source  code and using autodoc features of Sphinx wherever
       useful.

       Sphinx theme provided by Read the Docs :

          pip install sphinx-rtd-theme

   guide  Example module
       guide.example_func(a: int, b: str, test: str = None, flag: bool = True) -> None
              Parameters a and b are positional arguments, argument test defaults to None and flag to True.  Set
              a to 70 and b to “x”  as  an  example.  Inline  code  examples  example_func(70,  'x')  or  simple
              example_func(70, "x")

                 • arguments: a, b, test and flags

                 • literal number values: 1, 2 … 999

                 • literal string values: “a String”

                 • literal tags: (5, “F000”)

                 • inline code: call a example_func(x)

                 • Python keywords: None, True, False, tuple, list, dict, str, int, float

                 • Exception classes: DXFAttributeError

       class guide.ExampleCls(**kwargs)
              The  ExampleCls constructor accepts a number of optional keyword arguments.  Each keyword argument
              corresponds to an instance attribute, so for example

                 e = ExampleCls(flag=True)

              flag   This is the attribute flag.

              set_axis(axis)
                     axis as (x, y, z) tuple

                     Args:  axis: (x, y, z) tuple

              example_method(flag: bool = False) -> None
                     Method example_method() of class ExampleCls

   Text Formatting
       DXF version
              DXF R12 (AC1009), DXF R2004 (AC1018)

       DXF Types
              DXF types are always written in uppercase letters  but  without  further  formatting:  DXF,  LINE,
              CIRCLE

       (internal API)
              Marks methods as internal API, gets no public documentation.

       (internal class)
              Marks classes only for internal usage, gets not public documentation.

       Spatial Dimensions
              2D and 3D with an uppercase letter D

       Axis   x-axis, y-axis and z-axis

       Planes xy-plane, xz-plane, yz-plane

       Layouts
              modelspace, paperspace [layout], block [layout]

       Extended Entity Data
              AppData, XDATA, embedded object, APPID

GLOSSARY

       ACI    AutoCAD Color Index (ACI)

       ACIS   The  3D  ACIS Modeler (ACIS) is a geometric modeling kernel developed by Spatial Corp. ® (formerly
              Spatial Technology) and now part of Dassault Systems. All ACIS  based  DXF  entities  store  their
              geometry  as SAT or SAB data. These are not open data formats and a license has to be purchased to
              get access to their SDK, therefore ezdxf can not provide any support for creating,  processing  or
              transforming of ACIS based DXF entities.

       bulge  The Bulge value is used to create arc shaped line segments in Polyline and LWPolyline entities.

       CAD    Computer-Assisted Drafting or Computer-Aided Design

       CTB    Color dependent plot style table (ColorDependentPlotStyles)

       DWG    Proprietary  file  format  of  AutoCAD ®. Documentation for this format is available from the Open
              Design Alliance (ODA) at their  Downloads  section.  This  documentation  is  created  by  reverse
              engineering therefore not perfect nor complete.

       DXF    Drawing  eXchange  Format  is  a  file format used by AutoCAD ® to interchange data with other CAD
              applications. DXF is a trademark of Autodesk ®. See also What is DXF?

       proxy-graphic
              The proxy-graphic is an internal data format to add a graphical  representation  to  DXF  entities
              which  are  unknown  (custom DXF entities), not documented or very complex so CAD applications can
              display them without knowledge about the internal structure of these entities.

       raw-color
              Raw color value as stored in DWG files, this integer value can represent ACI values as well as and
              true-color values

       reliable CAD application
              CAD applications which create valid DXF documents in the meaning and interpretation  of  Autodesk.
              See also What is DXF?

       SAB    ACIS file format (Standard ACIS Binary), binary stored data

       SAT    ACIS file format (Standard ACIS Text), data stored as ASCII text

       STB    Named plot style table (NamedPlotStyles)

       true-color
              RGB color representation, a combination red, green and blue values to define a color.

KNOWLEDGE GRAPH

       I have started managing notes and documents that are not included in the ezdxf documentation in Logseq in
       late  2023.   It  works  like  a wiki but does not require a backend server. The Information is edited as
       Markdown files, which is much more intuitive than reStructured Text, and the content is stored  in  local
       files.

       The notes are included in the source code repository on Github in the notes folder.

       A  published  edition  of  this Knowledge Graph is included on the ezdxf website and is accessible by the
       link https://ezdxf.mozman.at/notes.

       The Knowledge Graph includes:

       • Release Notes of future releases and some versions back

       • CHANGELOGIDEAS for future releases

       • FAQ and the HOWTO sections from this documentation

       • all my notes to ezdxf

       • In the future the DXF Internals section from this documentation may also move to the Knowledge Graph.

       Logseq’s outline structure is not ideal for all the documents I want to include, but I chose Logseq  over
       Obsidian.md  because it is open source and can publish the knowledge graph as a static website, static in
       the sense of no server-side code execution.

       his feature is important to me for hosting the content of the Knowledge Graph on the ezdxf` website   and
       cannot be achieved for free with Obsidian.md.

       Logseq  is  an  Electron  application that runs on all platforms, with the disadvantage: it’s an Electron
       application.

INDICES AND TABLES

IndexSearch Page

AUTHOR

       Manfred Moitzi

COPYRIGHT

       2011-2023, Manfred Moitzi

1.1.3                                             Nov 25, 2023                                          EZDXF(1)