TheSwamp
Code Red => .NET => Topic started by: pjm8765 on May 11, 2017, 06:12:59 AM
-
Using the following code
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.
-
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)
-
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
-
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:
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).