Cybernetic Urbanism | Form Generation #01 DLA

Contents

  1. DLA
    1. What is DLA ?
    2. Pipeline
  2. OOP in GhPython | Example
    1. Scheme
    2. Grammer
  3. DLA Algorithm in Grasshopper | Example
    1. Agent Class
    2. DLA Class
    3. Draw Functions

DLA

What is DLA ?

The following is the quotation from wikipedia “Diffusion-limited aggregation“;

Diffusion-limited aggregation (DLA) is the process whereby particles undergoing a random walk due to Brownian motion cluster together to form aggregates of such particles. This theory, proposed by T.A. Witten Jr. and L.M. Sander in 1981,[1] is applicable to aggregation in any system where diffusion is the primary means of transport in the system. DLA can be observed in many systems such as electrodeposition, Hele-Shaw flow, mineral deposits, and dielectric breakdown.

Pipeline

There are 3 processes in programing DLA;

  • Random Walk
  • Connection Check
  • Connect Nodes
  • Draw Branch

OOP in GhPython

Scheme

With OOP(Object-Oriented Programming) in GhPython, we can make some programs coding apart.

Grammer

– Constructor

import ghpythonlib.components as gh
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import random as rand

class Agent:

 def __init__(self, step):
  self.pos = rg.Point3d(0,0,0)
  self.step = step
  self.log = []
  self.log.append(self.pos)

 def randwalk(self):
  sph = gh.Sphere(gh.XYPlane([0,0,0]),self.step)
  randVec = gh.PopulateGeometry(sph, 1, rand.randint(0,100))
  self.pos = rs.VectorAdd(self.pos,randVec)
  self.log.append(self.pos)

a = Agent(x)

– Update Function

x.randwalk()
a = x

– Draw Function

a = x.pos
a = x.log

DLA Algorithm in Grasshopper

Agent Class

class Agent:

    def __init__(self, targetPt, step, r, branchLength):
        sph = gh.Sphere(gh.XYPlane([0,0,0]),r)
        self.pos = gh.PopulateGeometry(sph, 1, rand.randint(0,100))
        self.step = step
        self.tPt = targetPt
        self.brLen = branchLength
        self.hierarchy = 0

    def randwalk(self):
        targetVec = rs.VectorScale(rs.VectorUnitize(rs.VectorSubtract(self.tPt,self.pos)),self.step)
        sph = gh.Sphere(gh.XYPlane([0,0,0]),self.step)
        tempVec = gh.PopulateGeometry(sph, 1, rand.randint(0,100))
        v = rs.VectorUnitize(rs.VectorAdd(targetVec,tempVec))
        self.pos = rs.VectorAdd(self.pos,v)

    def addConnection(self, index, pos, hierarchy):
        self.index = index
        v = rs.VectorSubtract(pos,self.pos)
        d = rs.VectorSubtract(rs.VectorScale(rs.VectorUnitize(v),self.brLen),v)
        self.pos = rs.VectorSubtract(self.pos,d)
        self.hierarchy = hierarchy + 1

    def getConnection(self):
        index = self.index
        return index

Center Agent Class

class centerAgent(Agent):
    def __init__(self, tPt, step, r, brLen):
        Agent.__init__(self, tPt, step, r, brLen)
        self.pos = tPt

DLA Class

class DLA:

    def __init__(self, cenPt, brLen, reso, proc):
        self.agents = []
        self.cenPt = cenPt
        self.brLen = brLen
        self.reso = reso
        self.proc = proc

        self.bndRad = 0
        self.agents.append(centerAgent(self.cenPt,self.reso,self.brLen,self.brLen))
        self.curAgent = Agent(self.cenPt,self.reso,self.brLen*2,self.brLen)
        self.finished = False

    def update(self):
        if self.proc:
            if self.finished :
                self.agents.append(self.curAgent)
                if gh.Distance(self.cenPt,self.curAgent.pos) > self.bndRad:
                    self.bndRad = gh.Distance(self.cenPt,self.curAgent.pos)
                self.curAgent = Agent(self.cenPt,self.reso,self.bndRad+self.brLen,self.brLen)
                self.finished = False
            else:
                self.val = self.checkConnection(self.curAgent)
                if self.val != "False":
                    self.curAgent.addConnection(self.val,self.agents[self.val].pos,self.agents[self.val].hierarchy)
                    self.finished = True
                else:
                    self.curAgent.randwalk();
        else:
            while self.finished == False:
                self.val = self.checkConnection(self.curAgent)
                if self.val != "False":
                    self.curAgent.addConnection(self.val,self.agents[self.val].pos,self.agents[self.val].hierarchy)
                    self.finished = True
                else:
                    self.curAgent.randwalk();
            self.agents.append(self.curAgent)
            if gh.Distance(self.cenPt,self.curAgent.pos) > self.bndRad:
                self.bndRad = gh.Distance(self.cenPt,self.curAgent.pos)
            self.curAgent = Agent(self.cenPt,self.reso,self.bndRad+self.brLen,self.brLen)
            self.finished = False

    def checkConnection(self, agent):
        pts = []
        pts = self.getPoints()
        closest = gh.ClosestPoint(self.curAgent.pos,pts)
        if closest[2] < self.brLen:
            return closest[1]
        else:
            return "False"

    def getHierarchicalBranch(self, hie):
        branches = []
        for i in range(1,len(self.agents)):
            if self.agents[i].hierarchy > hie+1:
                branches.append(rs.AddLine(self.agents[i].pos, self.agents[self.agents[i].getConnection()].pos))
        return branches

    def getBranches(self):
        branches = []
        if len(self.agents)>1:
            for i in range(1,len(self.agents)):
                branches.append(rs.AddLine(self.agents[i].pos, self.agents[self.agents[i].getConnection()].pos))
        else:
            branches.append(rs.AddLine(self.agents[0].pos,self.curAgent.pos))

        return branches

    def getPoints(self):
        points = []
        for ag in self.agents:
            points.append(ag.pos)
        return points

    def getcurAgentPos(self):
        p = self.curAgent.pos
        return p