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

Variation of Geometries on Multi Agent Algorithm (requires iGeo version 7.4.0 or higher)

     Pipes on Agents

This section shows examples of variation of geometries created along agents. Taking one of the examples of multi-agent algorithms already shown in the tutorials, different ways to put geometries on agents are described. The multi-agent algorithm used here is this branching algorithm. The following example shows a simple way to put one square pipe on each agent.

add_library('igeo')

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

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if isinstance(agent, LineAgent) : 
                    if agent is not self : 
                        # checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance :
                            self.isColliding=True
    
    def update(self) : 
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            IG.squarePipe(self.pt1,self.pt2,.2).clr(IRand.gray())
            dir = self.pt2.dif(self.pt1)
            #rotation axis with random direction
            axis = IRand.pt(-1,1).len(1)
            if IRand.pct(50) : #bend
                LineAgent(self.pt2, dir.dup().rot(axis,IRand.get(PI/3,PI/3*2)))
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, dir.dup().rot(axis,-IRand.get(PI/3,PI/3*2)))
            if IRand.pct(80) : #straight
                LineAgent(self.pt2, dir.dup())


     Tangent Curves on Agents

Here is an example to put curves whose tangents at the end points are matching with the tangents of the connected agents. Instead of putting a line between the start and end points, it puts a degree-2 curve on 3 points of the midpoint of the start and end points, the end point and the midpoint of the start and end points of the next agent.

add_library('igeo')

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

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.isColliding = False

    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if isinstance(agent, LineAgent) : 
                    if agent is not self : 
                        # checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding=True
    
    def update(self) : 
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            dir = self.pt2.dif(self.pt1)
            axis = IRand.pt(-1,1).len(1)
            if IRand.pct(100) : #bend
                nextDir1 = dir.dup().rot(axis,IRand.get(PI/3,PI/3*2))
                #degree 2 curve at midpoint of pt1&pt2, pt2, and midpoint of pt2 and next agent's point
                ICurve([ self.pt1.mid(self.pt2),self.pt2, \
                         self.pt2.mid(self.pt2.cp(nextDir1)) ], 2).clr(self.clr())
                LineAgent(self.pt2, nextDir1).clr(self.clr())
                
            if IRand.pct(50) : #bend the other way
                #degree 2 curve at midpoint of pt1&pt2, pt2, and midpoint of pt2 and next agent's point
                nextDir2 = dir.dup().rot(axis,-IRand.get(PI/3,PI/3*2))
                ICurve([ self.pt1.mid(self.pt2),self.pt2, \
                         self.pt2.mid(self.pt2.cp(nextDir2)) ],2).clr(self.clr())
                LineAgent(self.pt2, nextDir2).clr(self.clr())


     Surfaces with Tangent Edges on Agents

The following example is putting a surface whose edges are tangent to other connected agents' surface edges. The edges of surface are defined in the same way with the tangent curves in the previous example. The surface has 3 by 3 control points and its degree in U direction is 2 and also 2 in V direction. 3 of control points are same with those of the previous tangent curve's control points and other 3 are same with control points of another branching agent's curve.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(8)
    IG.duration(120)
    LineAgent(IVec(0,0,0), IVec(1,0,0)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.isColliding = False
    
    def interact(self, agents) :
        if self.time() == 0 : #only in the first time
            for agent in agents : 
                if isinstance(agent, LineAgent) : 
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding : 
            self.del()
        elif self.time() == 0 : #if not colliding
            dir = self.pt2.dif(self.pt1)
            axis = IRand.pt(-1,1).len(1)
            nextDir1 = dir.dup().rot(axis,PI/3)
            nextDir2 = dir.dup().rot(axis,-PI/3)
            #degree 2 surface with 3x3 control points
            cpts = []
            cpts.append([])
            cpts.append([])
            cpts.append([])
            cpts[0].append(self.pt1.mid(self.pt2))
            cpts[0].append(self.pt1.mid(self.pt2))
            cpts[0].append(self.pt1.mid(self.pt2))
            cpts[1].append(self.pt2)
            cpts[1].append(self.pt2)
            cpts[1].append(self.pt2)
            cpts[2].append(self.pt2.mid(self.pt2.cp(nextDir1)))
            cpts[2].append(self.pt2)
            cpts[2].append(self.pt2.mid(self.pt2.cp(nextDir2)))
            ISurface(cpts, 2, 2).clr(self.clr())
            r = self.clr().getRed() + IRand.getInt(-10, 10)
            g = self.clr().getGreen() + IRand.getInt(-10, 10)
            b = self.clr().getBlue() + IRand.getInt(-10, 10)
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1).clr(r,g,b)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2).clr(r,g,b)


     Surfaces around Agents: 1

The code below shows an example to put surfaces on the edges offset from the Y-shape branch skeleton of an agent. First offset points are calculated with vectors which are perpendicular to the axis of the agent and the direction of each branch. (offset1, offset2, offset3). Those offset vectors are calculated by cross vector operation.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    LineAgent(IVec(0,0,0), IVec(1,0,0)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
    
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            #making axis perpendicular to dir
            axis = IRand.pt(-1,1).cross(dir)
            # child dir & points
            nextDir1 = dir.dup().rot(axis,PI/3)
            nextDir2 = dir.dup().rot(axis,-PI/3)
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            offsetWidth = -0.5
            offset1 = dir.cross(axis).len(offsetWidth)
            offset2 = nextDir1.cross(axis).len(offsetWidth)
            offset3 = nextDir2.cross(axis).len(offsetWidth)
            
            #offset edge points 1
            edgePt11 = mid1.cp(offset1)
            edgePt12 = quarter1.cp(offset1)
            edgePt13 = quarter2.cp(offset2)
            edgePt14 = mid2.cp(offset2)
            #offset edge points 2      
            offset2.flip() #offset to opposite
            edgePt21 = mid2.cp(offset2)
            edgePt22 = quarter2.cp(offset2)
            edgePt23 = quarter3.cp(offset3)
            edgePt24 = mid3.cp(offset3)
            #offset edge points 3      
            offset1.flip() #offset to opposite
            offset3.flip() #offset to opposite
            edgePt31 = mid3.cp(offset3)
            edgePt32 = quarter3.cp(offset3)
            edgePt33 = quarter1.cp(offset1)
            edgePt34 = mid1.cp(offset1)
            #degree 3 curves
            ICurve([ edgePt11,edgePt12,edgePt13,edgePt14 ], 3).clr(0)
            ICurve([ edgePt21,edgePt22,edgePt23,edgePt24 ], 3).clr(0)
            ICurve([ edgePt31,edgePt32,edgePt33,edgePt34 ], 3).clr(0)
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2)

Then next, a surface on the offset curve is calculated by shifting the control points on both direction of the axis with the depthVec vector.

add_library('igeo')

def setup() :
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    LineAgent(IVec(0,0,0), IVec(1,0,0)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            #making axis perpendicular to dir
            axis = IRand.pt(-1,1).cross(dir)
            # child dir & points
            nextDir1 = dir.dup().rot(axis,PI/3)
            nextDir2 = dir.dup().rot(axis,-PI/3)
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            offsetWidth = -0.5
            offset1 = dir.cross(axis).len(offsetWidth)
            offset2 = nextDir1.cross(axis).len(offsetWidth)
            offset3 = nextDir2.cross(axis).len(offsetWidth)
            
            #offset edge points 1
            edgePt11 = mid1.cp(offset1)
            edgePt12 = quarter1.cp(offset1)
            edgePt13 = quarter2.cp(offset2)
            edgePt14 = mid2.cp(offset2)
            #offset edge points 2      
            offset2.flip() #offset to opposite
            edgePt21 = mid2.cp(offset2)
            edgePt22 = quarter2.cp(offset2)
            edgePt23 = quarter3.cp(offset3)
            edgePt24 = mid3.cp(offset3)
            #offset edge points 3      
            offset1.flip() #offset to opposite
            offset3.flip() #offset to opposite
            edgePt31 = mid3.cp(offset3)
            edgePt32 = quarter3.cp(offset3)
            edgePt33 = quarter1.cp(offset1)
            edgePt34 = mid1.cp(offset1)
            
            depth = 0.5
            depthVec = axis.dup().len(depth)
            
            cpts1 = []
            cpts1.append([])
            cpts1.append([])
            cpts1.append([])
            cpts1.append([])
            cpts1[0].append(edgePt11.dup().add(depthVec))
            cpts1[0].append(edgePt11.dup().sub(depthVec))
            cpts1[1].append(edgePt12.dup().add(depthVec))
            cpts1[1].append(edgePt12.dup().sub(depthVec))
            cpts1[2].append(edgePt13.dup().add(depthVec))
            cpts1[2].append(edgePt13.dup().sub(depthVec))
            cpts1[3].append(edgePt14.dup().add(depthVec))
            cpts1[3].append(edgePt14.dup().sub(depthVec))
            
            cpts2 = []
            cpts2.append([])
            cpts2.append([])
            cpts2.append([])
            cpts2.append([])
            cpts2[0].append(edgePt21.dup().add(depthVec))
            cpts2[0].append(edgePt21.dup().sub(depthVec))
            cpts2[1].append(edgePt22.dup().add(depthVec))
            cpts2[1].append(edgePt22.dup().sub(depthVec))
            cpts2[2].append(edgePt23.dup().add(depthVec))
            cpts2[2].append(edgePt23.dup().sub(depthVec))
            cpts2[3].append(edgePt24.dup().add(depthVec))
            cpts2[3].append(edgePt24.dup().sub(depthVec))
            
            cpts3 = []
            cpts3.append([])
            cpts3.append([])
            cpts3.append([])
            cpts3.append([])
            cpts3[0].append(edgePt31.dup().add(depthVec))
            cpts3[0].append(edgePt31.dup().sub(depthVec))
            cpts3[1].append(edgePt32.dup().add(depthVec))
            cpts3[1].append(edgePt32.dup().sub(depthVec))
            cpts3[2].append(edgePt33.dup().add(depthVec))
            cpts3[2].append(edgePt33.dup().sub(depthVec))
            cpts3[3].append(edgePt34.dup().add(depthVec))
            cpts3[3].append(edgePt34.dup().sub(depthVec))
            
            ISurface(cpts1, 3, 1)
            ISurface(cpts2, 3, 1)
            ISurface(cpts3, 3, 1)
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2)

In this example, the surface edges between an agent and the next child are not matching. A technique to make it connected and tangent is shown in the next example.


     Surfaces around Agents: 2

This example shows offset edge geometries connected smoothly with other child agents' geometries. To do this, each agent needs to keep information of axis direction around which the child branches are rotated. The added instance field is axis and the child agents' axis nextAxis1, nextAxis2 is defined inside update() method.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/3,PI/3))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/3,PI/3))
            
            offsetWidth = -0.5
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            #offset edge points 1
            edgePt11 = mid1.cp(offset1)
            edgePt12 = quarter1.cp(offset1)
            edgePt13 = quarter2.cp(offset2)
            edgePt14 = mid2.cp(offset2)
            #offset edge points 2      
            offset2.flip() #offset to opposite
            edgePt21 = mid2.cp(offset2)
            edgePt22 = quarter2.cp(offset2)
            edgePt23 = quarter3.cp(offset3)
            edgePt24 = mid3.cp(offset3)
            #offset edge points 3      
            offset1.flip() #offset to opposite
            offset3.flip() #offset to opposite
            edgePt31 = mid3.cp(offset3)
            edgePt32 = quarter3.cp(offset3)
            edgePt33 = quarter1.cp(offset1)
            edgePt34 = mid1.cp(offset1)
            #degree 3 curves
            ICurve([ edgePt11,edgePt12,edgePt13,edgePt14 ], 3).clr(0)
            ICurve([ edgePt21,edgePt22,edgePt23,edgePt24 ], 3).clr(0)
            ICurve([ edgePt31,edgePt32,edgePt33,edgePt34 ], 3).clr(0)
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2)

The surfaces are created on the offset curves. The code to create a surface out of 4 control points and two different ex is separated in a method of createEdgeSurface.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4))
            
            offsetWidth = -0.5
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            #offset edge points 1
            edgePt11 = mid1.cp(offset1)
            edgePt12 = quarter1.cp(offset1)
            edgePt13 = quarter2.cp(offset2)
            edgePt14 = mid2.cp(offset2)
            #offset edge points 2      
            offset2.flip() #offset to opposite
            edgePt21 = mid2.cp(offset2)
            edgePt22 = quarter2.cp(offset2)
            edgePt23 = quarter3.cp(offset3)
            edgePt24 = mid3.cp(offset3)
            #offset edge points 3      
            offset1.flip() #offset to opposite
            offset3.flip() #offset to opposite
            edgePt31 = mid3.cp(offset3)
            edgePt32 = quarter3.cp(offset3)
            edgePt33 = quarter1.cp(offset1)
            edgePt34 = mid1.cp(offset1)
            
            depth = 0.5
            depthVec1 = self.axis.dup().len(depth)
            depthVec2 = nextAxis1.dup().len(depth)
            depthVec3 = nextAxis2.dup().len(depth)
            
            self.createEdgeSurface(edgePt11,edgePt12,edgePt13,edgePt14,depthVec1,depthVec2)
            self.createEdgeSurface(edgePt21,edgePt22,edgePt23,edgePt24,depthVec2,depthVec3)
            self.createEdgeSurface(edgePt31,edgePt32,edgePt33,edgePt34,depthVec3,depthVec1)
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2)
    
    def createEdgeSurface(self,pt1,pt2,pt3,pt4,extrudeDir1,extrudeDir2) : 
        cpts = []
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts[0].append(pt1.dup().add(extrudeDir1))
        cpts[0].append(pt1.dup().sub(extrudeDir1))
        cpts[1].append(pt2.dup().add(extrudeDir1))
        cpts[1].append(pt2.dup().sub(extrudeDir1))
        cpts[2].append(pt3.dup().add(extrudeDir2))
        cpts[2].append(pt3.dup().sub(extrudeDir2))
        cpts[3].append(pt4.dup().add(extrudeDir2))
        cpts[3].append(pt4.dup().sub(extrudeDir2))
        return ISurface(cpts, 3, 1)


     Surfaces around Agents: 3

The code below shows example to create surfaces of a L-shaped section around the agent whose edges are above and below the Y-shaped center lines of the agent and the middle fold edge is outer offset of the center lines. The method createEdgeSurface is changed to take input arguments of 4 control points on two arm of the agent's Y-shaped center lines (pt1 - pt4), vectors to offset outward on each arm of Y-shape, (offsetDir1, offsetDir2), and vectors to shift above and below the center lines on each arm (extrudeDir1, extrudeDir2).

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4))
            
            offsetWidth = -0.5
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            depth = 0.5
            depthVec1 = self.axis.dup().len(depth)
            depthVec2 = nextAxis1.dup().len(depth)
            depthVec3 = nextAxis2.dup().len(depth)
            
            self.createEdgeSurface(mid1,quarter1,quarter2,mid2, \
                                   offset1, offset2, depthVec1, depthVec2)
            self.createEdgeSurface(mid2,quarter2,quarter3,mid3, \
                                   offset2.dup().flip(), offset3, depthVec2, depthVec3)
            self.createEdgeSurface(mid3,quarter3,quarter1,mid1, \
                                   offset3.dup().flip(), offset1.dup().flip(), depthVec3, depthVec1)
            
            if IRand.percent(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1)
            if IRand.percent(50) :  #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2)
    
    def createEdgeSurface(self,pt1,pt2,pt3,pt4,offsetDir1,\
                          offsetDir2,extrudeDir1,extrudeDir2) :
      cpts = []
      cpts.append([])
      cpts.append([])
      cpts.append([])
      cpts.append([])
      cpts[0].append(pt1.dup().add(extrudeDir1))
      cpts[0].append(pt1.dup().add(offsetDir1))
      cpts[0].append(pt1.dup().sub(extrudeDir1))
      cpts[1].append(pt2.dup().add(extrudeDir1))
      cpts[1].append(pt2.dup().add(offsetDir1))
      cpts[1].append(pt2.dup().sub(extrudeDir1))
      cpts[2].append(pt3.dup().add(extrudeDir2))
      cpts[2].append(pt3.dup().add(offsetDir2))
      cpts[2].append(pt3.dup().sub(extrudeDir2))
      cpts[3].append(pt4.dup().add(extrudeDir2))
      cpts[3].append(pt4.dup().add(offsetDir2))
      cpts[3].append(pt4.dup().sub(extrudeDir2))
      return ISurface(cpts, 3, 1)


     Surfaces around Agents: 4

The code below shows an example to enclose the surrounding surface of the agents. To create cap surfaces at the triangular opening at the center of the agent, another method createCapSurface is implemented. This code creates channel shaped surface by having v-degree 1 NURBS surfaces.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4))
            
            offsetWidth = -0.5
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            depth = 0.5
            depthVec1 = self.axis.dup().len(depth)
            depthVec2 = nextAxis1.dup().len(depth)
            depthVec3 = nextAxis2.dup().len(depth)
            
            self.createEdgeSurface(mid1,quarter1,quarter2,mid2, \
                                   offset1,offset2,depthVec1,depthVec2)
            self.createEdgeSurface(mid2,quarter2,quarter3,mid3, \
                                   offset2.dup().flip(),offset3,depthVec2,depthVec3)
            self.createEdgeSurface(mid3,quarter3,quarter1,mid1, \
                                   offset3.dup().flip(),offset1.dup().flip(),depthVec3,depthVec1)
            
            self.createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3, \
                                  depthVec1,depthVec2,depthVec3)
            self.createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2, \
                                  depthVec1.flip(),depthVec3.flip(),depthVec2.flip())
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2)
    
    def createEdgeSurface(self,pt1,pt2,pt3,pt4,offsetDir1,\
                          offsetDir2,extrudeDir1,extrudeDir2) : 
          cpts = []
          cpts.append([])
          cpts.append([])
          cpts.append([])
          cpts.append([])
          cpts[0].append(pt1.dup().add(extrudeDir1))
          cpts[0].append(pt1.dup().add(offsetDir1).add(extrudeDir1))
          cpts[0].append(pt1.dup().add(offsetDir1).sub(extrudeDir1))
          cpts[0].append(pt1.dup().sub(extrudeDir1))
          cpts[1].append(pt2.dup().add(extrudeDir1))
          cpts[1].append(pt2.dup().add(offsetDir1).add(extrudeDir1))
          cpts[1].append(pt2.dup().add(offsetDir1).sub(extrudeDir1))
          cpts[1].append(pt2.dup().sub(extrudeDir1))
          cpts[2].append(pt3.dup().add(extrudeDir2))
          cpts[2].append(pt3.dup().add(offsetDir2).add(extrudeDir2))
          cpts[2].append(pt3.dup().add(offsetDir2).sub(extrudeDir2))
          cpts[2].append(pt3.dup().sub(extrudeDir2))
          cpts[3].append(pt4.dup().add(extrudeDir2))
          cpts[3].append(pt4.dup().add(offsetDir2).add(extrudeDir2))
          cpts[3].append(pt4.dup().add(offsetDir2).sub(extrudeDir2))
          cpts[3].append(pt4.dup().sub(extrudeDir2))
          return ISurface(cpts, 3, 1)
  
    def createCapSurface(self,pt1,pt2,pt3,pt4,pt5,pt6,\
                         shiftDir1,shiftDir2,shiftDir3) : 
          cpts = []
          cpts.append([])
          cpts.append([])
          cpts.append([])
          cpts.append([])
          cpts[0].append(pt1.dup().add(shiftDir1))
          cpts[0].append(pt2.dup().add(shiftDir1))
          cpts[0].append(pt4.dup().add(shiftDir2))
          cpts[0].append(pt3.dup().add(shiftDir2))
          cpts[1].append(pt1.dup().add(shiftDir1))
          cpts[1].append(pt2.dup().add(shiftDir1))
          cpts[1].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
          cpts[1].append(pt4.dup().add(shiftDir2))
          cpts[2].append(pt1.dup().add(shiftDir1))
          cpts[2].append(pt2.dup().add(shiftDir1))
          cpts[2].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
          cpts[2].append(pt6.dup().add(shiftDir3))
          cpts[3].append(pt1.dup().add(shiftDir1))
          cpts[3].append(pt2.dup().add(shiftDir1))
          cpts[3].append(pt6.dup().add(shiftDir3))
          cpts[3].append(pt5.dup().add(shiftDir3))
          return ISurface(cpts, 3, 3)

The code below creates surfaces with curved section having v-degree 3 NURBS surfaces.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(3)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1)).clr(0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4))
            
            offsetWidth = -0.75
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            depth = 0.75
            depthVec1 = self.axis.dup().len(depth)
            depthVec2 = nextAxis1.dup().len(depth)
            depthVec3 = nextAxis2.dup().len(depth)
            
            self.createEdgeSurface(mid1,quarter1,quarter2,mid2,\
                                   offset1, offset2,depthVec1, depthVec2)
            self.createEdgeSurface(mid2,quarter2,quarter3,mid3,\
                                   offset2.dup().flip(),offset3,depthVec2,depthVec3)
            self.createEdgeSurface(mid3,quarter3,quarter1,mid1,\
                                   offset3.dup().flip(),offset1.dup().flip(),depthVec3,depthVec1)

            self.createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3,\
                                  depthVec1,depthVec2,depthVec3)
            self.createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2,\
                                  depthVec1.flip(),depthVec3.flip(),depthVec2.flip())
            
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2)
    
    def createEdgeSurface(self,pt1,pt2,pt3,pt4,offsetDir1,
                          offsetDir2,extrudeDir1, extrudeDir2) : 
        cpts = []
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts[0].append(pt1.dup().add(extrudeDir1))
        cpts[0].append(pt1.dup().add(offsetDir1).add(extrudeDir1))
        cpts[0].append(pt1.dup().add(offsetDir1).sub(extrudeDir1))
        cpts[0].append(pt1.dup().sub(extrudeDir1))
        cpts[1].append(pt2.dup().add(extrudeDir1))
        cpts[1].append(pt2.dup().add(offsetDir1).add(extrudeDir1))
        cpts[1].append(pt2.dup().add(offsetDir1).sub(extrudeDir1))
        cpts[1].append(pt2.dup().sub(extrudeDir1))
        cpts[2].append(pt3.dup().add(extrudeDir2))
        cpts[2].append(pt3.dup().add(offsetDir2).add(extrudeDir2))
        cpts[2].append(pt3.dup().add(offsetDir2).sub(extrudeDir2))
        cpts[2].append(pt3.dup().sub(extrudeDir2))
        cpts[3].append(pt4.dup().add(extrudeDir2))
        cpts[3].append(pt4.dup().add(offsetDir2).add(extrudeDir2))
        cpts[3].append(pt4.dup().add(offsetDir2).sub(extrudeDir2))
        cpts[3].append(pt4.dup().sub(extrudeDir2))
        return ISurface(cpts, 3, 3)
    
    def createCapSurface(self,pt1,pt2,pt3,pt4,pt5,pt6,\
	                 shiftDir1,shiftDir2,shiftDir3) : 
        cpts = []
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts[0].append(pt1.dup().add(shiftDir1))
        cpts[0].append(pt2.dup().add(shiftDir1))
        cpts[0].append(pt4.dup().add(shiftDir2))
        cpts[0].append(pt3.dup().add(shiftDir2))
        cpts[1].append(pt1.dup().add(shiftDir1))
        cpts[1].append(pt2.dup().add(shiftDir1))
        cpts[1].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
        cpts[1].append(pt4.dup().add(shiftDir2))
        cpts[2].append(pt1.dup().add(shiftDir1))
        cpts[2].append(pt2.dup().add(shiftDir1))
        cpts[2].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
        cpts[2].append(pt6.dup().add(shiftDir3))
        cpts[3].append(pt1.dup().add(shiftDir1))
        cpts[3].append(pt2.dup().add(shiftDir1))
        cpts[3].append(pt6.dup().add(shiftDir3))
        cpts[3].append(pt5.dup().add(shiftDir3))
        return ISurface(cpts, 3, 3)


     Surfaces around Agents: 5

This code shows a way to control which surfaces to be created and others not to. On top of the previous code, it limits the number of edge surfaces to two, instead of three covering Y-shaped center lines of the agent, keeping one side of three always open. It introduces new instance fields in boolean type createLeftSrf and createRightSrf to propagate the control of creation of surfaces in child agents in continuous way.

add_library('igeo')

def setup() : 
    size(480, 360, IG.GL)
    IRand.init(4)
    IG.duration(30)
    #second and third vector needs to be perpendicular
    LineAgent(IVec(0,0,0),IVec(1,0,0),IVec(0,0,1),True,True).clr(0.4,0,0)
    IG.fill()

class LineAgent(IAgent) : 
    length = 2
    clearance = 1.99 #less than length
  
    def __init__(self, pt, dir, ax, createLeft, createRight) : 
        self.pt1 = pt
        self.pt2 = pt.dup().add(dir.dup().len(LineAgent.length))
        self.axis = ax
        self.isColliding = False
        self.createLeftSrf = createLeft
        self.createRightSrf = createRight
    
    def interact(self, agents) : 
        if self.time() == 0 : #only in the first time
            for agent in agents :
                if isinstance(agent, LineAgent) :
                    if agent is not self : 
                        #checking clearance of end point
                        if agent.pt2.dist(self.pt2) < LineAgent.clearance : 
                            self.isColliding = True
    
    def update(self) : 
        if self.isColliding :
            self.del()
        elif self.time() == 0 : #if not colliding
            ICurve(self.pt1,self.pt2) # center line
            
            dir = self.pt2.dif(self.pt1)
            # child dir & points
            nextDir1 = dir.dup().rot(self.axis, IRand.get(PI/4,PI/3))
            nextDir2 = dir.dup().rot(self.axis,-IRand.get(PI/4,PI/3))
            nextPt1 = self.pt2.cp(nextDir1)
            nextPt2 = self.pt2.cp(nextDir2)
            #midpoints
            mid1 = self.pt1.mid(self.pt2)
            mid2 = self.pt2.mid(nextPt1)
            mid3 = self.pt2.mid(nextPt2)
            #mid of midpoints
            quarter1 = self.pt2.mid(mid1)
            quarter2 = self.pt2.mid(mid2)
            quarter3 = self.pt2.mid(mid3)
            
            #axis of child agents
            nextAxis1 = self.axis.dup().rot(nextDir1, IRand.get(-PI/4,PI/4))
            nextAxis2 = self.axis.dup().rot(nextDir2, IRand.get(-PI/4,PI/4))
            
            offsetWidth = -1.0
            offset1 = dir.cross(self.axis).len(offsetWidth)
            offset2 = nextDir1.cross(nextAxis1).len(offsetWidth)
            offset3 = nextDir2.cross(nextAxis2).len(offsetWidth)
            
            depth = 1.0
            depthVec1 = self.axis.dup().len(depth)
            depthVec2 = nextAxis1.dup().len(depth)
            depthVec3 = nextAxis2.dup().len(depth)
            
            if self.createLeftSrf :
                self.createEdgeSurface(mid1,quarter1,quarter2,mid2,\
                                       offset1,offset2,depthVec1,depthVec2).clr(self.clr())
            if not self.createLeftSrf or not self.createRightSrf :
                self.createEdgeSurface(mid2,quarter2,quarter3,mid3,\
                                       offset2.dup().flip(),offset3,depthVec2, depthVec3).clr(self.clr())
            if self.createRightSrf :
                self.createEdgeSurface(mid3,quarter3,quarter1,mid1,\
                                       offset3.dup().flip(), offset1.dup().flip(),depthVec3, depthVec1).clr(self.clr())
            
            self.createCapSurface(mid1,quarter1,mid2,quarter2,mid3,quarter3,\
                                  depthVec1,depthVec2,depthVec3).clr(self.clr())
            self.createCapSurface(mid1,quarter1,mid3,quarter3,mid2,quarter2,\
                                  depthVec1.flip(),depthVec3.flip(),depthVec2.flip()).clr(self.clr())
            
            #child agents color
            r = self.clr().getRed() + IRand.getInt(-10,10)
            g = self.clr().getGreen()
            b = self.clr().getBlue() + IRand.getInt(-10,10)
            if IRand.pct(80) : #bend
                LineAgent(self.pt2, nextDir1, nextAxis1, 
                          self.createLeftSrf, 
                          not self.createLeftSrf or not self.createRightSrf).clr(r,g,b)
            if IRand.pct(50) : #bend the other way
                LineAgent(self.pt2, nextDir2, nextAxis2,
                          not self.createLeftSrf or not self.createRightSrf, 
                          self.createRightSrf).clr(r,g,b)
    
    def createEdgeSurface(self,pt1,pt2,pt3,pt4,\
	                  offsetDir1,offsetDir2,extrudeDir1,extrudeDir2) : 
        cpts = []
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts[0].append(pt1.dup().add(extrudeDir1))
        cpts[0].append(pt1.dup().add(offsetDir1).add(extrudeDir1))
        cpts[0].append(pt1.dup().add(offsetDir1).sub(extrudeDir1))
        cpts[0].append(pt1.dup().sub(extrudeDir1))
        cpts[1].append(pt2.dup().add(extrudeDir1))
        cpts[1].append(pt2.dup().add(offsetDir1).add(extrudeDir1))
        cpts[1].append(pt2.dup().add(offsetDir1).sub(extrudeDir1))
        cpts[1].append(pt2.dup().sub(extrudeDir1))
        cpts[2].append(pt3.dup().add(extrudeDir2))
        cpts[2].append(pt3.dup().add(offsetDir2).add(extrudeDir2))
        cpts[2].append(pt3.dup().add(offsetDir2).sub(extrudeDir2))
        cpts[2].append(pt3.dup().sub(extrudeDir2))
        cpts[3].append(pt4.dup().add(extrudeDir2))
        cpts[3].append(pt4.dup().add(offsetDir2).add(extrudeDir2))
        cpts[3].append(pt4.dup().add(offsetDir2).sub(extrudeDir2))
        cpts[3].append(pt4.dup().sub(extrudeDir2))
        return ISurface(cpts, 3, 3)
    
    def createCapSurface(self,pt1,pt2,pt3,pt4,pt5,pt6,\
	                 shiftDir1,shiftDir2,shiftDir3) : 
        cpts = []
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts.append([])
        cpts[0].append(pt1.dup().add(shiftDir1))
        cpts[0].append(pt2.dup().add(shiftDir1))
        cpts[0].append(pt4.dup().add(shiftDir2))
        cpts[0].append(pt3.dup().add(shiftDir2))
        cpts[1].append(pt1.dup().add(shiftDir1))
        cpts[1].append(pt2.dup().add(shiftDir1))
        cpts[1].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
        cpts[1].append(pt4.dup().add(shiftDir2))
        cpts[2].append(pt1.dup().add(shiftDir1))
        cpts[2].append(pt2.dup().add(shiftDir1))
        cpts[2].append(pt4.mid(pt6).add(shiftDir2.mid(shiftDir3)))
        cpts[2].append(pt6.dup().add(shiftDir3))
        cpts[3].append(pt1.dup().add(shiftDir1))
        cpts[3].append(pt2.dup().add(shiftDir1))
        cpts[3].append(pt6.dup().add(shiftDir3))
        cpts[3].append(pt5.dup().add(shiftDir3))
        return ISurface(cpts, 3, 3)


(back to the list of tutorials)

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