Tutorial for Blocks¶
What are Blocks?¶
Blocks are collections of DXF entities which can be placed multiple times as
block references in different layouts and other block definitions.
The block reference (Insert
) can be rotated, scaled,
placed in 3D by OCS and arranged in a grid like manner, each
Insert
entity can have individual attributes
(Attrib
) attached.
Create a Block¶
Blocks are managed as BlockLayout
by a
BlocksSection
object, every drawing has only
one blocks section stored in the 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 is a DXF Insert
entity and can be placed in any layout:
Modelspace
, any Paperspace
or BlockLayout
(which enables nested block references). Every block reference can be scaled and rotated individually.
Lets insert some random flags into 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 inserting a block reference into the modelspace or another block
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.
What are Attributes?¶
An 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 programs.
An attribute can be visible or hidden. The simple way to use attributes is just to add an attribute to a block
reference by Insert.add_attrib()
, but the attribute is geometrically not related to the
block reference, so you have to calculate the insertion point, rotation and scaling of the attribute by yourself.
Using Attribute Definitions¶
The second way to use attributes in block references is a two step process, first step is to create an attribute
definition (template) in the block definition, the second step is adding the block reference by
Layout.add_blockref()
and attach and fill attribute automatically by the
add_auto_attribs()
method to the block reference.
The advantage of this method is that all attributes are placed relative to the block base point with the same
rotation and scaling as the block, but has the disadvantage that non uniform scaling is not handled very well.
The method Layout.add_auto_blockref()
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 which will create correct
graphical representations at least by AutoCAD and BricsCAD. This method has the disadvantage of a more complex
evaluation of attached attributes
Using attribute definitions (Attdef
):
# 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 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 real references to 'FLAG'
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 and still experimental feature and because ezdxf is still not a CAD application, the results may no be perfect. Non uniform scaling lead to incorrect results for text entities (TEXT, MTEXT, ATTRIB) and some other entities like HATCH with arc or ellipse path segments.
By default the “exploded” entities are added to the same layout as the block reference is located.
for flag_ref in msp.query('INSERT[name=="FLAG"]'):
flag_ref.explode()
Examine Entities of Block References¶
If you just want to examine the entities of a block reference use the virtual_entities()
method.
This methods yields “virtual” entities with attributes 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)}.')