Python rhinoscriptsyntax custom_filter question

I am trying to limit the selection to either a closed planar curve or a planar surface. I have tried all sorts of combinations of different ways to set up the custom filter including more detailed if statements and try/except clauses, but none work correctly, either I can select some things that don’t fit the filter criteria or I can’t select some things that do… Haven’t found the right combination yet. Anyone have any pointers here?

def cp_filt(rhino_object, geometry, component_index):
    a=(rs.IsSurface(geometry) and rs.IsSurfacePlanar(geometry))
    b=(rs.IsCurvePlanar(geometry) and rs.IsCurveClosed(geometry))
    return a | b

def TestFilter():
    msg="Select closed planar curve or planar surface"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj

Thx, --Mitch

the filter function has signature (RhinoObject, GeometryBase, ComponentIndex)

Looking at the docs I see that rs.IsSuface expects an objectId, not a geometry. Same for IsSurfacePlanar, IsCurvePlanar and IsCurveCosed

http://4.rhino3d.com/5/ironpython/modules/surface_module.htm
http://4.rhino3d.com/5/ironpython/modules/curve_module.htm

So, probably you’d have to write something along the lines of

def cp_filt(rhino_object, geometry, component_index):
    a=(rs.IsSurface(rhino_object.Id) and rs.IsSurfacePlanar(rhino_object.Id))
    b=(rs.IsCurvePlanar(rhino_object.Id) and rs.IsCurveClosed(rhino_object.Id))
    return a | b

Does that help? I may be barking up the wrong tree though…

No unfortunately, that still allows me to select stuff other than the filter specifies, notably non-planar surfaces… But thanks for trying!

Edit - OK, my theory here is that the custom_filter can’t distinguish basic object types like whether it’s a curve or a surface - but rather just the object type sub characteristics like closed or planar. So when the primary filter feeds it the possibility of two different types of object it gets confused… My evidence:

The following works correctly for closed planar curves:

def cp_filt(rhino_object, geometry, component_index):
    return rs.IsCurvePlanar(geometry) and rs.IsCurveClosed(geometry)

def TestFilter():
    msg="Select planar object"
    obj=rs.GetObject(msg,4,True,custom_filter=cp_filt)
    print obj
TestFilter()

Now, add the possibility of selecting surfaces - it then fails (any kind of surface can also be selected):

def cp_filt(rhino_object, geometry, component_index):
    return rs.IsCurvePlanar(geometry) and rs.IsCurveClosed(geometry)

def TestFilter():
    msg="Select planar object"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj
TestFilter()

OK, try filtering for curve objects inside the custom filter:

import rhinoscriptsyntax as rs

def cp_filt(rhino_object, geometry, component_index):
    return rs.IsCurve(geometry) and rs.IsCurvePlanar(geometry) and rs.IsCurveClosed(geometry)

def TestFilter():
    msg="Select planar object"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj
TestFilter()

That also fails, surfaces can still be selected…

–Mitch

Not sure whether you’re looking for a workaround or are trying to understand why that method does not work …
Anyway, if I understand the problem correctly, nesting the input code inside a loop might work as a workaround:

import rhinoscriptsyntax as rs

id = None
while not id:
    id = rs.GetObject( '?' )
    if not id:
        break
    if rs.IsSurface( id ) and rs.IsSurfacePlanar( id ):
        pass
    elif rs.IsCurve( id ) and rs.IsCurvePlanar( id ):
        pass
    else:
        id = None
print id

HTH

Hi Mitch, this works for me:

import Rhino
import rhinoscriptsyntax as rs

def cp_filt(rhino_object, geometry, component_index):
    if geometry.IsPlanar():
        if isinstance(geometry, Rhino.Geometry.Curve):
            if not geometry.IsClosed: return False
        return True
    return False

def TestFilter():
    msg="Select planar object"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj
    
TestFilter()

Edit: posted the wrong version, hope this works

1 Like

Hey Jess,

You nailed it! So, I just have to go deeper into RhinoCommon for this function, this is a lot of help!

Cheers, --Mitch

Hi Mitch, well you could also do it with rhinoscriptsyntax, but you’ll have to be more explicit:

import rhinoscriptsyntax as rs

def cp_filt(rhino_object, geometry, component_index):
    if rs.IsCurve(rhino_object.Id):
        if rs.IsCurveClosed(rhino_object.Id):
            if rs.IsCurvePlanar(rhino_object.Id):
                return True
    elif rs.IsSurface(rhino_object.Id):
            if rs.IsSurfacePlanar(rhino_object.Id):
                return True
    return False

def TestFilter():
    msg="Select planar object"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj
    
TestFilter()

In your code you’ve checked surface properties on curves and vice versa. Looks like a custom_filter is simply being ignored once there is some faulty code inside.

I had tried all sorts of stuff like that before posting… But somehow never got it right… :confounded:

Trying to understand a little more, I edited Mitch’s original code applying what Menno and Jess tought us.
(obviously it works)
Also, calling a Curve method onto a Surface usually makes the script break, but calling it inside the filter function lets the script run and give meaningless results. Just like Jess said.
Thanks guys, I’ve learnt something more :smiley:

import rhinoscriptsyntax as rs

def cp_filt(rhino_object, geometry, component_index):
    a=(rs.IsSurface(rhino_object.Id) and rs.IsSurfacePlanar(rhino_object.Id))
    b=(rs.IsCurve(rhino_object.Id) and rs.IsCurvePlanar(rhino_object.Id) and rs.IsCurveClosed(rhino_object.Id))
    return a | b

def TestFilter():
    msg="Select closed planar curve or planar surface"
    obj=rs.GetObject(msg,4+8,True,custom_filter=cp_filt)
    print obj
    
TestFilter()

@stevebaer I think I found a bug in one of these things:

This works to isolate polycurves:

import rhinoscriptsyntax as rs
import Rhino

#polycurves, but no polylines
def pcrv_filt(rhino_object, geometry, component_index):
    return rs.IsPolyCurve(geometry)

def TestFilter():
    msg="Select polycurves to test"
    crvIDs=rs.GetObjects(msg,4,preselect=True,custom_filter=pcrv_filt)
    if not crvIDs: return
TestFilter()

and this doesn’t:

import rhinoscriptsyntax as rs
import Rhino

#polycurves, but no polylines
def pcrv_filt(rhino_object, geometry, component_index):
    return geometry.IsPolyCurve()

def TestFilter():
    msg="Select polycurves to test"
    crvIDs=rs.GetObjects(msg,4,preselect=True,custom_filter=pcrv_filt)
    if not crvIDs: return
TestFilter()

For selecting polylines, for example, if you change PolyCurve to Polyline, they both work…

Note that return isinstance(geometry, Rhino.Geometry.PolyCurve) also works…

–Mitch

@alain can you look into this?

Hey Mitch,
I don’t see such a method in RhinoCommon.

Hey Alain,
You’re right, my bad, I didn’t look, I just assumed that it was there like IsPolyline(). Sorry for the noise… :hear_no_evil: