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/segment.ts","../../src/types/path.ts","../../src/types/group.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/shapeBoolean/index.ts","../../src/processing/index.ts"],"names":[],"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/** Line segment between two points. */\nexport type Segment = {\n a: Vec2\n b: Vec2\n}\n\nexport function segment(a: Vec2, b: Vec2): Segment {\n return { a, b }\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 {\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 { Group, Path } from '../types/index.js'\nimport { group, groupFromPaths, path, polygon, vec2 } from '../types/index.js'\nimport {\n clipDifference,\n clipIntersect,\n clipUnion,\n clipXor,\n pathToPathsD,\n pathsDToGroup,\n} from '../clipper/convert.js'\n\nfunction ensureClosed(p: Path): Path {\n if (!p.closed) {\n throw new Error('shapeBoolean requires closed paths')\n }\n return p\n}\n\n/** Union of two closed paths. */\nexport function union(a: Path, b: Path): Group {\n const result = clipUnion(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Union of many closed paths (folded left-to-right). */\nexport function unionAll(paths: Path[]): Group {\n if (paths.length === 0) return group([])\n let acc = pathToPathsD(ensureClosed(paths[0]!))\n for (let i = 1; i < paths.length; i++) {\n acc = clipUnion(acc, pathToPathsD(ensureClosed(paths[i]!)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Intersection of two closed paths. */\nexport function intersect(a: Path, b: Path): Group {\n const result = clipIntersect(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract b from a (a \\ b). */\nexport function subtract(a: Path, b: Path): Group {\n const result = clipDifference(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract many shapes from a base. */\nexport function subtractAll(base: Path, shapes: Path[]): Group {\n let acc = pathToPathsD(ensureClosed(base))\n for (const s of shapes) {\n acc = clipDifference(acc, pathToPathsD(ensureClosed(s)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Symmetric difference. */\nexport function symDifference(a: Path, b: Path): Group {\n const result = clipXor(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Complement of shape within axis-aligned rectangle [0,width] x [0,height]. */\nexport function complement(shape: Path, width: number, height: number): Group {\n const frame = polygon([\n vec2(0, 0),\n vec2(width, 0),\n vec2(width, height),\n vec2(0, height),\n ])\n return subtract(frame, shape)\n}\n\n/**\n * Painter-style occlusion: later paths in the group are on top.\n * Each path has higher paths subtracted from it; returns visible remainders.\n */\nexport function occlusionSubtract(g: Group): Group {\n const paths = g.paths\n const visible: Path[] = []\n for (let i = 0; i < paths.length; i++) {\n const subject = paths[i]\n if (!subject) continue\n const occluders = paths.slice(i + 1)\n const piece =\n occluders.length === 0\n ? groupFromPaths(ensureClosed(subject))\n : subtractAll(subject, occluders)\n for (const p of piece.paths) {\n visible.push(p)\n }\n }\n return group(visible)\n}\n\n/**\n * Regions covered by at least two input shapes.\n * If `merged`, collapse multi-overlaps into disjoint patches via union of pairwise intersects.\n */\nexport function overlapRegions(shapes: Path[], merged: boolean): Group {\n if (shapes.length < 2) return group([])\n const pairs: Path[] = []\n for (let i = 0; i < shapes.length; i++) {\n for (let j = i + 1; j < shapes.length; j++) {\n const a = shapes[i]\n const b = shapes[j]\n if (!a || !b) continue\n for (const p of intersect(a, b).paths) {\n pairs.push(p)\n }\n }\n }\n if (!merged) return group(pairs)\n return unionAll(pairs)\n}\n\nexport const shapeBoolean = {\n union,\n unionAll,\n intersect,\n subtract,\n subtractAll,\n symDifference,\n complement,\n occlusionSubtract,\n overlapRegions,\n}\n","import type { Group, Path, Segment, Vec2 } from '../types/index.js'\nimport { path, normalizeRing, polygon, segment, group } from '../types/index.js'\nimport { bounds, containsPoint, centroid } from '../predicates/index.js'\nimport { intersect, unionAll } from '../shapeBoolean/index.js'\n\n/** Exterior ring as its own closed path (holes dropped). */\nexport function extractPerimeter(p: Path): Path {\n const exterior = p.rings[0]\n if (!exterior) return path([], true)\n return polygon(exterior)\n}\n\n/** Alias for extractPerimeter. */\nexport function extractBoundary(p: Path): Path {\n return extractPerimeter(p)\n}\n\n/** Each hole as a separate closed path. */\nexport function extractHoles(p: Path): Path[] {\n const holes: Path[] = []\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && hole.length >= 3) holes.push(polygon(hole))\n }\n return holes\n}\n\n/**\n * Insert vertices so no edge exceeds `maxSegLen`.\n * Closed rings treat the wrap-around edge.\n */\nexport function densify(p: Path, maxSegLen: number): Path {\n if (maxSegLen <= 0) return p\n return path(\n p.rings.map((ring) => densifyRing(ring, maxSegLen, p.closed)),\n p.closed,\n )\n}\n\nfunction densifyRing(\n ring: Vec2[],\n maxSegLen: number,\n closed: boolean,\n): Vec2[] {\n if (ring.length < 2) return [...ring]\n const out: Vec2[] = []\n const n = ring.length\n const edges = closed ? n : n - 1\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n out.push(a)\n const dist = Math.hypot(b.x - a.x, b.y - a.y)\n const steps = Math.floor(dist / maxSegLen)\n for (let s = 1; s < steps; s++) {\n const t = s / steps\n out.push({\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n })\n }\n }\n if (!closed) out.push(ring[n - 1]!)\n return closed ? normalizeRing(out) : out\n}\n\n/** Drop holes whose absolute area is below `minArea`. */\nexport function removeSmallHoles(p: Path, minArea: number): Path {\n if (p.rings.length <= 1) return p\n const exterior = p.rings[0]!\n const kept = p.rings.slice(1).filter((hole) => {\n const a = Math.abs(shoelace(hole))\n return a >= minArea\n })\n return path([exterior, ...kept], p.closed)\n}\n\n/** Seeded uniform random points inside a closed path. */\nexport function generateRandomPoints(\n p: Path,\n count: number,\n seed = 1,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const b = bounds(p)\n const out: Vec2[] = []\n let attempts = 0\n const maxAttempts = Math.max(count * 50, 100)\n while (out.length < count && attempts < maxAttempts) {\n attempts++\n const pt = {\n x: b.minX + rng() * (b.maxX - b.minX),\n y: b.minY + rng() * (b.maxY - b.minY),\n }\n if (containsPoint(p, pt)) out.push(pt)\n }\n return out\n}\n\n/** Axis-aligned grid samples that fall inside the path. */\nexport function generateRandomGridPoints(\n p: Path,\n spacing: number,\n): Vec2[] {\n const step = Math.max(spacing, 1e-9)\n const b = bounds(p)\n const out: Vec2[] = []\n for (let x = b.minX; x <= b.maxX + 1e-12; x += step) {\n for (let y = b.minY; y <= b.maxY + 1e-12; y += step) {\n const pt = { x, y }\n if (containsPoint(p, pt)) out.push(pt)\n }\n }\n return out\n}\n\n/** Evenly spaced samples along the exterior perimeter. */\nexport function pointsOnExterior(p: Path, count: number): Vec2[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2 || count <= 0) return []\n const lengths = edgeLengths(ring, true)\n const total = lengths.reduce((s, L) => s + L, 0)\n if (total < 1e-12) return []\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n const target = (i / count) * total\n out.push(pointAtArcLength(ring, lengths, target))\n }\n return out\n}\n\n/** Exterior edges as segments. */\nexport function segmentsOnExterior(p: Path): Segment[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2) return []\n const n = ring.length\n const closed = p.closed\n const edges = closed ? n : n - 1\n const out: Segment[] = []\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n return out\n}\n\n/**\n * Cut `p` with the infinite line through `a`→`b`.\n * Returns pieces on both sides (typically 0–2 paths).\n */\nexport function slice(p: Path, a: Vec2, b: Vec2): Group {\n const dx = b.x - a.x\n const dy = b.y - a.y\n const len = Math.hypot(dx, dy)\n if (len < 1e-12) return group([p])\n const nx = -dy / len\n const ny = dx / len\n const bb = bounds(p)\n const span =\n Math.hypot(bb.maxX - bb.minX, bb.maxY - bb.minY) * 4 + 10\n const left = halfPlanePoly(a, nx, ny, span)\n const right = halfPlanePoly(a, -nx, -ny, span)\n const parts: Path[] = []\n for (const half of [left, right]) {\n parts.push(...intersect(p, half).paths)\n }\n return group(parts)\n}\n\n/** Split through the centroid with a vertical cut (left/right). */\nexport function centroidSplit(p: Path): Group {\n const c = centroid(p)\n const bb = bounds(p)\n const pad = Math.max(bb.maxY - bb.minY, 1) + 1\n return slice(p, { x: c.x, y: c.y - pad }, { x: c.x, y: c.y + pad })\n}\n\n/** Union all closed paths in a group (dissolve overlapping contours). */\nexport function dissolve(paths: Path[]): Group {\n return unionAll(paths)\n}\n\n/** Vertex–edge intersection points between two path boundaries. */\nexport function intersectionPoints(a: Path, b: Path): Vec2[] {\n const segsA = allSegments(a)\n const segsB = allSegments(b)\n const out: Vec2[] = []\n const seen = new Set<string>()\n for (const sa of segsA) {\n for (const sb of segsB) {\n const hit = segmentIntersection(sa.a, sa.b, sb.a, sb.b)\n if (!hit) continue\n const key = `${hit.x.toFixed(9)},${hit.y.toFixed(9)}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push(hit)\n }\n }\n return out\n}\n\nfunction halfPlanePoly(\n origin: Vec2,\n nx: number,\n ny: number,\n span: number,\n): Path {\n // Orthonormal tangent\n const tx = -ny\n const ty = nx\n const o = origin\n return polygon([\n {\n x: o.x - tx * span + nx * 1e-9,\n y: o.y - ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * 1e-9,\n y: o.y + ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * span,\n y: o.y + ty * span + ny * span,\n },\n {\n x: o.x - tx * span + nx * span,\n y: o.y - ty * span + ny * span,\n },\n ])\n}\n\nfunction allSegments(p: Path): Segment[] {\n const out: Segment[] = []\n for (const ring of p.rings) {\n const n = ring.length\n const edges = p.closed ? n : Math.max(0, n - 1)\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n }\n return out\n}\n\nfunction segmentIntersection(\n a: Vec2,\n b: Vec2,\n c: Vec2,\n d: Vec2,\n): Vec2 | null {\n const rX = b.x - a.x\n const rY = b.y - a.y\n const sX = d.x - c.x\n const sY = d.y - c.y\n const den = rX * sY - rY * sX\n if (Math.abs(den) < 1e-14) return null\n const t = ((c.x - a.x) * sY - (c.y - a.y) * sX) / den\n const u = ((c.x - a.x) * rY - (c.y - a.y) * rX) / den\n if (t < -1e-9 || t > 1 + 1e-9 || u < -1e-9 || u > 1 + 1e-9) return null\n return { x: a.x + t * rX, y: a.y + t * rY }\n}\n\nfunction edgeLengths(ring: Vec2[], closed: boolean): number[] {\n const n = ring.length\n const edges = closed ? n : n - 1\n const lengths: number[] = []\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n lengths.push(Math.hypot(b.x - a.x, b.y - a.y))\n }\n return lengths\n}\n\nfunction pointAtArcLength(\n ring: Vec2[],\n lengths: number[],\n target: number,\n): Vec2 {\n let remain = target\n const n = ring.length\n for (let i = 0; i < lengths.length; i++) {\n const L = lengths[i]!\n if (remain <= L || i === lengths.length - 1) {\n const t = L < 1e-12 ? 0 : remain / L\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n return {\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n }\n }\n remain -= L\n }\n return { ...ring[0]! }\n}\n\nfunction shoelace(ring: Vec2[]): number {\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\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 processing = {\n extractPerimeter,\n extractBoundary,\n extractHoles,\n densify,\n removeSmallHoles,\n generateRandomPoints,\n generateRandomGridPoints,\n pointsOnExterior,\n segmentsOnExterior,\n slice,\n centroidSplit,\n dissolve,\n intersectionPoints,\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { V as Vec2 } from '../vec2-CWyXN1Wj.js';
|
|
2
|
+
import { S as Segment } from '../segment-BKuIFMKD.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parallel segments through a center point (PGS `parallelSegments` semantics).
|
|
6
|
+
* `length` is the half-length along the segment direction; full span is `2 * length`.
|
|
7
|
+
* `angle` is radians along the segment; spacing is perpendicular.
|
|
8
|
+
*/
|
|
9
|
+
declare function parallelSegments(centerX: number, centerY: number, length: number, spacing: number, angle: number, n: number): Segment[];
|
|
10
|
+
declare function filterByMinLength(segments: Segment[], minLength: number): Segment[];
|
|
11
|
+
declare function filterAxisAligned(segments: Segment[], angleDelta: number): Segment[];
|
|
12
|
+
declare function segmentLength(s: Segment): number;
|
|
13
|
+
declare function segmentsToOpenPaths(segments: Segment[]): {
|
|
14
|
+
rings: Vec2[][];
|
|
15
|
+
closed: false;
|
|
16
|
+
}[];
|
|
17
|
+
declare const segmentSet: {
|
|
18
|
+
parallelSegments: typeof parallelSegments;
|
|
19
|
+
filterByMinLength: typeof filterByMinLength;
|
|
20
|
+
filterAxisAligned: typeof filterAxisAligned;
|
|
21
|
+
segmentLength: typeof segmentLength;
|
|
22
|
+
segmentsToOpenPaths: typeof segmentsToOpenPaths;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export { Vec2, filterAxisAligned, filterByMinLength, parallelSegments, segmentLength, segmentSet, segmentsToOpenPaths };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/types/vec2.ts
|
|
2
|
+
function vec2(x, y) {
|
|
3
|
+
return { x, y };
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/types/segment.ts
|
|
7
|
+
function segment(a, b) {
|
|
8
|
+
return { a, b };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// src/segmentSet/index.ts
|
|
12
|
+
function f32(n) {
|
|
13
|
+
return Math.fround(n);
|
|
14
|
+
}
|
|
15
|
+
function parallelSegments(centerX, centerY, length, spacing, angle, n) {
|
|
16
|
+
const edges = [];
|
|
17
|
+
if (n < 1) return edges;
|
|
18
|
+
const center = vec2(f32(centerX), f32(centerY));
|
|
19
|
+
let dx = f32(Math.cos(angle + Math.PI / 2) * spacing);
|
|
20
|
+
let dy = f32(Math.sin(angle + Math.PI / 2) * spacing);
|
|
21
|
+
const cos = f32(Math.cos(angle));
|
|
22
|
+
const sin = f32(Math.sin(angle));
|
|
23
|
+
const l = f32(length);
|
|
24
|
+
let i;
|
|
25
|
+
let offX = 0;
|
|
26
|
+
let offY = 0;
|
|
27
|
+
if (n % 2 === 1) {
|
|
28
|
+
const a = vec2(f32(center.x + cos * l), f32(center.y + sin * l));
|
|
29
|
+
const b = vec2(f32(center.x + cos * -l), f32(center.y + sin * -l));
|
|
30
|
+
edges.push(segment(a, b));
|
|
31
|
+
i = 1;
|
|
32
|
+
} else {
|
|
33
|
+
dx = f32(dx / 2);
|
|
34
|
+
dy = f32(dy / 2);
|
|
35
|
+
i = 1;
|
|
36
|
+
{
|
|
37
|
+
let a = vec2(f32(center.x + dx * i), f32(center.y + dy * i));
|
|
38
|
+
const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l));
|
|
39
|
+
a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l));
|
|
40
|
+
edges.push(segment(a, b));
|
|
41
|
+
}
|
|
42
|
+
{
|
|
43
|
+
let a = vec2(f32(center.x + dx * -i), f32(center.y + dy * -i));
|
|
44
|
+
const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l));
|
|
45
|
+
a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l));
|
|
46
|
+
edges.push(segment(a, b));
|
|
47
|
+
}
|
|
48
|
+
i = 2;
|
|
49
|
+
dx = f32(dx * 2);
|
|
50
|
+
dy = f32(dy * 2);
|
|
51
|
+
offX = f32(dx / 2);
|
|
52
|
+
offY = f32(dy / 2);
|
|
53
|
+
}
|
|
54
|
+
for (; i < 1 + Math.floor(n / 2); i++) {
|
|
55
|
+
{
|
|
56
|
+
let a = vec2(
|
|
57
|
+
f32(center.x + dx * i - offX),
|
|
58
|
+
f32(center.y + dy * i - offY)
|
|
59
|
+
);
|
|
60
|
+
const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l));
|
|
61
|
+
a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l));
|
|
62
|
+
edges.push(segment(a, b));
|
|
63
|
+
}
|
|
64
|
+
{
|
|
65
|
+
let a = vec2(
|
|
66
|
+
f32(center.x + dx * -i + offX),
|
|
67
|
+
f32(center.y + dy * -i + offY)
|
|
68
|
+
);
|
|
69
|
+
const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l));
|
|
70
|
+
a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l));
|
|
71
|
+
edges.push(segment(a, b));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return edges;
|
|
75
|
+
}
|
|
76
|
+
function filterByMinLength(segments, minLength) {
|
|
77
|
+
return segments.filter((s) => segmentLength(s) >= minLength);
|
|
78
|
+
}
|
|
79
|
+
function filterAxisAligned(segments, angleDelta) {
|
|
80
|
+
return segments.filter((s) => {
|
|
81
|
+
const ang = Math.abs(Math.atan2(s.b.y - s.a.y, s.b.x - s.a.x));
|
|
82
|
+
const norm = Math.min(ang % Math.PI, Math.PI - ang % Math.PI);
|
|
83
|
+
const nearH = norm <= angleDelta || Math.abs(norm - Math.PI) <= angleDelta;
|
|
84
|
+
const nearV = Math.abs(norm - Math.PI / 2) <= angleDelta;
|
|
85
|
+
return !(nearH || nearV);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function segmentLength(s) {
|
|
89
|
+
const dx = s.b.x - s.a.x;
|
|
90
|
+
const dy = s.b.y - s.a.y;
|
|
91
|
+
return Math.hypot(dx, dy);
|
|
92
|
+
}
|
|
93
|
+
function segmentsToOpenPaths(segments) {
|
|
94
|
+
return segments.map((s) => ({
|
|
95
|
+
rings: [[s.a, s.b]],
|
|
96
|
+
closed: false
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
var segmentSet = {
|
|
100
|
+
parallelSegments,
|
|
101
|
+
filterByMinLength,
|
|
102
|
+
filterAxisAligned,
|
|
103
|
+
segmentLength,
|
|
104
|
+
segmentsToOpenPaths
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export { filterAxisAligned, filterByMinLength, parallelSegments, segmentLength, segmentSet, segmentsToOpenPaths };
|
|
108
|
+
//# sourceMappingURL=index.js.map
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/vec2.ts","../../src/types/segment.ts","../../src/segmentSet/index.ts"],"names":[],"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/** Line segment between two points. */\nexport type Segment = {\n a: Vec2\n b: Vec2\n}\n\nexport function segment(a: Vec2, b: Vec2): Segment {\n return { a, b }\n}\n","import type { Segment, Vec2 } from '../types/index.js'\nimport { segment, vec2 } from '../types/index.js'\n\n/** Match Processing `float` for PGS parity on hatch fixtures. */\nfunction f32(n: number): number {\n return Math.fround(n)\n}\n\n/**\n * Parallel segments through a center point (PGS `parallelSegments` semantics).\n * `length` is the half-length along the segment direction; full span is `2 * length`.\n * `angle` is radians along the segment; spacing is perpendicular.\n */\nexport function parallelSegments(\n centerX: number,\n centerY: number,\n length: number,\n spacing: number,\n angle: number,\n n: number,\n): Segment[] {\n const edges: Segment[] = []\n if (n < 1) return edges\n\n const center = vec2(f32(centerX), f32(centerY))\n let dx = f32(Math.cos(angle + Math.PI / 2) * spacing)\n let dy = f32(Math.sin(angle + Math.PI / 2) * spacing)\n const cos = f32(Math.cos(angle))\n const sin = f32(Math.sin(angle))\n const l = f32(length)\n\n let i: number\n let offX = 0\n let offY = 0\n\n if (n % 2 === 1) {\n const a = vec2(f32(center.x + cos * l), f32(center.y + sin * l))\n const b = vec2(f32(center.x + cos * -l), f32(center.y + sin * -l))\n edges.push(segment(a, b))\n i = 1\n } else {\n dx = f32(dx / 2)\n dy = f32(dy / 2)\n i = 1\n {\n let a = vec2(f32(center.x + dx * i), f32(center.y + dy * i))\n const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l))\n a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l))\n edges.push(segment(a, b))\n }\n {\n let a = vec2(f32(center.x + dx * -i), f32(center.y + dy * -i))\n const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l))\n a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l))\n edges.push(segment(a, b))\n }\n i = 2\n dx = f32(dx * 2)\n dy = f32(dy * 2)\n offX = f32(dx / 2)\n offY = f32(dy / 2)\n }\n\n for (; i < 1 + Math.floor(n / 2); i++) {\n {\n let a = vec2(\n f32(center.x + dx * i - offX),\n f32(center.y + dy * i - offY),\n )\n const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l))\n a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l))\n edges.push(segment(a, b))\n }\n {\n let a = vec2(\n f32(center.x + dx * -i + offX),\n f32(center.y + dy * -i + offY),\n )\n const b = vec2(f32(a.x + cos * l), f32(a.y + sin * l))\n a = vec2(f32(a.x + cos * -l), f32(a.y + sin * -l))\n edges.push(segment(a, b))\n }\n }\n\n return edges\n}\n\nexport function filterByMinLength(\n segments: Segment[],\n minLength: number,\n): Segment[] {\n return segments.filter((s) => segmentLength(s) >= minLength)\n}\n\nexport function filterAxisAligned(\n segments: Segment[],\n angleDelta: number,\n): Segment[] {\n return segments.filter((s) => {\n const ang = Math.abs(Math.atan2(s.b.y - s.a.y, s.b.x - s.a.x))\n const norm = Math.min(ang % Math.PI, Math.PI - (ang % Math.PI))\n const nearH = norm <= angleDelta || Math.abs(norm - Math.PI) <= angleDelta\n const nearV = Math.abs(norm - Math.PI / 2) <= angleDelta\n return !(nearH || nearV)\n })\n}\n\nexport function segmentLength(s: Segment): number {\n const dx = s.b.x - s.a.x\n const dy = s.b.y - s.a.y\n return Math.hypot(dx, dy)\n}\n\nexport function segmentsToOpenPaths(segments: Segment[]) {\n return segments.map((s) => ({\n rings: [[s.a, s.b]],\n closed: false as const,\n }))\n}\n\nexport const segmentSet = {\n parallelSegments,\n filterByMinLength,\n filterAxisAligned,\n segmentLength,\n segmentsToOpenPaths,\n}\n\nexport type { Vec2 }\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { P as Path } from '../path-0RjhYjJs.js';
|
|
2
|
+
import { G as Group } from '../group-BNjVVYSQ.js';
|
|
3
|
+
import '../vec2-CWyXN1Wj.js';
|
|
4
|
+
|
|
5
|
+
/** Union of two closed paths. */
|
|
6
|
+
declare function union(a: Path, b: Path): Group;
|
|
7
|
+
/** Union of many closed paths (folded left-to-right). */
|
|
8
|
+
declare function unionAll(paths: Path[]): Group;
|
|
9
|
+
/** Intersection of two closed paths. */
|
|
10
|
+
declare function intersect(a: Path, b: Path): Group;
|
|
11
|
+
/** Subtract b from a (a \ b). */
|
|
12
|
+
declare function subtract(a: Path, b: Path): Group;
|
|
13
|
+
/** Subtract many shapes from a base. */
|
|
14
|
+
declare function subtractAll(base: Path, shapes: Path[]): Group;
|
|
15
|
+
/** Symmetric difference. */
|
|
16
|
+
declare function symDifference(a: Path, b: Path): Group;
|
|
17
|
+
/** Complement of shape within axis-aligned rectangle [0,width] x [0,height]. */
|
|
18
|
+
declare function complement(shape: Path, width: number, height: number): Group;
|
|
19
|
+
/**
|
|
20
|
+
* Painter-style occlusion: later paths in the group are on top.
|
|
21
|
+
* Each path has higher paths subtracted from it; returns visible remainders.
|
|
22
|
+
*/
|
|
23
|
+
declare function occlusionSubtract(g: Group): Group;
|
|
24
|
+
/**
|
|
25
|
+
* Regions covered by at least two input shapes.
|
|
26
|
+
* If `merged`, collapse multi-overlaps into disjoint patches via union of pairwise intersects.
|
|
27
|
+
*/
|
|
28
|
+
declare function overlapRegions(shapes: Path[], merged: boolean): Group;
|
|
29
|
+
declare const shapeBoolean: {
|
|
30
|
+
union: typeof union;
|
|
31
|
+
unionAll: typeof unionAll;
|
|
32
|
+
intersect: typeof intersect;
|
|
33
|
+
subtract: typeof subtract;
|
|
34
|
+
subtractAll: typeof subtractAll;
|
|
35
|
+
symDifference: typeof symDifference;
|
|
36
|
+
complement: typeof complement;
|
|
37
|
+
occlusionSubtract: typeof occlusionSubtract;
|
|
38
|
+
overlapRegions: typeof overlapRegions;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { complement, intersect, occlusionSubtract, overlapRegions, shapeBoolean, subtract, subtractAll, symDifference, union, unionAll };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { FillRule, unionD, isPositiveD, intersectD, differenceD, xorD, pointInPolygonD, PointInPolygonResult } from 'clipper2-ts';
|
|
2
|
+
|
|
3
|
+
// src/types/vec2.ts
|
|
4
|
+
function vec2(x, y) {
|
|
5
|
+
return { x, y };
|
|
6
|
+
}
|
|
7
|
+
function cloneVec2(v) {
|
|
8
|
+
return { x: v.x, y: v.y };
|
|
9
|
+
}
|
|
10
|
+
function equalsVec2(a, b, eps = 1e-9) {
|
|
11
|
+
return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/types/path.ts
|
|
15
|
+
function path(rings, closed = true) {
|
|
16
|
+
return {
|
|
17
|
+
rings: rings.map((ring) => ring.map(cloneVec2)),
|
|
18
|
+
closed
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function polygon(exterior, holes = []) {
|
|
22
|
+
return path([exterior, ...holes], true);
|
|
23
|
+
}
|
|
24
|
+
function normalizeRing(ring, eps = 1e-9) {
|
|
25
|
+
if (ring.length < 2) return ring.map(cloneVec2);
|
|
26
|
+
const first = ring[0];
|
|
27
|
+
const last = ring[ring.length - 1];
|
|
28
|
+
if (first && last && equalsVec2(first, last, eps)) {
|
|
29
|
+
return ring.slice(0, -1).map(cloneVec2);
|
|
30
|
+
}
|
|
31
|
+
return ring.map(cloneVec2);
|
|
32
|
+
}
|
|
33
|
+
function clonePath(p) {
|
|
34
|
+
return {
|
|
35
|
+
closed: p.closed,
|
|
36
|
+
rings: p.rings.map((ring) => ring.map(cloneVec2))
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/types/group.ts
|
|
41
|
+
function group(paths = []) {
|
|
42
|
+
return { paths: paths.map(clonePath) };
|
|
43
|
+
}
|
|
44
|
+
function groupFromPaths(...paths) {
|
|
45
|
+
return group(paths);
|
|
46
|
+
}
|
|
47
|
+
var DEFAULT_FILL_RULE = FillRule.NonZero;
|
|
48
|
+
function ringToPathD(ring) {
|
|
49
|
+
const pts = [];
|
|
50
|
+
for (const v of normalizeRing(ring)) {
|
|
51
|
+
pts.push({ x: v.x, y: v.y, z: 0 });
|
|
52
|
+
}
|
|
53
|
+
return pts;
|
|
54
|
+
}
|
|
55
|
+
function pathToPathsD(p) {
|
|
56
|
+
if (!p.closed || p.rings.length === 0) {
|
|
57
|
+
throw new Error("Boolean ops require a closed path with at least one ring");
|
|
58
|
+
}
|
|
59
|
+
return p.rings.map((ring) => ringToPathD(ring));
|
|
60
|
+
}
|
|
61
|
+
function pathsDToGroup(paths) {
|
|
62
|
+
if (paths.length === 0) return group([]);
|
|
63
|
+
const outers = [];
|
|
64
|
+
const holes = [];
|
|
65
|
+
for (const pd of paths) {
|
|
66
|
+
const ring = pathDToRing(pd);
|
|
67
|
+
if (ring.length < 3) continue;
|
|
68
|
+
if (isPositiveD(pd)) {
|
|
69
|
+
outers.push({ ring, holes: [] });
|
|
70
|
+
} else {
|
|
71
|
+
holes.push(ring);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const hole of holes) {
|
|
75
|
+
const sample = hole[0];
|
|
76
|
+
if (!sample) continue;
|
|
77
|
+
let assigned = false;
|
|
78
|
+
for (const outer of outers) {
|
|
79
|
+
if (pointInRing(sample, outer.ring)) {
|
|
80
|
+
outer.holes.push(hole);
|
|
81
|
+
assigned = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!assigned) {
|
|
86
|
+
outers.push({ ring: [...hole].reverse(), holes: [] });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return group(outers.map((o) => path([o.ring, ...o.holes], true)));
|
|
90
|
+
}
|
|
91
|
+
function pathDToRing(pd) {
|
|
92
|
+
return normalizeRing(pd.map((p) => vec2(p.x, p.y)));
|
|
93
|
+
}
|
|
94
|
+
function pointInRing(point, ring) {
|
|
95
|
+
const result = pointInPolygonD(
|
|
96
|
+
{ x: point.x, y: point.y, z: 0 },
|
|
97
|
+
ringToPathD(ring)
|
|
98
|
+
);
|
|
99
|
+
return result === PointInPolygonResult.IsInside || result === PointInPolygonResult.IsOn;
|
|
100
|
+
}
|
|
101
|
+
function clipUnion(a, b) {
|
|
102
|
+
return unionD(a, b, DEFAULT_FILL_RULE);
|
|
103
|
+
}
|
|
104
|
+
function clipIntersect(a, b) {
|
|
105
|
+
return intersectD(a, b, DEFAULT_FILL_RULE);
|
|
106
|
+
}
|
|
107
|
+
function clipDifference(a, b) {
|
|
108
|
+
return differenceD(a, b, DEFAULT_FILL_RULE);
|
|
109
|
+
}
|
|
110
|
+
function clipXor(a, b) {
|
|
111
|
+
return xorD(a, b, DEFAULT_FILL_RULE);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/shapeBoolean/index.ts
|
|
115
|
+
function ensureClosed(p) {
|
|
116
|
+
if (!p.closed) {
|
|
117
|
+
throw new Error("shapeBoolean requires closed paths");
|
|
118
|
+
}
|
|
119
|
+
return p;
|
|
120
|
+
}
|
|
121
|
+
function union(a, b) {
|
|
122
|
+
const result = clipUnion(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)));
|
|
123
|
+
return pathsDToGroup(result);
|
|
124
|
+
}
|
|
125
|
+
function unionAll(paths) {
|
|
126
|
+
if (paths.length === 0) return group([]);
|
|
127
|
+
let acc = pathToPathsD(ensureClosed(paths[0]));
|
|
128
|
+
for (let i = 1; i < paths.length; i++) {
|
|
129
|
+
acc = clipUnion(acc, pathToPathsD(ensureClosed(paths[i])));
|
|
130
|
+
}
|
|
131
|
+
return pathsDToGroup(acc);
|
|
132
|
+
}
|
|
133
|
+
function intersect(a, b) {
|
|
134
|
+
const result = clipIntersect(
|
|
135
|
+
pathToPathsD(ensureClosed(a)),
|
|
136
|
+
pathToPathsD(ensureClosed(b))
|
|
137
|
+
);
|
|
138
|
+
return pathsDToGroup(result);
|
|
139
|
+
}
|
|
140
|
+
function subtract(a, b) {
|
|
141
|
+
const result = clipDifference(
|
|
142
|
+
pathToPathsD(ensureClosed(a)),
|
|
143
|
+
pathToPathsD(ensureClosed(b))
|
|
144
|
+
);
|
|
145
|
+
return pathsDToGroup(result);
|
|
146
|
+
}
|
|
147
|
+
function subtractAll(base, shapes) {
|
|
148
|
+
let acc = pathToPathsD(ensureClosed(base));
|
|
149
|
+
for (const s of shapes) {
|
|
150
|
+
acc = clipDifference(acc, pathToPathsD(ensureClosed(s)));
|
|
151
|
+
}
|
|
152
|
+
return pathsDToGroup(acc);
|
|
153
|
+
}
|
|
154
|
+
function symDifference(a, b) {
|
|
155
|
+
const result = clipXor(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)));
|
|
156
|
+
return pathsDToGroup(result);
|
|
157
|
+
}
|
|
158
|
+
function complement(shape, width, height) {
|
|
159
|
+
const frame = polygon([
|
|
160
|
+
vec2(0, 0),
|
|
161
|
+
vec2(width, 0),
|
|
162
|
+
vec2(width, height),
|
|
163
|
+
vec2(0, height)
|
|
164
|
+
]);
|
|
165
|
+
return subtract(frame, shape);
|
|
166
|
+
}
|
|
167
|
+
function occlusionSubtract(g) {
|
|
168
|
+
const paths = g.paths;
|
|
169
|
+
const visible = [];
|
|
170
|
+
for (let i = 0; i < paths.length; i++) {
|
|
171
|
+
const subject = paths[i];
|
|
172
|
+
if (!subject) continue;
|
|
173
|
+
const occluders = paths.slice(i + 1);
|
|
174
|
+
const piece = occluders.length === 0 ? groupFromPaths(ensureClosed(subject)) : subtractAll(subject, occluders);
|
|
175
|
+
for (const p of piece.paths) {
|
|
176
|
+
visible.push(p);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return group(visible);
|
|
180
|
+
}
|
|
181
|
+
function overlapRegions(shapes, merged) {
|
|
182
|
+
if (shapes.length < 2) return group([]);
|
|
183
|
+
const pairs = [];
|
|
184
|
+
for (let i = 0; i < shapes.length; i++) {
|
|
185
|
+
for (let j = i + 1; j < shapes.length; j++) {
|
|
186
|
+
const a = shapes[i];
|
|
187
|
+
const b = shapes[j];
|
|
188
|
+
if (!a || !b) continue;
|
|
189
|
+
for (const p of intersect(a, b).paths) {
|
|
190
|
+
pairs.push(p);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!merged) return group(pairs);
|
|
195
|
+
return unionAll(pairs);
|
|
196
|
+
}
|
|
197
|
+
var shapeBoolean = {
|
|
198
|
+
union,
|
|
199
|
+
unionAll,
|
|
200
|
+
intersect,
|
|
201
|
+
subtract,
|
|
202
|
+
subtractAll,
|
|
203
|
+
symDifference,
|
|
204
|
+
complement,
|
|
205
|
+
occlusionSubtract,
|
|
206
|
+
overlapRegions
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export { complement, intersect, occlusionSubtract, overlapRegions, shapeBoolean, subtract, subtractAll, symDifference, union, unionAll };
|
|
210
|
+
//# sourceMappingURL=index.js.map
|
|
211
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types/vec2.ts","../../src/types/path.ts","../../src/types/group.ts","../../src/clipper/convert.ts","../../src/shapeBoolean/index.ts"],"names":[],"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'\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 {\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 } from '../types/index.js'\nimport { group, groupFromPaths, path, polygon, vec2 } from '../types/index.js'\nimport {\n clipDifference,\n clipIntersect,\n clipUnion,\n clipXor,\n pathToPathsD,\n pathsDToGroup,\n} from '../clipper/convert.js'\n\nfunction ensureClosed(p: Path): Path {\n if (!p.closed) {\n throw new Error('shapeBoolean requires closed paths')\n }\n return p\n}\n\n/** Union of two closed paths. */\nexport function union(a: Path, b: Path): Group {\n const result = clipUnion(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Union of many closed paths (folded left-to-right). */\nexport function unionAll(paths: Path[]): Group {\n if (paths.length === 0) return group([])\n let acc = pathToPathsD(ensureClosed(paths[0]!))\n for (let i = 1; i < paths.length; i++) {\n acc = clipUnion(acc, pathToPathsD(ensureClosed(paths[i]!)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Intersection of two closed paths. */\nexport function intersect(a: Path, b: Path): Group {\n const result = clipIntersect(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract b from a (a \\ b). */\nexport function subtract(a: Path, b: Path): Group {\n const result = clipDifference(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract many shapes from a base. */\nexport function subtractAll(base: Path, shapes: Path[]): Group {\n let acc = pathToPathsD(ensureClosed(base))\n for (const s of shapes) {\n acc = clipDifference(acc, pathToPathsD(ensureClosed(s)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Symmetric difference. */\nexport function symDifference(a: Path, b: Path): Group {\n const result = clipXor(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Complement of shape within axis-aligned rectangle [0,width] x [0,height]. */\nexport function complement(shape: Path, width: number, height: number): Group {\n const frame = polygon([\n vec2(0, 0),\n vec2(width, 0),\n vec2(width, height),\n vec2(0, height),\n ])\n return subtract(frame, shape)\n}\n\n/**\n * Painter-style occlusion: later paths in the group are on top.\n * Each path has higher paths subtracted from it; returns visible remainders.\n */\nexport function occlusionSubtract(g: Group): Group {\n const paths = g.paths\n const visible: Path[] = []\n for (let i = 0; i < paths.length; i++) {\n const subject = paths[i]\n if (!subject) continue\n const occluders = paths.slice(i + 1)\n const piece =\n occluders.length === 0\n ? groupFromPaths(ensureClosed(subject))\n : subtractAll(subject, occluders)\n for (const p of piece.paths) {\n visible.push(p)\n }\n }\n return group(visible)\n}\n\n/**\n * Regions covered by at least two input shapes.\n * If `merged`, collapse multi-overlaps into disjoint patches via union of pairwise intersects.\n */\nexport function overlapRegions(shapes: Path[], merged: boolean): Group {\n if (shapes.length < 2) return group([])\n const pairs: Path[] = []\n for (let i = 0; i < shapes.length; i++) {\n for (let j = i + 1; j < shapes.length; j++) {\n const a = shapes[i]\n const b = shapes[j]\n if (!a || !b) continue\n for (const p of intersect(a, b).paths) {\n pairs.push(p)\n }\n }\n }\n if (!merged) return group(pairs)\n return unionAll(pairs)\n}\n\nexport const shapeBoolean = {\n union,\n unionAll,\n intersect,\n subtract,\n subtractAll,\n symDifference,\n complement,\n occlusionSubtract,\n overlapRegions,\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { G as Group } from '../group-BNjVVYSQ.js';
|
|
2
|
+
import { R as Ring } from '../path-0RjhYjJs.js';
|
|
3
|
+
import '../vec2-CWyXN1Wj.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parse a subset of SVG into a geometry group.
|
|
7
|
+
* Supports: `path` (M/L/H/V/Z), `rect`, `circle`, `line`, `polyline`, `polygon`.
|
|
8
|
+
* Element order in the document is preserved (later = on top for occlusion).
|
|
9
|
+
*/
|
|
10
|
+
declare function parseSvg(svg: string): Group;
|
|
11
|
+
|
|
12
|
+
type ToSvgOptions = {
|
|
13
|
+
/** SVG viewBox attribute, e.g. `"0 0 100 100"`. */
|
|
14
|
+
viewBox?: string;
|
|
15
|
+
/** Root width/height attributes (optional). */
|
|
16
|
+
width?: number | string;
|
|
17
|
+
height?: number | string;
|
|
18
|
+
/** Stroke color (default `#000`). */
|
|
19
|
+
stroke?: string;
|
|
20
|
+
/** Stroke width (default `1`). */
|
|
21
|
+
strokeWidth?: number | string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Serialize a group to plotter-oriented SVG (`fill="none"`, stroked paths).
|
|
25
|
+
*/
|
|
26
|
+
declare function toSvg(g: Group, options?: ToSvgOptions): string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Minimal SVG path `d` tokenizer for plotter-oriented paths.
|
|
30
|
+
* Supports M/m L/l H/h V/v Z/z. Curves are rejected with a clear error (Phase 1).
|
|
31
|
+
*/
|
|
32
|
+
declare function parsePathData(d: string): {
|
|
33
|
+
rings: Ring[];
|
|
34
|
+
closed: boolean;
|
|
35
|
+
};
|
|
36
|
+
declare function serializePathData(rings: Ring[], closed: boolean): string;
|
|
37
|
+
|
|
38
|
+
export { type ToSvgOptions, parsePathData, parseSvg, serializePathData, toSvg };
|