public class LarvaPath { int stepCount; int stepIndex; int number; char type; Step[] steps; Integrator stepIntegrator; int lastDrawnStepCount; private float calculateDirection(Step target, Step src) { float offsetX = target.x - src.x; float offsetY = -1 * (target.y - src.y); float direction; if (offsetX != 0) { direction = atan(offsetY / offsetX); if (direction == 0) { if (offsetX < 0) { direction = PI; } } else if (offsetY > 0 && offsetX < 0) // quadrant II { direction = PI - direction; } else if (offsetY < 0 && offsetX < 0) //quadrant III { direction = PI + direction; } else if (offsetY < 0 && offsetX > 0) // quadrant IV { direction = PI * 2 + direction; } } else //offsetX == 0 { if (offsetY > 0) { direction = PI / 2.0; } else if (offsetY < 0) { direction = 3 * PI / 2.0; } else { direction = 0; } } return direction; } public LarvaPath() { this.stepIndex = 0; this.stepCount = 0; this.number = 0; this.lastDrawnStepCount = 0; //println("initialize empty larvapath"); } public LarvaPath(int stepCount, char type,int number) { this.lastDrawnStepCount = 0; this.stepIndex = 0; this.stepCount = stepCount; this.type = type; this.number = number; steps = new Step[stepCount]; //println("initialize larvapath:"+stepCount); } public boolean AppendStep(float x, float y) { if (this.stepIndex >= this.stepCount) { return false; } this.steps[stepIndex] = new Step(x,y); if (stepIndex > 0) { //calculation directon for last step, using current step's information float direction = calculateDirection(this.steps[stepIndex], this.steps[stepIndex - 1]); this.steps[stepIndex - 1].SetDirection(direction); } stepIndex++; return true; } public int GetStepCount() { return this.stepCount; } public void Draw(int toStep) { rectMode(CENTER); ellipseMode(CENTER); strokeJoin(ROUND); //println("Drawing path #" + this.number); int stepsToDraw; if (this.number > drawPathCount) { return; } colorMode(HSB,360,100,100,100); float hueValue = map(number,1,10,1,30); noFill(); if (toStep == -1) { stepsToDraw = this.stepCount; } else { stepsToDraw = min(this.stepCount,toStep); } lastDrawnStepCount = stepsToDraw; //print(" -- " + stepsToDraw + "steps: "); //println(" -- " + stepsToDraw + "/" + this.steps.length + " steps"); for (int i = 0; i < stepsToDraw; i++) { //println(" -- -- " + this.steps[i].x + "," + this.steps[i].y); float satur = 100;//map(i,0,this.stepCount,90,100); float bright = 100;//map(i,0,this.stepCount,80,100); noStroke(); if (stepsToDraw == this.stepCount) { //bright = 100; } if (i == 0)//first node { if (this.type == 'B') fill(baseHueB + 15,satur,bright,10); else fill(baseHueL + 15,satur,bright,10); ellipse(TX(this.steps[i].x),TY(this.steps[i].y),20,20); if (this.type == 'B') fill(hueValue + baseHueB,satur,bright,60); else fill(hueValue + baseHueL,satur,bright,60); ellipse(TX(this.steps[i].x),TY(this.steps[i].y),16,16); fill(1,0,100); text(labels[this.number - 1],TX(this.steps[i].x),TY(this.steps[i].y) + 4); } else if (i == stepsToDraw - 1) // last node { float radius = map(i,0,maxStep - 1,25,50); float radiusInner = map(i,0,maxStep - 1,12,36); if (this.type == 'B') fill(baseHueB + 15,satur,bright,25); else fill(baseHueL + 15,satur,bright,25); if (i == this.stepCount - 1) rect(TX(this.steps[i].x),TY(this.steps[i].y),radius,radius); else ellipse(TX(this.steps[i].x),TY(this.steps[i].y),radius,radius); if (this.type == 'B') fill(hueValue + baseHueB,satur,bright,40); else fill(hueValue + baseHueL,satur,bright,40); if (i == this.stepCount - 1) rect(TX(this.steps[i].x),TY(this.steps[i].y),radiusInner,radiusInner); else ellipse(TX(this.steps[i].x),TY(this.steps[i].y),radiusInner,radiusInner); fill(1,0,100); text(labels[this.number - 1],TX(this.steps[i].x),TY(this.steps[i].y) + 4); } else //normal nodes { if (i % 4 == 0) { if (debug) { float expected = calculateDirection(maxOdorStep, this.steps[i - 1]) / PI; float direction = this.steps[i - 1].direction / PI; text(nf(direction,1,2) + "/" + nf(expected,1,2),TX(this.steps[i].x),TY(this.steps[i].y) - 10); //text(nf(direction - expected,1,2),TX(this.steps[i].x),TY(this.steps[i].y) - 10); } } } if (this.type == 'B') stroke(hueValue + baseHueB,100,bright,36); else stroke(hueValue + baseHueL,100,bright,36); if (i > 0) { noStroke(); float expected = calculateDirection(maxOdorStep, this.steps[i - 1]); float direction = this.steps[i - 1].direction; if (expected < PI) { expected += 2 * PI; } if (direction < PI) { direction += 2 * PI; } float deviation = abs(expected - direction) / PI; float lineWidth; if (deviation < 0.05) { lineWidth = 8; } else if (deviation < 0.2) { lineWidth = 6; } else if (deviation < 0.3) { lineWidth = 5; } else if (deviation < 0.4) { lineWidth = 4; } else if (deviation < 0.6) { lineWidth = 3; } else if (deviation < 0.8) { lineWidth = 2; } else { lineWidth = 1; } float alphaValue = map(deviation,0,PI,40,20); if (this.type == 'B') fill(hueValue + baseHueB,100,bright,25); else fill(hueValue + baseHueL,100,bright,25); beginShape(); vertex(TX(this.steps[i - 1].x - lineWidth * sin(deviation)), TY(this.steps[i - 1].y - lineWidth * (cos(deviation)))); vertex(TX(this.steps[i - 1].x + lineWidth * sin(deviation)), TY(this.steps[i - 1].y + lineWidth * (cos(deviation)))); vertex(TX(this.steps[i].x + lineWidth * sin(deviation)), TY(this.steps[i].y + lineWidth * (cos(deviation)))); vertex(TX(this.steps[i].x - lineWidth * sin(deviation)), TY(this.steps[i].y - lineWidth * (cos(deviation)))); endShape(CLOSE); } } noFill(); } }