Installation of GhPython, and introduction of list and for.

Installation of GhPython

  1. Download GhPython 0.5.1.0 (GhPython.gha) from http://www.food4rhino.com/project/ghpython
  2. Run Rhino 5. (Make sure you are running Rhino 5. GhPython does not work with Rhino 4)
  3. Command:Grasshopper -> File -> Special Folders -> Components Folder
  4. Copy (or move) the GhPython.gha file to the specified Components Folder
  5. Restart Rhino 5.
  6. Command:Grasshopper
  7. Check if there is a new component "Python Script" in the Script group in the Math tab.

First Python program with GhPython

Command:Grasshopper->Maths->Script->Python
Place a Python component in the GH document.
Double click the component and type

import sys
print sys.version
print sys.subversion
print sys.version_info

Hit the Test button.
Check if the output is
|2.7.0 ()
|
|('IronPython', '', '')
|
|(2, 7, 0, 'beta', 0)

Congraturation :)

A python component outputs the strings being output by "print" functions to the "out" slot.

First Program with RhinoPython

Close the GH.
Command:EditPythonScript
Type

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
rs.AddPoint(0,0,0)
rs.AddPoint([10,0,0])
rs.AddLine([0,0,0],[10,0,0])
rs.AddLine(rg.Point3d(0,0,10),rg.Point3d(10,0,10))

and run.
01.jpg

import syntax

"import LooongTeeerm as b" has two functionality.

  • defines an alias of LooongTeeerm (it is b).
  • import the module "LooongTeeerm".

From the practical point of view, import syntax is very important in that it roughly classifies the script codes.

Polymorphism

rs.AddPoints(x,y,z) and rs.AddPoints(a list of 3 values) provides the same functionality.
This is called Polymorphism.
rs.AddLine(a list of 3 values,a list of 3 values) and rs.AddLines(Point3d,Point3d) are also the Polymorphism case.
Polymorphism is not automatic. rs.AddLine(x1,y1,z1,x2,y2,z2) causes an error simply because this is not defined internally. Therefore, read the documents.

List

[0,0,0] is treated as a list type object which has 3 elements.
Note that [0,0,0] itself is treated as one object by Python.
If you want to start with empty list, you can write

newList=list()

Nested List

Try

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
rs.AddPoints([[0,10,0],[10,10,0],[20,10,0]])
rs.AddPolyline([[0,0,0],[10,10,0],[20,0,0]])
rs.AddPoints([rg.Point3d(0,10,10),rg.Point3d(10,10,10),rg.Point3d(20,10,10)])
rs.AddPolyline([[0,0,10],[10,10,10],[20,0,10]])

[[0,10,0],[10,10,0],[20,10,0]] is treated as a list object which has 3 elements.
Each element is also a list object which has 3 elements.
An rs.AddSomethingPlural() only takes a list object as an input because the number of elements is variable.

Variables and ids

If you use the rhinoscriptsyntax module, every geometric element (except vectors) is manipulated via "id".

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
start=rs.AddPoint(0,0,0)
p1=rs.AddPoint(2,0,0)
p2=rs.AddPoint(4,0,0)
p3=rs.AddPoint(6,0,0)
p4=rs.AddPoint(8,0,0)
end=rs.AddPoint(10,0,0)
extra=rg.Point3d(12,0,0)
print type(start)
print type(extra)
rs.DeleteObject(p3)
rs.DeleteObject(p4)

Note that "print type(start)" returns
|<type 'Guid'>
Guid is a "Global Unique Identifier" that specifies an object added in the Rhino document.
rs.AddPoint returns the id of the newly added Point3d object.
On the contrary, Point3d() returns a new Point3d object but it is not added to the Rhino document automatically.
Note that "print type(extra)" returns
|<type 'Point3d'>
and no point can be found at the coordinate (12,0,0).

Loop

Even the functionality of "for" syntax in Python is mostly same as Java or C++, it is super different. (It is 99% same as "foreach" syntax in Java or C#)
The syntax of for in Python is

for object in [object1, object2,...]:
    do something to/with each object.

Python is indent sensitive
':' implies indented block followed by ':'

For example…

import rhinoscriptsyntax as rs
start=rs.AddPoint(0,0,0)
end=rs.AddPoint([10,0,0])
divide=20
vec=rs.VectorCreate(end,start)
vec=rs.VectorDivide(vec,divide)
centerList=list()
 
for i in range(divide):
    newVec=rs.VectorScale(vec,i)
    centerList.append(rs.CopyObject(start,newVec))
for center in centerList:
    rs.AddCircle(center,2.0)

04.jpg

empty list and member functions of list

if you want to start with an empty list, you can write

a=[]  #or
a=list()
a.append(0)
a.append(1)
a.append(2)
print(a)

Type "list.", then you can see the member list of the list type.

range() function

range() is provided in order to let 'for' works as the usual for.
Try

for i in range(10):
    print i,
print ""
for i in range(1,10):
    print i,
print ""
for i in range(1,10,2):
    print i,
print ""
for i in range(1,11,2):
    print i,
print ""
for i in range(1,12,2):
    print i,

',' can disable starting a new line.
Here are some notes;
  • range() can only take integers.
  • rs.frange() is also provided for floating numbers.

How to make it faster

Unfortunately, rhinoscriptsyntax always calls redraw.
You can disable this and can make your code faster.

import rhinoscriptsyntax as rs
start=rs.AddPoint(0,0,0)
end=rs.AddPoint([10,0,0])
divide=20
vec=rs.VectorCreate(end,start)
vec=rs.VectorDivide(vec,divide)
centerList=list()
rs.EnableRedraw(False)
for i in range(divide):
    newVec=rs.VectorScale(vec,i)
    centerList.append(rs.CopyObject(start,newVec))
for center in centerList:
    rs.AddCircle(center,2.0)
rs.EnableRedraw(True)
rs.Redraw()

Rewriting the code in an interactive fashion

import rhinoscriptsyntax as rs
rs.EnableRedraw(False)
start=rs.GetPoint("Start point?")
end=rs.GetPoint("End point?")
divide=rs.GetInteger("Division number?")
vec=(end-start)/(divide-1)
centerList=list()
for i in range(divide):
    newVec=vec*i
    centerList.append(rs.AddPoint(start+newVec))
for center in centerList:
    rs.AddCircle(center,2.0)
rs.EnableRedraw(True)

rs.GetSomegeometry() returns a Rhino.Geometry object.
Note that rs.VectorDivide(vec,divide-1) does not replace vec and just returns a new Vector3d. Therefore, the new Vecto3d must be substituted to 'vec'.

Operators

The arithmetic operators, +-*/, are sometimes defined for non-number objects.
For example,

  • Point3d-Point3d returns a Vector3d.
  • Vector3d/Number returns a Vector3d.
  • Point3d+Vector3d returns a Point3d.

These definitions of operators are not automatic. Only if they are defined (provided by a module), you can use it. Therefore, read the documents!
Internally, the functionality of these operators are provided by Add() Subtract(), Multiply() and Divide() functions. If they are provided in an object, you can use +-*/ operators for that object.

Let's move on to GhPython

For the rhinoscriptsyntax users

Set up x,y,N as inputs. (Zoom in to the Python component and click '+').
Specify x and y as ghdoc Objects by clicking the Type hint.
Specify N as 'int' by clicking the Type hint.
Connect two point parameters with x and y.
Connect integer slider with N.
Set up the integer slider as
min:0
max:30
14.png

import rhinoscriptsyntax as rs
if N<1:
    exit
vec=rs.VectorCreate(y,x)
vec=rs.VectorDivide(vec,N-1)
centerList=list()
a=list()
for i in range(N):
    newVec=rs.VectorScale(vec,i)
    centerList.append(rs.CopyObject(x,newVec))
for center in centerList:
    a.append(rs.AddCircle(center,2.0))

Try moving the start and end points.
Congraturation :)
05.jpg

For the Rhino.Geometry users

Prepare x,y,N as inputs. (Zoom in to the Python component and click '+').
Specify x and y as Point3d by clicking the Type hint.
Specify N as 'int' by clicking the Type hint.
Connect two point parameters with x and y.
Connect integer slider with N.
Set up the integer slider as
min:0
max:30

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
if N<1:
    exit
vec=(y-x)/(N-1)
centerList=list()
a=list()
for i in range(N):
    newVec=vec*i
    centerList.append(x+newVec)
for center in centerList:
    a.append(rg.Circle(center,2.0))

Extending the code

15.png
#inputs:x,y,N,shape
#x,y:Point3d
#N:Integer
#shape: general shape (rhinoscriptsyntax)
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
if N<1:
    exit
vec=(y-x)/(N-1)
centerList=list()
a=list()
b=list()
for i in range(N):
    newVec=vec*i
    centerList.append(x+newVec)
for center in centerList:
    a.append(rs.MoveObject(rs.CopyObject(shape),center))

06.jpg

Some notes

Dynamic Typing

Python has powerful dynamic typing features. It is also cAsE sensitive.

  • a=1 # the type of "a" is determined as integer because of the rhs.
  • a=2 # a is overrode.
  • A=3 # now, a=2 and A=3 exist.
  • a="string" #the type of a has been changed (this is what dynamic means)
  • A=a[1] # now A becomes a letter 't'.

Comments

'#' comments out the characters which follows after '#'

member functions of list type

The members of a type is called attributes in Python word.

a=[1,2,5]
for i in a:
    print i,

The index starts from '0' as well as C++ or Java.

a=[1,2,5]
print a[0],
print a[1],
print a[2]

append(object) adds objects to the end of a list.
the types of the elements in one list don't need to be identical.

a=list()
a.append(1)
a.append(2)
a.append(5)
for i in a:
    print i,

You may get the same result as the previous one.

pop(i) function deletes the i-th element.

a=[1,2,5]
a.pop(1)
for i in a:
    print i,

remove(object) deletes the first element in a list which matches with the specified object

a=[1,2,5]
a.remove(2)
for i in a:
    print i,

del(element) deletes the element from the list in which the specified element is contained

a=[1,2,5]
del(a[1])
for i in a:
    print i,

slices of a list

a=[1,2,3,4,5]
print a[2:]
print a[:2]
print a[:2]+a[2:]
print a[2:4]
print a[:-2]