How to create a new Block Definition?

Hi, I’m trying to create a new block definition.
At the end of my dynamo script I have several blockreferences and 3D polylines, I would like to create a block definition with all those objects, insert then as a block reference.

I searched on the foruns, custom packages and didn’t find anything.
I was trying to follow this link Creating an AutoCAD block using .NET - Through the Interface , but I know little of python and none of VB.net.

Hi @deividsteffens,

You could try these nodes from the Civil 3D Toolkit.

Blocks

That doesn’t work and I can’t use the first one, I’m working with cad objects, not dynamo geometry.
image

I’m Deivid Steffens, wrong login for this post.

read the log file in the temp folder

Hi Paolo, that error doesn’t trigger the log.

image

I was worred that even if this worked I was not able to choose the name of the block definition, but I can use parameter renaming.

I got something going, need to know how to get ObjectId of my objects.

# Load the Python Standard and DesignScript Libraries
import sys
import clr

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

def CreateBlock():
  #ids = IN[0].GetObjectIds()
  objs = IN[0]
  ids = []
  blockId = ObjectId.Null
  with adoc.LockDocument():
    with adoc.Database as db:
      with db.TransactionManager.StartTransaction() as tr:
        for obj in objs:
          #ids.append(tr.GetObject(obj.Id, OpenMode.ForRead))
          ids.append(obj.GetObjectId())

        bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
        bt.UpgradeOpen()
        record = BlockTableRecord()
        record.Name = "Teste001"
        bt.Add(record)
        tr.AddNewlyCreatedDBObject(record, true)
        
        blockId = bt['Teste001']
        tr.Commit()
CreateBlock()

OUT = [ids,blockid]



Ok, I was able to Create the Block Definition, now working on appending the objects.

A few thoughts:

  • I’m assuming eventually you’ll add the block name as an input for the function. In that case, it would be good to check if a block with that name already exists before trying to create it. The Block Table class inherits from the Symbol Table class, which has a Has method to check this.
  • If you want to copy the existing objects (which are already contained in the model space block table record) into the new block table record, you’ll need to use the Database.DeepCloneObjects method.
2 Likes

Hi mz, I will not give an input for the name, no worries about that.

I was looking for that code to clone the objects, I’m stuck on exactly that. When I find the full solution I post.

Finally was able to reach the solution.

# Load the Python Standard and DesignScript Libraries
import sys
import clr

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

def CreateBlock(bName, objs):
  ids = []
  blockId = ObjectId.Null
  
  with adoc.LockDocument():
    with adoc.Database as db:
      with db.TransactionManager.StartTransaction() as tr:


        bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
        bt.UpgradeOpen()
        btr = BlockTableRecord()
        btr.Name = bName
        bt.Add(btr)
        tr.AddNewlyCreatedDBObject(btr, True)       

        for obj in objs:
          id = obj.InternalObjectId
          ids.append(id)
          entity = tr.GetObject(id, OpenMode.ForRead)
          cloneEntity = entity.Clone()
          btr.AppendEntity(cloneEntity)
          tr.AddNewlyCreatedDBObject(cloneEntity, True)   
        tr.Commit()
        


OUT = CreateBlock('Teste004',IN[0])


1 Like

Now I just want to know, how do I return back to dynamo the block reference as a Dynamo Block Reference?

The return of my function now is an “Autodesk.AutoCAD.DatabaseServices.BlockReference”

# Load the Python Standard and DesignScript Libraries
import sys
import clr

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

def CreateBlock(bName, objs):
  ids = []
  blockId = ObjectId.Null
  
  with adoc.LockDocument():
    with adoc.Database as db:
      with db.TransactionManager.StartTransaction() as tr:


        bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead)
        model = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite)
        bt.UpgradeOpen()
        btr = BlockTableRecord()
        btr.Name = bName
        bt.Add(btr)
        tr.AddNewlyCreatedDBObject(btr, True)
        blockId = bt[bName]
        
        for obj in objs:
          id = obj.InternalObjectId
          ids.append(id)
          entity = tr.GetObject(id, OpenMode.ForRead)
          cloneEntity = entity.Clone()
          entity.Erase()
          btr.AppendEntity(cloneEntity)
          tr.AddNewlyCreatedDBObject(cloneEntity, True)   
        
        br = BlockReference(Point3d.Origin, blockId)
        model.AppendEntity(br)
        tr.AddNewlyCreatedDBObject(br, True)
        tr.Commit()
        return br


OUT = CreateBlock(IN[0],IN[1])


1 Like

You’ll have to add a reference to Autodesk.AutoCAD.DynamoNodes and then use Document.Current.BlockByName with the name of the block.

Nice work, Deivid! These would be some good nodes to add to Camber. Are you interested in contributing?

1 Like

Sure, I would like to.