1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
.. _tut_getting_data:
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 :ref:`arch-usr`.
Loading the DXF file:
.. code-block:: Python
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
:mod:`ezdxf.recover` module.
.. seealso::
- :ref:`dwgmanagement`
- :ref:`arch-usr`
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:
- :class:`~ezdxf.layouts.Modelspace`: the common construction space
- :class:`~ezdxf.layouts.Paperspace`: used to to create print layouts
- :class:`~ezdxf.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 :meth:`~ezdxf.document.Drawing.modelspace`.
.. code:: Python
msp = doc.modelspace()
Iterate over DXF entities of a layout
-------------------------------------
This code shows how to iterate over all DXF entities in modelspace:
.. code-block:: Python
# 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 :meth:`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 :attr:`~ezdxf.entities.dxfentity.DXFEntity.dxf`:
.. code-block:: Python
e.dxf.layer # layer of the entity as string
e.dxf.color # color of the entity as integer
See :ref:`Common graphical DXF attributes`
If a DXF attribute is not set (the DXF attribute does not exist), a
:class:`DXFValueError` will be raised. The :meth:`get` method returns a default
value in this case or ``None`` if no default value is specified:
.. code-block:: Python
# 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:
.. code-block:: Python
if e.dxf.hasattr("paperspace"):
...
An unsupported DXF attribute raises a :class:`DXFAttributeError`, to check if
an attribute is supported by an entity use:
.. code-block:: Python
if e.dxf.is_supported("paperspace"):
...
Getting a paperspace layout
---------------------------
.. code:: Python
paperspace = doc.paperspace("layout0")
The code above retrieves the paperspace named ``layout0``, the usage of the
:class:`~ezdxf.layouts.Paperspace` object is the same as of the modelspace object.
DXF R12 provides only one paperspace, therefore the paperspace name in the
method call :code:`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 :meth:`~ezdxf.document.Drawing.layout_names` and
:meth:`~ezdxf.document.Drawing.layout_names_in_taborder`.
.. _entity queries:
Retrieve entities by query language
-----------------------------------
`Ezdxf` provides a flexible query language for DXF entities.
All layout types have a :meth:`~ezdxf.layouts.BaseLayout.query` method to start
an entity query or use the :meth:`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``, ``!``.
.. seealso::
:ref:`entity query string`
Get all LINE entities from the modelspace:
.. code-block:: Python
msp = doc.modelspace()
lines = msp.query("LINE")
The result container :class:`~ezdxf.query.EntityQuery` also provides the
:meth:`query()` method to further refine the query, such as retrieving all
LINE entities at layer ``construction``:
.. code-block:: Python
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:
.. code-block:: Python
lines = msp.query('LINE[layer=="construction"]')
An advanced query for getting all modelspace entities at layer ``construction``,
but excluding entities with linetype ``DASHED``:
.. code-block:: Python
not_dashed_entities = msp.query('*[layer=="construction" and linetype!="DASHED"]')
Extended EntityQuery Features
-----------------------------
The :class:`~ezdxf.query.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
:class:`~ezdxf.query.EntityQuery` container:
.. code-block:: Python
# 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"
.. seealso::
:ref:`extended query features`
.. _using_groupby:
Retrieve entities by groupby() function
---------------------------------------
The :func:`~ezdxf.groupby.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:
.. code-block:: Python
from ezdxf.groupby import groupby
group = groupby(entities=msp, dxfattrib="layer")
The `entities` argument can be any container or generator which yields
DXF entities:
.. code-block:: Python
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:
.. code-block:: Python
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 :func:`~ezdxf.groupby.groupby` function catches :class:`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.
.. seealso::
:func:`~ezdxf.groupby.groupby` documentation
|