Scripting sub-object selection in Python

Is it possible to invoke sub-object selection through a Python script? For example, if I have a polysurface and I want to select one face. Or would I have to extract the face and deal with it that way? That’s what I am assuming I will need to do but I thought it’s worth asking.

Thanks,

Dan

If you were able to subobject select a face, what would you do with it?

Hi Dan,

you mean sub object selection by getting ?

import rhinoscriptsyntax as rs

def SubObjectSelect():
    obj_ref = rs.GetObject(message="Bla", filter=8, preselect=False, subobjects=True)
    if obj_ref:
        print "Surface:", obj_ref.Surface()
        print "Selection Point:", obj_ref.SelectionPoint()

if __name__=="__main__":
    SubObjectSelect()

Or you`ve meant something different ?

c.

You can get sub-objects - that is one of the strengths of Python, but you will have to go through RhinoCommon - as the subobject doesn’t really exist as an object with an ID in the document, so you have to first extract its geometry, then you can add that back to the document if you want it to exist in the document independently.

However, you can also just work with it as (virtual) geometry without adding it to the document - that is also one of the great strengths of Python/RhinoCommon. Unfortunately, at that point, as most rhinoscriptsyntax methods are based on ID’s - that is to say they only recognize objects that are in the document - if you want to continue working with your virtual geometry, you will need to do most of your succeeding operations in RhinoCommon as well. So things can get complicated pretty quick.

Following is a snippet that allows you to select a sub-surface and offset it by a given value. Note that the selection is not restricted to subsurfaces, it will also select surfaces (I don’t know yet how to restrict it to just Brep faces).

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def TestOffsetSubSrf():    
    msg="Select a surface or Brep face to offset"
    srf_filter=Rhino.DocObjects.ObjectType.Surface 
    rc,objref=Rhino.Input.RhinoGet.GetOneObject(msg,False,srf_filter)
    if rc!=Rhino.Commands.Result.Success: return
    
    offset=rs.GetReal("Offset value")
    if offset==None: return
    
    face=objref.Face()
    subSrf=face.ToNurbsSurface()
    
    oSrf=subSrf.Offset(offset,sc.doc.ModelAbsoluteTolerance)
    sc.doc.Objects.AddSurface(oSrf)
    sc.doc.Views.Redraw()

TestOffsetSubSrf()

the example above yours does. Thanks for your example too, i´ve learned something again from it !

c.

Me too, thanks… I actually remember how to do it now - the following does restrict selection to just subsurfaces:

import Rhino

def GetOnlyBrepFace():
    msg="Select a surface or Brep face to offset"
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt(msg)
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
    go.GeometryAttributeFilter=Rhino.Input.Custom.GeometryAttributeFilter.SubSurface
    go.SubObjectSelect = True
    go.AcceptNothing(False)
    
    if go.Get()!=Rhino.Input.GetResult.Object: return
    objref = go.Object(0)
    #etc

What I am trying to do is extract information from an object, specifically hole information from an imported Solidworks detail. Ideally I would like to select the cylindrical face that represents the hole, then have the diameter, depth and location fed back to the command line, or whatever else I need to do with it. I have a tool that provides this information currently, but it’s not as automated as I would like.

Thanks Mitch and Clement for your code samples. I will study these closely tomorrow.

Dan

Maybe like this:

import rhinoscriptsyntax as rs

def SubSelectCylinder():
    obj_ref = rs.GetObject(message="Sel", filter=8, preselect=False, subobjects=True)
    if obj_ref:
        subsrf=obj_ref.Surface()
        if subsrf:
            res, cyl = subsrf.TryGetCylinder()
            if res:
                circle = cyl.CircleAt(0.0)
                print "Cylinder properties:"
                print "axis vector:", cyl.Axis
                print "center:", cyl.Center
                print "height:", cyl.TotalHeight
                print "diameter:", circle.Diameter
            else:
                print "sorry, i am not a cylinder"

if __name__=="__main__":
    SubSelectCylinder()

c.

All of these examples are very informative and helpful. I think I have more reading to do, especially with regard to RhinoCommon and how to use it. For example, TryGetCylinder is unknown to me, but looks like exactly what I need.

Thanks,

Dan

Yes, good catch Clement, didn’t think of that as a test…

–Mitch

When I search for sub-object selection in Python, this is still the top result.

Has there been any development in this area the last decade?

I’m trying to change a script which only accepts single objects, to also accept a sub-object selected surface from a polysurface…

objIDs = rs.GetObjects(msg,8+16,preselect=True,minimum_count=2,maximum_count=2)

GetObjects only accepts 1 or multiple objects, GetObject can accept subobjects.

But 8+16 is surface or polysurface, and I’m holding shift+control during selection while using the script and I get no sub-object highlights with the script running in V8.

Pre-selecting the sub-objects I want also doesn’t work because the script just de-selects them and asks for 2 objects, despite preselect=True.

That’s correct, surfaces and polysurfaces are single objects allowed in the rs.GetObjects() method,
but this function does not have a subobjects argument like rs.GetObject()
You could write a function that allows you to select multiple faces in a loop using rs.GetObject()

Ok, should I be looking at a different set of documentation? These are the first hits on Google and neither mentions sub-objects:

https://developer.rhino3d.com/api/rhinoscript/selection_methods/getobjects.htm

https://developer.rhino3d.com/api/rhinoscript/selection_methods/getobject.htm

I was lazy and asked chatGPT to write it, and with the second question it actually produced this working example, using the GetObject function (so RhinoCommon directly instead of the rhinoscriptsyntax method)

import rhinoscriptsyntax as rs
import Rhino

def select_multiple_subobjects():
    # Initialize an empty list to store selected sub-object indices
    selected_subobjects = []
    
    # Prompt the user to select sub-objects (with sub-object selection enabled)
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("Select multiple sub-objects (faces, edges, vertices) from a polysurface")
    go.SubObjectSelect = True  # Enable sub-object selection
    go.GetMultiple(1, 0)  # Allow multiple selections
    
    if go.CommandResult() != Rhino.Commands.Result.Success:
        print("No sub-objects were selected.")
        return
    
    # Loop through the selected sub-objects
    for obj_ref in go.Objects():
        # Get the geometry of the selected sub-object
        subobject_index = obj_ref.GeometryComponentIndex.Index
        # Get the sub-object type
        subobject_type = obj_ref.GeometryComponentIndex.ComponentIndexType
        
        if subobject_type == Rhino.Geometry.ComponentIndexType.BrepFace:
            # Store only face sub-object indices
            selected_subobjects.append(subobject_index)
            print(f"Face with index {subobject_index} selected.")
        elif subobject_type == Rhino.Geometry.ComponentIndexType.BrepEdge:
            print(f"Edge with index {subobject_index} selected.")
        elif subobject_type == Rhino.Geometry.ComponentIndexType.BrepVertex:
            print(f"Vertex with index {subobject_index} selected.")
    
    # Display the result
    if selected_subobjects:
        print(f"Selected face indices: {selected_subobjects}")
    else:
        print("No faces were selected.")
        
# Run the function
select_multiple_subobjects()

for rhinoscriptsyntax, yes:
https://developer.rhino3d.com/api/RhinoScriptSyntax/

Thanks!

Since the pages I posted are the top results when I searched, perhaps it would be good to put a warning on the top of those pages (if the referrer is Gogle) with a link to the better source you posted?