Objective
A tutorial on Cellular Automata and PolyMedia Pixel using Rhino.Python
To develop a cellular automata (Conway's Game of Life) simulation in Rhino.Python.
Pramod Parajuli University of Technology, Sydney 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
Agenda ! Algorithm ! Implementation
! ! ! Rhino.Python Cellular Automata Polymedia Pixel
Algorithm
Python, Rhino.Python Cellular Automata Implementation Finalization
! Finalization
! ! Programming style Toolbar creation for UI
Pramod Parajuli, 2011 Cellular Automata & PolyMedia Pixel using Rhino.Python
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata (Conway's Game of Life) In an unlimited universe, there are four(4) basic rules for a cell;
! ! ! ! Any live cell with fewer than two live neighbours dies, as if caused by underpopulation. Any live cell with two or three live neighbours lives on to the next generation. Any live cell with more than three live neighbours dies, as if by overcrowding. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
Cellular Automata (Conway's Game of Life)
In simple terms;
! ! ! ! If already ALIVE and < 2 neighbours, then DIE If already ALIVE and neighbours = 2 or 3, then LIVE If already ALIVE and > 3 neighbours, then DIE If already DEAD and exactly 3 neighbours, then LIVE
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
GoL - practice
Algorithm
Python, Rhino.Python
Cellular Automata Implementation Finalization
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Python quick reference Lists
>>> a = [1, 2, 3]
>>> print(a)
[1, 2, 3]
>>> a[2] = 5
>>> print(a)
[1, 2, 5]
>>> sum(a)
8
Cellular Automata & PolyMedia Pixel using Rhino.Python
Python quick reference Why lists?
>>> world = [
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0] ]
>>> b = a
>>> a[2] = 10
>>> print(b)
???
>>> b = a[:]
>>> a[2] = 30
>>> print(b)
???
Pramod Parajuli, 2011
>>> print(world)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
Python quick reference for loops
>>> for i in world:
print I
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 1, 0, 0]
[0, 0, 0, 0, 0]
10
Python quick reference Why for loop?
>>> for aRow in world:
for aCol in aRow:
countNeighbours(aRow, aCol)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 2 0 0 1 1 1 0 1 1 2 1 0 0 0 0 0 0 1 2 3 2 0 0 0 0 0 0 0 0 0 0 0
11
>>> c = [ [1, 2, 3], [4, 5, 6]]
>>> len(c)
???
>>> zip(*c)
???
>>> b = [1, 2, 3]
>>> sum(b)
>>> len(b)
Cellular Automata & PolyMedia Pixel using Rhino.Python
What is countNeighbours ?? We will revisit it later.
Pramod Parajuli, 2011 Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Python quick reference Functions
>>> def add(x, y):
return x+y
>>> p = 10
>>> q = 5
>>> add(p, q)
15
Cellular Automata & PolyMedia Pixel using Rhino.Python
12
Python quick reference
More on slices
>>> world[1:2]
[[0, 0, 1, 0, 0 ]]
>>> z = [1, 2, 3, 4, 5]
>>> z[1:4]
???
>>> z[1:4][1]
???
Cellular Automata & PolyMedia Pixel using Rhino.Python
13
>>> p = 10
>>> q = 5
>>> add(p, q)
???
For our world, we need to select only 8 cells around current cell. How to select? We select 3x3 slice and remove the one at the centre. en sum all the 1s in the slice. at will give us the no. of neighbours in the surrounding of a cell.
Pramod Parajuli, 2011
Functions from libraries
>>> import math
>>> math.sin(30 * math.pi / 180)
Pramod Parajuli, 2011
Rhino.Python
Some examples First.py
import rhinoscriptsyntax as rs
rs.AddPoint([1,2,3])
center = [20, 0, 0]
radius = 5
rs.AddSphere(center, radius)
" "
Cellular Automata & PolyMedia Pixel using Rhino.Python
14
Rhino.Python drawSine.py
# settin z to a scaled value with intercept
z = math.sin(currentRadian) * 70
x = currentAngle
y = currentAngle
drawEnd = [x, y, z]
rs.AddLine(drawStart, drawEnd)
drawStart = drawEnd
import rhinoscriptsyntax as rs
import math
def drawSineWave():
print 'Drawing sine wave'
sineHeight = rs.GetReal("Please enter height:")
x = -30
y = -30
z = math.sin(-30 * math.pi / 180.0) * 70
drawStart = [x, y, z]
for currentAngle in range(-90, 90):
currentRadian = currentAngle * math.pi / 180.0
Cellular Automata & PolyMedia Pixel using Rhino.Python
15
Second.py
import rhinoscriptsyntax as rs
rs.EnableRedraw(False)
for i in range(0, 50):
if(i%5 == 0):
else:
rs.AddPoint([i, 0, 0])
rs.AddSphere([i, 0, 0], 0.5)
drawBox.py - demo
rs.EnableRedraw(True)
Pramod Parajuli, 2011
Pramod Parajuli, 2011
Rhino.Python Some bits for Classes and objects
import rhinoscriptsyntax as rs
import math
# lets create a class Tutorial
class Tutorial:
def __init__(self, _title, _curveA, _curveB):
self.title = _title
self.curveA = _curveA
self.curveB = _curveB
def displayName(self):
displayString = 'Title of this object is ' + self.title
print(displayString)
def drawEdgeSurface(self):
surface = rs.AddEdgeSrf([self.curveA, self.curveB])
rs.ObjectColor(surface, [0xff, 0x90, 0xc0])
Cellular Automata & PolyMedia Pixel using Rhino.Python
16
def main():
rstCurve = rs.GetObject("Select rst curve")
secondCurve = rs.GetObject("Select second curve")
# creating instance of Tutorial newCurve
# We will be using this instance holds the data about
# curves and also can execute its function on the data.
newCurve = Tutorial('Curve drawing tutorial',
rstCurve, secondCurve)
newCurve.displayName()
newCurve.drawEdgeSurface()
if( __name__ == '__main__' ):
main()
Pramod Parajuli, 2011
Drawing pseudo-surface using lines between curves
Draw 2 curves Divide curves into slices Get the end points of the slices Connect the points with lines
17
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
Draw pseudo-surface using lines between curves
import rhinoscriptsyntax as rs
class CurveLine:
def __init__(self, _strCurveA, _strCurveB, _numSlices):
self.strCurveA = _strCurveA
self.strCurveB = _strCurveB
self._numSlices = _numSlices
def drawLines(self):
ptsCurveA = rs.DivideCurve(self.strCurveA, self._numSlices, True, True)
ptsCurveB = rs.DivideCurve(self.strCurveB, self._numSlices, True, True)
counter = 0
for everyPOint in ptsCurveA:
rs.AddLine( ptsCurveA[counter], ptsCurveB[counter])
counter += 1
def main():
rstCurve = rs.GetObject("Pick rst curve", 4)
secondCurve = rs.GetObject("Pick second curve", 4)
newSurface = CurveLine(rstCurve, secondCurve, 100)
newSurface.drawLines()
Cellular Automata & PolyMedia Pixel using Rhino.Python
18
Draw pseudo-surface using curves between curves
Draw 3 curves (2 for end edge and 1 for control point Divide all curves into slices Get the endpoints of slices in three di erent lists Form new curves from three points in three lists Use these three points as control points to draw a curve Repeat for all points
19
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Draw pseudo-surface using curves between curves
class CurveSurface:
def __init__(self, _strCurveA, _strCurveB, _strCurveC, _numSlices):
self.strCurveA = _strCurveA
# similarly, create strCurveB, strCurveC
self._numSlices = _numSlices
def drawCurvesBetween(self):
ptsCurveA = rs.DivideCurve(self.strCurveA, self._numSlices, True, True)
# similarly, divide strCurveB, strCurveC
counter = 0
for everyPOint in ptsCurveA:
rs.AddCurve( [ptsCurveA[counter], ptsCurveB[counter], ptsCurveC[counter]])
counter += 1
def main():
rstCurve = rs.GetObject("Pick rst curve", 4)
secondCurve = rs.GetObject("Pick second curve", 4)
thirdCurve = rs.GetObject("Pick third curve", 4)
newSurface = CurveSurface(rstCurve, secondCurve, thirdCurve, 100)
newSurface.drawCurvesBetween()
Cellular Automata & PolyMedia Pixel using Rhino.Python
20
Draw surfaces using EdgeSurface between curves
Draw curves between curves as in previous example Draw EdgeSurface in between those curves
21
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Draw surfaces using EdgeSurface between curves
def drawSurfaceBetween(self):
ptsCurveA = rs.DivideCurve(self.strCurveA, self.numSlicesL, True, True)
ptsCurveB = rs.DivideCurve(self.strCurveB, self.numSlicesL, True, True)
ptsCurveC = rs.DivideCurve(self.strCurveC, self.numSlicesL, True, True)
counter = 0
previousCurve = rs.AddCurve([ptsCurveA[counter], ptsCurveB[counter], ptsCurveC[counter]])
counter += 1
for everyPOint in ptsCurveA:
currentCurve = rs.AddCurve( [ptsCurveA[counter], ptsCurveB[counter], ptsCurveC[counter]])
currentSurface = rs.AddEdgeSrf([previousCurve, currentCurve])
rs.ObjectColor(currentSurface, [counter+70, counter + 150, counter + 200])
previousCurve = currentCurve
counter += 1
Cellular Automata & PolyMedia Pixel using Rhino.Python
22
23
Algorithm Python, Rhino.Python
Cellular Automata Implementation
Polymedia Pixel
Finalization
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata (Conway's Game of Life) e algorithm:
! ! ! ! If already ALIVE and < 2 neighbours, then DIE If already ALIVE and neighbours = 2 or 3, then LIVE If already ALIVE and > 3 neighbours, then DIE If already DEAD and exactly 3 neighbours, then LIVE
24
Cellular Automata (Conway's Game of Life) Requirements data structures
! ! ! ! ! List to hold state of life of cells, lets say world[][]
List to hold neighbour count of every cell, lets say neighbours[][]
List to work for counting and deciding the life state for next stage, lets say buffer[][]
Size of the world worldSize
Boundary of the world in Rhino3d can be de ned as starting from (worldSize/2) to +(worldSize/2) in XY plane rangeX = worldSize/2
rangeY = worldSize/2
25
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata (Conway's Game of Life) Requirements - functions
! ! ! ! ! A function to create empty list for world, neighbours, and buffer __init__(worldSize)
A function to ll initial life states randomly in world - llRandomLives
A function to ll initial number of neighbour in neighbours llRandomNeighbours
A function to count neighbours given the cell location countNeighbours(row, col)
A function to count neighbours of all cells by calling countNeighbours(row, col) iteratively countAllNeighbours
26
Cellular Automata (Conway's Game of Life) Requirements - functions
! A function to decide state of cells for next phase using cellular automata rules and update it in buffer decideLife
! Check state of cell from world
! Check neighbour count from neighbours
! ! Decide next state of the cell Write the state to buffer
27
! !
A function to update graphics on the Rhino3d according to life states in buffer - updateGraphics
A function to update world from buffer - updateGraphics
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Cellular Automata (Conway's Game of Life) Requirements functions
! ! ! ! ! A function to count neighbours given the cell location countNeighbours(row, col)
A function to count neighbours of all cells by calling countNeighbours(row, col) iteratively countAllNeighbours
28
29
Algorithm Python, Rhino.Python Cellular Automata Implementation
A function to draw box on the Rhino 3D drawBox(basePoint, length, width, height, objColor)
A function to add two lists numerically by elements (used by drawBox) addLists(list1, list2)
A main program to de ne thread of control - main
Pramod Parajuli, 2011 Cellular Automata & PolyMedia Pixel using Rhino.Python
Polymedia Pixel
Finalization
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
PolyMedia Pixel Spreading a component object over di erent types of surfaces (polysurface, opensurface) Di erent tasks required to be done to accomplish it
Join and explode surfaces Evaluate surface to retrieve points Explode meshes or mesh objects into sub-meshes Playing with layers Surface normal, and object orientation
30
PolyMedia Pixel Joining surfaces
import rhinoscriptsyntax as rs
objs = []
surface1 = rs.GetObject('Select rst surface', rs.lter.surface)
surface2 = rs.GetObject('Select second surface', rs.lter.surface)
objs.append(surface1)
objs.append(surface2)
rs.JoinSurfaces(objs, True)
Cellular Automata & PolyMedia Pixel using Rhino.Python
31
Other utility functions such as view and plane for orientation, boundingbox for scaling etc.
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
Pramod Parajuli, 2011
PolyMedia Pixel Exploding poly-surface and mesh
import rhinoscriptsyntax as rs
newsurface = rs.GetObject("Select a poly-surface object,
rs.lter.polysurface)
objs = rs.ExplodePolysurfaces(newsurface)
rs.MoveObjects(objs, [20, 0, 0])
# similarly, we can explode mesh objects
newmesh = rs.GetObject("Select a mesh object", rs.lter.mesh)
meshobjs = rs.ExplodeMeshes(newmesh)
rs.MoveObjects(meshobjs, [20, 0, 0])
32
PolyMedia Pixel Evaluate surface (Divide surface)
33
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
PolyMedia Pixel Evaluate surface (Divide surface)
def DivideSlab(srf, divisions):
domain0 = rs.SurfaceDomain(srf, 0)
domain1 = rs.SurfaceDomain(srf, 1)
for i in range(divisions+1):
u = domain0[0] + (domain0[1]-domain0[0])*i/divisions
for j in range(divisions+1):
v = domain1[0] + (domain1[1]-domain1[0])*j/divisions
point = rs.EvaluateSurface(srf,u,v)
drawBox(point, 100, 100, 20, [0x00, 0x90, 0xC0])
34
PolyMedia Pixel Layers
srf = rs.GetObject("Select poly-surface to divide")
oldLayer = rs.ObjectLayer(srf)
newLayer = rs.AddLayer("dotsLayer")
rs.LayerVisible(newLayer, False)
rs.EnableRedraw(False)
# explode current polysurface into small surfaces rst
objSurfaces = rs.ExplodePolysurfaces(srf)
rs.CurrentLayer(newLayer)
" "
Cellular Automata & PolyMedia Pixel using Rhino.Python
35
for aSurface in objSurfaces:
DivideSlab(aSurface, 5, newLayer)
rs.LayerVisible(newLayer, True)
rs.EnableRedraw(True)
rs.LayerVisible(oldLayer, False)
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Pramod Parajuli, 2011
PolyMedia Pixel Surface normal
import rhinoscriptsyntax as rs
obj = rs.GetObject("Select a surface", rs.lter.surface)
if obj:
point = rs.GetPointOnSurface(obj)
if point:
param = rs.SurfaceClosestPoint(obj, point)
normal = rs.SurfaceNormal(obj, param)
rs.AddPoints( [point, point + normal] )
Cellular Automata & PolyMedia Pixel using Rhino.Python
36
PolyMedia Pixel Object orientation
import rhinoscriptsyntax as rs
obj = rs.GetObject("Select object to orient")
if obj:
reference = rs.GetPoints(message1="First reference point")
if reference and len(reference)>0:
target = rs.GetPoints(message1="First target point")
if target and len(target)>0:
rs.OrientObject( obj, reference, target )
37
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
PolyMedia Pixel Object orientation on surface demo
Cellular Automata & PolyMedia Pixel using Rhino.Python
38
PolyMedia Pixel e algorithm for poly-pixel implementation
Select component object Select surface
39
Check surface type If surface is poly-surface, explode and retain all open surfaces, if not will have only one open surface For all open surface/s, evaluate the surface according to no. of slice user want to do Ask user whether to scale component or not, scale accordingly Make copies of the component object, move them to center of all the evaluated point on the surface, then orient them to surface normal
Pramod Parajuli, 2011 Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
40
Finalizing
Creating custom toolbar to run script
Edit the icon.
41
Algorithm Python, Rhino.Python Cellular Automata Implementation Polymedia Pixel
Right click on the empty space by the Provide button text and tooltip text.
side of existing tabs Click Insert Toolbar In Select Toolbar box, click New Provide name to the toolbar RhinoTutorial Now you can see newly created toolbar.
"
In the macro library, select New Macro In the command box: include followings:
!-_RunPythonScript ("
# your python code here
)
Finalization
Shift+right click on the icon in the
toolbar.
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Pramod Parajuli, 2011
Finalizing Comments in the source-code
Use # to begin single comments Use to begin and end multiple line comments
----------------------------
Program :
<XYZ>
Description:
<This program is creates >
By:
<Your name>
Date:
31/10/2011
Revision:
1/11/2011 Added new feature
2/11/2011 Optimized function foo etc.
------------
import rhinoscriptsyntax as rs
# YOUR CODE STARTS HERE
# For Classes, Functions, Special data structures also, write their name, description, return values etc.
Cellular Automata & PolyMedia Pixel using Rhino.Python
42
Pramod Parajuli, 2011