Python Code About Validating User Input

I have read alot about validating the user input at different websites, but I still wasn’t able to find a method in python for generating the condition at “the end of the while statement”… Like in Visual Basic for example:

Do
    [ statements ]
    [ Continue Do ]
    [ statements ]
    [ Exit Do ]
    [ statements ]
Loop { While | Until } condition

So here is my code at the momen. I’m not sure, if everything is perfect. I am just a beginner … Maybe somebody has more knowledge and can provide me with a simple way to get to the solution…

import Rhino as rhinoRef
import Rhino.Geometry
import rhinoscriptsyntax as rs
import math
import scriptcontext


def abcde():

    # Parameters 
    # standard values for parameters
    bx = 0.0 # base point coordinates
    by = 0.0
    bz = 0.0
    lCube = 10.0    # side length of cube
    rCyl = 1.0        # radius of cylinder
    hCyl = 20.0    # height of cylinder
    rSph = 6.0        # radius of sphere
    thSl = 0.3        # thickness of slot
    hSl  = 1.3        # height of slot
    
    # ask the user to pick a base point 
    BasePoint = rs.GetPoint("Pick base point")
    # ask the user to enter the side length for the cube
    lCube = rs.GetReal("please, enter the side length for the cube C1",10.0,1,)   
    # ask the user to enter radius of the cylinder
    rCyl = rs.GetReal("please, enter the radius of the cylinder Cl1",1.0,1,)  
    # ask the user to enter height of the cylinder
    hCyl = rs.GetReal("please, enter the height of the cylinder Cl1",20.0,1,) 
    # ask the user to enter radius of the spehere
    rSph = rs.GetReal("please, enter the radius of the spehere S1",6.0,1,)    
    # ask the user to enter thickness of the slot 
    thSl = rs.GetReal("please, enter the thickness of the slot Sl1",0.3,0.1,)   
    # ask the user to enter height of the slot
    hSl = rs.GetReal("please, enter the height of the slot Sl1",1.3,0.5,)   
 
    # store base point coordiantes

    bx = BasePoint.X
    by = BasePoint.Y
    bz = BasePoint.Z

    # Validation of input
    
    while (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
        print ("The thickness of the slot" + " = " + str(thSl)  + "should not be smaller than the length of the cube" + " = " + str(lCube))
        print ("and the height of the slot" + " = " + str(thSl)  + "should not be smaller than the length of the cube" + " = " + str(lCube))
        print ("and the radius of the sphere" + " = " + str(rSph) + "should not be smaller than the half side length of the cube" + " = " + str(lCube/2))
        print ("please, repeat and make sure, that your input matches these criteria")
        return
 
 #create a cylinder
  
    rs.AddCylinder(BasePoint,hCyl,rCyl,cap=True)
 
#create a sphere
    
    rs.AddSphere(BasePoint,rSph)

One problem is that I am not really sure, what “return” exactly does here. The second problem is that neither sphere nor cylinder are created in Rhino!!

Thanks alot!!

Hello Ahmed,

Here is the script that works for the standard values for parameters.
Be warned that this kind of while loop can be dangerous and lead you into an infinite loop if break condition is never met!
You should always create a possibility for user to abort it, like entering zero for some parameter value or similar thing. In this case I’ve created it by checking if base point is selected. If you don’t select the basepoint, the script will end

hope this will help you go further with your script.

import rhinoscriptsyntax as rs

def abcde():
    # Parameters 
    # standard values for parameters
    bx = 0.0 # base point coordinates
    by = 0.0
    bz = 0.0
    lCube = 10.0    # side length of cube
    rCyl = 1.0        # radius of cylinder
    hCyl = 20.0    # height of cylinder
    rSph = 6.0        # radius of sphere
    thSl = 0.3        # thickness of slot
    hSl  = 1.3        # height of slot

    # start of the loop
    while True:

        # ask the user to pick a base point 
        BasePoint = rs.GetPoint("Pick base point")

        if not BasePoint:
            # if no point is entered, escape the loop and end script 
            return

        # ask the user to enter the side length for the cube
        lCube = rs.GetReal("please, enter the side length for the cube C1",10.0,1,)   
        # ask the user to enter radius of the cylinder
        rCyl = rs.GetReal("please, enter the radius of the cylinder Cl1",1.0,1,)  
        # ask the user to enter height of the cylinder
        hCyl = rs.GetReal("please, enter the height of the cylinder Cl1",20.0,1,) 
        # ask the user to enter radius of the spehere
        rSph = rs.GetReal("please, enter the radius of the spehere S1",6.0,1,)    
        # ask the user to enter thickness of the slot 
        thSl = rs.GetReal("please, enter the thickness of the slot Sl1",0.3,0.1,)   
        # ask the user to enter height of the slot
        hSl = rs.GetReal("please, enter the height of the slot Sl1",1.3,0.5,)   
    
        # store base point coordiantes
    
        bx = BasePoint.X
        by = BasePoint.Y
        bz = BasePoint.Z
    
        # Validation of input
        if not (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
            # condition is met - get out of the loop and continue with script
            break
        
        print ("The thickness of the slot" + " = " + str(thSl)  + "should not be smaller than the length of the cube" + " = " + str(lCube))
        print ("and the height of the slot" + " = " + str(thSl)  + "should not be smaller than the length of the cube" + " = " + str(lCube))
        print ("and the radius of the sphere" + " = " + str(rSph) + "should not be smaller than the half side length of the cube" + " = " + str(lCube/2))
        print ("please, repeat and make sure, that your input matches these criteria")
    
    #conditions are met, create cylinder and sphere

    rs.AddCylinder(BasePoint,hCyl,rCyl,cap=True)
    rs.AddSphere(BasePoint,rSph)

    return

if __name__=="__main__":
    abcde()`

Hello Alex,

A Question to this masterpiece :

if not (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
# condition is met - get out of the loop and continue with script
break

Ok, getting out of the loop means getting out of “while True… return”? But after return there is almost no more Script…

Ahmed,

I try to make this explanation as simple as possible.
You say you are the beginner, so I start from the anatomy of my script:
( please forgive me if this is “too wide” approach, as I’m just trying to help, not to lecture you )

The last two lines of code, together with function defined above it, are “standard” script template (I’ve found it somewhere in the online docs for rhino python scripting and I use it for most of my scripts).
These lines are the entry point for the script and they call your function.

now we get to the point, the return command is not part of the while loop, it ends the function abcde()

break command gets you out of the while loop, to the line:

       #conditions are met, create cylinder and sphere

so here you should put your code after validation is done, before return command

return command ends your function, gets you back to the entry point and the script ends

I hope it is more clear for you now

Alex

Hello Alex,

It’s alright, you could also lecture me, no problem!

But I think I have got the idea. Return ends the function abcde() and break exists the “infinite loop”. I got that.

There is one more thing about the statements inside the while loop. How do Python know, which statements have to be repeated? Does this have something with the “position of the statements” within the code? For example the command “break” is standing a little bit to the right…

Thank you

Hello Alex,

It’s alright, you could also lecture me, no problem!

But I think I have got the idea. Return ends the function abcde() and break exits the “infinite loop”. I got that.

There is one more thing about the statements inside the while loop. How do Python know, which statements have to be repeated? Does this have something to do with the “position of the statements” within the code? For example the command “break” is standing a little bit to the right… And if the condition is not met, would the script ask the user for new input values again?.. If the condition is not met and the user has to enter new values, such that the condition can be met, where in the code does this “jump back” exactly happen?..

Thank you

In VB (from your first post) the loop is between DO and LOOP, some languages used brackets and python uses indents

After WHILE statement, everything inside the loop is indented by four spaces. Using indents to separate code blocks is how python works, it is general rule and works for all kind of loops, if statements etc.
Code block indented 4 spaces after the WHILE command is considered inside the loop will repeat as long as the condition is True. In this case loop is practically infinite, because True is always True, and from this kind of loop you can exit only by BREAK.
The next statement after the loop has the same indent as the WHILE statement, that is where script continues after the BREAK

BR

Ok, Alex. Thank you. I understand it now.
I will test this soon and give you feedback and maybe some further questions, if I get stuck again!!! :sweat_smile:

Hi Alex,

so here is my code up to now:

def abcde():
# **************************************************
# Parameters ***************************************
# standard values for parameters
bx = 0.0 # base point coordinates
by = 0.0
bz = 0.0
lCube = 10.0 # side length of cube
rCyl = 1.0 # radius of cylinder
hCyl = 20.0 # height of cylinder
rSph = 6.0 # radius of sphere
thSl = 0.3 # thickness of slot
hSl = 1.3 # height of slot

# start of the loop
while True:

    # ask the user to pick a base point 
    BasePoint = rs.GetPoint("Pick base point")
    if not BasePoint:
        return
    # ask the user to enter the side length for the cube
    lCube = rs.GetReal("please, enter the side length for the cube C1",10.0,1,)   
    # ask the user to enter radius of the cylinder
    rCyl = rs.GetReal("please, enter the radius of the cylinder Cl1",1.0,1,)  
    # ask the user to enter height of the cylinder
    hCyl = rs.GetReal("please, enter the height of the cylinder Cl1",20.0,1,) 
    # ask the user to enter radius of the spehere
    rSph = rs.GetReal("please, enter the radius of the spehere S1",6.0,1,)    
    # ask the user to enter thickness of the slot 
    thSl = rs.GetReal("please, enter the thickness of the slot Sl1",0.3,0.1,)   
    # ask the user to enter height of the slot
    hSl = rs.GetReal("please, enter the height of the slot Sl1",1.3,0.5,)   

    # store base point coordiantes

    bx = BasePoint.X
    by = BasePoint.Y
    bz = BasePoint.Z

    # Validation of input
    if not (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
        # condition is met - get out of the loop and continue with script
        break
    
    print ("The thickness of the slot %s should not be smaller than the length of the cube %s" %(thSl,lCube))
    print ("and the height of the slot %s should not be smaller than the length of the cube %s" %(hSl,lCube))
    print ("and the radius of the sphere %s should not be smaller than the half side length of the cube %s" %(rSph,lCube/2))
    print ("please, repeat and make sure, that your input matches these criteria")

#conditions are met, create a clyinder
Cylinder = rs.AddCylinder(BasePoint,hCyl,rCyl,cap=True)

#conditions are met, create a cube
List1 = [[bx+lCube/2,by+lCube/2,bz+hCyl],[bx-lCube/2,by+lCube/2,bz+hCyl],[bx-lCube/2,by-lCube/2,bz+hCyl],[bx+lCube/2,by-lCube/2,bz+hCyl],[bx+lCube/2,by+lCube/2,bz+hCyl+2*rSph],[bx-lCube/2,by+lCube/2,bz+hCyl+2*rSph],[bx-lCube/2,by-lCube/2,bz+hCyl+2*rSph],[bx+lCube/2,by-lCube/2,bz+hCyl+2*rSph]]
Cube = rs.AddBox(List1)

#conditions are met, create a sphere
Sphere = rs.AddSphere([bx,by,bz+hCyl+rSph],rSph)

#conditions are met, create the slot
List2 = [[bx+rSph,by+thSl/2,bz+hCyl+2*rSph-hSl],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph-hSl],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph-hSl],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph-hSl],[bx+rSph,by+thSl/2,bz+hCyl+2*rSph],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph]]
Slot = rs.AddBox(List2)

# intersection 
Operation1 = rs.BooleanIntersection(Cube,Sphere)
# difference 
Operation2 = rs.BooleanDifference(Operation1,Slot)
# union 
input = rs.GetObjects("Select surfaces or polysurfaces to union", rs.filter.surface | rs.filter.polysurface)
if input and len(input)>1: rs.BooleanUnion(input)

if name==“main”:
abcde()

now the problem here is to make some boolean operations on the constucted shapes.
Everything works just fine except for the union operation. So I pressed F1 for the help on the “booleanunion” and just copied and pasted the code given in the help. It still doesn’t union both shapes though. This is weird, isn’t it?

Thanks again for the help.

Hello again Ahmed,

it seems that,at least for the default values of parameters, your solids do not intersect and that is why union fails!?

if you try “manually” to union them with BooleanUnion command - it fails also, but it says that parts do not intersect

BR

Hello again Alex,

I didn’t watch out for the warning message.
Yes, my “parts” don’t intersect, but from a mathematical point of view the two sets, which are being unioned, don’t have to intersect each other, do they?..

Ok, here is the code up to now:

def abcde():


# standard values for parameters
bx = 0.0 # base point coordinates
by = 0.0
bz = 0.0
lCube = 10.0    # side length of cube
rCyl = 1.0        # radius of cylinder
hCyl = 20.0    # height of cylinder
rSph = 6.0        # radius of sphere
thSl = 0.3        # thickness of slot
hSl  = 1.3        # height of slot

# start of the loop
while True:
    # ask the user to pick a base point 
    BasePoint = rs.GetPoint("Pick base point")
    if not BasePoint:
        return
    # ask the user to enter the side length for the cube
    lCube = rs.GetReal("please, enter the side length for the cube C1",10.0,1,)   
    # ask the user to enter radius of the cylinder
    rCyl = rs.GetReal("please, enter the radius of the cylinder Cl1",1.0,1,)  
    # ask the user to enter height of the cylinder
    hCyl = rs.GetReal("please, enter the height of the cylinder Cl1",20.0,1,) 
    # ask the user to enter radius of the spehere
    rSph = rs.GetReal("please, enter the radius of the spehere S1",6.0,1,)    
    # ask the user to enter thickness of the slot 
    thSl = rs.GetReal("please, enter the thickness of the slot Sl1",0.3,0.1,)   
    # ask the user to enter height of the slot
    hSl = rs.GetReal("please, enter the height of the slot Sl1",1.3,0.5,)   

    # store base point coordiantes

    bx = BasePoint.X
    by = BasePoint.Y
    bz = BasePoint.Z

    # Validation of input
    if not (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
        # condition is met - get out of the loop and continue with script
        break
    
    print ("The thickness of the slot %s should not be smaller than the length of the cube %s" %(thSl,lCube))
    print ("and the height of the slot %s should not be smaller than the length of the cube %s" %(hSl,lCube))
    print ("and the radius of the sphere %s should not be smaller than the half side length of the cube %s" %(rSph,lCube/2))
    print ("please, repeat your input and make sure, that it matches those criteria")

#conditions are met, create a clyinder
Cylinder = rs.AddCylinder(BasePoint,hCyl,rCyl,cap=True)

#conditions are met, create a cube
List1 = [[bx+lCube/2,by+lCube/2,bz+hCyl-0.01],[bx-lCube/2,by+lCube/2,bz+hCyl-0.01],[bx-lCube/2,by-lCube/2,bz+hCyl-0.01],[bx+lCube/2,by-lCube/2,bz+hCyl-0.01],[bx+lCube/2,by+lCube/2,bz+hCyl+2*rSph-0.01],[bx-lCube/2,by+lCube/2,bz+hCyl+2*rSph-0.01],[bx-lCube/2,by-lCube/2,bz+hCyl+2*rSph-0.01],[bx+lCube/2,by-lCube/2,bz+hCyl+2*rSph-0.01]]
Cube = rs.AddBox(List1)
#conditions are met, create a sphere
Sphere = rs.AddSphere([bx,by,bz+hCyl+rSph-0.01],rSph)

#conditions are met, create a slot
List2 = [[bx+rSph,by+thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx+rSph,by+thSl/2,bz+hCyl+2*rSph-0.01],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph-0.01],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph-0.01],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph-0.01]]
Slot = rs.AddBox(List2)


# intersection 
Operation1 = rs.BooleanIntersection(Cube,Sphere)
# difference 
Operation2 = rs.BooleanDifference(Operation1,Slot)
# union 
List3 = (Cylinder,Operation2)
Result = rs.BooleanUnion(List3)

# Transformation to CPlane 
# the construction plane of active viewport
# get construction plane from view
# define a coordiante transformation matrix
# apply transformation on final object

***** MAIN ***********

if name==“main”:
abcde()

I let the objects (cylinder, sphere and cube) intersect and after that the union operation has worked out fine. So thanks for the hint.

Now my last problem to conquer this exercise is to know a little bit more about the construction planes (cplanes).

I have read some stuff here and there and have also watched a couple of youtube videos on what are cplanes and how this works within rhino.

In the last part of the code, I should “somehow” use the commands [ChangeBasis] and [TransformObjects] …

The longitudinal orientation of the cylinder of the resulting object shall be normal to the construction plane of the currently active viewport.

In order for me to get that done, I need some hints to start with … Thanks!

[
Here is what I have tried so far (,which doesn’t work yet…):

# define a coordiante transformation matrix
initial_plane = rs.ViewCPlane()
final_plane = rs.PlaneFromNormal(BasePoint,[0,0,hCyl])
rs.XformChangeBasis(initial_plane, final_plane)

]

the result should be, that regardless how the cplane is oriented, after performing the code, it should always look like that:

Ok, Alex. I got that already!!!

Import statements

import Rhino as rhinoRef
import Rhino.Geometry as rg
import rhinoscriptsyntax as rs
import math as m
import scriptcontext as sc

def abcde():

# Parameters

bx = 0.0 # base point coordinates
by = 0.0
bz = 0.0
lCube = 10.0    # side length of cube
rCyl = 1.0        # radius of cylinder
hCyl = 20.0    # height of cylinder
rSph = 6.0        # radius of sphere
thSl = 0.3        # thickness of slot
hSl  = 1.3        # height of slot

# start of the loop
while True:

    # ask the user to pick a base point 
    BasePoint = rs.GetPoint("Pick base point")
    if not BasePoint:
        return
    # ask the user to enter the side length for the cube
    lCube = rs.GetReal("please, enter the side length for the cube C1",10.0,1,)   
    # ask the user to enter radius of the cylinder
    rCyl = rs.GetReal("please, enter the radius of the cylinder Cl1",1.0,1,)  
    # ask the user to enter height of the cylinder
    hCyl = rs.GetReal("please, enter the height of the cylinder Cl1",20.0,1,) 
    # ask the user to enter radius of the spehere
    rSph = rs.GetReal("please, enter the radius of the spehere S1",6.0,1,)    
    # ask the user to enter thickness of the slot 
    thSl = rs.GetReal("please, enter the thickness of the slot Sl1",0.3,0.1,)   
    # ask the user to enter height of the slot
    hSl = rs.GetReal("please, enter the height of the slot Sl1",1.3,0.5,)   

    # store base point coordiantes

    bx = BasePoint.X
    by = BasePoint.Y
    bz = BasePoint.Z

    # Validation of input
    if not (thSl < lCube and hSl < lCube and rSph >= lCube/2) == False:
        # condition is met - get out of the loop and continue with script
        break
    
    print ("The thickness of the slot %s should not be smaller than the length of the cube %s" %(thSl,lCube))
    print ("and the height of the slot %s should not be smaller than the length of the cube %s" %(hSl,lCube))
    print ("and the radius of the sphere %s should not be smaller than the half side length of the cube %s" %(rSph,lCube/2))
    print ("please, repeat your input and make sure, that it matches those criteria")

#conditions are met, create a clyinder
Cylinder = rs.AddCylinder(BasePoint,hCyl,rCyl,cap=True)

#conditions are met, create a cube
List1 = [[bx+lCube/2,by+lCube/2,bz+hCyl-0.01],[bx-lCube/2,by+lCube/2,bz+hCyl-0.01],[bx-lCube/2,by-lCube/2,bz+hCyl-0.01],[bx+lCube/2,by-lCube/2,bz+hCyl-0.01],[bx+lCube/2,by+lCube/2,bz+hCyl+2*rSph-0.01],[bx-lCube/2,by+lCube/2,bz+hCyl+2*rSph-0.01],[bx-lCube/2,by-lCube/2,bz+hCyl+2*rSph-0.01],[bx+lCube/2,by-lCube/2,bz+hCyl+2*rSph-0.01]]
Cube = rs.AddBox(List1)
#conditions are met, create a sphere
Sphere = rs.AddSphere([bx,by,bz+hCyl+rSph-0.01],rSph)

#conditions are met, create a slot
List2 = [[bx+rSph,by+thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph-hSl-0.01],[bx+rSph,by+thSl/2,bz+hCyl+2*rSph-0.01],[bx-rSph,by+thSl/2,bz+hCyl+2*rSph-0.01],[bx-rSph,by-thSl/2,bz+hCyl+2*rSph-0.01],[bx+rSph,by-thSl/2,bz+hCyl+2*rSph-0.01]]
Slot = rs.AddBox(List2)

# intersection 
Operation1 = rs.BooleanIntersection(Cube,Sphere)
# difference 
Operation2 = rs.BooleanDifference(Operation1,Slot)
# union 
List3 = (Cylinder,Operation2)
Result = rs.BooleanUnion(List3)

# Transformation to CPlane 
view = sc.doc.Views.ActiveView
if not view: return
# get construction plane from view
initial_plane = rs.ViewCPlane()
# define a coordiante transformation matrix
final_plane = rs.PlaneFromNormal(BasePoint,[0,0,hCyl])
matrix = rs.XformChangeBasis(initial_plane, final_plane)
# apply transformation on final object of csg
rs.TransformObject(Result,matrix,False)

***** MAIN ***********

if name==“main”:

abcde()

It’s done! finished!