.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with inserting an external DWG as a block

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
Anonymous
730 Views, 16 Replies

Problem with inserting an external DWG as a block

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

16 REPLIES 16
Message 2 of 17
SENL1362
in reply to: Anonymous

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.

Message 3 of 17
SENL1362
in reply to: SENL1362

After these steps start a third transaction inserting the Block in Modelspace:

BlockReference blockRef =
new BlockReference(point, block.ObjectId);

ms.AppendEntity(blockRef);
thirdTr.AddNewlyCreatedDBObject(blockRef, true);
Message 4 of 17
Anonymous
in reply to: SENL1362

For the record, I don't know why I have two accounts on this site. Anyway, this is the one I wanted to use to post the question (sorry lol)

Thanks for the tip, I'm not sure what I was thinking ... I'm quite new to this. I committed the transaction after the dbInsert and ended the using statement, but nothing changes.
Message 5 of 17
Anonymous
in reply to: SENL1362

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.

Message 6 of 17
Anonymous
in reply to: SENL1362

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...

Message 7 of 17
SENL1362
in reply to: Anonymous

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. 🙂

 

 

Message 8 of 17
Anonymous
in reply to: SENL1362

Okay so I should insert the block using the name of it to retrieve the ID of the newly added block.

What do I do with the btrId afterwards though? And why isn't it inserted at 0,0,0?
Message 9 of 17
SENL1362
in reply to: Anonymous

Compare it with you're manual operation: Insert an external drawing.
In the first step the external drawing (blocks) will be added to the blocktable;
In the second step that block will be placed in the current space.

In you're VB code the first step is db.Insert, it's ADDING the Blocks to the BlockTable of the current drawing(db).
the second step is to insert in the (current) space (btr).

You can use the return btrId from db.insert to create the BlockReference(...)

Message 10 of 17
Anonymous
in reply to: SENL1362

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?

Message 11 of 17
SENL1362
in reply to: SENL1362

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

 

Message 12 of 17
SENL1362
in reply to: SENL1362

try to translate these two steps first.
Then we can have a look at your attribute problem.
Message 13 of 17
Anonymous
in reply to: SENL1362

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.

Message 14 of 17
SENL1362
in reply to: Anonymous

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

 

Message 15 of 17
Anonymous
in reply to: SENL1362

Wow. Excellent. Works!!!!!!

Thank you very much, you have helped me an insane amount.

Bonus question (lol): Is there a way to center the view pane for the user so that he doesn't need to double click his middle mouse button to zoom into the content of the layout? 😛

Thanks again!!!
Message 16 of 17
SENL1362
in reply to: Anonymous

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

 

 

Message 17 of 17
SENL1362
in reply to: SENL1362

 

 

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

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost