Newer
Older
function distance([x1, y1], [x2, y2]) {
return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
}
function sqr(x) {
return x * x
}
function dist2(v, w) {
return sqr(v[0] - w[0]) + sqr(v[1] - w[1])
}
// p - point
// v - start point of segment
// w - end point of segment
function distToSegmentSquared(p, v, w) {
var l2 = dist2(v, w)
if (l2 === 0) return dist2(p, v)
var t = ((p[0] - v[0]) * (w[0] - v[0]) + (p[1] - v[1]) * (w[1] - v[1])) / l2
t = Math.max(0, Math.min(1, t))
return dist2(p, [v[0] + t * (w[0] - v[0]), v[1] + t * (w[1] - v[1])])
}
// p - point
// v - start point of segment
// w - end point of segment
function distToSegment(p, v, w) {
return Math.sqrt(distToSegmentSquared(p, v, w))
}
function distanceToLine(lineStart, lineEnd, point) {
return distToSegment(point, lineStart, lineEnd)
}
function shouldAddErasureInterval(
point,
nextPoint,
erasureCenter,
erasureRadius,
) {
if (!nextPoint) return false
return distanceToLine(point, nextPoint, erasureCenter) <= erasureRadius
}
function interpolate([x1, y1], [x2, y2], t) {
return [x1 + (x2 - x1) * t, y1 + (y2 - y1) * t]
}
function project([x1, y1], [x2, y2], [x3, y3]) {
const x21 = x2 - x1,
y21 = y2 - y1
const x31 = x3 - x1,
y31 = y3 - y1
return (x31 * x21 + y31 * y21) / (x21 * x21 + y21 * y21)
}
function cap0(x) {
return Math.max(0, x)
}
function cap1(x) {
return Math.min(1, x)
}
function erasureInterval(lineStart, lineEnd, erasureCenter, erasureRadius) {
const [cx, cy] = interpolate(
lineStart,
lineEnd,
project(lineStart, lineEnd, erasureCenter),
)
const d = distanceToLine(lineStart, lineEnd, erasureCenter)
const halfLength = Math.sqrt(erasureRadius ** 2 - d ** 2)
const lineLength = distance(lineStart, lineEnd)
const touchFromStartDist = distance(lineStart, [cx, cy])
const touchBeginFromStarDist = touchFromStartDist - halfLength
const touchEndFromStarDist = touchFromStartDist + halfLength
return [
cap0(touchBeginFromStarDist / lineLength),
cap1(touchEndFromStarDist / lineLength),
]
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
}
function computeErasureIntervals(points, erasureCenter, erasureRadius) {
return points
.map((point, i) => ({ point, i }))
.filter(({ point, i }) =>
shouldAddErasureInterval(
point,
points[i + 1],
erasureCenter,
erasureRadius,
),
)
.reduce(
(acc, { point, i }) => ({
...acc,
[i]: erasureInterval(
point,
points[i + 1],
erasureCenter,
erasureRadius,
),
}),
{},
)
}
module.exports = {
computeErasureIntervals,
}