{
let circle = [NaN, NaN, 0];
const context = DOM.context2d(width, height);
yield context.canvas;
for (let i = 0, n = polygon.length - 1; i < n; ++i) {
const pi0 = polygon[i], pi1 = polygon[i + 1];
for (let j = i + 1; j < n; ++j) {
const pj0 = polygon[j], pj1 = polygon[j + 1];
for (let k = j + 1; k < n; ++k) {
const pk0 = polygon[k], pk1 = polygon[k + 1];
context.clearRect(0, 0, width, height);
const l0 = lineExtend(pi0, pi1);
const l1 = lineExtend(pj0, pj1);
const l2 = lineExtend(pk0, pk1);
context.save();
context.beginPath();
context.moveTo(...l0[0]);
context.lineTo(...l0[1]);
context.moveTo(...l1[0]);
context.lineTo(...l1[1]);
context.moveTo(...l2[0]);
context.lineTo(...l2[1]);
context.setLineDash([3, 3]);
context.strokeStyle = "#ccc";
context.stroke();
context.restore();
context.save();
context.beginPath();
context.moveTo(...polygon[0]);
for (let l = 1; l < n; ++l) context.lineTo(...polygon[l]);
context.closePath();
context.strokeStyle = "#ccc";
context.stroke();
context.restore();
const s0 = lineLineBisect(pi0, pi1, pj1, pj0);
const s1 = lineLineBisect(pj0, pj1, pk1, pk0);
if (!s0 || !s1) continue;
const b0 = lineExtend(...s0);
const b1 = lineExtend(...s1);
context.save();
context.beginPath();
context.moveTo(...b0[0]);
context.lineTo(...b0[1]);
context.moveTo(...b1[0]);
context.lineTo(...b1[1]);
context.strokeStyle = "blue";
context.stroke();
context.restore();
if (circle[2] > 0) {
const [cx, cy, cr] = circle;
context.save();
context.beginPath();
context.moveTo(cx + cr, cy);
context.arc(cx, cy, cr, 0, 2 * Math.PI);
context.globalAlpha = 0.2;
context.fill();
context.restore();
}
const [x, y, r] = circleTangent(pi0, pi1, pj0, pj1, pk0, pk1);
let contained = true;
for (let l = 0; l < n; ++l) {
if (l === i || l === j || l === k) continue;
const d = pointLineDistance([x, y], polygon[l], polygon[l + 1]);
if (d + 1e-6 < r) { contained = false; break; }
}
if (contained && r > circle[2]) circle = [x, y, r];
context.save();
context.beginPath();
context.moveTo(x + r, y);
context.arc(x, y, r, 0, 2 * Math.PI);
context.lineWidth = 1.5;
context.strokeStyle = contained ? "black" : "red";
context.stroke();
context.restore();
context.save();
context.beginPath();
context.moveTo(...pi0);
context.lineTo(...pi1);
context.moveTo(...pj0);
context.lineTo(...pj1);
context.moveTo(...pk0);
context.lineTo(...pk1);
context.lineWidth = 1.5;
context.stroke();
context.restore();
yield Promises.delay(1000, context.canvas);
}
}
}
context.clearRect(0, 0, width, height);
context.save();
context.beginPath();
context.moveTo(...polygon[0]);
for (let l = 1, n = polygon.length - 1; l < n; ++l) context.lineTo(...polygon[l]);
context.closePath();
context.strokeStyle = "#ccc";
context.stroke();
context.restore();
const [cx, cy, cr] = circle;
context.save();
context.beginPath();
context.moveTo(cx + cr, cy);
context.arc(cx, cy, cr, 0, 2 * Math.PI);
context.lineWidth = 1.5;
context.strokeStyle = "#000";
context.stroke();
context.restore();
yield context.canvas;
}