It doesn’t work on block instances, it works on block definitions - and it does that one definition at a time. The problem seems to be when the block definition contains block instance objects.
I created this a while ago with the help of @DavidLeon:
def block_dissect(block_id=Rhino.Geometry.InstanceDefinitionGeometry, parent_layer = "Root"):
#check if its a block
block_obj = rs.coercerhinoobject(block_id)
# if its not a block, add to document
if type(block_obj) is not Rhino.DocObjects.InstanceObject:
#print "{0} is not a block".format(block_obj)
rs.AddLayer(name=parent_layer, color=None, visible=True, locked=False, parent=None)
rs.ObjectLayer(block_obj, parent_layer)
#if its a block, get sub objects, and recursively dissect
if type(block_obj) is Rhino.DocObjects.InstanceObject:
#print "{0} is a block".format(block_obj)
block_name = rs.BlockInstanceName(block_id)
#nake new parent layer
parent_layer = parent_layer + "::" + block_name
rs.AddLayer(name=parent_layer, color=None, visible=True, locked=False, parent=None)
sub_objs = rs.BlockObjects(block_name)
for obj in sub_objs:
block_dissect(obj, parent_layer)
def initiate_dissection():
block_id = [obj for obj in rs.AllObjects() if rs.ObjectType(obj) == rs.filter.instance]
block_dissect(block_id[0])
Hmmm I’ve missed that part does it need to be definitions?
Yes, that was the point… The idea was that you are stuck with a block definition that is related to the layers of the original objects; there are no longer objects on those layers, and you want to purge them. I thought it might be simple to just get the definitions and change all the layers of the objects in the definition. That works file for one level, but somehow when it find a nested block, one or more of of the objects is a block instance object (not a definition), and the layer change fails there. Haven’t figured out why yet - and I guess I’m going to give up on it for now.
I dredged these up, dunno if any gets at what being sought here…
MoveBlockObjectstoLayer.py (1.3 KB)
MoveBlockObjectstoInstanceLayer.py (907 Bytes)
-Pascal
I was doing this out of curiosity mostly, I don’t need it personally, just trying to understand where I went wrong in my reasoning.
Hi Mitch
As far as I understand (not much, actually …), a RhinoObject cannot be an InstanceDefinition, only
an InstanceObject …
I edited your script a little.
I think it works on your file, but I may be wrong …
You might like to give it a try.
HTH
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
#Maybe working for nested blocks...
def NukeAllBlockDefs(b_def,layer_index):
block_objs=b_def.GetObjects()
for block_obj in block_objs:
print type(block_obj)
# if isinstance(block_obj,Rhino.DocObjects.InstanceDefinition):
# #recurse
# NukeAllBlockDefs(block_obj,layer_index)
if isinstance(block_obj,Rhino.DocObjects.InstanceObject):
indef=block_obj.InstanceDefinition
NukeAllBlockDefs(indef,layer_index)
else:
block_obj.Attributes.LayerIndex=layer_index
block_obj.CommitChanges()
b_defs=sc.doc.InstanceDefinitions
if b_defs:
msg="Layer to send all block objects to"
dest_layer=rs.GetLayer(msg,show_new_button=True)
if dest_layer:
layers=sc.doc.Layers
layer_index=sc.doc.Layers.Find(dest_layer,True)
for b_def in b_defs: NukeAllBlockDefs(b_def,layer_index)
sc.doc.Views.Redraw()
Hi Emilio,
No, it doesn’t actually work, for example if you specify the “Block” layer for all the objects, you can see that the nested block remains on Layer 01.
That’s true, but in any case if there was no instance definition passed to the function except the initial one then the part you commented out would never be reached, so it actually doesn’t matter if it is there.
Hmmm.
True …
I think your script moves all original objects to the desired layer,
but it only move those instances that are nested in other instances.
If you want to change any instance’s layer, I think we need another loop on the definition instances.
I also removed the recursion.
I think that b_defs should already contain any block definition.
This seems to move both objects in the definition and block instances to the desired layer …
Well … as I said … it ‘seems’ …
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
#Maybe working for nested blocks...
def NukeAllBlockDefs(b_def,layer_index):
block_objs=b_def.GetObjects()
for block_obj in block_objs:
print type(block_obj)
# if isinstance(block_obj,Rhino.DocObjects.InstanceDefinition):
# #recurse
# NukeAllBlockDefs(block_obj,layer_index)
# if isinstance(block_obj,Rhino.DocObjects.InstanceObject):
# indef=block_obj.InstanceDefinition
# NukeAllBlockDefs(indef,layer_index)
block_obj.Attributes.LayerIndex=layer_index
block_obj.CommitChanges()
instances = b_def.GetReferences( 1 )
for instance in instances:
instance.Attributes.LayerIndex=layer_index
instance.CommitChanges()
b_defs=sc.doc.InstanceDefinitions
if b_defs:
msg="Layer to send all block objects to"
dest_layer=rs.GetLayer(msg,show_new_button=True)
if dest_layer:
layers=sc.doc.Layers
layer_index=sc.doc.Layers.Find(dest_layer,True)
for b_def in b_defs: NukeAllBlockDefs(b_def,layer_index)
sc.doc.Views.Redraw()
Cheers
great script. did what i wanted. i reccomend this to be a part of block manager natively…
Thank You Pascal! That script is a life saver!
This script is very useful when working with imported Sketchup Models I found. Wouldn’t mind adding it to Rhino 8 and calling it ChangeLayerInBlocks
to match the existing ChangeLayer
command.
A moan to add to the pile (of very helpful resources) here. Usage of blocks in rhino is opaque, byzantine and a massive administrative time drain. I have taken to purging them completely from my model because of the maddening amount of work involved in their management (see the inability to delete a layer with a definition, which in itself cannot be deleted as it is nested in another block which must be deleted first etc), which is ridiculous.
Blocks should be the lingua franca of CAD programs and BIM/PLM. Rhino’s block system is some arcane language which takes an age to learn, mostly by trial and error. An Achilles heel in my favourite workhorse programme…
R