Author Topic: Trying to find Block references with no success  (Read 1787 times)

0 Members and 1 Guest are viewing this topic.

pjm8765

  • Guest
Trying to find Block references with no success
« on: May 11, 2017, 06:12:59 AM »
Using the following code

Code: [Select]
    Private Function GetBlockReferenceFromList(ByVal thisDocument As Document, _
                                               ByVal db As Database, _
                                               ByVal transaction As Transaction, _
                                               ByVal listOfBlockRefNames As List(Of String)) As List(Of BlockReference)

        Dim listOfBlockRef As New List(Of BlockReference)
        Dim blockTable As BlockTable
        Dim blockTableRecord As BlockTableRecord
        Dim objectID As ObjectId
        Dim objectCollection As ObjectIdCollection
        Dim i As Integer
        Dim blockRef As BlockReference

        Try

            blockTable = transaction.GetObject(db.BlockTableId, OpenMode.ForRead)

            For Each objectID In blockTable
                blockTableRecord = TryCast(transaction.GetObject(objectID, OpenMode.ForRead), BlockTableRecord)

                If Not IsNothing(blockTableRecord) Then
                    objectCollection = blockTableRecord.GetBlockReferenceIds(True, False)

                    If Not IsNothing(objectCollection) Then

                        If objectCollection.Count > 0 Then

                            For i = 0 To objectCollection.Count
                                blockRef = TryCast(transaction.GetObject(objectCollection(i), OpenMode.ForRead), BlockReference)

                                If Not IsNothing(blockRef) Then
                                    If listOfBlockRefNames.Contains(blockRef.Name) Then
                                        listOfBlockRef.Add(blockRef)
                                    End If
                                End If
                            Next

                        End If

                    End If
                End If
            Next

        Catch ex As Exception
            MsgBox("HollowCore_RemoveBlockReference.GetBlockReferenceFromList : " & ex.Message, MsgBoxStyle.OkOnly, EasiCADException.EasiCADErrorTitle)
        End Try

        Return listOfBlockRef

    End Function


I'm using AutoCAD 2014, VS2010 (.NET v4). 

To put this function in perspective I have inherited a system that creates and maintains blocks (used to represent concrete slabs on a floorplan) that should only have one block reference each.  I am finding drawings with duplicate block references where one or other bespoke command e.g. Copy, Move, are breaking and leaving these duplicates lying around, which are invisible.  The above function is part of a wider function to remove the duplicate Block references.

Bryco

  • Water Moccasin
  • Posts: 1882
Re: Trying to find Block references with no success
« Reply #1 on: May 11, 2017, 11:25:13 AM »
Check for same insertion pt and rotation.
Check visability
Check for non annotative and annotative (if both are found in blockrefs from the same block some become invisible)

n.yuan

  • Bull Frog
  • Posts: 348
Re: Trying to find Block references with no success
« Reply #2 on: May 11, 2017, 01:49:58 PM »
You may want to give more detail on what "with no success" mean. Do you mean that you do know there are block references with give block name existing in the drawing, but the code does not find it (thus, function returns the list with Count=0)?

If that is the case, then there could be 2 causes, seeing from your code:

1. the code compares block reference's name against a list of known block names here:

If listOfBlockRefNames.Contains(blockRef.Name) Then

The reason of this code being problematic is the block names in the list and the block reference's name could be literally the same but in difference case (upper or lower), then the condition in the "If..." could return False.

2. You did not mention, but if the block in interest is dynamic block, the block reference's name could be an anonymous block name, generated by AutoCAD. So, if the block may possibly be a dynamic one, you need to find its "effective" name, not BlockReference.Name.

Also, since you only are interested in a given set of block names, you can loop through the block name list, instead of loop through entire block record table. This will make the code logic easier to follow. Something like:

Private Function GetBlockReferenceFromList(db as Database, tran As Trsnaction, blkNames as List(of String)) As ...

    Dim listOfBlockRef As New List(of BlockReference)

    Dim blockTable as BlockTable=....

    For Each blkName As String in blkNames
        If blockTable.Has(blkName) Then
          Dim brefs=GetBlockRefs(tran, blockTable(blkName))
          If brefs.Count>0 Then
            listOfBlockref.AddRange(brefs)
          End If
        End If
    Next

    Return lisOfBlockRef

End Function

Private Function GetBlockRefs(tran as Transaction, blkId as ObjectId) As List(of BlockReference)

    Dim brefs As New List(of BlockReference)()

    Dim blockRecord=DirectCast(tran.GetObject(blkId,OpenMode.ForRead), BlockTableRecord)
   
    ''Get direct BlockReference
    Dim blks=FindBlockReferences(tran, blockRecord)
    If blks.Count>0 Then brefs.AddRange(blks)

    ''If the block is dynamic
    If blkRecord.IsDynamic Then
       Dim anonyBlkIds=blockRecord.GetAnonymousBlockIds()
       If anonyBlkIds IsNot Nothing AndAlso anonyBlkIds.Count>0 Then
           For Each blkId As ObjectId in anonyBlkIds
               Dim anonyBlkRecord=DirectCast(tran.GetObject(blkId,OpenMode.ForRead), BlockTableRecord)
               blks=FindBlockReferences(tran, anonyBlkRecord)
               If blks.Count>0 Then brefs.AddRange(blks)
           End If
       End If
    End if
    Return brefs

End Function

Private Function FindBlockreferences(tran As Transaction, blkRecord As BlockTableRecord) As List(of BlockReference)
    Dim brefs As New List(of BlockReference)()
   
    Dim idCollection=blkRecord.GetBlockReferenceIds(True, False)
    If idCollection IsNot Nothing AndAlso idCollection.Count>0 Then
       For Each id As ObjectId in idCollection
         bref.Add((DirectCast(tran.GetObject(id, OpenMode.ForRead), Blockreference))
       Next
    End If
    Return brefs
End Function

The code is not tested, but you get the idea:

1. Use BlockTable.Has() to see if a block definition with particular name exists in the database. Here you avoid having to compare block name by yourself (eliminating potential character's CASE issue); With BlockTable.Has() method while loop through your block name list, you only go deeper, if the block name is indeed a defined BlockTableRecord;
2. If the blocks in interest could be dynamic block, you must make sure the corresponding anonymous block references are also searched

HTH

pjm8765

  • Guest
Re: Trying to find Block references with no success
« Reply #3 on: May 12, 2017, 08:09:35 AM »
Thanks very much n.yuan.  So the lack of success is indeed that I know there are named block references and my code does not find them.  It does find block references, but none with the names that I know exist.

The majority of the system uses the COM style of programming and in the end I landed up writing the routine using that approach just to get it working:

Code: [Select]
    Private Function GetBlockReferenceFromList(ByVal thisDrawing As AcadDocument, ByVal listOfBlockRefNames As List(Of String)) As List(Of AcadBlockReference)

        Dim listOfBlockRef As New List(Of AcadBlockReference)
        Dim blockRef As AcadBlockReference
        Dim selectionSet As AcadSelectionSet = Nothing
        Dim filterType(1) As Short
        Dim filterData(1) As Object

        Try

            selectionSet = CreateSelSet(thisDrawing, "RemoveBlockReferences")

            filterType(0) = 0
            filterData(0) = "INSERT"     
            filterType(1) = 8
            filterData(1) = "SLABOUTLINE"

            selectionSet.Select(AcSelect.acSelectionSetAll, , , filterType, filterData)

            If selectionSet.Count > 0 Then
                For Each blockRef In selectionSet
                    If listOfBlockRefNames.Contains(blockRef.Name) Then
                        listOfBlockRef.Add(blockRef)
                    End If
                Next

            End If

        Catch ex As Exception
            MsgBox("HollowCore_RemoveObjects.GetBlockReferenceFromList : " & ex.Message, MsgBoxStyle.OkOnly, EasiCADException.EasiCADErrorTitle)
        Finally

            If Not IsNothing(selectionSet) Then
                selectionSet.Clear()
            End If
            DelSelSet(thisDrawing, "RemoveBlockReferences")
        End Try

        Return listOfBlockRef

    End Function


However, I want to get as far away from COM as I can, so I'll investigate further using your pointers when I've got some time free.

The Block and Blockreference names in question are numbers, so the case sensitivity doesn't come into it...but it's useful to be aware of that thanks.  I had noticed this with the Editor.GetString function. 

With regards to whether the blocks are dynamic or not, I'm not sure.  The system uses the AcadDocument.Blocks.Add function to add Blocks and AcadDocument.ModelSpace.InsertBlock function for BlockReferences (why a routine called InsertBlock returns a BlockReference is beyond me).