A blog for developers programming with Autodesk platforms, particularly AutoCAD and Forge. With a special focus on AR/VR and IoT.

January 22, 2010

Creating an AutoCAD block using .NET

This post – and its sister post, which will cover creating a group – are further topics I would expect to have already covered in this blog at some point, or perhaps to see covered by the AutoCAD .NET Developer’s Guide (and I’m sure they will be in a future incarnation of it). So thanks to Adam Nagy, from DevTech EMEA, for suggesting these topics. It’s nice to go back to basics once in a while (although this means I do have to beg the patience of the readers out there who know this stuff inside out).

So, here’s some simple C# code that creates a simple block definition (a BlockTableRecord in the BlockTable) and a corresponding block insertion (a BlockReference in the model-space BlockTableRecord).

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

namespace CollectionCreation

{

publicclassCommands

{

[CommandMethod("CB")]

publicvoid CreateBlock()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;

Transaction tr =

db.TransactionManager.StartTransaction();

using (tr)

{

// Get the block table from the drawing

BlockTable bt =

(BlockTable)tr.GetObject(

db.BlockTableId,

OpenMode.ForRead

);

// Check the block name, to see whether it's

// already in use

PromptStringOptions pso =

newPromptStringOptions(

"\nEnter new block name: "

);

pso.AllowSpaces = true;

// A variable for the block's name

string blkName = "";

do

{

PromptResult pr = ed.GetString(pso);

// Just return if the user cancelled

// (will abort the transaction as we drop out of the using

// statement's scope)

if (pr.Status != PromptStatus.OK)

return;

try

{

// Validate the provided symbol table name

SymbolUtilityServices.ValidateSymbolName(

pr.StringResult,

false

);

// Only set the block name if it isn't in use

if (bt.Has(pr.StringResult))

ed.WriteMessage(

"\nA block with this name already exists."

);

else

blkName = pr.StringResult;

}

catch

{

// An exception has been thrown, indicating the

// name is invalid

ed.WriteMessage(

"\nInvalid block name."

);

}

} while (blkName == "");

// Create our new block table record...

BlockTableRecord btr = newBlockTableRecord();

// ... and set its properties

btr.Name = blkName;

// Add the new block to the block table

bt.UpgradeOpen();

ObjectId btrId = bt.Add(btr);

tr.AddNewlyCreatedDBObject(btr, true);

// Add some lines to the block to form a square

// (the entities belong directly to the block)

DBObjectCollection ents = SquareOfLines(5);

foreach (Entity ent in ents)

{

btr.AppendEntity(ent);

tr.AddNewlyCreatedDBObject(ent, true);

}

// Add a block reference to the model space

BlockTableRecord ms =

(BlockTableRecord)tr.GetObject(

bt[BlockTableRecord.ModelSpace],

OpenMode.ForWrite

);

BlockReference br =

newBlockReference(Point3d.Origin, btrId);

ms.AppendEntity(br);

tr.AddNewlyCreatedDBObject(br, true);

// Commit the transaction

tr.Commit();

// Report what we've done

ed.WriteMessage(

"\nCreated block named \"{0}\" containing {1} entities.",

blkName, ents.Count

);

}

}

privateDBObjectCollection SquareOfLines(double size)

{

// A function to generate a set of entities for our block

DBObjectCollection ents = newDBObjectCollection();

Point3d[] pts =

{ newPoint3d(-size, -size, 0),

newPoint3d(size, -size, 0),

newPoint3d(size, size, 0),

newPoint3d(-size, size, 0)

};

int max = pts.GetUpperBound(0);

for (int i = 0; i <= max; i++)

{

int j = (i == max ? 0 : i + 1);

Line ln = newLine(pts[i], pts[j]);

ents.Add(ln);

}

return ents;

}

}

}

Let’s see what happens when we run the CB command to create a block:

Command: CB

Enter new block name: Square

Created block named "Square" containing 4 entities.

That's really all there is to it: after the code has been run you’ll see a block (named “Square”) made up of four lines aligned in a square around the origin.

I might have separated the above code out into functions to create the block definition and the block reference, but my main goal for this post was to show the procedure in a linear fashion. I did use one separate function – as we’ll also use that to create our group in the next post – which creates a collection of objects that will make up our block.