{"id":554,"date":"2012-04-15T04:51:56","date_gmt":"2012-04-15T04:51:56","guid":{"rendered":"http:\/\/www.new-territories.com\/blog\/rmit.uts\/?page_id=554"},"modified":"2012-04-30T02:49:34","modified_gmt":"2012-04-30T02:49:34","slug":"3_locus-ethereal_empirica","status":"publish","type":"page","link":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/code\/3_locus-ethereal_empirica\/","title":{"rendered":"1_locus; ethereal_empirica"},"content":{"rendered":"<p>\/*<br \/>\n* Copyright (c) 2012 Gwyllim Jahn<br \/>\n* http:\/\/scripts.crida.net\/gh<\/p>\n<p>* Developed By Gwyllim Jahn, Cam Newnham and Mark-Henry Delacrauz<br \/>\n* during the 2012 RMIT nCertainties studio.<br \/>\n*<br \/>\n* This code makes extensive use of several freely distributed<br \/>\n* processing libraries &#8211; thankyou especially to toxi.<\/p>\n<p>* This code is free software; you can redistribute it and\/or<br \/>\n* modify it under the terms of the GNU Lesser General Public<br \/>\n* License as published by the Free Software Foundation; either<br \/>\n* version 2.1 of the License, or (at your option) any later version.<br \/>\n*<br \/>\n* http:\/\/creativecommons.org\/licenses\/LGPL\/2.1\/<br \/>\n*<br \/>\n* This code is distributed in the hope that it will be useful,<br \/>\n* but WITHOUT ANY WARRANTY; without even the implied warranty of<br \/>\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br \/>\n* Lesser General Public License for more details.<br \/>\n*<br \/>\n*\/<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;OrbitingParticlesStrands &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>import processing.video.*;<\/p>\n<p>import toxi.physics2d.constraints.*;<br \/>\nimport toxi.physics.*;<br \/>\nimport toxi.physics.constraints.*;<br \/>\nimport toxi.physics2d.behaviors.*;<br \/>\nimport toxi.physics.behaviors.*;<br \/>\nimport toxi.physics2d.*;<br \/>\nimport controlP5.*;<br \/>\nimport processing.dxf.*;<br \/>\nimport toxi.geom.*;<br \/>\nimport org.apache.commons.collections.keyvalue.*;<br \/>\nimport org.apache.commons.collections.set.*;<br \/>\nimport org.apache.commons.collections.iterators.*;<br \/>\nimport org.apache.commons.collections.map.*;<br \/>\nimport org.apache.commons.collections.bag.*;<br \/>\nimport org.apache.commons.collections.list.*;<br \/>\nimport org.apache.commons.collections.bidimap.*;<br \/>\nimport org.apache.commons.collections.collection.*;<br \/>\nimport org.apache.commons.collections.*;<br \/>\nimport org.apache.commons.collections.functors.*;<br \/>\nimport peasy.org.apache.commons.math.*;<br \/>\nimport peasy.*;<br \/>\nimport peasy.org.apache.commons.math.geometry.*;<br \/>\nimport processing.opengl.*;<\/p>\n<p>\/\/ &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-GLOBALS<br \/>\n\/\/accessable by anything in your script.<br \/>\nVerletPhysics physics = new VerletPhysics();<\/p>\n<p>PeasyCam cam;<br \/>\nControlP5 controlP5;<br \/>\nControlWindow controlWindow;<\/p>\n<p>int numTrees = 6;<br \/>\n\/\/number of agents per tree<br \/>\nint numAgents = 75;<br \/>\nboolean record = false;<br \/>\nboolean agentsOn = true;<br \/>\nArrayList forest = new ArrayList();<br \/>\nArrayListfibrePop = new ArrayList();<br \/>\nMultiValueMap m = new MultiValueMap();<br \/>\nMultiValueMap particleMap = new MultiValueMap();<\/p>\n<p>int gridRes = 15;<\/p>\n<p>\/\/add the pause variable<br \/>\nBoolean paused = false;<br \/>\nBoolean bundling = false;<br \/>\n\/\/agent variables<br \/>\nint trailLength = 50;<br \/>\nfloat agentSpeed = 3.5;<br \/>\nint dropRate = 1;<\/p>\n<p>\/\/if a tree is less than this number away from the agent, then it will affect the path of the agent<br \/>\nfloat attractScale = 25;<\/p>\n<p>\/\/if the closest tree is less than this number away, the agent will try to move to the fringe of<br \/>\n\/\/the trees crown<br \/>\nfloat fringeScale = 80;<\/p>\n<p>\/\/three variables for how much each type of movement affects the agent<br \/>\nfloat spin = 0.5;<br \/>\nfloat push = 0.12;<br \/>\nfloat pull = 0.18;<\/p>\n<p>\/\/maximum movement for a tree point<br \/>\nfloat maxTreePull = 3;<br \/>\nfloat treeSpring = 0.1;<\/p>\n<p>\/\/bundling variables<br \/>\nfloat cutoff = 20;<br \/>\nfloat stiffness = 0.1;<br \/>\nfloat numToMove = .8;<br \/>\nfloat nodeStiffness = 0.002;<\/p>\n<p>\/\/video<br \/>\nboolean filming = false;<br \/>\nMovieMaker mm;<br \/>\n\/\/ &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-SETUP<\/p>\n<p>void setup(){<br \/>\nsize(1600,900,OPENGL);<\/p>\n<p>cam =new PeasyCam(this,800);<br \/>\nmm = new MovieMaker(this, width, height, &#8220;drawing.mov&#8221;, 30, MovieMaker.ANIMATION, MovieMaker.HIGH);<br \/>\ncam.rotateZ(1.57079633);<\/p>\n<p>\/\/setup the forest landscape<\/p>\n<p>\/\/setupRandomLandscape();<br \/>\nimportLandscape();<\/p>\n<p>setupP5();<br \/>\nbackground(255);<br \/>\n}<\/p>\n<p>void draw(){<br \/>\nbackground(255);<\/p>\n<p>if(record){<br \/>\nbeginRaw(DXF,&#8221;test.dxf&#8221;);<br \/>\n}<\/p>\n<p>if(!bundling){<\/p>\n<p>\/\/update the physics engine<br \/>\nphysics.update();<\/p>\n<p>for (TreeAttractor t :forest){<br \/>\nt.run();<br \/>\n}<br \/>\n}else{<br \/>\nfor (Fibre f: fibrePop){<br \/>\nf.update();<br \/>\n}<br \/>\n}<br \/>\nif(filming)mm.addFrame();<\/p>\n<p>if(record){<br \/>\nendRaw();<br \/>\nrecord = false;<br \/>\n}<br \/>\n}<\/p>\n<p>void keyPressed(){<\/p>\n<p>\/\/save a dxf<br \/>\nif (key == &#8216;e&#8217;) {<br \/>\nrecord = !record;<br \/>\n}<br \/>\n\/\/add the pause function<br \/>\nif (key == &#8216;p&#8217;) {<br \/>\npaused = !paused;<br \/>\n}<br \/>\nif (key == &#8216;a&#8217;) {<br \/>\nagentsOn = !agentsOn;<br \/>\n}<br \/>\n\/\/save a screengrab<br \/>\nif (key == &#8216;s&#8217;) {<br \/>\n\/\/ saveFrame(&#8220;pic_####.png&#8221;);<br \/>\nif(!bundling){<br \/>\nsavePts();<br \/>\n}else{<br \/>\nsaveBundles();<br \/>\n}<br \/>\n}<\/p>\n<p>if(key == &#8216;f&#8217;){<br \/>\nimportFibres();<br \/>\nbundling =true;<br \/>\n}<br \/>\nif(key == &#8216; &#8216;){<br \/>\nfilming =!filming;<br \/>\nif(!filming)mm.finish();<br \/>\n}<br \/>\n\/\/reset the sketch<br \/>\nif (key == &#8216;r&#8217;) {<br \/>\nbackground(255);<br \/>\nimportLandscape();<br \/>\nphysics = new VerletPhysics();<br \/>\nfibrePop=new ArrayList();<br \/>\nbundling = false;<br \/>\n\/\/setupRandomLandscape();<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Agents&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>\/\/simple agent class to interact with the data<br \/>\n\/\/field and other agents<\/p>\n<p>class Agent {<\/p>\n<p>Vec3D loc,vel;<br \/>\nTreeAttractor p;<br \/>\nfloat distToTree;<br \/>\nStrand trail;<\/p>\n<p>Agent(Vec3D _loc, Vec3D _vel, TreeAttractor _p){<br \/>\nloc = _loc;<br \/>\nvel = _vel;<br \/>\np = _p;<br \/>\n\/\/add the agent to the map<br \/>\nm.put(p,this);<br \/>\ndistToTree=0;<br \/>\ntrail = new Strand(loc);<br \/>\n}<\/p>\n<p>void run(){<br \/>\n\/\/moves the particles based on proximity to trees<br \/>\nif(!paused){<br \/>\ngetNearTrees();<\/p>\n<p>constrainToCrown();<\/p>\n<p>\/\/limit height of the agent to roughly the crown height<br \/>\nlimitHeight();<\/p>\n<p>updatePos();<br \/>\n}<\/p>\n<p>trail.run();<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>\/\/Behaviours<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>void getNearTrees(){<br \/>\n\/\/setup variables to set new parent<br \/>\nTreeAttractor n =p;<br \/>\nfloat minD = 10000;<\/p>\n<p>for (TreeAttractor tree:forest){<br \/>\n\/\/get the distance to the tree<br \/>\nfloat d = loc.distanceTo(tree.loc);<\/p>\n<p>if(dminD=d;<br \/>\nn = tree;<br \/>\n}<\/p>\n<p>if(d<\/p>\n<p>\/\/make the agent interact with the tree<br \/>\n\/\/and colide with debris<\/p>\n<p>vel.addSelf(getField(tree));<br \/>\n}<\/p>\n<p>}<br \/>\n\/\/re set the parent to the nearest tree<br \/>\nm.remove(p,this);<br \/>\np = n;<br \/>\nm.put(p,this);<\/p>\n<p>\/\/ set the node stiffness based on its distance to the tree point<br \/>\ndistToTree = p.loc.distanceTo(loc)-p.crownRadius;<br \/>\nif(distToTree distToTree = map(distToTree,0,40,0.01,0.5);<\/p>\n<p>\/\/ distToTree = m.getCollection(p).size();<br \/>\n\/\/distToTree = map(distToTree,0,50,0.05,0.7);<\/p>\n<p>\/\/make sure we keep orbiting current tree<br \/>\nvel.addSelf(getField(p));<br \/>\n}<\/p>\n<p>Vec3D getField(TreeAttractor t){<br \/>\nVec3D toAttr = loc.sub(t.loc);<br \/>\nVec3D perp = toAttr.cross(new Vec3D(0,0,1));<\/p>\n<p>\/\/create another vector to gently rotate the agents<br \/>\nVec3D tangent = toAttr.cross(vel);<\/p>\n<p>\/\/random mod for tangent<br \/>\nfloat mod = random(-0.2,0.2);<br \/>\ntangent.scaleSelf(mod);<br \/>\nperp.addSelf(tangent);<\/p>\n<p>float d = perp.magnitude();<br \/>\nfloat s = perp.magnitude();<br \/>\nperp.scaleSelf(spin\/s);<br \/>\n\/\/perp.normalize();<br \/>\ntoAttr.scaleSelf(push\/d);<br \/>\nreturn(perp.addSelf(toAttr));<\/p>\n<p>}<\/p>\n<p>void constrainToCrown(){<br \/>\n\/\/get vector from agent to tree location<br \/>\nVec3D toCrown = loc.sub(p.loc);<br \/>\ntoCrown.invert();<br \/>\n\/\/get distance to edge of crown<br \/>\nfloat diff = toCrown.magnitude()-p.crownRadius;<\/p>\n<p>\/\/constrain<br \/>\ndiff = abs(constrain(diff,-fringeScale,fringeScale));<\/p>\n<p>diff = (fringeScale &#8211; diff);<br \/>\nif(diff== 0) diff = 0.1;<br \/>\n\/\/inverse falloff<br \/>\ntoCrown.scaleSelf(pull\/diff);<\/p>\n<p>vel.addSelf(toCrown);<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>\/\/Function for limiting the height of the agent. If the agent moves below the height<br \/>\n\/\/of the tree crown, interpolate its vector upwards.<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>void limitHeight(){<\/p>\n<p>\/\/if agents z is less than closest trees z<br \/>\nif(loc.z vel.interpolateToSelf(new Vec3D(0,0,1),0.5);<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>\/\/Functions for managing trails and rendering the agent.<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\nvoid updatePos(){<br \/>\n\/\/move the agent<br \/>\nvel.normalizeTo(agentSpeed);<br \/>\nloc.addSelf(vel);<\/p>\n<p>trail.update(loc);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Controllers&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>void setupP5 (){<br \/>\ncontrolP5 = new ControlP5(this);<br \/>\ncontrolP5.setAutoDraw(false);<br \/>\ncontrolWindow = controlP5.addControlWindow(&#8220;controlP5window&#8221;,100,100,400,320);<br \/>\ncontrolWindow.hideCoordinates();<\/p>\n<p>Controller mySlider1 = controlP5.addSlider(&#8220;spin&#8221;,0,1.5).linebreak();<br \/>\nmySlider1.setWindow(controlWindow);<br \/>\nController mySlider2 =controlP5.addSlider(&#8220;push&#8221;,0,0.201).linebreak();<br \/>\nmySlider2.setWindow(controlWindow);<br \/>\nController mySlider3 = controlP5.addSlider(&#8220;pull&#8221;,0,0.201).linebreak();<br \/>\nmySlider3.setWindow(controlWindow);<br \/>\nController mySlider4 =controlP5.addSlider(&#8220;attractScale&#8221;,0,200).linebreak();<br \/>\nmySlider4.setWindow(controlWindow);<br \/>\nController mySlider5 =controlP5.addSlider(&#8220;fringeScale&#8221;,0,200).linebreak();<br \/>\nmySlider5.setWindow(controlWindow);<br \/>\nController mySlider6 =controlP5.addSlider(&#8220;agentSpeed&#8221;,0.1,3.5).linebreak();<br \/>\nmySlider6.setWindow(controlWindow);<br \/>\nController mySlider7 =controlP5.addSlider(&#8220;maxTreePull&#8221;,0,15.00).linebreak();<br \/>\nmySlider7.setWindow(controlWindow);<br \/>\nController mySlider9 =controlP5.addSlider(&#8220;treeSpring&#8221;,0,0.150).linebreak();<br \/>\nmySlider9.setWindow(controlWindow);<br \/>\nController mySlider8 =controlP5.addSlider(&#8220;latcherGrowthRate&#8221;,0,10.5).linebreak();<br \/>\nmySlider8.setWindow(controlWindow);<br \/>\nController mySlider10 =controlP5.addSlider(&#8220;latcherRotate&#8221;,0,0.500).linebreak();<br \/>\nmySlider10.setWindow(controlWindow);<br \/>\nTextlabel field = controlP5.addTextlabel(&#8220;Instructions&#8221;,&#8221;press r to reset simulation with new parameters&#8221;,20,300);<br \/>\nfield.setWindow(controlWindow);<\/p>\n<p>controlWindow.setTitle(&#8220;Spring GUI&#8221;);<\/p>\n<p>}<br \/>\n\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Debris&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class Debris {<\/p>\n<p>ArrayListchunks;<br \/>\nVec3D loc;<br \/>\nBoolean stillAdding = true;<\/p>\n<p>Debris (Vec3D _a){<br \/>\nloc = _a;<br \/>\nchunks = new ArrayList();<br \/>\nchunks.add(_a);<\/p>\n<p>}<\/p>\n<p>void render(){<br \/>\nstrokeWeight(5);<br \/>\npoint (loc.x,loc.y,loc.z);<br \/>\n}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Fibre&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class Fibre{<\/p>\n<p>ArrayListnodes;<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;constructor<br \/>\nFibre(){<br \/>\nnodes = new ArrayList();<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;setters and getters<br \/>\nvoid addNode(Node n){<br \/>\nnodes.add(n);<br \/>\n}<\/p>\n<p>void update(){<br \/>\nnoFill();<br \/>\nbeginShape();<br \/>\nfor (Node n:nodes){<br \/>\nn.run();<br \/>\nvertex(n.loc.x,n.loc.y,n.loc.z);<br \/>\n}<br \/>\nendShape();<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Initialisation&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>void setupRandomLandscape(){<br \/>\nm = new MultiValueMap();<br \/>\nforest = new ArrayList();<br \/>\nfor (int i=0;i<\/p>\n<p>\/\/create a new tree like so:<\/p>\n<p>\/\/TreeAttractor (_loc (x,y,z), _strength, _crownRadius){<br \/>\nTreeAttractor tree = new TreeAttractor(new Vec3D(random(0,300),random(0,300),random(0,50)), random(1,2.5), random(50,70));<br \/>\nforest.add(tree);<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;import functions<\/p>\n<p>void importLandscape() {<br \/>\nforest = new ArrayList();<br \/>\n\/\/load text<br \/>\nString[] txtLines = loadStrings(&#8220;trees.txt&#8221;);<br \/>\n\/\/splits strand points<br \/>\nString[] arrCoords = split(txtLines[0], &#8216;_&#8217;);<\/p>\n<p>for (int j = 0; j &lt; arrCoords.length; ++j) {<\/p>\n<p>\/\/separates coords<br \/>\nString[] arrToks = split(arrCoords[j], &#8216;,&#8217;);<br \/>\nfloat xx = Float.valueOf(arrToks[0]);<br \/>\nfloat yy = Float.valueOf(arrToks[1]);<br \/>\nfloat zz = Float.valueOf(arrToks[2]);<\/p>\n<p>\/\/create node<br \/>\nVec3D tmpPt = new Vec3D(xx, yy, zz);<br \/>\nTreeAttractor tree = new TreeAttractor(tmpPt, 1, random(100,120));<br \/>\nforest.add(tree);<br \/>\n}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Node&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class Node {<\/p>\n<p>\/\/location<br \/>\nVec3D loc;<br \/>\n\/\/parent fibre<br \/>\nFibre p;<br \/>\n\/\/siblings for spring behaviour<br \/>\nArrayList siblings;<br \/>\n\/\/neighbours to loop through<br \/>\nArrayList neighbours;<br \/>\n\/\/defines whether node is part of a bundle or not<br \/>\nBoolean active;<br \/>\nfloat nodeStiffness;<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;constructor<br \/>\nNode(Vec3D LOC, Fibre P, float STIFF) {<br \/>\nloc = LOC;<br \/>\np=P;<br \/>\nactive = true;<br \/>\nneighbours = new ArrayList();<br \/>\nsiblings = new ArrayList();<br \/>\nnodeStiffness = STIFF;<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;setters and getters<br \/>\nvoid activate(Boolean a) {<br \/>\nactive = a;<br \/>\n}<br \/>\nvoid addSibling (Node s) {<br \/>\nsiblings.add(s);<br \/>\n}<br \/>\nvoid setNeighbours(ArrayList N) {<br \/>\nneighbours = N;<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;main functions<br \/>\nvoid run() {<br \/>\nif(active){<br \/>\nattract();<br \/>\n}<br \/>\n\/\/render();<br \/>\n}<\/p>\n<p>void attract() {<br \/>\nArrayList closest = new ArrayList();<br \/>\nfloat minD = 999999;<\/p>\n<p>for (Node n: neighbours){<br \/>\nVec3D diff = loc.sub(n.loc);<br \/>\nfloat d = diff.magnitude();<br \/>\nif(d&gt;1){<br \/>\nif (d closest.add(diff);<br \/>\nif(closest.size()&gt;numToMove) closest.remove(0);<br \/>\nminD =d;<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\nfor (Vec3D v:closest){<br \/>\nfloat d = v.magnitude();<br \/>\nv.scaleSelf(nodeStiffness\/d);<br \/>\nloc.subSelf(v);<br \/>\nspring();<br \/>\n}<br \/>\n}<\/p>\n<p>void spring() {<br \/>\nVec3D avg = new Vec3D(0,0,0);<br \/>\nfor (Node n: siblings){<br \/>\nVec3D diff = loc.sub(n.loc);<br \/>\navg.addSelf(diff);<br \/>\n}<br \/>\navg.scaleSelf(stiffness);<br \/>\nloc.subSelf(avg);<br \/>\n}<\/p>\n<p>void render() {<br \/>\npoint(loc.x, loc.y, loc.z);<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Strand&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class Strand{<\/p>\n<p>ArrayListtrail;<br \/>\nArrayList pts;<br \/>\nfloat dropNum;<\/p>\n<p>Strand(Vec3D _loc){<\/p>\n<p>trail = new ArrayList();<br \/>\npts = new ArrayList();<br \/>\nMapParticle p = new MapParticle(_loc,getCoord(_loc));<br \/>\np.lock();<br \/>\npts.add(p);<br \/>\ndropNum = 0;<\/p>\n<p>}<\/p>\n<p>void update(Vec3D _loc){<\/p>\n<p>\/\/update the trail geom every 5 moves<br \/>\nif(dropNum%dropRate==0){<br \/>\nif(trail.size()<\/p>\n<p>MapParticle p = new MapParticle(_loc,getCoord(_loc));<br \/>\np.lock();<br \/>\nString coord = getCoord(p);<br \/>\nparticleMap.put(coord,p);<\/p>\n<p>MapParticle lastP = pts.get(pts.size()-1);<br \/>\nlastP.unlock();<\/p>\n<p>VerletSpring s = new VerletSpring(pts.get(pts.size()-1),p,(p.distanceTo(lastP)),0.5);<br \/>\nphysics.addParticle(p);<br \/>\nphysics.addSpring(s);<\/p>\n<p>trail.add(s);<br \/>\npts.add(p);<br \/>\n}else{<\/p>\n<p>physics.removeSpringElements(trail.get(0));<br \/>\ntrail.remove(0);<br \/>\npts.remove(0);<br \/>\n}<br \/>\ndropNum=0;<br \/>\n}<br \/>\ndropNum++;<br \/>\n}<\/p>\n<p>String getCoord(Vec3D p){<br \/>\nString s = &#8220;&#8221;+floor(p.x\/gridRes)+floor(p.y\/gridRes)+floor(p.z\/gridRes);<br \/>\nreturn s;<br \/>\n}<\/p>\n<p>void run(){<br \/>\n\/\/render agent trail as lines<br \/>\nstrokeWeight(1);<br \/>\nfloat c =1;<br \/>\nif(agentsOn){<br \/>\nfor (VerletSpring l : trail){<\/p>\n<p>float gs = ((trail.size()-c)\/trail.size())*255;<br \/>\nstroke(gs);<\/p>\n<p>MapParticle a = (MapParticle) l.a;<\/p>\n<p>a.run();<\/p>\n<p>line (l.a.x,l.a.y,l.a.z,l.b.x,l.b.y,l.b.z);<br \/>\nc+=1;<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;TrailPt&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class TrailPt {<\/p>\n<p>Vec3D loc;<br \/>\nfloat d2t;<\/p>\n<p>TrailPt(Vec3D LOC, float D2T){<\/p>\n<p>loc = LOC;<br \/>\nd2t = D2T;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;TreeAttractor&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<br \/>\nclass TreeAttractor {<br \/>\nVec3D loc,initLoc;<br \/>\nfloat strength;<br \/>\nfloat crownRadius;<br \/>\nArrayList bots;<\/p>\n<p>TreeAttractor (Vec3D _loc, float _strength, float _crownRadius){<br \/>\n\/\/assign properties<br \/>\nloc = _loc;<br \/>\ninitLoc = loc.copy();;<br \/>\nstrength = _strength;<br \/>\ncrownRadius = _crownRadius;<br \/>\nbots = new ArrayList();<\/p>\n<p>\/\/spawn robot agents<br \/>\nspawn();<br \/>\n}<\/p>\n<p>void run(){<br \/>\nfor (Agent a:bots){<br \/>\na.run();<br \/>\n}<\/p>\n<p>\/\/move the tree towards all nearby agents<br \/>\ncrownSagging();<br \/>\nrender();<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>\/\/Function for creating agents randomly on the sphere of the tree crown (perhaps should be<br \/>\n\/\/a hemisphere)<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>void spawn(){<br \/>\nfor (int i = 0; i Vec3D fringe = new Vec3D(crownRadius + random(-(crownRadius\/3),(crownRadius\/3)),0,0);<br \/>\nfringe.rotateZ(random(0,2*PI));<br \/>\nfringe.rotateX(random(0,2*PI));<br \/>\nfringe.rotateY(random(0,2*PI));<br \/>\nfringe.addSelf(loc);<br \/>\nVec3D vel = new Vec3D(random(-1,1),random(-1,1),random(-1,1));<\/p>\n<p>Agent a = new Agent(fringe,vel,this);<\/p>\n<p>bots.add(a);<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>\/\/Function for moving the centre point of the tree towards the agents that currently have<br \/>\n\/\/this tree as their parent.<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>void crownSagging(){<br \/>\n\/\/create zero length default vector<br \/>\nVec3D moveVel = new Vec3D(0,0,0);<br \/>\n\/\/loop through agents if there are any<br \/>\nif(m.getCollection(this)!=null){<br \/>\nfor(Agent a: (ArrayList) m.getCollection(this)){<br \/>\nVec3D influence = a.loc.sub(loc);<br \/>\ninfluence.invert();<br \/>\nfloat d = influence.magnitude();<\/p>\n<p>influence.normalizeTo(maxTreePull\/d);<br \/>\nmoveVel.addSelf(influence);<br \/>\n}<br \/>\n}<br \/>\n\/\/reduce influence of movevel the further the tree is from original point<br \/>\nVec3D toOriginalPos = initLoc.sub(loc);<br \/>\nfloat stretch = toOriginalPos.magnitude();<br \/>\ntoOriginalPos.normalizeTo(treeSpring*stretch);<\/p>\n<p>moveVel.addSelf(toOriginalPos);<\/p>\n<p>loc.addSelf(moveVel);<\/p>\n<p>}<\/p>\n<p>void render(){<br \/>\nstrokeWeight(0);<br \/>\npoint (loc.x,loc.y,loc.z);<\/p>\n<p>}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;BundlingInit&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;import functions<\/p>\n<p>void importFibres() {<\/p>\n<p>\/*<br \/>\nSet set = m.entrySet();<br \/>\nIterator it = set.iterator();<br \/>\nwhile (it.hasNext()) {<br \/>\nMap.Entry entry = (Map.Entry) it.next();<br \/>\nfor (Agent a :(ArrayList)entry.getValue()){<\/p>\n<p>\/\/creates a strand from the line in the txt file<br \/>\nFibre fibre = new Fibre();<\/p>\n<p>for (int j=0;j\/\/create node<br \/>\nTrailPt tmpPt = a.trail.get(j);<\/p>\n<p>Node n = new Node(tmpPt.loc.copy(), fibre, tmpPt.d2t);<\/p>\n<p>\/\/lock the node if its the start or end of the trail,<br \/>\n\/\/or if its the 15th node, or if its attr value is less than 0.1<br \/>\nif (j==0 || j==a.trail.size()-1 || j%15 ==0 ||tmpPt.d2t n.activate(false);<br \/>\n}<br \/>\nfibre.addNode(n);<br \/>\n}<br \/>\n\/\/add strand to draw loop<br \/>\nfibrePop.add(fibre);<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/setup the graph of nodes<br \/>\nsetupSiblings();<br \/>\nsetupGraph();<br \/>\n*\/<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;setup initial graph<\/p>\n<p>void setupSiblings(){<br \/>\n\/\/loop the fibres<br \/>\nfor (Fibre f: fibrePop) {<br \/>\n\/\/loop the nodes<\/p>\n<p>for (int i = 1; iNode currentNode = f.nodes.get(i);<br \/>\nNode lastNode = f.nodes.get(i-1);<br \/>\nNode nextNode = f.nodes.get(i+1);<br \/>\ncurrentNode.addSibling(lastNode);<br \/>\ncurrentNode.addSibling(nextNode);<br \/>\n}<\/p>\n<p>}<br \/>\n}<\/p>\n<p>void setupGraph() {<br \/>\n\/\/loop the fibres<br \/>\nint count=0;<br \/>\nfor (Fibre f: fibrePop) {<br \/>\n\/\/loop the nodes<br \/>\nfor (Node n:f.nodes){<br \/>\nArrayList neighbours = new ArrayList();<\/p>\n<p>\/\/find neighbours<br \/>\nfor (Fibre otherF:fibrePop){<br \/>\n\/\/dont use same fibre<br \/>\nif(otherF!= f){<br \/>\nfor(Node otherN:otherF.nodes){<\/p>\n<p>float d = n.loc.distanceTo(otherN.loc);<br \/>\nif(d neighbours.add(otherN);<br \/>\n}<\/p>\n<p>}<br \/>\n}<br \/>\n}<\/p>\n<p>n.setNeighbours(neighbours);<br \/>\n}<\/p>\n<p>println(&#8220;Percentage Loaded: &#8220;+(float(count)\/fibrePop.size())*100);<br \/>\ncount++;<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;mapParticle&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>class MapParticle extends VerletParticle {<\/p>\n<p>String mapCoord;<\/p>\n<p>MapParticle(Vec3D _loc, String _s) {<br \/>\nsuper (_loc);<br \/>\nmapCoord = _s;<br \/>\n}<\/p>\n<p>void run() {<br \/>\n\/\/get the grid pos and update if necessary<br \/>\nString newMapCoord = getCoord();<br \/>\nif (newMapCoord != mapCoord) {<br \/>\nparticleMap.remove(mapCoord, this);<br \/>\nparticleMap.put(newMapCoord, this);<br \/>\nmapCoord = newMapCoord;<br \/>\n}<br \/>\n\/\/attract to neighbouring particles<br \/>\nif (particleMap.getCollection(mapCoord)!=null) {<br \/>\nfor (MapParticle p: (ArrayList)particleMap.getCollection(mapCoord)) {<br \/>\nattract(p);<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>String getCoord(){<br \/>\nString s = &#8220;&#8221;+Math.floor(x\/gridRes)+Math.floor(y\/gridRes)+Math.floor(z\/gridRes);<br \/>\nreturn s;<br \/>\n}<\/p>\n<p>void attract(MapParticle P) {<br \/>\nVec3D diff = sub(P);<br \/>\ndiff.invert();<br \/>\nfloat d = diff.magnitude();<br \/>\nif (d&gt;1) {<br \/>\ndiff.scaleSelf(nodeStiffness\/d);<br \/>\naddVelocity(diff);<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Saving&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>void savePts(){<br \/>\n\/*<br \/>\nString[] lines = new String[m.totalSize()];<br \/>\nint c=0;<\/p>\n<p>Set set = m.entrySet();<br \/>\nIterator it = set.iterator();<br \/>\nwhile (it.hasNext()) {<br \/>\nMap.Entry entry = (Map.Entry) it.next();<br \/>\nfor (Agent a :(ArrayList)entry.getValue()){<br \/>\nlines[c] = &#8220;&#8221;;<\/p>\n<p>for(TrailPt t:a.trail){<br \/>\nlines[c] =lines[c]+ (t.loc.x +&#8221;,&#8221; + t.loc.y + &#8220;,&#8221; + t.loc.z + &#8220;\/&#8221;);<br \/>\n}<br \/>\nc++;<br \/>\n}<br \/>\n}<br \/>\nsaveStrings(&#8220;lines.txt&#8221;, lines);<\/p>\n<p>*\/<br \/>\n}<\/p>\n<p>void saveBundles(){<br \/>\nString[] lines = new String[m.totalSize()];<br \/>\nint c=0;<br \/>\nfor (Fibre f :fibrePop){<br \/>\nlines[c] = &#8220;&#8221;;<\/p>\n<p>for(Node n:f.nodes){<br \/>\nlines[c] =lines[c]+ (n.loc.x +&#8221;,&#8221; + n.loc.y + &#8220;,&#8221; + n.loc.z + &#8220;\/&#8221;);<br \/>\n}<br \/>\nc++;<br \/>\n}<br \/>\nsaveStrings(&#8220;lines.txt&#8221;, lines);<br \/>\n}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\/* * Copyright (c) 2012 Gwyllim Jahn * http:\/\/scripts.crida.net\/gh * Developed By Gwyllim Jahn, Cam Newnham and Mark-Henry Delacrauz * during the 2012 RMIT nCertainties studio. * * This code makes extensive use of several freely distributed * processing libraries &#8211; thankyou especially to toxi. * This code is free software; you can redistribute it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":20,"menu_order":0,"comment_status":"closed","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-554","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/554","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/comments?post=554"}],"version-history":[{"count":4,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/554\/revisions"}],"predecessor-version":[{"id":1013,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/554\/revisions\/1013"}],"up":[{"embeddable":true,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/20"}],"wp:attachment":[{"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/media?parent=554"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}