I am inserting a block with attributes in my drawing. Basically this enables the user to begin with the correct layout template that the company uses.
When the following code finishes executing, I can visually see that the block has been inserted.
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim ed As Editor = acDoc.Editor Dim db As Database = acDoc.Database Dim bt As BlockTable Dim btr As BlockTableRecord Dim blockref As BlockReference Dim att As AttributeReference Dim templateName As String = "BLOCKNT_LE" 'User saved Using tr As Transaction = db.TransactionManager.StartTransaction() bt = TryCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) btr = TryCast(tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite), BlockTableRecord) 'Insert template Using newdb As New Database(False, True) newdb.ReadDwgFile(clsProgramVariable.GetValue("LayoutNumberGenerator", templateName), FileOpenMode.OpenForReadAndAllShare, True, "") db.Insert(Matrix3d.Displacement(New Vector3d(0, 0, 0)), newdb, True) End Using 'List all block table record names Dim tmpstr As String = "" For Each id As ObjectId In bt btr = DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockTableRecord) If Not btr.IsLayout Then tmpstr = vbNewLine & btr.Name ed.WriteMessage(tmpstr) End If Next tr.Commit() End Using
The only issue is, I cannot find the BLOCKNT_LE when I list the block table record names... I need to find the BLOCKNT_LE because it has attributes and I need to change some values in there. Why is this? Do I need to save before? Do I need to do some sort of regen?
Also, this is a side question, but I can't seem to figure out how to center the user's view at (0,0,0) which is where the block is inserted.
Thanks,
Alex
Solved! Go to Solution.
Solved by SENL1362. Go to Solution.
Solved by SENL1362. Go to Solution.
You insert the dwg into the Database (db.insert(..))
What makes you think that it is inserted into Modelspace?
Hint: commit and end the Transaction after db.insert.
Then start a new Transaction in which you list the BlockTables.
I still cannot display the block "BLOCKNT_LE" that I tried to insert, yet it appears in the drawing.
Here's the modified code after your tips:
Public Sub AddLayout() Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument Dim ed As Editor = acDoc.Editor Dim db As Database = acDoc.Database Dim bt As BlockTable Dim btr As BlockTableRecord Dim templateName As String = "BLOCKNT_LE" 'User saved Using tr As Transaction = db.TransactionManager.StartTransaction() Using newdb As New Database(False, True) newdb.ReadDwgFile(clsProgramVariable.GetValue("LayoutNumberGenerator", templateName), FileOpenMode.OpenForReadAndAllShare, True, "") db.Insert(Matrix3d.Displacement(New Vector3d(0, 0, 0)), newdb, True) End Using tr.Commit() End Using Using tr As Transaction = db.TransactionManager.StartTransaction() 'Go through the block table records in the block table to verify if the template is in the drawing Dim tmpstr As String = "" bt = TryCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
For Each id As ObjectId In bt btr = DirectCast(tr.GetObject(id, OpenMode.ForRead), BlockTableRecord) If Not btr.IsLayout Then tmpstr = vbNewLine & btr.Name ed.WriteMessage(tmpstr) End If Next tr.Commit() End Using End Sub
I need to start a third transaction to append my blockRef? What if I can't find my block (BLOCKNT_LE) beforehand? I must be doing something wrong in the code block above.
Thanks for the help, I appreciate it.
I tried something else after some research.
I changed these lines:
Using newdb As New Database(False, True)
newdb.ReadDwgFile("C:\BLOCKNT_LE.DWG", FileOpenMode.OpenForReadAndAllShare, False, "")
db.Insert(Matrix3d.Displacement(New Vector3d(0, 0, 0)), newdb, True)
End Using
To this:
Using newdb As New Database(False, True) newdb.ReadDwgFile("C:\BLOCKNT_LE.DWG", FileOpenMode.OpenForReadAndAllShare, False, "") db.Insert(templateName, newdb, True) End Using
What's odd is, the first portion of code will insert the external DWG at position 0,0,0 but not contain the BLOCKNT_LE block. While the second portion of code will not insert (atleast not visually at 0,0,0) the external DWG but it will contain the BLOCKNT_LE block.
I'm confused...
the second way is youre way 🙂
btrId = db.Insert(asBlkName, dbToInsert, true);
The "asBlkName" will be the name of the new Block( may issue duplicated block messages),
and "btrId" is the new BlockId.
then to insert this block in (Ms, Ps or any other Block):
blkRef = new BlockReference(insPnt, btrId);
btr.UpgradeOpen();
btr.AppendEntity(blkRef);
tr.AddNewlyCreatedDBObject(blkRef, true);
regarding the "I'm confused..."
not much i can do about this nor should we do something about that.
It makes this "work" worthwhile. 🙂
Okay I see. I think we're getting closer. Take a look at my new code:
<CommandMethod("LayoutCreator-Add")> _
Public Sub AddLayout()
Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
Dim ed As Editor = acDoc.Editor
Dim db As Database = acDoc.Database
Dim bt As BlockTable
Dim btr As BlockTableRecord
Dim btrId As ObjectId
Dim blkRef As BlockReference
Dim templateName As String = "BLOCKNT_LE"
'User saved
Using tr As Transaction = db.TransactionManager.StartTransaction()
Using newdb As New Database(False, True)
newdb.ReadDwgFile("C:\BLOCKNT_LE.DWG", FileOpenMode.OpenForReadAndAllShare, False, "")
btrId = db.Insert(templateName, newdb, True)
End Using
tr.Commit()
End Using
Using tr As Transaction = db.TransactionManager.StartTransaction()
'Go through the block table records in the block table to verify if the template is in the drawing
bt = TryCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
For Each id As ObjectId In bt
btr = DirectCast(tr.GetObject(id, OpenMode.ForWrite), BlockTableRecord) 'Prepare to WRITE in btr
If Not btr.IsLayout And btr.Name = templateName Then
blkRef = New BlockReference(New Point3d(0, 0, 0), btrId)
btr.UpgradeOpen()
btr.AppendEntity(blkRef)
tr.AddNewlyCreatedDBObject(blkRef, True)
Exit For
End If
Next
tr.Commit()
End Using
ed.Regen()
End Sub
It's weird though, it finds the block but it doesn't show up ... When I insert it with the other db.Insert(Matrix.Displacement..., newdb, true) I actually see it show up physically but I can't find the block BLOCKNT_LE.
I'm missing the model space portion? How do I know that my btr is appending in the model space? Perhaps that's where I'm going wrong?
[CommandMethod("InsertDwg")] static public void InsertDwg() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; LayoutManager layoutManager = LayoutManager.Current; string templatePathname = @"c:\temp\template.dwg"; string templateBlockName = Path.GetFileNameWithoutExtension(templatePathname); string layoutName = "Layout1"; //Step I: get or insert+get TemplateBlock ObjectId templateBlkId = ObjectId.Null; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); if (bt.Has(templateBlockName)) templateBlkId = bt[templateBlockName]; else { if (!File.Exists(templatePathname)) throw new System.Exception(string.Format("Error: File not found: {0}", templatePathname)); using (Database templDb = new Database(false, true)) { templDb.ReadDwgFile(templatePathname, FileShare.Read, true, null); templDb.CloseInput(true); templateBlkId = db.Insert(templateBlockName, templDb, true); } } tr.Commit(); } //Step II: Insert into Layout (or Modelspace or ..) using (Transaction tr = db.TransactionManager.StartTransaction()) { ObjectId layoutId = layoutManager.GetLayoutId(layoutName); Layout layout = (Layout)tr.GetObject(layoutId, OpenMode.ForRead); BlockTableRecord layoutBtr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead); //or: BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); //or: BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead); BlockReference templRef = new BlockReference(new Point3d(0, 0, 0), templateBlkId); layoutBtr.UpgradeOpen(); layoutBtr.AppendEntity(templRef); //or ms.UpgradeOpen(); //or ms.AppendEntity(templRef); tr.AddNewlyCreatedDBObject(templRef, true); tr.Commit(); } }
Awesome. I got it to work using your code. I had to use the model space trick instead of the layout block table record.
It works! I used one transaction to insert the drawing, the other one to append it to the block table record and to add the block reference to the transaction.
Now I guess I'll need a third transaction to create my attributes? When I continue and try to verify the blkRef's attribute collection, it has a count of 0. I thought it would've already contained them since we inserted the block.
Ok, glad to hear it worked.
Now w'll add the attributes, witin step 2, her it is
//Step II: Insert into Layout (or Modelspace or ..)
using (Transaction tr = db.TransactionManager.StartTransaction())
{
ObjectId layoutId = layoutManager.GetLayoutId(layoutName);
Layout layout = (Layout)tr.GetObject(layoutId, OpenMode.ForRead);
BlockTableRecord layoutBtr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead);
//or: BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
//or: BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
BlockReference templRef = new BlockReference(new Point3d(0, 0, 0), templateBlkId);
layoutBtr.UpgradeOpen();
layoutBtr.AppendEntity(templRef);
//or ms.UpgradeOpen();
//or ms.AppendEntity(templRef);
tr.AddNewlyCreatedDBObject(templRef, true);
BlockTableRecord templDef = (BlockTableRecord)tr.GetObject(templateBlkId, OpenMode.ForRead);
//Copy BlockDef AttributeDefinitions to BlockRef AttributeReferences
foreach (ObjectId id in templDef)
{
DBObject templObj = (DBObject)tr.GetObject(id, OpenMode.ForRead);
AttributeDefinition attDef = templObj as AttributeDefinition;
if ((attDef != null) && (!attDef.Constant))
{
using (AttributeReference attRef = new AttributeReference())
{
attRef.SetAttributeFromBlock(attDef, templRef.BlockTransform);
attRef.TextString = "Default Attribute Value";
templRef.AttributeCollection.AppendAttribute(attRef);
tr.AddNewlyCreatedDBObject(attRef, true);
}
}
}
tr.Commit();
}
Some code retrieved from the internet with some modified
public static void ZoomObjects(Document doc, ObjectId[] idCol) { Database db = doc.Database; Editor ed = doc.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { using (ViewTableRecord view = ed.GetCurrentView()) { Matrix3d WCS2DCS = Matrix3d.PlaneToWorld(view.ViewDirection); WCS2DCS = Matrix3d.Displacement(view.Target - Point3d.Origin) * WCS2DCS; WCS2DCS = Matrix3d.Rotation(-view.ViewTwist, view.ViewDirection, view.Target) * WCS2DCS; WCS2DCS = WCS2DCS.Inverse(); Entity ent = (Entity)tr.GetObject(idCol[0], OpenMode.ForRead); Extents3d ext = new Extents3d(); try { ext.AddExtents(ent.GeometricExtents); } catch { if (ent.ObjectId.ObjectClass.DxfName == "INSERT") { BlockReference blkRef = (BlockReference)ent; ext = AcadExtentsTools.GetBlockRefExtentsByNestedEntities(blkRef); } } for (int i = 1; i < idCol.Length; i++) { ent = (Entity)tr.GetObject(idCol[i], OpenMode.ForRead); try { Extents3d tmp = ent.GeometricExtents; ext.AddExtents(tmp); } catch { } } ext.TransformBy(WCS2DCS); view.Width = ext.MaxPoint.X - ext.MinPoint.X; view.Height = ext.MaxPoint.Y - ext.MinPoint.Y; view.CenterPoint = new Point2d((ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0); ed.SetCurrentView(view); } tr.Commit(); } }
public static Extents3d GetBlockRefExtentsByNestedEntities(BlockReference blkRef) { Extents3d blkExtents = new Extents3d(); using (Transaction tr = blkRef.Database.TransactionManager.StartTransaction()) { DBObjectCollection oc = new DBObjectCollection(); blkRef.Explode(oc); if (oc.Count > 0) { foreach (DBObject obj in oc) { Entity ent2 = obj as Entity; if (ent2 != null && ent2.Visible) { if (ent2.Bounds.HasValue) { Extents3d x = ent2.GeometricExtents; blkExtents.AddExtents(x); } } obj.Dispose(); } } tr.Commit(); } return blkExtents; }