DuyTa's picture
Upload folder using huggingface_hub
bc20498 verified
raw
history blame
5.86 kB
/**
* Explained by Blindman67 at https://stackoverflow.com/a/44856925/11028828
*/
// Declare reused variable to avoid reallocating variables every time the function is called
let x, y, v1 = {}, v2 = {}, sinA, sinA90, radDirection, drawDirection, angle, halfAngle, cRadius, lenOut, radius, limit;
let startX, startY, stopX, stopY;
let lastPoint;
// convert 2 points into vector form, polar form, and normalised
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) => {
//-----------------------------------------
// Part 1
previousPoint !== lastPoint ? asVec(currentPoint, previousPoint, v1) : invertVec(v2, v1); // Avoid recalculating vec if it is the invert of the last one calculated
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;
}
//-----------------------------------------
// Part 2
halfAngle = angle / 2;
//-----------------------------------------
limit = Math.min(v1.len / 2, v2.len / 2);
if (isArcRadius) {
//-----------------------------------------
// Part 3
lenOut = Math.abs(Math.cos(halfAngle) * radius / Math.sin(halfAngle));
//-----------------------------------------
// Special part A
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));
}
//-----------------------------------------
//-----------------------------------------
// Part 4
stopX = currentPoint.x + v2.nx * lenOut;
stopY = currentPoint.y + v2.ny * lenOut;
//-----------------------------------------
// Part 5
x = stopX - v2.ny * cRadius * radDirection;
y = stopY + v2.nx * cRadius * radDirection;
//-----------------------------------------
// Additional Part : calculate start point E
startX = currentPoint.x + v1.nx * lenOut;
startY = currentPoint.y + v1.ny * lenOut;
// Save last point to avoid recalculating vector when not needed
lastPoint = currentPoint;
};
/**
* Draw round corner from a point and its previous and next neighbours in a path
*
* @param ctx :CanvasRenderingContext2D
* @param previousPoint {{x: number, y:number, radius: number?}}
* @param currentPoint {{x: number, y:number, radius: number?}}
* @param nextPoint {{x: number, y:number, radius: number?}}
* @param radiusMax :number
* @param isArcRadius :boolean
*/
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);
}
/**
* Draw corner provided by {@link getRoundCorner}
*
* @param ctx :CanvasRenderingContext2D
* @param roundCorner {{cx:number, cy:number, radius:number, endAngle: number, startAngle: number, counterClockwise: boolean}}
*/
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);
}
/**
* Get round corner from a point and its previous and next neighbours in a path
*
* @param previousPoint {{x: number, y:number, radius: number?}}
* @param currentPoint {{x: number, y:number, radius: number?}}
* @param nextPoint {{x: number, y:number, radius: number?}}
* @param radiusMax :number
* @param isArcRadius :boolean
* @return {{
* cx:number, cy:number, radius:number,
* startX:number, startY:number,
* stopX:number, stopY: number,
* endAngle: number, startAngle: number, counterClockwise: boolean
* }}
*/
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
};
}