Circle Intersections w/ Raphael
I was discussing an interesting problem with a friend of mine awhile back – it relates to simulating the intersection of two or more 2d bubbles. This turns out to be trickier than you might expect. The first sketch I created regarding this problem was this:
I used circle intersection logic from Paule Bourke. (That really is one of my favorite websites).
The above is interesting, but taking it further will be tricky – it looks like some kind of Voronoi variation might be the way to go.
Here is the main source:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | var r = new Raphael(0, 0, 500, 500); var CIRCLE_NUM = 4; var circles = []; var lines = []; // make some randomly positioned circles for (var i = 0; i < CIRCLE_NUM; i++){ circles.push(r.circle(Math.random() * 150 + 150, Math.random() * 150 + 150, 60) .attr({fill: "rgba(81, 121, 200, 0.3)"})); } var line = r.path(); var path = ""; render(); dragAndDrop(); function render() { path = ""; redPath = ""; lines = []; var leng = circles.length; for (var i = 0; i<leng; i++){ for (var j = i + 1; j<leng; j++){ circleIntersection(circles[i], circles[j]); } } } // easy to understand explanation here: // http://paulbourke.net/geometry/2circle/ function circleIntersection(a, b) { var a, h, cx, cy, px, py; var ax = a.attr("cx"); var ay = a.attr("cy"); var bx = b.attr("cx"); var by = b.attr("cy"); var ra = a.attr("r"); var rb = b.attr("r"); var dx = Math.abs(ax - bx); var dy = Math.abs(ay - by); var d = Math.sqrt(dx * dx + dy * dy); if (d > (ra + rb)) { // no solutions } else if (d < Math.abs(ra - rb)) { // no collisions, one inside other } else if (d == 0 && ra == rb) { // circles are coincident } else { // there is a collision a = (ra * ra - rb * rb + d * d) / (2 * d); h = Math.sqrt(ra * ra - a * a); cx = ax + a * (bx - ax) / d; cy = ay + a * (by - ay) / d; // point c (draw here) var tx = h * (by - ay) / d; var ty = h * (bx - ax) / d; px = cx + tx; py = cy - ty; var ln = {a:{x:px, y:py}}; path += "M " + px + " " + py + " "; px = cx - tx; py = cy + ty; ln.b = {x:px, y:py}; path += "L " + px + " " + py + " "; line.attr({path: path}); lines.push(ln); } } function dragAndDrop(){ var circs = r.set(); for (var i = 0; i < circles.length; i++) { circs.push(circles[i]); } circs.drag(function(dx, dy) { this.attr({cx: this.ox + dx, cy: this.oy + dy}); render(); }, function() { this.ox = this.attr("cx"); this.oy = this.attr("cy"); }); } |
On a side note, you can use this old-school gradient circle technique to create something similar:

Lately I’ve been speed coding actionscript, so no variable typing and no holding back on weird/bad tricks. Sometimes the result is unreadable – other times it looks like elegant pseudo-code (which one is this?):
This is the code for the above image.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | [SWF(width=400, height=400, frameRate=1, backgroundColor=0xFFFFFF)] var m = new Matrix(); var BUB_NUM = 30; for (var i = 0; i < BUB_NUM; i++) bubble(Math.random() * stage.stageWidth, Math.random() * stage.stageHeight); function bubble(xp, yp) { var bub = addChild(new Sprite()); var rad = Math.random() * 20 + 50; var diam = rad * 2; m.createGradientBox(diam, diam, 0, -rad, -rad); with(bub.graphics) { beginGradientFill("radial", [0, 0xFFFFFF], [1,1], [0,255], m); drawCircle(0, 0, rad); } with(bub){ x = xp; y = yp; blendMode = "darken"; cacheAsBitmap = true; } } |
Not sure what my final solution will be… should be interesting.
