.NET
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page
Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Hey everyone,
So i've been able to successfully import a single block at a time into an active drawing, now i'm trying to insert the same block multiple times to essentially create a layout within the drawing. How would i go about inserting a selected block "x" amount of times. For a better idea of where i'm stuck, i've commented a bit of code below with a better explanation. What i've got so far is this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DataExtraction;
using Autodesk.AutoCAD.Colors;
using DB_Extraction;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace CHTEST
{
public class CHTEST1
{
// This is the name of my command
[Autodesk.AutoCAD.Runtime.CommandMethod("CHTEST")]
public void CHTEST1()
{
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.D
Database db = doc.Database;
Editor ed = doc.Editor;
Point3d pMax = new Point3d();
string comp = "C:\\ACADSTUFF\\test.dwg";
// int numsprink = 5;
Transaction tr = doc.TransactionManager.StartTransaction();
using (DocumentLock acLckDoc = doc.LockDocument())
try
{
//Check to see if the layer CH-TST already exists, if so use it, if not create it and then use it
string sLayerName1 = "CH-TST";
LayerTable acLyrTbl1; acLyrTbl1 = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
LayerTableRecord acLyrTblRec;
if (acLyrTbl1.Has(sLayerName1) == false)
{
acLyrTblRec = new LayerTableRecord();
// Assign the layer a name
acLyrTblRec.Name = sLayerName1;
// Upgrade the Layer table for write
if (acLyrTbl1.IsWriteEnabled == false) acLyrTbl1.UpgradeOpen();
// Append the new layer to the Layer table and the transaction
acLyrTbl1.Add(acLyrTblRec);
tr.AddNewlyCreatedDBObject(acLyrTblRec, true);
}
else
{
// Open the layer if it already exists for write
acLyrTblRec = tr.GetObject(acLyrTbl1[sLayerName1], OpenMode.ForWrite) as LayerTableRecord;
}
//This partwill import the selected dwg into modelspace and activate it
string dwgName = HostApplicationServices.Current.FindFile(comp, acadApp.DocumentManager.MdiActiveDocument.Database
Database db1 = new Database(false, false);
db1.ReadDwgFile(dwgName, System.IO.FileShare.Read, true, "");
ObjectId BlkId;
BlkId = doc.Database.Insert(dwgName, db1, false);
BlockTable bt = (BlockTable)tr.GetObject(doc.Database.BlockTableId
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord
//ideally this next section will iterate the import process "x" amount of times and allow for effetive block placement!
// Below is part of some code that i had used to copy a paperspace layout "x" amount of times. I understand the iteration part but am not sure how to apply it to a block. I don't know how to reference the block that i intend to insert and then have it populate "x" amount of times.
/*
for (int i = 1; i <= numLayouts; i++)
{
lm.CopyLayout("Layout1", "SP-" + i.ToString());
Layout layout = (Layout)trx.GetObject(lm.GetLayoutId("SP-" + i.ToString()), OpenMode.ForWrite);
}
*/
//FACSPR7
BlockReference bref = new BlockReference(pMax, BlkId);
bref.Layer = "CH-TST";
btr.AppendEntity(bref);
tr.AddNewlyCreatedDBObject(bref, true);
bref.ExplodeToOwnerSpace();
bref.Erase();
tr.Commit();
}
catch
{
MessageBox.Show("Failed to read the DWG from the refence folder, are you sure it is present?");
}
finally
{
tr.Dispose();
}
}
}
}
}
Solved! Go to Solution.
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Can you clarify a bit? I'll give it a try. But maybe I'm missing your point.
You could just use the same command basically block insert several times and them DB commit when you're done.
Or just create several instances of a blockreference. Or you can use the copy object command.
Instead of Insert MText entity like in the code below insert a BlockReference Entity
( Dim myBRef As BlockReference)
I got this code from:
AutoCAD® .NET Basics, Part I
Stephen Preston – Autodesk Inc
Hope you don't mind I'm using VB.NET
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Public Class Class1
<CommandMethod("HelloWorld")> _
Public Sub MyMethod()
' Some variable definitions
Dim DB As Database
Dim BT As BlockTable
Dim MS As BlockTableRecord
' Start a transaction to edit the DWG database
Using trans As Transaction = Application.DocumentManager.MdiActiveDocument.Tran sactionManager.StartT()
ransaction()
' Open ModelSpace BlockTableRecord ready to add entity
DB = Application.DocumentManager.MdiActiveDocument.Data base
BT = trans.GetObject(DB.BlockTableId, OpenMode.ForRead)
MS = trans.GetObject(BT(BlockTableRecord.ModelSpace), OpenMode.ForWrite)
' Create a new MText entity and set its text
Dim txt As MText = New MText
txt.Contents = "Hello World from VB.NET"
' Add the MText to ModelSpace
MS.AppendEntity(txt)
' Add the Mtext to the transaction
trans.AddNewlyCreatedDBObject(txt, True)
' Commit transaction so changes persist in the DWG
trans.Commit()
End Using
End Sub
End Class
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
For clarification, i can already insert a block, i essentially need to have an argument for my command in which i can specify a positive integer. So if i select the block i want to insert, it will ask me how for how many i would like to insert. I've got pretty much everything downpact except how to insert a block "x" amount of times over. I was thinking of two possible ways. 1.) This would involve just running the command i've posted "x" amount of times, but i'm unsure of the syntax or where to begin. 2.) Copy the block i've chosen to insert "x" amount of times -1. However, i'm still unsure of the syntax or where to begin. From a logic point of view i understand what i have to do, i've got a good amount of experience programming in a variety of languages however this AutoCAD API never ceases to confuse me. What you've posted below makes sense, but im looking more for a way to achieve what you've posted "x" amount of times.
Thanks!
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
vince1327 can you tell me ; do you want to insert a block definition x number of times or do you want to create a blockreference of a block definition you have x number of times. maybe i got you wrong but just to be clear :
- do we aggree that a block definition is a blocktablerecord in blocktable symbol table that has entities in it?
- do we aggree that a blockreference is a like an entity that references a blocktablerecord.
i mean the block definition is the blueprint while the blockreference is the actual objects in the drawing.
as i said before maybe i got you wrong (if so please discard this post) but you want to insert objects to the drawing. so instead of inserting blocktablerecord s xnumber of times try to insert blockreferences of that blocktablerecord x number of times.
if that is what you mean please confirm for code example.
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Hi Cincir,
I'm new to AutoCAD overall and i've just spoken with one of our designers who has indeed confirmed what you've said. I'm looking to insert blockreferences of my block "x" number of times. The AutoCAD API is tricky to learn and is sometimes a bit confusing so i appreciate your time trying to help me find what i'm looking for. If you have an example of how to do this, it would be amazing!
Thanks
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
[CommandMethod("CreateBlockReference")]
public void CreateBlockReference()
{
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Editor acEd = acDoc.Editor;
PromptStringOptions acPSO = new PromptStringOptions("Enter the name of block you want to insert:");
PromptResult acPR = acEd.GetString(acPSO);
if (acPR.Status == PromptStatus.OK)
{
using (Transaction acTrans = acDoc.TransactionManager.StartTransaction())
{
BlockTable acBlkTbl = acTrans.GetObject(acDoc.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
if (acBlkTbl.Has(acPR.StringResult) == true) // Our BlockTable has block definition that we enter
{
ObjectId acBlockId = acTrans.GetObject(acBlkTbl[acPR.StringResult],Open
PromptIntegerOptions acPIO = new PromptInterOptions("Enter the number of times block will be inserted:");
acPIO.AllowNegative = false;
acPIO.AllowZero = false;
PromptIntegerResult acPIR = acEd.GetInteger(acPIO);
if (acPIR.Status == PromptStatus.OK)
{
BlockTableRecord acBlkTblRec = acTrans.GetObject(BlockTableRecord.ModelSpace,Open
Point3d pCenter = new Point3d(0,0,0);
Vector3d vOffset = new Vector3d(10,0,0);
for (int i = 0;i < acPIR.Value ; i++)
{
BlockReference acBR = new BlockReference(pCenter , acBlockId);
acBlkTblRec.AppendEntity(acBR);
acTrans.AddNewlyCreatedObject(acBR,true);
pCenter += vOffset;
}
}
}
acTrans.Commit();
}
}
}
i just wrote it i mean didnt copy-paste so may have syntax errors. feel free to ask questions for this or other stuff.
good luck.
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Like Cincir said:
For each Block Reference use
.AppendEntity
.AddNewlyCreatedObject
Those are your guys.
It's sure good to hear I'm not the only one who thinks the Autocad API is confusing.
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Thanks for the help so far! I'm just stuck on one line below. I get this error in VS 2010 "
Error 1 Cannot implicitly convert type 'Autodesk.AutoCAD.DatabaseServices.BlockTable' to 'Autodesk.AutoCAD.DatabaseServices.ObjectId'" How do i re-arrange this to work?
Thanks
namespace TEST
{
public class TEST
{
// This is the name of my command
[Autodesk.AutoCAD.Runtime.CommandMethod("CHTEST")]
public void TEST()
{
Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.D
Editor acEd = acDoc.Editor;
string comp = "C:\\ACADSTUFF\\test.dwg";
PromptStringOptions acPSO = new PromptStringOptions("Enter the name of block you want to insert:");
PromptResult acPR = acEd.GetString(acPSO);
if (acPR.Status == PromptStatus.OK)
{
using (Transaction acTrans = acDoc.TransactionManager.StartTransaction())
{
BlockTable acBlkTbl = acTrans.GetObject(acDoc.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
if (acBlkTbl.Has(acPR.StringResult) == true) // Our BlockTable has block definition that we enter
{
ObjectId acBlockId = (BlockTable)acTrans.GetObject(acBlkTbl[acPR.String
//ObjectId acBlockId = (BlockTableRecord)acTrans.GetObject(btr[acPR.Strin
//ObjectId acBlockId = acTrans.GetObject(acBlkTbl[acPR.StringResult],Open
PromptIntegerOptions acPIO = new PromptIntegerOptions("Enter the number of times block will be inserted:");
acPIO.AllowNegative = false;
acPIO.AllowZero = false;
PromptIntegerResult acPIR = acEd.GetInteger(acPIO);
if (acPIR.Status == PromptStatus.OK)
{
BlockTable bt = (BlockTable)acTrans.GetObject(acDoc.Database.Block
BlockTableRecord acBlkTblRec = (BlockTableRecord)acTrans.GetObject(bt[BlockTableR
Point3d pCenter = new Point3d(0, 0, 0);
Vector3d vOffset = new Vector3d(10, 0, 0);
for (int i = 0; i < acPIR.Value; i++)
{
BlockReference acBR = new BlockReference(pCenter, acBlockId);
acBlkTblRec.AppendEntity(acBR);
acTrans.AddNewlyCreatedDBObject(acBR, true);
pCenter += vOffset;
}
}
}
acTrans.Commit();
}
}
}
}
}
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
Hmm....
ObjectId acBlockId = (BlockTable)acTrans.GetObject(acBlkTbl[acPR.String
Why don't you skip that last line of code?
Just use: BlockReference acBR = new BlockReference(pCenter, myBlockTable(BlockName));
That way you don't have to worry about the object conflict your coming across.
And as long as a block with that name exists your fine.
Okay so maybe this doesn't help at all. But I figure at least try to excercise my programming brain muscle to make it stronger ![]()
Good Luck!
Maybe this will help:
Public Function ModelSpaceInsertBlock(ByVal InsPt As Geometry.Point3d, _ ByVal BlockName As String, ByVal XScale As Double, _ ByVal YScale As Double, ByVal ZScale As Double) As DatabaseServices.ObjectId Dim myBlkID As ObjectId = ObjectId.Null Try Dim myDwg As Document = Application.DocumentManager.MdiActiveDocument Using myTrans As Transaction = myDwg.TransactionManager.StartTransaction 'Open the database for Write Dim myBT As BlockTable = myDwg.Database.BlockTableId.GetObject(OpenMode.ForRead) Dim myModelSpace As BlockTableRecord = myBT(BlockTableRecord.ModelSpace).GetObject(OpenMo de.ForWrite) 'Insert the Block Dim myBlockDef As BlockTableRecord = myBT(BlockName).GetObject(OpenMode.ForRead) Dim myBlockRef As New DatabaseServices.BlockReference(InsPt, myBT(BlockName)) myBlockRef.ScaleFactors = New Geometry.Scale3d(XScale, YScale, ZScale) myModelSpace.AppendEntity(myBlockRef) myTrans.AddNewlyCreatedDBObject(myBlockRef, True) myBlkID = myBlockRef.ObjectId 'Append Attribute References to the BlockReference Dim myAttColl As DatabaseServices.AttributeCollection Dim myEntID As ObjectId Dim myEnt As DatabaseServices.Entity myAttColl = myBlockRef.AttributeCollection For Each myEntID In myBlockDef myEnt = myEntID.GetObject(OpenMode.ForWrite) If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then Dim myAttDef As DatabaseServices.AttributeDefinition = CType(myEnt, AttributeDefinition) Dim myAttRef As New DatabaseServices.AttributeReference myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform) myAttColl.AppendAttribute(myAttRef) myTrans.AddNewlyCreatedDBObject(myAttRef, True) End If Next 'Commit the Transaction myTrans.Commit() End Using Catch ex As Exception myBlkID = ObjectId.Null End Try Return myBlkID End Function
I also found this snippet in C#
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace BlockInsertion
{
public class Class1
{
[CommandMethod("Test")]
public void Test()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Get the block name
PromptStringOptions pso = new PromptStringOptions("\nEnter block name: ");
PromptResult pr = ed.GetString(pso);
if (pr.Status == PromptStatus.OK)
{
// Start a transaction
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// Test if block exists in the block table
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
if (!bt.Has(pr.StringResult))
{
ed.WriteMessage("\nBlock not found.");
}
else
{
ObjectId id = bt[pr.StringResult];
// Get insertion point
PromptPointOptions ppo = new PromptPointOptions("\nSpecify insertion point: ");
PromptPointResult ppr = ed.GetPoint(ppo);
if (ppr.Status == PromptStatus.OK)
{
Point3d pt = ppr.Value.TransformBy(ed.CurrentUserCoordinateSyst em);
// Create a block reference
BlockReference br = new BlockReference(pt, id);
// Get Model space
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord .ModelSpace], OpenMode.ForWrite);
// Add the block reference to Model space
btr.AppendEntity(br);
tr.AddNewlyCreatedDBObject(br, true);
}
}
// Commit the transaction
tr.Commit();
}
}
}
}
}
Re: Repeatedly Insert Block
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
ObjectId acBlockId = acTrans.GetObject(acBlkTbl[acPR.StringResult],OpenMode.ForRead);
change this line to
ObjectId acBlockId = acBlkTbl[acPR.StringResult];
as i said before i just typed it not copy - paste.



