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 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
|
.. _tut_xref_module:
Tutorial for External References
================================
.. contents::
:local:
Introduction
------------
This tutorial uses the :mod:`ezdxf.xref` module to work with external references (XREF).
Attached XREFs are links to the modelspace of a specified drawing file. Changes made
to the referenced drawing are automatically reflected in the current drawing when it's
opened or if the XREF is reloaded.
.. important::
**AutoCAD can only display DWG files as attached XREFs.**
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.
The :mod:`~ezdxf.addons.drawing` add-on included in `ezdxf` **does not display external
references at all!**
There are some example files included in the `examples/xref <https://github.com/mozman/ezdxf/tree/master/examples/xref>`_
folder of the repository:
- attach_dxf_dwg_xref.py
- detach_block_as_xref.py
- embed_dxf_dwg_xref.py
- load_table_resources.py
Supported Entities
------------------
All operations which move entities between layouts and XREFs copy these entities,
therefore only entities which are copyable can be transferred.
The following entities are not copyable:
- All entities which are not documented by the DXF reference.
- ACAD_TABLE
- ACAD_PROXY_ENTITY
- OLE2FRAME
- ACIS based entities: BODY, 3DSOLID, REGION, ...
- Custom entities from applications on top of AutoCAD like Map 3D, Civil 3D or
Architecture. The vertical integration stack is not documented by the DXF reference.
Unsupported entities are ignored and do not raise exceptions.
Environment Setup
-----------------
Required imports to follow this tutorial:
.. literalinclude:: src/xref/attach_dxf_dwg_xref.py
:lines: 3-9
Function to create a simple DXF file as XREF, the insertion point of the XREF is set to
(5, 5):
.. literalinclude:: src/xref/attach_dxf_dwg_xref.py
:lines: 14-26
Create the DXF file::
make_dxf_xref_document("xref.dxf")
The XREF looks like this:
.. image:: gfx/xref_doc.png
:align: center
Attach a DXF File
-----------------
Create a host document to which the XREF will be attached::
host_doc = ezdxf.new(DXFVERSION, units=units.M)
Attach the XREF by the :func:`ezdxf.xref.attach` function and save the host DXF file::
xref.attach(host_doc, block_name="dxf_xref", insert=(0, 0), filename="attached_xref.dxf")
host_doc.set_modelspace_vport(height=10, center=(0, 0))
host_doc.saveas("attach_host_dxf.dxf")
The :func:`attach` function is meant to simply attach an XREF once without any
overhead, therefore the :func:`attach` function creates the required block definition
automatically and raises an :class:`XrefDefinitionError` exception if the block definition
already exist. To attach additional XREF references use the method
:meth:`~ezdxf.layouts.BaseLayout.add_blockref`::
msp.add_blockref("dxf_xref", insert=another_location)
The attached DXF file in BricsCAD:
.. image:: gfx/xref_attached_dxf.png
:align: center
.. important::
AutoCAD can not display DXF files as attached XREFs.
Attach a DWG File
-----------------
Export the DXF file as DWG by the :mod:`~ezdxf.addons.odafc` add-on::
# It's not required to save the DXF file!
doc = make_dxf_xref_document("attached_xref.dxf")
try:
odafc.export_dwg(doc, "attached_xref.dwg", replace=True)
except odafc.ODAFCError as e:
print(str(e))
Attach the DWG file by the :func:`ezdxf.xref.attach` function and save the host DXF file::
host_doc = ezdxf.new(DXFVERSION, units=units.M)
xref.attach(host_doc, block_name="dwg_xref", filename="attached_xref.dwg", insert=(0, 0))
host_doc.set_modelspace_vport(height=10, center=(0, 0))
host_doc.saveas("attached_dwg.dxf")
Attached DWG file in Autodesk DWG TrueView 2023:
.. image:: gfx/xref_attached_dwg.png
:align: center
Detach an XREF
--------------
The :func:`~ezdxf.xref.detach` function writes the content of a block definition into
the modelspace of a new DXF document and convert the block to an external reference (XREF).
The new DXF document has to be written/exported by the caller.
The function does not create any block references. These references should already exist
and do not need to be changed since references to blocks and XREFs are the same.
.. literalinclude:: src/xref/detach_dxf_dwg_xref.py
:lines: 23-29
.. important::
Save the host document after detaching the block!
Detaching a block definition modifies the host document.
The :func:`detach` function returns a :class:`Drawing` instance, so it's possible
to convert the DXF document to DWG by the :mod:`~ezdxf.addons.odafc` add-on if necessary
(e.g. for Autodesk products). It's important that the argument :attr:`xref_filename`
match the filename of the exported DWG file:
.. literalinclude:: src/xref/detach_dxf_dwg_xref.py
:lines: 33-42
It's recommended to clean up the entity database of the host document afterwards::
host_doc.entitydb.purge()
For understanding, this is the :func:`make_block` function:
.. literalinclude:: src/xref/detach_dxf_dwg_xref.py
:lines: 10-19
Embed an XREF
-------------
The :func:`embed` function loads the content of the XREF into the block definition,
this is the reverse operation of detaching an XREF.
For loading the content of DWG files is a loading function required, which loads the
DWG file as :class:`Drawing` document. The :mod:`~ezdxf.addons.odafc` add-on module
provides such a function: :func:`~ezdxf.addons.odafc.readfile`.
This example embeds the XREF "attached_xref.dwg" of the first example as content of the
block definition "GEAR", the "attach_host_dwg.dxf" file is the host DXF document:
.. code-block:: Python
import ezdxf
from ezdxf.addons import odafc
doc = ezdxf.readfile("attach_host_dwg.dxf")
gear_xref = doc.blocks.get("GEAR")
try:
xref.embed(gear_xref, load_fn=odafc.readfile)
except FileNotFoundError as e:
print(str(e))
The default loading function for DXF files is the :func:`ezdxf.readfile` function and
doesn't have to be specified. For the loading function from the :mod:`~ezdxf.recover`
module use a lambda function:
.. code-block:: Python
import ezdxf
from ezdxf import recover
doc = ezdxf.readfile("attach_host_dxf.dxf")
gear_xref = doc.blocks.get("GEAR")
try:
xref.embed(gear_xref, load_fn=lambda f: recover.readfile(f)[0])
except FileNotFoundError as e:
print(str(e))
Load Modelspace
---------------
The :func:`ezdxf.xref.load_modelspace` function loads the content of the modelspace
of the source document into a layout of the target document, the modelspace of the
target document is the default target layout.
.. hint::
Use this function to combine multiple existing DXF files.
If the goal is just to add new entities to an existing document, rather load the
source document as a template by :func:`ezdxf.readfile`, add your content and save
the document as a new DXF file with the :meth:`saveas` method.
Merge multiple DXF files:
.. literalinclude:: src/xref/merge_dxf_files.py
:lines: 3-26
.. image:: gfx/xref_merged.png
:align: center
Load Paperspace
---------------
The function :func:`ezdxf.xref.load_paperspace` loads a paperspace layout as a new
paperspace layout into the target document. To be clear this function loads **only**
the content of the paperspace layout, the content of the modelspace isn't loaded,
therefore the loaded VIEWPORT entities show the content of the target modelspace.
Write Block
-----------
The function :func:`ezdxf.xref.write_block` writes the given entities into the
modelspace of a new DXF document, this document can be, but doesn't have to be used as
an external referenced block.
Conflict Policies
-----------------
Resources are definitions of layers, linetypes, text-, dimension-, mline- and mleader
styles, materials and blocks.
A resource conflict occurs when the source and target documents contain elements such as
layers, linetypes, text styles and so on that share the same name.
Many of the functions shown above support an argument to define the
:class:`ezdxf.xref.ConflictPolicy`, that gives you the choice how to handle resource
name conflicts.
ConflictPolicy.KEEP
~~~~~~~~~~~~~~~~~~~
Keeps the existing resource name of the target document and ignore the resource from the
source document. The loaded entities from the source document use the resources defined
in the target document and may alter their visual appearance, when the resources are
different.
ConflictPolicy.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.
.. important::
This policy ALWAYS renames the resource, even if the loaded resource doesn't have a
conflict in the target document.
ConflictPolicy.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.
.. important::
This policy renames the resource ONLY when the loaded resource has a conflict in
the target document.
Load Table Resources
--------------------
Resources are definitions of layers, linetypes, text-, dimension-, mline- and mleader
styles, materials and blocks.
The :class:`Loader` class is the low level tool to build a loading operation from simple
loading commands. Study the `source code`_ of the :mod:`xref` module, most of loading
commands used above are build upon the :class:`Loader` class.
This example shows how to import layer, linetype, text- and dimension style definitions:
.. code-block:: Python
import ezdxf
from ezdxf import xref
sdoc = ezdxf.new(setup=True)
tdoc = ezdxf.new()
# The default conflict policy is ConflictPolicy.KEEP
loader = xref.Loader(sdoc, tdoc)
# Load all layers:
loader.load_layers([layer.dxf.name for layer in sdoc.layers])
# Load specific linetypes:
loader.load_linetypes(["CENTER", "DASHED", "DASHDOT"])
# Load specific text style:
loader.load_text_styles(["OpenSans", "LiberationMono"])
# Load all DIMENSION styles, this command loads also the dependent text styles:
loader.load_dim_styles([dimstyle.dxf.name for dimstyle in sdoc.dimstyles])
# execute all loading commands:
loader.execute()
tdoc.saveas("target.dxf")
.. note::
Loading a layer does not load the entities which do reference this layer, a layer
is not an entity container, it's just an DXF attribute, see also Basic Concepts:
:ref:`layer_concept`.
.. _source code: https://github.com/mozman/ezdxf/blob/master/src/ezdxf/xref.py
|