|
|
|
|
|
|
|
|
|
|
|
|
|
let x, y, v1 = {}, v2 = {}, sinA, sinA90, radDirection, drawDirection, angle, halfAngle, cRadius, lenOut, radius, limit; |
|
let startX, startY, stopX, stopY; |
|
let lastPoint; |
|
|
|
|
|
const asVec = function (p, pp, v) { |
|
v.x = pp.x - p.x; |
|
v.y = pp.y - p.y; |
|
v.len = Math.sqrt(v.x * v.x + v.y * v.y); |
|
v.nx = v.x / v.len; |
|
v.ny = v.y / v.len; |
|
v.ang = Math.atan2(v.ny, v.nx); |
|
}; |
|
|
|
const invertVec = function (originalV, invertedV) { |
|
invertedV.x = originalV.x * -1; |
|
invertedV.y = originalV.y * -1; |
|
invertedV.nx = originalV.nx * -1; |
|
invertedV.ny = originalV.ny * -1; |
|
invertedV.ang = originalV.ang > 0 ? -(Math.PI - originalV.ang) : Math.PI + originalV.ang; |
|
}; |
|
|
|
const calcCornerArc = (previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius) => { |
|
|
|
|
|
previousPoint !== lastPoint ? asVec(currentPoint, previousPoint, v1) : invertVec(v2, v1); |
|
asVec(currentPoint, nextPoint, v2); |
|
sinA = v1.nx * v2.ny - v1.ny * v2.nx; |
|
sinA90 = v1.nx * v2.nx - v1.ny * -v2.ny; |
|
angle = Math.asin(Math.max(-1, Math.min(1, sinA))); |
|
if (Math.abs(angle) < 1e-6) { |
|
x = currentPoint.x; |
|
y = currentPoint.y; |
|
cRadius = radius = 0; |
|
return; |
|
} |
|
|
|
radDirection = 1; |
|
drawDirection = false; |
|
if (sinA90 < 0) { |
|
if (angle < 0) { |
|
angle = Math.PI + angle; |
|
} else { |
|
angle = Math.PI - angle; |
|
radDirection = -1; |
|
drawDirection = true; |
|
} |
|
} else { |
|
if (angle > 0) { |
|
radDirection = -1; |
|
drawDirection = true; |
|
} |
|
} |
|
if (currentPoint.radius !== undefined) { |
|
radius = currentPoint.radius; |
|
} else { |
|
radius = radiusMax; |
|
} |
|
|
|
|
|
halfAngle = angle / 2; |
|
|
|
|
|
|
|
limit = Math.min(v1.len / 2, v2.len / 2); |
|
|
|
if (isArcRadius) { |
|
|
|
|
|
lenOut = Math.abs(Math.cos(halfAngle) * radius / Math.sin(halfAngle)); |
|
|
|
|
|
|
|
if (lenOut > limit) { |
|
lenOut = limit; |
|
cRadius = Math.abs(lenOut * Math.sin(halfAngle) / Math.cos(halfAngle)); |
|
} else { |
|
cRadius = radius; |
|
} |
|
} else { |
|
lenOut = Math.min(limit, radius); |
|
cRadius = Math.abs(lenOut * Math.sin(halfAngle) / Math.cos(halfAngle)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
stopX = currentPoint.x + v2.nx * lenOut; |
|
stopY = currentPoint.y + v2.ny * lenOut; |
|
|
|
|
|
x = stopX - v2.ny * cRadius * radDirection; |
|
y = stopY + v2.nx * cRadius * radDirection; |
|
|
|
|
|
startX = currentPoint.x + v1.nx * lenOut; |
|
startY = currentPoint.y + v1.ny * lenOut; |
|
|
|
|
|
lastPoint = currentPoint; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function drawRoundCorner(ctx, previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius) { |
|
calcCornerArc(previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius); |
|
if (cRadius === 0) ctx.lineTo(currentPoint.x, currentPoint.y); |
|
else ctx.arc(x, y, cRadius, v1.ang + Math.PI / 2 * radDirection, v2.ang - Math.PI / 2 * radDirection, drawDirection); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function drawPreparedRoundCorner(ctx, roundCorner) { |
|
if (roundCorner.radius === 0) ctx.lineTo(roundCorner.cx, roundCorner.cy); |
|
else ctx.arc(roundCorner.cx, roundCorner.cy, roundCorner.radius, roundCorner.startAngle, roundCorner.endAngle, roundCorner.counterClockwise); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function getRoundCorner(previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius = true) { |
|
if (radiusMax === 0 || currentPoint.radius === 0) return { |
|
cx: currentPoint.x, |
|
cy: currentPoint.y, |
|
radius: 0, |
|
startX: currentPoint.x, |
|
startY: currentPoint.y, |
|
stopX: currentPoint.x, |
|
stopY: currentPoint.y, |
|
startAngle: undefined, |
|
endAngle: undefined, |
|
counterClockwise: undefined |
|
}; |
|
|
|
calcCornerArc(previousPoint, currentPoint, nextPoint, radiusMax, isArcRadius); |
|
return { |
|
cx: x, cy: y, radius: cRadius, |
|
startX, startY, |
|
stopX, stopY, |
|
startAngle: v1.ang + Math.PI / 2 * radDirection, |
|
endAngle: v2.ang - Math.PI / 2 * radDirection, |
|
counterClockwise: drawDirection |
|
}; |
|
} |
|
|