Copying surface from block in python

Is there a way to copy a surface from a BlockInstance without exploding the block?

I’m generating a bunch of different blocks to design a facade, but for simulations I just need to copy/choose a single specific surface from each of these (same Rhino Name and Layer in all BlockInstances) in a Python script without exploding the block, as it would increase file size.

I can do it in Grasshopper, but I’m learning Python and haven’t been able to find a starting point or path yet, so any suggestions would be a great help

Thanks

Have you tried using the ExtractSrf command?

– Dale

@dale How will I use ExtractSrf (a Rhino commend) to extract a named surface from a block in python2?

In grasshopper I can explode the block and filter for a named surface, but I’m not sure how to do that in a Python script.

thanks
anders

Hi @anders,

How about this?

import Rhino
import scriptcontext as sc

def ExtractSrf():
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("Select surface to extract")
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
    go.GeometryAttributeFilter = Rhino.Input.Custom.GeometryAttributeFilter.SubSurface
    go.EnablePreSelect(True, True)
    go.Get()
    if go.CommandResult() != Rhino.Commands.Result.Success:
        return
    
    objref = go.Object(0)
    face = objref.Face()
    if face:
        brep = face.DuplicateFace(True)
        if brep:
            sc.doc.Objects.AddBrep(brep)
            
    sc.doc.Views.Redraw()

if __name__ == "__main__":
    ExtractSrf()

– Dale

Wow, thanks @dale this is a bit over my level of understanding to integrate…

I currently use this to manually select the surfaces after exploding the blocks, but I’d like to automate it keep the file size down…exploding all the blocks make the file super heavy and slow (I often hundreds of panels with dozens of parts)

def main():
    objs = rs.GetObjects("Select surfaces to export data",8,preselect=True) # I'd replace 8 with 4096 to filter for blocks

From the selected blockinstances I’d like to use the surface with the Rhino name “PV Glass” for further processing…or directly select all the sub surfaces named “PV Glass” when the script is invoked.

Will I be able to use

go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
go.GeometryAttributeFilter = Rhino.Input.Custom.GeometryAttributeFilter.SubSurface

to do this in some way?..I guess I’d need to set another filter for the Rhino name of the sub surface in the blockinstance…

thanks
anders

Hi @anders,

Can you post a .3dm file that contains the block?

Thanks,

– Dale

Hi @dale thanks for looking at this.
Here is a .3dm and a screenshot showing the surface I need. There is also an open polysurface with the same name (the rear of the glass), but I only need the surface that has already been extracted in the block.

Panel block.3dm (596.9 KB)

Thanks
anders

Hi @anders,

See if this gets you any farther.

ExtractBlockInstanceComponent.py (1.4 KB)

– Dale

Thanks @dale.

I’m playing around with your sketch and have two questions.

How do I modify it to select multiple blocks (pre or post select)?
I’ve tried dropping in Rhino.Input.RhinoGet.GetMultipleObjects() without success and get this message and I’m sure it’s because it is not ready to receive multiple items, but when I do select two instances it selects the polysurface and the surface in the first instance (not the surface), and nothing in the second…

I would also like to hard code the name, but when I do, I causes an issue and this message that there are too many values…

thanks
anders

Hi @anders,

See the attached.

ExtractBlockInstanceComponent2.py (1.3 KB)

– Dale

Thank you @dale this works beautifully and I have added another ‘if statement’ to eliminate the polysurface that is also in the same layer, so I only get the front surface…all is well so far.

I’m doing all of this to build upon the easycut script and to create/export a panel schedule with a hit more details. I’ve dropped your code into my doctored script and are having some problems handing off the created surfaces to the existing code…I have been trying different tweaks to make it run, but I don’t have the Python skills.

The error that gets spit out in Terminal is ‘TypeError: iteration over non-sequence of type BrepObject’

Here are a few screenshots from the critical points and the complete code

20240608_solarlab-schedule maker - not working.py (21.0 KB)

I think the problems is that what ‘new_obj’ returns from ‘ExtractBlockInstanceComponent()’

            id = scriptcontext.doc.Objects.Add(obj, rh_obj.Attributes)
            new_obj = scriptcontext.doc.Objects.Find(id)
            rs.ObjectLayer(new_obj,"PV-Surfaces")
            if new_obj:
                new_obj.Select(True)  
    scriptcontext.doc.Views.Redraw()
    return new_obj

doesn’t fit what is used here in makeDeatil() where it is called ‘objs’:

def makeDetail(keys, objs):
    if not objs: return
    for obj in objs: # I get an error here 'TypeError: iteration over non-sequence of type BrepObject'
        for key in keys:
            cur_keys = rs.GetUserText (obj)
            if key not in cur_keys:
                rs.SetUserText (obj, key, "0", False)
            else:
                val = rs.GetUserText (obj, key)
                if len(val)<1 or val==" ":
                    rs.SetUserText (obj, key, "0", False)

I just don’t know how to make them play nice…
Any suggestion on how to make it over these last bumps?

thanks
anders

I’ve tried using coercesurface and coerceguid from RhinoScriptContext thinking it might be the wrong type, but neither work for me…Where am I going wrong?

I hope it is OK that I keep asking for help, but do you have any suggestions @dale ?

thank you
anders

Hey @anders - I am not going to have time to look this, sorry.

– Dale

I understand and I greatly appreciate your help getting me this far

thank you
anders