{"id":603,"date":"2012-04-16T14:16:07","date_gmt":"2012-04-16T14:16:07","guid":{"rendered":"http:\/\/www.new-territories.com\/blog\/rmit.uts\/?page_id=603"},"modified":"2012-04-30T02:51:10","modified_gmt":"2012-04-30T02:51:10","slug":"the-opus-of-caspar-questel_coding","status":"publish","type":"page","link":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/code\/the-opus-of-caspar-questel_coding\/","title":{"rendered":"The Opus of Caspar Questel_Coding"},"content":{"rendered":"<p>\/*<br \/>\n* Copyright (c) 2012 Gwyllim Jahn<br \/>\n* http:\/\/scripts.crida.net\/gh<\/p>\n<p>* Developed By Gwyllim Jahn, Kiet Nguyen and Vonne Yang<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>\/<\/p>\n<p>\/\/BONE_WEAVING<\/p>\n<p>\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;StitchersImport_black_moving&#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;<br \/>\n\/\/number of agents per tree<br \/>\nint numAgents = 30;<br \/>\nboolean record = false;<br \/>\nboolean agentsOn = true;<br \/>\nArrayList&lt;Agent&gt;agentPop = new ArrayList&lt;Agent&gt;();<br \/>\nArrayList&lt;Agent&gt;addList = new ArrayList&lt;Agent&gt;();<br \/>\nMultiValueMap particleMap = new MultiValueMap();<br \/>\nMovieMaker mm;<br \/>\nint gridRes = 20;<br \/>\nboolean recording = false;<br \/>\n\/\/add the pause variable<br \/>\nBoolean paused = true;<br \/>\nBoolean bundling = false;<br \/>\n\/\/agent variables<br \/>\nBoolean drawSingle = false;<br \/>\nint ct =0;<br \/>\n\/\/agent variables<br \/>\n\/\/number of points to draw a trail with<br \/>\nint trailLength\u00a0 = 300;<br \/>\nfloat agentSpeed = 1;<br \/>\n\/\/distance between trail points<br \/>\nint dropRate = 2;<br \/>\n\/\/size of field to spawn agents<br \/>\nfloat spawnSizeXY = 30;<br \/>\nfloat aAttract = 0.9;<br \/>\nfloat aAlign = 0.05;<br \/>\nfloat aRepel = 4;<br \/>\nfloat aAccel = 0.04;<\/p>\n<p>\/\/bundling variables<br \/>\nfloat cutoff = 20;<br \/>\nfloat stiffness = 0.05;<br \/>\nfloat numToMove = 1;<br \/>\nfloat nodeStiffness = 0.05;<br \/>\nfloat strandStiffness = 0.08;<\/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;-SETUP<\/p>\n<p>void setup(){<br \/>\nsize(600,600,OPENGL);<\/p>\n<p>cam =new PeasyCam(this,-50,-50,0,200);<br \/>\nphysics.setDrag(0.05);<br \/>\n\/\/spawn();<br \/>\nsetupP5();<br \/>\nimportFibres();<br \/>\nmm = new MovieMaker(this, width, height, &#8220;drawing.mov&#8221;, 30, MovieMaker.ANIMATION, MovieMaker.HIGH);<\/p>\n<p>background(0);<br \/>\n}<\/p>\n<p>void draw(){<br \/>\nprint(frameRate+&#8221;\u00a0 &#8220;);<br \/>\nbackground(0);<br \/>\nfloat[] gLA = cam.getLookAt();<\/p>\n<p>cam.lookAt(gLA[0],gLA[1],gLA[2]+1);<\/p>\n<p>if(record){<br \/>\nbeginRaw(DXF,&#8221;test.dxf&#8221;);<br \/>\n}<br \/>\n\/\/update the physics engine<br \/>\nphysics.update();<\/p>\n<p>for (Agent a: agentPop){<br \/>\na.run();<br \/>\n}<\/p>\n<p>if(record){<br \/>\nendRaw();<br \/>\nrecord = false;<br \/>\n}<br \/>\nif(recording)mm.addFrame();<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 \/>\nsavePts();<br \/>\n}<\/p>\n<p>\/\/reset the sketch<br \/>\nif (key == &#8216;r&#8217;) {<br \/>\nbackground(255);<br \/>\n\/\/importLandscape();<br \/>\nphysics = new VerletPhysics();<br \/>\n}<\/p>\n<p>if (key == &#8216; &#8216;) {<br \/>\nif(!recording) {<br \/>\nrecording = true;<br \/>\n}else{<br \/>\nrecording = false;<br \/>\nmm.finish();\u00a0 \/\/ Finish the movie if space bar is pressed!<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;Agents&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>&nbsp;<\/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,acc;<br \/>\nStrand trail;<br \/>\nArrayList&lt;Strand&gt; pastStrands;<br \/>\nboolean locked;<\/p>\n<p>Agent(Vec3D _loc, Vec3D _vel, boolean l){<br \/>\nloc = _loc;<br \/>\nvel = _vel;<br \/>\nlocked = l;<br \/>\nif(!locked){<br \/>\nacc= new Vec3D(0,0,0);<br \/>\ntrail = new Strand(loc);<br \/>\npastStrands = new ArrayList&lt;Strand&gt;();<br \/>\n}<br \/>\n}<\/p>\n<p>void run(){<br \/>\n\/\/moves the particles based on proximity to trees<br \/>\nif(!locked){<br \/>\nif(!paused){<br \/>\nsearchAgents();<br \/>\nupdatePos();<br \/>\n}<\/p>\n<p>trail.update(loc);<\/p>\n<p>trail.run();<\/p>\n<p>for(Strand s:pastStrands){<br \/>\ns.run();<br \/>\n}<br \/>\n}else{<br \/>\n\/\/line(loc.x,loc.y,loc.z,loc.x+vel.x,loc.y+vel.y,loc.z+vel.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;&#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;-<br \/>\nvoid searchAgents(){<br \/>\n\/\/reset accel<br \/>\nfor (Agent a:agentPop){<br \/>\n\/\/get essential variables<br \/>\nVec3D diff = a.loc.sub(loc.copy());<br \/>\nfloat d = diff.magnitude();<br \/>\nfloat val = 1;<br \/>\nif (a.locked) val = 2;<\/p>\n<p>if(d&lt;30&amp;&amp;d&gt;0){<br \/>\nattract(diff.copy(),d\/val); \/\/attract to neighbour<br \/>\nalign(a.vel.copy(),d); \/\/align with neighbour<br \/>\nif(d&lt;10) {<br \/>\nrepel(diff.copy(),d); \/\/avoid neighbour<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>void attract (Vec3D v, float d){<br \/>\nacc.interpolateToSelf(v,(aAttract\/d));<br \/>\n}<\/p>\n<p>void align(Vec3D v, float d){<br \/>\nacc.interpolateToSelf(v,aAlign);<br \/>\n}<\/p>\n<p>void repel (Vec3D v, float d){<br \/>\nv.invert();<br \/>\nacc.interpolateToSelf(v,(aRepel\/d));<br \/>\n}<\/p>\n<p>void respawn(){<br \/>\nVec3D loc = new Vec3D(random(spawnSizeXY\/2,spawnSizeXY*1.5),random(spawnSizeXY\/2,spawnSizeXY*1.5),0);<\/p>\n<p>Vec3D vel = new Vec3D(0,0,1);<br \/>\nAgent a = new Agent(loc,vel,false);<br \/>\naddList.add(a);<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 \/>\nacc.limit(aAccel);<br \/>\nvel.addSelf(acc);<br \/>\nvel.limit(agentSpeed);<br \/>\nloc.addSelf(vel);<\/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 mySlider6 =controlP5.addSlider(&#8220;agentSpeed&#8221;,0.1,3.5).linebreak();<br \/>\nmySlider6.setWindow(controlWindow);<\/p>\n<p>controlWindow.setTitle(&#8220;Spring GUI&#8221;);<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;Initalisation&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>void spawn(Vec3D l,Vec3D v){<\/p>\n<p>for (int i=0;i&lt;numAgents;i++){<br \/>\n\/\/ Vec3D loc = new Vec3D(random(0,gW*gRes),random(0,gH*gRes),0);<br \/>\nVec3D loc = new Vec3D(random(-spawnSizeXY\/2,spawnSizeXY*1.5),random(-spawnSizeXY\/2,spawnSizeXY*1.5),0);<br \/>\nloc.addSelf(l);<br \/>\nVec3D vel = v.copy();<br \/>\nAgent a = new Agent(loc,vel,false);<br \/>\nagentPop.add(a);<br \/>\n}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;import functions<\/p>\n<p>void importFibres() {<br \/>\n\/\/load text<br \/>\nString[] txtLines = loadStrings(&#8220;fibres2import.txt&#8221;);<\/p>\n<p>\/\/ loop thru them<br \/>\nint count = 0;<br \/>\nint fPt;<br \/>\nfor (int i = 0; i &lt; txtLines.length; ++i) {<\/p>\n<p>\/\/splits strand points<br \/>\nString[] arrCoords = split(txtLines[i], &#8216;_&#8217;);<br \/>\nVec3D lastPt = null;<br \/>\nfor (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 \/>\n\/\/set siblings<br \/>\nif (j&gt;0) {<\/p>\n<p>Vec3D loc = lastPt.copy();<br \/>\nVec3D vel = tmpPt.sub(lastPt);<\/p>\n<p>Agent a= new Agent(loc,vel,true);<br \/>\nagentPop.add(a);<\/p>\n<p>if(j==1) spawn(loc,vel);<br \/>\n}<br \/>\nlastPt = tmpPt.copy();<br \/>\n}<\/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;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>ArrayList&lt;VerletSpring&gt; trail;<br \/>\nArrayList&lt;MapParticle&gt; pts;<br \/>\nfloat dropNum;<br \/>\nboolean hang;<\/p>\n<p>Strand(Vec3D _loc){<\/p>\n<p>trail = new ArrayList&lt;VerletSpring&gt;();<br \/>\npts = new ArrayList&lt;MapParticle&gt;();<br \/>\nMapParticle p = new MapParticle(_loc,getCoord(_loc),this);<br \/>\np.lock();<br \/>\npts.add(p);<br \/>\ndropNum = 0;<br \/>\nhang = false;<\/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()&lt;trailLength){<\/p>\n<p>MapParticle p = new MapParticle(_loc,getCoord(_loc),this);<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)),strandStiffness);<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>l.setStrength(l.getStrength()*0.99);<\/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>if(hang)a.addVelocity(new Vec3D(0,0,-0.09));<\/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\/\/only hang once<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;mapParticales&#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;<br \/>\nStrand parent;<br \/>\nint age;<br \/>\nboolean alive;<\/p>\n<p>MapParticle(Vec3D _loc, String _s,Strand _p) {<br \/>\nsuper (_loc);<br \/>\nmapCoord = _s;<br \/>\nparent = _p;<br \/>\nage = 0;<br \/>\nalive = true;<br \/>\n}<\/p>\n<p>void run() {<br \/>\n\/\/get the grid pos and update if necessary<br \/>\nif(alive){<br \/>\nage++;<\/p>\n<p>String newMapCoord = getCoord();<br \/>\nif (newMapCoord != mapCoord) {<br \/>\nparticleMap.remove(mapCoord, this);<br \/>\nparticleMap.put(newMapCoord, this);<br \/>\nmapCoord = newMapCoord;<br \/>\n}<\/p>\n<p>ArrayList&lt;Vec3D&gt; closest = new ArrayList&lt;Vec3D&gt;();<br \/>\nfloat minD = 999999;<\/p>\n<p>\/\/attract to neighbouring particles<br \/>\nif (particleMap.getCollection(mapCoord)!=null) {<br \/>\nfor (MapParticle p: (ArrayList&lt;MapParticle&gt;)particleMap.getCollection(mapCoord)) {<br \/>\nif(p.parent!=parent){<br \/>\nVec3D diff = sub(p);<br \/>\ndiff.invert();<br \/>\nfloat d = diff.magnitude();<br \/>\nif(d&gt;0.1){<br \/>\nif (d&lt;minD){<br \/>\nclosest.add(diff);<br \/>\nif(closest.size()&gt;numToMove) closest.remove(0);<br \/>\nminD =d;<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>for (Vec3D v:closest){<br \/>\nfloat d = v.magnitude();<br \/>\nv.scaleSelf(nodeStiffness\/d);<br \/>\naddVelocity(v);<br \/>\n}<\/p>\n<p>}<br \/>\nif(age&gt;50){<br \/>\nphysics.particles.remove(this);<br \/>\nalive = false;<br \/>\nage = 0;<br \/>\n}<\/p>\n<p>}<\/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>}<\/p>\n<p>&nbsp;<\/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 \/>\nString[] lines = new String[agentPop.size()];<br \/>\nint c=0;<br \/>\nfor (int i =0;i&lt;agentPop.size();i++) {<br \/>\nAgent a = (Agent) agentPop.get(i);<br \/>\nlines[c] = &#8220;&#8221;;<br \/>\nif(a.trail!=null){<br \/>\nfor(MapParticle t:a.trail.pts){<br \/>\nlines[c] =lines[c]+ (t.x +&#8221;,&#8221; + t.y + &#8220;,&#8221; + t.z + &#8220;\/&#8221;);<br \/>\n}<br \/>\n}<br \/>\nc++;<br \/>\n}<\/p>\n<p>saveStrings(&#8220;lines.txt&#8221;, lines);<br \/>\n}<\/p>\n<p>BONE_&amp;_SKIN<\/p>\n<p>\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;StitchersImportSkin&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>&nbsp;<\/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;<br \/>\n\/\/number of agents per tree<br \/>\nint numAgents = 3;<br \/>\nboolean record = false;<br \/>\nboolean agentsOn = true;<br \/>\nArrayList&lt;Agent&gt;agentPop = new ArrayList&lt;Agent&gt;();<br \/>\nArrayList&lt;Agent&gt;addList = new ArrayList&lt;Agent&gt;();<br \/>\nMultiValueMap particleMap = new MultiValueMap();<\/p>\n<p>int gridRes = 20;<\/p>\n<p>\/\/add the pause variable<br \/>\nBoolean paused = false;<br \/>\nBoolean bundling = false;<br \/>\n\/\/agent variables<br \/>\nBoolean drawSingle = false;<br \/>\nint ct =0;<br \/>\n\/\/agent variables<br \/>\n\/\/number of points to draw a trail with<br \/>\nint trailLength\u00a0 = 300;<br \/>\nfloat agentSpeed = 1;<br \/>\n\/\/distance between trail points<br \/>\nint dropRate = 2;<br \/>\n\/\/size of field to spawn agents<br \/>\nfloat spawnSizeXY = 20;<br \/>\nfloat aAttract = 1;<br \/>\nfloat aAlign = 0.03;<br \/>\nfloat aRepel = 3;<br \/>\nfloat aAccel = 0.02;<\/p>\n<p>\/\/bundling variables<br \/>\nfloat cutoff = 20;<br \/>\nfloat stiffness = 0.05;<br \/>\nfloat numToMove = 1;<br \/>\nfloat nodeStiffness = 0.05;<br \/>\nfloat strandStiffness = 0.08;<\/p>\n<p>int numVertPerSkin = 80;<\/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;-SETUP<\/p>\n<p>void setup(){<br \/>\nsize(600,600,OPENGL);<\/p>\n<p>cam =new PeasyCam(this,200);<br \/>\nphysics.setDrag(0.05);<br \/>\n\/\/spawn();<br \/>\nsetupP5();<br \/>\nimportFibres();<\/p>\n<p>background(255);<br \/>\n}<\/p>\n<p>void draw(){<br \/>\n\/\/ print(frameRate+&#8221;\u00a0 &#8220;);<br \/>\nbackground(255);<br \/>\nif(record){<br \/>\nbeginRaw(DXF,&#8221;test.dxf&#8221;);<br \/>\n}<br \/>\n\/\/update the physics engine<br \/>\nif(!paused)physics.update();<\/p>\n<p>boolean allLocked = true;<\/p>\n<p>for (Agent a: agentPop){<br \/>\na.run();<br \/>\nif(!a.locked)allLocked = false;<br \/>\n}<\/p>\n<p>if(allLocked) importFibres();<\/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 \/>\nsavePts();<br \/>\n}<\/p>\n<p>\/\/reset the sketch<br \/>\nif (key == &#8216;r&#8217;) {<br \/>\nbackground(255);<br \/>\n\/\/importLandscape();<br \/>\nphysics = new VerletPhysics();<br \/>\n}<br \/>\n}<\/p>\n<p>&nbsp;<\/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 {<br \/>\nVec3D initLoc,initVel;<br \/>\nVec3D loc,vel,acc;<br \/>\nStrand trail;<br \/>\nArrayList&lt;Strand&gt; pastStrands;<br \/>\nboolean locked;<br \/>\nint depositNum;<br \/>\nint age;<\/p>\n<p>Agent(Vec3D _loc, Vec3D _vel, boolean l){<br \/>\nloc = _loc;<br \/>\nvel = _vel;<br \/>\ninitLoc = _loc.copy();<br \/>\ninitVel = _vel.copy();<\/p>\n<p>locked = l;<br \/>\nif(!locked){<br \/>\nacc= new Vec3D(0,0,0);<br \/>\ntrail = new Strand(loc);<br \/>\npastStrands = new ArrayList&lt;Strand&gt;();<br \/>\n}<br \/>\ndepositNum = 0;<br \/>\nage = 0;<br \/>\n}<\/p>\n<p>void run(){<br \/>\n\/\/moves the particles based on proximity to trees<br \/>\nif(!locked){<br \/>\nif(!paused){<br \/>\nsearchAgents();<br \/>\nupdatePos();<\/p>\n<p>trail.update(loc);<\/p>\n<p>makeSkin();<br \/>\n}<\/p>\n<p>age++;<br \/>\n}<\/p>\n<p>if(age&gt;0){<br \/>\ntrail.run();<br \/>\nfor(Strand s:pastStrands){<br \/>\ns.run();<br \/>\n}<br \/>\n}<br \/>\nline(loc.x,loc.y,loc.z,loc.x+vel.x,loc.y+vel.y,loc.z+vel.z);<\/p>\n<p>if(age&gt;300)locked = true;<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;-<br \/>\nvoid searchAgents(){<br \/>\n\/\/reset accel<br \/>\nfor (Agent a:agentPop){<br \/>\n\/\/get essential variables<br \/>\nVec3D diff = a.loc.sub(loc.copy());<br \/>\nfloat d = diff.magnitude();<\/p>\n<p>if(d&lt;100&amp;&amp;d&gt;0){<br \/>\nattract(diff.copy(),d); \/\/attract to neighbour<\/p>\n<p>if(a.locked){<br \/>\nfloat ang = vel.angleBetween(a.vel);<br \/>\nif(ang&gt;PI\/2){<br \/>\nalign(a.vel.copy().invert(),d);<br \/>\n}else{<br \/>\nalign(a.vel.copy(),d);<br \/>\n}<br \/>\n}else{<br \/>\nalign(a.vel.copy(),d); \/\/align with neighbour<br \/>\n}<br \/>\nif(d&lt;30) {<br \/>\nif(a.locked) d=d*2;<br \/>\nrepel(diff.copy(),d); \/\/avoid neighbour<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>void attract (Vec3D v, float d){<br \/>\nacc.interpolateToSelf(v,(aAttract\/d));<br \/>\n}<\/p>\n<p>void align(Vec3D v, float d){<br \/>\nacc.interpolateToSelf(v,aAlign);<br \/>\n}<\/p>\n<p>void repel (Vec3D v, float d){<br \/>\nv.invert();<br \/>\nacc.interpolateToSelf(v,(aRepel\/d));<br \/>\n}<\/p>\n<p>void respawn(){<br \/>\nVec3D loc = new Vec3D(random(spawnSizeXY\/2,spawnSizeXY*1.5),random(spawnSizeXY\/2,spawnSizeXY*1.5),0);<\/p>\n<p>Vec3D vel = new Vec3D(0,0,1);<br \/>\nAgent a = new Agent(loc,vel,false);<br \/>\naddList.add(a);<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 \/>\nacc.limit(aAccel);<br \/>\nvel.addSelf(acc);<br \/>\nvel.limit(agentSpeed);<br \/>\nloc.addSelf(vel);<\/p>\n<p>}<br \/>\nvoid makeSkin(){<\/p>\n<p>if(depositNum&gt;numVertPerSkin){<br \/>\nStrand skin = new Strand(loc);<br \/>\nVerletSpring s = new VerletSpring(skin.pts.get(0),trail.pts.get(trail.pts.size()-1),0,strandStiffness);<br \/>\nphysics.addSpring(s);<\/p>\n<p>skin.hang = true;<br \/>\nVec3D svel = new Vec3D(random(-1,1),random(-1,1),0);<br \/>\nfor (int i = 1;i&lt;=numVertPerSkin\/2;i++){<br \/>\nsvel.normalizeTo(i*2);<br \/>\nskin.addParticle(loc.add(svel));<br \/>\n}<br \/>\npastStrands.add(skin);<br \/>\ndepositNum = 0;<br \/>\n}<\/p>\n<p>depositNum++;<br \/>\n}<\/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>&nbsp;<\/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 mySlider6 =controlP5.addSlider(&#8220;agentSpeed&#8221;,0.1,3.5).linebreak();<br \/>\nmySlider6.setWindow(controlWindow);<\/p>\n<p>controlWindow.setTitle(&#8220;Spring GUI&#8221;);<\/p>\n<p>&nbsp;<\/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>&nbsp;<\/p>\n<p>void spawn(Vec3D l,Vec3D v){<\/p>\n<p>for (int i=0;i&lt;numAgents;i++){<br \/>\n\/\/ Vec3D loc = new Vec3D(random(0,gW*gRes),random(0,gH*gRes),0);<br \/>\nVec3D loc = new Vec3D(random(-spawnSizeXY\/2,spawnSizeXY*1.5),random(-spawnSizeXY\/2,spawnSizeXY*1.5),0);<br \/>\nloc.addSelf(l);<br \/>\nVec3D vel = v.copy();<br \/>\nAgent a = new Agent(loc,vel,false);<br \/>\nagentPop.add(a);<br \/>\n}<\/p>\n<p>}<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;import functions<\/p>\n<p>void importFibres() {<br \/>\n\/\/load text<br \/>\nString[] txtLines = loadStrings(&#8220;fibres2import.txt&#8221;);<\/p>\n<p>\/\/ loop thru them<br \/>\nint count = 0;<br \/>\nint fPt;<br \/>\nfor (int i = 0; i &lt; txtLines.length; ++i) {<\/p>\n<p>\/\/splits strand points<br \/>\nString[] arrCoords = split(txtLines[i], &#8216;_&#8217;);<br \/>\nVec3D lastPt = null;<br \/>\nfor (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);<\/p>\n<p>if (j&gt;0) {<\/p>\n<p>Vec3D loc = lastPt.copy();<br \/>\nVec3D vel = tmpPt.sub(lastPt);<\/p>\n<p>\/\/Agent a= new Agent(loc,vel,true);<br \/>\n\/\/agentPop.add(a);<\/p>\n<p>if(j==1) spawn(loc,vel);<br \/>\n}<br \/>\nlastPt = tmpPt.copy();<br \/>\n}<\/p>\n<p>}<br \/>\n}<\/p>\n<p>&nbsp;<\/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>ArrayList&lt;VerletSpring&gt; trail;<br \/>\nArrayList&lt;MapParticle&gt; pts;<br \/>\nfloat dropNum;<br \/>\nboolean hang;<\/p>\n<p>Strand(Vec3D _loc){<\/p>\n<p>trail = new ArrayList&lt;VerletSpring&gt;();<br \/>\npts = new ArrayList&lt;MapParticle&gt;();<br \/>\nMapParticle p = new MapParticle(_loc,getCoord(_loc),this);<br \/>\np.lock();<br \/>\npts.add(p);<br \/>\ndropNum = 0;<br \/>\nhang = false;<\/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()&lt;trailLength){<\/p>\n<p>MapParticle p = new MapParticle(_loc,getCoord(_loc),this);<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)),strandStiffness);<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>void addParticle(Vec3D _loc){<\/p>\n<p>\/\/update the trail geom every 5 moves<br \/>\nif(trail.size()&lt;trailLength){<\/p>\n<p>MapParticle p = new MapParticle(_loc,getCoord(_loc),this);<br \/>\nString coord = getCoord(p);<br \/>\nparticleMap.put(coord,p);<br \/>\nMapParticle lastP = pts.get(pts.size()-1);<\/p>\n<p>VerletSpring s = new VerletSpring(pts.get(pts.size()-1),p,(p.distanceTo(lastP)),strandStiffness);<br \/>\nphysics.addParticle(p);<br \/>\nphysics.addSpring(s);<\/p>\n<p>trail.add(s);<br \/>\npts.add(p);<br \/>\n}<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);<\/p>\n<p>float c =1;<br \/>\nif(agentsOn){<br \/>\nfor (VerletSpring l : trail){<\/p>\n<p>if(!paused){<br \/>\nl.setStrength(l.getStrength()*0.98);<\/p>\n<p>MapParticle a = (MapParticle) l.a;<\/p>\n<p>if(hang)a.addVelocity(new Vec3D(0,0,-0.09));<\/p>\n<p>a.run();<\/p>\n<p>}<br \/>\nfloat gs = ((trail.size()-c)\/trail.size())*255;<br \/>\nstroke(gs);<br \/>\nline (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\/\/if hanging look for ground condition or other particles<br \/>\nif(hang){<\/p>\n<p>\/\/check to see if the end of the strand meets some conditions<br \/>\nMapParticle last = pts.get(pts.size()-1);<\/p>\n<p>last.addVelocity(new Vec3D(0,0,-0.09));<br \/>\nlast.run();<br \/>\nif(last.closestP!=null){<br \/>\nfloat d = last.distanceTo(last.closestP);<\/p>\n<p>if(d&lt;2){<br \/>\nprint(&#8220;yep&#8221;);<br \/>\n\/\/make a spring between the two and contract<br \/>\npts.get(0).unlock();<br \/>\nVerletSpring s = new VerletSpring(last,last.closestP,d,strandStiffness);<br \/>\nphysics.addSpring(s);<br \/>\ntrail.add(s);<\/p>\n<p>for (VerletSpring spr:trail){<br \/>\nspr.setRestLength(0);<\/p>\n<p>hang = false;<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>if(last.z&lt;0){<br \/>\nlast.lock();<br \/>\npts.get(0).unlock();<br \/>\nfor (VerletSpring spr:trail){<br \/>\nspr.setRestLength(0);<br \/>\n\/\/spr.setStrength(strandStiffness*2);<\/p>\n<p>}<br \/>\nhang = false;<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;mapParticles&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;\/\/<\/p>\n<p>&nbsp;<\/p>\n<p>class MapParticle extends VerletParticle {<\/p>\n<p>String mapCoord;<br \/>\nStrand parent;<br \/>\nint age;<br \/>\nboolean alive;<br \/>\nMapParticle closestP;<\/p>\n<p>MapParticle(Vec3D _loc, String _s,Strand _p) {<br \/>\nsuper (_loc);<br \/>\nmapCoord = _s;<br \/>\nparent = _p;<br \/>\nage = 0;<br \/>\nalive = true;<br \/>\nclosestP = null;<br \/>\n}<\/p>\n<p>void run() {<br \/>\n\/\/get the grid pos and update if necessary<br \/>\nif(alive){<br \/>\nage++;<\/p>\n<p>String newMapCoord = getCoord();<br \/>\nif (newMapCoord != mapCoord) {<br \/>\nparticleMap.remove(mapCoord, this);<br \/>\nparticleMap.put(newMapCoord, this);<br \/>\nmapCoord = newMapCoord;<br \/>\n}<\/p>\n<p>ArrayList&lt;Vec3D&gt; closest = new ArrayList&lt;Vec3D&gt;();<br \/>\nfloat minD = 999999;<\/p>\n<p>\/\/attract to neighbouring particles<br \/>\nif (particleMap.getCollection(mapCoord)!=null) {<br \/>\nfor (MapParticle p: (ArrayList&lt;MapParticle&gt;)particleMap.getCollection(mapCoord)) {<br \/>\nif(p.parent!=parent){<br \/>\nVec3D diff = sub(p);<br \/>\ndiff.invert();<br \/>\nfloat d = diff.magnitude();<br \/>\nif(d&gt;0.1){<br \/>\nif (d&lt;minD){<br \/>\nclosest.add(diff);<br \/>\nif(closest.size()&gt;numToMove) closest.remove(0);<br \/>\nminD =d;<br \/>\nclosestP=p;<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\n}<\/p>\n<p>for (Vec3D v:closest){<br \/>\nfloat d = v.magnitude();<br \/>\nv.scaleSelf(nodeStiffness\/d);<br \/>\naddVelocity(v);<br \/>\n}<\/p>\n<p>}<br \/>\nif(age&gt;200){<br \/>\nphysics.particles.remove(this);<br \/>\nalive = false;<br \/>\nage = 0;<br \/>\n}<\/p>\n<p>}<\/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>}<\/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;\/\/<br \/>\nvoid savePts(){<br \/>\nString[] lines = new String[agentPop.size()];<br \/>\nint c=0;<br \/>\nfor (int i =0;i&lt;agentPop.size();i++) {<br \/>\nAgent a = (Agent) agentPop.get(i);<br \/>\nlines[c] = &#8220;&#8221;;<br \/>\nif(a.trail!=null){<br \/>\nfor(MapParticle t:a.trail.pts){<br \/>\nlines[c] =lines[c]+ (t.x +&#8221;,&#8221; + t.y + &#8220;,&#8221; + t.z + &#8220;\/&#8221;);<br \/>\n}<br \/>\n}<br \/>\nc++;<br \/>\n}<\/p>\n<p>saveStrings(&#8220;lines.txt&#8221;, lines);<\/p>\n<p>String[] skin = new String[agentPop.size()];<br \/>\nc=0;<br \/>\nfor (int i =0;i&lt;agentPop.size();i++) {<br \/>\nAgent a = (Agent) agentPop.get(i);<\/p>\n<p>if(a.pastStrands!=null){<br \/>\nfor(Strand s:a.pastStrands){<br \/>\nskin[c] = &#8220;&#8221;;<br \/>\nfor(MapParticle t:s.pts){<br \/>\nskin[c] =skin[c]+ (t.x +&#8221;,&#8221; + t.y + &#8220;,&#8221; + t.z + &#8220;\/&#8221;);<br \/>\n}<br \/>\n}<br \/>\n}<br \/>\nc++;<br \/>\n}<\/p>\n<p>saveStrings(&#8220;skin.txt&#8221;, skin);<br \/>\n}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\/* * Copyright (c) 2012 Gwyllim Jahn * http:\/\/scripts.crida.net\/gh * Developed By Gwyllim Jahn, Kiet Nguyen and Vonne Yang * 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-603","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/603","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=603"}],"version-history":[{"count":5,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/603\/revisions"}],"predecessor-version":[{"id":1016,"href":"https:\/\/www.new-territories.com\/blog\/rmit.uts\/wp-json\/wp\/v2\/pages\/603\/revisions\/1016"}],"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=603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}