File: bbox.rst

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (179 lines) | stat: -rw-r--r-- 5,403 bytes parent folder | download
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
Bounding Box
============

.. module:: ezdxf.bbox

The :mod:`ezdxf.bbox` module provide tools to calculate bounding boxes for
many DXF entities, but not for all. The bounding box calculation is based on the
:mod:`ezdxf.disassemble` module and therefore has the same limitation.

.. warning::

    If accurate boundary boxes for text entities are important for you,
    read this first: :ref:`Text Boundary Calculation`.
    TL;DR: Boundary boxes for text entities are **not accurate!**

Unsupported DXF entities:

    - All ACIS based types like BODY, 3DSOLID or REGION
    - External references (XREF) and UNDERLAY object
    - RAY and XRAY, extend into infinite
    - ACAD_TABLE, no basic support - only preserved by `ezdxf`


Unsupported entities are silently ignored, filtering of these DXF types is not
necessary.

The base type for bounding boxes is the :class:`~ezdxf.math.BoundingBox` class
from the module :mod:`ezdxf.math`.

The `entities` iterable as input can be the whole modelspace, an entity
query or any iterable container of DXF entities.

The Calculation of bounding boxes of curves is done by flattening the curve by
a default flattening distance of 0.01. Set argument `flatten` to 0 to speedup
the bounding box calculation by accepting less precision for curved objects by
using only the control vertices.

The **optional** caching object :class:`Cache` has to be instantiated by the
user, this is only useful if the same entities will be processed multiple times.

Example usage with caching:

.. code-block:: Python

    from ezdxf import bbox

    msp = doc.modelspace()
    cache = bbox.Cache()
    # get overall bounding box
    first_bbox = bbox.extents(msp, cache=cache)
    # bounding box of all LINE entities
    second_bbox = bbox.extend(msp.query("LINE"), cache=cache)

Functions
---------

.. autofunction:: extents

.. autofunction:: multi_flat

.. autofunction:: multi_recursive

Caching Strategies
------------------

Because `ezdxf` is not a CAD application, `ezdxf` does not manage data
structures which are optimized for a usage by a CAD kernel. This means
that the content of complex entities like block references or leaders has
to be created on demand by DXF primitives on the fly. These temporarily
created entities are called virtual entities and have no handle and are not
stored in the entity database.

All this is required to calculate the bounding box of complex entities,
and it is therefore a very time consuming task. By using a :class:`Cache` object
it is possible to speedup this calculations, but this is not a magically feature,
it requires an understanding of what is happening under the hood to achieve
any performance gains.

For a single bounding box calculation, without any reuse of entities it makes
no sense of using a :class:`Cache` object, e.g. calculation of the modelspace
extents:

.. code-block:: python

    from pathlib import Path
    import ezdxf
    from ezdxf import bbox

    CADKitSamples = Path(ezdxf.EZDXF_TEST_FILES) / 'CADKitSamples'

    doc = ezdxf.readfile(CADKitSamples / 'A_000217.dxf')
    cache = bbox.Cache()
    ext = bbox.extents(doc.modelspace(), cache)

    print(cache)

1226 cached objects and not a single cache hit::

    Cache(n=1226, hits=0, misses=3273)

The result for using UUIDs to cache virtual entities is not better::

    Cache(n=2206, hits=0, misses=3273)

Same count of hits and misses, but now the cache also references
~1000 virtual entities, which block your memory until the cache is deleted,
luckily this is a small DXF file (~838 kB).

Bounding box calculations for multiple entity queries, which have overlapping
entity results, using a :class:`Cache` object may speedup the calculation:

.. code-block:: python

    doc = ezdxf.readfile(CADKitSamples / 'A_000217.dxf.dxf')
    msp = doc.modelspace()
    cache = bbox.Cache(uuid=False)

    ext = bbox.extents(msp, cache)
    print(cache)

    # process modelspace again
    ext = bbox.extents(msp, cache)
    print(cache)

Processing the same data again leads some hits::

    1st run: Cache(n=1226, hits=0, misses=3273)
    2nd run: Cache(n=1226, hits=1224, misses=3309)

Using :code:`uuid=True` leads not to more hits, but more cache entries::

    1st run: Cache(n=2206, hits=0, misses=3273)
    2nd run: Cache(n=2206, hits=1224, misses=3309)

Creating stable virtual entities by disassembling the entities at
first leads to more hits:

.. code-block:: Python

    from ezdxf import disassemble

    entities = list(disassemble.recursive_decompose(msp))
    cache = bbox.Cache(uuid=False)

    bbox.extents(entities, cache)
    print(cache)

    bbox.extents(entities, cache)
    print(cache)

First without UUID for stable virtual entities::

    1st run: Cache(n=1037, hits=0, misses=4074)
    2nd run: Cache(n=1037, hits=1037, misses=6078)

Using UUID for stable virtual entities leads to more hits::

    1st run: Cache(n=2019, hits=0, misses=4074)
    2nd run: Cache(n=2019, hits=2018, misses=4116)

But caching virtual entities needs also more memory.

In conclusion: Using a cache is only useful, if you often process
**nearly the same data**; only then can an increase in performance be expected.

Cache Class
-----------

.. autoclass:: Cache

    .. py:attribute:: has_data

        ``True`` if the cache contains any bounding boxes

    .. py:attribute:: hits

    .. py:attribute:: misses

    .. automethod:: invalidate