home processing download documents tutorial python tutorial gallery source about
 Python Tutorials (back to the list of tutorials)

Multi-Agent 2D Examples

     Multi-Agent 2D Example 2 (requires iGeo version 7.5.1 or higher)

The code below defines an agent to make many branches in limited probability. When it doesn't create branches, it goes straight. The interact() method takes care of collision detection. This method uses intersectLine() method to check the collision instead of measuring distance of end points as done in the previous collision detection example .

IVec.intersectLine(pt1,pt2,a.pt1,a.pt2)!=null

The input argument of the intersectLine() method is 4 vector varaibles of one end point of the first line, another end point of the first line, one end point of the second line, and another end point of the second line. It returns an intersection point of two line as IVec variable but if they don't intersect, it returns null value. The two more conditions !pt1.eq(a.pt1) and !pt1.eq(a.pt2) inside the if-condition statement exclude the case of the parent line agent or other branching line agents which share the same parent agent.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(300)
    LineAgent(IVec(0,0,0), IVec(0,1,0)).clr(0)

class LineAgent(IAgent) : 
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.cp(dir)
        self.isColliding = False
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) : 
                    # checking clearance of end point
                    if not self.pt1.eq(agent.pt1) and \
                       not self.pt1.eq(agent.pt2) and \
                       IVec.intersectLine(self.pt1,self.pt2,agent.pt1,agent.pt2)is not None :
                        self.isColliding=True
    
    def update(self) :
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2).clr(self.clr())
            dir = self.pt2.dif(self.pt1)
            
            r = self.red() + IRand.get(-0.06,0.06)
            g = self.green() + IRand.get(-0.06,0.06)
            b = self.blue() + IRand.get(-0.06,0.06)
            
            if IRand.pct(2.5) : #branching
                num = 15
                for i in range(1, num) : 
                    if IRand.pct(40) :
                        dir2 = dir.dup().rev()
                        dir2.rot(2*PI*i/num)
                        LineAgent(self.pt2,dir2).clr(r,g,b)
            elif IRand.pct(99) : #going straight
                LineAgent(self.pt2,dir).clr(r,g,b)

The next code adds just one line to let the agent turn slightly instead of going straight by rotating the direction vector dir.

dir.rot( PI/80 );

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(300)
    LineAgent(IVec(0,0,0), IVec(0,1,0)).clr(0)

class LineAgent(IAgent) : 
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.cp(dir)
        self.isColliding = False
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) : 
                    # checking clearance of end point
                    if not self.pt1.eq(agent.pt1) and \
                       not self.pt1.eq(agent.pt2) and \
                       IVec.intersectLine(self.pt1,self.pt2,agent.pt1,agent.pt2)is not None :
                        self.isColliding=True
    
    def update(self) :
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2).clr(self.clr())
            dir = self.pt2.dif(self.pt1)
            
            r = self.red() + IRand.get(-0.06,0.06)
            g = self.green() + IRand.get(-0.06,0.06)
            b = self.blue() + IRand.get(-0.06,0.06)
            
            if IRand.pct(2.5) : #branching
                num = 15
                for i in range(1, num) : 
                    if IRand.pct(40) :
                        dir2 = dir.dup().rev()
                        dir2.rot(2*PI*i/num)
                        LineAgent(self.pt2,dir2).clr(r,g,b)
            elif IRand.pct(99) : #going straight
                dir.rot(PI/80)
                LineAgent(self.pt2,dir).clr(r,g,b)

The code below randomize the move of an agent when it doesn't create branches by randomly rotating the direction vector dir.

dir.rot( IRand.get(-PI/8, PI/8) );

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(300)
    LineAgent(IVec(0,0,0), IVec(0,1,0)).clr(0)

class LineAgent(IAgent) : 
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.cp(dir)
        self.isColliding = False
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) : 
                    # checking clearance of end point
                    if not self.pt1.eq(agent.pt1) and \
                       not self.pt1.eq(agent.pt2) and \
                       IVec.intersectLine(self.pt1,self.pt2,agent.pt1,agent.pt2)is not None :
                        self.isColliding=True
    
    def update(self) :
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2).clr(self.clr())
            dir = self.pt2.dif(self.pt1)
            
            r = self.red() + IRand.get(-0.06,0.06)
            g = self.green() + IRand.get(-0.06,0.06)
            b = self.blue() + IRand.get(-0.06,0.06)
            
            if IRand.pct(2.5) : #branching
                num = 15
                for i in range(1, num) : 
                    if IRand.pct(40) :
                        dir2 = dir.dup().rev()
                        dir2.rot(2*PI*i/num)
                        LineAgent(self.pt2,dir2).clr(r,g,b)
            elif IRand.pct(99) : #going straight
                dir.rot(IRand.get(-PI/20,PI/20))
                LineAgent(self.pt2,dir).clr(r,g,b)

This code below changes two parts of the second rotating agent code. First, the range of branching angle is limited to Pi, instead of 2 Pi, by changing this line in the previous code
dir2.rot( 2*PI*i/num );
to
dir2.rot( PI*i/num );
The second change is to scale down (or sometimes up) the length of line agents in both cases of creating branch agents and just going with a single agent. This is done by multiplying some number to the direction vector dir for a single agent or dir2 for branching agents in those lines.
dir2.mul( IRand.get(0.9, 1.35) ); //scale up or down
dir.mul( 0.98 ); //scale down

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(250)
    LineAgent(IVec(0,0,0), IVec(0,1,0)).clr(0)

class LineAgent(IAgent) : 
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.cp(dir)
        self.isColliding = False

    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if self.isColliding :
                    return
                if isinstance(agent, LineAgent) : 
                    # checking clearance of end point
                    if not self.pt1.eq(agent.pt1) and \
                       not self.pt1.eq(agent.pt2) and \
                       IVec.intersectLine(self.pt1,self.pt2,agent.pt1,agent.pt2)is not None :
                        self.isColliding=True
    
    def update(self) :
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2).clr(self.clr())
            dir = self.pt2.dif(self.pt1)
            
            r = self.red() + IRand.get(-0.06,0.06)
            g = self.green() + IRand.get(-0.06,0.06)
            b = self.blue() + IRand.get(-0.06,0.06)
            
            if IRand.pct(2.5) : #branching
                num = 15
                for i in range(1, num) : 
                    if IRand.pct(40) :
                        dir2 = dir.dup().rev()
                        dir2.rot(PI*i/num);
                        dir2.mul(IRand.get(0.9, 1.35)) #scale up or down
                        LineAgent(self.pt2,dir2).clr(r,g,b)
            elif IRand.pct(99) : #going straight
                dir.rot(PI/40);
                dir.mul(0.98); #scale down
                LineAgent(self.pt2,dir).clr(r,g,b)


(back to the list of tutorials)

HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java / Python)
GALLERY
SOURCE CODE(GitHub)
ABOUT