public class Bifurcator { public int xPos; public int yPos; public int w; public int h; public int[][] freqMap; public PImage diagramImage; public int progress; public ParamSet p; public float pInit; private int nPoint = 10000; // Number of iterations at each R value private int nSpin = 0; // Number of iterations to skip before recording in freqMap public Bifurcator(int xPos, int yPos, int w, int h) { this.xPos = xPos; this.yPos = yPos; this.w = w; this.h = h; pStack = new Stack(); p = new ParamSet(1, 4, 0, 1); pInit = 0.5; freqMap = new int[w][h]; progress = 0; } private void genFreqMap() { float pop; float rRng = p.getRRng(); float pRng = p.getPRng(); // Clear out freqMap for(int x = 0; x < w; x++) for(int y = 0; y < h; y++) freqMap[x][y] = 0; for(int x = 0; x < w; x++) { // Initialize population pop = constrain(pInit, p.pMin, p.pMax); // Calculate the current value of r float r = ((float)x)/((float)w)*rRng + p.rMin; // Iterate for(int i = 0; i < nSpin + nPoint; i++) { pop = logistic(r, pop); if(i < nSpin) continue; float pScaled = (constrain(pop, p.pMin, p.pMax) - p.pMin) / pRng * (h-1); freqMap[x][h-(round(pScaled)+1)]++; } } } // Generate the diagramImage, once the freqMap has been calculated private void genDiagramImage() { color dPixels[] = new color[w * h]; // Construct dPixels for(int x = 0; x < w; x++) for(int y = 0; y < h; y++) dPixels[(y * w) + x] = blend(color(255), color(0, 2*freqMap[x][y]), BLEND); // Now create diagramImage diagramImage = new PImage(dPixels, w, h, RGB); } public void setP(ParamSet p) { print(p.toString()); this.p = p; } // Call genFreqMap() and then genDiagramImage(); public void update() { genFreqMap(); genDiagramImage(); progress = 0; } // Translate an x position, in pixels to an r value public float xPosToR(float x) { return ((float)x)/((float)w) * p.getRRng() + p.rMin; } // Translate a y position, in pixels to a p value public float yPosToP(float y) { return ((float)h - (float)y)/((float)h) * p.getPRng() + p.pMin; } public float rToXPos(float r) { return ((r - p.rMin) / p.getRRng()) * w; } public float pToYPos(float pop) { return h - ((pop - p.pMin) / p.getPRng() * h); } public String toString() { String str = "R: "+p.rMin+" - "+p.rMax+"\n"; str += "P: "+p.pMin+" - "+p.pMax+"\n"; return str; } public void render() { image(diagramImage, xPos, yPos); stroke(lineRed); // Draw a red line indicating where rCurrent is float lineX = xPos + rToXPos(p.rCurrent); line(lineX, yPos, lineX, yPos+h); // Draw a line inidicating where pInit is float lineY = yPos + pToYPos(p.pInit); line(xPos, lineY, xPos+100, lineY); int labelWidth = 60; int labelHeight = 15; // Draw the rCurrent label on the left or right, depending on situational love stroke(100); fill(200); float labelStart; if(lineX < labelWidth) labelStart = lineX; else labelStart = lineX - labelWidth; rect(labelStart, yPos-1, labelWidth, labelHeight); fill(0); float rR = round(p.rCurrent*10000) / 10000.0; textFont(font, 10); text("R="+rR, labelStart+5, yPos+12); // Draw the pInit label labelStart = xPos + 100 - labelWidth; fill(200); rect(labelStart, lineY - labelHeight, labelWidth, labelHeight); float pR = round(p.pInit*10000) / 10000.0; fill(0); text("P="+pR, labelStart+5, lineY-3); // Draw other lines if needed Iterator it = p.rValues.iterator(); int i = 1; while(it.hasNext()) { SavedR sr = (SavedR)it.next(); lineX = xPos + rToXPos(sr.r); stroke(sr.col); line(lineX, yPos, lineX, yPos+h); // Hoo boy stroke(100); fill(sr.col); if(lineX < 60) labelStart = lineX; else labelStart = lineX - 60; int y = yPos+h-15*i; rect(labelStart, y, 60, 15); if(brightness(sr.col) < 255/2) fill(255); else fill(0); rR = round(sr.r*10000) / 10000.0; textFont(font, 10); text("R="+rR, labelStart+5, y+12); i++; } } }