UNPKG

geometrix

Version:

The 2D geometry engine of the parametrix

1,729 lines (1,718 loc) 143 kB
// 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;