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 3 (requires iGeo version 7.5.1 or higher)

The example code below defines an agent to draw constantly curving arc shape and occasionally create a new branch. The agent direction dir is bent left and/or right depending on the probability percentages pctL and pctR. Those percentages of the left and the right are stochastically swapped changing the major direction to bend. Because given initial percentages are a large percentage (99%)and a small percentage (1.5%), the agent draw an arc shape for a while and then change the bending direction or create a branch.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(700)
    # left 99.0%, right 1.5%
    LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 1.5).clr(0)

class LineAgent(IAgent) : 
    def __init__(self, pt, dir, pctL, pctR) : 
        self.pos = pt 
        self.dir = dir
        self.pctL = pctL
        self.pctR = pctR
    
    def update(self) : 
        if self.time()==0 :
            #putting line geometry
            pos2 = self.pos.dup().add(self.dir)
            ICurve(self.pos, pos2).clr(self.clr())
            
            r = self.red() + IRand.get(-0.05, 0.05)
            g = self.green() + IRand.get(-0.05, 0.05)
            b = self.blue() + IRand.get(-0.05, 0.05)
            
            if IRand.pct(3.0) : #swap L/R percent
                tmp = self.pctL
                self.pctL = self.pctR
                self.pctR = tmp
            
            if IRand.pct(self.pctL) : #bend left
                dir2 = self.dir.dup()
                dir2.rot(PI/30)
                LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)
            
            if IRand.pct(self.pctR) : #bend right
                dir2 = self.dir.dup()
                dir2.rot(-PI/30)
                LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)
            
            self.del()

The next code adds interact() method to the previous code to detect collision of line agents. A line agent stops when it collides into other existing agents. Then the algorithm to swap left and right probability is also changed to swap them only when an agent creates a new branch.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(350)
    # left 99.0%, right 7.0%
    LineAgent(IG.v(0,0,0), IG.v(2,0,0), 99.0, 7.0).clr(0)

class LineAgent(IAgent) : 
    def __init__(self, pt, dir, pctL, pctR) : 
        self.pos = pt 
        self.dir = dir
        self.pctL = pctL
        self.pctR = pctR
        self.isColliding = False

    def interact(self, agents) :
        if self.time()==0 :
            for agent in agents : 
                if self.isColliding : 
                    return 
                if isinstance(agent, LineAgent) and agent is not self :
                    if agent.pos.dist(self.pos.cp(self.dir)) < self.dir.len()*0.999 :
                        self.isColliding=True
    
    def update(self) : 
        if self.time()==0 :
            if self.isColliding : 
                self.del()
                return
            #putting line geometry
            pos2 = self.pos.dup().add(self.dir)
            ICurve(self.pos, pos2).clr(self.clr())
            
            r = self.red() + IRand.get(-0.05, 0.05)
            g = self.green() + IRand.get(-0.05, 0.05)
            b = self.blue() + IRand.get(-0.05, 0.05)
            
            branchL = IRand.pct(self.pctL) #boolean switch L
            branchR = IRand.pct(self.pctR) #boolean switch R
            
            if branchL : #bend left
                dir2 = self.dir.dup()
                dir2.rot(PI/30)
                if branchR and self.pctR > self.pctL :#swap L/R% when branching both
                    LineAgent(pos2, dir2, self.pctR, self.pctL).clr(r,g,b)
                else : 
                    LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)
                
            if branchR : #bend right
                dir2 = self.dir.dup()
                dir2.rot(-PI/30)
                if branchL and self.pctR < self.pctL :#swap L/R% when branching both
                    LineAgent(pos2, dir2, self.pctR, self.pctL).clr(r,g,b)
                else : 
                    LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)

The code below changes the length of agent's line at every update. The lengths of all agents are slightly scaled down constantly, creating swirling curves. On top of it, the length is scaled up or down stochastically, only when the agent is creating a branch. In intersect() method, the collision detection algorithm is changed. It's using the method of
IVec.intersectLine(IVec line1Pt1, IVec line1Pt2, IVec line2Pt1, IVec line2Pt2) to calculate intersection of two line segments because the previous algorithm of collision detection wouldn't work when there are different lengths of lines.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IG.duration(400)
    # left 100%, right 4.5%
    LineAgent(IG.v(0,0,0), IG.v(2,0,0), 100, 4.5).clr(0)

class LineAgent(IAgent) : 
    def __init__(self, pt, dir, pctL, pctR) : 
        self.pos = pt 
        self.dir = dir
        self.pctL = pctL
        self.pctR = pctR
        self.isColliding = False

    def interact(self, agents) : 
        if self.time()==0 :
            for agent in agents : 
                if self.isColliding : 
                    return 
                if isinstance(agent, LineAgent) and agent is not self :
                    pos2 = self.pos.cp(self.dir)
                    apos2 = agent.pos.cp(agent.dir)
                    # not sharing root and intersecting
                    if not apos2.eq(self.pos) and not agent.pos.eq(self.pos) and \
                       IVec.intersectLine(agent.pos,apos2,self.pos,pos2) is not None : 
                        self.isColliding=True
    
    def update(self) :
        if self.time()==0 : 
            if self.isColliding : 
                self.del()
                return
            
            pos2 = self.pos.dup().add(self.dir)
            ICurve(self.pos, pos2).clr(self.clr())
            
            r = self.red() + IRand.get(-0.05, 0.05)
            g = self.green() + IRand.get(-0.05, 0.05)
            b = self.blue() + IRand.get(-0.05, 0.05)
            
            branchL = IRand.pct(self.pctL)
            branchR = IRand.pct(self.pctR)
            
            lenL = self.dir.len()
            lenR = self.dir.len()
            lenL*=0.995 #shrinking length
            lenR*=0.995 #shrinking length
            
            if branchL and branchR :  #only when branching both
                if IRand.pct(50) :
                    if self.pctL < self.pctR : 
                        lenL *= 0.9
                    else : 
                        lenR *= 0.9
                elif IRand.pct(6.0) :
                    if self.pctL < self.pctR : 
                        lenL *= 0.4
                    else : 
                        lenR *= 0.4
                elif IRand.pct(5.0) :
                    if self.pctL < self.pctR : 
                        lenL *= 4.0
                    else : 
                        lenR *= 4.0 
            
            if branchL : #bend left
                dir2 = self.dir.dup()
                dir2.len(lenL) #update length
                dir2.rot(PI/30)
                
                if branchR and self.pctR > self.pctL : #swap L/R% when branching both
                    LineAgent(pos2, dir2, self.pctR, self.pctL).clr(r,g,b)
                else : 
                    LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)
            
            if branchR : #bend right
                dir2 = self.dir.dup()
                dir2.len(lenR) #update length
                dir2.rot(-PI/30)
                
                if branchL and self.pctR < self.pctL : #swap L/R% when branching both
                    LineAgent(pos2, dir2, self.pctR, self.pctL).clr(r,g,b)
                else : 
                    LineAgent(pos2, dir2, self.pctL, self.pctR).clr(r,g,b)


(back to the list of tutorials)

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