None can not be converted to a Plane - Break a While Loop

G’day everyone,

The code below will not break out of the while loop cleanly upon pressing ESC. It gives the message “None can not be converted to a Plane” and seems to indicate something wrong with the AddSphere line of code. This error message doesn’t come up in rhino, only the python editor, but the final line of code that shows all the hidden objects does not run, which is a problem.

It seems to be that the while loop begins to run again before realising that it should break. It gets to the AddSphere without a centre variable and errors out.

Any thoughts on this?

cheers,
Nick

import rhinoscriptsyntax as rs
import scriptcontext

def Hole():
    
    # Get the part and its attributes (if any exist)
    tupPart=rs.GetSurfaceObject("Select a surface for adding a hole to.", True, True)
    if not tupPart: return
    
    strID=tupPart[0]
    
    
    #Isolate the surface
    rs.SelectObject(strID)
    hiddenObjs = rs.InvertSelectedObjects()     # keep a list of items for showing later
    rs.HideObjects(hiddenObjs)
    rs.SelectObject(strID)
    
    
    # Get the hole radius
    rad=rs.GetReal("Radius?", 30, 15, 100)
    
    
    # Use a sphere for the trimming/splitting
    #    Does not require a plane and can be used on any type of surfaces (planar or curved)
    
    #Setup trimming object
    #Pick trim point
    while True:
        centre = rs.GetPointOnSurface(strID, "Hole Centre Point")
        
        #Create trimming object
        sphere = rs.AddSphere(centre, rad)
        
        splitSurfIDs = rs.SplitBrep(strID, sphere, True)
        
        #Delete cylinder and smallest split Brep
        rs.DeleteObject(sphere)
        
        if rs.SurfaceArea(splitSurfIDs[0]) < rs.SurfaceArea(splitSurfIDs[1]):
            smallSrf = splitSurfIDs[0]
            strID = splitSurfIDs[1]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        if rs.SurfaceArea(splitSurfIDs[1]) < rs.SurfaceArea(splitSurfIDs[0]):
            smallSrf = splitSurfIDs[1]
            strID = splitSurfIDs[0]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        rs.DeleteObject(smallSrf)
        
        # Press Esc or Enter to break out of the loop when finished
        if scriptcontext.escape_test(False):
            print "ESC pressed "
            break      #get out of the loop
    
    rs.ShowObjects(hiddenObjs)
    





##########################################################################
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if( __name__ == "__main__" ):
  #call function defined above
  Hole()

This feels better but still has the same problem.

import rhinoscriptsyntax as rs
import scriptcontext

def Hole():
    
    # Get the part and its attributes (if any exist)
    tupPart=rs.GetSurfaceObject("Select a surface for adding a hole to.", True, True)
    if not tupPart: return
    
    strID=tupPart[0]
    
    
    #Isolate the surface
    rs.SelectObject(strID)
    hiddenObjs = rs.InvertSelectedObjects()     # keep a list of items for showing later
    rs.HideObjects(hiddenObjs)
    rs.SelectObject(strID)
    
    
    # Get the hole radius
    rad=rs.GetReal("Radius?", 30, 15, 100)
    
    
    # Use a sphere for the trimming/splitting
    #    Does not require a plane and can be used on any type of surfaces (planar or curved)
    
    #Setup trimming object
    #Pick trim point
    while not scriptcontext.escape_test(False):
        centre = rs.GetPointOnSurface(strID, "Hole Centre Point")
        
        #Create trimming object
        sphere = rs.AddSphere(centre, rad)
        
        splitSurfIDs = rs.SplitBrep(strID, sphere, True)
        
        #Delete cylinder and smallest split Brep
        rs.DeleteObject(sphere)
        
        if rs.SurfaceArea(splitSurfIDs[0]) < rs.SurfaceArea(splitSurfIDs[1]):
            smallSrf = splitSurfIDs[0]
            strID = splitSurfIDs[1]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        if rs.SurfaceArea(splitSurfIDs[1]) < rs.SurfaceArea(splitSurfIDs[0]):
            smallSrf = splitSurfIDs[1]
            strID = splitSurfIDs[0]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        rs.DeleteObject(smallSrf)
        

    
    rs.ShowObjects(hiddenObjs)
    





##########################################################################
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if( __name__ == "__main__" ):
  #call function defined above
  Hole()

Hello,

How about something like this? (added if not ... tests for centre and sphere)

import rhinoscriptsyntax as rs
import scriptcontext

def Hole():
    
    # Get the part and its attributes (if any exist)
    tupPart=rs.GetSurfaceObject("Select a surface for adding a hole to.", True, True)
    if not tupPart: return
    
    strID=tupPart[0]
    
    
    #Isolate the surface
    rs.SelectObject(strID)
    hiddenObjs = rs.InvertSelectedObjects()     # keep a list of items for showing later
    rs.HideObjects(hiddenObjs)
    rs.SelectObject(strID)
    
    
    # Get the hole radius
    rad=rs.GetReal("Radius?", 30, 15, 100)
    
    
    # Use a sphere for the trimming/splitting
    #    Does not require a plane and can be used on any type of surfaces (planar or curved)
    
    #Setup trimming object
    #Pick trim point
    while not scriptcontext.escape_test(False):
        centre = rs.GetPointOnSurface(strID, "Hole Centre Point")
        if not centre:
            break
        
        #Create trimming object
        sphere = rs.AddSphere(centre, rad)
        if not sphere:
            break
            
        splitSurfIDs = rs.SplitBrep(strID, sphere, True)
        
        #Delete cylinder and smallest split Brep
        rs.DeleteObject(sphere)
        
        if rs.SurfaceArea(splitSurfIDs[0]) < rs.SurfaceArea(splitSurfIDs[1]):
            smallSrf = splitSurfIDs[0]
            strID = splitSurfIDs[1]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        if rs.SurfaceArea(splitSurfIDs[1]) < rs.SurfaceArea(splitSurfIDs[0]):
            smallSrf = splitSurfIDs[1]
            strID = splitSurfIDs[0]     # split operation creates a new surface with a new GUID, so reset strID to this
            
        rs.DeleteObject(smallSrf)
        

    
    rs.ShowObjects(hiddenObjs)
    





##########################################################################
# Check to see if this file is being executed as the "main" python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
if( __name__ == "__main__" ):
  #call function defined above
  Hole()

Thank you so much @Dancergraham.

I see the problem now, it was starting the next loop and asking for user input (GetPointOnSurface) prior to pressing ESC or Enter. The scriptcontext.escape_test(False) is probably not necessary, but will keep it around as a backup.