pattapatta 0.2.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.
- package/CHANGELOG.md +11 -0
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/circle-BDbKfrdR.d.ts +12 -0
- package/dist/circlePacking/index.d.ts +78 -0
- package/dist/circlePacking/index.js +381 -0
- package/dist/circlePacking/index.js.map +1 -0
- package/dist/cli.js +365 -0
- package/dist/cli.js.map +1 -0
- package/dist/construction/index.d.ts +26 -0
- package/dist/construction/index.js +102 -0
- package/dist/construction/index.js.map +1 -0
- package/dist/contour/index.d.ts +20 -0
- package/dist/contour/index.js +118 -0
- package/dist/contour/index.js.map +1 -0
- package/dist/conversion/index.d.ts +31 -0
- package/dist/conversion/index.js +99 -0
- package/dist/conversion/index.js.map +1 -0
- package/dist/group-BNjVVYSQ.d.ts +13 -0
- package/dist/hatch/index.d.ts +41 -0
- package/dist/hatch/index.js +253 -0
- package/dist/hatch/index.js.map +1 -0
- package/dist/hull/index.d.ts +16 -0
- package/dist/hull/index.js +97 -0
- package/dist/hull/index.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.js +3933 -0
- package/dist/index.js.map +1 -0
- package/dist/meshing/index.d.ts +125 -0
- package/dist/meshing/index.js +1333 -0
- package/dist/meshing/index.js.map +1 -0
- package/dist/morphology/index.d.ts +58 -0
- package/dist/morphology/index.js +268 -0
- package/dist/morphology/index.js.map +1 -0
- package/dist/optimisation/index.d.ts +43 -0
- package/dist/optimisation/index.js +400 -0
- package/dist/optimisation/index.js.map +1 -0
- package/dist/path-0RjhYjJs.d.ts +21 -0
- package/dist/pointSet/index.d.ts +24 -0
- package/dist/pointSet/index.js +139 -0
- package/dist/pointSet/index.js.map +1 -0
- package/dist/polygonisation/index.d.ts +44 -0
- package/dist/polygonisation/index.js +310 -0
- package/dist/polygonisation/index.js.map +1 -0
- package/dist/predicates/index.d.ts +35 -0
- package/dist/predicates/index.js +159 -0
- package/dist/predicates/index.js.map +1 -0
- package/dist/processing/index.d.ts +54 -0
- package/dist/processing/index.js +457 -0
- package/dist/processing/index.js.map +1 -0
- package/dist/segment-BKuIFMKD.d.ts +10 -0
- package/dist/segmentSet/index.d.ts +25 -0
- package/dist/segmentSet/index.js +109 -0
- package/dist/segmentSet/index.js.map +1 -0
- package/dist/shapeBoolean/index.d.ts +41 -0
- package/dist/shapeBoolean/index.js +211 -0
- package/dist/shapeBoolean/index.js.map +1 -0
- package/dist/svg/index.d.ts +38 -0
- package/dist/svg/index.js +317 -0
- package/dist/svg/index.js.map +1 -0
- package/dist/tiling/index.d.ts +32 -0
- package/dist/tiling/index.js +344 -0
- package/dist/tiling/index.js.map +1 -0
- package/dist/transformation/index.d.ts +37 -0
- package/dist/transformation/index.js +184 -0
- package/dist/transformation/index.js.map +1 -0
- package/dist/triangulation/index.d.ts +48 -0
- package/dist/triangulation/index.js +334 -0
- package/dist/triangulation/index.js.map +1 -0
- package/dist/vec2-CWyXN1Wj.d.ts +10 -0
- package/dist/voronoi/index.d.ts +31 -0
- package/dist/voronoi/index.js +211 -0
- package/dist/voronoi/index.js.map +1 -0
- package/package.json +165 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/vec2.ts","../../src/types/circle.ts","../../src/types/path.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/circlePacking/index.ts"],"names":["path"],"mappings":"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","file":"index.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\n\n/** Circle with center (x, y) and radius r (PGS often stored radius in PVector.z). */\nexport type Circle = {\n x: number\n y: number\n r: number\n}\n\nexport function circle(x: number, y: number, r: number): Circle {\n return { x, y, r }\n}\n\nexport function circleCenter(c: Circle): Vec2 {\n return { x: c.x, y: c.y }\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import {\n FillRule,\n areaD,\n differenceD,\n intersectD,\n isPositiveD,\n pointInPolygonD,\n PointInPolygonResult,\n unionD,\n xorD,\n type PathD,\n type PathsD,\n type PointD,\n} from 'clipper2-ts'\nimport type { Group, Path, Ring, Vec2 } from '../types/index.js'\nimport { group, normalizeRing, path, vec2 } from '../types/index.js'\n\nexport const DEFAULT_FILL_RULE = FillRule.NonZero\n\nexport function ringToPathD(ring: Ring): PathD {\n const pts: PointD[] = []\n for (const v of normalizeRing(ring)) {\n pts.push({ x: v.x, y: v.y, z: 0 })\n }\n return pts\n}\n\n/** Closed path → Clipper subject/clip paths (exterior + holes). */\nexport function pathToPathsD(p: Path): PathsD {\n if (!p.closed || p.rings.length === 0) {\n throw new Error('Boolean ops require a closed path with at least one ring')\n }\n return p.rings.map((ring) => ringToPathD(ring))\n}\n\nexport function pathsDToGroup(paths: PathsD): Group {\n if (paths.length === 0) return group([])\n\n const outers: { ring: Ring; holes: Ring[] }[] = []\n const holes: Ring[] = []\n\n for (const pd of paths) {\n const ring = pathDToRing(pd)\n if (ring.length < 3) continue\n if (isPositiveD(pd)) {\n outers.push({ ring, holes: [] })\n } else {\n holes.push(ring)\n }\n }\n\n for (const hole of holes) {\n const sample = hole[0]\n if (!sample) continue\n let assigned = false\n for (const outer of outers) {\n if (pointInRing(sample, outer.ring)) {\n outer.holes.push(hole)\n assigned = true\n break\n }\n }\n if (!assigned) {\n // Treat unmatched negative rings as their own outers (orientation flip).\n outers.push({ ring: [...hole].reverse(), holes: [] })\n }\n }\n\n return group(outers.map((o) => path([o.ring, ...o.holes], true)))\n}\n\nexport function pathDToRing(pd: PathD): Ring {\n return normalizeRing(pd.map((p) => vec2(p.x, p.y)))\n}\n\nexport function pointInRing(point: Vec2, ring: Ring): boolean {\n const result = pointInPolygonD(\n { x: point.x, y: point.y, z: 0 },\n ringToPathD(ring),\n )\n return (\n result === PointInPolygonResult.IsInside ||\n result === PointInPolygonResult.IsOn\n )\n}\n\nexport function clipUnion(a: PathsD, b: PathsD): PathsD {\n return unionD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipIntersect(a: PathsD, b: PathsD): PathsD {\n return intersectD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipDifference(a: PathsD, b: PathsD): PathsD {\n return differenceD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipXor(a: PathsD, b: PathsD): PathsD {\n return xorD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function pathsArea(paths: PathsD): number {\n let sum = 0\n for (const p of paths) {\n sum += Math.abs(areaD(p))\n }\n return sum\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { vec2 } from '../types/index.js'\nimport {\n pathToPathsD,\n pathsArea,\n pointInRing,\n} from '../clipper/convert.js'\n\n/** Signed area of a closed ring (shoelace). */\nexport function ringArea(ring: Vec2[]): number {\n if (ring.length < 3) return 0\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\n/** Absolute area of a closed path (exterior minus holes). */\nexport function area(p: Path): number {\n if (!p.closed || p.rings.length === 0) return 0\n try {\n return pathsArea(pathToPathsD(p))\n } catch {\n let total = 0\n for (let i = 0; i < p.rings.length; i++) {\n const a = Math.abs(ringArea(p.rings[i]!))\n total += i === 0 ? a : -a\n }\n return Math.max(0, total)\n }\n}\n\nexport function areaGroup(g: Group): number {\n return g.paths.reduce((sum, p) => sum + area(p), 0)\n}\n\n/** Centroid of a closed exterior ring (ignores holes for Phase 2). */\nexport function centroid(p: Path): Vec2 {\n const ring = p.rings[0]\n if (!ring || ring.length === 0) return vec2(0, 0)\n const a = ringArea(ring)\n if (Math.abs(a) < 1e-12) {\n let sx = 0\n let sy = 0\n for (const v of ring) {\n sx += v.x\n sy += v.y\n }\n return vec2(sx / ring.length, sy / ring.length)\n }\n let cx = 0\n let cy = 0\n for (let i = 0; i < ring.length; i++) {\n const p0 = ring[i]!\n const p1 = ring[(i + 1) % ring.length]!\n const cross = p0.x * p1.y - p1.x * p0.y\n cx += (p0.x + p1.x) * cross\n cy += (p0.y + p1.y) * cross\n }\n return vec2(cx / (6 * a), cy / (6 * a))\n}\n\nexport function containsPoint(p: Path, point: Vec2): boolean {\n if (!p.closed || !p.rings[0]) return false\n if (!pointInRing(point, p.rings[0])) return false\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && pointInRing(point, hole)) return false\n }\n return true\n}\n\nexport function bounds(p: Path): {\n minX: number\n minY: number\n maxX: number\n maxY: number\n} {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n if (!Number.isFinite(minX)) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 }\n }\n return { minX, minY, maxX, maxY }\n}\n\nexport function width(p: Path): number {\n const b = bounds(p)\n return b.maxX - b.minX\n}\n\nexport function height(p: Path): number {\n const b = bounds(p)\n return b.maxY - b.minY\n}\n\n/** Rough polygon similarity via absolute area difference relative to max area. */\nexport function areaSimilarity(a: Path, b: Path): number {\n const aa = area(a)\n const bb = area(b)\n const denom = Math.max(aa, bb, 1e-12)\n return 1 - Math.abs(aa - bb) / denom\n}\n\nexport const predicates = {\n area,\n areaGroup,\n ringArea,\n centroid,\n containsPoint,\n bounds,\n width,\n height,\n areaSimilarity,\n}\n","import type { Circle, Path, Vec2 } from '../types/index.js'\nimport { circle } from '../types/index.js'\nimport { bounds, containsPoint } from '../predicates/index.js'\n\n/**\n * Lattice inclusion mode.\n * - `overlap` (default): full-path fill — keep disks that overlap the path;\n * center the lattice so opposite-edge cutoffs match. Clip in SVG to cut at\n * the boundary (including holes).\n * - `contained`: keep only disks fully inside the path (when you must stroke\n * complete circles); lattice centered with equal leftover margins.\n */\nexport type LatticePackMode = 'overlap' | 'contained'\n\n/**\n * Square lattice of equal circles.\n * @see docs/decisions/0003-deferred-circle-packing.md\n */\nexport function squareLatticePack(\n path: Path,\n diameter: number,\n mode: LatticePackMode = 'overlap',\n): Circle[] {\n const d = Math.max(diameter, 0.1)\n const r = d / 2\n const b = bounds(path)\n const out: Circle[] = []\n const accept =\n mode === 'contained' ? circleContainedInPath : circleOverlapsPath\n const inset = mode === 'contained' ? r : 0\n const { ox, oy, nX, nY } = centeredLatticeGrid(b, d, d, inset, d)\n if (nX < 1 || nY < 1) return out\n\n for (let i = 0; i < nX; i++) {\n for (let j = 0; j < nY; j++) {\n const c = circle(ox + i * d, oy + j * d, r)\n if (accept(c, path)) out.push(c)\n }\n }\n return out\n}\n\n/**\n * Hexagonal lattice of equal circles.\n */\nexport function hexLatticePack(\n path: Path,\n diameter: number,\n mode: LatticePackMode = 'overlap',\n): Circle[] {\n const d = Math.max(diameter, 0.1)\n const r = d / 2\n const b = bounds(path)\n const z = r * Math.sqrt(3)\n const out: Circle[] = []\n const accept =\n mode === 'contained' ? circleContainedInPath : circleOverlapsPath\n const inset = mode === 'contained' ? r : 0\n const { ox, nX, nY } = centeredLatticeGrid(b, z, d, inset, d)\n if (nX < 1 || nY < 1) return out\n\n // First column uses offset `r`, so Y centers span [oy - r, oy + (nY-1)*d].\n // Re-center that full extent so top/bottom cutoffs match.\n const innerH = b.maxY - b.minY - 2 * inset\n const extentY = (nY - 1) * d + r\n const oy = b.minY + inset + (innerH - extentY) / 2 + r\n\n let offset = 0\n for (let i = 0; i < nX; i++) {\n offset = offset === r ? 0 : r\n for (let j = 0; j < nY; j++) {\n const c = circle(ox + i * z, oy + j * d - offset, r)\n if (accept(c, path)) out.push(c)\n }\n }\n return out\n}\n\n/**\n * Centered lattice grid. `inset` > 0 (contained) keeps disk edges inside the AABB;\n * `inset` 0 (overlap) matches PGS coverage count, shifted so opposite cutoffs match.\n * `endPad` mirrors the historical loop bound `max + diameter`.\n */\nfunction centeredLatticeGrid(\n b: { minX: number; minY: number; maxX: number; maxY: number },\n stepX: number,\n stepY: number,\n inset: number,\n endPad: number,\n): { ox: number; oy: number; nX: number; nY: number } {\n const innerW = b.maxX - b.minX - 2 * inset\n const innerH = b.maxY - b.minY - 2 * inset\n if (innerW < -1e-9 || innerH < -1e-9) {\n return { ox: 0, oy: 0, nX: 0, nY: 0 }\n }\n\n let nX: number\n let nY: number\n if (inset > 0) {\n nX = Math.floor(innerW / stepX + 1e-9) + 1\n nY = Math.floor(innerH / stepY + 1e-9) + 1\n } else {\n // Same count as `for (x = min; x < max + endPad; x += step)`\n nX = Math.floor((innerW + endPad) / stepX - 1e-12) + 1\n nY = Math.floor((innerH + endPad) / stepY - 1e-12) + 1\n }\n\n const spanX = (nX - 1) * stepX\n const spanY = (nY - 1) * stepY\n const ox = b.minX + inset + (innerW - spanX) / 2\n const oy = b.minY + inset + (innerH - spanY) / 2\n return { ox, oy, nX, nY }\n}\n\n/**\n * Seeded stochastic packing: sample random points, grow max non-overlapping\n * radius (tangent to nearest circle or limited by distance to boundary).\n * Triangulation Steiner mode deferred.\n */\nexport function stochasticPack(\n path: Path,\n points: number,\n minRadius: number,\n seed = 1,\n): Circle[] {\n const rng = mulberry32(seed >>> 0)\n const b = bounds(path)\n const packing: Circle[] = []\n\n for (let attempt = 0; attempt < points; attempt++) {\n const p = vecInBounds(b, rng)\n if (!containsPoint(path, p)) continue\n\n const maxR = clearanceRadius(p, path, packing)\n if (maxR < minRadius) continue\n packing.push(circle(p.x, p.y, maxR))\n }\n\n return packing\n}\n\n/**\n * Pack up to `n` maximum inscribed circles via iterative largest-empty-circle\n * search (grid + local refine). Circles are fully contained and non-overlapping.\n * `tolerance` controls coarse grid step as a fraction of the bbox diagonal\n * (PGS uses a related accuracy knob; values ~0.5–1 are reasonable).\n *\n * Deferred: `tangencyPack`, `trinscribedPack` — see ADR 0003.\n */\nexport function maximumInscribedPack(\n path: Path,\n n: number,\n tolerance = 1,\n): Circle[] {\n return obstaclePack(path, [], n, tolerance)\n}\n\n/**\n * Pack inscribed circles while radius stays ≥ `minRadius`.\n */\nexport function maximumInscribedPackUntil(\n path: Path,\n minRadius: number,\n tolerance = 1,\n): Circle[] {\n const packing: Circle[] = []\n const tol = Math.max(0.01, tolerance)\n const minR = Math.max(0.01, minRadius)\n for (;;) {\n const next = findLargestEmptyCircle(path, packing, tol)\n if (!next || next.r < minR) break\n packing.push(next)\n }\n return packing\n}\n\n/**\n * Successive LECs inside `path`, treating `obstacles` as already-placed disks.\n * Simpler than full PGS obstacle packing; sufficient for “avoid these circles.”\n */\nexport function obstaclePack(\n path: Path,\n obstacles: Circle[],\n n: number,\n tolerance = 1,\n): Circle[] {\n const packing: Circle[] = obstacles.map((c) => ({ ...c }))\n const placed: Circle[] = []\n const tol = Math.max(0.01, tolerance)\n for (let i = 0; i < n; i++) {\n const next = findLargestEmptyCircle(path, packing, tol)\n if (!next || next.r <= 1e-9) break\n packing.push(next)\n placed.push(next)\n }\n return placed\n}\n\n/**\n * Front-chain-inspired packing of (possibly varying) radii in the path envelope,\n * then keep circles that overlap the path. Seeded for determinism.\n * Grows until placement stalls (region effectively full); no fixed circle count.\n * Not a line-by-line port of PGS FrontChainPacker — same role, approximate layout.\n */\nexport function frontChainPack(\n path: Path,\n radiusMin: number,\n radiusMax: number,\n seed = 1,\n): Circle[] {\n let rMin = Math.max(1e-6, Math.min(radiusMin, radiusMax))\n let rMax = Math.max(rMin, Math.max(radiusMin, radiusMax))\n const rng = mulberry32(seed >>> 0)\n const b = bounds(path)\n const packing: Circle[] = []\n const area = Math.max(1e-6, (b.maxX - b.minX) * (b.maxY - b.minY))\n // Safety ceiling only — real stop is consecutive placement failures.\n const capacity = Math.max(\n 4,\n Math.ceil((area / (Math.PI * rMin * rMin)) * 2),\n )\n\n const trySeed = (): boolean => {\n const p = vecInBounds(b, rng)\n const r = rMin + rng() * (rMax - rMin)\n const c = circle(p.x, p.y, r)\n if (!overlapsAny(c, packing) && circleOverlapsPath(c, path)) {\n packing.push(c)\n return true\n }\n return false\n }\n\n // Seed a few circles, then grow a frontier of tangent candidates.\n for (let i = 0; i < 8; i++) trySeed()\n\n let fails = 0\n while (packing.length < capacity) {\n const stallLimit = Math.max(500, packing.length * 12)\n if (fails >= stallLimit) break\n\n if (packing.length === 0) {\n if (trySeed()) fails = 0\n else fails++\n continue\n }\n\n // Reseed empty pockets so growth is not stuck on one cluster.\n if (fails > 0 && fails % 50 === 0) {\n if (trySeed()) {\n fails = 0\n continue\n }\n }\n\n const base = packing[Math.floor(rng() * packing.length)]!\n const ang = rng() * Math.PI * 2\n const r = rMin + rng() * (rMax - rMin)\n const dist = base.r + r\n const c = circle(\n base.x + Math.cos(ang) * dist,\n base.y + Math.sin(ang) * dist,\n r,\n )\n if (\n c.x < b.minX - rMax ||\n c.x > b.maxX + rMax ||\n c.y < b.minY - rMax ||\n c.y > b.maxY + rMax\n ) {\n fails++\n continue\n }\n if (!overlapsAny(c, packing) && circleOverlapsPath(c, path)) {\n packing.push(c)\n fails = 0\n } else {\n fails++\n }\n }\n\n return packing.filter((c) => circleOverlapsPath(c, path))\n}\n\n/**\n * Seed random circles in the envelope, then iteratively repulse overlaps;\n * keep those that overlap the path (PGS repulsionPack role).\n */\nexport function repulsionPack(\n path: Path,\n radiusMin: number,\n radiusMax: number,\n seed = 1,\n iterations = 80,\n): Circle[] {\n const rMin = Math.max(1e-6, Math.min(radiusMin, radiusMax))\n const rMax = Math.max(rMin, Math.max(radiusMin, radiusMax))\n const rng = mulberry32(seed >>> 0)\n const b = bounds(path)\n const area = Math.max(1e-6, (b.maxX - b.minX) * (b.maxY - b.minY))\n const avgR = (rMin + rMax) / 2\n const target = Math.max(\n 4,\n Math.floor(area / (Math.PI * avgR * avgR) * 0.6),\n )\n\n const circles: Circle[] = []\n for (let i = 0; i < target; i++) {\n const p = vecInBounds(b, rng)\n circles.push(circle(p.x, p.y, rMin + rng() * (rMax - rMin)))\n }\n\n for (let iter = 0; iter < iterations; iter++) {\n for (let i = 0; i < circles.length; i++) {\n for (let j = i + 1; j < circles.length; j++) {\n const a = circles[i]!\n const bC = circles[j]!\n const dx = bC.x - a.x\n const dy = bC.y - a.y\n const dist = Math.hypot(dx, dy) || 1e-9\n const minDist = a.r + bC.r\n if (dist >= minDist) continue\n const push = ((minDist - dist) / 2) * 0.5\n const ux = dx / dist\n const uy = dy / dist\n a.x -= ux * push\n a.y -= uy * push\n bC.x += ux * push\n bC.y += uy * push\n }\n }\n // Soft clamp to inflated envelope\n for (const c of circles) {\n c.x = Math.min(b.maxX + c.r, Math.max(b.minX - c.r, c.x))\n c.y = Math.min(b.maxY + c.r, Math.max(b.minY - c.r, c.y))\n }\n }\n\n return circles.filter((c) => circleOverlapsPath(c, path))\n}\n\n/** True if disk overlaps the filled path (including partial exterior overlap). */\nexport function circleOverlapsPath(c: Circle, path: Path): boolean {\n const center = { x: c.x, y: c.y }\n const dist = distanceToPolygon(center, path)\n return dist <= c.r * 0.95\n}\n\n/** True if the disk lies fully inside the path. */\nexport function circleContainedInPath(c: Circle, path: Path): boolean {\n const center = { x: c.x, y: c.y }\n if (!containsPoint(path, center)) return false\n return distanceToBoundary(center, path) + 1e-9 >= c.r\n}\n\n/** Distance from point to polygon: 0 if inside, else distance to boundary. */\nexport function distanceToPolygon(p: Vec2, path: Path): number {\n if (containsPoint(path, p)) return 0\n return distanceToBoundary(p, path)\n}\n\nfunction findLargestEmptyCircle(\n path: Path,\n obstacles: Circle[],\n tolerance: number,\n): Circle | null {\n const b = bounds(path)\n const diag = Math.hypot(b.maxX - b.minX, b.maxY - b.minY) || 1\n // denser grid for smaller tolerance\n const step = Math.max(diag * 0.02 * Math.sqrt(tolerance), diag * 0.01)\n let best: Circle | null = null\n\n for (let x = b.minX; x <= b.maxX; x += step) {\n for (let y = b.minY; y <= b.maxY; y += step) {\n const p = { x, y }\n if (!containsPoint(path, p)) continue\n const r = clearanceRadius(p, path, obstacles)\n if (!best || r > best.r) best = circle(p.x, p.y, r)\n }\n }\n\n if (!best) return null\n\n // Local refine around best\n let cur = best\n let span = step\n for (let iter = 0; iter < 8; iter++) {\n let improved = cur\n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n if (dx === 0 && dy === 0) continue\n const p = { x: cur.x + dx * span, y: cur.y + dy * span }\n if (!containsPoint(path, p)) continue\n const r = clearanceRadius(p, path, obstacles)\n if (r > improved.r) improved = circle(p.x, p.y, r)\n }\n }\n cur = improved\n span *= 0.5\n }\n return cur\n}\n\nfunction clearanceRadius(\n p: Vec2,\n path: Path,\n obstacles: Circle[],\n): number {\n let r = distanceToBoundary(p, path)\n for (const c of obstacles) {\n r = Math.min(r, Math.hypot(p.x - c.x, p.y - c.y) - c.r)\n }\n return Math.max(0, r)\n}\n\nfunction overlapsAny(c: Circle, packing: Circle[]): boolean {\n for (const o of packing) {\n if (Math.hypot(c.x - o.x, c.y - o.y) < c.r + o.r - 1e-9) return true\n }\n return false\n}\n\nfunction distanceToBoundary(p: Vec2, path: Path): number {\n let min = Infinity\n for (const ring of path.rings) {\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n min = Math.min(min, pointSegmentDistance(p, a, b))\n }\n }\n return min\n}\n\nfunction pointSegmentDistance(p: Vec2, a: Vec2, b: Vec2): number {\n const abx = b.x - a.x\n const aby = b.y - a.y\n const len2 = abx * abx + aby * aby\n if (len2 < 1e-18) return Math.hypot(p.x - a.x, p.y - a.y)\n let t = ((p.x - a.x) * abx + (p.y - a.y) * aby) / len2\n t = Math.max(0, Math.min(1, t))\n return Math.hypot(p.x - (a.x + t * abx), p.y - (a.y + t * aby))\n}\n\nfunction vecInBounds(\n b: { minX: number; minY: number; maxX: number; maxY: number },\n rng: () => number,\n): Vec2 {\n return {\n x: b.minX + rng() * (b.maxX - b.minX),\n y: b.minY + rng() * (b.maxY - b.minY),\n }\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nexport const circlePacking = {\n squareLatticePack,\n hexLatticePack,\n stochasticPack,\n maximumInscribedPack,\n maximumInscribedPackUntil,\n obstaclePack,\n frontChainPack,\n repulsionPack,\n circleOverlapsPath,\n circleContainedInPath,\n}\n"]}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
// src/types/vec2.ts
|
|
5
|
+
function vec2(x, y) {
|
|
6
|
+
return { x, y };
|
|
7
|
+
}
|
|
8
|
+
function cloneVec2(v) {
|
|
9
|
+
return { x: v.x, y: v.y };
|
|
10
|
+
}
|
|
11
|
+
function equalsVec2(a, b, eps = 1e-9) {
|
|
12
|
+
return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/types/path.ts
|
|
16
|
+
function path(rings, closed = true) {
|
|
17
|
+
return {
|
|
18
|
+
rings: rings.map((ring) => ring.map(cloneVec2)),
|
|
19
|
+
closed
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function polyline(points) {
|
|
23
|
+
return path([points], false);
|
|
24
|
+
}
|
|
25
|
+
function polygon(exterior, holes = []) {
|
|
26
|
+
return path([exterior, ...holes], true);
|
|
27
|
+
}
|
|
28
|
+
function normalizeRing(ring, eps = 1e-9) {
|
|
29
|
+
if (ring.length < 2) return ring.map(cloneVec2);
|
|
30
|
+
const first = ring[0];
|
|
31
|
+
const last = ring[ring.length - 1];
|
|
32
|
+
if (first && last && equalsVec2(first, last, eps)) {
|
|
33
|
+
return ring.slice(0, -1).map(cloneVec2);
|
|
34
|
+
}
|
|
35
|
+
return ring.map(cloneVec2);
|
|
36
|
+
}
|
|
37
|
+
function clonePath(p) {
|
|
38
|
+
return {
|
|
39
|
+
closed: p.closed,
|
|
40
|
+
rings: p.rings.map((ring) => ring.map(cloneVec2))
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/types/group.ts
|
|
45
|
+
function group(paths = []) {
|
|
46
|
+
return { paths: paths.map(clonePath) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/svg/pathData.ts
|
|
50
|
+
function parsePathData(d) {
|
|
51
|
+
const tokens = tokenize(d);
|
|
52
|
+
const rings = [];
|
|
53
|
+
let current = [];
|
|
54
|
+
let cx = 0;
|
|
55
|
+
let cy = 0;
|
|
56
|
+
let startX = 0;
|
|
57
|
+
let startY = 0;
|
|
58
|
+
let sawClose = false;
|
|
59
|
+
let i = 0;
|
|
60
|
+
const pushPoint = (x, y) => {
|
|
61
|
+
current.push(vec2(x, y));
|
|
62
|
+
cx = x;
|
|
63
|
+
cy = y;
|
|
64
|
+
};
|
|
65
|
+
const finishSubpath = () => {
|
|
66
|
+
if (current.length === 0) return;
|
|
67
|
+
const ring = normalizeRing(current);
|
|
68
|
+
if (ring.length > 0) rings.push(ring);
|
|
69
|
+
current = [];
|
|
70
|
+
};
|
|
71
|
+
while (i < tokens.length) {
|
|
72
|
+
const raw = tokens[i];
|
|
73
|
+
if (raw === void 0) break;
|
|
74
|
+
i += 1;
|
|
75
|
+
if (!/^[MmLlHhVvZz]$/.test(raw)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unsupported SVG path command or token "${raw}". Phase 1 supports M/L/H/V/Z only.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const relative = raw === raw.toLowerCase();
|
|
81
|
+
const kind = raw.toUpperCase();
|
|
82
|
+
if (kind === "Z") {
|
|
83
|
+
sawClose = true;
|
|
84
|
+
finishSubpath();
|
|
85
|
+
cx = startX;
|
|
86
|
+
cy = startY;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (kind === "M") {
|
|
90
|
+
finishSubpath();
|
|
91
|
+
const pair = readPair(tokens, i);
|
|
92
|
+
i = pair.next;
|
|
93
|
+
const x = relative ? cx + pair.x : pair.x;
|
|
94
|
+
const y = relative ? cy + pair.y : pair.y;
|
|
95
|
+
pushPoint(x, y);
|
|
96
|
+
startX = x;
|
|
97
|
+
startY = y;
|
|
98
|
+
while (i < tokens.length && isNumberToken(tokens[i])) {
|
|
99
|
+
const next = readPair(tokens, i);
|
|
100
|
+
i = next.next;
|
|
101
|
+
const nx = relative ? cx + next.x : next.x;
|
|
102
|
+
const ny = relative ? cy + next.y : next.y;
|
|
103
|
+
pushPoint(nx, ny);
|
|
104
|
+
}
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (kind === "L") {
|
|
108
|
+
while (i < tokens.length && isNumberToken(tokens[i])) {
|
|
109
|
+
const pair = readPair(tokens, i);
|
|
110
|
+
i = pair.next;
|
|
111
|
+
const x = relative ? cx + pair.x : pair.x;
|
|
112
|
+
const y = relative ? cy + pair.y : pair.y;
|
|
113
|
+
pushPoint(x, y);
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (kind === "H") {
|
|
118
|
+
while (i < tokens.length && isNumberToken(tokens[i])) {
|
|
119
|
+
const v = readNumber(tokens, i);
|
|
120
|
+
i = v.next;
|
|
121
|
+
const x = relative ? cx + v.value : v.value;
|
|
122
|
+
pushPoint(x, cy);
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (kind === "V") {
|
|
127
|
+
while (i < tokens.length && isNumberToken(tokens[i])) {
|
|
128
|
+
const v = readNumber(tokens, i);
|
|
129
|
+
i = v.next;
|
|
130
|
+
const y = relative ? cy + v.value : v.value;
|
|
131
|
+
pushPoint(cx, y);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
finishSubpath();
|
|
136
|
+
return { rings, closed: sawClose };
|
|
137
|
+
}
|
|
138
|
+
function serializePathData(rings, closed) {
|
|
139
|
+
const parts = [];
|
|
140
|
+
for (const ring of rings) {
|
|
141
|
+
if (ring.length === 0) continue;
|
|
142
|
+
const first = ring[0];
|
|
143
|
+
if (!first) continue;
|
|
144
|
+
parts.push(`M ${fmt(first.x)} ${fmt(first.y)}`);
|
|
145
|
+
for (let i = 1; i < ring.length; i += 1) {
|
|
146
|
+
const p = ring[i];
|
|
147
|
+
if (!p) continue;
|
|
148
|
+
parts.push(`L ${fmt(p.x)} ${fmt(p.y)}`);
|
|
149
|
+
}
|
|
150
|
+
if (closed) parts.push("Z");
|
|
151
|
+
}
|
|
152
|
+
return parts.join(" ");
|
|
153
|
+
}
|
|
154
|
+
function tokenize(d) {
|
|
155
|
+
const out = [];
|
|
156
|
+
const re = /([MmLlHhVvZz])|([+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/g;
|
|
157
|
+
let m;
|
|
158
|
+
while ((m = re.exec(d)) !== null) {
|
|
159
|
+
const token = m[1] ?? m[2];
|
|
160
|
+
if (token) out.push(token);
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
function isNumberToken(token) {
|
|
165
|
+
return token !== void 0 && /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(token);
|
|
166
|
+
}
|
|
167
|
+
function readNumber(tokens, i) {
|
|
168
|
+
const t = tokens[i];
|
|
169
|
+
if (!isNumberToken(t) || t === void 0) {
|
|
170
|
+
throw new Error(`Expected number in path data at token index ${i}`);
|
|
171
|
+
}
|
|
172
|
+
return { value: Number(t), next: i + 1 };
|
|
173
|
+
}
|
|
174
|
+
function readPair(tokens, i) {
|
|
175
|
+
const x = readNumber(tokens, i);
|
|
176
|
+
const y = readNumber(tokens, x.next);
|
|
177
|
+
return { x: x.value, y: y.value, next: y.next };
|
|
178
|
+
}
|
|
179
|
+
function fmt(n) {
|
|
180
|
+
if (Number.isInteger(n)) return String(n);
|
|
181
|
+
return String(Number(n.toPrecision(12)));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/svg/parse.ts
|
|
185
|
+
var SHAPE_RE = /<(path|rect|circle|line|polyline|polygon)\b[^>]*\/?>/gi;
|
|
186
|
+
function parseSvg(svg) {
|
|
187
|
+
const paths = [];
|
|
188
|
+
for (const match of svg.matchAll(SHAPE_RE)) {
|
|
189
|
+
const el = match[0];
|
|
190
|
+
const tag = match[1]?.toLowerCase();
|
|
191
|
+
if (!tag) continue;
|
|
192
|
+
if (tag === "path") {
|
|
193
|
+
const d = getAttr(el, "d");
|
|
194
|
+
if (!d) continue;
|
|
195
|
+
const parsed = parsePathData(d);
|
|
196
|
+
if (parsed.rings.length === 0) continue;
|
|
197
|
+
paths.push(path(parsed.rings, parsed.closed));
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (tag === "rect") {
|
|
201
|
+
const x = num(getAttr(el, "x"), 0);
|
|
202
|
+
const y = num(getAttr(el, "y"), 0);
|
|
203
|
+
const w = num(getAttr(el, "width"), 0);
|
|
204
|
+
const h = num(getAttr(el, "height"), 0);
|
|
205
|
+
if (w === 0 || h === 0) continue;
|
|
206
|
+
paths.push(
|
|
207
|
+
polygon([
|
|
208
|
+
vec2(x, y),
|
|
209
|
+
vec2(x + w, y),
|
|
210
|
+
vec2(x + w, y + h),
|
|
211
|
+
vec2(x, y + h)
|
|
212
|
+
])
|
|
213
|
+
);
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (tag === "circle") {
|
|
217
|
+
const cx = num(getAttr(el, "cx"), 0);
|
|
218
|
+
const cy = num(getAttr(el, "cy"), 0);
|
|
219
|
+
const r = num(getAttr(el, "r"), 0);
|
|
220
|
+
if (r <= 0) continue;
|
|
221
|
+
paths.push(polygon(circleRing(cx, cy, r, 64)));
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (tag === "line") {
|
|
225
|
+
const x1 = num(getAttr(el, "x1"), 0);
|
|
226
|
+
const y1 = num(getAttr(el, "y1"), 0);
|
|
227
|
+
const x2 = num(getAttr(el, "x2"), 0);
|
|
228
|
+
const y2 = num(getAttr(el, "y2"), 0);
|
|
229
|
+
paths.push(polyline([vec2(x1, y1), vec2(x2, y2)]));
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (tag === "polyline") {
|
|
233
|
+
const pts = parsePoints(getAttr(el, "points") ?? "");
|
|
234
|
+
if (pts.length >= 2) paths.push(polyline(pts));
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (tag === "polygon") {
|
|
238
|
+
const pts = parsePoints(getAttr(el, "points") ?? "");
|
|
239
|
+
if (pts.length >= 3) paths.push(polygon(pts));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return group(paths);
|
|
243
|
+
}
|
|
244
|
+
function getAttr(el, name) {
|
|
245
|
+
const re = new RegExp(`\\b${name}\\s*=\\s*["']([^"']*)["']`, "i");
|
|
246
|
+
const m = re.exec(el);
|
|
247
|
+
return m?.[1];
|
|
248
|
+
}
|
|
249
|
+
function num(value, fallback) {
|
|
250
|
+
if (value === void 0 || value === "") return fallback;
|
|
251
|
+
const n = Number(value);
|
|
252
|
+
return Number.isFinite(n) ? n : fallback;
|
|
253
|
+
}
|
|
254
|
+
function parsePoints(points) {
|
|
255
|
+
const nums = points.trim().split(/[\s,]+/).filter(Boolean).map(Number);
|
|
256
|
+
const out = [];
|
|
257
|
+
for (let i = 0; i + 1 < nums.length; i += 2) {
|
|
258
|
+
const x = nums[i];
|
|
259
|
+
const y = nums[i + 1];
|
|
260
|
+
if (x === void 0 || y === void 0) continue;
|
|
261
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) continue;
|
|
262
|
+
out.push(vec2(x, y));
|
|
263
|
+
}
|
|
264
|
+
return out;
|
|
265
|
+
}
|
|
266
|
+
function circleRing(cx, cy, r, segments) {
|
|
267
|
+
const ring = [];
|
|
268
|
+
for (let i = 0; i < segments; i += 1) {
|
|
269
|
+
const t = i / segments * Math.PI * 2;
|
|
270
|
+
ring.push(vec2(cx + r * Math.cos(t), cy + r * Math.sin(t)));
|
|
271
|
+
}
|
|
272
|
+
return ring;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/svg/serialize.ts
|
|
276
|
+
function toSvg(g, options = {}) {
|
|
277
|
+
const stroke = options.stroke ?? "#000";
|
|
278
|
+
const strokeWidth = options.strokeWidth ?? 1;
|
|
279
|
+
const viewBox = options.viewBox ?? inferViewBox(g);
|
|
280
|
+
const widthAttr = options.width !== void 0 ? ` width="${options.width}"` : "";
|
|
281
|
+
const heightAttr = options.height !== void 0 ? ` height="${options.height}"` : "";
|
|
282
|
+
const body = g.paths.map((p) => pathElement(p, stroke, strokeWidth)).filter(Boolean).join("\n ");
|
|
283
|
+
return [
|
|
284
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
285
|
+
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}"${widthAttr}${heightAttr} fill="none">`,
|
|
286
|
+
body ? ` ${body}` : "",
|
|
287
|
+
`</svg>`
|
|
288
|
+
].filter((line) => line !== "").join("\n");
|
|
289
|
+
}
|
|
290
|
+
function pathElement(p, stroke, strokeWidth) {
|
|
291
|
+
if (p.rings.length === 0) return "";
|
|
292
|
+
const d = serializePathData(p.rings, p.closed);
|
|
293
|
+
if (!d) return "";
|
|
294
|
+
return `<path d="${d}" stroke="${stroke}" stroke-width="${strokeWidth}" fill="none" />`;
|
|
295
|
+
}
|
|
296
|
+
function inferViewBox(g) {
|
|
297
|
+
let minX = Infinity;
|
|
298
|
+
let minY = Infinity;
|
|
299
|
+
let maxX = -Infinity;
|
|
300
|
+
let maxY = -Infinity;
|
|
301
|
+
for (const p of g.paths) {
|
|
302
|
+
for (const ring of p.rings) {
|
|
303
|
+
for (const v of ring) {
|
|
304
|
+
minX = Math.min(minX, v.x);
|
|
305
|
+
minY = Math.min(minY, v.y);
|
|
306
|
+
maxX = Math.max(maxX, v.x);
|
|
307
|
+
maxY = Math.max(maxY, v.y);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!Number.isFinite(minX)) return "0 0 100 100";
|
|
312
|
+
const pad = 1;
|
|
313
|
+
const w = Math.max(maxX - minX, 0) + pad * 2;
|
|
314
|
+
const h = Math.max(maxY - minY, 0) + pad * 2;
|
|
315
|
+
return `${minX - pad} ${minY - pad} ${w} ${h}`;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// src/cli.ts
|
|
319
|
+
function printHelp() {
|
|
320
|
+
console.log(`pattapatta \u2014 pen-plotter geometry CLI
|
|
321
|
+
|
|
322
|
+
Usage:
|
|
323
|
+
pattapatta --help
|
|
324
|
+
pattapatta --version
|
|
325
|
+
pattapatta svg:roundtrip <input.svg> [output.svg]
|
|
326
|
+
|
|
327
|
+
Commands:
|
|
328
|
+
svg:roundtrip Parse SVG and write plotter SVG (fill=none, stroked paths)
|
|
329
|
+
`);
|
|
330
|
+
}
|
|
331
|
+
function main(argv) {
|
|
332
|
+
const args = argv.slice(2);
|
|
333
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
334
|
+
printHelp();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
338
|
+
console.log("0.1.0");
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const [cmd, input, output] = args;
|
|
342
|
+
if (cmd === "svg:roundtrip") {
|
|
343
|
+
if (!input) {
|
|
344
|
+
console.error("Missing input.svg");
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const svg = readFileSync(input, "utf8");
|
|
349
|
+
const group2 = parseSvg(svg);
|
|
350
|
+
const out = toSvg(group2);
|
|
351
|
+
if (output) {
|
|
352
|
+
writeFileSync(output, out, "utf8");
|
|
353
|
+
} else {
|
|
354
|
+
process.stdout.write(out);
|
|
355
|
+
if (!out.endsWith("\n")) process.stdout.write("\n");
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
console.error(`Unknown command: ${cmd}`);
|
|
360
|
+
printHelp();
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
}
|
|
363
|
+
main(process.argv);
|
|
364
|
+
//# sourceMappingURL=cli.js.map
|
|
365
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/vec2.ts","../src/types/path.ts","../src/types/group.ts","../src/svg/pathData.ts","../src/svg/parse.ts","../src/svg/serialize.ts","../src/cli.ts"],"names":["group"],"mappings":"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","file":"cli.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import type { Path } from './path.js'\nimport { clonePath } from './path.js'\n\n/**\n * Ordered collection of paths. Later entries are “on top” for occlusion-style ops.\n */\nexport type Group = {\n paths: Path[]\n}\n\nexport function group(paths: Path[] = []): Group {\n return { paths: paths.map(clonePath) }\n}\n\nexport function groupFromPaths(...paths: Path[]): Group {\n return group(paths)\n}\n\nexport function cloneGroup(g: Group): Group {\n return group(g.paths)\n}\n","import type { Ring } from '../types/index.js'\nimport { normalizeRing, vec2 } from '../types/index.js'\n\n/**\n * Minimal SVG path `d` tokenizer for plotter-oriented paths.\n * Supports M/m L/l H/h V/v Z/z. Curves are rejected with a clear error (Phase 1).\n */\nexport function parsePathData(d: string): { rings: Ring[]; closed: boolean } {\n const tokens = tokenize(d)\n const rings: Ring[] = []\n let current: Ring = []\n let cx = 0\n let cy = 0\n let startX = 0\n let startY = 0\n let sawClose = false\n let i = 0\n\n const pushPoint = (x: number, y: number) => {\n current.push(vec2(x, y))\n cx = x\n cy = y\n }\n\n const finishSubpath = () => {\n if (current.length === 0) return\n const ring = normalizeRing(current)\n if (ring.length > 0) rings.push(ring)\n current = []\n }\n\n while (i < tokens.length) {\n const raw = tokens[i]\n if (raw === undefined) break\n i += 1\n\n if (!/^[MmLlHhVvZz]$/.test(raw)) {\n throw new Error(\n `Unsupported SVG path command or token \"${raw}\". Phase 1 supports M/L/H/V/Z only.`,\n )\n }\n\n const relative = raw === raw.toLowerCase()\n const kind = raw.toUpperCase()\n\n if (kind === 'Z') {\n sawClose = true\n finishSubpath()\n cx = startX\n cy = startY\n continue\n }\n\n if (kind === 'M') {\n finishSubpath()\n const pair = readPair(tokens, i)\n i = pair.next\n const x = relative ? cx + pair.x : pair.x\n const y = relative ? cy + pair.y : pair.y\n pushPoint(x, y)\n startX = x\n startY = y\n while (i < tokens.length && isNumberToken(tokens[i])) {\n const next = readPair(tokens, i)\n i = next.next\n const nx = relative ? cx + next.x : next.x\n const ny = relative ? cy + next.y : next.y\n pushPoint(nx, ny)\n }\n continue\n }\n\n if (kind === 'L') {\n while (i < tokens.length && isNumberToken(tokens[i])) {\n const pair = readPair(tokens, i)\n i = pair.next\n const x = relative ? cx + pair.x : pair.x\n const y = relative ? cy + pair.y : pair.y\n pushPoint(x, y)\n }\n continue\n }\n\n if (kind === 'H') {\n while (i < tokens.length && isNumberToken(tokens[i])) {\n const v = readNumber(tokens, i)\n i = v.next\n const x = relative ? cx + v.value : v.value\n pushPoint(x, cy)\n }\n continue\n }\n\n if (kind === 'V') {\n while (i < tokens.length && isNumberToken(tokens[i])) {\n const v = readNumber(tokens, i)\n i = v.next\n const y = relative ? cy + v.value : v.value\n pushPoint(cx, y)\n }\n }\n }\n\n finishSubpath()\n return { rings, closed: sawClose }\n}\n\nexport function serializePathData(rings: Ring[], closed: boolean): string {\n const parts: string[] = []\n for (const ring of rings) {\n if (ring.length === 0) continue\n const first = ring[0]\n if (!first) continue\n parts.push(`M ${fmt(first.x)} ${fmt(first.y)}`)\n for (let i = 1; i < ring.length; i += 1) {\n const p = ring[i]\n if (!p) continue\n parts.push(`L ${fmt(p.x)} ${fmt(p.y)}`)\n }\n if (closed) parts.push('Z')\n }\n return parts.join(' ')\n}\n\nfunction tokenize(d: string): string[] {\n const out: string[] = []\n const re = /([MmLlHhVvZz])|([+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?)/g\n let m: RegExpExecArray | null\n while ((m = re.exec(d)) !== null) {\n const token = m[1] ?? m[2]\n if (token) out.push(token)\n }\n return out\n}\n\nfunction isNumberToken(token: string | undefined): boolean {\n return token !== undefined && /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(token)\n}\n\nfunction readNumber(tokens: string[], i: number): { value: number; next: number } {\n const t = tokens[i]\n if (!isNumberToken(t) || t === undefined) {\n throw new Error(`Expected number in path data at token index ${i}`)\n }\n return { value: Number(t), next: i + 1 }\n}\n\nfunction readPair(\n tokens: string[],\n i: number,\n): { x: number; y: number; next: number } {\n const x = readNumber(tokens, i)\n const y = readNumber(tokens, x.next)\n return { x: x.value, y: y.value, next: y.next }\n}\n\nfunction fmt(n: number): string {\n if (Number.isInteger(n)) return String(n)\n return String(Number(n.toPrecision(12)))\n}\n","import type { Group, Path } from '../types/index.js'\nimport { group, path, polygon, polyline, vec2 } from '../types/index.js'\nimport { parsePathData } from './pathData.js'\n\nconst SHAPE_RE =\n /<(path|rect|circle|line|polyline|polygon)\\b[^>]*\\/?>/gi\n\n/**\n * Parse a subset of SVG into a geometry group.\n * Supports: `path` (M/L/H/V/Z), `rect`, `circle`, `line`, `polyline`, `polygon`.\n * Element order in the document is preserved (later = on top for occlusion).\n */\nexport function parseSvg(svg: string): Group {\n const paths: Path[] = []\n\n for (const match of svg.matchAll(SHAPE_RE)) {\n const el = match[0]\n const tag = match[1]?.toLowerCase()\n if (!tag) continue\n\n if (tag === 'path') {\n const d = getAttr(el, 'd')\n if (!d) continue\n const parsed = parsePathData(d)\n if (parsed.rings.length === 0) continue\n paths.push(path(parsed.rings, parsed.closed))\n continue\n }\n\n if (tag === 'rect') {\n const x = num(getAttr(el, 'x'), 0)\n const y = num(getAttr(el, 'y'), 0)\n const w = num(getAttr(el, 'width'), 0)\n const h = num(getAttr(el, 'height'), 0)\n if (w === 0 || h === 0) continue\n paths.push(\n polygon([\n vec2(x, y),\n vec2(x + w, y),\n vec2(x + w, y + h),\n vec2(x, y + h),\n ]),\n )\n continue\n }\n\n if (tag === 'circle') {\n const cx = num(getAttr(el, 'cx'), 0)\n const cy = num(getAttr(el, 'cy'), 0)\n const r = num(getAttr(el, 'r'), 0)\n if (r <= 0) continue\n paths.push(polygon(circleRing(cx, cy, r, 64)))\n continue\n }\n\n if (tag === 'line') {\n const x1 = num(getAttr(el, 'x1'), 0)\n const y1 = num(getAttr(el, 'y1'), 0)\n const x2 = num(getAttr(el, 'x2'), 0)\n const y2 = num(getAttr(el, 'y2'), 0)\n paths.push(polyline([vec2(x1, y1), vec2(x2, y2)]))\n continue\n }\n\n if (tag === 'polyline') {\n const pts = parsePoints(getAttr(el, 'points') ?? '')\n if (pts.length >= 2) paths.push(polyline(pts))\n continue\n }\n\n if (tag === 'polygon') {\n const pts = parsePoints(getAttr(el, 'points') ?? '')\n if (pts.length >= 3) paths.push(polygon(pts))\n }\n }\n\n return group(paths)\n}\n\nfunction getAttr(el: string, name: string): string | undefined {\n const re = new RegExp(`\\\\b${name}\\\\s*=\\\\s*[\"']([^\"']*)[\"']`, 'i')\n const m = re.exec(el)\n return m?.[1]\n}\n\nfunction num(value: string | undefined, fallback: number): number {\n if (value === undefined || value === '') return fallback\n const n = Number(value)\n return Number.isFinite(n) ? n : fallback\n}\n\nfunction parsePoints(points: string) {\n const nums = points\n .trim()\n .split(/[\\s,]+/)\n .filter(Boolean)\n .map(Number)\n const out = []\n for (let i = 0; i + 1 < nums.length; i += 2) {\n const x = nums[i]\n const y = nums[i + 1]\n if (x === undefined || y === undefined) continue\n if (!Number.isFinite(x) || !Number.isFinite(y)) continue\n out.push(vec2(x, y))\n }\n return out\n}\n\nfunction circleRing(cx: number, cy: number, r: number, segments: number) {\n const ring = []\n for (let i = 0; i < segments; i += 1) {\n const t = (i / segments) * Math.PI * 2\n ring.push(vec2(cx + r * Math.cos(t), cy + r * Math.sin(t)))\n }\n return ring\n}\n","import type { Group, Path } from '../types/index.js'\nimport { serializePathData } from './pathData.js'\n\nexport type ToSvgOptions = {\n /** SVG viewBox attribute, e.g. `\"0 0 100 100\"`. */\n viewBox?: string\n /** Root width/height attributes (optional). */\n width?: number | string\n height?: number | string\n /** Stroke color (default `#000`). */\n stroke?: string\n /** Stroke width (default `1`). */\n strokeWidth?: number | string\n}\n\n/**\n * Serialize a group to plotter-oriented SVG (`fill=\"none\"`, stroked paths).\n */\nexport function toSvg(g: Group, options: ToSvgOptions = {}): string {\n const stroke = options.stroke ?? '#000'\n const strokeWidth = options.strokeWidth ?? 1\n const viewBox = options.viewBox ?? inferViewBox(g)\n const widthAttr =\n options.width !== undefined ? ` width=\"${options.width}\"` : ''\n const heightAttr =\n options.height !== undefined ? ` height=\"${options.height}\"` : ''\n\n const body = g.paths\n .map((p) => pathElement(p, stroke, strokeWidth))\n .filter(Boolean)\n .join('\\n ')\n\n return [\n `<?xml version=\"1.0\" encoding=\"UTF-8\"?>`,\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${viewBox}\"${widthAttr}${heightAttr} fill=\"none\">`,\n body ? ` ${body}` : '',\n `</svg>`,\n ]\n .filter((line) => line !== '')\n .join('\\n')\n}\n\nfunction pathElement(\n p: Path,\n stroke: string,\n strokeWidth: number | string,\n): string {\n if (p.rings.length === 0) return ''\n const d = serializePathData(p.rings, p.closed)\n if (!d) return ''\n return `<path d=\"${d}\" stroke=\"${stroke}\" stroke-width=\"${strokeWidth}\" fill=\"none\" />`\n}\n\nfunction inferViewBox(g: Group): string {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const p of g.paths) {\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n }\n if (!Number.isFinite(minX)) return '0 0 100 100'\n const pad = 1\n const w = Math.max(maxX - minX, 0) + pad * 2\n const h = Math.max(maxY - minY, 0) + pad * 2\n return `${minX - pad} ${minY - pad} ${w} ${h}`\n}\n","import { readFileSync, writeFileSync } from 'node:fs'\nimport { parseSvg, toSvg } from './index.js'\n\nfunction printHelp(): void {\n console.log(`pattapatta — pen-plotter geometry CLI\n\nUsage:\n pattapatta --help\n pattapatta --version\n pattapatta svg:roundtrip <input.svg> [output.svg]\n\nCommands:\n svg:roundtrip Parse SVG and write plotter SVG (fill=none, stroked paths)\n`)\n}\n\nfunction main(argv: string[]): void {\n const args = argv.slice(2)\n if (args.length === 0 || args.includes('--help') || args.includes('-h')) {\n printHelp()\n return\n }\n if (args.includes('--version') || args.includes('-v')) {\n console.log('0.1.0')\n return\n }\n\n const [cmd, input, output] = args\n if (cmd === 'svg:roundtrip') {\n if (!input) {\n console.error('Missing input.svg')\n process.exitCode = 1\n return\n }\n const svg = readFileSync(input, 'utf8')\n const group = parseSvg(svg)\n const out = toSvg(group)\n if (output) {\n writeFileSync(output, out, 'utf8')\n } else {\n process.stdout.write(out)\n if (!out.endsWith('\\n')) process.stdout.write('\\n')\n }\n return\n }\n\n console.error(`Unknown command: ${cmd}`)\n printHelp()\n process.exitCode = 1\n}\n\nmain(process.argv)\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { P as Path } from '../path-0RjhYjJs.js';
|
|
2
|
+
import '../vec2-CWyXN1Wj.js';
|
|
3
|
+
|
|
4
|
+
/** Regular n-gon approximating a circle. */
|
|
5
|
+
declare function createCircle(cx: number, cy: number, radius: number, segments?: number): Path;
|
|
6
|
+
declare function createRect(x: number, y: number, width: number, height: number): Path;
|
|
7
|
+
declare function createRegularPolygon(cx: number, cy: number, radius: number, sides: number, rotation?: number): Path;
|
|
8
|
+
/** Annulus as exterior + hole. */
|
|
9
|
+
declare function createRing(cx: number, cy: number, outerRadius: number, innerRadius: number, segments?: number): Path;
|
|
10
|
+
/** Open circular arc polyline from `startAngle` to `endAngle` (radians). */
|
|
11
|
+
declare function createArc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number, segments?: number): Path;
|
|
12
|
+
/** Star polygon (outer/inner radius alternating). */
|
|
13
|
+
declare function createStar(cx: number, cy: number, outerRadius: number, innerRadius: number, points?: number, rotation?: number): Path;
|
|
14
|
+
/** Koch snowflake after `iterations` refinement (0 = equilateral triangle). */
|
|
15
|
+
declare function createKochSnowflake(cx: number, cy: number, radius: number, iterations?: number): Path;
|
|
16
|
+
declare const construction: {
|
|
17
|
+
createCircle: typeof createCircle;
|
|
18
|
+
createRect: typeof createRect;
|
|
19
|
+
createRegularPolygon: typeof createRegularPolygon;
|
|
20
|
+
createRing: typeof createRing;
|
|
21
|
+
createArc: typeof createArc;
|
|
22
|
+
createStar: typeof createStar;
|
|
23
|
+
createKochSnowflake: typeof createKochSnowflake;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { construction, createArc, createCircle, createKochSnowflake, createRect, createRegularPolygon, createRing, createStar };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// src/types/vec2.ts
|
|
2
|
+
function cloneVec2(v) {
|
|
3
|
+
return { x: v.x, y: v.y };
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/types/path.ts
|
|
7
|
+
function path(rings, closed = true) {
|
|
8
|
+
return {
|
|
9
|
+
rings: rings.map((ring) => ring.map(cloneVec2)),
|
|
10
|
+
closed
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function polyline(points) {
|
|
14
|
+
return path([points], false);
|
|
15
|
+
}
|
|
16
|
+
function polygon(exterior, holes = []) {
|
|
17
|
+
return path([exterior, ...holes], true);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/construction/index.ts
|
|
21
|
+
function createCircle(cx, cy, radius, segments = 64) {
|
|
22
|
+
return createRegularPolygon(cx, cy, radius, Math.max(3, Math.floor(segments)));
|
|
23
|
+
}
|
|
24
|
+
function createRect(x, y, width, height) {
|
|
25
|
+
return polygon([
|
|
26
|
+
{ x, y },
|
|
27
|
+
{ x: x + width, y },
|
|
28
|
+
{ x: x + width, y: y + height },
|
|
29
|
+
{ x, y: y + height }
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
function createRegularPolygon(cx, cy, radius, sides, rotation = -Math.PI / 2) {
|
|
33
|
+
const n = Math.max(3, Math.floor(sides));
|
|
34
|
+
const ring = [];
|
|
35
|
+
for (let i = 0; i < n; i++) {
|
|
36
|
+
const t = rotation + i / n * Math.PI * 2;
|
|
37
|
+
ring.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius });
|
|
38
|
+
}
|
|
39
|
+
return polygon(ring);
|
|
40
|
+
}
|
|
41
|
+
function createRing(cx, cy, outerRadius, innerRadius, segments = 64) {
|
|
42
|
+
const outer = createCircle(cx, cy, outerRadius, segments).rings[0];
|
|
43
|
+
const inner = createCircle(cx, cy, Math.min(innerRadius, outerRadius), segments).rings[0];
|
|
44
|
+
return path([outer, [...inner].reverse()], true);
|
|
45
|
+
}
|
|
46
|
+
function createArc(cx, cy, radius, startAngle, endAngle, segments = 32) {
|
|
47
|
+
const n = Math.max(2, Math.floor(segments));
|
|
48
|
+
const pts = [];
|
|
49
|
+
for (let i = 0; i <= n; i++) {
|
|
50
|
+
const t = startAngle + (endAngle - startAngle) * i / n;
|
|
51
|
+
pts.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius });
|
|
52
|
+
}
|
|
53
|
+
return polyline(pts);
|
|
54
|
+
}
|
|
55
|
+
function createStar(cx, cy, outerRadius, innerRadius, points = 5, rotation = -Math.PI / 2) {
|
|
56
|
+
const n = Math.max(3, Math.floor(points));
|
|
57
|
+
const ring = [];
|
|
58
|
+
for (let i = 0; i < n * 2; i++) {
|
|
59
|
+
const r = i % 2 === 0 ? outerRadius : innerRadius;
|
|
60
|
+
const t = rotation + i / (n * 2) * Math.PI * 2;
|
|
61
|
+
ring.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r });
|
|
62
|
+
}
|
|
63
|
+
return polygon(ring);
|
|
64
|
+
}
|
|
65
|
+
function createKochSnowflake(cx, cy, radius, iterations = 3) {
|
|
66
|
+
const tri = createRegularPolygon(cx, cy, radius, 3);
|
|
67
|
+
let ring = tri.rings[0];
|
|
68
|
+
const iters = Math.max(0, Math.min(6, Math.floor(iterations)));
|
|
69
|
+
for (let i = 0; i < iters; i++) {
|
|
70
|
+
ring = kochRefine(ring);
|
|
71
|
+
}
|
|
72
|
+
return polygon(ring);
|
|
73
|
+
}
|
|
74
|
+
function kochRefine(ring) {
|
|
75
|
+
const out = [];
|
|
76
|
+
const n = ring.length;
|
|
77
|
+
for (let i = 0; i < n; i++) {
|
|
78
|
+
const a = ring[i];
|
|
79
|
+
const b = ring[(i + 1) % n];
|
|
80
|
+
const dx = b.x - a.x;
|
|
81
|
+
const dy = b.y - a.y;
|
|
82
|
+
const p1 = { x: a.x + dx / 3, y: a.y + dy / 3 };
|
|
83
|
+
const p2 = { x: a.x + 2 * dx / 3, y: a.y + 2 * dy / 3 };
|
|
84
|
+
const px = a.x + dx / 2 - dy * (Math.sqrt(3) / 6);
|
|
85
|
+
const py = a.y + dy / 2 + dx * (Math.sqrt(3) / 6);
|
|
86
|
+
out.push(a, p1, { x: px, y: py }, p2);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
var construction = {
|
|
91
|
+
createCircle,
|
|
92
|
+
createRect,
|
|
93
|
+
createRegularPolygon,
|
|
94
|
+
createRing,
|
|
95
|
+
createArc,
|
|
96
|
+
createStar,
|
|
97
|
+
createKochSnowflake
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export { construction, createArc, createCircle, createKochSnowflake, createRect, createRegularPolygon, createRing, createStar };
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
102
|
+
//# sourceMappingURL=index.js.map
|