pantograph2d 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"pantograph.js","sources":["../src/algorithms/offsets/offsetSegment.ts","../src/algorithms/filletSegments.ts","../src/draw.ts","../src/utils/listOfFigures.ts","../src/booleanOperations.ts","../src/algorithms/distances/lineLineDistance.ts","../src/algorithms/distances/lineArcDistance.ts","../src/algorithms/distances/arcArcDistance.ts","../src/algorithms/distances/index.ts","../../../node_modules/.pnpm/flatqueue@2.0.3/node_modules/flatqueue/index.js","../../../node_modules/.pnpm/flatbush@4.1.0/node_modules/flatbush/index.js","../src/algorithms/stitchSegments.ts","../src/algorithms/offsets/offsetLoop.ts","../src/algorithms/offsets/offsetFigure.ts","../src/offsetOperations.ts","../src/export/svg/svgSegment.ts","../src/export/svg/svgLoop.ts","../src/export/svg/svgFigure.ts","../src/export/svg/svgDiagram.ts","../src/export/svg/wrapSVG.ts","../src/export/svg/exportSVG.ts","../src/import/json/importJSON.ts","../src/main.ts"],"sourcesContent":["import { Line } from \"../../models/segments/Line\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Segment } from \"../../models/segments/Segment\";\nimport {\n add,\n normalize,\n perpendicular,\n scalarMultiply,\n subtract,\n} from \"../../vectorOperations\";\nimport { Vector } from \"../../definitions\";\n\nexport class DegenerateSegment {\n constructor(\n public readonly firstPoint: Vector,\n public readonly lastPoint: Vector\n ) {}\n}\n\nexport function offsetSegment(\n segment: Segment,\n offset: number\n): Segment | DegenerateSegment {\n if (segment instanceof Line) {\n return offsetLine(segment, offset);\n }\n\n if (segment instanceof Arc) {\n return offsetArc(segment, offset);\n }\n\n throw new Error(\"Not implemented\");\n}\n\nexport function offsetLine(line: Line, offset: number): Line {\n const { firstPoint, lastPoint } = line;\n\n const normal = line.normalVector;\n return new Line(\n add(firstPoint, scalarMultiply(normal, offset)),\n add(lastPoint, scalarMultiply(normal, offset))\n );\n}\n\nexport function offsetArc(arc: Arc, offset: number): Arc | DegenerateSegment {\n const offsetStartPoint = add(\n arc.firstPoint,\n scalarMultiply(perpendicular(arc.tangentAtFirstPoint), offset)\n );\n const offsetEndPoint = add(\n arc.lastPoint,\n scalarMultiply(perpendicular(arc.tangentAtLastPoint), offset)\n );\n\n const orientedOffset = offset * (arc.clockwise ? 1 : -1);\n const newRadius = arc.radius + orientedOffset;\n if (newRadius < arc.precision) {\n return new DegenerateSegment(offsetStartPoint, offsetEndPoint);\n }\n\n return new Arc(offsetStartPoint, offsetEndPoint, arc.center, arc.clockwise);\n}\n","import { Vector } from \"../definitions\";\nimport { Line } from \"../models/segments/Line\";\nimport { tangentArc } from \"../models/segments/Arc\";\nimport type { Segment } from \"../models/segments/Segment\";\nimport {\n add,\n crossProduct,\n perpendicular,\n perpendicularClockwise,\n scalarMultiply,\n} from \"../vectorOperations\";\nimport { findIntersections } from \"./intersections\";\nimport { DegenerateSegment, offsetSegment } from \"./offsets/offsetSegment\";\nimport { exportJSON } from \"../main\";\n\nfunction removeCorner(\n firstSegment: Segment,\n secondSegment: Segment,\n radius: number\n) {\n const sinAngle = crossProduct(\n firstSegment.tangentAtLastPoint,\n secondSegment.tangentAtFirstPoint\n );\n\n // This cover the case when the segments are colinear\n if (Math.abs(sinAngle) < 1e-10) return null;\n\n const orientationCorrection = sinAngle > 0 ? 1 : -1;\n const offset = Math.abs(radius) * orientationCorrection;\n\n const firstOffset = offsetSegment(firstSegment, offset);\n const secondOffset = offsetSegment(secondSegment, offset);\n\n if (\n firstOffset instanceof DegenerateSegment ||\n secondOffset instanceof DegenerateSegment\n ) {\n return null;\n }\n\n let potentialCenter: Vector | undefined;\n try {\n const intersections = findIntersections(firstOffset, secondOffset, 1e-9);\n\n // We need to work on the case where there are more than one intersections\n potentialCenter = intersections.at(-1);\n } catch (e) {\n return null;\n }\n\n if (!potentialCenter) {\n return null;\n }\n const center = potentialCenter;\n\n const splitForFillet = (segment: Segment, offsetSegment: Segment) => {\n const tgt = offsetSegment.tangentAt(center);\n const normal = perpendicularClockwise(tgt);\n const splitPoint = add(center, scalarMultiply(normal, offset));\n return segment.splitAt(splitPoint);\n };\n\n const [first] = splitForFillet(firstSegment, firstOffset);\n const [, second] = splitForFillet(secondSegment, secondOffset);\n\n return { first, second, center };\n}\n\nexport function filletSegments(\n firstSegment: Segment,\n secondSegment: Segment,\n radius: number\n) {\n const cornerRemoved = removeCorner(firstSegment, secondSegment, radius);\n if (!cornerRemoved) {\n console.warn(\n \"Cannot fillet between segments\",\n firstSegment.repr,\n secondSegment.repr\n );\n return [firstSegment, secondSegment];\n }\n\n const { first, second } = cornerRemoved;\n\n return [\n first,\n tangentArc(first.lastPoint, second.firstPoint, first.tangentAtLastPoint),\n second,\n ];\n}\n\nexport function chamferSegments(\n firstSegment: Segment,\n secondSegment: Segment,\n radius: number\n) {\n const cornerRemoved = removeCorner(firstSegment, secondSegment, radius);\n if (!cornerRemoved) {\n console.warn(\n \"Cannot chamfer between segments\",\n firstSegment.repr,\n secondSegment.repr\n );\n return [firstSegment, secondSegment];\n }\n\n const { first, second } = cornerRemoved;\n\n return [first, new Line(first.lastPoint, second.firstPoint), second];\n}\n","import { chamferSegments, filletSegments } from \"./algorithms/filletSegments\";\nimport { Vector } from \"./definitions\";\nimport { Diagram } from \"./models/Diagram\";\nimport { Figure } from \"./models/Figure\";\nimport { Loop } from \"./models/Loop\";\nimport { tangentArc, threePointsArc } from \"./models/segments/Arc\";\nimport { Line } from \"./models/segments/Line\";\nimport { Segment } from \"./models/segments/Segment\";\nimport { TransformationMatrix } from \"./models/TransformationMatrix\";\nimport {\n polarToCartesian,\n DEG2RAD,\n subtract,\n sameVector,\n perpendicular,\n add,\n scalarMultiply,\n distance,\n} from \"./vectorOperations\";\n\nfunction loopySegmentsToDiagram(segments: Segment[]) {\n // Here we will need to do our best to fix cases where the drawing is\n // broken in some way (i.e. self-intersecting loops)\n\n return new Diagram([new Figure(new Loop(segments))]);\n}\n\nexport class DrawingPen {\n protected pointer: Vector;\n protected firstPoint: Vector;\n protected pendingSegments: Segment[];\n\n protected _nextCorner: { radius: number; mode: \"fillet\" | \"chamfer\" } | null;\n\n constructor(origin: Vector = [0, 0]) {\n this.pointer = origin;\n this.firstPoint = origin;\n\n this.pendingSegments = [];\n this._nextCorner = null;\n }\n\n movePointerTo(point: Vector): this {\n if (this.pendingSegments.length)\n throw new Error(\n \"You can only move the pointer if there is no segment defined\"\n );\n\n this.pointer = point;\n this.firstPoint = point;\n return this;\n }\n\n protected saveSegment(segment: Segment) {\n if (sameVector(segment.firstPoint, segment.lastPoint)) {\n throw new Error(`Segment has no length, ${segment.repr}`);\n }\n\n if (!this._nextCorner) {\n this.pendingSegments.push(segment);\n return this;\n }\n\n const previousSegment = this.pendingSegments.pop();\n if (!previousSegment) throw new Error(\"bug in the custom corner algorithm\");\n\n const makeCorner =\n this._nextCorner.mode === \"chamfer\" ? chamferSegments : filletSegments;\n\n this.pendingSegments.push(\n ...makeCorner(previousSegment, segment, this._nextCorner.radius)\n );\n this._nextCorner = null;\n return this;\n }\n\n lineTo(point: Vector): this {\n const segment = new Line(this.pointer, point);\n this.pointer = point;\n return this.saveSegment(segment);\n }\n\n line(xDist: number, yDist: number): this {\n return this.lineTo([this.pointer[0] + xDist, this.pointer[1] + yDist]);\n }\n\n vLine(distance: number): this {\n return this.line(0, distance);\n }\n\n hLine(distance: number): this {\n return this.line(distance, 0);\n }\n\n vLineTo(yPos: number): this {\n return this.lineTo([this.pointer[0], yPos]);\n }\n\n hLineTo(xPos: number): this {\n return this.lineTo([xPos, this.pointer[1]]);\n }\n\n polarLineTo([r, theta]: Vector): this {\n const angleInRads = theta * DEG2RAD;\n const point = polarToCartesian(r, angleInRads);\n return this.lineTo(point);\n }\n\n polarLine(distance: number, angle: number): this {\n const angleInRads = angle * DEG2RAD;\n const [x, y] = polarToCartesian(distance, angleInRads);\n return this.line(x, y);\n }\n\n tangentLine(distance: number): this {\n const previousCurve = this.pendingSegments.at(-1);\n\n if (!previousCurve)\n throw new Error(\"You need a previous segment to sketch a tangent line\");\n\n const [xDir, yDir] = previousCurve.tangentAtLastPoint;\n return this.line(xDir * distance, yDir * distance);\n }\n\n threePointsArcTo(end: Vector, midPoint: Vector): this {\n this.saveSegment(threePointsArc(this.pointer, midPoint, end));\n this.pointer = end;\n return this;\n }\n\n threePointsArc(\n xDist: number,\n yDist: number,\n viaXDist: number,\n viaYDist: number\n ): this {\n const [x0, y0] = this.pointer;\n return this.threePointsArcTo(\n [x0 + xDist, y0 + yDist],\n [x0 + viaXDist, y0 + viaYDist]\n );\n }\n\n sagittaArcTo(end: Vector, sagitta: number): this {\n if (!sagitta) return this.lineTo(end);\n const chord = new Line(this.pointer, end);\n const norm = perpendicular(chord.tangentAtFirstPoint);\n\n const sagPoint: Vector = add(chord.midPoint, scalarMultiply(norm, sagitta));\n\n return this.threePointsArcTo(end, sagPoint);\n }\n\n sagittaArc(xDist: number, yDist: number, sagitta: number): this {\n return this.sagittaArcTo(\n [xDist + this.pointer[0], yDist + this.pointer[1]],\n sagitta\n );\n }\n\n vSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(0, distance, sagitta);\n }\n\n hSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(distance, 0, sagitta);\n }\n\n bulgeArcTo(end: Vector, bulge: number): this {\n if (!bulge) return this.lineTo(end);\n const halfChord = distance(this.pointer, end) / 2;\n const bulgeAsSagitta = -bulge * halfChord;\n\n return this.sagittaArcTo(end, bulgeAsSagitta);\n }\n\n bulgeArc(xDist: number, yDist: number, bulge: number): this {\n return this.bulgeArcTo(\n [xDist + this.pointer[0], yDist + this.pointer[1]],\n bulge\n );\n }\n\n vBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(0, distance, bulge);\n }\n\n hBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(distance, 0, bulge);\n }\n\n tangentArcTo(end: Vector): this {\n const previousCurve = this.pendingSegments.at(-1);\n\n if (!previousCurve)\n throw new Error(\"You need a previous curve to sketch a tangent arc\");\n\n this.saveSegment(\n tangentArc(this.pointer, end, previousCurve.tangentAtLastPoint)\n );\n\n this.pointer = end;\n return this;\n }\n\n tangentArc(xDist: number, yDist: number): this {\n const [x0, y0] = this.pointer;\n return this.tangentArcTo([xDist + x0, yDist + y0]);\n }\n\n customCorner(radius: number, mode: \"fillet\" | \"chamfer\" = \"fillet\") {\n if (!this.pendingSegments.length)\n throw new Error(\"You need a segment defined to fillet the angle\");\n\n this._nextCorner = { mode, radius };\n return this;\n }\n\n protected _customCornerLastWithFirst(\n radius: number,\n mode: \"fillet\" | \"chamfer\" = \"fillet\"\n ) {\n if (!radius) return;\n\n const lastSegment = this.pendingSegments.pop();\n const firstSegment = this.pendingSegments.shift();\n\n if (!lastSegment || !firstSegment)\n throw new Error(\"Not enough curves to close and fillet\");\n\n const makeCorner = mode === \"chamfer\" ? chamferSegments : filletSegments;\n\n this.pendingSegments.push(...makeCorner(lastSegment, firstSegment, radius));\n }\n\n close(): Diagram {\n if (!this.pendingSegments.length) throw new Error(\"No segments to close\");\n const firstSegment = this.pendingSegments[0];\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const lastSegment = this.pendingSegments.at(-1)!;\n\n if (!sameVector(firstSegment.firstPoint, lastSegment.lastPoint)) {\n this.lineTo(firstSegment.firstPoint);\n }\n\n if (this._nextCorner !== null) {\n this._customCornerLastWithFirst(\n this._nextCorner.radius,\n this._nextCorner.mode\n );\n this._nextCorner = null;\n }\n\n return loopySegmentsToDiagram(this.pendingSegments);\n }\n\n closeWithMirror(): Diagram {\n if (!this.pendingSegments.length) throw new Error(\"No segments to close\");\n\n const firstSegment = this.pendingSegments[0];\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const lastSegment = this.pendingSegments.at(-1)!;\n\n const mirrorVector = subtract(\n lastSegment.lastPoint,\n firstSegment.firstPoint\n );\n const mirrorTranform = new TransformationMatrix().mirrorLine(\n mirrorVector,\n firstSegment.firstPoint\n );\n\n const mirroredSegments = this.pendingSegments.map((segment) =>\n segment.transform(mirrorTranform).reverse()\n );\n mirroredSegments.reverse();\n\n return loopySegmentsToDiagram([\n ...this.pendingSegments,\n ...mirroredSegments,\n ]);\n }\n}\n\nexport function draw(origin: Vector = [0, 0]): DrawingPen {\n return new DrawingPen(origin);\n}\n","import { Diagram } from \"../models/Diagram\";\nimport { Figure } from \"../models/Figure\";\nimport { Loop } from \"../models/Loop\";\n\nexport function listOfFigures(shape: Diagram | Figure | Loop): Figure[] {\n if (shape instanceof Figure) {\n return [shape];\n } else if (shape instanceof Loop) {\n return [new Figure(shape)];\n } else if (shape instanceof Diagram) {\n return shape.figures;\n }\n throw new Error(\"Unknown shape\");\n}\n","import {\n cutFiguresLists,\n fuseFiguresLists,\n intersectFiguresLists,\n} from \"./algorithms/boolean/figureBooleans\";\nimport { Diagram } from \"./models/Diagram\";\nimport { Figure } from \"./models/Figure\";\nimport { Loop } from \"./models/Loop\";\nimport { listOfFigures } from \"./utils/listOfFigures\";\n\nexport function fuse(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n fuseFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n\nexport function fuseAll(shapes: (Diagram | Figure | Loop)[]): Diagram {\n return shapes.reduce(\n (acc: Diagram, shape: Diagram | Figure | Loop) => fuse(acc, shape),\n new Diagram()\n );\n}\n\nexport function cut(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n cutFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n\nexport function intersect(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n intersectFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n","import { lineLineParams } from \"../intersections/lineLineIntersection\";\nimport type { Line } from \"../../models/segments/Line\";\nimport { distance } from \"../../vectorOperations\";\n\nfunction segmentPosition(intersectionParam: number) {\n if (intersectionParam < 0) return \"before\";\n if (intersectionParam > 1) return \"after\";\n return \"between\";\n}\n\nconst handleBetween = (\n lineBetween: Line,\n otherLine: Line,\n otherPosition: \"before\" | \"after\"\n) => {\n if (otherPosition === \"before\")\n return lineBetween.distanceFrom(otherLine.firstPoint);\n else if (otherPosition === \"after\")\n return lineBetween.distanceFrom(otherLine.lastPoint);\n else throw new Error(\"Invalid position\");\n};\n\nexport function lineLineDistance(line1: Line, line2: Line): number {\n const intersectionParams = lineLineParams(line1, line2);\n\n if (intersectionParams === \"parallel\") {\n return Math.min(\n line1.distanceFrom(line2.firstPoint),\n line1.distanceFrom(line2.lastPoint)\n );\n }\n\n const { intersectionParam1, intersectionParam2 } = intersectionParams;\n\n const firstPosition = segmentPosition(intersectionParam1);\n const secondPosition = segmentPosition(intersectionParam2);\n\n if (firstPosition === \"between\" && secondPosition === \"between\") {\n return 0;\n } else if (firstPosition === \"between\" && secondPosition !== \"between\") {\n return handleBetween(line1, line2, secondPosition);\n } else if (secondPosition === \"between\" && firstPosition !== \"between\") {\n return handleBetween(line2, line1, firstPosition);\n } else if (firstPosition === \"before\" && secondPosition === \"before\") {\n return distance(line1.firstPoint, line2.firstPoint);\n } else if (firstPosition === \"after\" && secondPosition === \"after\") {\n return distance(line1.lastPoint, line2.lastPoint);\n } else if (firstPosition === \"before\" && secondPosition === \"after\") {\n return distance(line1.firstPoint, line2.lastPoint);\n } else if (firstPosition === \"after\" && secondPosition === \"before\") {\n return distance(line1.lastPoint, line2.firstPoint);\n } else {\n throw new Error(\"Invalid position\");\n }\n}\n","import type { Line } from \"../../models/segments/Line\";\nimport type { Arc } from \"../../models/segments/Arc\";\nimport {\n normalize,\n subtract,\n distance,\n add,\n scalarMultiply,\n} from \"../../vectorOperations\";\nimport { projectPointOnLine } from \"../../utils/projectPointOnLine\";\nimport { lineArcIntersection } from \"../intersections/lineArcIntersection\";\n\nexport function lineArcDistance(line: Line, arc: Arc): number {\n // We might be able to optimise this if necessary\n\n if (lineArcIntersection(line, arc).length > 0) {\n return 0;\n }\n\n const closestPointOnLine = projectPointOnLine(line, arc.center);\n\n if (line.isOnSegment(closestPointOnLine)) {\n const circleCenterLineDistance = distance(closestPointOnLine, arc.center);\n\n // The line is tangent to the circle\n if (Math.abs(circleCenterLineDistance - arc.radius) < line.precision) {\n if (arc.isOnSegment(closestPointOnLine)) {\n return 0;\n }\n }\n\n if (circleCenterLineDistance - arc.radius > line.precision) {\n const centerLineDirection = normalize(\n subtract(closestPointOnLine, arc.center)\n );\n\n const closestPointOnCircle = add(\n arc.center,\n scalarMultiply(centerLineDirection, arc.radius)\n );\n\n if (arc.isOnSegment(closestPointOnCircle)) {\n return distance(closestPointOnCircle, closestPointOnLine);\n }\n }\n }\n\n return Math.min(\n arc.distanceFrom(line.firstPoint),\n arc.distanceFrom(line.lastPoint),\n line.distanceFrom(arc.firstPoint),\n line.distanceFrom(arc.lastPoint)\n );\n}\n","import {\n distance,\n normalize,\n polarAngle,\n subtract,\n} from \"../../vectorOperations\";\nimport type { Arc } from \"../../models/segments/Arc\";\nimport { arcArcIntersection } from \"../intersections/arcArcIntersection\";\n\nconst overlappingAngles = (arc1: Arc, arc2: Arc): boolean => {\n const p1 = arc1.angleToParam(arc2.firstAngle);\n if (arc1.isValidParameter(p1)) return true;\n\n const p2 = arc1.angleToParam(arc2.lastAngle);\n if (arc1.isValidParameter(p2)) return true;\n return false;\n};\n\nexport function arcArcDistance(arc1: Arc, arc2: Arc): number {\n if (arcArcIntersection(arc1, arc2, true).length > 0) return 0;\n\n const centersDistance = distance(arc1.center, arc2.center);\n\n if (centersDistance < arc1.precision) {\n if (overlappingAngles(arc1, arc2)) {\n return Math.abs(arc1.radius - arc2.radius);\n }\n }\n\n const centerCenterDirection = normalize(subtract(arc2.center, arc1.center));\n\n const containedCircles =\n centersDistance - Math.abs(arc1.radius - arc2.radius) < arc1.precision;\n\n let arc1ClosestPointAngle = polarAngle(centerCenterDirection);\n if (containedCircles && arc2.radius > arc1.radius) {\n arc1ClosestPointAngle += Math.PI;\n }\n const arc2ClosestPointAngle = containedCircles\n ? arc1ClosestPointAngle\n : arc1ClosestPointAngle + Math.PI;\n\n const p1 = arc1.angleToParam(arc1ClosestPointAngle);\n const p2 = arc2.angleToParam(arc2ClosestPointAngle);\n\n if (arc1.isValidParameter(p1) && arc2.isValidParameter(p2)) {\n // There might be some optimization here (with the center distance and radius differences)\n return distance(arc1.paramPoint(p1), arc2.paramPoint(p2));\n }\n\n return Math.min(\n arc1.distanceFrom(arc2.firstPoint),\n arc1.distanceFrom(arc2.lastPoint),\n arc2.distanceFrom(arc1.firstPoint),\n arc2.distanceFrom(arc1.lastPoint)\n );\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { lineLineDistance } from \"./lineLineDistance\";\nimport { lineArcDistance } from \"./lineArcDistance\";\nimport { arcArcDistance } from \"./arcArcDistance\";\nimport type { Segment } from \"../../models/segments/Segment\";\n\nexport function distance(segment1: Segment, segment2: Segment): number {\n if (segment1 instanceof Line && segment2 instanceof Line) {\n return lineLineDistance(segment1, segment2);\n }\n\n if (segment1 instanceof Line && segment2 instanceof Arc) {\n return lineArcDistance(segment1, segment2);\n }\n\n if (segment1 instanceof Arc && segment2 instanceof Line) {\n return lineArcDistance(segment2, segment1);\n }\n\n if (segment1 instanceof Arc && segment2 instanceof Arc) {\n return arcArcDistance(segment1, segment2);\n }\n\n throw new Error(\"Not implemented\");\n}\n","\nexport default class FlatQueue {\n\n constructor() {\n this.ids = [];\n this.values = [];\n this.length = 0;\n }\n\n clear() {\n this.length = 0;\n }\n\n push(id, value) {\n let pos = this.length++;\n\n while (pos > 0) {\n const parent = (pos - 1) >> 1;\n const parentValue = this.values[parent];\n if (value >= parentValue) break;\n this.ids[pos] = this.ids[parent];\n this.values[pos] = parentValue;\n pos = parent;\n }\n\n this.ids[pos] = id;\n this.values[pos] = value;\n }\n\n pop() {\n if (this.length === 0) return undefined;\n\n const top = this.ids[0];\n this.length--;\n\n if (this.length > 0) {\n const id = this.ids[0] = this.ids[this.length];\n const value = this.values[0] = this.values[this.length];\n const halfLength = this.length >> 1;\n let pos = 0;\n\n while (pos < halfLength) {\n let left = (pos << 1) + 1;\n const right = left + 1;\n let bestIndex = this.ids[left];\n let bestValue = this.values[left];\n const rightValue = this.values[right];\n\n if (right < this.length && rightValue < bestValue) {\n left = right;\n bestIndex = this.ids[right];\n bestValue = rightValue;\n }\n if (bestValue >= value) break;\n\n this.ids[pos] = bestIndex;\n this.values[pos] = bestValue;\n pos = left;\n }\n\n this.ids[pos] = id;\n this.values[pos] = value;\n }\n\n return top;\n }\n\n peek() {\n if (this.length === 0) return undefined;\n return this.ids[0];\n }\n\n peekValue() {\n if (this.length === 0) return undefined;\n return this.values[0];\n }\n\n shrink() {\n this.ids.length = this.values.length = this.length;\n }\n}\n","import FlatQueue from 'flatqueue';\n\nconst ARRAY_TYPES = [\n Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array,\n Int32Array, Uint32Array, Float32Array, Float64Array\n];\n\nconst VERSION = 3; // serialized format version\n\nexport default class Flatbush {\n\n static from(data) {\n if (!data || data.byteLength === undefined || data.buffer) {\n throw new Error('Data must be an instance of ArrayBuffer or SharedArrayBuffer.');\n }\n const [magic, versionAndType] = new Uint8Array(data, 0, 2);\n if (magic !== 0xfb) {\n throw new Error('Data does not appear to be in a Flatbush format.');\n }\n if (versionAndType >> 4 !== VERSION) {\n throw new Error(`Got v${versionAndType >> 4} data when expected v${VERSION}.`);\n }\n const [nodeSize] = new Uint16Array(data, 2, 1);\n const [numItems] = new Uint32Array(data, 4, 1);\n\n return new Flatbush(numItems, nodeSize, ARRAY_TYPES[versionAndType & 0x0f], undefined, data);\n }\n\n constructor(numItems, nodeSize = 16, ArrayType = Float64Array, ArrayBufferType = ArrayBuffer, data) {\n if (numItems === undefined) throw new Error('Missing required argument: numItems.');\n if (isNaN(numItems) || numItems <= 0) throw new Error(`Unexpected numItems value: ${numItems}.`);\n\n this.numItems = +numItems;\n this.nodeSize = Math.min(Math.max(+nodeSize, 2), 65535);\n\n // calculate the total number of nodes in the R-tree to allocate space for\n // and the index of each tree level (used in search later)\n let n = numItems;\n let numNodes = n;\n this._levelBounds = [n * 4];\n do {\n n = Math.ceil(n / this.nodeSize);\n numNodes += n;\n this._levelBounds.push(numNodes * 4);\n } while (n !== 1);\n\n this.ArrayType = ArrayType || Float64Array;\n this.IndexArrayType = numNodes < 16384 ? Uint16Array : Uint32Array;\n\n const arrayTypeIndex = ARRAY_TYPES.indexOf(this.ArrayType);\n const nodesByteSize = numNodes * 4 * this.ArrayType.BYTES_PER_ELEMENT;\n\n if (arrayTypeIndex < 0) {\n throw new Error(`Unexpected typed array class: ${ArrayType}.`);\n }\n\n if (data && data.byteLength !== undefined && !data.buffer) {\n this.data = data;\n this._boxes = new this.ArrayType(this.data, 8, numNodes * 4);\n this._indices = new this.IndexArrayType(this.data, 8 + nodesByteSize, numNodes);\n\n this._pos = numNodes * 4;\n this.minX = this._boxes[this._pos - 4];\n this.minY = this._boxes[this._pos - 3];\n this.maxX = this._boxes[this._pos - 2];\n this.maxY = this._boxes[this._pos - 1];\n\n } else {\n this.data = new ArrayBufferType(8 + nodesByteSize + numNodes * this.IndexArrayType.BYTES_PER_ELEMENT);\n this._boxes = new this.ArrayType(this.data, 8, numNodes * 4);\n this._indices = new this.IndexArrayType(this.data, 8 + nodesByteSize, numNodes);\n this._pos = 0;\n this.minX = Infinity;\n this.minY = Infinity;\n this.maxX = -Infinity;\n this.maxY = -Infinity;\n\n new Uint8Array(this.data, 0, 2).set([0xfb, (VERSION << 4) + arrayTypeIndex]);\n new Uint16Array(this.data, 2, 1)[0] = nodeSize;\n new Uint32Array(this.data, 4, 1)[0] = numItems;\n }\n\n // a priority queue for k-nearest-neighbors queries\n this._queue = new FlatQueue();\n }\n\n add(minX, minY, maxX, maxY) {\n const index = this._pos >> 2;\n const boxes = this._boxes;\n this._indices[index] = index;\n boxes[this._pos++] = minX;\n boxes[this._pos++] = minY;\n boxes[this._pos++] = maxX;\n boxes[this._pos++] = maxY;\n\n if (minX < this.minX) this.minX = minX;\n if (minY < this.minY) this.minY = minY;\n if (maxX > this.maxX) this.maxX = maxX;\n if (maxY > this.maxY) this.maxY = maxY;\n\n return index;\n }\n\n finish() {\n if (this._pos >> 2 !== this.numItems) {\n throw new Error(`Added ${this._pos >> 2} items when expected ${this.numItems}.`);\n }\n const boxes = this._boxes;\n\n if (this.numItems <= this.nodeSize) {\n // only one node, skip sorting and just fill the root box\n boxes[this._pos++] = this.minX;\n boxes[this._pos++] = this.minY;\n boxes[this._pos++] = this.maxX;\n boxes[this._pos++] = this.maxY;\n return;\n }\n\n const width = (this.maxX - this.minX) || 1;\n const height = (this.maxY - this.minY) || 1;\n const hilbertValues = new Uint32Array(this.numItems);\n const hilbertMax = (1 << 16) - 1;\n\n // map item centers into Hilbert coordinate space and calculate Hilbert values\n for (let i = 0, pos = 0; i < this.numItems; i++) {\n const minX = boxes[pos++];\n const minY = boxes[pos++];\n const maxX = boxes[pos++];\n const maxY = boxes[pos++];\n const x = Math.floor(hilbertMax * ((minX + maxX) / 2 - this.minX) / width);\n const y = Math.floor(hilbertMax * ((minY + maxY) / 2 - this.minY) / height);\n hilbertValues[i] = hilbert(x, y);\n }\n\n // sort items by their Hilbert value (for packing later)\n sort(hilbertValues, boxes, this._indices, 0, this.numItems - 1, this.nodeSize);\n\n // generate nodes at each tree level, bottom-up\n for (let i = 0, pos = 0; i < this._levelBounds.length - 1; i++) {\n const end = this._levelBounds[i];\n\n // generate a parent node for each block of consecutive <nodeSize> nodes\n while (pos < end) {\n const nodeIndex = pos;\n\n // calculate bbox for the new node\n let nodeMinX = boxes[pos++];\n let nodeMinY = boxes[pos++];\n let nodeMaxX = boxes[pos++];\n let nodeMaxY = boxes[pos++];\n for (let j = 1; j < this.nodeSize && pos < end; j++) {\n nodeMinX = Math.min(nodeMinX, boxes[pos++]);\n nodeMinY = Math.min(nodeMinY, boxes[pos++]);\n nodeMaxX = Math.max(nodeMaxX, boxes[pos++]);\n nodeMaxY = Math.max(nodeMaxY, boxes[pos++]);\n }\n\n // add the new node to the tree data\n this._indices[this._pos >> 2] = nodeIndex;\n boxes[this._pos++] = nodeMinX;\n boxes[this._pos++] = nodeMinY;\n boxes[this._pos++] = nodeMaxX;\n boxes[this._pos++] = nodeMaxY;\n }\n }\n }\n\n search(minX, minY, maxX, maxY, filterFn) {\n if (this._pos !== this._boxes.length) {\n throw new Error('Data not yet indexed - call index.finish().');\n }\n\n let nodeIndex = this._boxes.length - 4;\n const queue = [];\n const results = [];\n\n while (nodeIndex !== undefined) {\n // find the end index of the node\n const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));\n\n // search through child nodes\n for (let pos = nodeIndex; pos < end; pos += 4) {\n // check if node bbox intersects with query bbox\n if (maxX < this._boxes[pos]) continue; // maxX < nodeMinX\n if (maxY < this._boxes[pos + 1]) continue; // maxY < nodeMinY\n if (minX > this._boxes[pos + 2]) continue; // minX > nodeMaxX\n if (minY > this._boxes[pos + 3]) continue; // minY > nodeMaxY\n\n const index = this._indices[pos >> 2] | 0;\n\n if (nodeIndex >= this.numItems * 4) {\n queue.push(index); // node; add it to the search queue\n\n } else if (filterFn === undefined || filterFn(index)) {\n results.push(index); // leaf item\n }\n }\n\n nodeIndex = queue.pop();\n }\n\n return results;\n }\n\n neighbors(x, y, maxResults = Infinity, maxDistance = Infinity, filterFn) {\n if (this._pos !== this._boxes.length) {\n throw new Error('Data not yet indexed - call index.finish().');\n }\n\n let nodeIndex = this._boxes.length - 4;\n const q = this._queue;\n const results = [];\n const maxDistSquared = maxDistance * maxDistance;\n\n while (nodeIndex !== undefined) {\n // find the end index of the node\n const end = Math.min(nodeIndex + this.nodeSize * 4, upperBound(nodeIndex, this._levelBounds));\n\n // add child nodes to the queue\n for (let pos = nodeIndex; pos < end; pos += 4) {\n const index = this._indices[pos >> 2] | 0;\n\n const dx = axisDist(x, this._boxes[pos], this._boxes[pos + 2]);\n const dy = axisDist(y, this._boxes[pos + 1], this._boxes[pos + 3]);\n const dist = dx * dx + dy * dy;\n\n if (nodeIndex >= this.numItems * 4) {\n q.push(index << 1, dist); // node (use even id)\n\n } else if (filterFn === undefined || filterFn(index)) {\n q.push((index << 1) + 1, dist); // leaf item (use odd id)\n }\n }\n\n // pop items from the queue\n while (q.length && (q.peek() & 1)) {\n const dist = q.peekValue();\n if (dist > maxDistSquared) {\n q.clear();\n return results;\n }\n results.push(q.pop() >> 1);\n\n if (results.length === maxResults) {\n q.clear();\n return results;\n }\n }\n\n nodeIndex = q.pop() >> 1;\n }\n\n q.clear();\n return results;\n }\n}\n\nfunction axisDist(k, min, max) {\n return k < min ? min - k : k <= max ? 0 : k - max;\n}\n\n// binary search for the first value in the array bigger than the given\nfunction upperBound(value, arr) {\n let i = 0;\n let j = arr.length - 1;\n while (i < j) {\n const m = (i + j) >> 1;\n if (arr[m] > value) {\n j = m;\n } else {\n i = m + 1;\n }\n }\n return arr[i];\n}\n\n// custom quicksort that partially sorts bbox data alongside the hilbert values\nfunction sort(values, boxes, indices, left, right, nodeSize) {\n if (Math.floor(left / nodeSize) >= Math.floor(right / nodeSize)) return;\n\n const pivot = values[(left + right) >> 1];\n let i = left - 1;\n let j = right + 1;\n\n while (true) {\n do i++; while (values[i] < pivot);\n do j--; while (values[j] > pivot);\n if (i >= j) break;\n swap(values, boxes, indices, i, j);\n }\n\n sort(values, boxes, indices, left, j, nodeSize);\n sort(values, boxes, indices, j + 1, right, nodeSize);\n}\n\n// swap two values and two corresponding boxes\nfunction swap(values, boxes, indices, i, j) {\n const temp = values[i];\n values[i] = values[j];\n values[j] = temp;\n\n const k = 4 * i;\n const m = 4 * j;\n\n const a = boxes[k];\n const b = boxes[k + 1];\n const c = boxes[k + 2];\n const d = boxes[k + 3];\n boxes[k] = boxes[m];\n boxes[k + 1] = boxes[m + 1];\n boxes[k + 2] = boxes[m + 2];\n boxes[k + 3] = boxes[m + 3];\n boxes[m] = a;\n boxes[m + 1] = b;\n boxes[m + 2] = c;\n boxes[m + 3] = d;\n\n const e = indices[i];\n indices[i] = indices[j];\n indices[j] = e;\n}\n\n// Fast Hilbert curve algorithm by http://threadlocalmutex.com/\n// Ported from C++ https://github.com/rawrunprotected/hilbert_curves (public domain)\nfunction hilbert(x, y) {\n let a = x ^ y;\n let b = 0xFFFF ^ a;\n let c = 0xFFFF ^ (x | y);\n let d = x & (y ^ 0xFFFF);\n\n let A = a | (b >> 1);\n let B = (a >> 1) ^ a;\n let C = ((c >> 1) ^ (b & (d >> 1))) ^ c;\n let D = ((a & (c >> 1)) ^ (d >> 1)) ^ d;\n\n a = A; b = B; c = C; d = D;\n A = ((a & (a >> 2)) ^ (b & (b >> 2)));\n B = ((a & (b >> 2)) ^ (b & ((a ^ b) >> 2)));\n C ^= ((a & (c >> 2)) ^ (b & (d >> 2)));\n D ^= ((b & (c >> 2)) ^ ((a ^ b) & (d >> 2)));\n\n a = A; b = B; c = C; d = D;\n A = ((a & (a >> 4)) ^ (b & (b >> 4)));\n B = ((a & (b >> 4)) ^ (b & ((a ^ b) >> 4)));\n C ^= ((a & (c >> 4)) ^ (b & (d >> 4)));\n D ^= ((b & (c >> 4)) ^ ((a ^ b) & (d >> 4)));\n\n a = A; b = B; c = C; d = D;\n C ^= ((a & (c >> 8)) ^ (b & (d >> 8)));\n D ^= ((b & (c >> 8)) ^ ((a ^ b) & (d >> 8)));\n\n a = C ^ (C >> 1);\n b = D ^ (D >> 1);\n\n let i0 = x ^ y;\n let i1 = b | (0xFFFF ^ (i0 | a));\n\n i0 = (i0 | (i0 << 8)) & 0x00FF00FF;\n i0 = (i0 | (i0 << 4)) & 0x0F0F0F0F;\n i0 = (i0 | (i0 << 2)) & 0x33333333;\n i0 = (i0 | (i0 << 1)) & 0x55555555;\n\n i1 = (i1 | (i1 << 8)) & 0x00FF00FF;\n i1 = (i1 | (i1 << 4)) & 0x0F0F0F0F;\n i1 = (i1 | (i1 << 2)) & 0x33333333;\n i1 = (i1 | (i1 << 1)) & 0x55555555;\n\n return ((i1 << 1) | i0) >>> 0;\n}\n","import Flatbush from \"flatbush\";\nimport { Segment } from \"../models/segments/Segment\";\n\nexport function stitchSegments(\n segments: Segment[],\n precision = 1e-7\n): Segment[][] {\n // We create a spacial index of the startpoints\n const startPoints = new Flatbush(segments.length);\n segments.forEach((c) => {\n const [x, y] = c.firstPoint;\n startPoints.add(x - precision, y - precision, x + precision, y + precision);\n });\n startPoints.finish();\n\n const stitchedSegments: Segment[][] = [];\n const visited = new Set<number>();\n\n segments.forEach((segment, index) => {\n if (visited.has(index)) return;\n\n const connectedSegments: Segment[] = [segment];\n let currentIndex = index;\n\n visited.add(index);\n\n // Once we have started a connected segment segment, we look for the next\n\n let maxLoops = segments.length;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n if (maxLoops-- < 0) {\n throw new Error(\"Infinite loop detected\");\n }\n\n const lastPoint =\n connectedSegments[connectedSegments.length - 1].lastPoint;\n\n const [x, y] = lastPoint;\n const neighbors = startPoints.search(\n x - precision,\n y - precision,\n x + precision,\n y + precision\n );\n\n const indexDistance = (otherIndex: number) =>\n Math.abs((currentIndex - otherIndex) % segments.length);\n const potentialNextSegments = neighbors\n .filter((neighborIndex) => !visited.has(neighborIndex))\n .map((neighborIndex): [Segment, number, number] => [\n segments[neighborIndex],\n neighborIndex,\n indexDistance(neighborIndex),\n ])\n .sort(([, , a], [, , b]) => indexDistance(a) - indexDistance(b));\n\n if (potentialNextSegments.length === 0) {\n // No more segments to connect we should have wrapped\n stitchedSegments.push(connectedSegments);\n break;\n }\n\n const [nextSegment, nextSegmentIndex] = potentialNextSegments[0];\n\n connectedSegments.push(nextSegment);\n visited.add(nextSegmentIndex);\n currentIndex = nextSegmentIndex;\n }\n });\n\n return stitchedSegments;\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Loop } from \"../../models/Loop\";\nimport { Segment } from \"../../models/segments/Segment\";\nimport {\n crossProduct,\n sameVector,\n squareDistance,\n subtract,\n} from \"../../vectorOperations\";\nimport { distance } from \"../distances\";\nimport { offsetSegment, DegenerateSegment } from \"./offsetSegment\";\nimport { Vector } from \"../../definitions\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Diagram } from \"../../models/Diagram\";\nimport { findIntersectionsAndOverlaps } from \"../intersections\";\nimport { Figure } from \"../../models/Figure\";\nimport { stitchSegments } from \"../stitchSegments\";\n\nconst PRECISION = 1e-8;\n\nexport function rawOffsets(\n segmentsToOffset: Segment[],\n offset: number\n): Segment[] {\n const offsetSegments: OffsetSegmentPair[] = segmentsToOffset.map((c) => ({\n offset: offsetSegment(c, offset),\n original: c,\n }));\n\n // Ideally we would use the length of the segment to make sure it is\n // not only a point, but the algo we have access to are a bit to\n // convoluted to be usable here\n\n const offsettedArray: Segment[] = [];\n\n let savedLastSegment: null | OffsetSegmentPair = null;\n\n let previousSegment = offsetSegments.at(-1);\n\n // We have no offseted segments\n if (!previousSegment) return [];\n if (offsettedArray.length === 1) return offsettedArray;\n\n const appendSegment = (segment: OffsetSegmentPair) => {\n if (!savedLastSegment) {\n savedLastSegment = segment;\n } else if (!(segment.offset instanceof DegenerateSegment)) {\n offsettedArray.push(segment.offset);\n } else if (\n !sameVector(segment.offset.firstPoint, segment.offset.lastPoint)\n ) {\n offsettedArray.push(\n new Line(segment.offset.firstPoint, segment.offset.lastPoint)\n );\n }\n };\n const iterateOffsetSegments = function* (): Generator<OffsetSegmentPair> {\n for (const segment of offsetSegments.slice(0, -1)) {\n yield segment;\n }\n // This should never happen\n if (!savedLastSegment) throw new Error(\"Bug in the offset algorithm\");\n yield savedLastSegment;\n };\n\n for (const segment of iterateOffsetSegments()) {\n const previousLastPoint = previousSegment.offset.lastPoint;\n const firstPoint = segment.offset.firstPoint;\n\n // When the offset segments do still touch we do nothing\n if (sameVector(previousLastPoint, firstPoint)) {\n appendSegment(previousSegment);\n previousSegment = segment;\n continue;\n }\n\n let intersections: Vector[] = [];\n\n if (\n !(previousSegment.offset instanceof DegenerateSegment) &&\n !(segment.offset instanceof DegenerateSegment)\n ) {\n // When the offset segments intersect we cut them and save them at\n const { intersections: pointIntersections, overlaps } =\n findIntersectionsAndOverlaps(\n previousSegment.offset,\n segment.offset,\n PRECISION / 100\n );\n intersections = [\n ...pointIntersections,\n ...overlaps.flatMap((c) => [c.firstPoint, c.lastPoint]),\n ];\n }\n\n if (intersections.length > 0) {\n let intersection = intersections[0];\n if (intersections.length > 1) {\n // We choose the intersection point the closest to the end of the\n // original segment endpoint (why? not sure, following\n // https://github.com/jbuckmccready/cavalier_contours/)\n\n const originalEndpoint = previousSegment?.original.lastPoint;\n const distances = intersections.map((i) =>\n squareDistance(i, originalEndpoint)\n );\n intersection = intersections[distances.indexOf(Math.min(...distances))];\n }\n\n // We need to be a lot more careful here with multiple intersections\n // as well as cases where segments overlap\n\n const splitPreviousSegment = (previousSegment.offset as Segment).splitAt([\n intersection,\n ])[0];\n const splitSegment = (segment.offset as Segment)\n .splitAt([intersection])\n .at(-1);\n\n if (!splitSegment) throw new Error(\"Bug in the splitting algo in offset\");\n\n appendSegment({\n offset: splitPreviousSegment,\n original: previousSegment.original,\n });\n previousSegment = { offset: splitSegment, original: segment.original };\n continue;\n }\n\n // When the offset segments do not intersect we link them with an arc of\n // radius offset\n const center = previousSegment.original.lastPoint;\n const clockwise =\n crossProduct(\n subtract(firstPoint, center),\n subtract(previousLastPoint, center)\n ) > 0;\n\n const joiner = new Arc(previousLastPoint, firstPoint, center, clockwise);\n\n appendSegment(previousSegment);\n offsettedArray.push(joiner);\n previousSegment = segment;\n }\n\n appendSegment(previousSegment);\n return offsettedArray;\n}\n\ninterface OffsetSegmentPair {\n offset: Segment | DegenerateSegment;\n original: Segment;\n}\n\nexport function offsetLoop(loop: Loop, offset: number): Diagram {\n const correctedOffset = loop.clockwise ? offset : -offset;\n const offsettedArray = rawOffsets(loop.segments, correctedOffset);\n\n if (offsettedArray.length < 2) return new Diagram();\n\n // We remove the self intersections with the use the the algorithm as described in\n // https://github.com/jbuckmccready/CavalierContours#offset-algorithm-and-stepwise-example\n\n const allIntersections: Map<number, Vector[]> = new Map();\n const updateIntersections = (index: number, newPoints: Vector[]) => {\n const intersections = allIntersections.get(index) || [];\n allIntersections.set(index, [...intersections, ...newPoints]);\n };\n\n offsettedArray.forEach((firstSegment, firstIndex) => {\n offsettedArray\n .slice(firstIndex + 1)\n .forEach((secondSegment, secondIndex) => {\n const { intersections: rawIntersections, overlaps } =\n findIntersectionsAndOverlaps(firstSegment, secondSegment, PRECISION);\n\n const intersections = [\n ...rawIntersections,\n ...overlaps.flatMap((c) => [c.firstPoint, c.lastPoint]),\n ].filter((intersection) => {\n const onFirstSegmentExtremity =\n sameVector(intersection, firstSegment.firstPoint) ||\n sameVector(intersection, firstSegment.lastPoint);\n\n const onSecondSegmentExtremity =\n sameVector(intersection, secondSegment.firstPoint) ||\n sameVector(intersection, secondSegment.lastPoint);\n\n return !(onFirstSegmentExtremity && onSecondSegmentExtremity);\n });\n\n if (!intersections.length) return;\n\n updateIntersections(firstIndex, intersections);\n updateIntersections(secondIndex + firstIndex + 1, intersections);\n });\n });\n\n if (!allIntersections.size) {\n const offsettedLoop = new Loop(offsettedArray);\n return new Diagram([new Figure(offsettedLoop)]);\n\n /* this was in the replicad algorithm - not sure why\n if (!loop.intersects(offsettedLoop)) return offsettedLoop;\n return new Diagram();\n */\n }\n\n const splitSegments = offsettedArray.flatMap((segment, index) => {\n if (!allIntersections.has(index)) return segment;\n\n const intersections = allIntersections.get(index) || [];\n const splitSegments = segment.splitAt(intersections);\n return splitSegments;\n });\n\n // We remove all the segments that are closer to the original segment than the offset\n const prunedSegments = splitSegments.filter((segment) => {\n const closeSegment = loop.segments.some((c) => {\n return distance(c, segment) < Math.abs(offset) - PRECISION;\n });\n return !closeSegment;\n });\n\n if (!prunedSegments.length) return new Diagram();\n\n const segmentsGrouped = stitchSegments(prunedSegments);\n\n const newLoops = segmentsGrouped\n .filter((c) => c.length > 1)\n .filter((c) => sameVector(c[0].firstPoint, c.at(-1)!.lastPoint))\n .map((c) => new Loop(c));\n\n if (!newLoops.length) return new Diagram();\n return new Diagram(newLoops.map((l) => new Figure(l)));\n}\n","import { Figure } from \"../../models/Figure\";\nimport { Diagram } from \"../../models/Diagram\";\nimport { cut, fuseAll } from \"../../booleanOperations\";\nimport { offsetLoop } from \"./offsetLoop\";\n\nexport default function offsetFigures(\n figures: Figure[],\n offsetDistance: number\n): Diagram {\n const offsetFigures = figures.map((figure) => {\n const innerShape = fuseAll(\n figure.holes.map((l) => offsetLoop(l, offsetDistance))\n );\n return cut(offsetLoop(figure.contour, offsetDistance), innerShape);\n });\n\n return fuseAll(offsetFigures);\n}\n","import offsetFigures from \"./algorithms/offsets/offsetFigure\";\nimport { Diagram } from \"./models/Diagram\";\nimport { Figure } from \"./models/Figure\";\nimport { Loop } from \"./models/Loop\";\nimport { listOfFigures } from \"./utils/listOfFigures\";\n\nexport function offset(\n shape: Diagram | Figure | Loop,\n offsetDistance: number\n): Diagram {\n return offsetFigures(listOfFigures(shape), offsetDistance);\n}\n","import { Arc } from \"../../models/segments/Arc\";\nimport { Line } from \"../../models/segments/Line\";\nimport { Segment } from \"../../models/segments/Segment\";\n\nexport function svgSegmentToPath(segment: Segment) {\n if (segment instanceof Line) {\n return `L ${segment.lastPoint.join(\" \")}`;\n }\n if (segment instanceof Arc) {\n return `A ${segment.radius} ${segment.radius} 0 ${\n segment.angularLength > Math.PI ? \"1\" : \"0\"\n } ${segment.clockwise ? \"0\" : \"1\"} ${segment.lastPoint.join(\" \")}`;\n }\n\n throw new Error(\"Unknown segment type\");\n}\n","import type { Loop } from \"../../models/Loop\";\nimport { svgSegmentToPath } from \"./svgSegment\";\n\nexport function svgLoop(loop: Loop) {\n const start = `M ${loop.firstPoint.join(\" \")}`;\n const segments = loop.segments.map(svgSegmentToPath).join(\" \");\n return `${start} ${segments} Z`;\n}\n","import type { Figure } from \"../../models/Figure\";\nimport { svgLoop } from \"./svgLoop\";\n\nexport function svgFigure(figure: Figure) {\n const path = figure.allLoops.map(svgLoop).join(\" \");\n return `<path d=\"${path}\" />`;\n}\n","import { Diagram } from \"../../models/Diagram\";\nimport { svgFigure } from \"./svgFigure\";\n\nexport function svgDiagram(diagram: Diagram) {\n return `<g>\n ${diagram.figures.map(svgFigure).join(\"\\n\")}\n</g>`;\n}\n","import { BoundingBox } from \"../../models/BoundingBox\";\n\nexport function SVGViewbox(bbox: BoundingBox, margin = 1) {\n const minX = bbox.xMin - margin;\n const minY = bbox.yMin - margin;\n\n return `${minX} ${minY} ${bbox.width + 2 * margin} ${\n bbox.height + 2 * margin\n }`;\n}\n\nexport function wrapSVG(body: string, boundingBox: BoundingBox, margin = 1) {\n const vbox = SVGViewbox(boundingBox, margin);\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${vbox}\" fill=\"none\" stroke=\"black\" stroke-width=\"0.2%\" vector-effect=\"non-scaling-stroke\">\n ${body}\n</svg>`;\n}\n","import { Diagram } from \"../../models/Diagram\";\nimport { Figure } from \"../../models/Figure\";\nimport { Loop } from \"../../models/Loop\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Line } from \"../../models/segments/Line\";\nimport { svgDiagram } from \"./svgDiagram\";\nimport { svgFigure } from \"./svgFigure\";\nimport { svgLoop } from \"./svgLoop\";\nimport { svgSegmentToPath } from \"./svgSegment\";\nimport { wrapSVG } from \"./wrapSVG\";\n\ntype Shape = Loop | Figure | Diagram | Arc | Line;\n\nexport function svgBody(shape: Shape) {\n if (shape instanceof Diagram) {\n return svgDiagram(shape);\n } else if (shape instanceof Figure) {\n return svgFigure(shape);\n } else if (shape instanceof Loop) {\n return `<path d=\"${svgLoop(shape)}\" />`;\n } else if (shape instanceof Arc || shape instanceof Line) {\n return `<path d=\"${`M ${shape.firstPoint.join(\" \")}`} ${svgSegmentToPath(\n shape\n )}\" />`;\n } else {\n throw new Error(\"Unknown shape type\");\n }\n}\n\nexport function exportSVG(shape: Shape | Shape[], margin = 1) {\n if (Array.isArray(shape)) {\n const flipped = shape.map((s) => s.mirror());\n const body = flipped.map((s) => svgBody(s)).join(\"\\n\");\n const bbox = flipped\n .slice(1)\n .reduce((bbox, s) => bbox.merge(s.boundingBox), flipped[0].boundingBox);\n\n return wrapSVG(body, bbox);\n }\n const flipped = shape.mirror();\n return wrapSVG(svgBody(flipped), flipped.boundingBox, margin);\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Loop } from \"../../models/Loop\";\nimport { Figure } from \"../../models/Figure\";\nimport { Diagram } from \"../../models/Diagram\";\n\nconst importSegment = (json: any) => {\n if (json.type === \"LINE\") {\n return new Line(json.firstPoint, json.lastPoint);\n }\n if (json.type === \"ARC\") {\n return new Arc(\n json.firstPoint,\n json.lastPoint,\n json.center,\n json.clockwise\n );\n }\n throw new Error(\"Unknown segment type\");\n};\n\nconst importLoop = (json: any) => {\n const segments = json.segments.map(importSegment);\n return new Loop(segments);\n};\n\nconst importFigure = (json: any) => {\n const contour = importLoop(json.contour);\n const holes = json.holes.map(importLoop);\n return new Figure(contour, holes);\n};\n\nconst importDiagram = (json: any) => {\n const figures = json.figures.map(importFigure);\n return new Diagram(figures);\n};\n\nexport function importJSON(json: any) {\n if (json.type === \"DIAGRAM\") {\n return importDiagram(json);\n }\n if (json.type === \"FIGURE\") {\n return importFigure(json);\n }\n if (json.type === \"LOOP\") {\n return importLoop(json);\n }\n if (json.type === \"LINE\" || json.type === \"ARC\") {\n return importSegment(json);\n }\n throw new Error(\"Unknown shape type\");\n}\n","import type { Vector } from \"./definitions\";\nexport { Vector };\n\nexport const DEG2RAD = Math.PI / 180;\nexport const RAD2DEG = 180 / Math.PI;\n\nexport function polarToCartesian(r: number, theta: number): Vector {\n const x = Math.cos(theta * DEG2RAD) * r;\n const y = Math.sin(theta * DEG2RAD) * r;\n return [x, y];\n}\n\nexport function cartesianToPolar([x, y]: Vector): [number, number] {\n const r = Math.sqrt(x * x + y * y);\n const theta = Math.atan2(y, x) * RAD2DEG;\n return [r, theta];\n}\n\nexport type {\n Diagram,\n Figure,\n Loop,\n Strand,\n Stroke,\n TransformationMatrix,\n BoundingBox,\n Segment,\n Line,\n Arc,\n} from \"./models/exports\";\n\nexport { draw } from \"./draw\";\nexport { fuse, fuseAll, cut, intersect, offset } from \"./operations\";\n\nexport { exportSVG, svgBody } from \"./export/svg/exportSVG\";\n\nexport { exportJSON } from \"./export/json/exportJSON\";\nexport { importJSON } from \"./import/json/importJSON\";\n"],"names":["DegenerateSegment","firstPoint","lastPoint","offsetSegment","segment","offset","Line","offsetLine","Arc","offsetArc","line","normal","add","scalarMultiply","arc","offsetStartPoint","perpendicular","offsetEndPoint","orientedOffset","removeCorner","firstSegment","secondSegment","radius","sinAngle","crossProduct","orientationCorrection","firstOffset","secondOffset","potentialCenter","findIntersections","center","splitForFillet","tgt","perpendicularClockwise","splitPoint","first","second","filletSegments","cornerRemoved","tangentArc","chamferSegments","loopySegmentsToDiagram","segments","Diagram","Figure","Loop","DrawingPen","origin","point","sameVector","previousSegment","makeCorner","xDist","yDist","distance","yPos","xPos","r","theta","angleInRads","DEG2RAD","polarToCartesian","angle","x","y","previousCurve","xDir","yDir","end","midPoint","threePointsArc","viaXDist","viaYDist","x0","y0","sagitta","chord","norm","sagPoint","bulge","halfChord","bulgeAsSagitta","mode","lastSegment","mirrorVector","subtract","mirrorTranform","TransformationMatrix","mirroredSegments","draw","listOfFigures","shape","fuse","fuseFiguresLists","fuseAll","shapes","acc","cut","cutFiguresLists","intersect","intersectFiguresLists","segmentPosition","intersectionParam","handleBetween","lineBetween","otherLine","otherPosition","lineLineDistance","line1","line2","intersectionParams","lineLineParams","intersectionParam1","intersectionParam2","firstPosition","secondPosition","lineArcDistance","lineArcIntersection","closestPointOnLine","projectPointOnLine","circleCenterLineDistance","centerLineDirection","normalize","closestPointOnCircle","overlappingAngles","arc1","arc2","p1","p2","arcArcDistance","arcArcIntersection","centersDistance","centerCenterDirection","containedCircles","arc1ClosestPointAngle","polarAngle","arc2ClosestPointAngle","segment1","segment2","FlatQueue","id","value","pos","parent","parentValue","top","halfLength","left","right","bestIndex","bestValue","rightValue","ARRAY_TYPES","VERSION","Flatbush","data","magic","versionAndType","nodeSize","numItems","ArrayType","ArrayBufferType","n","numNodes","arrayTypeIndex","nodesByteSize","minX","minY","maxX","maxY","index","boxes","width","height","hilbertValues","hilbertMax","i","hilbert","sort","nodeIndex","nodeMinX","nodeMinY","nodeMaxX","nodeMaxY","j","filterFn","queue","results","upperBound","maxResults","maxDistance","q","maxDistSquared","dx","axisDist","dy","dist","k","min","max","arr","m","values","indices","pivot","swap","temp","a","b","d","e","c","A","B","C","D","i0","i1","stitchSegments","precision","startPoints","stitchedSegments","visited","connectedSegments","currentIndex","maxLoops","neighbors","indexDistance","otherIndex","potentialNextSegments","neighborIndex","nextSegment","nextSegmentIndex","PRECISION","rawOffsets","segmentsToOffset","offsetSegments","offsettedArray","savedLastSegment","appendSegment","iterateOffsetSegments","previousLastPoint","intersections","pointIntersections","overlaps","findIntersectionsAndOverlaps","intersection","originalEndpoint","distances","squareDistance","splitPreviousSegment","splitSegment","clockwise","joiner","offsetLoop","loop","correctedOffset","allIntersections","updateIntersections","newPoints","firstIndex","secondIndex","rawIntersections","onFirstSegmentExtremity","onSecondSegmentExtremity","offsettedLoop","prunedSegments","splitSegments","newLoops","l","offsetFigures","figures","offsetDistance","figure","innerShape","svgSegmentToPath","svgLoop","start","svgFigure","svgDiagram","diagram","SVGViewbox","bbox","margin","wrapSVG","body","boundingBox","svgBody","exportSVG","flipped","s","importSegment","json","importLoop","importFigure","contour","holes","importDiagram","importJSON","RAD2DEG","cartesianToPolar"],"mappings":"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","x_google_ignoreList":[9,10]}
1
+ {"version":3,"file":"pantograph.js","sources":["../src/utils/listOfFigures.ts","../src/algorithms/boolean/strandBoolean.ts","../src/booleanOperations.ts","../src/algorithms/distances/lineLineDistance.ts","../src/algorithms/distances/lineArcDistance.ts","../src/algorithms/distances/arcArcDistance.ts","../src/algorithms/distances/index.ts","../src/algorithms/offsets/offsetLoop.ts","../src/algorithms/offsets/offsetFigure.ts","../src/offsetOperations.ts","../src/export/svg/svgSegment.ts","../src/export/svg/svgLoop.ts","../src/export/svg/svgFigure.ts","../src/export/svg/svgDiagram.ts","../src/export/svg/svgStrand.ts","../src/export/svg/wrapSVG.ts","../src/export/svg/exportSVG.ts","../src/import/json/importJSON.ts","../src/main.ts"],"sourcesContent":["import { Diagram } from \"../models/Diagram\";\nimport { Figure } from \"../models/Figure\";\nimport { Loop } from \"../models/Loop\";\n\nexport function listOfFigures(shape: Diagram | Figure | Loop): Figure[] {\n if (shape instanceof Figure) {\n return [shape];\n } else if (shape instanceof Loop) {\n return [new Figure(shape)];\n } else if (shape instanceof Diagram) {\n return shape.figures;\n }\n throw new Error(\"Unknown shape\");\n}\n","import { Vector } from \"../../definitions\";\nimport { Segment } from \"../../models/segments/Segment\";\nimport { Loop } from \"../../models/Loop\";\nimport { Strand } from \"../../models/Strand\";\nimport { findIntersectionsAndOverlaps } from \"../intersections\";\nimport removeDuplicatePoints from \"../../utils/removeDuplicatePoints\";\nimport zip from \"../../utils/zip\";\nimport { strandsBetweenIntersections } from \"./strandsBetweenIntersections\";\nimport { Figure } from \"../../main\";\n\nfunction strandLoopSections(\n loop: Loop,\n strand: Strand,\n precision = 1e-9\n): Strand[] {\n let allIntersections: Vector[] = [];\n const allCommonSegments: Segment[] = [];\n\n const splitPoints: Vector[][] = new Array(strand.segments.length)\n .fill(0)\n .map(() => []);\n\n strand.segments.forEach((strandSegment, strandIndex) => {\n loop.segments.forEach((loopSegment) => {\n const { intersections, overlaps } = findIntersectionsAndOverlaps(\n strandSegment,\n loopSegment,\n precision\n );\n\n allIntersections.push(...intersections);\n splitPoints[strandIndex].push(...intersections);\n\n allCommonSegments.push(...overlaps);\n const commonSegmentsPoints = overlaps.flatMap((s) => [\n s.firstPoint,\n s.lastPoint,\n ]);\n allIntersections.push(...commonSegmentsPoints);\n splitPoints[strandIndex].push(...commonSegmentsPoints);\n });\n });\n\n allIntersections = removeDuplicatePoints(allIntersections, precision);\n\n const strandSegments = zip([strand.segments, splitPoints] as [\n Segment[],\n Vector[][]\n ]).flatMap(([segment, intersections]: [Segment, Vector[]]): Segment[] => {\n if (!intersections.length) return [segment];\n return segment.splitAt(intersections);\n });\n\n return Array.from(\n strandsBetweenIntersections(\n strandSegments,\n allIntersections,\n allCommonSegments\n )\n );\n}\n\nexport function eraseStrandWithinLoop(\n strand: Strand,\n loop: Loop,\n eraseOnBorder = false\n) {\n const strands = strandLoopSections(loop, strand);\n\n // We keep only the strands that are outside the loop\n return strands.filter((strand) => {\n const strandCenter = strand.segments[0].midPoint;\n if (loop.onStroke(strandCenter)) return !eraseOnBorder;\n\n return !loop.contains(strandCenter);\n });\n}\n\nexport function eraseStrandOutsideLoop(\n strand: Strand,\n loop: Loop,\n eraseOnBorder = false\n) {\n const strands = strandLoopSections(loop, strand);\n\n // We keep only the strands that are outside the loop\n return strands.filter((strand) => {\n const strandCenter = strand.segments[0].midPoint;\n if (loop.onStroke(strandCenter)) return !eraseOnBorder;\n\n return loop.contains(strandCenter);\n });\n}\n\nexport function eraseStrandWithinFigure(\n strand: Strand,\n figure: Figure,\n eraseOnBorder = false\n) {\n const outsideStrands = eraseStrandWithinLoop(\n strand,\n figure.contour,\n eraseOnBorder\n );\n\n const inLoopStrand = figure.holes.flatMap((hole: Loop) =>\n eraseStrandOutsideLoop(strand, hole, eraseOnBorder)\n );\n\n return [...outsideStrands, ...inLoopStrand];\n}\n\nexport function eraseStrandOutsideFigure(\n strand: Strand,\n figure: Figure,\n eraseOnBorder = false\n) {\n let insideStrands = eraseStrandOutsideLoop(\n strand,\n figure.contour,\n eraseOnBorder\n );\n\n figure.holes.forEach((hole: Loop) => {\n insideStrands = insideStrands.flatMap((strand) =>\n eraseStrandWithinLoop(strand, hole, eraseOnBorder)\n );\n });\n\n return insideStrands;\n}\n","import {\n cutFiguresLists,\n fuseFiguresLists,\n intersectFiguresLists,\n} from \"./algorithms/boolean/figureBooleans\";\nimport { Strand } from \"./models/Strand\";\nimport { Diagram } from \"./models/Diagram\";\nimport { Figure } from \"./models/Figure\";\nimport { Loop } from \"./models/Loop\";\nimport { listOfFigures } from \"./utils/listOfFigures\";\nimport {\n eraseStrandOutsideFigure,\n eraseStrandOutsideLoop,\n eraseStrandWithinFigure,\n eraseStrandWithinLoop,\n} from \"./algorithms/boolean/strandBoolean\";\n\nexport function fuse(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n fuseFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n\nexport function fuseAll(shapes: (Diagram | Figure | Loop)[]): Diagram {\n return shapes.reduce(\n (acc: Diagram, shape: Diagram | Figure | Loop) => fuse(acc, shape),\n new Diagram()\n );\n}\n\nexport function cut(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n cutFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n\nexport function intersect(\n first: Diagram | Figure | Loop,\n second: Diagram | Figure | Loop\n): Diagram {\n return new Diagram(\n intersectFiguresLists(listOfFigures(first), listOfFigures(second))\n );\n}\n\nexport function eraseStrand(\n strand: Strand,\n diagram: Diagram | Figure | Loop,\n eraseOnBorder = true\n): Strand[] {\n if (diagram instanceof Loop) {\n return eraseStrandWithinLoop(strand, diagram, eraseOnBorder);\n }\n\n if (diagram instanceof Figure) {\n return eraseStrandWithinFigure(strand, diagram, eraseOnBorder);\n }\n\n let outStrands: Strand[] = [strand];\n diagram.figures.forEach((figure: Figure) => {\n outStrands = outStrands.flatMap((strand: Strand) => {\n return eraseStrandWithinFigure(strand, figure, eraseOnBorder);\n });\n });\n\n return outStrands;\n}\n\nexport function confineStrand(\n strand: Strand,\n diagram: Diagram | Figure | Loop,\n eraseOnBorder = false\n): Strand[] {\n if (diagram instanceof Loop) {\n return eraseStrandOutsideLoop(strand, diagram, eraseOnBorder);\n }\n\n if (diagram instanceof Figure) {\n return eraseStrandOutsideFigure(strand, diagram, eraseOnBorder);\n }\n\n let outStrands: Strand[] = [strand];\n diagram.figures.forEach((figure: Figure) => {\n outStrands = outStrands.flatMap((strand: Strand) => {\n return eraseStrandOutsideFigure(strand, figure, eraseOnBorder);\n });\n });\n\n return outStrands;\n}\n","import { lineLineParams } from \"../intersections/lineLineIntersection\";\nimport type { Line } from \"../../models/segments/Line\";\nimport { distance } from \"../../vectorOperations\";\n\nfunction segmentPosition(intersectionParam: number) {\n if (intersectionParam < 0) return \"before\";\n if (intersectionParam > 1) return \"after\";\n return \"between\";\n}\n\nconst handleBetween = (\n lineBetween: Line,\n otherLine: Line,\n otherPosition: \"before\" | \"after\"\n) => {\n if (otherPosition === \"before\")\n return lineBetween.distanceFrom(otherLine.firstPoint);\n else if (otherPosition === \"after\")\n return lineBetween.distanceFrom(otherLine.lastPoint);\n else throw new Error(\"Invalid position\");\n};\n\nexport function lineLineDistance(line1: Line, line2: Line): number {\n const intersectionParams = lineLineParams(line1, line2);\n\n if (intersectionParams === \"parallel\") {\n return Math.min(\n line1.distanceFrom(line2.firstPoint),\n line1.distanceFrom(line2.lastPoint)\n );\n }\n\n const { intersectionParam1, intersectionParam2 } = intersectionParams;\n\n const firstPosition = segmentPosition(intersectionParam1);\n const secondPosition = segmentPosition(intersectionParam2);\n\n if (firstPosition === \"between\" && secondPosition === \"between\") {\n return 0;\n } else if (firstPosition === \"between\" && secondPosition !== \"between\") {\n return handleBetween(line1, line2, secondPosition);\n } else if (secondPosition === \"between\" && firstPosition !== \"between\") {\n return handleBetween(line2, line1, firstPosition);\n } else if (firstPosition === \"before\" && secondPosition === \"before\") {\n return distance(line1.firstPoint, line2.firstPoint);\n } else if (firstPosition === \"after\" && secondPosition === \"after\") {\n return distance(line1.lastPoint, line2.lastPoint);\n } else if (firstPosition === \"before\" && secondPosition === \"after\") {\n return distance(line1.firstPoint, line2.lastPoint);\n } else if (firstPosition === \"after\" && secondPosition === \"before\") {\n return distance(line1.lastPoint, line2.firstPoint);\n } else {\n throw new Error(\"Invalid position\");\n }\n}\n","import type { Line } from \"../../models/segments/Line\";\nimport type { Arc } from \"../../models/segments/Arc\";\nimport {\n normalize,\n subtract,\n distance,\n add,\n scalarMultiply,\n} from \"../../vectorOperations\";\nimport { projectPointOnLine } from \"../../utils/projectPointOnLine\";\nimport { lineArcIntersection } from \"../intersections/lineArcIntersection\";\n\nexport function lineArcDistance(line: Line, arc: Arc): number {\n // We might be able to optimise this if necessary\n\n if (lineArcIntersection(line, arc).length > 0) {\n return 0;\n }\n\n const closestPointOnLine = projectPointOnLine(line, arc.center);\n\n if (line.isOnSegment(closestPointOnLine)) {\n const circleCenterLineDistance = distance(closestPointOnLine, arc.center);\n\n // The line is tangent to the circle\n if (Math.abs(circleCenterLineDistance - arc.radius) < line.precision) {\n if (arc.isOnSegment(closestPointOnLine)) {\n return 0;\n }\n }\n\n if (circleCenterLineDistance - arc.radius > line.precision) {\n const centerLineDirection = normalize(\n subtract(closestPointOnLine, arc.center)\n );\n\n const closestPointOnCircle = add(\n arc.center,\n scalarMultiply(centerLineDirection, arc.radius)\n );\n\n if (arc.isOnSegment(closestPointOnCircle)) {\n return distance(closestPointOnCircle, closestPointOnLine);\n }\n }\n }\n\n return Math.min(\n arc.distanceFrom(line.firstPoint),\n arc.distanceFrom(line.lastPoint),\n line.distanceFrom(arc.firstPoint),\n line.distanceFrom(arc.lastPoint)\n );\n}\n","import {\n distance,\n normalize,\n polarAngle,\n subtract,\n} from \"../../vectorOperations\";\nimport type { Arc } from \"../../models/segments/Arc\";\nimport { arcArcIntersection } from \"../intersections/arcArcIntersection\";\n\nconst overlappingAngles = (arc1: Arc, arc2: Arc): boolean => {\n const p1 = arc1.angleToParam(arc2.firstAngle);\n if (arc1.isValidParameter(p1)) return true;\n\n const p2 = arc1.angleToParam(arc2.lastAngle);\n if (arc1.isValidParameter(p2)) return true;\n return false;\n};\n\nexport function arcArcDistance(arc1: Arc, arc2: Arc): number {\n if (arcArcIntersection(arc1, arc2, true).length > 0) return 0;\n\n const centersDistance = distance(arc1.center, arc2.center);\n\n if (centersDistance < arc1.precision) {\n if (overlappingAngles(arc1, arc2)) {\n return Math.abs(arc1.radius - arc2.radius);\n }\n }\n\n const centerCenterDirection = normalize(subtract(arc2.center, arc1.center));\n\n const containedCircles =\n centersDistance - Math.abs(arc1.radius - arc2.radius) < arc1.precision;\n\n let arc1ClosestPointAngle = polarAngle(centerCenterDirection);\n if (containedCircles && arc2.radius > arc1.radius) {\n arc1ClosestPointAngle += Math.PI;\n }\n const arc2ClosestPointAngle = containedCircles\n ? arc1ClosestPointAngle\n : arc1ClosestPointAngle + Math.PI;\n\n const p1 = arc1.angleToParam(arc1ClosestPointAngle);\n const p2 = arc2.angleToParam(arc2ClosestPointAngle);\n\n if (arc1.isValidParameter(p1) && arc2.isValidParameter(p2)) {\n // There might be some optimization here (with the center distance and radius differences)\n return distance(arc1.paramPoint(p1), arc2.paramPoint(p2));\n }\n\n return Math.min(\n arc1.distanceFrom(arc2.firstPoint),\n arc1.distanceFrom(arc2.lastPoint),\n arc2.distanceFrom(arc1.firstPoint),\n arc2.distanceFrom(arc1.lastPoint)\n );\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { lineLineDistance } from \"./lineLineDistance\";\nimport { lineArcDistance } from \"./lineArcDistance\";\nimport { arcArcDistance } from \"./arcArcDistance\";\nimport type { Segment } from \"../../models/segments/Segment\";\n\nexport function distance(segment1: Segment, segment2: Segment): number {\n if (segment1 instanceof Line && segment2 instanceof Line) {\n return lineLineDistance(segment1, segment2);\n }\n\n if (segment1 instanceof Line && segment2 instanceof Arc) {\n return lineArcDistance(segment1, segment2);\n }\n\n if (segment1 instanceof Arc && segment2 instanceof Line) {\n return lineArcDistance(segment2, segment1);\n }\n\n if (segment1 instanceof Arc && segment2 instanceof Arc) {\n return arcArcDistance(segment1, segment2);\n }\n\n throw new Error(\"Not implemented\");\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Loop } from \"../../models/Loop\";\nimport { Segment } from \"../../models/segments/Segment\";\nimport {\n crossProduct,\n sameVector,\n squareDistance,\n subtract,\n} from \"../../vectorOperations\";\nimport { distance } from \"../distances\";\nimport { offsetSegment, DegenerateSegment } from \"./offsetSegment\";\nimport { Vector } from \"../../definitions\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Diagram } from \"../../models/Diagram\";\nimport { findIntersectionsAndOverlaps } from \"../intersections\";\nimport { Figure } from \"../../models/Figure\";\nimport { stitchSegments } from \"../stitchSegments\";\n\nconst PRECISION = 1e-8;\n\nexport function rawOffsets(\n segmentsToOffset: Segment[],\n offset: number\n): Segment[] {\n const offsetSegments: OffsetSegmentPair[] = segmentsToOffset.map((c) => ({\n offset: offsetSegment(c, offset),\n original: c,\n }));\n\n // Ideally we would use the length of the segment to make sure it is\n // not only a point, but the algo we have access to are a bit to\n // convoluted to be usable here\n\n const offsettedArray: Segment[] = [];\n\n let savedLastSegment: null | OffsetSegmentPair = null;\n\n let previousSegment = offsetSegments.at(-1);\n\n // We have no offseted segments\n if (!previousSegment) return [];\n if (offsettedArray.length === 1) return offsettedArray;\n\n const appendSegment = (segment: OffsetSegmentPair) => {\n if (!savedLastSegment) {\n savedLastSegment = segment;\n } else if (!(segment.offset instanceof DegenerateSegment)) {\n offsettedArray.push(segment.offset);\n } else if (\n !sameVector(segment.offset.firstPoint, segment.offset.lastPoint)\n ) {\n offsettedArray.push(\n new Line(segment.offset.firstPoint, segment.offset.lastPoint)\n );\n }\n };\n const iterateOffsetSegments = function* (): Generator<OffsetSegmentPair> {\n for (const segment of offsetSegments.slice(0, -1)) {\n yield segment;\n }\n // This should never happen\n if (!savedLastSegment) throw new Error(\"Bug in the offset algorithm\");\n yield savedLastSegment;\n };\n\n for (const segment of iterateOffsetSegments()) {\n const previousLastPoint = previousSegment.offset.lastPoint;\n const firstPoint = segment.offset.firstPoint;\n\n // When the offset segments do still touch we do nothing\n if (sameVector(previousLastPoint, firstPoint)) {\n appendSegment(previousSegment);\n previousSegment = segment;\n continue;\n }\n\n let intersections: Vector[] = [];\n\n if (\n !(previousSegment.offset instanceof DegenerateSegment) &&\n !(segment.offset instanceof DegenerateSegment)\n ) {\n // When the offset segments intersect we cut them and save them at\n const { intersections: pointIntersections, overlaps } =\n findIntersectionsAndOverlaps(\n previousSegment.offset,\n segment.offset,\n PRECISION / 100\n );\n intersections = [\n ...pointIntersections,\n ...overlaps.flatMap((c) => [c.firstPoint, c.lastPoint]),\n ];\n }\n\n if (intersections.length > 0) {\n let intersection = intersections[0];\n if (intersections.length > 1) {\n // We choose the intersection point the closest to the end of the\n // original segment endpoint (why? not sure, following\n // https://github.com/jbuckmccready/cavalier_contours/)\n\n const originalEndpoint = previousSegment?.original.lastPoint;\n const distances = intersections.map((i) =>\n squareDistance(i, originalEndpoint)\n );\n intersection = intersections[distances.indexOf(Math.min(...distances))];\n }\n\n // We need to be a lot more careful here with multiple intersections\n // as well as cases where segments overlap\n\n const splitPreviousSegment = (previousSegment.offset as Segment).splitAt([\n intersection,\n ])[0];\n const splitSegment = (segment.offset as Segment)\n .splitAt([intersection])\n .at(-1);\n\n if (!splitSegment) throw new Error(\"Bug in the splitting algo in offset\");\n\n appendSegment({\n offset: splitPreviousSegment,\n original: previousSegment.original,\n });\n previousSegment = { offset: splitSegment, original: segment.original };\n continue;\n }\n\n // When the offset segments do not intersect we link them with an arc of\n // radius offset\n const center = previousSegment.original.lastPoint;\n const clockwise =\n crossProduct(\n subtract(firstPoint, center),\n subtract(previousLastPoint, center)\n ) > 0;\n\n const joiner = new Arc(previousLastPoint, firstPoint, center, clockwise);\n\n appendSegment(previousSegment);\n offsettedArray.push(joiner);\n previousSegment = segment;\n }\n\n appendSegment(previousSegment);\n return offsettedArray;\n}\n\ninterface OffsetSegmentPair {\n offset: Segment | DegenerateSegment;\n original: Segment;\n}\n\nexport function offsetLoop(loop: Loop, offset: number): Diagram {\n const correctedOffset = loop.clockwise ? offset : -offset;\n const offsettedArray = rawOffsets(loop.segments, correctedOffset);\n\n if (offsettedArray.length < 2) return new Diagram();\n\n // We remove the self intersections with the use the the algorithm as described in\n // https://github.com/jbuckmccready/CavalierContours#offset-algorithm-and-stepwise-example\n\n const allIntersections: Map<number, Vector[]> = new Map();\n const updateIntersections = (index: number, newPoints: Vector[]) => {\n const intersections = allIntersections.get(index) || [];\n allIntersections.set(index, [...intersections, ...newPoints]);\n };\n\n offsettedArray.forEach((firstSegment, firstIndex) => {\n offsettedArray\n .slice(firstIndex + 1)\n .forEach((secondSegment, secondIndex) => {\n const { intersections: rawIntersections, overlaps } =\n findIntersectionsAndOverlaps(firstSegment, secondSegment, PRECISION);\n\n const intersections = [\n ...rawIntersections,\n ...overlaps.flatMap((c) => [c.firstPoint, c.lastPoint]),\n ].filter((intersection) => {\n const onFirstSegmentExtremity =\n sameVector(intersection, firstSegment.firstPoint) ||\n sameVector(intersection, firstSegment.lastPoint);\n\n const onSecondSegmentExtremity =\n sameVector(intersection, secondSegment.firstPoint) ||\n sameVector(intersection, secondSegment.lastPoint);\n\n return !(onFirstSegmentExtremity && onSecondSegmentExtremity);\n });\n\n if (!intersections.length) return;\n\n updateIntersections(firstIndex, intersections);\n updateIntersections(secondIndex + firstIndex + 1, intersections);\n });\n });\n\n if (!allIntersections.size) {\n const offsettedLoop = new Loop(offsettedArray);\n return new Diagram([new Figure(offsettedLoop)]);\n\n /* this was in the replicad algorithm - not sure why\n if (!loop.intersects(offsettedLoop)) return offsettedLoop;\n return new Diagram();\n */\n }\n\n const splitSegments = offsettedArray.flatMap((segment, index) => {\n if (!allIntersections.has(index)) return segment;\n\n const intersections = allIntersections.get(index) || [];\n const splitSegments = segment.splitAt(intersections);\n return splitSegments;\n });\n\n // We remove all the segments that are closer to the original segment than the offset\n const prunedSegments = splitSegments.filter((segment) => {\n const closeSegment = loop.segments.some((c) => {\n return distance(c, segment) < Math.abs(offset) - PRECISION;\n });\n return !closeSegment;\n });\n\n if (!prunedSegments.length) return new Diagram();\n\n const segmentsGrouped = stitchSegments(prunedSegments);\n\n const newLoops = segmentsGrouped\n .filter((c) => c.length > 1)\n .filter((c) => sameVector(c[0].firstPoint, c.at(-1)!.lastPoint))\n .map((c) => new Loop(c));\n\n if (!newLoops.length) return new Diagram();\n return new Diagram(newLoops.map((l) => new Figure(l)));\n}\n","import { Figure } from \"../../models/Figure\";\nimport { Diagram } from \"../../models/Diagram\";\nimport { cut, fuseAll } from \"../../booleanOperations\";\nimport { offsetLoop } from \"./offsetLoop\";\n\nexport default function offsetFigures(\n figures: Figure[],\n offsetDistance: number\n): Diagram {\n const offsetFigures = figures.map((figure) => {\n const innerShape = fuseAll(\n figure.holes.map((l) => offsetLoop(l, offsetDistance))\n );\n return cut(offsetLoop(figure.contour, offsetDistance), innerShape);\n });\n\n return fuseAll(offsetFigures);\n}\n","import offsetFigures from \"./algorithms/offsets/offsetFigure\";\nimport { Diagram } from \"./models/Diagram\";\nimport { Figure } from \"./models/Figure\";\nimport { Loop } from \"./models/Loop\";\nimport { listOfFigures } from \"./utils/listOfFigures\";\n\nexport function offset(\n shape: Diagram | Figure | Loop,\n offsetDistance: number\n): Diagram {\n return offsetFigures(listOfFigures(shape), offsetDistance);\n}\n","import { Arc } from \"../../models/segments/Arc\";\nimport { Line } from \"../../models/segments/Line\";\nimport { Segment } from \"../../models/segments/Segment\";\n\nexport function svgSegmentToPath(segment: Segment) {\n if (segment instanceof Line) {\n return `L ${segment.lastPoint.join(\" \")}`;\n }\n if (segment instanceof Arc) {\n return `A ${segment.radius} ${segment.radius} 0 ${\n segment.angularLength > Math.PI ? \"1\" : \"0\"\n } ${segment.clockwise ? \"0\" : \"1\"} ${segment.lastPoint.join(\" \")}`;\n }\n\n throw new Error(\"Unknown segment type\");\n}\n","import type { Loop } from \"../../models/Loop\";\nimport { svgSegmentToPath } from \"./svgSegment\";\n\nexport function svgLoop(loop: Loop) {\n const start = `M ${loop.firstPoint.join(\" \")}`;\n const segments = loop.segments.map(svgSegmentToPath).join(\" \");\n return `${start} ${segments} Z`;\n}\n","import type { Figure } from \"../../models/Figure\";\nimport { svgLoop } from \"./svgLoop\";\n\nexport function svgFigure(figure: Figure) {\n const path = figure.allLoops.map(svgLoop).join(\" \");\n return `<path d=\"${path}\" />`;\n}\n","import { Diagram } from \"../../models/Diagram\";\nimport { svgFigure } from \"./svgFigure\";\n\nexport function svgDiagram(diagram: Diagram) {\n return `<g>\n ${diagram.figures.map(svgFigure).join(\"\\n\")}\n</g>`;\n}\n","import type { Strand } from \"../../models/Strand\";\nimport { svgSegmentToPath } from \"./svgSegment\";\n\nexport function svgStrand(strand: Strand) {\n const start = `M ${strand.firstPoint.join(\" \")}`;\n const segments = strand.segments.map(svgSegmentToPath).join(\" \");\n return `${start} ${segments}`;\n}\n","import { BoundingBox } from \"../../models/BoundingBox\";\n\nexport function SVGViewbox(bbox: BoundingBox, margin = 1) {\n const minX = bbox.xMin - margin;\n const minY = bbox.yMin - margin;\n\n return `${minX} ${minY} ${bbox.width + 2 * margin} ${\n bbox.height + 2 * margin\n }`;\n}\n\nexport function wrapSVG(body: string, boundingBox: BoundingBox, margin = 1) {\n const vbox = SVGViewbox(boundingBox, margin);\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${vbox}\" fill=\"none\" stroke=\"black\" stroke-width=\"0.2%\" vector-effect=\"non-scaling-stroke\">\n ${body}\n</svg>`;\n}\n","import { Strand } from \"../../models/Strand\";\nimport { Diagram } from \"../../models/Diagram\";\nimport { Figure } from \"../../models/Figure\";\nimport { Loop } from \"../../models/Loop\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Line } from \"../../models/segments/Line\";\nimport { svgDiagram } from \"./svgDiagram\";\nimport { svgFigure } from \"./svgFigure\";\nimport { svgLoop } from \"./svgLoop\";\nimport { svgSegmentToPath } from \"./svgSegment\";\nimport { svgStrand } from \"./svgStrand\";\nimport { wrapSVG } from \"./wrapSVG\";\n\ntype Shape = Loop | Figure | Diagram | Arc | Line | Strand;\n\nexport function svgBody(shape: Shape) {\n if (shape instanceof Diagram) {\n return svgDiagram(shape);\n } else if (shape instanceof Figure) {\n return svgFigure(shape);\n } else if (shape instanceof Loop) {\n return `<path d=\"${svgLoop(shape)}\" />`;\n } else if (shape instanceof Strand) {\n return `<path d=\"${svgStrand(shape)}\" />`;\n } else if (shape instanceof Arc || shape instanceof Line) {\n return `<path d=\"${`M ${shape.firstPoint.join(\" \")}`} ${svgSegmentToPath(\n shape\n )}\" />`;\n } else {\n throw new Error(\"Unknown shape type\");\n }\n}\n\ntype ConfiguredShape = Shape | { shape: Shape; color?: string };\n\nconst extractShape = (shape: ConfiguredShape) =>\n \"shape\" in shape ? shape.shape : shape;\n\nconst addConfig = (shape: ConfiguredShape, body: string) => {\n if (!(\"shape\" in shape)) return body;\n const { color } = shape;\n if (!color) return body;\n return `<g stroke=\"${color}\">${body}</g>`;\n};\n\nexport function exportSVG(\n shape: ConfiguredShape | ConfiguredShape[],\n margin = 1\n) {\n if (Array.isArray(shape)) {\n const flipped = shape.map((s) => extractShape(s).mirror());\n const body = flipped\n .map((s, i) => addConfig(shape[i], svgBody(s)))\n .join(\"\\n\");\n const bbox = flipped\n .slice(1)\n .reduce((bbox, s) => bbox.merge(s.boundingBox), flipped[0].boundingBox);\n\n return wrapSVG(body, bbox);\n }\n const flipped = extractShape(shape).mirror();\n return wrapSVG(\n addConfig(shape, svgBody(flipped)),\n flipped.boundingBox,\n margin\n );\n}\n","import { Line } from \"../../models/segments/Line\";\nimport { Arc } from \"../../models/segments/Arc\";\nimport { Loop } from \"../../models/Loop\";\nimport { Figure } from \"../../models/Figure\";\nimport { Diagram } from \"../../models/Diagram\";\n\nconst importSegment = (json: any) => {\n if (json.type === \"LINE\") {\n return new Line(json.firstPoint, json.lastPoint);\n }\n if (json.type === \"ARC\") {\n return new Arc(\n json.firstPoint,\n json.lastPoint,\n json.center,\n json.clockwise\n );\n }\n throw new Error(\"Unknown segment type\");\n};\n\nconst importLoop = (json: any) => {\n const segments = json.segments.map(importSegment);\n return new Loop(segments);\n};\n\nconst importFigure = (json: any) => {\n const contour = importLoop(json.contour);\n const holes = json.holes.map(importLoop);\n return new Figure(contour, holes);\n};\n\nconst importDiagram = (json: any) => {\n const figures = json.figures.map(importFigure);\n return new Diagram(figures);\n};\n\nexport function importJSON(json: any) {\n if (json.type === \"DIAGRAM\") {\n return importDiagram(json);\n }\n if (json.type === \"FIGURE\") {\n return importFigure(json);\n }\n if (json.type === \"LOOP\") {\n return importLoop(json);\n }\n if (json.type === \"LINE\" || json.type === \"ARC\") {\n return importSegment(json);\n }\n throw new Error(\"Unknown shape type\");\n}\n","import type { Vector } from \"./definitions\";\nexport { Vector };\n\nexport const DEG2RAD = Math.PI / 180;\nexport const RAD2DEG = 180 / Math.PI;\n\nexport function polarToCartesian(r: number, theta: number): Vector {\n const x = Math.cos(theta * DEG2RAD) * r;\n const y = Math.sin(theta * DEG2RAD) * r;\n return [x, y];\n}\n\nexport function cartesianToPolar([x, y]: Vector): [number, number] {\n const r = Math.sqrt(x * x + y * y);\n const theta = Math.atan2(y, x) * RAD2DEG;\n return [r, theta];\n}\n\nexport type {\n Diagram,\n Figure,\n Loop,\n Strand,\n Stroke,\n TransformationMatrix,\n BoundingBox,\n Segment,\n Line,\n Arc,\n} from \"./models/exports\";\n\nexport { draw } from \"./draw\";\nexport {\n // Surface booleans\n fuseAll,\n fuse,\n cut,\n intersect,\n // Strand booleans\n eraseStrand,\n confineStrand,\n // Offset\n offset,\n} from \"./operations\";\n\nexport { exportSVG, svgBody } from \"./export/svg/exportSVG\";\n\nexport { exportJSON } from \"./export/json/exportJSON\";\nexport { importJSON } from \"./import/json/importJSON\";\n"],"names":["listOfFigures","shape","Figure","Loop","Diagram","strandLoopSections","loop","strand","precision","allIntersections","allCommonSegments","splitPoints","strandSegment","strandIndex","loopSegment","intersections","overlaps","findIntersectionsAndOverlaps","commonSegmentsPoints","s","removeDuplicatePoints","strandSegments","zip","segment","strandsBetweenIntersections","eraseStrandWithinLoop","eraseOnBorder","strandCenter","eraseStrandOutsideLoop","eraseStrandWithinFigure","figure","outsideStrands","inLoopStrand","hole","eraseStrandOutsideFigure","insideStrands","fuse","first","second","fuseFiguresLists","fuseAll","shapes","acc","cut","cutFiguresLists","intersect","intersectFiguresLists","eraseStrand","diagram","outStrands","confineStrand","segmentPosition","intersectionParam","handleBetween","lineBetween","otherLine","otherPosition","lineLineDistance","line1","line2","intersectionParams","lineLineParams","intersectionParam1","intersectionParam2","firstPosition","secondPosition","distance","lineArcDistance","line","arc","lineArcIntersection","closestPointOnLine","projectPointOnLine","circleCenterLineDistance","centerLineDirection","normalize","subtract","closestPointOnCircle","add","scalarMultiply","overlappingAngles","arc1","arc2","p1","p2","arcArcDistance","arcArcIntersection","centersDistance","centerCenterDirection","containedCircles","arc1ClosestPointAngle","polarAngle","arc2ClosestPointAngle","segment1","segment2","Line","Arc","PRECISION","rawOffsets","segmentsToOffset","offset","offsetSegments","c","offsetSegment","offsettedArray","savedLastSegment","previousSegment","appendSegment","DegenerateSegment","sameVector","iterateOffsetSegments","previousLastPoint","firstPoint","pointIntersections","intersection","originalEndpoint","distances","i","squareDistance","splitPreviousSegment","splitSegment","center","clockwise","crossProduct","joiner","offsetLoop","correctedOffset","updateIntersections","index","newPoints","firstSegment","firstIndex","secondSegment","secondIndex","rawIntersections","onFirstSegmentExtremity","onSecondSegmentExtremity","offsettedLoop","prunedSegments","splitSegments","newLoops","stitchSegments","l","offsetFigures","figures","offsetDistance","innerShape","svgSegmentToPath","svgLoop","start","segments","svgFigure","svgDiagram","svgStrand","SVGViewbox","bbox","margin","minX","minY","wrapSVG","body","boundingBox","svgBody","Strand","extractShape","addConfig","color","exportSVG","flipped","importSegment","json","importLoop","importFigure","contour","holes","importDiagram","importJSON","DEG2RAD","RAD2DEG","polarToCartesian","r","theta","x","y","cartesianToPolar"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pantograph2d",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Pantograph, the pure JS 2D CAD library",
5
5
  "type": "module",
6
6
  "main": "./dist/pantograph.cjs",
@@ -17,6 +17,10 @@
17
17
  "./models": {
18
18
  "import": "./dist/pantograph/models.js",
19
19
  "require": "./dist/pantograph/models.cjs"
20
+ },
21
+ "./drawShape": {
22
+ "import": "./dist/pantograph/drawShape.js",
23
+ "require": "./dist/pantograph/drawShape.cjs"
20
24
  }
21
25
  },
22
26
  "scripts": {
@@ -44,7 +48,7 @@
44
48
  "vite-plugin-dts": "^2.2.0",
45
49
  "vitest": "^0.29.2"
46
50
  },
47
- "gitHead": "46ec6506931df9c9e0b4de3e8045248715fd17d5",
51
+ "gitHead": "d24dc526d7990568852b06aef880d0162006ce37",
48
52
  "dependencies": {
49
53
  "-": "^0.0.1",
50
54
  "@types/flatbush": "^3.3.0",
@@ -1,4 +0,0 @@
1
- "use strict";function X(n,t,e,r){return n<=r&&t>=e}class T{constructor(t=1/0,e=1/0,r=-1/0,s=-1/0){this.xMin=t,this.yMin=e,this.xMax=r,this.yMax=s}get width(){return this.xMax-this.xMin}get height(){return this.yMax-this.yMin}contains(t){const[e,r]=t;return X(this.xMin,this.xMax,e,e)&&X(this.yMin,this.yMax,r,r)}overlaps(t){return X(this.xMin,this.xMax,t.xMin,t.xMax)&&X(this.yMin,this.yMax,t.yMin,t.yMax)}addPoint(t){const[e,r]=t;return new T(Math.min(this.xMin,e),Math.min(this.yMin,r),Math.max(this.xMax,e),Math.max(this.yMax,r))}merge(t){return new T(Math.min(this.xMin,t.xMin),Math.min(this.yMin,t.yMin),Math.max(this.xMax,t.xMax),Math.max(this.yMax,t.yMax))}}const ft=(n,t=1e-9)=>{let e=n;return Math.abs(n)<t&&(e=0),e.toFixed(-Math.log10(t))};function Z(n,t=1e-9){return Array.from(new Map(n.map(([e,r])=>[`[${ft(e,t)},${ft(r,t)}]`,[e,r]])).values())}const Mt=Math.PI/180,_=n=>`[${n[0]}, ${n[1]}]`,h=([n,t],[e,r],s=1e-9)=>Math.abs(n-e)<=s&&Math.abs(t-r)<=s,M=([n,t],[e,r])=>[n+e,t+r],S=([n,t],[e,r])=>[n-e,t-r],Y=([n,t])=>n*n+t*t,k=([n,t],e)=>[n*e,t*e],D=([n,t],[e,r]=[0,0])=>(n-e)**2+(t-r)**2,v=(n,t=[0,0])=>Math.sqrt(D(n,t));function F([n,t],[e,r]){return n*r-t*e}function st([n,t],[e,r]){return n*e+t*r}function V([n,t]){const e=v([n,t]);return[n/e,t/e]}function R(n,t){const e=Math.cos(t)*n,r=Math.sin(t)*n;return[e,r]}function St([n,t]){return Math.atan2(t,n)}function Bt(n){const t=v(n),e=St(n);return[t,e]}function yt(n,t,e=1e-9){const r=F(n,t),s=Y(n),i=Y(t);return r*r<s*i*e*e}function I(n){return[-n[1],n[0]]}function H(n){return[n[1],-n[0]]}const q=(n,t)=>{const[e,r,s,i,o,a,u,c,l]=n,[f,P,p,d,w,x,E,A,$]=t;return[e*f+r*d+s*E,e*P+r*w+s*A,e*p+r*x+s*$,i*f+o*d+a*E,i*P+o*w+a*A,i*p+o*x+a*$,u*f+c*d+l*E,u*P+c*w+l*A,u*p+c*x+l*$]};class C{constructor(){this._matrix=[1,0,0,0,1,0,0,0,1]}translate(t,e){return this._matrix=q(this._matrix,[1,0,t,0,1,e,0,0,1]),this}rotate(t,e){const r=Math.cos(t),s=Math.sin(t),i=[r,-s,0,s,r,0,0,0,1];return e&&this.translate(e[0],e[1]),this._matrix=q(this._matrix,i),e&&this.translate(-e[0],-e[1]),this}mirrorX(){return this._matrix=q(this._matrix,[1,0,0,0,-1,0,0,0,1]),this}mirrorY(){return this._matrix=q(this._matrix,[-1,0,0,0,1,0,0,0,1]),this}mirrorLine(t,e){const[r,s]=t,i=Math.atan2(s,r);return e&&this.translate(e[0],e[1]),this.rotate(i),this.mirrorX(),this.rotate(-i),e&&this.translate(-e[0],-e[1]),this}mirrorCenter(t){return t&&this.translate(t[0],t[1]),this._matrix=q(this._matrix,[-1,0,0,0,-1,0,0,0,1]),t&&this.translate(-t[0],-t[1]),this}scale(t,e){return e&&this.translate(e[0],e[1]),this._matrix=q(this._matrix,[t,0,0,0,t,0,0,0,1]),e&&this.translate(-e[0],-e[1]),this}transform(t){const[e,r]=t,[s,i,o,a,u,c]=this._matrix;return[s*e+i*r+o,a*e+u*r+c]}keepsOrientation(){const[t,,,,e]=this._matrix;return t*e>0}}class tt{translateX(t){const e=new C().translate(t,0);return this.transform(e)}translateY(t){const e=new C().translate(0,t);return this.transform(e)}translate(t,e){const r=new C().translate(t,e);return this.transform(r)}translateTo([t,e]){const r=new C().translate(t,e);return this.transform(r)}rotate(t,e){const r=new C().rotate(t*Mt,e);return this.transform(r)}scale(t,e){const r=new C().scale(t,e);return this.transform(r)}mirrorCenter(t){const e=new C().mirrorCenter(t);return this.transform(e)}mirror(t="x",e){const r=new C;return t==="x"?r.mirrorX():t==="y"?r.mirrorY():r.mirrorLine(t,e),this.transform(r)}}class At extends tt{constructor(t,e){super(),this.firstPoint=t,this.lastPoint=e,this.precision=1e-9,this.firstPoint=t,this.lastPoint=e}get repr(){return`${this.segmentType} ${_(this.firstPoint)} - ${_(this.lastPoint)}`}[Symbol.for("nodejs.util.inspect.custom")](){return this.repr}}class m extends At{constructor(){super(...arguments),this.segmentType="LINE",this._V=null,this._boundingBox=null}isValidParameter(t){const e=this.length*this.precision;return t>=-e&&1-t>=-e}paramPoint(t){return M(this.firstPoint,k(this.V,t))}get length(){return v(this.firstPoint,this.lastPoint)}get squareLength(){return D(this.firstPoint,this.lastPoint)}get V(){return this._V===null&&(this._V=S(this.lastPoint,this.firstPoint)),this._V}get midPoint(){return M(this.firstPoint,k(this.V,.5))}isSame(t){return t instanceof m?h(this.firstPoint,t.firstPoint)&&h(this.lastPoint,t.lastPoint)||h(this.lastPoint,t.firstPoint)&&h(this.firstPoint,t.lastPoint):!1}clone(){return new m(this.firstPoint,this.lastPoint)}reverse(){return new m(this.lastPoint,this.firstPoint)}get boundingBox(){return this._boundingBox===null&&(this._boundingBox=new T(Math.min(this.firstPoint[0],this.lastPoint[0])-this.precision,Math.min(this.firstPoint[1],this.lastPoint[1])-this.precision,Math.max(this.firstPoint[0],this.lastPoint[0])+this.precision,Math.max(this.firstPoint[1],this.lastPoint[1])+this.precision)),this._boundingBox}distanceFrom(t){const e=S(t,this.firstPoint),r=st(e,this.V)/this.squareLength;if(r<0)return v(t,this.firstPoint);if(r>1)return v(t,this.lastPoint);const s=this.paramPoint(r);return v(t,s)}isOnSegment(t){if(h(t,this.firstPoint,this.precision))return!0;const e=S(t,this.firstPoint);if(!yt(this.V,e))return!1;const r=st(e,this.V)/this.squareLength;return this.isValidParameter(r)}tangentAt(t){if(!this.isOnSegment(t))throw new Error("Point is not on segment");return V(this.V)}get normalVector(){return I(V(this.V))}get tangentAtFirstPoint(){return V(this.V)}get tangentAtLastPoint(){return V(this.V)}splitAt(t){let e;if(Array.isArray(t)&&t.length===0)return[this];Array.isArray(t[0])?e=t:e=[t],e.forEach(u=>{if(!this.isOnSegment(u))throw new Error(`Point ${_(u)} is not on segment ${this.repr}`)});const r=[this.firstPoint,...e,this.lastPoint],s=Z(r),i=this.lastPoint[0]-this.firstPoint[0];let o=Math.sign(i),a=0;return Math.abs(i)<this.precision&&(o=Math.sign(this.lastPoint[1]-this.firstPoint[1]),a=1),s.sort((u,c)=>o*(u[a]-c[a])),s.flatMap((u,c)=>c===s.length-1?[]:new m(u,s[c+1]))}transform(t){return new m(t.transform(this.firstPoint),t.transform(this.lastPoint))}}function Tt(n){return Array.from(Array(n).keys())}function B(n){const t=Math.min(...n.map(e=>e.length));return Tt(t).map(e=>n.map(r=>r[e]))}function et(n){return n<0?n+2*Math.PI:n>=2*Math.PI?n%(2*Math.PI):n}function gt(n,t,e){let r=t-n;return e&&(r=-r),r<0&&(r+=2*Math.PI),r}const W=(n,t,e)=>{const r=F(n.V,t.V),s=Y(n.V),i=Y(t.V),o=e?e*e:n.precision*t.precision;if(r*r<s*i*o)return"parallel";const a=S(t.firstPoint,n.firstPoint),u=F(a,t.V)/r,c=F(a,n.V)/r;return{intersectionParam1:u,intersectionParam2:c}};function bt(n,t,e=!1,r){const s=W(n,t,r);if(s==="parallel"){if(!e)return null;if(n.isSame(t))return n;const a=Z([t.isOnSegment(n.firstPoint)?n.firstPoint:null,t.isOnSegment(n.lastPoint)?n.lastPoint:null,n.isOnSegment(t.firstPoint)?t.firstPoint:null,n.isOnSegment(t.lastPoint)?t.lastPoint:null].filter(u=>u!==null)).sort((u,c)=>u[0]-c[0]);if(a.length===0)return null;if(a.length===1)return null;if(a.length===2)return new m(a[0],a[1]);throw console.error(a),new Error("Unexpected number of points while intersecting parallel lines")}const{intersectionParam1:i,intersectionParam2:o}=s;return!n.isValidParameter(i)||!t.isValidParameter(o)?null:n.paramPoint(i)}const z=(n,t)=>{const e=S(n,t);return Bt(e)};class g extends At{constructor(t,e,r,s=!1,{ignoreChecks:i=!1}={}){if(super(t,e),this.segmentType="ARC",this._angularLength=null,this._radius=null,this._firstAngle=null,this._lastAngle=null,this._boundingBox=null,this.center=r,this.clockwise=s,!i){if(h(t,e))throw new Error("Invalid arc, cannot be a full circle");if(Math.abs(this.radius-v(this.lastPoint,this.center))>this.precision)throw new Error("Invalid arc, radius does not match between start and end")}}isValidParameter(t){return 1-t>=-this.precision&&t>=-this.precision}angleToParam(t){return gt(this.firstAngle,et(t),this.clockwise)/this.angularLength}get angularLength(){return this._angularLength||(this._angularLength=gt(this.firstAngle,this.lastAngle,this.clockwise)),this._angularLength}paramPoint(t){return M(this.center,R(this.radius,this.firstAngle+t*this.angularLength*(this.clockwise?-1:1)))}pointToParam(t){const[e,r]=z(t,this.center);if(Math.abs(e-this.radius)>this.precision)throw new Error(`Point ${_(t)} is not on segment ${this.repr}`);const s=this.angleToParam(r);if(!this.isValidParameter(s))throw new Error(`Point ${_(t)} is not on segment ${this.repr}`);return s}get radius(){return this._radius===null&&(this._radius=v(this.firstPoint,this.center)),this._radius}get firstAngle(){if(this._firstAngle===null){const[t,e]=S(this.firstPoint,this.center);this._firstAngle=et(Math.atan2(e,t))}return this._firstAngle}get lastAngle(){if(this._lastAngle===null){const[t,e]=S(this.lastPoint,this.center);this._lastAngle=et(Math.atan2(e,t))}return this._lastAngle}get length(){return this.radius*this.angularLength}get squareLength(){return this.length*this.length}get midPoint(){return this.paramPoint(.5)}isSame(t){return!(t instanceof g)||!h(this.center,t.center)?!1:h(this.firstPoint,t.firstPoint)&&h(this.lastPoint,t.lastPoint)&&this.clockwise===t.clockwise||h(this.lastPoint,t.firstPoint)&&h(this.firstPoint,t.lastPoint)&&this.clockwise===!t.clockwise}clone(){return new g(this.firstPoint,this.lastPoint,this.center,this.clockwise)}reverse(){return new g(this.lastPoint,this.firstPoint,this.center,!this.clockwise)}get boundingBox(){if(this._boundingBox===null){const t=this.radius+this.precision,e=r=>this.isValidParameter(this.angleToParam(r));this._boundingBox=new T(e(Math.PI)?this.center[0]-t:Math.min(this.firstPoint[0],this.lastPoint[0])-this.precision,e(Math.PI*1.5)?this.center[1]-t:Math.min(this.firstPoint[1],this.lastPoint[1])-this.precision,e(0)?this.center[0]+t:Math.max(this.firstPoint[0],this.lastPoint[0])+this.precision,e(Math.PI/2)?this.center[1]+t:Math.max(this.firstPoint[1],this.lastPoint[1])+this.precision)}return this._boundingBox}distanceFrom(t){const[e,r]=z(t,this.center);return this.isValidParameter(this.angleToParam(r))?Math.abs(e-this.radius):Math.sqrt(Math.min(D(t,this.firstPoint),D(t,this.lastPoint)))}isOnSegment(t){const[e,r]=z(t,this.center);if(Math.abs(e-this.radius)>this.precision)return!1;const s=this.angleToParam(r);return this.isValidParameter(s)}tangentAt(t){const[e,r]=z(t,this.center);if(Math.abs(e-this.radius)>this.precision)throw new Error("Point is not on the arc");const s=this.angleToParam(r);if(!this.isValidParameter(s))throw new Error("Point is not on the arc");const i=R(1,r);return(this.clockwise?H:I)(V(i))}get tangentAtFirstPoint(){const t=R(1,this.firstAngle);return(this.clockwise?H:I)(V(t))}get tangentAtLastPoint(){const t=R(1,this.lastAngle);return(this.clockwise?H:I)(V(t))}splitAt(t){let e;if(Array.isArray(t)&&t.length===0)return[this];Array.isArray(t[0])?e=t:e=[t];const s=[0,1,...e.map(a=>this.pointToParam(a))],i=new Map(B([s,[this.firstPoint,this.lastPoint,...e]]));s.sort((a,u)=>a-u);let o=null;return s.flatMap((a,u)=>{if(u===s.length-1)return[];const c=s[u+1];if(c-a<this.precision)return o===null&&(o=a),[];const l=o===null?a:o,f=new g(i.get(l)||this.paramPoint(l),i.get(c)||this.paramPoint(c),this.center,this.clockwise);return o=null,f})}transform(t){return new g(t.transform(this.firstPoint),t.transform(this.lastPoint),t.transform(this.center),t.keepsOrientation()?this.clockwise:!this.clockwise)}}function _t(n,t,e){const r=new m(t,n),s=new m(t,e),i=I(r.tangentAtFirstPoint),o=I(s.tangentAtLastPoint),a=W({firstPoint:r.midPoint,V:i,precision:1e-9},{firstPoint:s.midPoint,V:o,precision:1e-9});if(a==="parallel")throw new Error("Cannot create an arc from three colinear points");const u=F(S(n,t),S(e,t))>0;return new g(n,e,M(r.midPoint,k(i,a.intersectionParam1)),u,{ignoreChecks:!0})}function $t(n,t,e){const r=new m(t,n),s=I(r.tangentAtFirstPoint),i=W({firstPoint:r.midPoint,V:s,precision:1e-9},{firstPoint:n,V:I(e),precision:1e-9});if(i==="parallel")throw new Error("Cannot create an arc from three colinear points");const o=M(r.midPoint,k(s,i.intersectionParam1)),a=F(S(o,n),M(n,e))>0;return new g(n,t,o,a,{ignoreChecks:!0})}function kt(n,t){const e=S(t,n.firstPoint),r=st(e,n.V)/n.squareLength;return n.paramPoint(r)}function U(n,t,e){const r=e||n.precision,s=kt(n,t.center),i=v(s,t.center);if(i>t.radius+r)return[];if(Math.abs(i-t.radius)<r){const f=s;return n.isOnSegment(f)&&t.isOnSegment(f)?[f]:[]}const o=[],a=Math.sqrt(t.radius*t.radius-i*i),u=n.tangentAtFirstPoint,c=M(s,k(u,a));n.isOnSegment(c)&&t.isOnSegment(c)&&o.push(c);const l=M(s,k(u,-a));return n.isOnSegment(l)&&t.isOnSegment(l)&&o.push(l),o}const qt=n=>{const{firstPoint:t,lastPoint:e,center:r,clockwise:s}=n;return new g(e,t,r,s,{ignoreChecks:!0})},Dt=(n,t)=>{if(n.isSame(t))return[n];const e=Z([t.isOnSegment(n.firstPoint)?n.firstPoint:null,t.isOnSegment(n.lastPoint)?n.lastPoint:null,n.isOnSegment(t.firstPoint)?t.firstPoint:null,n.isOnSegment(t.lastPoint)?t.lastPoint:null].filter(r=>r!==null)).sort((r,s)=>n.pointToParam(r)-n.pointToParam(s));if(e.length===0)return[];if(e.length===1)return[];if(e.length===2)return n.isSame(qt(t))?[]:[new g(e[0],e[1],n.center,n.clockwise)];if(e.length===3){const r=h(e[0],t.lastPoint)||h(e[0],t.firstPoint)?1:0;return[new g(e[0+r],e[1+r],n.center,n.clockwise)]}else if(e.length===4)return[new g(e[0],e[1],n.center,n.clockwise),new g(e[2],e[3],n.center,n.clockwise)];throw new Error("Bug in the arc arc overlap algorithm")};function ut(n,t,e=!1,r){const s=r||n.precision,i=v(n.center,t.center),o=n.radius+t.radius;if(i>o+s)return[];const a=Math.abs(n.radius-t.radius);if(i<a-s)return[];if(i<s)return a>s?[]:e?Dt(n,t):[];const u=V(S(t.center,n.center)),c=i>o-s;if(c||Math.abs(i-a)<s){const E=c||n.radius>t.radius?1:-1,A=M(n.center,k(u,E*n.radius));return n.isOnSegment(A)&&t.isOnSegment(A)?[A]:[]}const l=n.radius*n.radius/(2*i)-t.radius*t.radius/(2*i)+i/2,f=M(n.center,k(u,l)),P=Math.sqrt(n.radius*n.radius-l*l),p=I(u),d=M(f,k(p,P)),w=M(f,k(p,-P)),x=[];return n.isOnSegment(d)&&t.isOnSegment(d)&&x.push(d),n.isOnSegment(w)&&t.isOnSegment(w)&&x.push(w),x}function jt(n,t,e){if(n instanceof m&&t instanceof m){const r=bt(n,t,!1,e);return r===null?[]:[r]}if(n instanceof m&&t instanceof g)return U(n,t,e);if(n instanceof g&&t instanceof m)return U(t,n,e);if(n instanceof g&&t instanceof g)return ut(n,t,!1,e);throw new Error("Not implemented")}function nt(n,t,e){if(n instanceof m&&t instanceof m){const r=bt(n,t,!0,e);return r===null?{intersections:[],overlaps:[],count:0}:r instanceof m?{intersections:[],overlaps:[r],count:1}:{intersections:[r],overlaps:[],count:1}}if(!n.boundingBox.overlaps(t.boundingBox))return{intersections:[],overlaps:[],count:0};if(n instanceof m&&t instanceof g){const r=U(n,t,e);return{intersections:r,overlaps:[],count:r.length}}if(n instanceof g&&t instanceof m){const r=U(t,n,e);return{intersections:r,overlaps:[],count:r.length}}if(n instanceof g&&t instanceof g){const r=ut(n,t,!0,e);return r.length?r[0]instanceof g?{intersections:[],overlaps:r,count:r.length}:{intersections:r,overlaps:[],count:r.length}:{intersections:[],overlaps:[],count:0}}throw new Error("Not implemented")}function vt(n){const t=[];for(let e=0;e<n;e++)for(let r=0;r<=e;r++)t.push([e,r]);return t}function*it(n){for(const[t,e]of vt(n.length))t!==e&&(yield[n[t],n[e]])}class y extends tt{constructor(t,e=[],{ignoreChecks:r=!1}={}){super(),r||Nt(t,e),this.contour=t,this.holes=e}get boundingBox(){return this.contour.boundingBox}get isFull(){return this.holes.length===0}get allLoops(){return[this.contour,...this.holes]}clone(){return new y(this.contour.clone(),this.holes.map(t=>t.clone()))}transform(t){return new y(this.contour.transform(t),this.holes.map(e=>e.transform(t)))}contains(t){return this.contour.contains(t)&&!this.holes.some(e=>e.contains(t))}intersects(t){return this.allLoops.some(e=>t.allLoops.some(r=>e.intersects(r)))}}function Nt(n,t=[]){if(!n)throw new Error("Figure must have a contour");for(const[e,r]of it([n,...t]))if(e.intersects(r))throw new Error("Loops in a figure must not intersect");if(t.some(e=>!n.contains(e.firstPoint)))throw new Error("Holes must be inside the contour");for(const[e,r]of it(t))if(e.contains(r.firstPoint))throw console.error(at(e),at(r)),new Error("Holes must not be inside other holes")}const Rt=n=>{const t=n.map((s,i)=>n.slice(i+1).map((o,a)=>[a+i+1,o]).filter(([,o])=>s.boundingBox.overlaps(o.boundingBox)).map(([o])=>o)),e=[],r=Array(t.length);return t.forEach((s,i)=>{let o=r[i];o||(o=[],e.push(o)),o.push(n[i]),s.length&&s.forEach(a=>{r[a]=o})}),e},It=n=>n.map((t,e)=>{const s=t.segments[0].midPoint,i=n.filter((o,a)=>e===a?!1:o.contains(s));return{loop:t,isIn:i}}),Gt=(n,t)=>n.flatMap(({loop:e})=>ct(t.filter(({loop:r,isIn:s})=>r===e||s.indexOf(e)!==-1))),Ut=(n,t)=>{const e=t.filter(({isIn:s})=>s.length<=1),r=ct(It(n.map(({loop:s})=>s)));return[e,...r]},ct=n=>{if(!n.length)return[];const t=n.filter(({isIn:r})=>!r.length),e=n.filter(({isIn:r})=>r.length>1);return t.length===1&&e.length===0?[n]:t.length>1?Gt(t,n):Ut(e,n)};function G(n){return Rt(n).map(It).flatMap(ct).map(e=>{if(e.length===1)return new y(e[0].loop);e.sort((i,o)=>i.isIn.length-o.isIn.length);const[r,...s]=e.map(({loop:i})=>i);return new y(r,s)})}function Wt(n,t){const e=[];for(const r of n)for(const s of t)e.push([r,s]);return e}class Ct extends tt{constructor(t,{ignoreChecks:e=!1}={}){super(),this._boundingBox=null,e||Vt(t),this.segments=t}get repr(){return this.segments.map(t=>t.repr).join(`
2
- `)+`
3
- `}get firstPoint(){return this.segments[0].firstPoint}get lastPoint(){return this.segments[this.segments.length-1].lastPoint}get segmentsCount(){return this.segments.length}onStroke(t){return this.segments.some(e=>e.isOnSegment(t))}intersects(t){return this.boundingBox.overlaps(t.boundingBox)?this.segments.some(e=>t.segments.some(r=>nt(e,r).count>0)):!1}get boundingBox(){if(this._boundingBox===null){let t=this.segments[0].boundingBox;this.segments.slice(1).forEach(e=>{t=t.merge(e.boundingBox)}),this._boundingBox=t}return this._boundingBox}[Symbol.for("nodejs.util.inspect.custom")](){return this.repr}}function Xt(n,t="Stroke"){vt(n.length).forEach(([e,r])=>{if(e===r)return;const s=n[e],i=n[r],o=nt(s,i);if(o.count!==0){if(o.count===1&&!o.overlaps.length){const a=e-r,u=o.intersections[0];if(a===1&&h(s.firstPoint,u)||a===-1&&h(s.lastPoint,u)||a===n.length-1&&h(s.lastPoint,u)&&h(i.firstPoint,u)||-a===n.length-1&&h(s.firstPoint,u)&&h(i.lastPoint,u))return}throw new Error(`${t} segments must not intersect, but segments ${s.repr} and ${i.repr} do`)}})}function Vt(n,t="Stroke"){if(n.length===0)throw new Error(`${t} must have at least one segment`);B([n.slice(0,-1),n.slice(1)]).forEach(([e,r])=>{if(!h(e.lastPoint,r.firstPoint))throw new Error(`${t} segments must be connected, but ${e.repr} and ${r.repr} are not`)}),Xt(n,t)}function mt(n,t){return!!(n instanceof m&&t instanceof m&&yt(n.V,t.V)||n instanceof g&&t instanceof g&&h(n.center,t.center)&&n.radius-t.radius<n.precision)}function Pt(n,t){if(n instanceof m&&t instanceof m)return new m(n.firstPoint,t.lastPoint);if(n instanceof g&&t instanceof g)return new g(n.firstPoint,t.lastPoint,n.center,n.clockwise);throw new Error("Not implemented")}function Et(n){let t=!1;const e=[];for(const r of n.segments){if(e.length===0){e.push(r);continue}const s=e[e.length-1];mt(s,r)?(t=!0,e.pop(),e.push(Pt(s,r))):e.push(r)}if(h(n.firstPoint,n.lastPoint)&&mt(e[0],e[e.length-1])){t=!0;const r=e.pop();e[0]=Pt(r,e[0])}return t?e:null}class b extends Ct{constructor(){super(...arguments),this.strokeType="STRAND"}reverse(){const t=this.segments.map(e=>e.reverse());return t.reverse(),new b(t,{ignoreChecks:!0})}clone(){return new b(this.segments.map(t=>t.clone()),{ignoreChecks:!0})}extend(t){if(!h(this.lastPoint,t.firstPoint))throw console.error(this.repr,t.repr),new Error("Cannot extend strand: connection point is not the same");return new b([...this.segments,...t.segments])}simplify(){const t=Et(this);return t?new b(t,{ignoreChecks:!0}):this}transform(t){return new b(this.segments.map(e=>e.transform(t)),{ignoreChecks:!0})}}const zt=(n,t)=>{const e=W(t,{V:[1,0],firstPoint:n,precision:t.precision});if(e==="parallel")return 0;const{intersectionParam1:r,intersectionParam2:s}=e;if(!t.isValidParameter(r)||s<=-t.precision)return 0;if(Math.abs(r)<t.precision||Math.abs(r-1)<t.precision){const[,i]=t.midPoint;return n[1]-i<0?1:0}return 1},Ht=(n,t)=>{const e=t.precision,r=Math.abs(n[1]-t.center[1]);if(r>t.radius+e)return 0;const s=D(n,t.center),i=t.radius*t.radius,o=e*e;if(Math.abs(s-i)<o)return 0;const a=s-i>o;if(a&&t.center[0]<n[0])return 0;const u=Math.sqrt(t.radius*t.radius-r*r);let c=0;const l=f=>{t.isOnSegment(f)&&(h(f,t.firstPoint)?c+=t.tangentAtFirstPoint[1]>0?1:0:h(f,t.lastPoint)?c+=t.tangentAtLastPoint[1]>0?0:1:c+=1)};return l([t.center[0]+u,n[1]]),a&&l([t.center[0]-u,n[1]]),c};function Yt(n,t){if(t instanceof m)return zt(n,t);if(t instanceof g)return Ht(n,t);throw new Error("Not implemented")}class L extends Ct{constructor(t,{ignoreChecks:e=!1}={}){super(t,{ignoreChecks:!0}),this.strokeType="LOOP",this._clockwise=null,e||Jt(t)}get clockwise(){if(this._clockwise===null){const t=this.segments.flatMap(r=>r instanceof m?[r.firstPoint]:[r.firstPoint,r.paramPoint(.5)]),e=t.map((r,s)=>{const i=t[(s+1)%t.length];return(i[0]-r[0])*(i[1]+r[1])}).reduce((r,s)=>r+s,0);this._clockwise=e>0}return this._clockwise}clone(){return new L(this.segments.map(t=>t.clone()),{ignoreChecks:!0})}reverse(){const t=this.segments.map(e=>e.reverse());return t.reverse(),new L(t,{ignoreChecks:!0})}transform(t){return new L(this.segments.map(e=>e.transform(t)),{ignoreChecks:!0})}contains(t){return this.onStroke(t)||!this.boundingBox.contains(t)?!1:this.segments.reduce((r,s)=>r+Yt(t,s),0)%2===1}simplify(){const t=Et(this);return t?new L(t,{ignoreChecks:!0}):this}}function Jt(n){if(Vt(n,"Loop"),!h(n[0].firstPoint,n[n.length-1].lastPoint))throw new Error("Loop segment must be closed")}const pt=(n,t)=>{const e=n.findIndex(i=>h(t,i.firstPoint)),r=n.slice(0,e);return n.slice(e).concat(r)},dt=(n,t)=>{let e=n;const r=a=>h(a.firstPoint,t.firstPoint)&&h(a.lastPoint,t.lastPoint);let s=n.findIndex(r);if(s===-1){const a=n.map(u=>u.reverse());if(a.reverse(),s=a.findIndex(r),s===-1)throw console.error(a.map(u=>u.repr),t.repr),new Error("Failed to rotate to segment start");e=a}const i=e.slice(0,s);return e.slice(s).concat(i)};function*wt(n,t,e){const r=o=>t.some(a=>h(a,o.lastPoint)),s=o=>e.some(a=>o.isSame(a));let i=[];for(const o of n)r(o)?(i.push(o),yield new b(i,{ignoreChecks:!0}),i=[]):s(o)?(i.length&&(yield new b(i,{ignoreChecks:!0}),i=[]),yield new b([o],{ignoreChecks:!0})):i.push(o);i.length&&(yield new b(i,{ignoreChecks:!0}))}function Kt(n,t,e){return n.filter(r=>{const s=t.filter(a=>h(a.firstPoint,r)||h(a.lastPoint,r));if(s.length%2)throw new Error("Bug in the intersection algo on non crossing point");const i=s.map(a=>e.contains(a.midPoint));return!(i.every(a=>a)||!i.some(a=>a))})}function Qt(n,t,e){let r=[];const s=[],i=new Array(n.segments.length).fill(0).map(()=>[]),o=new Array(t.segments.length).fill(0).map(()=>[]);if(n.segments.forEach((P,p)=>{t.segments.forEach((d,w)=>{const{intersections:x,overlaps:E}=nt(P,d,e);r.push(...x),i[p].push(...x),o[w].push(...x),s.push(...E);const A=E.flatMap($=>[$.firstPoint,$.lastPoint]);r.push(...A),i[p].push(...A),o[w].push(...A)})}),r=Z(r,e),!r.length||r.length===1)return null;const a=([P,p])=>p.length?P.splitAt(p):[P];let u=B([n.segments,i]).flatMap(a),c=B([t.segments,o]).flatMap(a);if(r=Kt(r,u,t),!r.length&&!s.length)return null;if(s.length){const P=s[0];u=dt(u,P),c=dt(c,P)}else{const P=r[0];u=pt(u,P),c=pt(c,P)}const l=Array.from(wt(u,r,s));let f=Array.from(wt(c,r,s));return(!h(f[0].lastPoint,l[0].lastPoint)||s.length>0&&f[0].segmentsCount!==1)&&(f=f.reverse().map(P=>P.reverse())),B([l,f]).map(([P,p])=>P.segmentsCount===1&&s.some(d=>P.segments[0].isSame(d))?[P,"same"]:[P,p])}function rt(n){let t=n[0];for(const e of n.slice(1))t=t.extend(e);if(!h(t.firstPoint,t.lastPoint))throw console.error(_(t.firstPoint),_(t.lastPoint)),new Error("Bug in the intersection algo on non closing strand");return new L(t.segments)}function Zt(n){if(!n.length)return[];const t=n.map(o=>o.firstPoint);let e=n.map(o=>o.lastPoint);e=e.slice(-1).concat(e.slice(0,-1));const r=B([t,e]).flatMap(([o,a],u)=>h(o,a)?[]:u);if(!r.length)return[rt(n)];const s=B([r.slice(0,-1),r.slice(1)]).map(([o,a])=>rt(n.slice(o,a)));let i=n.slice(r[r.length-1]);return r[0]!==0&&(i=i.concat(n.slice(0,r[0]))),s.push(rt(i)),s}const xt=(n,t)=>{if(n.length===0)return[t];const e=n.at(-1);return h(e.lastPoint,t.firstPoint)?n.slice(0,-1).concat([e.extend(t)]):h(e.lastPoint,t.lastPoint)?n.slice(0,-1).concat([e.extend(t.reverse())]):n.concat([t])},tn=(n,t)=>n.length===0?[t]:h(n[0].firstPoint,t.lastPoint)?[t.extend(n[0])].concat(n.slice(1)):[t].concat(n);function lt(n,t,{firstInside:e,secondInside:r}){const s=Qt(n,t);if(!s){const u=n.segments[0].midPoint,c=t.contains(u),l=t.segments[0].midPoint,f=n.contains(l);return{identical:!1,firstCurveInSecond:c,secondCurveInFirst:f}}if(s.every(([,u])=>u==="same"))return{identical:!0};let i=null,o=null;const a=s.flatMap(([u,c])=>{let l=[],f=0;if(c==="same")return o===1?(o=1,u):o===2||o===0?(o=null,[]):o===null?(i?i=i.extend(u):i=u,[]):(console.error("weird situation"),[]);const P=u.segments[0].midPoint,p=t.contains(P);(e==="keep"&&p||e==="remove"&&!p)&&(f+=1,l=xt(l,u));const d=c.segments[0].midPoint,w=n.contains(d);if(r==="keep"&&w||r==="remove"&&!w){const x=c;f+=1,f===2&&l.length?(l=xt(l,x),i=null):l=[x]}return o===null&&f===1&&i&&(l=tn(l,i)),f===1&&(o=f,i=null),l.length?l:(i=null,[])});return Zt(a)}const nn=(n,t)=>{const e=lt(n,t,{firstInside:"remove",secondInside:"remove"});return Array.isArray(e)?e:e.identical?[n]:e.firstCurveInSecond?[t]:e.secondCurveInFirst?[n]:[n,t]},J=(n,t)=>{const e=lt(n,t,{firstInside:"remove",secondInside:"keep"});return Array.isArray(e)?e:e.identical?[]:e.firstCurveInSecond?[]:e.secondCurveInFirst?[n,t]:[n]},ht=(n,t)=>{const e=lt(n,t,{firstInside:"keep",secondInside:"keep"});return Array.isArray(e)?e:e.identical?[n]:e.firstCurveInSecond?[n]:e.secondCurveInFirst?[t]:[]};function en(n){const t=new Map,e=[];return n.forEach((r,s)=>{let i;t.has(s)?i=t.get(s):(i={current:[r],fusedWith:new Set([s])},e.push(i)),n.slice(s+1).forEach((o,a)=>{const u=i.current,c=s+a+1;if(i.fusedWith.has(c))return;let l=[o],f=!1;if(t.has(c)&&(l=t.get(c).current,f=!0),!u.some(d=>l.some(w=>d.intersects(w))))return;let p;u.length>1||l.length>1?p=j(u,l):p=Ot(u[0],l[0]),i.fusedWith.add(c),i.current=p,f||t.set(c,i)})}),e.flatMap(({current:r})=>r)}function Ot(n,t){const e=nn(n.contour,t.contour),r=t.holes.flatMap(o=>J(o,n.contour)),s=n.holes.flatMap(o=>J(o,t.contour)),i=Wt(n.holes,t.holes).flatMap(([o,a])=>ht(o,a));return G([...e,...r,...s,...i])}function K(n,t){if(n.isFull&&t.isFull)return G(J(n.contour,t.contour));if(n.isFull){const r=J(n.contour,t.contour),s=t.holes.flatMap(i=>ht(i,n.contour));return G([...r,...s])}else if(t.isFull&&!n.contour.intersects(t.contour))if(n.contour.contains(t.contour.firstPoint)){const r=j(n.holes.map(s=>new y(s)),[t]);return G([n.contour,...r.flatMap(s=>s.allLoops)])}else return[n];let e=K(new y(n.contour),t);return n.holes.forEach(r=>{e=e.flatMap(s=>K(s,new y(r)))}),e}function rn(n,t){const e=ht(n.contour,t.contour);if(!e.length)return[];let r=G(e);return r=N(r,n.holes.map(s=>new y(s))),N(r,t.holes.map(s=>new y(s)))}function j(n,t){if(!n.length)return t;if(!t.length)return n;if(n.length===1&&t.length>1||t.length===1&&n.length>1)return en([...n,...t]);if(n.length>1&&t.length>1){let e=j([n[0]],t);return n.slice(1).forEach(r=>{e=j([r],e)}),e}return n.length===1&&t.length===1?Ot(n[0],t[0]):[]}function N(n,t){if(!n.length)return[];if(!t.length)return n;if(n.length===1&&t.length===1)return K(n[0],t[0]);if(n.length>1)return n.flatMap(r=>N([r],t));let e=K(n[0],t[0]);return t.slice(1).forEach(r=>{e=N(e,[r])}),e}function Q(n,t){return!n.length||!t.length?[]:n.length===1&&t.length===1?rn(n[0],t[0]):n.length>1?n.flatMap(e=>Q([e],t)):t.flatMap(e=>Q(n,[e]))}class O extends tt{constructor(t=[],{ignoreChecks:e=!1}={}){super(),this._boundingBox=null,e||sn(t),this.figures=t}get isEmpty(){return this.figures.length===0}get boundingBox(){if(this.isEmpty)return new T;if(this._boundingBox===null){let t=this.figures[0].boundingBox;for(const e of this.figures.slice(1))t=t.merge(e.boundingBox);this._boundingBox=t}return this._boundingBox}clone(){return new O(this.figures.map(t=>t.clone()))}transform(t){return new O(this.figures.map(e=>e.transform(t)))}contains(t){return this.figures.some(e=>e.contains(t))}intersects(t){return this.figures.some(e=>t.figures.some(r=>e.intersects(r)))}fuse(t){return new O(j(this.figures,t.figures))}cut(t){return new O(N(this.figures,t.figures))}intersect(t){return new O(Q(this.figures,t.figures))}}function sn(n){for(const[t,e]of it(n))if(t.intersects(e))throw new Error("Diagram figures must not intersect")}function Lt(n){if(n instanceof m)return{type:n.segmentType,firstPoint:n.firstPoint,lastPoint:n.lastPoint};if(n instanceof g)return{type:n.segmentType,firstPoint:n.firstPoint,lastPoint:n.lastPoint,center:n.center,clockwise:n.clockwise};throw new Error("Unknown segment type")}function ot(n){return{type:"LOOP",segments:n.segments.map(Lt)}}function Ft(n){return{type:"FIGURE",contour:ot(n.contour),holes:n.holes.map(ot)}}function on(n){return{type:"DIAGRAM",figures:n.figures.map(Ft)}}function at(n){if(n instanceof O)return on(n);if(n instanceof y)return Ft(n);if(n instanceof L)return ot(n);if(n instanceof g||n instanceof m)return Lt(n);throw new Error("Unknown shape type")}exports.Arc=g;exports.BoundingBox=T;exports.DEG2RAD=Mt;exports.Diagram=O;exports.Figure=y;exports.Line=m;exports.Loop=L;exports.Strand=b;exports.TransformationMatrix=C;exports.add=M;exports.arcArcIntersection=ut;exports.crossProduct=F;exports.cutFiguresLists=N;exports.distance=v;exports.exportJSON=at;exports.findIntersections=jt;exports.findIntersectionsAndOverlaps=nt;exports.fuseFiguresLists=j;exports.intersectFiguresLists=Q;exports.lineArcIntersection=U;exports.lineLineParams=W;exports.normalize=V;exports.perpendicular=I;exports.perpendicularClockwise=H;exports.polarAngle=St;exports.polarToCartesian=R;exports.projectPointOnLine=kt;exports.sameVector=h;exports.scalarMultiply=k;exports.squareDistance=D;exports.subtract=S;exports.tangentArc=$t;exports.threePointsArc=_t;
4
- //# sourceMappingURL=exportJSON-944c662d.cjs.map