In this article I elaborate on Block objects in AutoCAD and how working with them can be automatized using Python.
Although for this practical example I am using the pyautocad library I can also use pythoncom. I have explained how to use communication modules in Python in previous blog posts. More precisely, I am specifically referring to pythoncom and win32com.
Creating AutoCAD Block objects in Python
Firstly, let me explain why AutoCAD Block objects are so significant.
Whenever I want to use certain objects repeatedly, I create a block for those objects. That one block object can contain multiple other objects with e.g. different geometries, attributes, etc.
Once I create a AutoCAD Block object with the pyautocad module in Python, it gets saved in the Document database. I have explained how this Document object works in one of my previous articles.
I can save multiple AutoCAD Block objects in the Document database. Likewise, I can do the same for Blocks collectively in the form of a Blocks Collection object.
Creating instances with InsertBlock()-method in pyautocad
Now that I have created blocks I want to use them in my drawing. This is when I use the InsertBlock method. This method creates an AutoCAD Block object instance for the block that I pass as an input parameter value.
The Block that is present in my drawing by now is known as the BlockReference object.
Let me write the code to explain this considering all the things above.
from pyautocad import Autocad, APoint, aDouble
acad = Autocad(create_if_not_exists=True)
# flow
# Document > BlocksCollection > Block > BlockReference
# insertion point for block
ip = APoint(0, 0, 0)
# adding block to documents block collection
b1 = acad.doc.Blocks.Add(ip, "Test_block_1")
# adding geometries to block
pl = b1.AddPolyline(aDouble(0, 0, 0, 10000, 0, 0, 10000, 5000, 0, 0, 5000, 0, 0, 0, 0))
l = b1.AddLine(APoint(0, 250, 0), APoint(10000, 250, 0))
# adding block instance to drawing (creating a reference to the block)
block_ref1 = acad.model.InsertBlock(APoint(50, 50, 0), "Test_block_1", 1, 1, 1, 0)
AutoCAD Block and BlockReference object properties
As I have now created both AutoCAD Block and AutoCAD BlockReference objects I will now walk you through the various different properties of these two object types.
Firstly, let me talk about some of the important properties of the AutoCAD Block object. While using blocks I have different requirements. For example, I have to decide whether or not my block has to be explodable, whether it should be dynamic or static, and whether I want to keep it flexible to scale or not, etc.
Below is the code showing how I can use all such properties using the pyautocad module in Python.
# properties
print("Object Name: " + b1.ObjectName)
print("Name of Block: " + b1.Name)
print("Native units of measures for the Block: ", end="")
print(b1.Units)
print("Is scaling allowed for the Block ? ", end="")
print(b1.BlockScaling)
print("Is the Block explodable ? ", end="")
print(b1.Explodable)
print("Is the Block dynamic ? ", end="")
print(b1.IsDynamicBlock)
O/p:
Object Name: AcDbBlockTableRecord
Name of Block: Test_block_1
Native units of measures for the Block: 0
Is scaling allowed for the Block ? 0
Is the Block explodable ? True
Is the Block dynamic ? False
In above code the BlockScaling property is returning a “0”. This represents a type of scaling from the list of types given below:
- acAny: 0
- acUniform: 1
On the other hand, I have BlockReference properties. Check the code displayed below.
# properties of BlockReference
print("Object Name: " + block_ref1.ObjectName)
print("Block Name: " + block_ref1.Name)
print("Original Block Name: " + block_ref1.EffectiveName)
print("Entity Transparency: ", end="")
print(block_ref1.EntityTransparency)
print("Does the Block contain any Attributes: ", end="")
print(block_ref1.HasAttributes)
print("Insertion Point: ", end="")
print(block_ref1.InsertionPoint)
print("Insert units saved with Blocks: ", end="")
print(block_ref1.InsUnits)
print("Conversion factor between Block units and drawing units: ", end="")
print(block_ref1.InsUnitsFactor)
print("Is the Block dynamic ? ", end="")
print(block_ref1.IsDynamicBlock)
print("Layer: " + block_ref1.Layer)
print("Line type: " + block_ref1.Linetype)
print("Line type scale: ")
print(block_ref1.LinetypeScale)
print("Line weight: ")
print(block_ref1.Lineweight)
print("Rotation angle for the block: ")
print(block_ref1.Lineweight)
#Scale factors
print("X Scale factor of block: ", end="")
print(block_ref1.XEffectiveScaleFactor)
print("X Scale factor for block or external reference (xref): ", end="")
print(block_ref1.XScaleFactor)
print("Y Scale factor of block: ", end="")
print(block_ref1.YEffectiveScaleFactor)
print("Y Scale factor for block or external reference (xref): ", end="")
print(block_ref1.YScaleFactor)
print("Z Scale factor of block: ", end="")
print(block_ref1.ZEffectiveScaleFactor)
print("Z Scale factor for block or external reference (xref): ", end="")
print(block_ref1.ZScaleFactor)
O/p:
Object Name: AcDbBlockReference
Block Name: Test_block_1
Original Block Name: Test_block_1
Entity Transparency: ByLayer
Does the Block contain any Attributes: False
Insertion Point: (50.0, 50.0, 0.0)
Insert units saved with Blocks: Unitless
Conversion factor between Block units and drawing units: 1.0
Is the Block dynamic ? False
Layer: 0
Line type: ByLayer
Line type scale:
1.0
Line weight:
-1
Rotation angle for the block:
-1
X Scale factor of block: 1.0
X Scale factor for block or external reference (xref): 1.0
Y Scale factor of block: 1.0
Y Scale factor for block or external reference (xref): 1.0
Z Scale factor of block: 1.0
Z Scale factor for block or external reference (xref): 1.0
Block (Reference) methods in AutoCAD using Python
This section is just to introduce two of the important methods for Block objects:
- InsertBlock
- Delete
As I have already mentioned in the first section I need the BlockCollections object from Document (object/database) in order to be able to insert a Block.
acad.doc.Blocks.Add(Insertion point, Block name)
To delete a AutoCAD Block object I can simply take the respective AutoCAD Block instance and apply the Delete method on the same.
block.Delete()
Coming to the BlockReference object there are a few methods I have to mention:
- ConvertToAnonymousBlock
- ConvertToStaticBlock
- GetConstantAttributes
- GetDynamicBlockProperties
- ResetBlock
The ConvertToAnonymousBlock method converts a Dynamic block to Anonymous Block.
block_ref1.ConvertToAnonymousBlock
On the other hand, the ConvertToStaticBlock method converts a Dynamic block to a named block. This takes a name as a parameter.
block_ref1.ConvertToStaticBlock("static_block1")
To fetch the constant attributes from a Block or external reference I can use the GetConstantAttributes method. This method returns an array of AutoCAD Attribute objects that are constant for the BlockReference object.
block_ref1.GetConstantAttributes
Also, If I want to fetch an array of dynamic properties assigned to a block I can use the following code:
block_ref1.GetDynamicBlockProperties
Lastly, to reset any dynamic block to the default state I can use the ResetBlock method.
block_ref1.ResetBlock
Besides that, the BlockReference object has all those same methods available as I use with any other AutoCAD objects such as Line, Layer, Circle, Raster, etc. Some of those important methods are listed below:
- ArrayPolar
- ArrayRectangular
- Copy
- Delete
- GetBoundingBox
- IntersectWith
- Mirror
- Mirror3D
- Move
- Rotate
- Rotate3D
- ScaleEntity
- Update
- UpdateMTextAttribute
Do check out my previous blog posts to understand how to implement those methods.
Example of an AutoCAD Attributed Block
Coming to an end, I would like to share an example of an Attributed Block. An attributed block is the one containing different attributes which further contains metadata of that Block or entities inside the same.
I will explain more about the Attribute objects and the AttributeReference objects separately in the future.
from pyautocad import Autocad, APoint, aDouble
acad = Autocad(create_if_not_exists=True)
ip = APoint(0, 0, 0)
b1 = acad.doc.Blocks.Add(ip, "Attributed_Block_1")
pl = b1.AddPolyline(aDouble(0, 0, 0, 10000, 0, 0, 10000, 5000, 0, 0, 5000, 0, 0, 0, 0))
l = b1.AddLine(APoint(0, 250, 0), APoint(10000, 250, 0))
l = b1.AddLine(APoint(5000, 250, 0), APoint(5000, 0, 0))
a1 = b1.AddAttribute(50, 0, "DATE", aDouble(200, 100, 0), "DATE", "Date: 17/07/2022")
a2 = b1.AddAttribute(50, 0, "DWG", aDouble(5200, 100, 0), "DWG", "Drawing Name: Drawing 1")
br = acad.model.InsertBlock(APoint(50, 50, 0), "Attributed_Block_1", 1, 1, 1, 0)
Evidently, as it contains attributes if I use the HasAttribute property method for this Block reference, I will get a True value.
print("Does the Block contain any Attributes: ", end="")
print(br.HasAttributes)
O/p:
Does the Block contain any Attributes: True
Concluding remarks
To sum up, I can conclude that using the above methods I can automatize different tasks related to AutoCAD Block and AutoCAD BlockReference objects.
Also, in case of any queries do leave your question in the comment section below. As well as you can contact me using our contact form for any kind of technical consultation. Please check out my other articles for understanding the usage and significance of the pyautocad and pywin32 Python modules.
References to related content
I, together with other SCDA members, have built a series of blog posts documenting AutoCAD, pyautocad and pywin32 for AutoCAD automatization with Python. Here is a list of some related content:
- Link: Python for AutoCAD pyautocad module
- Link: add() method in pyautocad
- Link: Solved call was rejected by callee in pythoncom
- Link: Tree data structure for AutoCAD objects using Python
- Link: Extending the objects in AutoCAD using pyautocad in Python
- Link: Using Python lists and dictionaries to work with AutoCAD objects with pyautocad
- Link: Hatching objects on AutoCAD template using pywin32 in Python
- Link: Raster image object in AutoCAD with pyautocad in Python
- Link: Working with 3D mesh object in AutoCAD using pyautocad in Python
- Link: Creating adouble constructor using pywin32 in Python
- Link: Creating apoint method using pywin32 in Python
- Link: Python integration with AutoCAD using pywin32 and win32com
- Link: Deleting objects in a AutoCAD template with pyautocad and pywin32 in Python
- Link: Mirror object on a 2D plane with pyautocad in Python
- Link: Working with texts in Autocad using pyautocad in Python
- Link: Polar arrays in AutoCAD using pyautocad in Python
- Link: Rectangular arrays in AutoCAD using pyautocad in Python
- Link: Operations with AutoCAD objects using pyautocad in Python
- Link: Solid objects in AutoCAD using pyautocad in Python
- Link: Working with helices in AutoCAD using pyautocad in Python
- Link: Drawing splines in AutoCAD with pyautocad in Python
- Link: Polylines in pyautocad for drawing AutoCAD polygons in Python
- Link: Drawing ellipse arcs in AutoCAD using pyautocad in Python
- Link: Drawing arcs in AutoCAD using pyautocad in Python
- Link: Near simultaneous factory design and process optimization with Promodel AutoCAD edition
- Link: Python for AutoCAD pyautocad module
- Link: Region object in AutoCAD with Python
- Link: AutoCAD Application object class in Python
Civil engineer interested in automation in core subjects such as civil, mechanical and electrical, using IT skills comprising cloud computing, devops, programming languages and databases along with the technical skills gained while working as a civil engineer since past 3 years.
22 comments
Hey Tanmay,
Thank You for various use cases with Blocks.
However, I am struggling to get geometric extents of block (i.e title block) in python console.
Is there anyway to get minpoint and maxpoint of the block object?
I tired using AcDbBlockReference but it’s throwing unknown attribute error.
Thank You.
see below example
import win32com.client
acad = win32com.client.Dispatch(“AutoCAD.Application”)
doc = acad.ActiveDocument
mspace = doc.ModelSpace
block_ref = mspace.InsertBlock(point, block_name, 1.0, 1.0, 1.0, 0.0)
bbox = block_ref.BoundingBox
min_point = bbox[0]
max_point = bbox[1]
Hello Tanmay,
This is the issue that I am running into. I have a drawing that has several values saved as Parameters. I would like to have the python script write to that document and change that specific parameter. In that same document I have a text box where I would like to change the text according to a python script.
import win32com.client
acad = win32com.client.Dispatch(“AutoCAD.Application”)
doc = acad.ActiveDocument
named_objs = doc.NamedObjects
param_name = “MyParam”
param = named_objs.Item(param_name)
param.Value = 42
text_name = “MyText”
text_obj = named_objs.Item(text_name)
text_obj.TextString = “Hello, world!”
doc.Save()
Hello Thank you for Tutorial,
It s possible to introdus the point APoint() by mouse?
Thank You again
try something like this:
import pyautocad
acad = pyautocad.Autocad()
point = acad.doc.Utility.GetPoint()
circle = acad.model.AddCircle(point, 10)
this should prompt you to select a point using your mouse
Hello,
Thank you for your response, magic 🙂
Hi!
Thank you for your work!
Please tell me how to change the parameter of the dynamic block?
see my other reply
Hi!
Thank you for your work!
Please tell me where to look for information on my problem:
I have a dynamic block in the form of a frame with a table. I need to change this block in length (pull the frame to one side). I tried the scaling method when inserting a block, but the table inside the block is also stretched and this method is not suitable. There is a parameter “length” in the block properties. If this parameter is changed, then the block stretches as I need. How to do it using Python code?
does this work for you?
import win32com.client
import pythoncom
import time
acad = win32com.client.Dispatch(“AutoCAD.Application”)
def stretch_block(block_name, x_scale_factor, y_scale_factor, insertion_point):
doc = acad.ActiveDocument
ms = doc.ModelSpace
blk_def = doc.Database.BlockTableId.GetObject(acad.ActiveDocument.Database).GetBlockDefinitionNames()[block_name]
blk_ref = ms.InsertBlock(insertion_point, blk_def.Name, 1, 1, 1, 0)
blk_ref.ScaleFactors = (x_scale_factor, y_scale_factor, 1)
stretch_action = blk_ref.GetDynamicBlockProperties().GetAction(“Stretch”)
stretch_action.GetParameter(“X”).Value = x_scale_factor
stretch_action.GetParameter(“Y”).Value = y_scale_factor
blk_ref.Update()
doc.ActiveViewport.Refresh()
doc.Save()
# example application
stretch_block(“MyDynamicBlock”, 2, 2, (0, 0, 0))
Thank you, but this method is not suitable, because inside the block the table is drawn with lines (this is not an autocad table, it cannot have an ID). I tried to add the autocad table to my block. Returns the error “KeyError: (‘BlockTableId’, 3)”. I did it with the help of this construction:
acad1 = win32com.client.Dispatch(‘AutoCAD.Application’)
acad1.Visible = True
acadModel = acad1.ActiveDocument.ModelSpace
n = 10
for i in acadModel:
if i.IsDynamicBlock:
print(i.EffectiveName)
if i.EffectiveName == ‘Block_test’:
for p in i.GetDynamicBlockProperties():
if p.PropertyName == ‘quantity_columns’:
p.Value *= n
This method does not change the entire block, but only part of it with columns for information. Is it possible to simplify this method somehow? or maybe there is a solution that does not sort through the space of the autocad model in search of the right block?
Hello, please help! I have been struggling with the problem for 3 days.
I have a function that inserts the “Block_test” block into the autocad drawing. Then I look for this block in the space of the autocad model, find the properties of this block, change one of the properties to the value I need. Then I will transform this block into a static one. Up to this point, the code works fine. But as soon as I insert the same block again by shifting the Y coordinate, this block is no longer searched for as dynamic. The line of code “print(i.efficiename)” does not print the name of this block. Accordingly, it is not possible to edit this block. How can I solve this problem? Please help me!!!
boxes_list = [“Box1′, ‘Box2’]
cor_x = 0
cor_y = 0
def create_box_to_autocad(name_box, x, y):
block_table_box = acad.model.InsertBlock(APoint(x, y), ‘Block_test’, 1, 1, 1, 0) # Insert block_test
for i in acadModel:
if i.IsDynamicBlock:
print(i.EffectiveName)
if i.EffectiveName == “Block_test”:
for p in i.GetDynamicBlockProperties():
if p.PropertyName == ‘Length’:
p.Value *= 5
block_table_box.ConvertToStaticBlock(“static_Block_test-” + name_box)
for box in boxes_list:
create_box_to_autocad(box, cor_x, cor_y)
cor_y -= 350
Thank you for your question. Please remember that I am not the core developer or package owner. I run this blog for personal interest and commercial profit. We offer consulting against a fee and would love to help you. Just make inquiry via contact form. Alternatively will get back to your comment at earliest convenience. Thanks and have a nice day
I realised you! Anyway, thank you! While I was writing, there were some ideas to correct the error. If nothing works out, I’ll contact you for a paid consultation!
ok thanks share your ideas here if it worked out or not
Hi,
I need your help regarding Inserting multiple blocks with the python scripts. can you help me
Respected Sir,
I have created a number of blocks, and now I want to give them dimensions. Can you provide me with suggestions on that, please? Also, can you suggest resources to learn more about different methods that help me work with blocks?
Hello, please help me to translate this VBA code into python language:
Set blockRef = ThisDrawing.ModelSpase.InsertBlock(APoint(x, y), ‘Name_block’, 1, 1, 1, 0)
If blockRef.IsDynamicBlock = True Then
Props = blockRef.GetDynamicBlockProperties
For Index = LBound(Props) to UBound(Props)
Set prop = Props(Index)
If prop.PropertyName == ‘Length’ Then
prop.Value = 50
Hello,
How do I add a block or external reference to paperspace? I have tried it multiple ways and can’t seem to get python to recognize paperspace.
Hello,
Thanks for this article. It helped me a lot. However, I am looking for something I could not find anywhere on the net, so I give it a go there: does anyone know how to hatch a block through pyautocad or through pythoncom and win32com.client?
I am able to define a block in pyautocad, add polylines and text, but I can’t find the way to hatch it – I am able to hatch any closed area in the model space though , but not in the BlockEditor.
Yet, I think that such a way exists, because in AutoCAD, it is easy to create a block with hatches in it.
Any help would be really appreciated,
Thanks,
Matu
acad=win32com.client.Dispatch(“Autocad.Application”)
acadDoc=acad.ActiveDocument
acadModel=acad.ActiveDocument.ModelSpace
# Checking layer exist or not
def layerexist(lay):
layers = acadDoc.Layers
layers_nums = layers.Count
layers_names = [layers.Item(i).Name for i in range(layers_nums)] # List of ACAD layers
if lay in layers_names:
return True
else:
return False
# Create polyline
def make_pline(pts, lay):
plineObj = acadModel.AddPolyline(vtFloat(pts))
if not layerexist(lay):
acadDoc.Layers.Add(lay)
plineObj.Layer = lay
return plineObj
b1 = acadDoc.Blocks.Add(p3, “Test_block_1”)
# thanh bao ngang trên C3328=1.23
pontos1 = [p1x,p1y,0,p2x,p2y,0,p2x+A,p2y-A,0,p1x-A,p1y-A,0,p1x,p1y,0]
thanh1=make_pline(pontos1, “haaa”)
How to add object “thanh1” in to Block “b1”