.NET

Reply
Distinguished Contributor
vince1327
Posts: 117
Registered: ‎11-02-2011
Message 1 of 36 (1,561 Views)
Accepted Solution

Repeatedly Insert Block

1561 Views, 35 Replies
01-17-2012 06:06 AM

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.DocumentManager.MdiActiveDocument;
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, FindFileHint.Default);

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, OpenMode.ForRead, true);

BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);


//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();
}

 


}

}
}

}

 

 

 

[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],OpenMode.ForRead);

 

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,OpenMode.ForWrite) as BlockTableRecord;

 

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.

Distinguished Contributor
VB_Autocad_guy
Posts: 136
Registered: ‎07-24-2009
Message 2 of 36 (1,550 Views)

Re: Repeatedly Insert Block

01-17-2012 08:11 AM in reply to: vince1327

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.TransactionManager.StartT()
                ransaction()
                ' Open ModelSpace BlockTableRecord ready to add entity
                DB = Application.DocumentManager.MdiActiveDocument.Database
                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

 





Distinguished Contributor
vince1327
Posts: 117
Registered: ‎11-02-2011
Message 3 of 36 (1,545 Views)

Re: Repeatedly Insert Block

01-17-2012 08:35 AM in reply to: VB_Autocad_guy

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!

Active Contributor
cincir
Posts: 32
Registered: ‎08-12-2011
Message 4 of 36 (1,520 Views)

Re: Repeatedly Insert Block

01-19-2012 12:29 PM in reply to: vince1327

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.

Distinguished Contributor
vince1327
Posts: 117
Registered: ‎11-02-2011
Message 5 of 36 (1,515 Views)

Re: Repeatedly Insert Block

01-19-2012 12:58 PM in reply to: cincir

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

 

Active Contributor
cincir
Posts: 32
Registered: ‎08-12-2011
Message 6 of 36 (1,512 Views)

Re: Repeatedly Insert Block

01-19-2012 01:41 PM in reply to: vince1327

[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],OpenMode.ForRead);

 

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,OpenMode.ForWrite) as BlockTableRecord;

 

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.

Distinguished Contributor
VB_Autocad_guy
Posts: 136
Registered: ‎07-24-2009
Message 7 of 36 (1,498 Views)

Re: Repeatedly Insert Block

01-20-2012 07:28 AM in reply to: cincir

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. 

 

Distinguished Contributor
vince1327
Posts: 117
Registered: ‎11-02-2011
Message 8 of 36 (1,469 Views)

Re: Repeatedly Insert Block

01-23-2012 12:05 PM in reply to: vince1327

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.DocumentManager.MdiActiveDocument;
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.StringResult], OpenMode.ForRead);


//ObjectId acBlockId = (BlockTableRecord)acTrans.GetObject(btr[acPR.StringResult], OpenMode.ForWrite);
//ObjectId acBlockId = acTrans.GetObject(acBlkTbl[acPR.StringResult],OpenMode.ForRead);

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.BlockTableId, OpenMode.ForRead, true);
BlockTableRecord acBlkTblRec = (BlockTableRecord)acTrans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

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();
}
}
}
}

}

Distinguished Contributor
VB_Autocad_guy
Posts: 136
Registered: ‎07-24-2009
Message 9 of 36 (1,453 Views)

Re: Repeatedly Insert Block

01-23-2012 01:17 PM in reply to: vince1327

Hmm.... 

ObjectId acBlockId = (BlockTable)acTrans.GetObject(acBlkTbl[acPR.StringResult], OpenMode.ForRead);

 

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 :smileyhappy:

 

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(OpenMode.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.CurrentUserCoordinateSystem);

                            // 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();
                }
            }
        }
    }
}

 

Active Contributor
cincir
Posts: 32
Registered: ‎08-12-2011
Message 10 of 36 (1,444 Views)

Re: Repeatedly Insert Block

01-23-2012 03:35 PM in reply to: VB_Autocad_guy

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. 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!