| 83 | } |
| 84 | |
| 85 | function closestSegment(pts, p) { |
| 86 | let best = Infinity; |
| 87 | let bestIdx = 0; |
| 88 | for (let i = 0; i < pts.length - 1; i++) { |
| 89 | const a = pts[i]; |
| 90 | const b = pts[i + 1]; |
| 91 | const dx = b.x - a.x; |
| 92 | const dy = b.y - a.y; |
| 93 | const len2 = dx * dx + dy * dy; |
| 94 | let t = len2 === 0 ? 0 : ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2; |
| 95 | t = Math.max(0, Math.min(1, t)); |
| 96 | const proj = { x: a.x + t * dx, y: a.y + t * dy }; |
| 97 | const d = dist(proj, p); |
| 98 | if (d < best) { |
| 99 | best = d; |
| 100 | bestIdx = i; |
| 101 | } |
| 102 | } |
| 103 | return { dist: best, segIndex: bestIdx }; |
| 104 | } |
| 105 | |
| 106 | // --------------------------------------------------------------------------- |
| 107 | // Extension registration |