### Circle collisions ⚪

Collisions of circles on a grid

```Canvas.setpenopacity(0.85);

const turtle = new Turtle();
const grid = 11; // min=5, max=17, step=2
const radius = 11; // min=2, max=23, step=2
const size = 7/9 * 200 / grid;

function getX(x) { return x - (grid/2|0) };
function getY(y) { return y - (grid/2|0) };

function walk() {
const circles = [];
for(let idx=0;idx<grid*grid;idx++) {
const px = getX(idx % grid);
const py = getY(idx / grid | 0);
const r = 3 + Math.random() * radius;
circles.push([px * size, py * size, r]);
}

circles.forEach(circle => drawCircle(circle, turtle));

let collisions = [];
for(let idx=0;idx<circles.length-1;idx++) {
let circle1 = circles[idx];
for(let idy=idx + 1;idy<circles.length;idy++) {
let circle2 = circles[idy];
let intersection = circleToCircle(circle1, circle2);
if (intersection) {
collisions.push({circle1, circle2, intersection});
}
}
}
collisions.forEach((col, idx) => {
const circle1 = col.circle1;
const circle2 = col.circle2;
const [p1, p2] = col.intersection;

drawCircle([...p1, 0.75], turtle);
drawCircle([...p2, 0.75], turtle);
});
}

// centered circle
function drawCircle(c, t) {
t.circle(c[2]);
}

function drawArc(c, a1, a2, t, DENSITY = 0.25) {
while (a2 < a1) a2 += Math.PI*2;
const [x,y,r] = c;
for (let a = a1; a < a2; a += 1/r/DENSITY) {
if (a == a1) t.jump(x + Math.cos(a) * r, y + Math.sin(a) * r);
t.goto(x + Math.cos(a) * r, y + Math.sin(a) * r);
}
t.goto(x + Math.cos(a2) * r, y + Math.sin(a2) * r);
}

// https://www.xarg.org/2016/07/calculate-the-intersection-points-of-two-circles/
function circleToCircle(p0, p1) {
const r0 = p0[2];
const r1 = p1[2];
const dd = sub(p1, p0);
const d = len(dd);
if (d <= r0 + r1 && d >= Math.abs(r1 - r0)) {
const e = scl(dd, 1 / d);
const x = ((r0**2) - (r1**2) + (d**2)) / (2*d);
const y = Math.sqrt((r0**2) - (x**2));
return [
[
p0[0] + x * e[0] - y * e[1],
p0[1] + x * e[1] + y * e[0],
],
[
p0[0] + x * e[0] + y * e[1],
p0[1] + x * e[1] - y * e[0],
]
];
} else {
return null;
}
}

function pointInCircle(p,c) {
return len(sub(p,c)) + 0.001 < c[2];
}

// vec2 functions
function vec2(a)    { return [a,a]; }
function scl(a,b)   { return [a[0]*b, a[1]*b]; }
function add(a,b)   { return [a[0]+b[0], a[1]+b[1]]; }
function sub(a,b)   { return [a[0]-b[0], a[1]-b[1]]; }
function dot(a,b)   { return a[0]*b[0] + a[1]*b[1]; }
function len(a)     { return Math.sqrt(a[0]**2 + a[1]**2); }
function nrm(a)     { return scl(a, 1/len(a)); }
function lrp(a,b,f) { return [a[0]*f+b[0]*(1-f), a[1]*f+b[1]*(1-f)]; }
function angle(a) { return Math.atan2(a[1], a[0]); }
function eql(a,b)    { return a[0]==b[0] && a[1]==b[1]; }

```