Python Tutorials (back to the list of tutorials)

## Physics Simulation and Swarm Examples

### Swarm Example 1 (requires iGeo version 7.6.2 or higher)

The codes below shows an example of the swarm algorithm applied on a surface creating polygon mesh geometries.

The first code below has the swarm agent class MyBoid inheriting IBoid class. This adds a behavior to stay in the range from 0.0 to 1.0 in X and Y. In the update() method the position of the agent is checked and if it's out of the range, it adds or subtracts 1.0 to X or Y to jump to the other end of the range. To avoid drawing a line from one end to the other end, boolean variable jump is defined to check if it's jumping and if so it doesn't create a line. In setup() method, IG.top() method turns iGeo to show only top view instead of 4 views and IG.focus() method adjusts the view to zoom into the existing geometries.

```add_library('igeo')

def setup() :
size(480, 360, IG.GL)
IG.duration(800)
for i in range(200) :
MyBoid(IRand.pt(1,1,0),IRand.pt(-0.01,-0.01,0,0.01,0.01,0))
IG.top() #only showing the top view
IG.focus() #focusing into existing geometries

class MyBoid(IBoid) :
def __init__(self, pos, vel) :
IBoid.__init__(self,pos,vel)
self.prevPos = None
self.cohesionDist(0.03)
self.cohesionRatio(1)
self.separationDist(0.04)
self.separationRatio(2)
self.alignmentDist(0.03)
self.alignmentRatio(0)

def update(self) :
jump=False
if self.pos().x() < 0.0  :
jump=True
elif self.pos().x() > 1.0 :
self.pos().sub(1, 0, 0)
jump=True
if self.pos().y() < 0.0 :
jump=True
elif self.pos().y() > 1.0 :
self.pos().sub(0, 1, 0)
jump=True

curPos = self.pos().cp()
if self.prevPos is not None and not jump :
ICurve(self.prevPos, curPos).clr(0)
self.prevPos = curPos

```

This second code keeps movements of the swarm agents same but drawing lines in different locations. Whereas the previous code draws lines on the trace of the movement, this code draws lines between two agents when two agents are closer than a certain distance. These two lines calculates a distance between two agents and limit the condition when the distance is smaller than 0.08 (note that the whole range is from 0.0 to 1.0).
double dist = pos().dist( b.pos() );
if ( dist < 0.08 ) {

Another if-condition of if ( IG.time()%15==0 ) { is added to control the density of lines.

```add_library('igeo')

def setup() :
size(480, 360, IG.GL)
IG.duration(800)
for i in range(200) :
MyBoid(IRand.pt(1,1,0),IRand.pt(-0.01,-0.01,0,0.01,0.01,0))
IG.top() #only showing the top view
IG.focus() #focusing into existing geometries

class MyBoid(IBoid) :
def __init__(self, pos, vel) :
IBoid.__init__(self,pos,vel)
self.cohesionDist(0.03)
self.cohesionRatio(1)
self.separationDist(0.04)
self.separationRatio(2)
self.alignmentDist(0.03)
self.alignmentRatio(0)

def interact(self, agents) :
for agent in agents :
if agent is self :
return
if isinstance(agent, MyBoid) :
dist = self.pos().dist(agent.pos())
if dist < 0.08 :
if IG.time()%15==0 :
ICurve(self.pos().cp(),agent.pos().cp()).clr(0)

def update(self) :
if self.pos().x() < 0.0  :
elif self.pos().x() > 1.0 :
self.pos().sub(1, 0, 0)
if self.pos().y() < 0.0 :
elif self.pos().y() > 1.0 :
self.pos().sub(0, 1, 0)

```

The next code only changes the color of line drawing. The background color is changed by the method IG.bg(0) to black. When you put one number into this method ( IG.bg(double) ) it's gray scale color and when you put three numbers (IG.bg(double,double,double) ) it's RGB color. The color of the lines is changed to transparent white color at this line by setting the alpha value of the color to 0.2.
new ICurve(pos().cp(), b.pos().cp()).clr(1.0,0.2); //transparent white
The points of agents are also hidden by the agent's method hide().
if ( time()==0 ) { hide(); } //hiding a point of boid

```add_library('igeo')

def setup() :
size(480, 360, IG.GL)
IG.duration(800)
for i in range(200) :
MyBoid(IRand.pt(1,1,0),IRand.pt(-0.01,-0.01,0,0.01,0.01,0))
IG.bg(0) #black background
IG.top() #only showing the top view
IG.focus() #focusing into existing geometries

class MyBoid(IBoid) :
def __init__(self, pos, vel) :
IBoid.__init__(self,pos,vel)
self.cohesionDist(0.03)
self.cohesionRatio(1)
self.separationDist(0.04)
self.separationRatio(2)
self.alignmentDist(0.03)
self.alignmentRatio(0)

def interact(self, agents) :
for agent in agents :
if agent is self :
return
if isinstance(agent, MyBoid) :
dist = self.pos().dist(agent.pos())
if dist < 0.08 :
if IG.time()%15==0 :
ICurve(self.pos().cp(),agent.pos().cp()).clr(1.0,0.2) #transparent white

def update(self) :
if self.pos().x() < 0.0  :
elif self.pos().x() > 1.0 :
self.pos().sub(1, 0, 0)
if self.pos().y() < 0.0 :
elif self.pos().y() > 1.0 :
self.pos().sub(0, 1, 0)

```

The code below maps the swarm agents onto a surface. It reads an input Rhino file and takes one surface out to put it into an agent of MyBoidOnSurface class. MyBoidOnSurface class contains two data fields.
ISurface surface;
IVec surfPt;

With those fields, the agent keeps the information of a surface to map onto and mapped vector location on the surface. The original position information on the agent pos() is used as U-V coordinates. Although the original position is interpreted as U-V coordinates, the actual point of the agent still exists in X-Y-Z coordinates. To hide this point, the method hide() is called inside the constructor. If you don't hide the point, it floats somewhere on X-Y plane within (0.0, 0.0) - (1.0, 1.0).

This agent's original position pos() is then mapped onto the position on the surface by this line inside the constructor and also inside update() method to keep the field surfPt updated.
surfPt = surface.pt(pos);
Then this surfPt is used to measure the distance and to create a line in 3D X-Y-Z coordinates. The input Rhino file used in the example is this one below.

```add_library('igeo')

def setup() :
size(480, 360, IG.GL)
IG.duration(800)
IG.open("surface13.3dm")
surf = IG.surface(0)
for i in range(300) :
MyBoidOnSurface(surf,IRand.pt(1,1,0),IRand.pt(-0.01,-0.01,0,0.01,0.01,0))
surf.del()

class MyBoidOnSurface(IBoid) :
def __init__(self, srf, pos, vel) :
IBoid.__init__(self,pos,vel)
self.surface = srf
self.surfPt = srf.pt(pos)
self.hide() #hiding a point of boid
self.cohesionDist(0.03)
self.cohesionRatio(1)
self.separationDist(0.04)
self.separationRatio(2)
self.alignmentDist(0.03)
self.alignmentRatio(0)

def interact(self, agents) :
for agent in agents :
if agent is self :
return
if isinstance(agent, MyBoidOnSurface) :
dist = self.surfPt.dist(agent.surfPt)
if dist < 5.0 :
if IG.time()%15==0 :
ICurve(self.surfPt.cp(),agent.surfPt.cp()).clr(0)

def update(self) :
if self.pos().x() < 0.0  :
elif self.pos().x() > 1.0 :
self.pos().sub(1, 0, 0)
if self.pos().y() < 0.0 :
elif self.pos().y() > 1.0 :
self.pos().sub(0, 1, 0)

self.surfPt = self.surface.pt(self.pos()) #update surface point

```

```add_library('igeo')

def setup() :
size(480, 360, IG.GL)
IG.duration(800)
IG.open("surface13.3dm")
surf = IG.surface(0)
for i in range(300) :
MyBoidOnSurface(surf,IRand.pt(1,1,0),IRand.pt(-0.01,-0.01,0,0.01,0.01,0))
surf.del()

class MyBoidOnSurface(IBoid) :
def __init__(self, srf, pos, vel) :
IBoid.__init__(self,pos,vel)
self.surface = srf
self.surfPt = srf.pt(pos)
self.hide() #hiding a point of boid
self.cohesionDist(0.03)
self.cohesionRatio(1)
self.separationDist(0.04)
self.separationRatio(2)
self.alignmentDist(0.03)
self.alignmentRatio(0)

def interact(self, agents) :
for agent in agents :
if agent is self :
return
if isinstance(agent, MyBoidOnSurface) :
dist = self.surfPt.dist(agent.surfPt)
if dist < 5.0 and dist > 2.0 :
if IG.time()%15==0 :
#controlling depth
depth = sin(IG.time()*0.01)*1.5
pt1 = self.surface.pt(self.pos().x(), self.pos().y(), depth)
pt2 = agent.surface.pt(agent.pos().x(), agent.pos().y(), depth)
gray = sin(IG.time()*0.01)*0.5+0.5
IG.meshSquareStick(pt1,pt2,0.4).clr(gray)

def update(self) :
if self.pos().x() < 0.0  :