Author Topic: Retrieving object IDs from blocks in the drawing  (Read 4955 times)

0 Members and 1 Guest are viewing this topic.

cannorth

  • Guest
Retrieving object IDs from blocks in the drawing
« on: August 03, 2012, 03:13:27 PM »
Hello,

  I have a drawing where I just inserted blocks, but when I use code to retrieve the block ID's, it shows nothing.  This is my code:

        trans = doc.Database.TransactionManager.StartTransaction()

        bt = trans.GetObject(doc.Database.BlockTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)

        For Each cur_block In block_list
            With trans

                'open blockTableRecord

                Dim btr As Autodesk.AutoCAD.DatabaseServices.BlockTableRecord
                Dim logo_id As ObjectId

                    btr = trans.GetObject(bt(BlockTableRecord.ModelSpace), Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite)


                'append blockRef to blockTableRecord

                For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False)

  When it does the for each loop, there are no IDs.  How can I get IDs?

Thanks,

cannorth

BlackBox

  • King Gator
  • Posts: 3770
Re: Retrieving object IDs from blocks in the drawing
« Reply #1 on: August 03, 2012, 05:41:21 PM »
First, you might consider putting the code within the applicable [CODE ] Tags, so it's easier for others to read your post.  ;-)

Second... I'm no .NET expert, so I may be mistaken... You'd need to Commit() the Transaction for those to be available, no?  :?
"How we think determines what we do, and what we do determines what we get."

cannorth

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #2 on: August 03, 2012, 05:56:52 PM »
Code: [Select]
trans = doc.Database.TransactionManager.StartTransaction()

        bt = trans.GetObject(doc.Database.BlockTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)

        For Each cur_block In block_list
            With trans

                'open blockTableRecord

                Dim btr As Autodesk.AutoCAD.DatabaseServices.BlockTableRecord
                Dim logo_id As ObjectId

                    btr = trans.GetObject(bt(BlockTableRecord.ModelSpace), Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite)


                'append blockRef to blockTableRecord

                For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False

  I do use a commit statement at the end of my code.  This is a snippet before.

cannorth

TheMaster

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #3 on: August 04, 2012, 12:18:32 AM »
The code you posted doesn't do anything because it is trying to get all
insertions of the model space block. There are no insertions of the
model space block.

I think it's clear that you've not gone through all the training materials
available to you, because you are using the wrong APIs and with the
wrong objects to achieve something.

You can get all insertions (BlockReferences) of a block by calling
GetBlockReferenceIds() on the BlockTableRecord that represents
the block you want the insertions of. You get the latter from the
BlockTable, using the block's name.

Code: [Select]
trans = doc.Database.TransactionManager.StartTransaction()

        bt = trans.GetObject(doc.Database.BlockTableId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)

        For Each cur_block In block_list
            With trans

                'open blockTableRecord

                Dim btr As Autodesk.AutoCAD.DatabaseServices.BlockTableRecord
                Dim logo_id As ObjectId

                    btr = trans.GetObject(bt(BlockTableRecord.ModelSpace), Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite)


                'append blockRef to blockTableRecord

                For Each brId As ObjectId In btr.GetBlockReferenceIds(True, False

  I do use a commit statement at the end of my code.  This is a snippet before.

cannorth

cannorth

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #4 on: August 07, 2012, 10:10:53 AM »
Ok, I'd like to know how can I get all the block insertions from a drawing, not just for one particular block.  Code examples would help.

cannorth
« Last Edit: August 07, 2012, 10:36:18 AM by cannorth »

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Retrieving object IDs from blocks in the drawing
« Reply #5 on: August 07, 2012, 11:19:56 AM »
Hi,

Please, try to be more accurate in your request.
Do you want to get all BlockReference objects in the drawing, even nested in blockTableRecords which aren't layouts ?
Do you want to get all BlockReference objects inserted in both model and paper spaces ?
Do you want to get all BlockReference objects inserted in model space ?
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: Retrieving object IDs from blocks in the drawing
« Reply #6 on: August 07, 2012, 11:25:13 AM »
... Building on Gile's questions (if I may):

What do you want the BlockReference Objects for?

Do you want them selected in ModelSpace (for example), or do you want them returned to the Command Line as a list (i.e., are you after a CommandMethod aka performs a function or query on the BlockReference Objects, or a LispFunction, aka sub-function with a return type)?

** Edit -

Ok, I'd like to know how can I get all the block insertions from a drawing

This suggests to me that you want a LispFunction that returns a point list. Albeit a point list that has no context, but still.
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #7 on: August 07, 2012, 11:59:39 AM »
Ok, I'd like to know how can I get all the block insertions from a drawing, not just for one particular block.  Code examples would help.

cannorth

All block insertions in a drawing includes all blocks that are inserted into other blocks, as well as all blocks inserted into model space and paper space.  If you only want the blocks inserted into model and/or paper space for drawings that are open in the AutoCAD editor, then there's different method that you can use.

Try being more specific about what you need.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Retrieving object IDs from blocks in the drawing
« Reply #8 on: August 07, 2012, 01:37:42 PM »
Here're some examples assuming you want to get all the ObjectIds of block references inserted into model space.

The first method uses the Editor.SelectAll method. To filter blocks in paper spaces too only, you can remove the TypedValue(410, "Model") from the filter.
For this method you need acces to the AutoCAD editor (i.e. the drawing is opened in the editor).
Code - C#: [Select]
  1.         private ObjectIdCollection SelectAllReferences()
  2.         {
  3.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  4.             TypedValue[] filter = new TypedValue[2] { new TypedValue(0, "INSERT"), new TypedValue(410, "Model") };
  5.             PromptSelectionResult psr = ed.SelectAll(new SelectionFilter(filter));
  6.             if (psr.Status != PromptStatus.OK)
  7.                 return new ObjectIdCollection();
  8.             return new ObjectIdCollection(psr.Value.GetObjectIds());
  9.         }

This other method 'hard codes' the SelectAll() method iterating the model space BlockTableRecord.
It can be used without acces to the Editor (i.e. with side Database)
Code - C#: [Select]
  1.         private ObjectIdCollection GetAllReferences(Database db)
  2.         {
  3.             ObjectIdCollection retVal = new ObjectIdCollection();
  4.             RXClass brClass = RXClass.GetClass(typeof(BlockReference));
  5.             using (Transaction tr = db.TransactionManager.StartTransaction())
  6.             {
  7.                 BlockTableRecord model =
  8.                     (BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
  9.                 foreach (ObjectId id in model)
  10.                 {
  11.                     if (id.ObjectClass == brClass)
  12.                     {
  13.                         retVal.Add(id);
  14.                     }
  15.                 }
  16.             }
  17.             return retVal;
  18.         }

The same one written in a more functional/declarative style with the Linq extension methods.
Code - C#: [Select]
  1.         private ObjectIdCollection GetAllReferencesDeclarative(Database db)
  2.         {
  3.             RXClass brClass = RXClass.GetClass(typeof(BlockReference));
  4.             using (Transaction tr = db.TransactionManager.StartTransaction())
  5.             {
  6.                 var ids =
  7.                     ((BlockTableRecord)tr.GetObject(SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead))
  8.                     .Cast<ObjectId>()
  9.                     .Where(id => id.ObjectClass == brClass)
  10.                     .ToArray();
  11.                 return ids.Length > 0 ? new ObjectIdCollection(ids) : new ObjectIdCollection();
  12.             }
  13.         }

This last method uses a reverse process. It gets the block refrences from the block definitions in the BlockTable. It needs to evaluate the reference owner to know if it's the model space (or a layout) or another BlockTableRecord (for nested blocks).
It may be faster than the others if they're many entities in the drawing that aren't block references.
Code - C#: [Select]
  1.         private ObjectIdCollection GetAllReferencesFromRecords(Database db)
  2.         {
  3.             ObjectIdCollection retVal = new ObjectIdCollection();
  4.             using (Transaction tr = db.TransactionManager.StartTransaction())
  5.             {
  6.                 BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
  7.                 foreach (ObjectId btrId in bt)
  8.                 {
  9.                     BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
  10.                     if (!btr.IsLayout)
  11.                     {
  12.                         foreach (ObjectId  id in btr.GetBlockReferenceIds(true, false))
  13.                         {
  14.                             BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
  15.                             BlockTableRecord owner = (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead);
  16.                             if (owner.Name == "*Model_Space")
  17.                             {
  18.                                 retVal.Add(br.ObjectId);
  19.                             }
  20.                         }
  21.                     }
  22.                 }
  23.             }
  24.             return retVal;
  25.         }

The same method using Linq:
Code - C#: [Select]
  1.         private ObjectIdCollection GetAllReferencesFromRecordsDeclarative(Database db)
  2.         {
  3.             using (Transaction tr = db.TransactionManager.StartTransaction())
  4.             {
  5.                 var ids = ((BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead))
  6.                     .Cast<ObjectId>()
  7.                     .Select(id => (BlockTableRecord)id.GetObject(OpenMode.ForRead))
  8.                     .Where(btr => !btr.IsLayout)
  9.                     .SelectMany(btr => btr.GetBlockReferenceIds(true, false).Cast<ObjectId>())
  10.                     .Select(id => (BlockReference)id.GetObject(OpenMode.ForRead))
  11.                     .Where(br => ((BlockTableRecord)br.OwnerId.GetObject(OpenMode.ForRead)).Name == "*Model_Space")
  12.                     .Select(br => br.ObjectId)
  13.                     .ToArray();
  14.                 return ids.Count() > 0 ? new ObjectIdCollection(ids) : new ObjectIdCollection();
  15.             }
  16.         }
« Last Edit: August 07, 2012, 02:55:43 PM by gile »
Speaking English as a French Frog

fixo

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #9 on: August 07, 2012, 03:58:33 PM »
Ok, I'd like to know how can I get all the block insertions from a drawing, not just for one particular block.  Code examples would help.

cannorth
Hi, cannorth

Try this simple code, tested on A2010:

Code: [Select]
''      get the real block name.           ''
    Public Function EffectiveName(tr As Transaction, bref As BlockReference) As String
        Dim btr As BlockTableRecord = Nothing
        If (bref.IsDynamicBlock) Or (bref.Name.StartsWith("*U", StringComparison.InvariantCultureIgnoreCase)) Then
            btr = TryCast(tr.GetObject(bref.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)
        Else
            btr = TryCast(tr.GetObject(bref.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
        End If
        Return btr.Name
    End Function


    <CommandMethod("QtyBlk")> _
    Public Sub CountAllBlocks()

        Dim countblocks As New SortedList(Of String, Long)
        Dim blkname As String
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument()
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Try
            Using tr As Transaction = db.TransactionManager.StartTransaction

                Dim res As PromptSelectionResult
                ' change value to your suit
                Dim tvs(0) As TypedValue
                tvs(0) = New TypedValue(0, "insert")

                Dim filt As SelectionFilter = New SelectionFilter(tvs)
                ' select all blocks
                res = ed.SelectAll(filt)
                ' select on screen
                'res = ed.GetSelection(filt)
                If res.Status <> PromptStatus.OK Then
                    Return
                End If
                For Each sobj As SelectedObject In res.Value
                    Dim obj As DBObject = DirectCast(tr.GetObject(sobj.ObjectId, OpenMode.ForRead, False), DBObject)
                    Dim bref As BlockReference = TryCast(obj, BlockReference)

                    If bref IsNot Nothing Then
                        blkname = EffectiveName(tr, bref)
                        If Not countblocks.ContainsKey(blkname) Then
                            countblocks.Add(blkname, 1)
                        Else
                            countblocks(blkname) += 1
                        End If

                    End If
                Next
                'display result
                For Each item As KeyValuePair(Of String, Long) In countblocks
                    ed.WriteMessage(String.Format(vbLf + "Block: ""{0}"" Count:  {1}" + vbLf, item.Key, item.Value))
                Next
                tr.Commit()
            End Using
        Catch ex As Autodesk.AutoCAD.Runtime.Exception

            Autodesk.AutoCAD.ApplicationServices.Application.ShowAlertDialog((ex.ToString() & vbLf) + ex.Message)
        Finally
            ed.WriteMessage(vbLf + "Pokey")
        End Try
    End Sub

~'J'~

BlackBox

  • King Gator
  • Posts: 3770
Re: Retrieving object IDs from blocks in the drawing
« Reply #10 on: August 07, 2012, 04:29:15 PM »
... Interesting that every code sample here uses StartTransaction() rather than StartOpenCloseTransaction().  :-D

/Stirs Pot
"How we think determines what we do, and what we do determines what we get."

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Retrieving object IDs from blocks in the drawing
« Reply #11 on: August 07, 2012, 04:49:17 PM »
... Interesting that every code sample here uses StartTransaction() rather than StartOpenCloseTransaction().  :-D

/Stirs Pot

I never heard so much about StartOpenCloseTransaction() than these days...
All my templates and code snippets use StartTransaction().
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: Retrieving object IDs from blocks in the drawing
« Reply #12 on: August 07, 2012, 04:58:20 PM »
... Interesting that every code sample here uses StartTransaction() rather than StartOpenCloseTransaction().  :-D

/Stirs Pot

I never heard so much about StartOpenCloseTransaction() than these days...
All my templates and code snippets use StartTransaction().

My apologies to the OP for even bringing this topic up, as it's being discussed in a separate thread... I simply thought those involved here and there would find this (yet another?) humorous example of the valid points being made elsewhere.

I'll respectfully stop stirring the pot here, and step back to 'listen' and learn.
"How we think determines what we do, and what we do determines what we get."

fixo

  • Guest
Re: Retrieving object IDs from blocks in the drawing
« Reply #13 on: August 10, 2012, 01:46:52 AM »
... Interesting that every code sample here uses StartTransaction() rather than StartOpenCloseTransaction().  :-D

/Stirs Pot
From the article by Mike Tursley:
"The main difference between using a normal Transaction and an OpenCloseTransaction or Open/Close is that, when not using a normal Transaction, opening an object can fail if that object is already open."

~'J'~