geometrix
Version:
The 2D geometry engine of the parametrix
1,729 lines (1,718 loc) • 143 kB
JavaScript
// src/angle_utils.ts
var tolerance = 10 ** -4;
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
function radToDeg(rad) {
return 180 * rad / Math.PI;
}
function roundZero(ix) {
let rx = ix;
if (Math.abs(rx) < tolerance) {
rx = 0;
}
return rx;
}
function withinZero2Pi(ia) {
let ra = ia % (2 * Math.PI);
if (ra < 0) {
ra += 2 * Math.PI;
}
return ra;
}
function withinPiPi(ia) {
let ra = withinZero2Pi(ia);
if (ra > Math.PI) {
ra -= 2 * Math.PI;
}
return ra;
}
function withinZeroPi(ia) {
let ra = ia % Math.PI;
if (ra < 0) {
ra += Math.PI;
}
return ra;
}
function withinHPiHPi(ia) {
let ra = withinZeroPi(ia);
if (ra > Math.PI / 2) {
ra -= Math.PI;
}
return ra;
}
function orientedArc(aStart, aStop, ccw) {
const arc = withinPiPi(aStop) - withinPiPi(aStart);
const arc2 = ccw ? withinZero2Pi(arc) : withinZero2Pi(arc) - 2 * Math.PI;
return arc2;
}
function isWithin(aNew, aStart, aStop, ccw) {
let rYes = false;
if (roundZero(withinPiPi(aNew - aStart)) === 0) {
rYes = true;
} else if (roundZero(withinPiPi(aNew - aStop)) === 0) {
rYes = true;
} else {
const arcOrig = orientedArc(aStart, aStop, ccw);
const arcNew = orientedArc(aStart, aNew, ccw);
if (Math.abs(arcNew) < Math.abs(arcOrig)) {
rYes = true;
}
}
return rYes;
}
function pointCoord(ax, ay, aAB, lAB) {
const rBx = ax + lAB * Math.cos(aAB);
const rBy = ay + lAB * Math.sin(aAB);
return [rBx, rBy];
}
function ffix(ifloat) {
return ifloat.toFixed(2);
}
// src/canvas_utils.ts
var colors = {
point: "grey",
line: "grey",
vector: "DarkTurquoise",
contour: "green",
mainOuter: "SlateBlue",
mainInner: "SteelBlue",
mainB: "SlateGrey",
second: "Violet",
secondB: "SlateGrey",
dynamics: "Tomato",
ruler: "blue",
origin: "red",
reference: "blue",
mouse: "yellow"
};
var c_margin = 0.05;
function point2canvas(px, py, iAdjust) {
const cx2 = iAdjust.shiftX + (px - iAdjust.xMin) * iAdjust.scaleX;
const cy2 = iAdjust.shiftY + (py - iAdjust.yMin) * iAdjust.scaleY;
return [cx2, cy2];
}
function canvas2point(cx, cy, iAdjust) {
const px2 = (cx - iAdjust.shiftX) / iAdjust.scaleX + iAdjust.xMin;
const py2 = (cy - iAdjust.shiftY) / iAdjust.scaleY + iAdjust.yMin;
return [px2, py2];
}
function canvasTranslatePolar(cx, cy, ia, il) {
const cx2 = cx + il * Math.cos(ia);
const cy2 = cy - il * Math.sin(ia);
return [cx2, cy2];
}
function radius2canvas(iRadius, iAdjust) {
if (roundZero(iAdjust.scaleX - Math.abs(iAdjust.scaleY)) !== 0) {
throw `err683: iAdjust.scaleX and scaleY differ ${iAdjust.scaleX} ${iAdjust.scaleY}`;
}
if (iAdjust.scaleX < 0) {
throw `err684: iAdjust.scaleX ${iAdjust.scaleX} is negative`;
}
const rRadius = iRadius * iAdjust.scaleX;
if (rRadius < 0) {
throw `err685: rRadius for canvas ${rRadius} is negative`;
}
return rRadius;
}
function adjustZero() {
const rAdjustZero = {
init: 0,
xMin: 0,
yMin: 0,
xyDiff: 1,
shiftX: 0,
shiftY: 0,
scaleX: 1,
scaleY: 1
};
return rAdjustZero;
}
function adjustCopy(iAdjust) {
const rAdjustZero = {
init: iAdjust.init,
xMin: iAdjust.xMin,
yMin: iAdjust.yMin,
xyDiff: iAdjust.xyDiff,
shiftX: iAdjust.shiftX,
shiftY: iAdjust.shiftY,
scaleX: iAdjust.scaleX,
scaleY: iAdjust.scaleY
};
return rAdjustZero;
}
function adjustInit(xMin, xMax, yMin, yMax, cWidth, cHeight) {
const rAdjust = adjustZero();
const xDiff = Math.max(xMax - xMin, 1);
const yDiff = Math.max(yMax - yMin, 1);
const xScale = cWidth / xDiff;
const yScale = cHeight / yDiff;
let xyScale = 0.9 * xScale;
let xyDiff = xDiff;
if (yScale < xScale) {
xyScale = 0.9 * yScale;
xyDiff = yDiff;
}
rAdjust.init = 1;
rAdjust.xMin = xMin;
rAdjust.yMin = yMin;
rAdjust.xyDiff = xyDiff;
rAdjust.shiftX = c_margin * cWidth;
rAdjust.scaleX = xyScale;
rAdjust.shiftY = cHeight - c_margin * cHeight;
rAdjust.scaleY = -1 * xyScale;
return rAdjust;
}
function adjustCenter(px, py, iAdjust) {
const rAdjust = adjustCopy(iAdjust);
rAdjust.xMin = px - rAdjust.xyDiff / 2;
rAdjust.yMin = py - rAdjust.xyDiff / 2;
return rAdjust;
}
function adjustRect(p1x, p1y, p2x, p2y, cWidth, cHeight) {
const xMin = Math.min(p1x, p2x);
const xMax = Math.max(p1x, p2x);
const yMin = Math.min(p1y, p2y);
const yMax = Math.max(p1y, p2y);
const rAdjust = adjustInit(xMin, xMax, yMin, yMax, cWidth, cHeight);
return rAdjust;
}
function adjustScale(iFactor, iAdjust) {
const rAdjust = adjustCopy(iAdjust);
const shift = (1 - iFactor) / 2;
rAdjust.xMin += shift * iAdjust.xyDiff;
rAdjust.yMin += shift * iAdjust.xyDiff;
rAdjust.xyDiff *= iFactor;
rAdjust.scaleX *= 1 / iFactor;
rAdjust.scaleY *= 1 / iFactor;
return rAdjust;
}
function adjustTranslate(p1x, p1y, p2x, p2y, iAdjust) {
const rAdjust = adjustCopy(iAdjust);
const xDiff = p2x - p1x;
const yDiff = p2y - p1y;
rAdjust.xMin += -xDiff;
rAdjust.yMin += -yDiff;
return rAdjust;
}
function adjustMini(widthOrig, widthTarget, iAdjust) {
const rAdjust = adjustCopy(iAdjust);
if (widthOrig > 0 && widthTarget > 0) {
const mf = widthOrig / widthTarget;
rAdjust.xyDiff *= mf;
rAdjust.scaleX *= 1 / mf;
rAdjust.scaleY *= 1 / mf;
rAdjust.shiftX += c_margin * widthTarget - c_margin * widthOrig;
rAdjust.shiftY += (1 - c_margin) * widthTarget - (1 - c_margin) * widthOrig;
}
return rAdjust;
}
// src/triangle_utils.ts
function rightTriLaFromLbLc(ilb, ilc) {
return Math.sqrt(ilb ** 2 + ilc ** 2);
}
function rightTriLbFromLaLc(ila, ilc) {
let rlb = 0;
if (ilc > ila) {
throw `err539: ila < ilc ${ila} ${ilc}`;
} else {
rlb = Math.sqrt(ila ** 2 - ilc ** 2);
}
return rlb;
}
function lcFromLaLbAc(la, lb, ac) {
const rlc = Math.sqrt(la ** 2 + lb ** 2 - 2 * la * lb * Math.cos(ac));
return rlc;
}
function aCFromLaLbLc(la, lb, lc) {
let rac = 0;
const l3 = [la, lb, lc];
for (let i = 0; i < l3.length; i++) {
if (l3[i] < 0) {
throw `err209: l3[${i}] = ${l3[i]}`;
}
}
const l3s = l3.sort(function(a, b) {
return b - a;
});
if (l3s[0] > l3s[1] + l3s[2]) {
throw `err839: impossible triangle with length ${la}, ${lb} and ${lc}`;
} else {
rac = Math.acos((la ** 2 + lb ** 2 - lc ** 2) / (2 * la * lb));
}
return rac;
}
function aCFromAaAb(iaA, iaB) {
let rac = 0;
const aA = Math.abs(withinPiPi(iaA));
const aB = Math.abs(withinPiPi(iaB));
const sum = aA + aB;
if (sum > Math.PI) {
throw `err739: impossible triangle with angles ${iaA} and ${iaB}`;
} else {
rac = Math.PI - sum;
}
return rac;
}
function lbFromLaAaAb(ila, iaA, iaB) {
let rlb = 0;
const args = [ila, iaA, iaB];
for (let i = 0; i < args.length; i++) {
if (roundZero(args[i]) === 0 || args[i] < 0) {
throw `err329: negative or zero triangle-args ${i} : ${args[i]}`;
}
}
const aA = withinZeroPi(iaA);
const aB = withinZeroPi(iaB);
const sum = aA + aB;
if (sum > Math.PI) {
throw `err939: impossible triangle with angles ${iaA} and ${iaB}`;
} else {
rlb = ila * Math.sin(iaB) / Math.sin(iaA);
}
return rlb;
}
function aBFromLaLbAa(ila, ilb, iaA) {
let rab = 0;
const args = [ila, ilb, iaA];
for (let i = 0; i < args.length; i++) {
if (args[i] <= 0) {
throw `err429: negative or zero triangle-args ${i} : ${args[i]}`;
}
}
rab = Math.asin(ilb * Math.sin(iaA) / ila);
return rab;
}
// src/point.ts
var ShapePoint = /* @__PURE__ */ ((ShapePoint2) => {
ShapePoint2[ShapePoint2["eDefault"] = 0] = "eDefault";
ShapePoint2[ShapePoint2["eCircle"] = 1] = "eCircle";
ShapePoint2[ShapePoint2["eCross"] = 2] = "eCross";
ShapePoint2[ShapePoint2["eSquare"] = 3] = "eSquare";
ShapePoint2[ShapePoint2["eBigSquare"] = 4] = "eBigSquare";
ShapePoint2[ShapePoint2["eTwoTri"] = 5] = "eTwoTri";
ShapePoint2[ShapePoint2["eTri1"] = 6] = "eTri1";
ShapePoint2[ShapePoint2["eTri2"] = 7] = "eTri2";
ShapePoint2[ShapePoint2["eTri3"] = 8] = "eTri3";
ShapePoint2[ShapePoint2["eTri4"] = 9] = "eTri4";
return ShapePoint2;
})(ShapePoint || {});
var Point = class _Point {
cx;
cy;
shape;
constructor(ix, iy, ishape = 0 /* eDefault */) {
this.cx = ix;
this.cy = iy;
this.shape = ishape;
}
draw(ctx, cAdjust, color = colors.point, ishape = 0 /* eDefault */) {
if (isFinite(this.cx) && isFinite(this.cy)) {
const radius = ctx.canvas.width * (0.7 / 100);
const radius2 = 2 * radius;
const [cx2, cy2] = point2canvas(this.cx, this.cy, cAdjust);
let shape = ishape;
if (shape === 0 /* eDefault */) {
shape = this.shape;
}
ctx.beginPath();
switch (shape) {
case 2 /* eCross */:
ctx.moveTo(cx2 - radius2, cy2);
ctx.lineTo(cx2 + radius2, cy2);
ctx.moveTo(cx2, cy2 - radius2);
ctx.lineTo(cx2, cy2 + radius2);
break;
case 3 /* eSquare */:
ctx.rect(cx2 - radius, cy2 - radius, 2 * radius, 2 * radius);
break;
case 4 /* eBigSquare */:
ctx.rect(cx2 - 2 * radius, cy2 - 2 * radius, 4 * radius, 4 * radius);
break;
case 5 /* eTwoTri */:
ctx.moveTo(cx2 - radius2, cy2);
ctx.lineTo(cx2 + radius2, cy2);
ctx.lineTo(cx2, cy2 + radius2);
ctx.lineTo(cx2, cy2 - radius2);
ctx.lineTo(cx2 - radius2, cy2);
break;
case 6 /* eTri1 */:
ctx.moveTo(cx2 - radius2, cy2);
ctx.lineTo(cx2 + radius2, cy2);
ctx.lineTo(cx2, cy2 - radius2);
ctx.lineTo(cx2, cy2 + radius2);
break;
case 7 /* eTri2 */:
ctx.moveTo(cx2 + radius2, cy2);
ctx.lineTo(cx2 - radius2, cy2);
ctx.lineTo(cx2, cy2 - radius2);
ctx.lineTo(cx2, cy2 + radius2);
break;
case 8 /* eTri3 */:
ctx.moveTo(cx2 + radius2, cy2);
ctx.lineTo(cx2 - radius2, cy2);
ctx.lineTo(cx2, cy2 + radius2);
ctx.lineTo(cx2, cy2 - radius2);
break;
case 9 /* eTri4 */:
ctx.moveTo(cx2 - radius2, cy2);
ctx.lineTo(cx2 + radius2, cy2);
ctx.lineTo(cx2, cy2 + radius2);
ctx.lineTo(cx2, cy2 - radius2);
break;
case 1 /* eCircle */:
default:
ctx.arc(cx2, cy2, radius, 0, 2 * Math.PI);
}
ctx.strokeStyle = color;
ctx.stroke();
} else {
console.log(`INFO489: point not draw because of infinity ${this.cx} ${this.cy}`);
}
}
distanceOrig() {
return Math.sqrt(this.cx ** 2 + this.cy ** 2);
}
angleOrig() {
return Math.atan2(this.cy, this.cx);
}
getPolar() {
return [this.angleOrig(), this.distanceOrig()];
}
setPolar(ia, il) {
return new _Point(il * Math.cos(ia), il * Math.sin(ia));
}
translate(ix, iy) {
return new _Point(this.cx + ix, this.cy + iy);
}
translatePolar(ia, il) {
return new _Point(this.cx + il * Math.cos(ia), this.cy + il * Math.sin(ia));
}
clone(ishape = 0 /* eDefault */) {
return new _Point(this.cx, this.cy, ishape);
}
rotateOrig(ia) {
const polar = this.getPolar();
return this.setPolar(polar[0] + ia, polar[1]);
}
scaleOrig(ir) {
const polar = this.getPolar();
return this.setPolar(polar[0], polar[1] * ir);
}
rotate(ic, ia) {
const p1 = this.translate(-1 * ic.cx, -1 * ic.cy);
const polar = p1.getPolar();
const p2 = this.setPolar(polar[0] + ia, polar[1]);
return p2.translate(ic.cx, ic.cy);
}
scale(ic, ir) {
const p1 = this.translate(-1 * ic.cx, -1 * ic.cy);
const polar = p1.getPolar();
const p2 = this.setPolar(polar[0], polar[1] * ir);
return p2.translate(ic.cx, ic.cy);
}
// point comparison
isEqual(ic) {
const rb = roundZero(this.cx - ic.cx) === 0 && roundZero(this.cy - ic.cy) === 0;
return rb;
}
// measurement
distanceToPoint(p2) {
const rd = Math.sqrt((p2.cx - this.cx) ** 2 + (p2.cy - this.cy) ** 2);
return rd;
}
angleToPoint(p2) {
if (roundZero(this.distanceToPoint(p2)) === 0) {
throw `err434: no angle because points identical ${this.cx} ${p2.cx} ${this.cy} ${p2.cy}`;
}
const ra = Math.atan2(p2.cy - this.cy, p2.cx - this.cx);
return ra;
}
angleFromToPoints(p2, p3) {
const ap2 = this.angleToPoint(p2);
const ap3 = this.angleToPoint(p3);
const ra = withinPiPi(ap3 - ap2);
return ra;
}
// from 2 points create a new point
middlePoint(p2) {
const rx = (this.cx + p2.cx) / 2;
const ry = (this.cy + p2.cy) / 2;
return new _Point(rx, ry);
}
equidistantPoint(p2, dist, p3) {
const lp1p2h = this.distanceToPoint(p2) / 2;
if (this.isEqual(p2)) {
throw `err633: no equidistance because identical point ${this.cx} ${this.cy}`;
}
if (dist < lp1p2h) {
throw `err392: equidistance ${dist} smaller than lp1p2h ${lp1p2h}`;
}
const pbi = this.middlePoint(p2);
const abi = this.angleToPoint(p2) + Math.PI / 2;
const oppos = Math.sqrt(dist ** 2 - lp1p2h ** 2);
const rp1 = pbi.translatePolar(abi, oppos);
const rp2 = pbi.translatePolar(abi + Math.PI, oppos);
const dp1 = p3.distanceToPoint(rp1);
const dp2 = p3.distanceToPoint(rp2);
if (oppos !== 0 && dp1 === dp2) {
throw `err284: magnet point p3 is on line p1p2. cx ${p3.cx} cy: ${p3.cy}`;
}
let rp = rp1;
if (dp2 < dp1) {
rp = rp2;
}
return rp;
}
};
function point(ix, iy, ishape = 0 /* eDefault */) {
return new Point(ix, iy, ishape);
}
function pointMinMax(aPoint) {
let xMin = 0;
let xMax = 0;
let yMin = 0;
let yMax = 0;
if (aPoint.length > 0) {
const p0 = aPoint[0];
if (p0.cx === Number.NEGATIVE_INFINITY || p0.cx === Number.POSITIVE_INFINITY || p0.cy === Number.NEGATIVE_INFINITY || p0.cy === Number.POSITIVE_INFINITY) {
throw `err292: pointMinMax first point with infinity: ${p0.cx} ${p0.cy}`;
}
xMin = aPoint[0].cx;
xMax = aPoint[0].cx;
yMin = aPoint[0].cy;
yMax = aPoint[0].cy;
for (const p of aPoint) {
if (p.cx !== Number.NEGATIVE_INFINITY) {
xMin = Math.min(xMin, p.cx);
}
if (p.cx !== Number.POSITIVE_INFINITY) {
xMax = Math.max(xMax, p.cx);
}
if (p.cy !== Number.NEGATIVE_INFINITY) {
yMin = Math.min(yMin, p.cy);
}
if (p.cy !== Number.POSITIVE_INFINITY) {
yMax = Math.max(yMax, p.cy);
}
}
}
return [xMin, xMax, yMin, yMax];
}
// src/line.ts
var Line = class _Line {
cx;
cy;
ca;
constructor(ix, iy, ia) {
this.cx = ix;
this.cy = iy;
this.ca = ia;
}
draw(ctx, cAdjust, color = colors.line) {
const display_length = ctx.canvas.width * 2;
const [cx1, cy1] = point2canvas(
this.cx - display_length * Math.cos(this.ca),
this.cy - display_length * Math.sin(this.ca),
cAdjust
);
const [cx2, cy2] = point2canvas(
this.cx + 2 * display_length * Math.cos(this.ca),
this.cy + 2 * display_length * Math.sin(this.ca),
cAdjust
);
ctx.beginPath();
ctx.moveTo(cx1, cy1);
ctx.lineTo(cx2, cy2);
ctx.strokeStyle = color;
ctx.stroke();
}
setFromPoints(p1, p2) {
this.cx = p1.cx;
this.cy = p1.cy;
this.ca = p1.angleToPoint(p2);
return this;
}
getAffine() {
const rAffine = { quasiVertical: false, ha: 0, hb: 0, va: 0, vb: 0 };
const angleZeroHPi = Math.abs(withinHPiHPi(this.ca));
if (angleZeroHPi > Math.PI / 4) {
rAffine.quasiVertical = true;
rAffine.va = -1 * Math.tan(withinHPiHPi(this.ca - Math.PI / 2));
rAffine.vb = this.cx - rAffine.va * this.cy;
} else {
rAffine.ha = Math.tan(withinHPiHPi(this.ca));
rAffine.hb = this.cy - rAffine.ha * this.cx;
}
return rAffine;
}
setAffine(iAffine) {
const rLine = new _Line(0, 0, 0);
if (iAffine.quasiVertical) {
rLine.ca = Math.PI / 2 - Math.atan(iAffine.va);
rLine.cx = iAffine.vb;
rLine.cy = 0;
} else {
rLine.ca = Math.atan(iAffine.ha);
rLine.cx = 0;
rLine.cy = iAffine.hb;
}
return rLine;
}
// intersection
intersection(il) {
if (this.isParallel(il)) {
throw `err902: no intersection, lines are parallel ca1: ${this.ca} ca2: ${il.ca}`;
}
let rx = 0;
let ry = 0;
const affin1 = this.getAffine();
const affin2 = il.getAffine();
if (affin1.quasiVertical) {
if (affin2.quasiVertical) {
ry = (affin1.vb - affin2.vb) / (affin2.va - affin1.va);
rx = affin1.va * ry + affin1.vb;
} else {
rx = (affin1.va * affin2.hb + affin1.vb) / (1 - affin1.va * affin2.ha);
ry = affin2.ha * rx + affin2.hb;
}
} else {
if (affin2.quasiVertical) {
ry = (affin1.ha * affin2.vb + affin1.hb) / (1 - affin1.ha * affin2.va);
rx = affin2.va * ry + affin2.vb;
} else {
rx = (affin1.hb - affin2.hb) / (affin2.ha - affin1.ha);
ry = affin1.ha * rx + affin1.hb;
}
}
const rp = point(rx, ry);
return rp;
}
getAxisXIntersection() {
const c_axisX = new _Line(0, 0, 0);
const rp = this.intersection(c_axisX);
return rp.cx;
}
getAxisYIntersection() {
const c_axisY = new _Line(0, 0, Math.PI / 2);
const rp = this.intersection(c_axisY);
return rp.cy;
}
getAxisXIntersecTri() {
let rX = Infinity;
if (roundZero(withinHPiHPi(this.ca)) !== 0) {
const p1 = new Point(this.cx, this.cy);
const l1ca = withinZeroPi(this.ca);
const aC = p1.angleOrig();
const la = p1.distanceOrig();
if (roundZero(la) === 0) {
rX = 0;
} else if (roundZero(withinHPiHPi(l1ca - aC)) === 0) {
rX = 0;
} else {
const aA = Math.min(l1ca, Math.PI - l1ca);
const aB = withinPiPi(l1ca - aC);
const aB2 = Math.min(Math.abs(aB), Math.PI - Math.abs(aB));
rX = Math.sign(aB) * lbFromLaAaAb(la, aA, aB2);
}
}
return rX;
}
getAxisYIntersecTri() {
let rY = Infinity;
if (roundZero(withinHPiHPi(this.ca - Math.PI / 2)) !== 0) {
const p1 = new Point(this.cx, this.cy);
const l1ca = withinHPiHPi(this.ca);
const aC = p1.angleOrig();
const la = p1.distanceOrig();
const angleDiff = withinHPiHPi(l1ca - aC);
if (roundZero(la) === 0) {
rY = 0;
} else if (roundZero(angleDiff) === 0) {
rY = 0;
} else {
const aA = withinZeroPi(l1ca - Math.PI / 2);
const aB = -1 * withinPiPi(l1ca - aC);
const aA2 = Math.min(aA, Math.PI - aA);
const aB2 = Math.min(Math.abs(aB), Math.PI - Math.abs(aB));
rY = Math.sign(aB) * lbFromLaAaAb(la, aA2, aB2);
}
}
return rY;
}
angleOrig() {
const p1 = new Point(this.cx, this.cy);
const aC = p1.angleOrig();
const l1ca = withinHPiHPi(this.ca);
const aB = -1 * withinPiPi(l1ca - aC);
let direction = 0;
if (aB < 0) {
direction = -Math.PI;
}
const ra = withinZeroPi(Math.PI / 2 + this.ca) + direction;
return ra;
}
distanceOrig() {
const a1 = this.angleOrig();
const p1 = new Point(this.cx, this.cy);
const a2 = p1.angleOrig();
const la = p1.distanceOrig();
const a12 = withinHPiHPi(a2 - a1);
const rd = la * Math.cos(a12);
return rd;
}
projectOrig() {
const pa = this.angleOrig();
const pl = this.distanceOrig();
return point(0, 0).setPolar(pa, pl);
}
// methods inherited from point
translate(ix, iy) {
return new _Line(this.cx + ix, this.cy + iy, this.ca);
}
rotateOrig(ia) {
const lPoint2 = new Point(this.cx, this.cy).rotateOrig(ia);
return new _Line(lPoint2.cx, lPoint2.cy, withinPiPi(this.ca + ia));
}
scaleOrig(ir) {
const lPoint2 = new Point(this.cx, this.cy).scaleOrig(ir);
return new _Line(lPoint2.cx, lPoint2.cy, this.ca);
}
rotate(ic, ia) {
const lPoint2 = new Point(this.cx, this.cy).rotate(ic, ia);
return new _Line(lPoint2.cx, lPoint2.cy, withinPiPi(this.ca + ia));
}
scale(ic, ir) {
const lPoint2 = new Point(this.cx, this.cy).scale(ic, ir);
return new _Line(lPoint2.cx, lPoint2.cy, this.ca);
}
clone() {
const lPoint2 = new Point(this.cx, this.cy);
return new _Line(lPoint2.cx, lPoint2.cy, this.ca);
}
// end of methods from point
// line creation
lineOrthogonal(ic) {
return new _Line(ic.cx, ic.cy, this.ca + Math.PI / 2);
}
lineParallel(ic) {
return new _Line(ic.cx, ic.cy, this.ca);
}
// orthogonal projection
distanceToPoint(ic) {
let rd = 0;
const p1 = new Point(this.cx, this.cy);
const lp1ic = p1.distanceToPoint(ic);
if (roundZero(lp1ic) !== 0) {
const aC = p1.angleToPoint(ic);
const aB = withinHPiHPi(aC - this.ca);
rd = lp1ic * Math.abs(Math.sin(aB));
}
return rd;
}
projectPoint(ic) {
let rd = 0;
const p1 = new Point(this.cx, this.cy);
const lp1ic = p1.distanceToPoint(ic);
if (roundZero(lp1ic) !== 0) {
const aC = p1.angleToPoint(ic);
const aB = withinPiPi(aC - this.ca);
rd = lp1ic * Math.cos(aB);
}
const rp = p1.translatePolar(this.ca, rd);
return rp;
}
// line comparison
isParallel(il) {
const rb = roundZero(withinHPiHPi(this.ca - il.ca)) === 0;
return rb;
}
isOrthogonal(il) {
const rb = roundZero(withinHPiHPi(Math.PI / 2 + this.ca - il.ca)) === 0;
return rb;
}
isEqual(il) {
const p2 = point(il.cx, il.cy);
const dist = this.distanceToPoint(p2);
const rb = roundZero(dist) === 0 && this.isParallel(il);
return rb;
}
// bisector
bisector(il, ip) {
const pInter = this.intersection(il);
const a1t = withinZeroPi(this.ca);
const a2t = withinZeroPi(il.ca);
const a1 = Math.min(a1t, a2t);
const a2 = Math.max(a1t, a2t);
const aList = [a1, a2, a1 + Math.PI, a2 + Math.PI, a1];
const aRef = pInter.angleToPoint(ip);
let idx = 0;
for (let i = 0; i < 4; i++) {
const aDiff1 = withinPiPi(aList[i] - aRef);
const aDiff2 = withinPiPi(aList[i + 1] - aRef);
if (aDiff1 === 0 || aDiff2 === 0) {
throw `err419: bad reference point for bisecor ${ip.cx} ${ip.cy}`;
}
if (aDiff1 < 0 && aDiff2 > 0) {
idx = i;
}
}
const a0 = withinZeroPi((a1 + a2) / 2);
const ca = a0 + idx * Math.PI / 2;
return new _Line(pInter.cx, pInter.cy, ca);
}
// parallel distance
lineParallelDistance(iDist, ipMagnet, ipMagnet2) {
const p1 = point(this.cx, this.cy);
const p2a = p1.translatePolar(this.ca + Math.PI / 2, iDist);
const p2b = p1.translatePolar(this.ca - Math.PI / 2, iDist);
let p2 = p2b;
let pMagnet = ipMagnet;
if (roundZero(this.distanceToPoint(pMagnet)) === 0) {
pMagnet = ipMagnet2;
}
if (pMagnet.distanceToPoint(p2a) < pMagnet.distanceToPoint(p2b)) {
p2 = p2a;
}
return new _Line(p2.cx, p2.cy, this.ca);
}
};
function line(ix, iy, ia) {
return new Line(ix, iy, ia);
}
function linePP(ip1, ip2) {
const rline = line(0, 0, 0).setFromPoints(ip1, ip2);
return rline;
}
function bisector(ip1, ip2) {
if (ip1.isEqual(ip2)) {
throw `err546: no bisector with two same points cx: ${ip1.cx} cy: ${ip1.cy}`;
}
const pbi = ip1.middlePoint(ip2);
const abi = withinZeroPi(ip1.angleToPoint(ip2) + Math.PI / 2);
return line(pbi.cx, pbi.cy, abi);
}
function circleCenter(ip1, ip2, ip3) {
if (ip1.isEqual(ip2) || ip2.isEqual(ip3) || ip1.isEqual(ip3)) {
throw `err833: no bisector with two same points cx: ${ip1.cx} cy: ${ip1.cy}`;
}
const bisec1 = bisector(ip1, ip2);
const bisec2 = bisector(ip2, ip3);
const rp = bisec1.intersection(bisec2);
return rp;
}
// src/segment.ts
var SegEnum = /* @__PURE__ */ ((SegEnum2) => {
SegEnum2[SegEnum2["eStroke"] = 0] = "eStroke";
SegEnum2[SegEnum2["eArc"] = 1] = "eArc";
SegEnum2[SegEnum2["ePointed"] = 2] = "ePointed";
SegEnum2[SegEnum2["eRounded"] = 3] = "eRounded";
SegEnum2[SegEnum2["eWidened"] = 4] = "eWidened";
SegEnum2[SegEnum2["eWideAcc"] = 5] = "eWideAcc";
SegEnum2[SegEnum2["eStart"] = 6] = "eStart";
return SegEnum2;
})(SegEnum || {});
function isSeg(iSegEnum) {
let rIsSeg = false;
if (iSegEnum === 0 /* eStroke */ || iSegEnum === 1 /* eArc */) {
rIsSeg = true;
}
return rIsSeg;
}
function isAddPoint(iSegEnum) {
let rIsOther = false;
if (isSeg(iSegEnum) || iSegEnum === 6 /* eStart */) {
rIsOther = true;
}
return rIsOther;
}
function isActiveCorner(iSegEnum) {
let rIsActiveCorner = false;
if (iSegEnum === 3 /* eRounded */ || iSegEnum === 4 /* eWidened */ || iSegEnum === 5 /* eWideAcc */) {
rIsActiveCorner = true;
}
return rIsActiveCorner;
}
function isCorner(iSegEnum) {
let rIsCorner = false;
if (iSegEnum === 2 /* ePointed */ || isActiveCorner(iSegEnum)) {
rIsCorner = true;
}
return rIsCorner;
}
var Segment1 = class _Segment1 {
sType;
px;
py;
radius;
arcLarge;
arcCcw;
constructor(iType, ix, iy, iRadius, iArcLarge = false, iArcCcw = false) {
this.sType = iType;
this.px = ix;
this.py = iy;
this.radius = iRadius;
this.arcLarge = iArcLarge;
this.arcCcw = iArcCcw;
}
clone() {
const rseg1 = new _Segment1(
this.sType,
this.px,
this.py,
this.radius,
this.arcLarge,
this.arcCcw
);
return rseg1;
}
};
var Segment2 = class {
sType;
p1;
p2;
pc;
radius;
a1;
a2;
arcCcw;
constructor(iType, ip1, ip2, ipc, iRadius, ia1, ia2, iArcCcw = false) {
this.sType = iType;
this.p1 = ip1;
this.p2 = ip2;
this.pc = ipc;
this.radius = iRadius;
this.a1 = ia1;
this.a2 = ia2;
this.arcCcw = iArcCcw;
}
};
var SegDbg = class {
debugPoints;
debugLines;
logMessage;
constructor() {
this.debugPoints = [];
this.debugLines = [];
this.logMessage = "";
}
addPoint(ip) {
this.debugPoints.push(ip);
}
getPoints() {
return this.debugPoints;
}
clearPoints() {
this.debugPoints = [];
}
addLine(il) {
this.debugLines.push(il);
}
getLines() {
return this.debugLines;
}
clearLines() {
this.debugLines = [];
}
addMsg(iMsg) {
this.logMessage += iMsg;
}
getMsg() {
return this.logMessage;
}
clearMsg() {
this.logMessage = "";
}
};
var gSegDbg = new SegDbg();
function arcSeg1To2(px1, py1, iSeg1) {
if (iSeg1.sType !== 1 /* eArc */) {
throw `err202: arcSeg1To2 has unexpected type ${iSeg1.sType}`;
}
const p1 = point(px1, py1);
const p2 = point(iSeg1.px, iSeg1.py);
const lp1p2h = p1.distanceToPoint(p2) / 2;
if (p1.isEqual(p2)) {
throw `err638: no equidistance because identical point ${p1.cx} ${p2.cy}`;
}
let oppos = 0;
if (roundZero(iSeg1.radius - lp1p2h) === 0) {
oppos = 0;
} else if (iSeg1.radius < lp1p2h) {
throw `err399: radius ${iSeg1.radius} smaller than lp1p2h ${lp1p2h}`;
} else {
oppos = rightTriLbFromLaLc(iSeg1.radius, lp1p2h);
}
const pbi = p1.middlePoint(p2);
const abi = p1.angleToPoint(p2) + Math.PI / 2;
const rp1 = pbi.translatePolar(abi, oppos);
const rp2 = pbi.translatePolar(abi + Math.PI, oppos);
let rp3 = rp1;
if (!iSeg1.arcLarge && !iSeg1.arcCcw || iSeg1.arcLarge && iSeg1.arcCcw) {
rp3 = rp2;
}
const a1 = rp3.angleToPoint(p1);
const a2 = rp3.angleToPoint(p2);
const rSeg2 = new Segment2(1 /* eArc */, p1, p2, rp3, iSeg1.radius, a1, a2, iSeg1.arcCcw);
return rSeg2;
}
function arcSeg2To1(iSeg2) {
let a12 = withinZero2Pi(iSeg2.a2 - iSeg2.a1);
if (!iSeg2.arcCcw) {
a12 = 2 * Math.PI - a12;
}
let large = false;
if (a12 > Math.PI) {
large = true;
}
const rSeg1 = new Segment1(
1 /* eArc */,
iSeg2.p2.cx,
iSeg2.p2.cy,
iSeg2.radius,
large,
iSeg2.arcCcw
);
return rSeg1;
}
function prepare(s1, s2, s3) {
const p1 = s1.p1;
const p2 = s1.p2;
const p2b = s3.p1;
const p3 = s3.p2;
if (!p2.isEqual(p2b)) {
throw `err309: makeCorner-prepare p2 and p2b differ px ${p2.cx} ${p2b.cx} py ${p2.cy} ${p2b.cy}`;
}
let aTangent1 = p2.angleToPoint(p1);
if (s1.sType === 1 /* eArc */) {
const sign = s1.arcCcw ? 1 : -1;
aTangent1 = s1.a2 - sign * Math.PI / 2;
}
let aTangent3 = p2.angleToPoint(p3);
if (s3.sType === 1 /* eArc */) {
const sign = s3.arcCcw ? 1 : -1;
aTangent3 = s3.a1 + sign * Math.PI / 2;
}
const a123 = aTangent3 - aTangent1;
const a123b = withinPiPi(a123);
let aPeakHalf = a123b / 2;
if (roundZero(aPeakHalf) === 0) {
const tolerance2 = tolerance * 10 ** -2;
if (s1.sType === 0 /* eStroke */ && s3.sType === 1 /* eArc */) {
aPeakHalf = s3.arcCcw ? tolerance2 : -tolerance2;
} else if (s1.sType === 1 /* eArc */ && s3.sType === 0 /* eStroke */) {
aPeakHalf = s1.arcCcw ? tolerance2 : -tolerance2;
} else if (s1.sType === 0 /* eStroke */ && s3.sType === 0 /* eStroke */) {
throw `err402: prepare aPeakHalf too closed to zero ${aPeakHalf}`;
}
}
const aBisector = aTangent1 + aPeakHalf;
const p6 = p2.translatePolar(aBisector, s2.radius);
const rPre = {
s1,
s2,
s3,
ra: s2.radius,
p1,
p2,
p3,
p4: s1.pc,
p5: s3.pc,
p6,
at1: aTangent1,
at3: aTangent3,
abi: aBisector,
aph: aPeakHalf
};
return rPre;
}
function modifRadius(iaph, iseg, iradius) {
if (iseg.sType !== 1 /* eArc */) {
throw `err510: modifRadius with wrong type ${iseg.sType}`;
}
const bisector2 = iaph > 0 ? 1 : -1;
const arcCcw = iseg.arcCcw ? 1 : -1;
const sign = roundZero(iaph) === 0 ? 1 : bisector2 * arcCcw;
const rmr = iseg.radius + sign * iradius;
if (rmr <= 0) {
throw `err621: modifRadius with negative modified lenght ${rmr}`;
}
return rmr;
}
function closestPoint(ica, dist, pB, p6) {
const p7a = pB.translatePolar(ica, dist);
const p7b = pB.translatePolar(ica + Math.PI, dist);
const d67a = p6.distanceToPoint(p7a);
const d67b = p6.distanceToPoint(p7b);
const rp7 = d67a < d67b ? p7a : p7b;
return rp7;
}
function closestPoint2(p4, a45, a547, dist, p6) {
const p7a = p4.translatePolar(a45 - a547, dist);
const p7b = p4.translatePolar(a45 + a547, dist);
const d67a = p6.distanceToPoint(p7a);
const d67b = p6.distanceToPoint(p7b);
const sign = d67a < d67b ? -1 : 1;
return sign;
}
function newStrokeFirst(iseg, ip) {
const p8 = ip.clone();
const p1 = iseg.p1.clone();
const p2 = iseg.p2;
if (iseg.sType !== 0 /* eStroke */) {
throw `err103: newStrokeFirst unexpected sType ${iseg.sType}`;
}
const distLine = linePP(p1, p2).distanceToPoint(p8);
if (roundZero(distLine) !== 0) {
throw `err104: newStrokeFirst new point not aligned ${distLine} ${p8.cx} ${p8.cy}`;
}
const a2 = p1.angleToPoint(p2);
const a8 = p1.angleToPoint(p8);
if (roundZero(withinPiPi(a8 - a2)) !== 0) {
throw `err105: newStrokeFirst new point miss aligned ${a2} ${a8} ${p8.cx} ${p8.cy}`;
}
const l18 = p1.distanceToPoint(p8);
const l12 = p1.distanceToPoint(p2);
if (l12 < l18) {
throw `err106: newStrokeFirst new point out of scope ${l12} ${l18} ${p8.cx} ${p8.cy}`;
}
const p0 = point(0, 0);
const rNewSeg = new Segment2(0 /* eStroke */, p1, p8, p0, 0, 0, 0, false);
return rNewSeg;
}
function newStrokeSecond(iseg, ip) {
const p9 = ip.clone();
const p3 = iseg.p2.clone();
const p2 = iseg.p1;
if (iseg.sType !== 0 /* eStroke */) {
throw `err203: newStrokeSecond unexpected sType ${iseg.sType}`;
}
const distLine = linePP(p3, p2).distanceToPoint(p9);
if (roundZero(distLine) !== 0) {
throw `err204: newStrokeSecond new point not aligned ${distLine} ${p9.cx} ${p9.cy}`;
}
const a2 = p3.angleToPoint(p2);
const a9 = p3.angleToPoint(p9);
if (roundZero(withinPiPi(a9 - a2)) !== 0) {
throw `err205: newStrokeSecond new point miss aligned ${a2} ${a9} ${p9.cx} ${p9.cy}`;
}
const l39 = p3.distanceToPoint(p9);
const l32 = p3.distanceToPoint(p2);
if (l32 < l39) {
throw `err206: newStrokeSecond new point out of scope ${l32} ${l39} ${p9.cx} ${p9.cy}`;
}
const p0 = point(0, 0);
const rNewSeg = new Segment2(0 /* eStroke */, p9, p3, p0, 0, 0, 0, false);
return rNewSeg;
}
function newArcFirst(iseg, ip) {
if (iseg.sType !== 1 /* eArc */) {
throw `err203: newArcFirst unexpected sType ${iseg.sType}`;
}
const p1 = iseg.p1.clone();
const p4 = iseg.pc.clone();
const p8 = ip.clone();
const a48 = p4.angleToPoint(p8);
if (!isWithin(a48, iseg.a1, iseg.a2, iseg.arcCcw)) {
throw `err908: newArcFirst a48 out of scope ${a48} ${iseg.a1} ${iseg.a2} ${iseg.arcCcw}`;
}
const rNewSeg = new Segment2(1 /* eArc */, p1, p8, p4, iseg.radius, iseg.a1, a48, iseg.arcCcw);
return rNewSeg;
}
function newArcSecond(iseg, ip) {
if (iseg.sType !== 1 /* eArc */) {
throw `err204: newArcSecond unexpected sType ${iseg.sType}`;
}
const p3 = iseg.p2.clone();
const p5 = iseg.pc.clone();
const p9 = ip.clone();
const a59 = p5.angleToPoint(p9);
if (!isWithin(a59, iseg.a1, iseg.a2, iseg.arcCcw)) {
throw `err907: newArcSecond a59 out of scope ${a59} ${iseg.a1} ${iseg.a2} ${iseg.arcCcw}`;
}
const rNewSeg = new Segment2(1 /* eArc */, p9, p3, p5, iseg.radius, a59, iseg.a2, iseg.arcCcw);
return rNewSeg;
}
function newRounded(ip8, ip9, ip7, ra, aph, abi) {
const p8 = ip8.clone();
const p9 = ip9.clone();
const p7 = ip7.clone();
const l78 = p7.distanceToPoint(p8);
const l79 = p7.distanceToPoint(p9);
if (roundZero(l78 - ra) !== 0 || roundZero(l79 - ra) !== 0) {
throw `err610: newRounded not on circle ${ra} ${l78} ${l79}`;
}
const a78 = p7.angleToPoint(p8);
const a79 = p7.angleToPoint(p9);
const a873 = withinPiPi(a78 - abi + Math.PI);
const a973 = withinPiPi(a79 - abi + Math.PI);
if (Math.abs(a973 - a873) > Math.PI + tolerance) {
gSegDbg.addMsg(
`warn882: newRounded a873 or a972 larger than PI/2 ${ffix(a873)} ${ffix(a973)} at ${ffix(p7.cx)} ${ffix(p7.cy)}
`
);
}
const ccw2 = aph > 0 ? false : true;
const rNewSeg = new Segment2(1 /* eArc */, p8, p9, p7, ra, a78, a79, ccw2);
return rNewSeg;
}
function roundStrokeStroke(ag) {
const l7 = Math.abs(ag.ra / Math.sin(ag.aph));
const l7b = l7 * Math.cos(ag.aph);
const p7 = ag.p2.translatePolar(ag.abi, l7);
const p8 = ag.p2.translatePolar(ag.at1, l7b);
const p9 = ag.p2.translatePolar(ag.at3, l7b);
const rsegs = [];
rsegs.push(newStrokeFirst(ag.s1, p8));
rsegs.push(newRounded(p8, p9, p7, ag.ra, ag.aph, ag.abi));
rsegs.push(newStrokeSecond(ag.s3, p9));
return rsegs;
}
function roundStrokeArc(ag) {
const lStroke = linePP(ag.p1, ag.p2);
const lStrokep = lStroke.lineParallelDistance(ag.ra, ag.p6, ag.p5);
const pB = lStrokep.projectPoint(ag.p5);
const lB5 = pB.distanceToPoint(ag.p5);
const ml = modifRadius(ag.aph, ag.s3, ag.ra);
const lB7 = rightTriLbFromLaLc(ml, lB5);
const p7 = closestPoint(lStrokep.ca, lB7, pB, ag.p6);
const a57 = ag.p5.angleToPoint(p7);
const p9 = ag.p5.translatePolar(a57, ag.s3.radius);
const a127 = ag.p2.angleFromToPoints(ag.p1, p7);
const l27 = Math.abs(ag.ra / Math.sin(a127));
const l28 = l27 * Math.cos(a127);
const a28 = ag.p2.angleToPoint(ag.p1);
const p8 = ag.p2.translatePolar(a28, l28);
const rsegs = [];
rsegs.push(newStrokeFirst(ag.s1, p8));
rsegs.push(newRounded(p8, p9, p7, ag.ra, ag.aph, ag.abi));
rsegs.push(newArcSecond(ag.s3, p9));
return rsegs;
}
function roundArcStroke(ag) {
const lStroke = linePP(ag.p3, ag.p2);
const lStrokep = lStroke.lineParallelDistance(ag.ra, ag.p6, ag.p4);
const pB = lStrokep.projectPoint(ag.p4);
const lB4 = pB.distanceToPoint(ag.p4);
const ml = modifRadius(ag.aph, ag.s1, ag.ra);
const lB7 = rightTriLbFromLaLc(ml, lB4);
const p7 = closestPoint(lStrokep.ca, lB7, pB, ag.p6);
const a47 = ag.p4.angleToPoint(p7);
const p8 = ag.p4.translatePolar(a47, ag.s1.radius);
const a327 = ag.p2.angleFromToPoints(ag.p3, p7);
const l27 = Math.abs(ag.ra / Math.sin(a327));
const l29 = l27 * Math.cos(a327);
const a29 = ag.p2.angleToPoint(ag.p3);
const p9 = ag.p2.translatePolar(a29, l29);
const rsegs = [];
rsegs.push(newArcFirst(ag.s1, p8));
rsegs.push(newRounded(p8, p9, p7, ag.ra, ag.aph, ag.abi));
rsegs.push(newStrokeSecond(ag.s3, p9));
return rsegs;
}
function roundArcArc(ag) {
const mr1 = modifRadius(ag.aph, ag.s1, ag.ra);
const mr3 = modifRadius(ag.aph, ag.s3, ag.ra);
const lp4p5 = ag.p4.distanceToPoint(ag.p5);
const a45 = ag.p4.angleToPoint(ag.p5);
const a547 = aCFromLaLbLc(lp4p5, mr1, mr3);
const sign1 = closestPoint2(ag.p4, a45, a547, mr1, ag.p6);
const a47 = a45 + sign1 * a547;
const p7 = ag.p4.translatePolar(a47, mr1);
const p8 = ag.p4.translatePolar(a47, ag.s1.radius);
const a54 = Math.PI + a45;
const a457 = aCFromLaLbLc(lp4p5, mr3, mr1);
const sign2 = closestPoint2(ag.p5, a54, a457, mr3, ag.p6);
const a57 = a54 + sign2 * a457;
const p7b = ag.p5.translatePolar(a57, mr3);
if (!p7b.isEqual(p7)) {
throw `err909: roundArcArc p7 anf p7b differ ${p7.cx} ${p7b.cx} ${p7.cy} ${p7b.cy} ${0 /* eDefault */}`;
}
const p9 = ag.p5.translatePolar(a57, ag.s3.radius);
const rsegs = [];
rsegs.push(newArcFirst(ag.s1, p8));
rsegs.push(newRounded(p8, p9, p7, ag.ra, ag.aph, ag.abi));
rsegs.push(newArcSecond(ag.s3, p9));
return rsegs;
}
function widenCorner(ag) {
const a68 = ag.abi - 2 * ag.aph;
const a69 = ag.abi + 2 * ag.aph;
let p8 = ag.p6.translatePolar(a68, ag.ra);
let p9 = ag.p6.translatePolar(a69, ag.ra);
if (ag.s1.sType === 1 /* eArc */) {
const a246 = ag.p4.angleFromToPoints(ag.p2, ag.p6);
const a42 = ag.p4.angleToPoint(ag.p2);
const a46 = a42 + 2 * a246;
p8 = ag.p4.translatePolar(a46, ag.s1.radius);
}
if (ag.s3.sType === 1 /* eArc */) {
const a256 = ag.p5.angleFromToPoints(ag.p2, ag.p6);
const a52 = ag.p5.angleToPoint(ag.p2);
const a56 = a52 + 2 * a256;
p9 = ag.p5.translatePolar(a56, ag.s3.radius);
}
const ccw2 = ag.aph > 0 ? false : true;
const segCorner = new Segment2(1 /* eArc */, p8, p9, ag.p6, ag.ra, a68, a69, ccw2);
const rsegs = [];
if (ag.s1.sType === 0 /* eStroke */) {
rsegs.push(newStrokeFirst(ag.s1, p8));
} else if (ag.s1.sType === 1 /* eArc */) {
rsegs.push(newArcFirst(ag.s1, p8));
}
rsegs.push(segCorner);
if (ag.s3.sType === 0 /* eStroke */) {
rsegs.push(newStrokeSecond(ag.s3, p9));
} else if (ag.s3.sType === 1 /* eArc */) {
rsegs.push(newArcSecond(ag.s3, p9));
}
return rsegs;
}
function wideAccessSide(sign, one, p8one, ag) {
let p8a = p8one;
let p8b = p8one;
const a268 = ag.p6.angleFromToPoints(ag.p2, p8one);
if (Math.abs(a268) > Math.PI / 2) {
p8b = ag.p6.translatePolar(ag.abi + sign * Math.PI / 2, ag.ra);
const l2 = line(p8b.cx, p8b.cy, ag.abi);
if (one.sType === 0 /* eStroke */) {
const l1 = linePP(one.p1, one.p2);
p8a = l1.intersection(l2);
} else if (one.sType === 1 /* eArc */) {
const ph = l2.projectPoint(one.pc);
const lh4 = ph.distanceToPoint(one.pc);
if (lh4 < one.radius) {
const lh8a = rightTriLbFromLaLc(one.radius, lh4);
p8a = closestPoint(ag.abi, lh8a, ph, p8one);
} else {
gSegDbg.addMsg(
`warn222: wideAccess not possible on arc ${ffix(one.radius)} ${ffix(lh4)} at ${ffix(p8one.cx)} ${ffix(p8one.cy)}
`
);
p8a = p8one;
p8b = p8one;
}
}
}
return [p8a, p8b];
}
function wideAccessCorner(ag) {
const ones = widenCorner(ag);
const sign1 = ones[1].arcCcw ? 1 : -1;
const [p8a, p8b] = wideAccessSide(sign1, ag.s1, ones[1].p1, ag);
const [p9a, p9b] = wideAccessSide(-sign1, ag.s3, ones[1].p2, ag);
const rsegs = [];
if (p8a.isEqual(p8b)) {
rsegs.push(ones[0]);
} else {
if (ag.s1.sType === 0 /* eStroke */) {
rsegs.push(newStrokeFirst(ag.s1, p8a));
} else if (ag.s1.sType === 1 /* eArc */) {
rsegs.push(newArcFirst(ag.s1, p8a));
}
const p0 = point(0, 0);
const newStroke = new Segment2(0 /* eStroke */, p8a, p8b, p0, 0, 0, 0, false);
rsegs.push(newStroke);
}
rsegs.push(newRounded(p8b, p9b, ag.p6, ag.ra, ag.aph, ag.abi));
if (p9a.isEqual(p9b)) {
rsegs.push(ones[2]);
} else {
const p0 = point(0, 0);
const newStroke = new Segment2(0 /* eStroke */, p9b, p9a, p0, 0, 0, 0, false);
rsegs.push(newStroke);
if (ag.s3.sType === 0 /* eStroke */) {
rsegs.push(newStrokeSecond(ag.s3, p9a));
} else if (ag.s3.sType === 1 /* eArc */) {
rsegs.push(newArcSecond(ag.s3, p9a));
}
}
return rsegs;
}
function makeCorner(s1, s2, s3) {
const preArg = prepare(s1, s2, s3);
const rsegs = [];
if (s2.sType === 3 /* eRounded */) {
if (s1.sType === 0 /* eStroke */ && s3.sType === 0 /* eStroke */) {
rsegs.push(...roundStrokeStroke(preArg));
} else if (s1.sType === 0 /* eStroke */ && s3.sType === 1 /* eArc */) {
rsegs.push(...roundStrokeArc(preArg));
} else if (s1.sType === 1 /* eArc */ && s3.sType === 0 /* eStroke */) {
rsegs.push(...roundArcStroke(preArg));
} else if (s1.sType === 1 /* eArc */ && s3.sType === 1 /* eArc */) {
rsegs.push(...roundArcArc(preArg));
} else {
throw `err123: makeCorner unexpected s1s3.sType ${s1.sType} ${s3.sType}`;
}
} else if (s2.sType === 4 /* eWidened */) {
rsegs.push(...widenCorner(preArg));
} else if (s2.sType === 5 /* eWideAcc */) {
rsegs.push(...wideAccessCorner(preArg));
} else {
throw `err723: makeCorner unexpected s2.sType ${s2.sType}`;
}
return rsegs;
}
// src/vector.ts
var Vector = class _Vector {
ca;
cl;
drawPoint;
constructor(ia, il, iDrawPoint) {
this.ca = ia;
this.cl = il;
this.drawPoint = iDrawPoint;
}
draw(ctx, cAdjust, color = colors.vector) {
const radius = ctx.canvas.width * (0.7 / 100);
const [cx2, cy2] = point2canvas(this.drawPoint.cx, this.drawPoint.cy, cAdjust);
const [cx3, cy3] = canvasTranslatePolar(cx2, cy2, this.ca + Math.PI / 2, 2 * radius);
const [cx4, cy4] = canvasTranslatePolar(cx2, cy2, this.ca - Math.PI / 2, 2 * radius);
const p3 = this.drawPoint.translatePolar(this.ca, this.cl);
const [cx5, cy5] = point2canvas(p3.cx, p3.cy, cAdjust);
const [cx6, cy6] = canvasTranslatePolar(cx5, cy5, this.ca + 3 * Math.PI / 4, 4 * radius);
const [cx7, cy7] = canvasTranslatePolar(cx5, cy5, this.ca + 5 * Math.PI / 4, 4 * radius);
ctx.beginPath();
ctx.moveTo(cx3, cy3);
ctx.lineTo(cx4, cy4);
ctx.moveTo(cx2, cy2);
ctx.lineTo(cx5, cy5);
ctx.lineTo(cx6, cy6);
ctx.moveTo(cx5, cy5);
ctx.lineTo(cx7, cy7);
ctx.strokeStyle = color;
ctx.stroke();
}
getCartesian() {
return [this.cl * Math.cos(this.ca), this.cl * Math.sin(this.ca)];
}
setCartesian(ix, iy) {
return new _Vector(Math.atan2(iy, ix), Math.sqrt(ix ** 2 + iy ** 2), this.drawPoint);
}
translatePoint(ip) {
const [x1, y1] = this.getCartesian();
return ip.translate(x1, y1);
}
add(iVect) {
const [x1, y1] = this.getCartesian();
const [x2, y2] = iVect.getCartesian();
const rVect = this.setCartesian(x1 + x2, y1 + y2);
return rVect;
}
addCart(ix, iy) {
const [x1, y1] = this.getCartesian();
const rVect = this.setCartesian(x1 + ix, y1 + iy);
return rVect;
}
// transforms
translate(ix, iy) {
const rVec = new _Vector(this.ca, this.cl, this.drawPoint.translate(ix, iy));
return rVec;
}
rotate(ic, ia) {
const rVec = new _Vector(this.ca + ia, this.cl, this.drawPoint.rotate(ic, ia));
return rVec;
}
clone() {
const rVec = new _Vector(this.ca, this.cl, this.drawPoint.clone());
return rVec;
}
// point comparison
isEqual(iVect) {
const [x1, y1] = this.getCartesian();
const [x2, y2] = iVect.getCartesian();
const rb = roundZero(x2 - x1) === 0 && roundZero(y2 - y1) === 0;
return rb;
}
// dot product
dotProduct(iVect) {
const angle = withinPiPi(iVect.ca - this.ca);
return this.cl * iVect.cl * Math.cos(angle);
}
// cross product
crossProduct(iVect) {
const angle = withinPiPi(iVect.ca - this.ca);
return this.cl * iVect.cl * Math.sin(angle);
}
};
function vector(ia, il, iDrawPoint) {
return new Vector(ia, il, iDrawPoint);
}
// src/write_svg.ts
function ff(ifloat) {
return ifloat.toFixed(4);
}
function svgCircleString(cx, cy, radius, color = "") {
let sColor = color;
if (sColor === "") {
sColor = "black";
}
const rSvg = `<circle cx="${ff(cx)}" cy="${ff(cy)}" r="${ff(
radius
)}" stroke="${sColor}" stroke-width="1" fill="none" />`;
return rSvg;
}
var SvgPath = class {
pathD;
constructor() {
this.pathD = "";
}
addStart(px, py) {
this.pathD = `M ${ff(px)} ${ff(py)}`;
}
addStroke(px, py) {
this.pathD += ` L ${ff(px)} ${ff(py)}`;
}
addArc(px, py, radius, large, ccw) {
const aRadius = ff(radius);
const aLarge = large ? 1 : 0;
const aCcw = ccw ? 1 : 0;
this.pathD += ` A ${aRadius} ${aRadius} 0 ${aLarge} ${aCcw} ${ff(px)} ${ff(py)}`;
}
stringify(color = "") {
let sColor = color;
if (sColor === "") {
sColor = "black";
}
const rSvg = `<path d="${this.pathD} Z" stroke="${sColor}" stroke-width="1" fill="none" />`;
return rSvg;
}
};
function svgPath() {
const rSvgPath = new SvgPath();
return rSvgPath;
}
var SvgWriter = class {
svgStr;
payloadStr;
groupActive;
constructor() {
this.payloadStr = "";
this.svgStr = "";
this.groupActive = false;
}
addHeader(xMin, xWidth, yMin, yHeight) {
const viewBoxValues = `${xMin} ${yMin} ${xWidth} ${yHeight}`;
this.svgStr = `<svg width="${xWidth}" height="${yHeight}" viewBox="${viewBoxValues}" xmlns="http://www.w3.org/2000/svg">`;
}
addSvgString(svgString) {
this.payloadStr += svgString;
}
addGroup(groupId) {
if (this.groupActive) {
throw `err321: group must be closed before opening a new one`;
}
this.groupActive = true;
this.payloadStr += `<g id="${groupId}">`;
}
closeGroup() {
if (!this.groupActive) {
throw `err331: group is not active so can not be closed`;
}
this.groupActive = false;
this.payloadStr += `</g>`;
}
closeSvg() {
if (this.svgStr === "") {
throw `err301: no header set for the svg`;
}
if (this.groupActive) {
throw `err311: group is not closed`;
}
this.svgStr += this.payloadStr;
this.svgStr += "</svg>";
}
stringify() {
this.closeSvg();
return this.svgStr;
}
};
function svgWriter() {
const rSvgWrite = new SvgWriter();
return rSvgWrite;
}
// src/write_dxf.ts
function ff2(ifloat) {
return ifloat.toFixed(4);
}
var DxfSeg = class {
arc;
p1x;
p1y;
radius;
a1;
a2;
p2x;
p2y;
constructor(arc, p1x, p1y, radius, a1, a2, p2x, p2y) {
this.arc = arc;
this.p1x = p1x;
this.p1y = p1y;
this.radius = radius;
this.a1 = a1;
this.a2 = a2;
this.p2x = p2x;
this.p2y = p2y;
}
};
function dxfSegLine(p1x, p1y, p2x, p2y) {
const rDxfSeg = new DxfSeg(false, p1x, p1y, 0, 0, 0, p2x, p2y);
return rDxfSeg;
}
function dxfSegArc(p1x, p1y, radius, aa1, aa2, arcCcw) {
const a1 = arcCcw ? aa1 : aa2;
const a2 = arcCcw ? aa2 : aa1;
const b1 = radToDeg(withinZero2Pi(a1));
const b2 = radToDeg(withinZero2Pi(a2));
const rDxfSeg = new DxfSeg(true, p1x, p1y, radius, b1, b2, 0, 0);
return rDxfSeg;
}
function dxfSegCircle(p1x, p1y, radius) {
const rDxfSeg = new DxfSeg(false, p1x, p1y, radius, 0, 0, 0, 0);
return rDxfSeg;
}
var DxfWrite = class {
dxfStr;
constructor() {
this.dxfStr = "0\nSECTION\n2\nENTITIES\n";
}
addCircle(cx, cy, radius) {
this.dxfStr += "0\nCIRCLE\n8\nPARAMETRIX\n";
this.dxfStr += `10
${ff2(cx)}
20
${ff2(cy)}
40
${ff2(radius)}
`;
}
addLine(p1x, p1y, p2x, p2y) {
this.dxfStr += "0\nLINE\n8\nPARAMETRIX\n";
this.dxfStr += `10
${ff2(p1x)}
20
${ff2(p1y)}
11
${ff2(p2x)}
21
${ff2(p2y)}
`;
}
addArc(cx, cy, ra, a1, a2) {
this.dxfStr += "0\nARC\n8\nPARAMETRIX\n";
this.dxfStr += `10
${ff2(cx)}
20
${ff2(cy)}
40
${ff2(ra)}
50
${ff2(a1)}
51
${ff2(
a2
)}
`;
}
close() {
this.dxfStr += "0\nENDSEC\n0\nEOF\n";
}
stringify() {
this.close();
return this.dxfStr;
}
};
function dxfWriter() {
const rDxfWrite = new DxfWrite();
return rDxfWrite;
}
// src/prepare_pax.ts
function ff3(ifloat) {
const rFloat = ifloat;
return rFloat;
}
var PSeg = /* @__PURE__ */ ((PSeg2) => {
PSeg2[PSeg2["eStart"] = 0] = "eStart";
PSeg2[PSeg2["eStroke"] = 1] = "eStroke";
PSeg2[PSeg2["eArc"] = 2] = "eArc";
return PSeg2;
})(PSeg || {});
function paxCircle(cx, cy, radius) {
const rPax = {
circle: true,
cx: ff3(cx),
cy: ff3(cy),
radius: ff3(radius)
};
return rPax;
}
var PaxPath = class {
seg;
constructor() {
this.seg = [];
}
addStart(px, py) {
this.seg = [];
const one = {
typ: 0 /* eStart */,
px,
py
};
this.seg.push(one);
}
addStroke(px, py) {
const one = {
typ: 1 /* eStroke */,
px,
py
};
this.seg.push(one);
}
addArc(cx, cy, radius, large, ccw) {
const one = {
typ: 2 /* eArc */,
px: cx,
py: cy,
radius,
large,
ccw
};
this.seg.push(one);
}
toJson() {
const rPaxC = {
circle: false,
seg: this.seg
};
return rPaxC;
}
};
function paxPath() {
const rPaxPath = new PaxPath();
return rPaxPath;
}
// src/contour.ts
var AContour = class {
};
function midArcPoint(px1, py1, seg, dnb) {
const seg2 = arcSeg1To2(px1, py1, seg);
const p3 = point(seg2.pc.cx, seg2.pc.cy);
const a12h = withinZero2Pi(seg2.a2 - seg2.a1);
const a12g = seg.arcCcw ? a12h : a12h - 2 * Math.PI;
const a12f = a12g / dnb;
const rPts = [];
for (let idx = 1; idx < dnb; idx++) {
rPts.push(p3.translatePolar(seg2.a1 + idx * a12f, seg.radius));
}
return rPts;
}
var Contour = class _Contour extends AContour {
/** @internal */
circle = false;
segments;
points;
debugPoints;
debugLines;
lastPoint;
lastPoint2;
imposedColor;