File: create_nested_block_references.py

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 (210 lines) | stat: -rw-r--r-- 6,551 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
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
# Copyright (c) 2021-2022, Manfred Moitzi
# License: MIT License
from __future__ import annotations
from typing import Dict, cast
import math
import ezdxf

from ezdxf.math import Vec3, Matrix44, X_AXIS, OCS
from ezdxf import zoom, disassemble
from ezdxf.entities import copy_attrib_as_text

from ezdxf.layouts import BlockLayout, BaseLayout
from ezdxf.document import Drawing

# Check if a viewer and ezdxf does correct block reference (INSERT)
# transformations. It is not possible to check the drawing add-on by this
# example, because it uses the ezdxf transformation!
#
# If the viewer and ezdxf works correct only the exploded, magenta colored
# arrows are visible after loading. If any red, green or blue colored arrowheads
# are visible, the transformation of the block references applied by the viewer
# is different to the transformation done by ezdxf.
#
# Turn of the "EXPLODE" layer to see the original block references.

EXPLODE_CONTENT = True
EXPLODE_ATTRIBS = False  # explode ATTRIB entities as TEXT

BLK_CONTENT = "ARROWS"  # original block references
ATTRIBS = "CONFIG"  # transformation parameters of the base block as ATTRIBs
EXPLODE = "EXPLODE"  # by ezdxf exploded block references

LAYERS = [BLK_CONTENT, EXPLODE, ATTRIBS]


def explode(layout: BaseLayout):
    if EXPLODE_CONTENT:
        entities = list(disassemble.recursive_decompose(layout))
        for e in entities:
            if e.dxftype() in ("ATTRIB", "ATTDEF"):
                if not EXPLODE_ATTRIBS:
                    continue
                e = copy_attrib_as_text(cast("BaseAttrib", e))
            e = cast("DXFGraphic", e)
            e.dxf.layer = EXPLODE
            e.dxf.color = 6
            layout.add_entity(e)


def create_doc(filename, content_creator):
    doc = ezdxf.new(dxfversion="R2004")
    for name in LAYERS:
        doc.layers.new(name)
    doc.styles.new(ATTRIBS, dxfattribs={"font": "OpenSansCondensed-Light.ttf"})
    content_creator(doc)
    msp = doc.modelspace()
    if EXPLODE_CONTENT:
        # processing only LINE entities is much faster:
        zoom.objects(msp, doc.modelspace().query("LINE"))
    else:
        zoom.extents(msp)
    doc.saveas(filename)
    print(f"created {filename}")


def create_base_block(block: BlockLayout, arrow_length=4):
    def add_axis(attribs: Dict, m: Matrix44 = None):
        start = -X_AXIS * arrow_length / 2
        end = X_AXIS * arrow_length / 2
        leg1 = Vec3.from_deg_angle(180 - leg_angle) * leg_length
        leg2 = Vec3.from_deg_angle(180 + leg_angle) * leg_length

        lines = [
            block.add_line(start, end, dxfattribs=attribs),
            block.add_line(end, end + leg1, dxfattribs=attribs),
            block.add_line(end, end + leg2, dxfattribs=attribs),
        ]
        if m is not None:
            for line in lines:
                line.transform(m)

    leg_length = arrow_length / 10
    leg_angle = 15
    deg_90 = math.radians(90)
    # red x-axis
    add_axis(attribs={"color": 1, "layer": BLK_CONTENT})
    # green y-axis
    add_axis(
        attribs={"color": 3, "layer": BLK_CONTENT}, m=Matrix44.z_rotate(deg_90)
    )
    # blue z-axis
    add_axis(
        attribs={"color": 5, "layer": BLK_CONTENT}, m=Matrix44.y_rotate(-deg_90)
    )
    x = -arrow_length * 0.45
    y = arrow_length / 20
    line_spacing = 1.50
    height = arrow_length / 20
    block.add_attdef(
        "ROTATION", (x, y), dxfattribs={"style": ATTRIBS, "height": height}
    )
    y += height * line_spacing
    block.add_attdef(
        "SCALE", (x, y), dxfattribs={"style": ATTRIBS, "height": height}
    )
    y += height * line_spacing
    block.add_attdef(
        "EXTRUSION", (x, y), dxfattribs={"style": ATTRIBS, "height": height}
    )


def show_config(blk_ref):
    dxf = blk_ref.dxf
    blk_ref.add_auto_attribs(
        {
            "ROTATION": f"Rotation: {dxf.rotation:.2f} deg",
            "SCALE": f"Scale: x={dxf.xscale}  y={dxf.yscale}  z={dxf.zscale}",
            "EXTRUSION": f"Extrusion: {str(dxf.extrusion.round(3))}",
        }
    )


def create_block_references(
    layout: BaseLayout,
    block_name: str,
    layer: str = "LAYER",
    grid=(10, 10),
    extrusions=((0, 0, 1), (0, 0, -1)),
    scales=((1, 1, 1), (-1, 1, 1), (1, -1, 1), (1, 1, -1)),
    angles=(0, 45, 90, 135, 180, 225, 270, 315),
):
    y = 0
    grid_x, grid_y = grid
    for extrusion in extrusions:
        ocs = OCS(extrusion)
        for sx, sy, sz in scales:
            for index, angle in enumerate(angles):
                x = index * grid_x
                insert = ocs.from_wcs((x, y))
                blk_ref = layout.add_blockref(
                    block_name,
                    insert,
                    dxfattribs={
                        "layer": layer,
                        "rotation": angle,
                        "xscale": sx,
                        "yscale": sy,
                        "zscale": sz,
                        "extrusion": extrusion,
                    },
                )
                show_config(blk_ref)
            y += grid_y


def create_l0_block_references(layout: BaseLayout, block_name: str):
    create_block_references(
        layout,
        block_name,
        layer=ATTRIBS,
        grid=(4.5, 4.5),
        extrusions=(
            (0, 0, 1),
            (1, 0, 0),
            (0, 1, 0),
            (0, 0, -1),
            (-1, 0, 0),
            (0, -1, 0),
        ),
        scales=((1, 1, 1), (-1, 1, 1), (1, -1, 1), (1, 1, -1)),
        angles=(0, 45, 90, 135, 180, 225, 270, 315),
    )


def create_l1_block_references(layout: BaseLayout, block_name: str):
    create_block_references(
        layout,
        block_name,
        layer=ATTRIBS,
        grid=(220, 220),
        extrusions=(
            (0, 0, 1),
            (1, 0, 0),
            (0, 1, 0),
            (0, 0, -1),
            (-1, 0, 0),
            (0, -1, 0),
        ),
        scales=((1, 1, 1), (-1, 1, 1), (1, -1, 1), (1, 1, -1)),
        angles=(0, 90, 180),
    )


def nesting_level_0(doc: Drawing):
    blk = doc.blocks.new("BASE")
    create_base_block(blk)
    create_l0_block_references(doc.modelspace(), "BASE")


def nesting_level_1(doc: Drawing):
    blk = doc.blocks.new("BASE")
    create_base_block(blk)
    blk0 = doc.blocks.new("LEVEL0")
    create_l0_block_references(blk0, "BASE")
    create_l1_block_references(doc.modelspace(), "LEVEL0")


if __name__ == "__main__":
    create_doc("insert_nesting_level_0.dxf", nesting_level_0)
    create_doc("insert_nesting_level_1.dxf", nesting_level_1)