@weasel-js/geom 1.11.0 → 1.11.1

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.
@@ -64,7 +64,8 @@ interface SnapProblem<M> {
64
64
  candidates: readonly SnapCandidate<M>[];
65
65
  /** World to screen pixels. A non-finite result puts that position out of reach. */
66
66
  toScreen(world: Vec): Vec;
67
- /** Candidates kept per probe, nearest first. Default 24. */
67
+ /** Candidates kept per probe, nearest first, besides the required ones,
68
+ * which are all kept. Default 24. */
68
69
  poolSize?: number;
69
70
  /** World-space tolerance for "on the locus". Default 1e-6. */
70
71
  eps?: number;
package/dist/nd/index.js CHANGED
@@ -1,8 +1,7 @@
1
1
  export { PORT_REACH, cubicAt, portControls, portCurvePoints } from '../chunk-YQADYJJ7.js';
2
2
 
3
3
  // src/snap/flat.ts
4
- var RANK_TOL = 1e-9;
5
- var PIVOT_TOL = 1e-12;
4
+ var RANK_TOL = 1e-6;
6
5
  function dotv(a, b) {
7
6
  let s = 0;
8
7
  for (let i = 0; i < a.length; i++) s += a[i] * b[i];
@@ -55,29 +54,22 @@ function closestOnFlat(f, p) {
55
54
  function solveLeastSquares(cols, rhs) {
56
55
  const k = cols.length;
57
56
  const m = cols.map((a) => [...cols.map((b) => dotv(a, b)), dotv(a, rhs)]);
58
- let maxDiag = 0;
59
- for (let i = 0; i < k; i++) maxDiag = Math.max(maxDiag, Math.abs(m[i][i]));
60
- const tol = PIVOT_TOL * (maxDiag || 1);
61
- const pivots = [];
62
- let row = 0;
63
- for (let col = 0; col < k && row < k; col++) {
64
- let best = row;
65
- for (let r = row + 1; r < k; r++) if (Math.abs(m[r][col]) > Math.abs(m[best][col])) best = r;
66
- if (!(Math.abs(m[best][col]) > tol)) continue;
67
- [m[row], m[best]] = [m[best], m[row]];
68
- for (let r = row + 1; r < k; r++) {
69
- const f = m[r][col] / m[row][col];
70
- for (let c = col; c <= k; c++) m[r][c] -= f * m[row][c];
57
+ const len2 = m.map((r, i) => r[i]);
58
+ const kept = [];
59
+ for (let col = 0; col < k; col++) {
60
+ if (!(m[col][col] > RANK_TOL * RANK_TOL * len2[col])) continue;
61
+ for (let r = col + 1; r < k; r++) {
62
+ const f = m[r][col] / m[col][col];
63
+ for (let c = col; c <= k; c++) m[r][c] -= f * m[col][c];
71
64
  }
72
- pivots.push([row, col]);
73
- row++;
65
+ kept.push(col);
74
66
  }
75
67
  const x = new Array(k).fill(0);
76
- for (let p = pivots.length - 1; p >= 0; p--) {
77
- const [r, col] = pivots[p];
78
- let s = m[r][k];
79
- for (let c = col + 1; c < k; c++) s -= m[r][c] * x[c];
80
- x[col] = s / m[r][col];
68
+ for (let p = kept.length - 1; p >= 0; p--) {
69
+ const col = kept[p];
70
+ let s = m[col][k];
71
+ for (let c = col + 1; c < k; c++) s -= m[col][c] * x[c];
72
+ x[col] = s / m[col][col];
81
73
  }
82
74
  return x;
83
75
  }
@@ -149,7 +141,7 @@ function liveCandidates(problem, m) {
149
141
  const live = [];
150
142
  for (const c of problem.candidates) {
151
143
  const probe = probes.get(c.probe);
152
- if (!probe || !isFiniteVec2(probe) || !isFiniteVec2(c.locus.at)) continue;
144
+ if (!probe || !isFiniteVec2(probe) || !isFiniteVec2(c.locus.at) || !c.locus.dirs.every(isFiniteVec2)) continue;
153
145
  const within = intersectFlats(problem.input, { at: minus(c.locus.at, probe), dirs: c.locus.dirs }, m.eps);
154
146
  if (!within) continue;
155
147
  const px = meets(m, c, probe, closestOnFlat(within, problem.delta0));
@@ -167,7 +159,7 @@ function pool(live, size) {
167
159
  const out = [];
168
160
  for (const list of byProbe.values()) {
169
161
  list.sort((a, b) => Math.abs(a.px - b.px) > SAME_PX ? a.px - b.px : a.c.order - b.c.order);
170
- out.push(...list.slice(0, size));
162
+ out.push(...list.filter((l, i) => i < size || l.c.required));
171
163
  }
172
164
  return out;
173
165
  }
@@ -183,7 +175,8 @@ function compareCombos(a, b) {
183
175
  if (Math.abs(a.px - b.px) > SAME_PX) return a.px - b.px;
184
176
  return compareOrders(a.members, b.members);
185
177
  }
186
- function extend(parent, l, hDim, delta0, m) {
178
+ function extend(parent, l, input, delta0, m) {
179
+ const hDim = flatDim(input);
187
180
  const flat = intersectFlats(parent.flat, l.within, m.eps);
188
181
  if (!flat) return null;
189
182
  const dim = flatDim(flat);
@@ -191,15 +184,17 @@ function extend(parent, l, hDim, delta0, m) {
191
184
  const delta = closestOnFlat(flat, delta0);
192
185
  if (!isFiniteVec2(delta)) return null;
193
186
  const members = [...parent.members, l];
187
+ for (const mem of members) if (meets(m, mem.c, mem.probe, delta) === null) return null;
188
+ const targetFlat = l.c.tier === "target" ? intersectFlats(parent.targetFlat, l.within, m.eps) ?? flat : parent.targetFlat;
189
+ const kept = prune(members, input, dim, flatDim(targetFlat), m.eps);
194
190
  let px = 0;
195
- for (const mem of members) {
191
+ for (const mem of kept) {
196
192
  const p = meets(m, mem.c, mem.probe, delta);
197
193
  if (p === null) return null;
198
194
  px = Math.max(px, p);
199
195
  }
200
- const targetFlat = l.c.tier === "target" ? intersectFlats(parent.targetFlat, l.within, m.eps) ?? flat : parent.targetFlat;
201
196
  return {
202
- members,
197
+ members: kept,
203
198
  flat,
204
199
  dim,
205
200
  targetFlat,
@@ -209,6 +204,26 @@ function extend(parent, l, hDim, delta0, m) {
209
204
  targetCodim: hDim - flatDim(targetFlat)
210
205
  };
211
206
  }
207
+ function flatsOf(members, input, eps) {
208
+ let flat = input;
209
+ let target = input;
210
+ for (const mem of members) {
211
+ flat = intersectFlats(flat, mem.within, eps);
212
+ if (!flat) return null;
213
+ if (mem.c.tier === "target") target = intersectFlats(target, mem.within, eps) ?? flat;
214
+ }
215
+ return { dim: flatDim(flat), targetDim: flatDim(target) };
216
+ }
217
+ function prune(members, input, dim, targetDim, eps) {
218
+ let kept = members;
219
+ for (let i = 0; i < kept.length && kept.length > 1; ) {
220
+ const rest = kept.filter((_, j) => j !== i);
221
+ const f = flatsOf(rest, input, eps);
222
+ if (f && f.dim === dim && f.targetDim === targetDim) kept = rest;
223
+ else i++;
224
+ }
225
+ return kept;
226
+ }
212
227
  function search(candidates, root, delta0, m) {
213
228
  const best = { any: root, required: null };
214
229
  const consider = (c) => {
@@ -219,7 +234,7 @@ function search(candidates, root, delta0, m) {
219
234
  };
220
235
  const visit = (start, parent) => {
221
236
  for (let i = start; i < candidates.length; i++) {
222
- const next = extend(parent, candidates[i], root.dim, delta0, m);
237
+ const next = extend(parent, candidates[i], root.flat, delta0, m);
223
238
  if (!next) continue;
224
239
  consider(next);
225
240
  if (next.dim > 0) visit(i + 1, next);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/snap/flat.ts","../../src/snap/resolve.ts","../../src/snap/stepLine.ts"],"names":["isFiniteVec"],"mappings":"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","file":"index.js","sourcesContent":["/** Affine subspaces (\"flats\") over plain number arrays, in any dimension:\n * the points, lines and planes a snap resolves against. */\n\nexport type Vec = readonly number[];\n\n/** The affine subspace `at + span(dirs)`. `dirs` need not be orthonormal or\n * independent; a zero or repeated direction adds nothing. */\nexport interface Flat {\n at: Vec;\n dirs: readonly Vec[];\n}\n\n/** A direction left with less than this fraction of its length after the\n * ones before it are taken out counts as dependent on them. */\nconst RANK_TOL = 1e-9;\n/** Pivots below this fraction of the largest diagonal entry count as zero. */\nconst PIVOT_TOL = 1e-12;\n\nfunction dotv(a: Vec, b: Vec): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += a[i] * b[i];\n return s;\n}\n\nfunction normv(a: Vec): number {\n return Math.sqrt(dotv(a, a));\n}\n\nfunction isFiniteVec(a: Vec): boolean {\n return a.every(Number.isFinite);\n}\n\n/** An orthonormal basis of `span(vecs)`, built by Gram-Schmidt with a second\n * pass for stability. Non-finite and dependent vectors are dropped. */\nexport function orthonormalize(vecs: readonly Vec[], start: readonly Vec[] = []): number[][] {\n const basis: number[][] = start.map((q) => q.slice());\n const out: number[][] = [];\n for (const d of vecs) {\n const n0 = normv(d);\n if (!(n0 > 0) || !isFiniteVec(d)) continue;\n const v = d.slice();\n for (let pass = 0; pass < 2; pass++) {\n for (const q of basis) {\n const k = dotv(v, q);\n for (let i = 0; i < v.length; i++) v[i] -= k * q[i];\n }\n }\n const n = normv(v);\n if (n <= RANK_TOL * n0) continue;\n for (let i = 0; i < v.length; i++) v[i] /= n;\n basis.push(v);\n out.push(v);\n }\n return out;\n}\n\n/** An orthonormal basis of the orthogonal complement of the orthonormal `basis` in R^n. */\nfunction complement(basis: readonly Vec[], n: number): number[][] {\n const axes: number[][] = [];\n for (let i = 0; i < n; i++) axes.push(Array.from({ length: n }, (_, j) => (i === j ? 1 : 0)));\n return orthonormalize(axes, basis);\n}\n\n/** The flat's dimension: the rank of its directions. */\nexport function flatDim(f: Flat): number {\n return orthonormalize(f.dirs).length;\n}\n\n/** The point of `f` nearest `p`. */\nexport function closestOnFlat(f: Flat, p: Vec): Vec {\n const out = f.at.slice();\n for (const q of orthonormalize(f.dirs)) {\n let k = 0;\n for (let i = 0; i < q.length; i++) k += q[i] * (p[i] - f.at[i]);\n for (let i = 0; i < out.length; i++) out[i] += k * q[i];\n }\n return out;\n}\n\n/**\n * The `x` minimizing `|Σ x_j cols_j − rhs|`, through the normal equations.\n * A rank-deficient system has many minimizers; this returns the one whose\n * free unknowns are zero.\n */\nexport function solveLeastSquares(cols: readonly Vec[], rhs: Vec): number[] {\n const k = cols.length;\n const m = cols.map((a) => [...cols.map((b) => dotv(a, b)), dotv(a, rhs)]);\n let maxDiag = 0;\n for (let i = 0; i < k; i++) maxDiag = Math.max(maxDiag, Math.abs(m[i][i]));\n const tol = PIVOT_TOL * (maxDiag || 1);\n const pivots: [row: number, col: number][] = [];\n let row = 0;\n for (let col = 0; col < k && row < k; col++) {\n let best = row;\n for (let r = row + 1; r < k; r++) if (Math.abs(m[r][col]) > Math.abs(m[best][col])) best = r;\n if (!(Math.abs(m[best][col]) > tol)) continue;\n [m[row], m[best]] = [m[best], m[row]];\n for (let r = row + 1; r < k; r++) {\n const f = m[r][col] / m[row][col];\n for (let c = col; c <= k; c++) m[r][c] -= f * m[row][c];\n }\n pivots.push([row, col]);\n row++;\n }\n const x = new Array<number>(k).fill(0);\n for (let p = pivots.length - 1; p >= 0; p--) {\n const [r, col] = pivots[p];\n let s = m[r][k];\n for (let c = col + 1; c < k; c++) s -= m[r][c] * x[c];\n x[col] = s / m[r][col];\n }\n return x;\n}\n\n/** The nearest pair of points, one on each flat. Parallel flats have many\n * such pairs; this returns one of them. */\nexport function closestBetweenFlats(a: Flat, b: Flat): { onA: Vec; onB: Vec } {\n const qa = orthonormalize(a.dirs);\n const qb = orthonormalize(b.dirs);\n const d = b.at.map((v, i) => v - a.at[i]);\n const x = solveLeastSquares([...qa, ...qb.map((q) => q.map((v) => -v))], d);\n const onA = a.at.slice();\n const onB = b.at.slice();\n qa.forEach((q, j) => q.forEach((v, i) => { onA[i] += x[j] * v; }));\n qb.forEach((q, j) => q.forEach((v, i) => { onB[i] += x[qa.length + j] * v; }));\n return { onA, onB };\n}\n\n/** `a ∩ b`, or null when they miss each other by more than `eps`. */\nexport function intersectFlats(a: Flat, b: Flat, eps = 1e-6): Flat | null {\n const { onA, onB } = closestBetweenFlats(a, b);\n let gap2 = 0;\n for (let i = 0; i < onA.length; i++) gap2 += (onA[i] - onB[i]) ** 2;\n if (!(Math.sqrt(gap2) <= eps) || !isFiniteVec(onA)) return null;\n const n = a.at.length;\n const normals = orthonormalize([\n ...complement(orthonormalize(a.dirs), n),\n ...complement(orthonormalize(b.dirs), n),\n ]);\n return { at: onA, dirs: complement(normals, n) };\n}\n","/** The snap resolver: every gesture's snap, in any dimension, as one search\n * over affine constraints on the move `δ`. */\n\nimport { closestOnFlat, flatDim, intersectFlats, solveLeastSquares, type Flat, type Vec } from './flat';\n\n/** A `fallback` candidate holds only the axes no `target` claims. */\nexport type SnapTier = 'target' | 'fallback';\n/** What a probe stands for on the subject; sources match probes by role. */\nexport type ProbeRole = 'origin' | 'box' | 'geometry' | 'pointer';\n\n/** A point on the subject that should land on a locus. `role` says which\n * sources may match it. */\nexport interface SnapProbe {\n id: string;\n at: Vec;\n role: ProbeRole;\n}\n\n/** One probe paired with one locus. `M` is the mark payload, opaque here. */\nexport interface SnapCandidate<M> {\n /** `SnapProbe.id`. */\n probe: string;\n locus: Flat;\n /** One interval per locus dir, in multiples of that dir. A solution\n * outside it fails the candidate. */\n span?: readonly (readonly [number, number])[];\n source: string;\n /** Stable tiebreak: lower wins when everything else is equal. */\n order: number;\n tier: SnapTier;\n reachPx: number;\n /** When any required candidate exists, the result includes one of them,\n * whatever its reach. */\n required?: boolean;\n mark?: M;\n}\n\n/** One frame's snap: the probes, the input subspace, the raw move, and the candidates. */\nexport interface SnapProblem<M> {\n probes: readonly SnapProbe[];\n /** `H`, the subspace of δ-space the result stays inside. */\n input: Flat;\n /** The unsnapped move. */\n delta0: Vec;\n candidates: readonly SnapCandidate<M>[];\n /** World to screen pixels. A non-finite result puts that position out of reach. */\n toScreen(world: Vec): Vec;\n /** Candidates kept per probe, nearest first. Default 24. */\n poolSize?: number;\n /** World-space tolerance for \"on the locus\". Default 1e-6. */\n eps?: number;\n}\n\n/** The move `resolveSnap` chose and the candidates it meets. */\nexport interface SnapResolution<M> {\n /** `closestOnFlat(input, delta0)` when nothing snaps. */\n delta: Vec;\n members: readonly SnapCandidate<M>[];\n /** Every in-reach candidate the result meets: the ones whose marks show. */\n satisfied: readonly SnapCandidate<M>[];\n /** How many dimensions of `H` the result pins. */\n codim: number;\n}\n\n/** A candidate that can be met on its own: its probe, and `H ∩ C` in δ-space. */\ninterface Live<M> {\n c: SnapCandidate<M>;\n probe: Vec;\n within: Flat;\n px: number;\n}\n\ninterface Combo<M> {\n members: Live<M>[];\n flat: Flat;\n dim: number;\n targetFlat: Flat;\n delta: Vec;\n codim: number;\n targetCodim: number;\n px: number;\n}\n\nconst DEFAULT_POOL = 24;\nconst DEFAULT_EPS = 1e-6;\n/** Screen displacements closer than this rank as equal, so order decides. */\nconst SAME_PX = 1e-9;\n\nconst plus = (a: Vec, b: Vec): Vec => a.map((v, i) => v + b[i]);\nconst minus = (a: Vec, b: Vec): Vec => a.map((v, i) => v - b[i]);\nconst isFiniteVec = (a: Vec): boolean => a.every(Number.isFinite);\n\nfunction distance(a: Vec, b: Vec): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += (a[i] - b[i]) ** 2;\n return Math.sqrt(s);\n}\n\n/** What the resolver needs to measure a candidate against a trial δ. */\ninterface Measure {\n /** Screen pixels the probe moves going from δ0 (projected into `H`) to\n * `delta`; NaN when either end has no finite screen position. */\n move(probeId: string, probe: Vec, delta: Vec): number;\n eps: number;\n}\n\nfunction makeMeasure<M>(problem: SnapProblem<M>, base: Vec, eps: number): Measure {\n const home = new Map<string, Vec>();\n return {\n eps,\n move(probeId, probe, delta) {\n let h = home.get(probeId);\n if (!h) home.set(probeId, (h = problem.toScreen(plus(probe, base))));\n const d = distance(problem.toScreen(plus(probe, delta)), h);\n return Number.isFinite(d) ? d : NaN;\n },\n };\n}\n\nfunction spanHolds<M>(c: SnapCandidate<M>, world: Vec, eps: number): boolean {\n if (!c.span) return true;\n const u = solveLeastSquares(c.locus.dirs, minus(world, c.locus.at));\n return c.span.every(([lo, hi], i) => u[i] >= lo - eps && u[i] <= hi + eps);\n}\n\n/** The probe's screen move under `delta`, or null when it is out of reach or off the span. */\nfunction meets<M>(m: Measure, c: SnapCandidate<M>, probe: Vec, delta: Vec): number | null {\n const measured = m.move(c.probe, probe, delta);\n if (!c.required && (Number.isNaN(measured) || !(measured <= c.reachPx))) return null;\n const px = Number.isNaN(measured) ? Infinity : measured;\n return spanHolds(c, plus(probe, delta), m.eps) ? px : null;\n}\n\nfunction liveCandidates<M>(problem: SnapProblem<M>, m: Measure): Live<M>[] {\n const probes = new Map(problem.probes.map((p) => [p.id, p.at]));\n const live: Live<M>[] = [];\n for (const c of problem.candidates) {\n const probe = probes.get(c.probe);\n if (!probe || !isFiniteVec(probe) || !isFiniteVec(c.locus.at)) continue;\n const within = intersectFlats(problem.input, { at: minus(c.locus.at, probe), dirs: c.locus.dirs }, m.eps);\n if (!within) continue;\n const px = meets(m, c, probe, closestOnFlat(within, problem.delta0));\n if (px !== null) live.push({ c, probe, within, px });\n }\n return live;\n}\n\nfunction pool<M>(live: Live<M>[], size: number): Live<M>[] {\n const byProbe = new Map<string, Live<M>[]>();\n for (const l of live) {\n const list = byProbe.get(l.c.probe) ?? [];\n list.push(l);\n byProbe.set(l.c.probe, list);\n }\n const out: Live<M>[] = [];\n for (const list of byProbe.values()) {\n list.sort((a, b) => (Math.abs(a.px - b.px) > SAME_PX ? a.px - b.px : a.c.order - b.c.order));\n out.push(...list.slice(0, size));\n }\n return out;\n}\n\nfunction compareOrders<M>(a: Live<M>[], b: Live<M>[]): number {\n const oa = a.map((l) => l.c.order).sort((x, y) => x - y);\n const ob = b.map((l) => l.c.order).sort((x, y) => x - y);\n for (let i = 0; i < Math.min(oa.length, ob.length); i++) if (oa[i] !== ob[i]) return oa[i] - ob[i];\n return oa.length - ob.length;\n}\n\n/** Negative when `a` ranks ahead of `b`. */\nfunction compareCombos<M>(a: Combo<M>, b: Combo<M>): number {\n if (a.codim !== b.codim) return b.codim - a.codim;\n if (a.targetCodim !== b.targetCodim) return b.targetCodim - a.targetCodim;\n if (Math.abs(a.px - b.px) > SAME_PX) return a.px - b.px;\n return compareOrders(a.members, b.members);\n}\n\n/** `parent` plus `l`, or null when `l` adds no constraint or breaks a member's reach or span. */\nfunction extend<M>(parent: Combo<M>, l: Live<M>, hDim: number, delta0: Vec, m: Measure): Combo<M> | null {\n const flat = intersectFlats(parent.flat, l.within, m.eps);\n if (!flat) return null;\n const dim = flatDim(flat);\n if (dim >= parent.dim) return null;\n const delta = closestOnFlat(flat, delta0);\n if (!isFiniteVec(delta)) return null;\n const members = [...parent.members, l];\n let px = 0;\n for (const mem of members) {\n const p = meets(m, mem.c, mem.probe, delta);\n if (p === null) return null;\n px = Math.max(px, p);\n }\n const targetFlat = l.c.tier === 'target'\n ? intersectFlats(parent.targetFlat, l.within, m.eps) ?? flat\n : parent.targetFlat;\n return {\n members, flat, dim, targetFlat, delta, px,\n codim: hDim - dim,\n targetCodim: hDim - flatDim(targetFlat),\n };\n}\n\n/** The best combination; when any can include a required candidate, the best of those. */\nfunction search<M>(candidates: Live<M>[], root: Combo<M>, delta0: Vec, m: Measure): Combo<M> {\n const best: { any: Combo<M>; required: Combo<M> | null } = { any: root, required: null };\n const consider = (c: Combo<M>) => {\n if (compareCombos(c, best.any) < 0) best.any = c;\n if (c.members.some((l) => l.c.required) && (!best.required || compareCombos(c, best.required) < 0)) {\n best.required = c;\n }\n };\n const visit = (start: number, parent: Combo<M>) => {\n for (let i = start; i < candidates.length; i++) {\n const next = extend(parent, candidates[i], root.dim, delta0, m);\n if (!next) continue;\n consider(next);\n if (next.dim > 0) visit(i + 1, next);\n }\n };\n visit(0, root);\n return best.required ?? best.any;\n}\n\nfunction satisfiedBy<M>(problem: SnapProblem<M>, delta: Vec, m: Measure): SnapCandidate<M>[] {\n const probes = new Map(problem.probes.map((p) => [p.id, p.at]));\n return problem.candidates.filter((c) => {\n const probe = probes.get(c.probe);\n if (!probe) return false;\n const world = plus(probe, delta);\n if (!(distance(closestOnFlat(c.locus, world), world) <= m.eps)) return false;\n return meets(m, c, probe, delta) !== null;\n });\n}\n\n/** The move nearest `delta0` within `H` that meets the best-ranked set of\n * candidates in reach, or `delta0` projected into `H` when none is. */\nexport function resolveSnap<M>(problem: SnapProblem<M>): SnapResolution<M> {\n const { input, delta0 } = problem;\n let base = closestOnFlat(input, delta0);\n if (!isFiniteVec(base)) base = isFiniteVec(input.at) ? input.at : input.at.map(() => 0);\n const m = makeMeasure(problem, base, problem.eps ?? DEFAULT_EPS);\n const hDim = flatDim(input);\n const root: Combo<M> = {\n members: [], flat: input, dim: hDim, targetFlat: input, delta: base, codim: 0, targetCodim: 0, px: 0,\n };\n const live = pool(liveCandidates(problem, m), problem.poolSize ?? DEFAULT_POOL);\n const win = search(live, root, delta0, m);\n return {\n delta: win.delta,\n members: win.members.map((l) => l.c),\n satisfied: satisfiedBy(problem, win.delta, m),\n codim: win.codim,\n };\n}\n","import type { Flat, Vec } from './flat';\n\n/**\n * The line through `about` whose direction, measured in the plane `basis`\n * spans (as an angle from `basis[0]` toward `basis[1]`), is the multiple of\n * `step` nearest the direction from `about` to `toward`: a constrained\n * gesture's input subspace, in any dimension. `basis` is orthonormal.\n */\nexport function stepLine(about: Vec, toward: Vec, basis: readonly [Vec, Vec], step: number): Flat {\n const [u, v] = basis;\n let a = 0;\n let b = 0;\n for (let i = 0; i < about.length; i++) {\n const d = toward[i] - about[i];\n a += d * u[i];\n b += d * v[i];\n }\n const theta = a === 0 && b === 0 ? 0 : Math.round(Math.atan2(b, a) / step) * step;\n const c = Math.cos(theta);\n const s = Math.sin(theta);\n return { at: about, dirs: [u.map((x, i) => x * c + v[i] * s)] };\n}\n"]}
1
+ {"version":3,"sources":["../../src/snap/flat.ts","../../src/snap/resolve.ts","../../src/snap/stepLine.ts"],"names":["isFiniteVec"],"mappings":"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","file":"index.js","sourcesContent":["/** Affine subspaces (\"flats\") over plain number arrays, in any dimension:\n * the points, lines and planes a snap resolves against. */\n\nexport type Vec = readonly number[];\n\n/** The affine subspace `at + span(dirs)`. `dirs` need not be orthonormal or\n * independent; a zero or repeated direction adds nothing. */\nexport interface Flat {\n at: Vec;\n dirs: readonly Vec[];\n}\n\n/** A direction left with less than this fraction of its length after the\n * ones before it are taken out counts as dependent on them. The solve's\n * pivots are those leftover lengths squared, so it shares this one value.\n * Squaring loses angles below about 1e-8 rad to rounding; at 1e-8 the two\n * verdicts part, so this sits two decades clear. */\nconst RANK_TOL = 1e-6;\n\nfunction dotv(a: Vec, b: Vec): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += a[i] * b[i];\n return s;\n}\n\nfunction normv(a: Vec): number {\n return Math.sqrt(dotv(a, a));\n}\n\nfunction isFiniteVec(a: Vec): boolean {\n return a.every(Number.isFinite);\n}\n\n/** An orthonormal basis of `span(vecs)`, built by Gram-Schmidt with a second\n * pass for stability. Non-finite and dependent vectors are dropped. */\nexport function orthonormalize(vecs: readonly Vec[], start: readonly Vec[] = []): number[][] {\n const basis: number[][] = start.map((q) => q.slice());\n const out: number[][] = [];\n for (const d of vecs) {\n const n0 = normv(d);\n if (!(n0 > 0) || !isFiniteVec(d)) continue;\n const v = d.slice();\n for (let pass = 0; pass < 2; pass++) {\n for (const q of basis) {\n const k = dotv(v, q);\n for (let i = 0; i < v.length; i++) v[i] -= k * q[i];\n }\n }\n const n = normv(v);\n if (n <= RANK_TOL * n0) continue;\n for (let i = 0; i < v.length; i++) v[i] /= n;\n basis.push(v);\n out.push(v);\n }\n return out;\n}\n\n/** An orthonormal basis of the orthogonal complement of the orthonormal `basis` in R^n. */\nfunction complement(basis: readonly Vec[], n: number): number[][] {\n const axes: number[][] = [];\n for (let i = 0; i < n; i++) axes.push(Array.from({ length: n }, (_, j) => (i === j ? 1 : 0)));\n return orthonormalize(axes, basis);\n}\n\n/** The flat's dimension: the rank of its directions. */\nexport function flatDim(f: Flat): number {\n return orthonormalize(f.dirs).length;\n}\n\n/** The point of `f` nearest `p`. */\nexport function closestOnFlat(f: Flat, p: Vec): Vec {\n const out = f.at.slice();\n for (const q of orthonormalize(f.dirs)) {\n let k = 0;\n for (let i = 0; i < q.length; i++) k += q[i] * (p[i] - f.at[i]);\n for (let i = 0; i < out.length; i++) out[i] += k * q[i];\n }\n return out;\n}\n\n/**\n * The `x` minimizing `|Σ x_j cols_j − rhs|`, through the normal equations.\n * A column within `RANK_TOL` of the span of the kept ones before it is\n * dropped, the same verdict `orthonormalize` reaches, and its unknown is zero.\n */\nexport function solveLeastSquares(cols: readonly Vec[], rhs: Vec): number[] {\n const k = cols.length;\n const m = cols.map((a) => [...cols.map((b) => dotv(a, b)), dotv(a, rhs)]);\n const len2 = m.map((r, i) => r[i]);\n const kept: number[] = [];\n for (let col = 0; col < k; col++) {\n if (!(m[col][col] > RANK_TOL * RANK_TOL * len2[col])) continue;\n for (let r = col + 1; r < k; r++) {\n const f = m[r][col] / m[col][col];\n for (let c = col; c <= k; c++) m[r][c] -= f * m[col][c];\n }\n kept.push(col);\n }\n const x = new Array<number>(k).fill(0);\n for (let p = kept.length - 1; p >= 0; p--) {\n const col = kept[p];\n let s = m[col][k];\n for (let c = col + 1; c < k; c++) s -= m[col][c] * x[c];\n x[col] = s / m[col][col];\n }\n return x;\n}\n\n/** The nearest pair of points, one on each flat. Parallel flats have many\n * such pairs; this returns one of them. */\nexport function closestBetweenFlats(a: Flat, b: Flat): { onA: Vec; onB: Vec } {\n const qa = orthonormalize(a.dirs);\n const qb = orthonormalize(b.dirs);\n const d = b.at.map((v, i) => v - a.at[i]);\n const x = solveLeastSquares([...qa, ...qb.map((q) => q.map((v) => -v))], d);\n const onA = a.at.slice();\n const onB = b.at.slice();\n qa.forEach((q, j) => q.forEach((v, i) => { onA[i] += x[j] * v; }));\n qb.forEach((q, j) => q.forEach((v, i) => { onB[i] += x[qa.length + j] * v; }));\n return { onA, onB };\n}\n\n/** `a ∩ b`, or null when they miss each other by more than `eps`. */\nexport function intersectFlats(a: Flat, b: Flat, eps = 1e-6): Flat | null {\n const { onA, onB } = closestBetweenFlats(a, b);\n let gap2 = 0;\n for (let i = 0; i < onA.length; i++) gap2 += (onA[i] - onB[i]) ** 2;\n if (!(Math.sqrt(gap2) <= eps) || !isFiniteVec(onA)) return null;\n const n = a.at.length;\n const normals = orthonormalize([\n ...complement(orthonormalize(a.dirs), n),\n ...complement(orthonormalize(b.dirs), n),\n ]);\n return { at: onA, dirs: complement(normals, n) };\n}\n","/** The snap resolver: every gesture's snap, in any dimension, as one search\n * over affine constraints on the move `δ`. */\n\nimport { closestOnFlat, flatDim, intersectFlats, solveLeastSquares, type Flat, type Vec } from './flat';\n\n/** A `fallback` candidate holds only the axes no `target` claims. */\nexport type SnapTier = 'target' | 'fallback';\n/** What a probe stands for on the subject; sources match probes by role. */\nexport type ProbeRole = 'origin' | 'box' | 'geometry' | 'pointer';\n\n/** A point on the subject that should land on a locus. `role` says which\n * sources may match it. */\nexport interface SnapProbe {\n id: string;\n at: Vec;\n role: ProbeRole;\n}\n\n/** One probe paired with one locus. `M` is the mark payload, opaque here. */\nexport interface SnapCandidate<M> {\n /** `SnapProbe.id`. */\n probe: string;\n locus: Flat;\n /** One interval per locus dir, in multiples of that dir. A solution\n * outside it fails the candidate. */\n span?: readonly (readonly [number, number])[];\n source: string;\n /** Stable tiebreak: lower wins when everything else is equal. */\n order: number;\n tier: SnapTier;\n reachPx: number;\n /** When any required candidate exists, the result includes one of them,\n * whatever its reach. */\n required?: boolean;\n mark?: M;\n}\n\n/** One frame's snap: the probes, the input subspace, the raw move, and the candidates. */\nexport interface SnapProblem<M> {\n probes: readonly SnapProbe[];\n /** `H`, the subspace of δ-space the result stays inside. */\n input: Flat;\n /** The unsnapped move. */\n delta0: Vec;\n candidates: readonly SnapCandidate<M>[];\n /** World to screen pixels. A non-finite result puts that position out of reach. */\n toScreen(world: Vec): Vec;\n /** Candidates kept per probe, nearest first, besides the required ones,\n * which are all kept. Default 24. */\n poolSize?: number;\n /** World-space tolerance for \"on the locus\". Default 1e-6. */\n eps?: number;\n}\n\n/** The move `resolveSnap` chose and the candidates it meets. */\nexport interface SnapResolution<M> {\n /** `closestOnFlat(input, delta0)` when nothing snaps. */\n delta: Vec;\n members: readonly SnapCandidate<M>[];\n /** Every in-reach candidate the result meets: the ones whose marks show. */\n satisfied: readonly SnapCandidate<M>[];\n /** How many dimensions of `H` the result pins. */\n codim: number;\n}\n\n/** A candidate that can be met on its own: its probe, and `H ∩ C` in δ-space. */\ninterface Live<M> {\n c: SnapCandidate<M>;\n probe: Vec;\n within: Flat;\n px: number;\n}\n\ninterface Combo<M> {\n members: Live<M>[];\n flat: Flat;\n dim: number;\n targetFlat: Flat;\n delta: Vec;\n codim: number;\n targetCodim: number;\n px: number;\n}\n\nconst DEFAULT_POOL = 24;\nconst DEFAULT_EPS = 1e-6;\n/** Screen displacements closer than this rank as equal, so order decides. */\nconst SAME_PX = 1e-9;\n\nconst plus = (a: Vec, b: Vec): Vec => a.map((v, i) => v + b[i]);\nconst minus = (a: Vec, b: Vec): Vec => a.map((v, i) => v - b[i]);\nconst isFiniteVec = (a: Vec): boolean => a.every(Number.isFinite);\n\nfunction distance(a: Vec, b: Vec): number {\n let s = 0;\n for (let i = 0; i < a.length; i++) s += (a[i] - b[i]) ** 2;\n return Math.sqrt(s);\n}\n\n/** What the resolver needs to measure a candidate against a trial δ. */\ninterface Measure {\n /** Screen pixels the probe moves going from δ0 (projected into `H`) to\n * `delta`; NaN when either end has no finite screen position. */\n move(probeId: string, probe: Vec, delta: Vec): number;\n eps: number;\n}\n\nfunction makeMeasure<M>(problem: SnapProblem<M>, base: Vec, eps: number): Measure {\n const home = new Map<string, Vec>();\n return {\n eps,\n move(probeId, probe, delta) {\n let h = home.get(probeId);\n if (!h) home.set(probeId, (h = problem.toScreen(plus(probe, base))));\n const d = distance(problem.toScreen(plus(probe, delta)), h);\n return Number.isFinite(d) ? d : NaN;\n },\n };\n}\n\nfunction spanHolds<M>(c: SnapCandidate<M>, world: Vec, eps: number): boolean {\n if (!c.span) return true;\n const u = solveLeastSquares(c.locus.dirs, minus(world, c.locus.at));\n return c.span.every(([lo, hi], i) => u[i] >= lo - eps && u[i] <= hi + eps);\n}\n\n/** The probe's screen move under `delta`, or null when it is out of reach or off the span. */\nfunction meets<M>(m: Measure, c: SnapCandidate<M>, probe: Vec, delta: Vec): number | null {\n const measured = m.move(c.probe, probe, delta);\n if (!c.required && (Number.isNaN(measured) || !(measured <= c.reachPx))) return null;\n const px = Number.isNaN(measured) ? Infinity : measured;\n return spanHolds(c, plus(probe, delta), m.eps) ? px : null;\n}\n\nfunction liveCandidates<M>(problem: SnapProblem<M>, m: Measure): Live<M>[] {\n const probes = new Map(problem.probes.map((p) => [p.id, p.at]));\n const live: Live<M>[] = [];\n for (const c of problem.candidates) {\n const probe = probes.get(c.probe);\n if (!probe || !isFiniteVec(probe) || !isFiniteVec(c.locus.at) || !c.locus.dirs.every(isFiniteVec)) continue;\n const within = intersectFlats(problem.input, { at: minus(c.locus.at, probe), dirs: c.locus.dirs }, m.eps);\n if (!within) continue;\n const px = meets(m, c, probe, closestOnFlat(within, problem.delta0));\n if (px !== null) live.push({ c, probe, within, px });\n }\n return live;\n}\n\nfunction pool<M>(live: Live<M>[], size: number): Live<M>[] {\n const byProbe = new Map<string, Live<M>[]>();\n for (const l of live) {\n const list = byProbe.get(l.c.probe) ?? [];\n list.push(l);\n byProbe.set(l.c.probe, list);\n }\n const out: Live<M>[] = [];\n for (const list of byProbe.values()) {\n list.sort((a, b) => (Math.abs(a.px - b.px) > SAME_PX ? a.px - b.px : a.c.order - b.c.order));\n out.push(...list.filter((l, i) => i < size || l.c.required));\n }\n return out;\n}\n\nfunction compareOrders<M>(a: Live<M>[], b: Live<M>[]): number {\n const oa = a.map((l) => l.c.order).sort((x, y) => x - y);\n const ob = b.map((l) => l.c.order).sort((x, y) => x - y);\n for (let i = 0; i < Math.min(oa.length, ob.length); i++) if (oa[i] !== ob[i]) return oa[i] - ob[i];\n return oa.length - ob.length;\n}\n\n/** Negative when `a` ranks ahead of `b`. */\nfunction compareCombos<M>(a: Combo<M>, b: Combo<M>): number {\n if (a.codim !== b.codim) return b.codim - a.codim;\n if (a.targetCodim !== b.targetCodim) return b.targetCodim - a.targetCodim;\n if (Math.abs(a.px - b.px) > SAME_PX) return a.px - b.px;\n return compareOrders(a.members, b.members);\n}\n\n/** `parent` plus `l`, or null when `l` adds no constraint or breaks a member's reach or span. */\nfunction extend<M>(parent: Combo<M>, l: Live<M>, input: Flat, delta0: Vec, m: Measure): Combo<M> | null {\n const hDim = flatDim(input);\n const flat = intersectFlats(parent.flat, l.within, m.eps);\n if (!flat) return null;\n const dim = flatDim(flat);\n if (dim >= parent.dim) return null;\n const delta = closestOnFlat(flat, delta0);\n if (!isFiniteVec(delta)) return null;\n const members = [...parent.members, l];\n for (const mem of members) if (meets(m, mem.c, mem.probe, delta) === null) return null;\n const targetFlat = l.c.tier === 'target'\n ? intersectFlats(parent.targetFlat, l.within, m.eps) ?? flat\n : parent.targetFlat;\n const kept = prune(members, input, dim, flatDim(targetFlat), m.eps);\n let px = 0;\n for (const mem of kept) {\n const p = meets(m, mem.c, mem.probe, delta);\n if (p === null) return null;\n px = Math.max(px, p);\n }\n return {\n members: kept, flat, dim, targetFlat, delta, px,\n codim: hDim - dim,\n targetCodim: hDim - flatDim(targetFlat),\n };\n}\n\n/** The flat `members` pin inside `input`, and the one their target-tier members pin. */\nfunction flatsOf<M>(members: readonly Live<M>[], input: Flat, eps: number): { dim: number; targetDim: number } | null {\n let flat: Flat | null = input;\n let target: Flat = input;\n for (const mem of members) {\n flat = intersectFlats(flat, mem.within, eps);\n if (!flat) return null;\n if (mem.c.tier === 'target') target = intersectFlats(target, mem.within, eps) ?? flat;\n }\n return { dim: flatDim(flat), targetDim: flatDim(target) };\n}\n\n/** `members` less every one the rest already imply, oldest first, so a\n * redundant member neither shows in `members` nor decides a tie on order. */\nfunction prune<M>(members: Live<M>[], input: Flat, dim: number, targetDim: number, eps: number): Live<M>[] {\n let kept = members;\n for (let i = 0; i < kept.length && kept.length > 1;) {\n const rest = kept.filter((_, j) => j !== i);\n const f = flatsOf(rest, input, eps);\n if (f && f.dim === dim && f.targetDim === targetDim) kept = rest;\n else i++;\n }\n return kept;\n}\n\n/** The best combination; when any can include a required candidate, the best of those. */\nfunction search<M>(candidates: Live<M>[], root: Combo<M>, delta0: Vec, m: Measure): Combo<M> {\n const best: { any: Combo<M>; required: Combo<M> | null } = { any: root, required: null };\n const consider = (c: Combo<M>) => {\n if (compareCombos(c, best.any) < 0) best.any = c;\n if (c.members.some((l) => l.c.required) && (!best.required || compareCombos(c, best.required) < 0)) {\n best.required = c;\n }\n };\n const visit = (start: number, parent: Combo<M>) => {\n for (let i = start; i < candidates.length; i++) {\n const next = extend(parent, candidates[i], root.flat, delta0, m);\n if (!next) continue;\n consider(next);\n if (next.dim > 0) visit(i + 1, next);\n }\n };\n visit(0, root);\n return best.required ?? best.any;\n}\n\nfunction satisfiedBy<M>(problem: SnapProblem<M>, delta: Vec, m: Measure): SnapCandidate<M>[] {\n const probes = new Map(problem.probes.map((p) => [p.id, p.at]));\n return problem.candidates.filter((c) => {\n const probe = probes.get(c.probe);\n if (!probe) return false;\n const world = plus(probe, delta);\n if (!(distance(closestOnFlat(c.locus, world), world) <= m.eps)) return false;\n return meets(m, c, probe, delta) !== null;\n });\n}\n\n/** The move nearest `delta0` within `H` that meets the best-ranked set of\n * candidates in reach, or `delta0` projected into `H` when none is. */\nexport function resolveSnap<M>(problem: SnapProblem<M>): SnapResolution<M> {\n const { input, delta0 } = problem;\n let base = closestOnFlat(input, delta0);\n if (!isFiniteVec(base)) base = isFiniteVec(input.at) ? input.at : input.at.map(() => 0);\n const m = makeMeasure(problem, base, problem.eps ?? DEFAULT_EPS);\n const hDim = flatDim(input);\n const root: Combo<M> = {\n members: [], flat: input, dim: hDim, targetFlat: input, delta: base, codim: 0, targetCodim: 0, px: 0,\n };\n const live = pool(liveCandidates(problem, m), problem.poolSize ?? DEFAULT_POOL);\n const win = search(live, root, delta0, m);\n return {\n delta: win.delta,\n members: win.members.map((l) => l.c),\n satisfied: satisfiedBy(problem, win.delta, m),\n codim: win.codim,\n };\n}\n","import type { Flat, Vec } from './flat';\n\n/**\n * The line through `about` whose direction, measured in the plane `basis`\n * spans (as an angle from `basis[0]` toward `basis[1]`), is the multiple of\n * `step` nearest the direction from `about` to `toward`: a constrained\n * gesture's input subspace, in any dimension. `basis` is orthonormal.\n */\nexport function stepLine(about: Vec, toward: Vec, basis: readonly [Vec, Vec], step: number): Flat {\n const [u, v] = basis;\n let a = 0;\n let b = 0;\n for (let i = 0; i < about.length; i++) {\n const d = toward[i] - about[i];\n a += d * u[i];\n b += d * v[i];\n }\n const theta = a === 0 && b === 0 ? 0 : Math.round(Math.atan2(b, a) / step) * step;\n const c = Math.cos(theta);\n const s = Math.sin(theta);\n return { at: about, dirs: [u.map((x, i) => x * c + v[i] * s)] };\n}\n"]}
@@ -1,6 +1,6 @@
1
- export { extractPolylines } from '../chunk-6XSJY3TC.js';
2
- export { tessellate } from '../chunk-SASMXDBE.js';
3
- import '../chunk-J2O2B54M.js';
1
+ export { extractPolylines } from '../chunk-7F66PQCJ.js';
2
+ export { tessellate } from '../chunk-LRVPK7HI.js';
3
+ import '../chunk-EAKE3N7W.js';
4
4
  import '../chunk-755Y4YZS.js';
5
5
  import '../chunk-B53BERKG.js';
6
6
 
@@ -137,7 +137,9 @@ declare function puppetMesh(path: PolygonPath, pins: readonly Point[], opts?: Pu
137
137
  * between them moved as rigidly as the pins allow. The shape's fill is
138
138
  * triangulated (`puppetMesh`) and deformed as-rigid-as-possible (`arap`), so
139
139
  * the pull of a pin travels through the shape: two limbs that nearly touch
140
- * share no triangle and move apart. A point follows the triangle holding it.
140
+ * share no triangle and move apart. A point is carried by a smooth
141
+ * (Clough–Tocher) interpolation of the deformed mesh, so a bend has no kink
142
+ * where two triangles meet.
141
143
  */
142
144
 
143
145
  /** A pin: where it was placed on the unwarped shape, and where it is now. */
@@ -146,11 +148,11 @@ interface PuppetPin {
146
148
  to: Point;
147
149
  }
148
150
  /**
149
- * The map `pins` make of `source`'s fill: each point carried by the triangle
150
- * of the deformed mesh holding it, or the nearest one for a point off the
151
+ * The map `pins` make of `source`'s fill: smooth across the deformed mesh,
152
+ * through every pin, and carried on past the outline for a point off the
151
153
  * shape. The mesh and its solve are set up once per source and pin set, so
152
- * moving pins only re-solves. No pins is the identity, and one pin moves the
153
- * whole shape with it.
154
+ * moving pins only re-solves. No pins, or none moved, is the identity, and
155
+ * one pin moves the whole shape with it.
154
156
  */
155
157
  declare function puppetMap(source: PolygonPath, pins: readonly PuppetPin[]): (p: Point) => Point;
156
158
  /**
@@ -1,8 +1,8 @@
1
- import { boundsOfPath, keepCorner, fitPointRun } from '../chunk-HGF5OVEN.js';
1
+ import { boundsOfPath, keepCorner, fitPointRun } from '../chunk-6FGQML7D.js';
2
2
  import { pathToAnchors, anchorsToPath } from '../chunk-Q66NA2FU.js';
3
3
  import '../chunk-CE7IY7TB.js';
4
- import { nestRings, flattenPolygon, resolveCrossings } from '../chunk-SASMXDBE.js';
5
- import { pointInPolygon } from '../chunk-J2O2B54M.js';
4
+ import { nestRings, flattenPolygon, resolveCrossings } from '../chunk-LRVPK7HI.js';
5
+ import { pointInPolygon } from '../chunk-EAKE3N7W.js';
6
6
  import '../chunk-755Y4YZS.js';
7
7
  import { cubicPointAt } from '../chunk-B53BERKG.js';
8
8
  import earcut from 'earcut';
@@ -697,6 +697,144 @@ function createArapSolver(mesh, pinned) {
697
697
  };
698
698
  }
699
699
 
700
+ // src/warp/cloughTocher.ts
701
+ function restFrames2(mesh) {
702
+ const V = mesh.vertices, T = mesh.triangles;
703
+ const nt = T.length / 3;
704
+ const inverse = new Float64Array(4 * nt);
705
+ const area = new Float64Array(nt);
706
+ for (let t = 0; t < nt; t++) {
707
+ const a = T[3 * t], b = T[3 * t + 1], c = T[3 * t + 2];
708
+ const ux = V[2 * b] - V[2 * a], uy = V[2 * b + 1] - V[2 * a + 1];
709
+ const vx = V[2 * c] - V[2 * a], vy = V[2 * c + 1] - V[2 * a + 1];
710
+ const det = ux * vy - uy * vx;
711
+ if (det === 0) continue;
712
+ inverse.set([vy / det, -vx / det, -uy / det, ux / det], 4 * t);
713
+ area[t] = Math.abs(det) / 2;
714
+ }
715
+ return { inverse, area };
716
+ }
717
+ function vertexDerivatives(mesh, frames, at) {
718
+ const T = mesh.triangles;
719
+ const nv = mesh.vertices.length / 2;
720
+ const J = new Float64Array(4 * nv);
721
+ const weight = new Float64Array(nv);
722
+ for (let t = 0; t < T.length / 3; t++) {
723
+ const w = frames.area[t];
724
+ if (w === 0) continue;
725
+ const a = T[3 * t], b = T[3 * t + 1], c = T[3 * t + 2];
726
+ const ux = at[2 * b] - at[2 * a], uy = at[2 * b + 1] - at[2 * a + 1];
727
+ const vx = at[2 * c] - at[2 * a], vy = at[2 * c + 1] - at[2 * a + 1];
728
+ const i = frames.inverse;
729
+ const m0 = ux * i[4 * t] + vx * i[4 * t + 2], m1 = ux * i[4 * t + 1] + vx * i[4 * t + 3];
730
+ const m2 = uy * i[4 * t] + vy * i[4 * t + 2], m3 = uy * i[4 * t + 1] + vy * i[4 * t + 3];
731
+ for (const v of [a, b, c]) {
732
+ J[4 * v] += w * m0;
733
+ J[4 * v + 1] += w * m1;
734
+ J[4 * v + 2] += w * m2;
735
+ J[4 * v + 3] += w * m3;
736
+ weight[v] += w;
737
+ }
738
+ }
739
+ for (let v = 0; v < nv; v++) {
740
+ if (weight[v] === 0) {
741
+ J[4 * v] = 1;
742
+ J[4 * v + 3] = 1;
743
+ continue;
744
+ }
745
+ for (let k = 0; k < 4; k++) J[4 * v + k] /= weight[v];
746
+ }
747
+ return J;
748
+ }
749
+ var F = 0;
750
+ var S = 3;
751
+ var I = 6;
752
+ var N = 9;
753
+ var P = 12;
754
+ var M = 15;
755
+ var C = 18;
756
+ var ORDINATES = 19;
757
+ function buildOrdinates(V, T, at, J, t, out) {
758
+ const vx = [0, 0, 0], vy = [0, 0, 0], v = [0, 0, 0];
759
+ for (let k = 0; k < 3; k++) {
760
+ v[k] = T[3 * t + k];
761
+ vx[k] = V[2 * v[k]];
762
+ vy[k] = V[2 * v[k] + 1];
763
+ }
764
+ const sx = (vx[0] + vx[1] + vx[2]) / 3, sy = (vy[0] + vy[1] + vy[2]) / 3;
765
+ const set = (o, x2, y2) => {
766
+ out[2 * o] = x2;
767
+ out[2 * o + 1] = y2;
768
+ };
769
+ const x = (o) => out[2 * o], y = (o) => out[2 * o + 1];
770
+ const toward = (o, k, px, py) => {
771
+ const dx = (px - vx[k]) / 3, dy = (py - vy[k]) / 3, j = 4 * v[k];
772
+ set(o, at[2 * v[k]] + J[j] * dx + J[j + 1] * dy, at[2 * v[k] + 1] + J[j + 2] * dx + J[j + 3] * dy);
773
+ };
774
+ for (let k = 0; k < 3; k++) {
775
+ const n = (k + 1) % 3, p = (k + 2) % 3;
776
+ set(F + k, at[2 * v[k]], at[2 * v[k] + 1]);
777
+ toward(S + k, k, sx, sy);
778
+ toward(N + k, k, vx[n], vy[n]);
779
+ toward(P + k, k, vx[p], vy[p]);
780
+ }
781
+ for (let k = 0; k < 3; k++) {
782
+ const a = (k + 1) % 3, b = (k + 2) % 3;
783
+ const ex = vx[b] - vx[a], ey = vy[b] - vy[a];
784
+ const lb = ((sx - vx[a]) * ex + (sy - vy[a]) * ey) / (ex * ex + ey * ey), la = 1 - lb;
785
+ const mid = (c) => la * c(N + a) + lb * c(P + b) + 0.5 * (c(S + a) - la * c(F + a) - lb * c(N + a) + c(S + b) - la * c(P + b) - lb * c(F + b));
786
+ set(M + k, mid(x), mid(y));
787
+ }
788
+ for (let k = 0; k < 3; k++) {
789
+ const e1 = M + (k + 1) % 3, e2 = M + (k + 2) % 3;
790
+ set(I + k, (x(S + k) + x(e1) + x(e2)) / 3, (y(S + k) + y(e1) + y(e2)) / 3);
791
+ }
792
+ set(C, (x(I) + x(I + 1) + x(I + 2)) / 3, (y(I) + y(I + 1) + y(I + 2)) / 3);
793
+ }
794
+ var PIECES = [0, 1, 2].map((k) => {
795
+ const a = (k + 1) % 3, b = (k + 2) % 3;
796
+ return Int32Array.from([F + a, F + b, C, N + a, P + b, S + a, I + a, S + b, I + b, M + k], (o) => 2 * o);
797
+ });
798
+ function evaluate(o, base, w, d = [0, 0, 0]) {
799
+ const k = w[0] <= w[1] && w[0] <= w[2] ? 0 : w[1] <= w[2] ? 1 : 2;
800
+ const a = (k + 1) % 3, b = (k + 2) % 3;
801
+ const u = w[a] - w[k], v = w[b] - w[k], s = 3 * w[k];
802
+ const du = d[a] - d[k], dv = d[b] - d[k], ds = 3 * d[k];
803
+ const c0 = u * u * u + 3 * u * u * du;
804
+ const c1 = v * v * v + 3 * v * v * dv;
805
+ const c2 = s * s * s + 3 * s * s * ds;
806
+ const c3 = 3 * (u * u * v + 2 * u * v * du + u * u * dv);
807
+ const c4 = 3 * (u * v * v + v * v * du + 2 * u * v * dv);
808
+ const c5 = 3 * (u * u * s + 2 * u * s * du + u * u * ds);
809
+ const c6 = 3 * (u * s * s + s * s * du + 2 * u * s * ds);
810
+ const c7 = 3 * (v * v * s + 2 * v * s * dv + v * v * ds);
811
+ const c8 = 3 * (v * s * s + s * s * dv + 2 * v * s * ds);
812
+ const c9 = 6 * (u * v * s + v * s * du + u * s * dv + u * v * ds);
813
+ const q = PIECES[k];
814
+ const sum = (c) => c0 * o[base + q[0] + c] + c1 * o[base + q[1] + c] + c2 * o[base + q[2] + c] + c3 * o[base + q[3] + c] + c4 * o[base + q[4] + c] + c5 * o[base + q[5] + c] + c6 * o[base + q[6] + c] + c7 * o[base + q[7] + c] + c8 * o[base + q[8] + c] + c9 * o[base + q[9] + c];
815
+ return { x: sum(0), y: sum(1) };
816
+ }
817
+ function cloughTocherMap(mesh, frames, at) {
818
+ const V = mesh.vertices, T = mesh.triangles;
819
+ const J = vertexDerivatives(mesh, frames, at);
820
+ const ordinates = new Float64Array(2 * ORDINATES * (T.length / 3));
821
+ const built = new Uint8Array(T.length / 3);
822
+ return (spot) => {
823
+ const t = spot.tri;
824
+ if (!built[t]) {
825
+ buildOrdinates(V, T, at, J, t, ordinates.subarray(2 * ORDINATES * t, 2 * ORDINATES * (t + 1)));
826
+ built[t] = 1;
827
+ }
828
+ const base = 2 * ORDINATES * t;
829
+ const w = [spot.w0, spot.w1, spot.w2];
830
+ if (w[0] >= 0 && w[1] >= 0 && w[2] >= 0) return evaluate(ordinates, base, w);
831
+ const clamped = w.map((v) => Math.max(0, v));
832
+ const sum = clamped[0] + clamped[1] + clamped[2];
833
+ const near = clamped.map((v) => v / sum);
834
+ return evaluate(ordinates, base, near, w.map((v, i) => v - near[i]));
835
+ };
836
+ }
837
+
700
838
  // src/warp/meshMap.ts
701
839
  var EPS = 1e-9;
702
840
  function weights(V, T, t, x, y) {
@@ -766,13 +904,6 @@ function meshLocator(mesh) {
766
904
  return best;
767
905
  };
768
906
  }
769
- function placeSpot(T, at, s) {
770
- const a = T[3 * s.tri], b = T[3 * s.tri + 1], c = T[3 * s.tri + 2];
771
- return {
772
- x: s.w0 * at[2 * a] + s.w1 * at[2 * b] + s.w2 * at[2 * c],
773
- y: s.w0 * at[2 * a + 1] + s.w1 * at[2 * b + 1] + s.w2 * at[2 * c + 1]
774
- };
775
- }
776
907
 
777
908
  // src/warp/refine.ts
778
909
  function orient(V, a, b, c) {
@@ -1112,21 +1243,22 @@ function rigFor(source, pins) {
1112
1243
  if (held?.key === key) return held;
1113
1244
  const mesh = puppetMesh(source, pins.map((p) => p.from));
1114
1245
  const pinned = [...new Set(Array.from(mesh.pinVertex).filter((v) => v >= 0))];
1115
- const rig = { key, mesh, solver: createArapSolver(mesh, pinned), locate: meshLocator(mesh), spots: /* @__PURE__ */ new Map(), remembered: 0 };
1246
+ const rig = { key, mesh, frames: restFrames2(mesh), solver: createArapSolver(mesh, pinned), locate: meshLocator(mesh), spots: /* @__PURE__ */ new Map(), remembered: 0 };
1116
1247
  rigs.set(source, rig);
1117
1248
  return rig;
1118
1249
  }
1119
1250
  function puppetMap(source, pins) {
1120
- if (pins.length === 0) return (p) => ({ x: p.x, y: p.y });
1251
+ if (pins.every((p) => p.to.x === p.from.x && p.to.y === p.from.y)) return (p) => ({ x: p.x, y: p.y });
1121
1252
  const rig = rigFor(source, pins);
1122
1253
  const at = solveRig(rig, pins);
1123
1254
  if (!at) {
1124
1255
  const dx = pins[0].to.x - pins[0].from.x, dy = pins[0].to.y - pins[0].from.y;
1125
1256
  return (p) => ({ x: p.x + dx, y: p.y + dy });
1126
1257
  }
1258
+ const place = cloughTocherMap(rig.mesh, rig.frames, at);
1127
1259
  return (p) => {
1128
1260
  const spot = spotOf(rig, p);
1129
- return spot ? placeSpot(rig.mesh.triangles, at, spot) : { x: p.x, y: p.y };
1261
+ return spot ? place(spot) : { x: p.x, y: p.y };
1130
1262
  };
1131
1263
  }
1132
1264
  function solveRig(rig, pins, opts) {