/* A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display: A. The instantaneous intersections of the circles >>> B. The aggregate intersections of the circles Ported to p5.js by Casey Reas 11 July 2016 p5.js 0.5.2 Restored by Casey Reas <http://reas.com> 22 June 2016 Processing v.3.1.1 <http://processing.org> Implemented by J. Tarbell <http://levitated.net> 8 April 2004 Processing v.68 <http://processing.org> */ // widthensions var num = 100; var time = 0; // display flag var showStructure = false; // object array var discs = []; function setup() { createCanvas(500, 500); background(0); frameRate(30); // arrange linearly for (var i = 0; i < num; i++) { var x = random(width); var y = random(width); var fy = 0; var fx = random(-1.0, 1.0); var r = 20 + random(20); discs[i] = new Disc(i, x, y, fx, fy, r); discs[i].createPainters(); } } function draw() { if (showStructure) { background(0); // render circles and intersections for (var c = 0; c < num; c++) { discs[c].draw(); } } // move discs for (var c = 0; c < num; c++) { discs[c].move(); discs[c].render(); } time++; } function keyReleased() { if (key == ' ') { background(0); if (showStructure) { showStructure = false; } else { showStructure = true; } } } // translucent point function tpoint(x1, y1, gc, a) { noStroke(); fill(gc, a * 255); rect(x1, y1, 1, 1); } // disc object function Disc(Id, X, Y, Vx, Vy, R) { this.id = Id; this.x = X; this.y = Y; this.vx = Vx; this.vy = Vy; this.dr = R; this.r = 1.0; // sand painters this.numsands = 1; this.sands = []; //SandPainter[] sands = new SandPainter[numsands]; this.createPainters = function() { for (var n = 0; n < this.numsands; n++) { this.sands[n] = new SandPainter(); } } this.draw = function() { stroke(64); noFill(); ellipse(this.x, this.y, this.r, this.r); } this.render = function() { // find intersecting points with all ascending discs for (var n = this.id + 1; n < num; n++) { // find distance to other disc var dx = discs[n].x - this.x; var dy = discs[n].y - this.y; var d = sqrt(dx * dx + dy * dy); // intersection test if (d < (discs[n].r + this.r)) { // complete containment test if (d > abs(discs[n].r - this.r)) { // find circle intersection solutions var a = (this.r * this.r - discs[n].r * discs[n].r + d * d) / (2 * d); var p2x = this.x + a * (discs[n].x - this.x) / d; var p2y = this.y + a * (discs[n].y - this.y) / d; var h = sqrt(this.r * this.r - a * a); var p3ax = p2x + h * (discs[n].y - this.y) / d; var p3ay = p2y - h * (discs[n].x - this.x) / d; var p3bx = p2x - h * (discs[n].y - this.y) / d; var p3by = p2y + h * (discs[n].x - this.x) / d; // P3a and P3B may be identical - ignore this case (for now) if (showStructure) { stroke(255); point(p3ax, p3ay); point(p3bx, p3by); } else { tpoint(int(p3ax - 1), int(p3ay), 255, 0.21); tpoint(int(p3ax + 1), int(p3ay), 0, 0.21); tpoint(int(p3bx - 1), int(p3by), 255, 0.21); tpoint(int(p3ax + 1), int(p3ay), 0, 0.21); } // draw sand painters for (var s = 0; s < this.numsands; s++) { this.sands[s].render(p3ax, p3ay, p3bx, p3by); } } } } } this.move = function() { // move radius towards destination radius if (this.r < this.dr) this.r += 0.02; // add velocity to position this.x += this.vx; this.y += this.vy; // bound check if (this.x + this.r < 0) { this.x += width + this.r + this.r; this.y = random(width); } if (this.x - this.r > width) { this.x -= width + this.r + this.r; this.y = random(width); } if (this.y + this.r < 0) { this.y += width + this.r + this.r; this.x = random(width); } if (this.y - this.r > width) { this.y -= width + this.r + this.r; this.x = random(width); } } } // sandpainter object function SandPainter() { this.p = random(1.0); this.c = int(random(256)); this.g = random(0.01, 0.1); this.render = function(x, y, ox, oy) { // draw painting sweeps tpoint(int(ox + (x - ox) * sin(this.p)), int(oy + (y - oy) * sin(this.p)), this.c, 0.11); this.g += random(-0.050, 0.050); var maxg = 0.5; if (this.g < -maxg) g = -maxg; if (this.g > maxg) g = maxg; this.p += random(-0.050, 0.050); if (this.p < 0) this.p = 0; if (this.p > 1.0) this.p = 1.0; var w = this.g / 10.0; for (var i = 0; i < 11; i++) { tpoint(int(ox + (x - ox) * sin(this.p + sin(i * w))), int(oy + (y - oy) * sin(this.p + sin(i * w))), this.c, 0.1 - i / 110); tpoint(int(ox + (x - ox) * sin(this.p - sin(i * w))), int(oy + (y - oy) * sin(this.p - sin(i * w))), this.c, 0.1 - i / 110); } } }