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();
}
}
}
}
}
Solved! Go to Solution.
Solved by cincir. Go to Solution.
Haha i feel your pain with the intellisense, i've slowly been getting used to it but sometimes...just sometimes. I've updated the code but still no luck. When i run the command, it imports my blocks, but i still don't have the custom attributes that i would see when the block is exploded. I'm not sure what's going on here? Is is possible to just explode the block to owner space and then copy it to the appropriate layer?
Thanks again!
something must be missing. i have similar code in one of my software working. are your blocks dynamic? and you know you must set the values of nonconstant attributereferences in order them to be shown. i advise you to double-click one of your blockreferences and see that your attributedefinitions are successfully transported to your blockreference. if so nothing bad just assign values to attributereferences.
Hey Cincir,
What do you mean that i must set the values of nonconstant attributereferences? Right now they import just fine and on the correct layer but i can only view my custom attributes if i explode the blocks. If i use attedit, i'm told that the block has no editable attributes.
Thanks again for all your help, it really is much appreciated.
Have you come across "attsync"? I don't know if you can do it in .net. There is 1 post in this forum with no replies.
After you get the block inserted on the correct layer, try "attsync" manually (command line) to see if it fixes your attributes. It's worth a try IMHO.
Ok so i've figured out what's going on with the help of our design guys here. The original dwg already contains the block, with attributes and all. When i bring it into my new drawing with this code, it creates a block out of this block and loses all it's attributes until it's exploded. When it is exploded, it takes on the layer it was assigned in the original dwg. So what i need to do now is bring in the block from the original dwg as it is and re-assign it's layer. What is the easiest way to do this do you know?
thanks again!
Also, if i explode the original dwg previous to running my import command, it still loses all it's attributes. I'm not sure why?
Your block definition(BlocktableRecord) contain the AttributeDefinition. When you create a BlockReference you need to add a AttributeReference for each AttributeDefinition.
When you explode the reference you are getting all the entites in the BlockDefinition including the AttributeDefinition and it showing the default value. Notice when you explode the entity then double on the AttributeDefinition how the Edit Attribute Definition dialog shows instead of 'Edit Attributes' or 'Enhanced Att ed'
Here are some examples of inserting a Drawing into another drawing then adding the AttributeReferences in F#, C#, & VB
http://www.theswamp.org/index.php?topic=37686.msg427843#msg427843
Hey Guys,
I've been going through the examples posted previously at the Swamp and have come to two problems. The first one is that in the sample code there are references to "CreateLayer", "InsertBlockReference" and "RadiansToDegrees" which don't exist. Are these placeholders for code or are these documented fuctions in the API i can't seem to find?
The other thing is that just by reading through the code, these examples don't seem to sync the attributes from the original blocks but rather provide the option to add new ones (multiple ones)...My existing blocks have attributes with values already and I have hundreds of them that i'd rather not have to redo manually. Hopefully i'm wrong or there's another way to accomplish what i'm trying to do.
Thanks again
Vince
>> The first one is that in the sample code there are references to "CreateLayer", "InsertBlockReference" and "RadiansToDegrees" which don't exist. Are these placeholders for code or are these documented fuctions in the API i can't seem to find? <<
Have a look at Reply #28
http://www.theswamp.org/index.php?topic=37686.msg427833#msg427833
OR
make the .NET forum current
and do a search for the keyword you want
Regards
// Called Kerry in my other life.
Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.
class keyThumper<T> : Lazy<T>; another Swamper
When i try to put the code together from reply 28, i get the errors i posted above. When i try the compiled dll that was attached to the post and run BI_20, i get an eFilerError which halts everything. It's making me crazy that what i'm trying to do should be so simple yet is so annoyingly difficult. I've also gone through the .NET forums with no luck on this. I'll keep tacking at it and post any progress.
Cheers
Vince
Maybe try one thing at a time.
1. Can you manually or through the UI insert a block into a drawing?(I guess you are inserting a drawing as block vs a block from another drawing)
2. Can you code just the part to insert another blockreference with attributes?
Hey Jeff,
1.) I can insert the block with no problems manually by going to "Insert"-->"Block" from the AutoCAD 2012 GUI.
2.) I'm not sure what you mean here....i need it to be able to insert the block reference with the original attributes and then do that "x' times over. I've tried pre-exploding/bursting the original block in the original dwg but to no avail.
Try this:
Private Sub InsertAttibuteInBlockRef(ByVal blkRef As BlockReference, ByVal attributeTag As String, ByVal attributeText As String, ByVal tr As Transaction) Dim btr As BlockTableRecord = DirectCast(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) For Each attId As ObjectId In btr Dim ent As Entity = DirectCast(tr.GetObject(attId, OpenMode.ForRead), Entity) If TypeOf ent Is AttributeDefinition Then Dim attDef As AttributeDefinition = DirectCast(ent, AttributeDefinition) Dim attRef As New AttributeReference() attRef.SetAttributeFromBlock(attDef, blkRef.BlockTransform) If attRef.Tag = attributeTag Then attRef.TextString = attributeText Dim id As ObjectId = blkRef.AttributeCollection.AppendAttribute(attRef) tr.AddNewlyCreatedDBObject(attRef, True) Exit For End If End If Next End Sub
Public Sub BlkInsert(ByVal basePath As String, ByVal blkName As String, ByVal px As Point3d, ByVal theta As Double, ByVal sx As Double, ByVal Layer As String, ByVal side As String, ByVal AttValList As ArrayList, ByVal AttTagList As ArrayList) Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database acCurDb = HostApplicationServices.WorkingDatabase() Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction() Dim acBlkTbl As BlockTable acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) If acBlkTbl.Has(blkName) Then Dim blkObjId = acBlkTbl(blkName) Dim acBlkTblRec As BlockTableRecord acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite) Dim blkRef As BlockReference = New BlockReference(px, blkObjId) blkRef.Rotation = theta blkRef.ScaleFactors = New Scale3d(sx, sx, 1) blkRef.Layer = Layer acBlkTblRec.AppendEntity(blkRef) acTrans.AddNewlyCreatedDBObject(blkRef, True) Dim dPropsCollection As DynamicBlockReferencePropertyCollection dPropsCollection = blkRef.DynamicBlockReferencePropertyCollection For Each dprop As DynamicBlockReferenceProperty In dPropsCollection If dprop.PropertyName = "Visibility1" Then dprop.Value = side End If Next Try Dim i As Integer = 0 For Each tag As String In AttTagList InsertAttibuteInBlockRef(blkRef, tag, AttValList(i).ToString, acTrans) i = i + 1 Next acBlkTblRec.UpdateAnonymousBlocks() blkRef.RecordGraphicsModified(True) Catch ex As Exception MsgBox(ex.Message) End Try Else Dim blkFile As String = basePath + "\\" + blkName + ".dwg" Dim blkObjId As ObjectId Dim dbDwg As New Database(False, True) dbDwg.ReadDwgFile(blkFile, IO.FileShare.Read, True, "") blkObjId = acCurDb.Insert(blkName, dbDwg, True) dbDwg.Dispose() Dim acBlkTblRec As BlockTableRecord acBlkTblRec = acTrans.GetObject(acBlkTbl(BlockTableRecord.ModelSpace), OpenMode.ForWrite) Dim blkRef As BlockReference = New BlockReference(px, blkObjId) blkRef.Rotation = theta blkRef.ScaleFactors = New Scale3d(sx, sx, 1) blkRef.Layer = Layer acBlkTblRec.AppendEntity(blkRef) acTrans.AddNewlyCreatedDBObject(blkRef, True) Dim dPropsCollection As DynamicBlockReferencePropertyCollection dPropsCollection = blkRef.DynamicBlockReferencePropertyCollection For Each dprop As DynamicBlockReferenceProperty In dPropsCollection If dprop.PropertyName = "Visibility1" Then dprop.Value = side End If Next Dim i As Integer = 0 For Each tag As String In AttTagList InsertAttibuteInBlockRef(blkRef, tag, AttValList(i).ToString, acTrans) i = i + 1 Next acBlkTblRec.UpdateAnonymousBlocks() blkRef.RecordGraphicsModified(True) End If acTrans.Commit() End Using End Sub
<CommandMethod("MBLKTEST")> _ Public Sub Blktest() Dim TagList As New ArrayList Dim ValList As New ArrayList Dim side As String = "Top" TagList.Add("TAG1") TagList.Add("TAG2") ValList.Add("VAL1") ValList.Add("VAL2") Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim acCurDb As Database = acDoc.Database Dim pr As PromptPointResult = ed.GetPoint("Pick a point:") If pr.Status = PromptStatus.OK Then Dim i As Integer = 0 Dim n As Integer = 10 Dim basePath As String = "C:\\MyBasePath" Dim px As Point3d = pr.Value For i = 0 To n AlInsert(basePath, "MyBlockName", px, 0, 1, "0", side, ValList, TagList) px = Polar(px, 3500, 0) Next End If End Sub
Private Function Polar(ByVal bpoint As Point3d, ByVal r As Double, ByVal theta As Double) As Point3d Dim px As New Point3d(bpoint.X + r * Math.Cos(theta), bpoint.Y + r * Math.Sin(theta), bpoint.Z) Return px End Function
You will need a dynamic block with 2 visibility states (the "side" parameter) and 2 attributes , or you can just get rid off that part of the code, and use a simple block with attributes.
Gaston Nunez
Thanks gasty1001,
I actually got it running with help from jeff, sorry for the delayed response. Thanks for the help though!
Can't find what you're looking for? Ask the community or share your knowledge.