mirror of
https://kevinblog.sytes.net/Code/Jibo-Revival-Group/RoboCommander.git
synced 2026-06-15 22:56:02 +00:00
119 lines
2.9 KiB
JavaScript
119 lines
2.9 KiB
JavaScript
|
|
import {shuffle, slice} from "../array";
|
||
|
|
|
||
|
|
export default function(circles) {
|
||
|
|
var i = 0, n = (circles = shuffle(slice.call(circles))).length, B = [], p, e;
|
||
|
|
|
||
|
|
while (i < n) {
|
||
|
|
p = circles[i];
|
||
|
|
if (e && enclosesWeak(e, p)) ++i;
|
||
|
|
else e = encloseBasis(B = extendBasis(B, p)), i = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return e;
|
||
|
|
}
|
||
|
|
|
||
|
|
function extendBasis(B, p) {
|
||
|
|
var i, j;
|
||
|
|
|
||
|
|
if (enclosesWeakAll(p, B)) return [p];
|
||
|
|
|
||
|
|
// If we get here then B must have at least one element.
|
||
|
|
for (i = 0; i < B.length; ++i) {
|
||
|
|
if (enclosesNot(p, B[i])
|
||
|
|
&& enclosesWeakAll(encloseBasis2(B[i], p), B)) {
|
||
|
|
return [B[i], p];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If we get here then B must have at least two elements.
|
||
|
|
for (i = 0; i < B.length - 1; ++i) {
|
||
|
|
for (j = i + 1; j < B.length; ++j) {
|
||
|
|
if (enclosesNot(encloseBasis2(B[i], B[j]), p)
|
||
|
|
&& enclosesNot(encloseBasis2(B[i], p), B[j])
|
||
|
|
&& enclosesNot(encloseBasis2(B[j], p), B[i])
|
||
|
|
&& enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
|
||
|
|
return [B[i], B[j], p];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If we get here then something is very wrong.
|
||
|
|
throw new Error;
|
||
|
|
}
|
||
|
|
|
||
|
|
function enclosesNot(a, b) {
|
||
|
|
var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
|
||
|
|
return dr < 0 || dr * dr < dx * dx + dy * dy;
|
||
|
|
}
|
||
|
|
|
||
|
|
function enclosesWeak(a, b) {
|
||
|
|
var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y;
|
||
|
|
return dr > 0 && dr * dr > dx * dx + dy * dy;
|
||
|
|
}
|
||
|
|
|
||
|
|
function enclosesWeakAll(a, B) {
|
||
|
|
for (var i = 0; i < B.length; ++i) {
|
||
|
|
if (!enclosesWeak(a, B[i])) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
function encloseBasis(B) {
|
||
|
|
switch (B.length) {
|
||
|
|
case 1: return encloseBasis1(B[0]);
|
||
|
|
case 2: return encloseBasis2(B[0], B[1]);
|
||
|
|
case 3: return encloseBasis3(B[0], B[1], B[2]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function encloseBasis1(a) {
|
||
|
|
return {
|
||
|
|
x: a.x,
|
||
|
|
y: a.y,
|
||
|
|
r: a.r
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function encloseBasis2(a, b) {
|
||
|
|
var x1 = a.x, y1 = a.y, r1 = a.r,
|
||
|
|
x2 = b.x, y2 = b.y, r2 = b.r,
|
||
|
|
x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
|
||
|
|
l = Math.sqrt(x21 * x21 + y21 * y21);
|
||
|
|
return {
|
||
|
|
x: (x1 + x2 + x21 / l * r21) / 2,
|
||
|
|
y: (y1 + y2 + y21 / l * r21) / 2,
|
||
|
|
r: (l + r1 + r2) / 2
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function encloseBasis3(a, b, c) {
|
||
|
|
var x1 = a.x, y1 = a.y, r1 = a.r,
|
||
|
|
x2 = b.x, y2 = b.y, r2 = b.r,
|
||
|
|
x3 = c.x, y3 = c.y, r3 = c.r,
|
||
|
|
a2 = x1 - x2,
|
||
|
|
a3 = x1 - x3,
|
||
|
|
b2 = y1 - y2,
|
||
|
|
b3 = y1 - y3,
|
||
|
|
c2 = r2 - r1,
|
||
|
|
c3 = r3 - r1,
|
||
|
|
d1 = x1 * x1 + y1 * y1 - r1 * r1,
|
||
|
|
d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
|
||
|
|
d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
|
||
|
|
ab = a3 * b2 - a2 * b3,
|
||
|
|
xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
|
||
|
|
xb = (b3 * c2 - b2 * c3) / ab,
|
||
|
|
ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
|
||
|
|
yb = (a2 * c3 - a3 * c2) / ab,
|
||
|
|
A = xb * xb + yb * yb - 1,
|
||
|
|
B = 2 * (r1 + xa * xb + ya * yb),
|
||
|
|
C = xa * xa + ya * ya - r1 * r1,
|
||
|
|
r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
|
||
|
|
return {
|
||
|
|
x: x1 + xa + xb * r,
|
||
|
|
y: y1 + ya + yb * r,
|
||
|
|
r: r
|
||
|
|
};
|
||
|
|
}
|