Skip to content
Snippets Groups Projects

Intuitive erasing

1 file
+ 19
31
Compare changes
  • Side-by-side
  • Inline
+ 19
31
function sqr(x) {
return x ** 2
function getDistance([x0, y0], [x1, y1]) {
return Math.hypot(x1 - x0, y1 - y0)
}
function hypotenuseSquared(a, b) {
return sqr(a) + sqr(b)
function clamp(x, min, max) {
return Math.max(min, Math.min(max, x))
}
function distanceSquared([x0, y0], [x1, y1]) {
return hypotenuseSquared(x0 - x1, y0 - y1)
}
function distance(point0, point1) {
return Math.sqrt(distanceSquared(point0, point1))
}
function cap01(x) {
return Math.max(0, Math.min(1, x))
}
function distToSegmentSquared(lineStart, lineEnd, point) {
const l2 = distanceSquared(lineStart, lineEnd)
if (l2 === 0) return distanceSquared(point, lineStart)
function distToSegment(lineStart, lineEnd, point) {
const l = getDistance(lineStart, lineEnd)
if (l === 0) return getDistance(point, lineStart)
let t =
((point[0] - lineStart[0]) * (lineEnd[0] - lineStart[0]) +
(point[1] - lineStart[1]) * (lineEnd[1] - lineStart[1])) /
l2
t = cap01(t)
return distanceSquared(point, [
l ** 2
t = clamp(t, 0, 1)
return getDistance(point, [
lineStart[0] + t * (lineEnd[0] - lineStart[0]),
lineStart[1] + t * (lineEnd[1] - lineStart[1]),
])
@@ -47,30 +35,30 @@ function project([x1, y1], [x2, y2], [x3, y3]) {
function erasureInterval(lineStart, lineEnd, erasureCenter, erasureRadius) {
if (!(lineStart && lineEnd && erasureCenter)) return
const distToSegment2 = distToSegmentSquared(lineStart, lineEnd, erasureCenter)
if (erasureRadius ** 2 < distToSegment2) return
const dist = distToSegment(lineStart, lineEnd, erasureCenter)
if (erasureRadius < dist) return
const lineLength = distance(lineStart, lineEnd)
const lineLength = getDistance(lineStart, lineEnd)
if (lineLength === 0) {
return distToSegment2 <= erasureRadius ** 2 ? [0, 1] : [0, 0]
return dist <= erasureRadius ? [0, 1] : [0, 0]
}
const projT = project(lineStart, lineEnd, erasureCenter)
const projectionPoint = interpolate(lineStart, lineEnd, projT)
const d2 = distance(erasureCenter, projectionPoint)
const halfLength = Math.sqrt(Math.abs(sqr(erasureRadius) - sqr(d2)))
const d2 = getDistance(erasureCenter, projectionPoint)
const halfLength = Math.sqrt(Math.abs(erasureRadius ** 2 - d2 ** 2))
if (halfLength === 0) return undefined
let touchFromStartDist = distance(lineStart, projectionPoint)
let touchFromStartDist = getDistance(lineStart, projectionPoint)
if (projT < 0) touchFromStartDist = -touchFromStartDist
const touchBeginFromStarDist = touchFromStartDist - halfLength
const touchEndFromStarDist = touchFromStartDist + halfLength
return [
cap01(touchBeginFromStarDist / lineLength),
cap01(touchEndFromStarDist / lineLength),
clamp(touchBeginFromStarDist / lineLength, 0, 1),
clamp(touchEndFromStarDist / lineLength, 0, 1),
]
}
Loading