Explode Blocks using VBA but program loops

Explode Blocks using VBA but program loops

JustinSider
Enthusiast Enthusiast
5,582 Views
10 Replies
Message 1 of 11

Explode Blocks using VBA but program loops

JustinSider
Enthusiast
Enthusiast

Hello anybody! 

 

I've spent the last two days searching forums and reading through my vba book on exploding block references.  I have a drawing my company uses as a base drawing but there's a bunch of layers we don't want on it and the only way to delete the layers is to first explode all the blocks in the drawing. 

 

I wrote some code that deletes the first block it finds, I couldn't get it to loop through and explode all of them.  The code below is what I found on these forums and it works but it won't execute the next subroutine because the For statement keeps looping.  I need a statement before my IF condition to check the drawing for block references first and if there aren't any it would go to the next sub.  I'm almost there!  Any help is greatly appreciated, new with VBA.

 

 

Sub ExplodeAllBlocks()
    Dim oEnt As AcadEntity
    For Each oEnt In ThisDrawing.ModelSpace
        If TypeOf oEnt Is AcadBlockReference Then
            ExpBlock oEnt
        End If
    Next
End Sub

Sub ExpBlock(ByRef BR)
    Dim varEx As Variant
    Dim BRef As AcadBlockReference
    Dim i As Double
   
    varEx = BR.Explode
    BR.Delete
    For i = 0 To UBound(varEx)
        If TypeOf varEx(i) Is AcadBlockReference Then
            Set BRef = varEx(i)
            ExpBlock BRef
        End If
    Next

 

End Sub

 

(my next Sub would start here)

Accepted solutions (1)
5,583 Views
10 Replies
Replies (10)
Message 2 of 11

norman.yuan
Mentor
Mentor

Let me see if I understand you correctly: your ultimate goal is to purge certain layer. So, you have already made sure there is no entity on that layer, but there is block definition which contains entity (or entities that is/are on that layer). So, you need to first erase all block references to that block definition, so that you can purge that block definition, then in turn you can finally purge the layer.

 

If this is what you need to do, why do you need to explode block reference before erasing? You simply erase all the block references to that block definition and then call Purge once, which would purge the block definition so that the layer held up by the block definition is freed. Then call Purge again would purge the layer.

 

For your code, you seem to explode all block references and then erase them. Does that imply that all block definitions in the drawing somehow hold the layer in them? If so, it seems that the drawing is used as "base drawing" really should be cleaned up, rather than each time it is used first and running code to clean it up up on use.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 11

JustinSider
Enthusiast
Enthusiast
Yes I totally agree about cleaning up the drawing, our client owns this drawing and has no desire to clean it. It is a live drawing meaning they add to it almost every day and when we execute a project for them we download their drawing to use for Civil/Mechanical background.

Right now my code takes all the layers and either deletes all entities on certain layers and deletes those layers And takes the other layers’ entities to our layer. If there are blocks on any those layers the code ignores it.

If I can find all the blocks in the drawing, explode them and delete the reference, I can then run my code and completely clean it up.

The other way is to merge the layers nested inside the block, but I couldn’t find a simple way to do this.

Thank you very much for your reply! I’m excited to get this macro to work, will save us thousands of hours.
0 Likes
Message 4 of 11

norman.yuan
Mentor
Mentor

I am still a bit confused: if the goal is to purge an unwanted layer, why do you need to explode block reference?

 

See, a layer could not be purged/deleted if any entity is on that layer. There could be 2 situations that hold a layer up: entities (either in ModelSpace or PaperSpace) sitting on that layer, including block references; or a BLOCK DEFINITION that consists of entities on that layer. For the former, you only need to erase them to free up the later. For the latter, even no block references to the block definition exists, the block definition still holds up the layer. So, you need to purge the block definition (of course you need to erase all its references) first. Then you can finally purge the layer in interest. So where does the "exploding" need come into play here?

 

If I understand your need correctly (purging certain layer or layers), I'd do these:

 

1. Loop through ModelSpace and all layouts (PaperSpaces) to search entities on that layer(s). If found, erase them. You can also create SelectSet with layer(s) filter to select all entities in drawing and erase them;

 

2. Loop through all block definitions of the drawing (AcadDocument.Blocks), for each block definition (AcadBlock), loop through its entities inside to check the Layer property. If the layer is the target layer(s), that block has to be purged. Therefore, you search the ModelSpace/PaperSpaces again for the block references to that block definition. If found (regardless the block reference sitting on which layer itself), erase it. Finally the block definition will no longer referenced.

 

3. Call AcadDocument.PurgeAll() method at least 2 times, the first would purge the block definitions that hold up the layer(s), and the second time the layer(s) in interest would be purged. However, calling PurgeAll() would purge other Blocks/Layers... that you do not want to purge. Alternatively, you can simply call AcadBlock.Delete() and AcadLayer.Delete() as long as they become delete-able (after the block definition is reference-free and the layer is hold-free).

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 5 of 11

JustinSider
Enthusiast
Enthusiast
Hi Norman,


Sorry I was on vacation and just returned from out of the country.


You seem to know what I'm trying to do and your points are valid. Exploding blocks are the only way I know how to access the layers and change them/delete them, this is why I was trying to find a way to merge layers onto other layers so I don't need to explode the blocks. I don't have a lot of experience with blocks so maybe I'm not understanding you correctly.


Your point number 2, you say loop through the blocks entities inside so this means essentially opening up a block and changing the layers? If I could include this code with what I have somehow this would be great. I know my code isn't perfect, I'm a beginner but I know it works.


Here's my basic code to clean up my drawing, I know there's a better way but this works:


Sub CleanLayers()

Dim ent As AcadEntity
' Deletes all objects on the layers and the purgeall command at the end deletes the layer
For Each ent In ThisDrawing.ModelSpace
If ent.Layer = "0ELV" Or ent.Layer = "1" Or ent.Layer Then

ent.Delete

End If

Next

' changes the layers to MEPHAN layer

For Each ent In ThisDrawing.ModelSpace
If ent.Layer = "1-collection pipe" Or ent.Layer = "ACID" Then

ent.Linetype = "ByLayer"
ent.Lineweight = acLnWtByLayer
ent.color = acByLayer
ent.Layer = "MEPHAN"
End If
Next

' Clean up the drawing

ThisDrawing.PurgeAll

ThisDrawing.Regen acActiveViewport
ThisDrawing.Application.ZoomExtents

End Sub


I have more layers added to the Or function, but you get the point. If I can get this to program to work on the blocks then I'll be golden!! Trying to keep this simple as I don't have much experience but had the time to learn some basic commands.


Thanks for your help!




0 Likes
Message 6 of 11

Anonymous
Not applicable

Hello,
Concerning these work on Blocks, where can I find documentation on the different Blockobjects, atributes and methods? Is there a Autodesk web site giving this? I always find old stuff or general information. Missing the typical Lexicon where all is together.

0 Likes
Message 7 of 11

JustinSider
Enthusiast
Enthusiast
There's a help page for Autodesk but you'll have to go through it to find what you're looking for.


http://help.autodesk.com/view/ACD/2015/ENU/?guid=GUID-36BF58F3-537D-4B59-BEFE-2D0FEF5A4443

0 Likes
Message 8 of 11

Anonymous
Not applicable

Thank you Justin 🙂

0 Likes
Message 9 of 11

Anonymous
Not applicable

I'm new on VBA on Autocad, knowing them separately. 
Reading your code I asked myself:

- in the block there are elements: lines, polylines, etc. 

- These don't have to be on the layer of the Block or blockreference. So if you explode the blocks these become "free" on the layer they were created. Meaning: as long as these are not changed of layer or deleted their layer won't be able to be deleted at all.

- in my idea there needs to be a recursive selection of elements in the block that then are changed of layer.
Otherwise exploding and deleting blocks and blockreferences will only be a part of the job.

Other comment: when I am working like this on existing drawings I explode all blocks of the drawing and nested blocks and then I select all elements of the drawing and put them on one specific layer. Then I purge twice and 
Only then I delete layers that I don't want to see. This must be easely done on VBA I guess.

0 Likes
Message 10 of 11

norman.yuan
Mentor
Mentor

@JustinSider wrote:
...
Your point number 2, you say loop through the blocks entities inside so this means essentially opening up a block and changing the layers? If I could include this code with what I have somehow this would be great. I know my code isn't perfect, I'm a beginner but I know it works.

My point is that beside the visible entities (on ModelSpace or in Layouts) that may reside on the layer you want to delete, there are "inivisible" entities in various block definition that also associated to that layer, thus make that layer not delete-able. Therefore, simply change all visible entities' layer (or erase these entities) may not enough to release the layer for deleting. So, you need to check each block definitions (except for *Model_Space" and "*Paper_Spacex" block) to see if any entity in the block definition is associated to the layer. If yes, you can either change the block definition (i.e. change the entity's layer in the block definition), or you can erase the block definition (but you need to erase all the block's references).

Attached some VBA code and an example drawing to demonstrate how to do it in following scenario:

1. A drawing has a block definition containing 3 entities: one on layer 0, one on layer1, and one on layer2. Then 3 block references to this block definition are inserted on layer 0, layer 1 and layer2. There are also 3 circle drawn on layer 0, layer1 and layer2.
2. I want to delete layer1 and layer2. Obviously I cannot, even I deleted the 2 circles on layer1 and layer2 and 2 block references on layer1 and layer2 (so, no visible entity sits on layer1 and layer2), because layer1 and layer2 are still referred in the block definition.
3. So, I need to examine all block definitions to see if the 2 layers are referred in them. For each block definition found with the 2 layers referred, I first search the drawing to delete all the block reference, then I can delete the block definition, thus free the 2 layers from the block definitions.
4. After doing this, I can finally make sure the layers are not referred to by any entity, be it in visible spaces, or in block definitions, then I can delete it.
5. I could have call PurgeAll(), but it might not be good if you still want to keep other purge-bale objects (linetypes, text styles...) in drawing, but only want to purge certain layer, my code is the customized "purge" only target particular objects (2 layers, here).
6. Also pay attention: if the drawing has entities not only in ModelSpace, but also various Layouts, the code would also need to search entities/block reference in Layouts... But you get the idea.

HTH

P.S.  Somehow I cannot post the reply with attachment of *.7z file. So I renamed it as "DeleteLayer.7z.RAR". You would need to rename it back to "DeleteLayer.7z" after download it.



 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 11 of 11

JustinSider
Enthusiast
Enthusiast
Accepted solution

thanks for all the help, your code was a bit confusing for me and hard to incorporate into what I wanted to do but was interesting going through it and getting a new perspective with different code.  I got my code to be able to explode all block references if anyone is curious but I did find a way to cycle through the blocks and change the layer inside the blocks without having to explode them which is way better. 

 

' ' Code to explode all block references in the drawing

 

Dim ent As AcadEntity
Dim BlkRef As AcadBlockReference
Dim Obj As Object

For Each Obj In ThisDrawing.ModelSpace
If TypeOf Obj Is AcadBlockReference Then
Set BlkRef = Obj

Dim ObjArray As Variant
ObjArray = BlkRef.Explode

BlkRef.Delete

Dim AcadObj As AcadObject
Dim ObjFromBlkRef As Variant

For Each ObjFromBlkRef In ObjArray
Set AcadObj = ObjFromBlkRef
Next ObjFromBlkRef
End If
Next Obj

 

' ' Code to cycle through blocks and change layers inside them

 

Dim ent As AcadEntity
Dim objBlock As AcadBlock
For Each objBlock In ThisDrawing.Blocks
 Set blk = ThisDrawing.Blocks(objBlock.Name)

 For Each ent In blk
 If ent.Layer = "Something" Then
 ent.Layer = "MTEXT"
 End If
 Next

 

Not the most sophisticated but it works... this code will also change anything not a part of a block which was fine for me because I needed everything changed but if anyone else needs this they'll have to figure it out on their own.

 

 

 

0 Likes