Explode Block - preserve texture mapping (rs.ExplodeBlockInstance)

I can’t find any solution to my problem - Automated exploding blocks with preserved texture mapping of the output geometry. In my example, geometry inside the block definition is using box mapping.

Approaches I tried:

  1. With the use of Grasshopper components from plugins: Heteroptera, Human, Elefront.
    I can receive internal geometry this way but without attributes. I can reassign materials but not the mapping of course.

  2. ExplodeBlock command in Rhino - manual approach gives me good results but it is manual. I could try to run Rhino command from Grasshopper with the use of "Rhino Command " component from LunchBox plugin but such an approach is far from how should it be. I would need to select geometry in the Rhino window etc.

  3. My last hope - Python.
    I used rs.ExplodeBlockInstance method
    https://developer.rhino3d.com/api/RhinoScriptSyntax/#collapse-ExplodeBlockInstance
    Unfortunately, it changes the mapping (rotates it to match world cplane and maybe does something more to it).

All of the approaches I took are visible on the screenshot and in the file that I attached.

File:
explode block.3dm (756.5 KB)

Another strange behavior with mapping and exploding Blocks.

Geometry inside the Block has Box Mapping.

  1. Explode the block.
  2. Copy to clipboard received geometry.
  3. Undo exploding the block.
  4. Paste geometry.

Pasted geometry changed its mapping from Box Mapping to Surface Mapping.

Hi @Czaja,

Does this help?

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

def coerceinstanceobject(id, raise_if_missing):
    rhobj = rs.coercerhinoobject(id, True, raise_if_missing)
    if isinstance(rhobj, Rhino.DocObjects.InstanceObject): return rhobj
    if raise_if_missing: raise ValueError("unable to find InstanceObject")

def test_explodeinstance():    
    iref_id = rs.GetObject("Select block instance to explode", rs.filter.instance);
    if not iref_id: return
    
    iref = coerceinstanceobject(iref_id, True)
    if not iref: return    
    
    xf = iref.InstanceXform
    yes = xf.IsValid and not xf.IsZero and not xf.IsIdentity
    
    guids = sc.doc.Objects.AddExplodedInstancePieces(iref, False, True)
    if guids:
        if yes:
            for id in guids:
                rhobj = sc.doc.Objects.FindId(id)
                atts = rhobj.Attributes.Duplicate()
                atts.Transform(xf)
                sc.doc.Objects.ModifyAttributes(id, atts, True)
        sc.doc.Objects.Delete(iref_id, True)
    sc.doc.Views.Redraw()
    
test_explodeinstance()    

– Dale

Hi @dale

Unfortunately, it gives me the same result as “short” python approach which I mentioned in my post.
Here’s a video.

hi Jakub

You can call Rhino Explore command using python.like this.

import rhinoscriptsyntax as rs
guids = rs.GetObjects("Select block instance to explode", rs.filter.instance)
if(guids):
    for guid in guids:
        rs.Command(" _Explode " + " SelID " +  str(guid) + " Enter ")

ExplodeBlock.py (224 Bytes)

1 Like

Thank You.

I converted it into this to use it inside Grasshopper.

import rhinoscriptsyntax as rs

if toggle:
Guidy =
Guidy.append(x)

guids = Guidy
for guid in guids:
    rs.Command(" _Explode " + " SelID " +  str(guid) + " Enter ")   

else:
print “off”

Using this method, is there a straightforward way to receive guids of all exploded geometries? If I explode 3 blocks and use Last Created Objects, it selects only one set of geometry.

Modify the dale code to do it.,like this:

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
def coerceinstanceobject(id, raise_if_missing):
    rhobj = rs.coercerhinoobject(id, True, raise_if_missing)
    if isinstance(rhobj, Rhino.DocObjects.InstanceObject): return rhobj
    if raise_if_missing: raise ValueError("unable to find InstanceObject")

def test_explodeinstance():
    outlist =[]    
    guids = rs.GetObjects("Select block instance to explode", rs.filter.instance);
    if not guids: return
    
    for guid in guids:
        list = []
        iref = coerceinstanceobject(guid, True)
        if not iref: return    
        
        geos = iref.GetSubObjects()
        for geo in geos:
            list.append(geo.Id)
        
        rs.Command(" _Explode " + " SelID " +  str(guid) + " Enter ")
        outlist.append(list)
    
    
    return outlist


print test_explodeinstance()