Post on 28-Nov-2014
description
A tutorial on Cellular Automata and PolyMedia Pixel using Rhino.Python
Pramod Parajuli University of Technology, Sydney
2011
Cellular Automata & PolyMedia Pixel using Rhino.Python
Objective
To develop a cellular automata (Conway's Game of Life) simulation in Rhino.Python.
Pramod Parajuli, 2011
1
Agenda
! Algorithm
! Implementation ! Rhino.Python ! Cellular Automata ! Polymedia Pixel
! Finalization ! Programming style ! Toolbar creation for UI
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
2
Cellular Automata & PolyMedia Pixel using Rhino.Python
Algorithm Python, Rhino.Python
Cellular Automata Implementation
Finalization
Pramod Parajuli, 2011
3
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 under-population.
! 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 & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
4 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
5
GoL - practice
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
6
Cellular Automata & PolyMedia Pixel using Rhino.Python
Algorithm
Python, Rhino.Python Cellular Automata Implementation
Finalization
Pramod Parajuli, 2011
7
Python – quick reference
Lists >>> a = [1, 2, 3]
>>> print(a)
[1, 2, 3]
>>> a[2] = 5
>>> print(a)
[1, 2, 5]
>>> sum(a)
8
>>> b = a
>>> a[2] = 10
>>> print(b)
???
>>> b = a[:]
>>> a[2] = 30
>>> print(b)
??? Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
8 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] ]
>>> print(world)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
9
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]
>>> b = [1, 2, 3]
>>> sum(b)
>>> len(b)
>>> c = [ [1, 2, 3], [4, 5, 6]]
>>> len(c)
???
>>> zip(*c)
???
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
10 Python – quick reference
Why ‘for’ loop?
>>> for aRow in world:
for aCol in aRow:
countNeighbours(aRow, aCol)
What is ‘countNeighbours’ ?? We will revisit it later.
Cellular Automata & PolyMedia Pixel using Rhino.Python
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
0 1 1 1 0
0 2 1 2 0
0 3 2 3 0
0 2 1 2 0
0 0 0 0 0
Pramod Parajuli, 2011
11
Python – quick reference
Functions
>>> def add(x, y):
return x+y
>>> p = 10
>>> q = 5
>>> add(p, q)
15
>>> p = “10”
>>> q = “5”
>>> add(p, q)
???
Functions from libraries
>>> import math
>>> math.sin(30 * math.pi / 180)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
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]
???
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 ‘1’s in the slice.
!at will give us the no. of neighbours in the surrounding of a cell.
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
13
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)
""
Second.py import rhinoscriptsyntax as rs
rs.EnableRedraw(False)
for i in range(0, 50):
if(i%5 == 0):
rs.AddSphere([i, 0, 0], 0.5)
else:
rs.AddPoint([i, 0, 0])
rs.EnableRedraw(True)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
14 Rhino.Python
drawSine.py 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
# 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
drawBox.py - demo
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
15
Rhino.Python
Some bits for Classes and objects import rhinoscriptsyntax as rs import math # let’s 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])
def main(): firstCurve = rs.GetObject("Select first 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',
firstCurve, secondCurve) newCurve.displayName() newCurve.drawEdgeSurface() if( __name__ == '__main__' ): main()
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
16 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
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
17
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(): firstCurve = rs.GetObject("Pick first curve", 4) secondCurve = rs.GetObject("Pick second curve", 4) newSurface = CurveLine(firstCurve, secondCurve, 100) newSurface.drawLines()
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
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 Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
19
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(): firstCurve = rs.GetObject("Pick first curve", 4) secondCurve = rs.GetObject("Pick second curve", 4) thirdCurve = rs.GetObject("Pick third curve", 4) newSurface = CurveSurface(firstCurve, secondCurve, thirdCurve, 100) newSurface.drawCurvesBetween()
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
20 Draw surfaces using EdgeSurface between curves
Cellular Automata & PolyMedia Pixel using Rhino.Python
• Draw curves between curves as in previous example
• Draw EdgeSurface in between those curves
Pramod Parajuli, 2011
21
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 Pramod Parajuli, 2011
22
Cellular Automata & PolyMedia Pixel using Rhino.Python
Algorithm
Python, Rhino.Python
Cellular Automata Implementation Polymedia Pixel
Finalization
Pramod Parajuli, 2011
23
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
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
24 Cellular Automata (Conway's Game of Life) Requirements – data structures
! List to hold state of life of cells, let’s say – world[][]
! List to hold neighbour count of every cell, let’s say – neighbours[][]
! List to work for counting and deciding the life state for next stage, let’s 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
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
25
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 - fillRandomLives
! A function to #ll initial number of neighbour in neighbours - fillRandomNeighbours
! 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
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
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
! A function to update graphics on the Rhino3d according to life states in buffer - updateGraphics
! A function to update world from buffer - updateGraphics Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
27
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
! 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 Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
28
Cellular Automata & PolyMedia Pixel using Rhino.Python
Algorithm
Python, Rhino.Python
Cellular Automata Implementation
Polymedia Pixel Finalization
Pramod Parajuli, 2011
29
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 • Other utility functions such as view and plane for orientation, boundingbox
for scaling etc.
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
30 PolyMedia Pixel
Joining surfaces import rhinoscriptsyntax as rs
objs = []
surface1 = rs.GetObject('Select first surface', rs.filter.surface)
surface2 = rs.GetObject('Select second surface', rs.filter.surface)
objs.append(surface1)
objs.append(surface2)
rs.JoinSurfaces(objs, True)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
31
PolyMedia Pixel Exploding poly-surface and mesh import rhinoscriptsyntax as rs
newsurface = rs.GetObject("Select a poly-surface object”,
rs.filter.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.filter.mesh)
meshobjs = rs.ExplodeMeshes(newmesh)
rs.MoveObjects(meshobjs, [20, 0, 0])
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
32 PolyMedia Pixel Evaluate surface (Divide surface)
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
33
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])
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
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 first objSurfaces = rs.ExplodePolysurfaces(srf) rs.CurrentLayer(newLayer) ""
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
35
PolyMedia Pixel
Surface normal
import rhinoscriptsyntax as rs obj = rs.GetObject("Select a surface", rs.filter.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 Pramod Parajuli, 2011
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 )
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
37
PolyMedia Pixel
Object orientation on surface demo
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
38 PolyMedia Pixel
!e algorithm for poly-pixel implementation • Select component object • Select surface • 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
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
39
Cellular Automata & PolyMedia Pixel using Rhino.Python
Algorithm
Python, Rhino.Python
Cellular Automata Implementation
Polymedia Pixel
Finalization
Pramod Parajuli, 2011
40 Finalizing
Creating custom toolbar to run script
• Right click on the empty space by the 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.
• Shift+right click on the icon in the toolbar.
• Edit the icon.
• Provide button text and tooltip text.
• In the ‘macro library’, select ‘New Macro’
• In the command box: include followings:
!-_RunPythonScript (" # your python code here ")
Cellular Automata & PolyMedia Pixel using Rhino.Python Pramod Parajuli, 2011
41
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 Pramod Parajuli, 2011
42