× Project Code

// The packing approach used in R A Robertson's "Circle Packing 3" (sketch #57325), // modified to allow nested rings. // Mouse click to animate and reset packing. Left/right mouse render differently. // The number of ring rendered in the animation is limited to 450. // PImage.gif has 14,000 rings, the sketch found it very // difficult to find further free space beyond this. // arrayList, boolean, random, ellipse, ring /*@pjs preload="washers.gif";*/ float x, y, inner, outer, howFar; float minR = 10, maxR = 80; float sw = 1.5; ArrayList<Ring> rings = new ArrayList<Ring>(); color bgCol, bgPick; boolean isOver, stop = true, isBlkBg; PImage pic; void setup() { size(600, 600); background(bgCol); pic = loadImage("https://www.openprocessing.org/sketch/348463/files/washers.gif"); ellipseMode(RADIUS); if (!stop) { // prime the list rings.add(new Ring(random(200, 400), random(200, 400), 100)); } else image(pic, 0, 0); } void draw() { if (!stop) { outer = random(minR, maxR); inner = outer * random(.5, .95); x = random(40+outer*2, width-outer*2-40); y = random(40+outer*2, height-outer*2-40); // test if landing on background bgPick = get(int(x), int(y)); if (bgPick == bgCol) isOver = true; else isOver = false; // if not over background, move to another pos while (!isOver) { x = random(40+outer*2, width-outer*2-40); y = random(40+outer*2, height-outer*2-40); bgPick = get(int(x), int(y)); if (bgPick == bgCol)isOver = true; else isOver = false; } // check for overlap and reduce size if needed if (isOver) { for (Ring c : rings) { howFar = dist(x, y, c.x, c.y); if (howFar > outer + c.outer + sw +1 || howFar + outer + (sw*.5)+1 < c.inner + (sw*.5)) continue; // if we arrive here there is an overlap if (howFar >= c.inner) { // must be an outer/outer overlap outer = howFar - c.outer; outer = outer - (sw*2); // allow some space } else { outer = c. inner - howFar; // otherwise is innner/outer overlap outer = outer - (sw*2); // catch any negatives below } } // add new ring and draw it // throw back the little ones and catch any negatives if (outer > sw*2) rings.add(new Ring(x, y, outer)); if ((rings.size()) >= 450 ) stop = true; } stroke(255); strokeWeight(1); fill(0); rect(40, 555, 40, 20); fill(255); text(rings.size(), 50, 570); } } class Ring { float x, y, inner, outer; Ring(float xIn, float yIn, float outerIn) { x = xIn; y = yIn; outer = outerIn ; inner = outer * random(.6, .85); strokeWeight(sw); if (isBlkBg) { if (frameCount % 2 == 0) { fill(#FC7AA5); stroke(255); } else { stroke(#FB380C); fill(255); } } else { // is not black bg if (frameCount % 2 == 0) { fill(#FC7AA5); stroke(0); } else { stroke(#FB380C); fill(0); } } ellipse(x, y, outer, outer); fill(bgCol); ellipse(x, y, inner, inner); } } void mousePressed() { if (mouseButton == LEFT) { bgCol = -1;// white isBlkBg = false; } else if (mouseButton == RIGHT) { bgCol = -16777216;// black isBlkBg = true; } stop = false; rings = new ArrayList<Ring>(); // won't work (properly) without this in JS setup(); }