hyper-scatter 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -0
  3. package/dist-lib/controller/interaction_controller.d.ts +29 -0
  4. package/dist-lib/controller/interaction_controller.d.ts.map +1 -0
  5. package/dist-lib/controller/interaction_controller.js +286 -0
  6. package/dist-lib/controller/interaction_controller.js.map +1 -0
  7. package/dist-lib/core/dataset.d.ts +62 -0
  8. package/dist-lib/core/dataset.d.ts.map +1 -0
  9. package/dist-lib/core/dataset.js +152 -0
  10. package/dist-lib/core/dataset.js.map +1 -0
  11. package/dist-lib/core/lasso_simplify.d.ts +16 -0
  12. package/dist-lib/core/lasso_simplify.d.ts.map +1 -0
  13. package/dist-lib/core/lasso_simplify.js +173 -0
  14. package/dist-lib/core/lasso_simplify.js.map +1 -0
  15. package/dist-lib/core/math/euclidean.d.ts +31 -0
  16. package/dist-lib/core/math/euclidean.d.ts.map +1 -0
  17. package/dist-lib/core/math/euclidean.js +64 -0
  18. package/dist-lib/core/math/euclidean.js.map +1 -0
  19. package/dist-lib/core/math/poincare.d.ts +117 -0
  20. package/dist-lib/core/math/poincare.d.ts.map +1 -0
  21. package/dist-lib/core/math/poincare.js +321 -0
  22. package/dist-lib/core/math/poincare.js.map +1 -0
  23. package/dist-lib/core/rng.d.ts +18 -0
  24. package/dist-lib/core/rng.d.ts.map +1 -0
  25. package/dist-lib/core/rng.js +52 -0
  26. package/dist-lib/core/rng.js.map +1 -0
  27. package/dist-lib/core/selection/point_in_polygon.d.ts +30 -0
  28. package/dist-lib/core/selection/point_in_polygon.d.ts.map +1 -0
  29. package/dist-lib/core/selection/point_in_polygon.js +112 -0
  30. package/dist-lib/core/selection/point_in_polygon.js.map +1 -0
  31. package/dist-lib/core/types.d.ts +185 -0
  32. package/dist-lib/core/types.d.ts.map +1 -0
  33. package/dist-lib/core/types.js +53 -0
  34. package/dist-lib/core/types.js.map +1 -0
  35. package/dist-lib/impl_candidate/spatial_index.d.ts +45 -0
  36. package/dist-lib/impl_candidate/spatial_index.d.ts.map +1 -0
  37. package/dist-lib/impl_candidate/spatial_index.js +186 -0
  38. package/dist-lib/impl_candidate/spatial_index.js.map +1 -0
  39. package/dist-lib/impl_candidate/webgl_candidate.d.ts +283 -0
  40. package/dist-lib/impl_candidate/webgl_candidate.d.ts.map +1 -0
  41. package/dist-lib/impl_candidate/webgl_candidate.js +2276 -0
  42. package/dist-lib/impl_candidate/webgl_candidate.js.map +1 -0
  43. package/dist-lib/index.d.ts +11 -0
  44. package/dist-lib/index.d.ts.map +1 -0
  45. package/dist-lib/index.js +52 -0
  46. package/dist-lib/index.js.map +1 -0
  47. package/package.json +63 -0
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Poincare disk (hyperbolic) geometry utilities.
3
+ *
4
+ * The Poincare disk model represents hyperbolic space inside the unit disk.
5
+ * Points are represented as complex numbers z with |z| < 1.
6
+ *
7
+ * Isometries (distance-preserving transformations) are Mobius transformations
8
+ * of the form: f(z) = (z - a) / (1 - conj(a) * z) where |a| < 1
9
+ *
10
+ * This maps point 'a' to the origin, which is our "camera translation".
11
+ *
12
+ * References:
13
+ * - https://math.libretexts.org/Bookshelves/Geometry/Geometry_with_an_Introduction_to_Cosmic_Topology_(Hitchman)/05:_Hyperbolic_Geometry/5.01:_The_Poincare_Disk_Model
14
+ * - https://geoopt.readthedocs.io/en/latest/extended/stereographic.html
15
+ */
16
+ /**
17
+ * Create a default hyperbolic view state (centered at origin).
18
+ */
19
+ export function createHyperbolicView() {
20
+ return {
21
+ type: 'poincare',
22
+ ax: 0,
23
+ ay: 0,
24
+ displayZoom: 1,
25
+ };
26
+ }
27
+ /**
28
+ * Apply Mobius transformation: T_a(z) = (z - a) / (1 - conj(a) * z)
29
+ * This is the hyperbolic isometry that translates 'a' to the origin.
30
+ *
31
+ * Mathematical derivation:
32
+ * - Numerator: z - a (complex subtraction)
33
+ * - Denominator: 1 - conj(a) * z where conj(a) = ax - i*ay
34
+ */
35
+ export function mobiusTransform(zx, zy, ax, ay) {
36
+ // Numerator: z - a
37
+ const numX = zx - ax;
38
+ const numY = zy - ay;
39
+ // Denominator: 1 - conj(a) * z = 1 - (ax - i*ay)(zx + i*zy)
40
+ // = 1 - (ax*zx + ay*zy + i*(ax*zy - ay*zx))
41
+ const denomX = 1 - (ax * zx + ay * zy);
42
+ const denomY = -(ax * zy - ay * zx);
43
+ // Complex division: num / denom
44
+ const denomNormSq = denomX * denomX + denomY * denomY;
45
+ if (denomNormSq < 1e-12) {
46
+ // Degenerate case, return clamped to boundary
47
+ const norm = Math.sqrt(numX * numX + numY * numY);
48
+ if (norm < 1e-12)
49
+ return { x: 0, y: 0 };
50
+ return { x: (numX / norm) * 0.999, y: (numY / norm) * 0.999 };
51
+ }
52
+ const resultX = (numX * denomX + numY * denomY) / denomNormSq;
53
+ const resultY = (numY * denomX - numX * denomY) / denomNormSq;
54
+ // Clamp to disk (numerical safety)
55
+ const rSq = resultX * resultX + resultY * resultY;
56
+ if (rSq >= 1) {
57
+ const r = Math.sqrt(rSq);
58
+ return { x: (resultX / r) * 0.999, y: (resultY / r) * 0.999 };
59
+ }
60
+ return { x: resultX, y: resultY };
61
+ }
62
+ /**
63
+ * Inverse Mobius transformation.
64
+ * If forward is T_a(z) = (z - a) / (1 - conj(a) * z)
65
+ * Then inverse is T_a^{-1}(w) = (w + a) / (1 + conj(a) * w)
66
+ */
67
+ export function inverseMobiusTransform(wx, wy, ax, ay) {
68
+ // Numerator: w + a
69
+ const numX = wx + ax;
70
+ const numY = wy + ay;
71
+ // Denominator: 1 + conj(a) * w = 1 + (ax - i*ay)(wx + i*wy)
72
+ // = 1 + (ax*wx + ay*wy + i*(ax*wy - ay*wx))
73
+ const denomX = 1 + (ax * wx + ay * wy);
74
+ const denomY = ax * wy - ay * wx;
75
+ // Complex division
76
+ const denomNormSq = denomX * denomX + denomY * denomY;
77
+ if (denomNormSq < 1e-12) {
78
+ const norm = Math.sqrt(numX * numX + numY * numY);
79
+ if (norm < 1e-12)
80
+ return { x: 0, y: 0 };
81
+ return { x: (numX / norm) * 0.999, y: (numY / norm) * 0.999 };
82
+ }
83
+ const resultX = (numX * denomX + numY * denomY) / denomNormSq;
84
+ const resultY = (numY * denomX - numX * denomY) / denomNormSq;
85
+ const rSq = resultX * resultX + resultY * resultY;
86
+ if (rSq >= 1) {
87
+ const r = Math.sqrt(rSq);
88
+ return { x: (resultX / r) * 0.999, y: (resultY / r) * 0.999 };
89
+ }
90
+ return { x: resultX, y: resultY };
91
+ }
92
+ /**
93
+ * Mobius addition (gyroaddition) in the Poincare ball.
94
+ * Formula from geoopt for curvature k = -1:
95
+ *
96
+ * x ⊕ y = ((1 + 2⟨x,y⟩ + ‖y‖²)x + (1 - ‖x‖²)y) / (1 + 2⟨x,y⟩ + ‖x‖²‖y‖²)
97
+ *
98
+ * where ⟨x,y⟩ is the real inner product (dot product).
99
+ */
100
+ export function mobiusAdd(ax, ay, bx, by) {
101
+ const dotAB = ax * bx + ay * by; // ⟨a, b⟩
102
+ const normASq = ax * ax + ay * ay; // ‖a‖²
103
+ const normBSq = bx * bx + by * by; // ‖b‖²
104
+ // Numerator coefficients
105
+ const coeffA = 1 + 2 * dotAB + normBSq;
106
+ const coeffB = 1 - normASq;
107
+ // Denominator
108
+ const denom = 1 + 2 * dotAB + normASq * normBSq;
109
+ if (Math.abs(denom) < 1e-12) {
110
+ return { x: 0, y: 0 };
111
+ }
112
+ const resultX = (coeffA * ax + coeffB * bx) / denom;
113
+ const resultY = (coeffA * ay + coeffB * by) / denom;
114
+ // Clamp to disk
115
+ const rSq = resultX * resultX + resultY * resultY;
116
+ if (rSq >= 1) {
117
+ const r = Math.sqrt(rSq);
118
+ return { x: (resultX / r) * 0.99, y: (resultY / r) * 0.99 };
119
+ }
120
+ return { x: resultX, y: resultY };
121
+ }
122
+ /**
123
+ * Mobius negation: -x in the gyrogroup is just negation.
124
+ */
125
+ export function mobiusNeg(x, y) {
126
+ return { x: -x, y: -y };
127
+ }
128
+ /**
129
+ * Mobius subtraction: x ⊖ y = x ⊕ (-y)
130
+ */
131
+ export function mobiusSub(ax, ay, bx, by) {
132
+ return mobiusAdd(ax, ay, -bx, -by);
133
+ }
134
+ /**
135
+ * Project a Poincare disk point to screen coordinates.
136
+ */
137
+ export function projectPoincare(dataX, dataY, view, width, height) {
138
+ // First apply the Mobius transformation (camera)
139
+ const transformed = mobiusTransform(dataX, dataY, view.ax, view.ay);
140
+ // Then apply display zoom and map to screen
141
+ // The disk has radius 1, we map it to fit in the canvas
142
+ const diskRadius = Math.min(width, height) * 0.45 * view.displayZoom;
143
+ const x = width / 2 + transformed.x * diskRadius;
144
+ const y = height / 2 - transformed.y * diskRadius; // flip Y
145
+ return { x, y };
146
+ }
147
+ /**
148
+ * Unproject screen coordinates to Poincare disk (data space).
149
+ */
150
+ export function unprojectPoincare(screenX, screenY, view, width, height) {
151
+ // Map screen to disk coordinates (after camera)
152
+ const diskRadius = Math.min(width, height) * 0.45 * view.displayZoom;
153
+ const diskX = (screenX - width / 2) / diskRadius;
154
+ const diskY = -(screenY - height / 2) / diskRadius; // flip Y
155
+ // Check if point is outside disk
156
+ const rSq = diskX * diskX + diskY * diskY;
157
+ if (rSq >= 1) {
158
+ // Clamp to disk boundary
159
+ const r = Math.sqrt(rSq);
160
+ const clampedX = (diskX / r) * 0.999;
161
+ const clampedY = (diskY / r) * 0.999;
162
+ return inverseMobiusTransform(clampedX, clampedY, view.ax, view.ay);
163
+ }
164
+ // Apply inverse Mobius to get data coordinates
165
+ return inverseMobiusTransform(diskX, diskY, view.ax, view.ay);
166
+ }
167
+ /**
168
+ * Solve for new camera position a' such that T_{a'}(p) = d2
169
+ *
170
+ * Given: data point p, target display position d2
171
+ * Find: camera a' such that (p - a') / (1 - conj(a') * p) = d2
172
+ *
173
+ * This is solved as a linear system in the real and imaginary parts of a'.
174
+ *
175
+ * The system is:
176
+ * (1 - A) * x - B * y = px - d2x
177
+ * B * x - (1 + A) * y = d2y - py
178
+ *
179
+ * where A = d2x*px - d2y*py, B = d2x*py + d2y*px
180
+ * and the determinant is A² + B² - 1 = |d2|²|p|² - 1
181
+ */
182
+ function solveForCamera(px, py, d2x, d2y) {
183
+ const A = d2x * px - d2y * py;
184
+ const B = d2x * py + d2y * px;
185
+ // Determinant = |d2|² * |p|² - 1
186
+ // For points inside disk, this is always negative
187
+ const det = A * A + B * B - 1;
188
+ if (Math.abs(det) < 1e-10) {
189
+ // Degenerate case: either p or d2 is at origin, or on boundary
190
+ // Fall back to simple approximation
191
+ return { x: -d2x, y: -d2y };
192
+ }
193
+ const rhsX = px - d2x;
194
+ const rhsY = d2y - py;
195
+ // Cramer's rule
196
+ const x = (-(1 + A) * rhsX + B * rhsY) / det;
197
+ const y = ((1 - A) * rhsY - B * rhsX) / det;
198
+ // Clamp to ensure |a'| < 1
199
+ const rSq = x * x + y * y;
200
+ if (rSq >= 1) {
201
+ const r = Math.sqrt(rSq);
202
+ return { x: (x / r) * 0.99, y: (y / r) * 0.99 };
203
+ }
204
+ return { x, y };
205
+ }
206
+ /**
207
+ * Apply pan to hyperbolic view (anchor-invariant).
208
+ *
209
+ * The point under the cursor at drag start should stay under the cursor
210
+ * throughout the drag. This is the correct "natural" drag behavior.
211
+ *
212
+ * Algorithm:
213
+ * 1. Find the data point p under the start screen position
214
+ * 2. Get the target disk position d2 from end screen position
215
+ * 3. Solve for new camera a' such that T_{a'}(p) = d2
216
+ */
217
+ export function panPoincare(view, startScreenX, startScreenY, endScreenX, endScreenY, width, height) {
218
+ const diskRadius = Math.min(width, height) * 0.45 * view.displayZoom;
219
+ // Convert screen positions to disk coordinates (display space, after camera)
220
+ const d1x = (startScreenX - width / 2) / diskRadius;
221
+ const d1y = -(startScreenY - height / 2) / diskRadius;
222
+ const d2x = (endScreenX - width / 2) / diskRadius;
223
+ const d2y = -(endScreenY - height / 2) / diskRadius;
224
+ // Clamp to disk with margin
225
+ const clampToDisk = (x, y, maxR = 0.95) => {
226
+ const rSq = x * x + y * y;
227
+ if (rSq > maxR * maxR) {
228
+ const r = Math.sqrt(rSq);
229
+ return { x: (x / r) * maxR, y: (y / r) * maxR };
230
+ }
231
+ return { x, y };
232
+ };
233
+ const d1 = clampToDisk(d1x, d1y);
234
+ const d2 = clampToDisk(d2x, d2y);
235
+ // Get the data point currently displayed at d1
236
+ // p = T_a^{-1}(d1)
237
+ const p = inverseMobiusTransform(d1.x, d1.y, view.ax, view.ay);
238
+ // Solve for new camera a' such that T_{a'}(p) = d2
239
+ const newA = solveForCamera(p.x, p.y, d2.x, d2.y);
240
+ return {
241
+ ...view,
242
+ ax: newA.x,
243
+ ay: newA.y,
244
+ };
245
+ }
246
+ /**
247
+ * Apply zoom to hyperbolic view (anchor-invariant).
248
+ *
249
+ * Display zoom scales the visual representation while keeping the
250
+ * data point under the cursor stationary.
251
+ */
252
+ export function zoomPoincare(view, anchorScreenX, anchorScreenY, delta, width, height) {
253
+ // Calculate new display zoom
254
+ const zoomFactor = Math.pow(1.1, delta);
255
+ const newDisplayZoom = Math.max(0.5, Math.min(10, view.displayZoom * zoomFactor));
256
+ // Get the data point under the anchor
257
+ const dataPoint = unprojectPoincare(anchorScreenX, anchorScreenY, view, width, height);
258
+ // Calculate where this data point would appear with new zoom (but same camera)
259
+ const diskRadiusNew = Math.min(width, height) * 0.45 * newDisplayZoom;
260
+ // The display position of dataPoint after camera transform
261
+ const transformed = mobiusTransform(dataPoint.x, dataPoint.y, view.ax, view.ay);
262
+ // Screen position with new zoom (if we don't adjust camera)
263
+ const newScreenX = width / 2 + transformed.x * diskRadiusNew;
264
+ const newScreenY = height / 2 - transformed.y * diskRadiusNew;
265
+ // If the point moved significantly, adjust camera to compensate
266
+ const dx = newScreenX - anchorScreenX;
267
+ const dy = newScreenY - anchorScreenY;
268
+ if (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) {
269
+ // Pan to bring the anchor point back under the cursor
270
+ return panPoincare({ ...view, displayZoom: newDisplayZoom }, newScreenX, newScreenY, anchorScreenX, anchorScreenY, width, height);
271
+ }
272
+ return {
273
+ ...view,
274
+ displayZoom: newDisplayZoom,
275
+ };
276
+ }
277
+ /**
278
+ * Hyperbolic distance between two points in the Poincare disk.
279
+ * d(z1, z2) = 2 * arctanh(|z1 - z2| / |1 - conj(z1) * z2|)
280
+ */
281
+ export function hyperbolicDistance(x1, y1, x2, y2) {
282
+ const diffX = x1 - x2;
283
+ const diffY = y1 - y2;
284
+ const diffNorm = Math.sqrt(diffX * diffX + diffY * diffY);
285
+ // 1 - conj(z1) * z2
286
+ const denomX = 1 - (x1 * x2 + y1 * y2);
287
+ const denomY = -(x1 * y2 - y1 * x2);
288
+ const denomNorm = Math.sqrt(denomX * denomX + denomY * denomY);
289
+ if (denomNorm < 1e-12)
290
+ return Infinity;
291
+ // Clamp ratio to avoid atanh(1) = Infinity due to floating-point errors
292
+ const ratio = Math.min(diffNorm / denomNorm, 1 - 1e-10);
293
+ return 2 * Math.atanh(ratio);
294
+ }
295
+ /**
296
+ * Geodesic interpolation between two points.
297
+ * gamma(t) = x ⊕ (t ⊗ ((-x) ⊕ y))
298
+ *
299
+ * For simplicity, we use a linear approximation in disk space
300
+ * which is accurate for small distances.
301
+ */
302
+ export function geodesicInterpolate(x1, y1, x2, y2, t) {
303
+ // Transform so x1 is at origin
304
+ const transformed = mobiusTransform(x2, y2, x1, y1);
305
+ // Scale by t (this is exact for geodesics through origin)
306
+ const scaledNorm = Math.sqrt(transformed.x * transformed.x + transformed.y * transformed.y);
307
+ if (scaledNorm < 1e-12) {
308
+ return { x: x1, y: y1 };
309
+ }
310
+ // Clamp to avoid atanh(1) = Infinity near boundary
311
+ const clampedNorm = Math.min(scaledNorm, 1 - 1e-10);
312
+ // Use arctanh/tanh for proper geodesic scaling
313
+ const targetNorm = Math.tanh(t * Math.atanh(clampedNorm));
314
+ const scaled = {
315
+ x: (transformed.x / scaledNorm) * targetNorm,
316
+ y: (transformed.y / scaledNorm) * targetNorm,
317
+ };
318
+ // Transform back
319
+ return inverseMobiusTransform(scaled.x, scaled.y, x1, y1);
320
+ }
321
+ //# sourceMappingURL=poincare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poincare.js","sourceRoot":"","sources":["../../../src/core/math/poincare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Seeded pseudo-random number generator for deterministic datasets.
3
+ * Uses a simple xoshiro128** algorithm.
4
+ */
5
+ export declare class SeededRNG {
6
+ private state;
7
+ constructor(seed: number);
8
+ /** Returns a float in [0, 1) */
9
+ random(): number;
10
+ /** Returns a float in [min, max) */
11
+ range(min: number, max: number): number;
12
+ /** Returns an integer in [0, max) */
13
+ int(max: number): number;
14
+ /** Returns a normally distributed value (Box-Muller) */
15
+ gaussian(mean?: number, std?: number): number;
16
+ private rotl;
17
+ }
18
+ //# sourceMappingURL=rng.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rng.d.ts","sourceRoot":"","sources":["../../src/core/rng.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAc;gBAEf,IAAI,EAAE,MAAM;IAcxB,gCAAgC;IAChC,MAAM,IAAI,MAAM;IAchB,oCAAoC;IACpC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIvC,qCAAqC;IACrC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIxB,wDAAwD;IACxD,QAAQ,CAAC,IAAI,SAAI,EAAE,GAAG,SAAI,GAAG,MAAM;IAQnC,OAAO,CAAC,IAAI;CAGb"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Seeded pseudo-random number generator for deterministic datasets.
3
+ * Uses a simple xoshiro128** algorithm.
4
+ */
5
+ export class SeededRNG {
6
+ state;
7
+ constructor(seed) {
8
+ // Initialize state from seed using splitmix64
9
+ this.state = new Uint32Array(4);
10
+ let s = seed >>> 0;
11
+ for (let i = 0; i < 4; i++) {
12
+ s = (s + 0x9e3779b9) >>> 0;
13
+ let z = s;
14
+ z = ((z ^ (z >>> 16)) * 0x85ebca6b) >>> 0;
15
+ z = ((z ^ (z >>> 13)) * 0xc2b2ae35) >>> 0;
16
+ z = (z ^ (z >>> 16)) >>> 0;
17
+ this.state[i] = z;
18
+ }
19
+ }
20
+ /** Returns a float in [0, 1) */
21
+ random() {
22
+ const result = this.rotl(this.state[1] * 5, 7) * 9;
23
+ const t = this.state[1] << 9;
24
+ this.state[2] ^= this.state[0];
25
+ this.state[3] ^= this.state[1];
26
+ this.state[1] ^= this.state[2];
27
+ this.state[0] ^= this.state[3];
28
+ this.state[2] ^= t;
29
+ this.state[3] = this.rotl(this.state[3], 11);
30
+ return (result >>> 0) / 0x100000000;
31
+ }
32
+ /** Returns a float in [min, max) */
33
+ range(min, max) {
34
+ return min + this.random() * (max - min);
35
+ }
36
+ /** Returns an integer in [0, max) */
37
+ int(max) {
38
+ return Math.floor(this.random() * max);
39
+ }
40
+ /** Returns a normally distributed value (Box-Muller) */
41
+ gaussian(mean = 0, std = 1) {
42
+ // Clamp u1 away from 0 to avoid log(0) = -Infinity
43
+ const u1 = Math.max(this.random(), 1e-10);
44
+ const u2 = this.random();
45
+ const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
46
+ return mean + z * std;
47
+ }
48
+ rotl(x, k) {
49
+ return ((x << k) | (x >>> (32 - k))) >>> 0;
50
+ }
51
+ }
52
+ //# sourceMappingURL=rng.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rng.js","sourceRoot":"","sources":["../../src/core/rng.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,SAAS;IACZ,KAAK,CAAc;IAE3B,YAAY,IAAY;QACtB,8CAA8C;QAC9C,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;YACV,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YAC1C,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,MAAM;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAE7C,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC;IACtC,CAAC;IAED,oCAAoC;IACpC,KAAK,CAAC,GAAW,EAAE,GAAW;QAC5B,OAAO,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,qCAAqC;IACrC,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,wDAAwD;IACxD,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC;QACxB,mDAAmD;QACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACpE,OAAO,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC;IACxB,CAAC;IAEO,IAAI,CAAC,CAAS,EAAE,CAAS;QAC/B,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;CACF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Point-in-polygon test using ray casting algorithm.
3
+ * This is the naive, accurate implementation for reference.
4
+ */
5
+ import type { Bounds2D } from '../types.js';
6
+ /**
7
+ * Test if a point is inside a polygon using ray casting.
8
+ * Polygon is given as interleaved x,y coordinates.
9
+ *
10
+ * Polygon semantics:
11
+ * - The polygon is implicitly CLOSED (edge from last vertex to first).
12
+ * - Vertex order may be CW or CCW (even-odd rule; winding does not matter).
13
+ * - Boundary rule: points exactly on an edge are considered INSIDE (within tolerance).
14
+ * - Ray crossing uses a half-open y-interval ((yi > py) !== (yj > py)) to avoid double counts.
15
+ *
16
+ * Boundary rule: points exactly on the edge are considered INSIDE.
17
+ */
18
+ export declare function pointInPolygon(px: number, py: number, polygon: Float32Array): boolean;
19
+ /**
20
+ * Compute an axis-aligned bounding box (AABB) for an interleaved polygon.
21
+ *
22
+ * Returns a finite bounds object. For empty input, returns all zeros.
23
+ */
24
+ export declare function boundsOfPolygon(polygon: Float32Array): Bounds2D;
25
+ /**
26
+ * Brute-force lasso selection: test all points against polygon.
27
+ * Returns indices of points inside the polygon.
28
+ */
29
+ export declare function lassoSelectBruteForce(positions: Float32Array, polygon: Float32Array): Set<number>;
30
+ //# sourceMappingURL=point_in_polygon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point_in_polygon.d.ts","sourceRoot":"","sources":["../../../src/core/selection/point_in_polygon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,YAAY,GACpB,OAAO,CA2BT;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ,CAoB/D;AA4CD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,YAAY,GACpB,GAAG,CAAC,MAAM,CAAC,CAab"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Point-in-polygon test using ray casting algorithm.
3
+ * This is the naive, accurate implementation for reference.
4
+ */
5
+ /**
6
+ * Test if a point is inside a polygon using ray casting.
7
+ * Polygon is given as interleaved x,y coordinates.
8
+ *
9
+ * Polygon semantics:
10
+ * - The polygon is implicitly CLOSED (edge from last vertex to first).
11
+ * - Vertex order may be CW or CCW (even-odd rule; winding does not matter).
12
+ * - Boundary rule: points exactly on an edge are considered INSIDE (within tolerance).
13
+ * - Ray crossing uses a half-open y-interval ((yi > py) !== (yj > py)) to avoid double counts.
14
+ *
15
+ * Boundary rule: points exactly on the edge are considered INSIDE.
16
+ */
17
+ export function pointInPolygon(px, py, polygon) {
18
+ const n = polygon.length / 2;
19
+ if (n < 3)
20
+ return false;
21
+ let inside = false;
22
+ for (let i = 0, j = n - 1; i < n; j = i++) {
23
+ const xi = polygon[i * 2];
24
+ const yi = polygon[i * 2 + 1];
25
+ const xj = polygon[j * 2];
26
+ const yj = polygon[j * 2 + 1];
27
+ // Check if point is on edge (within tolerance)
28
+ if (isPointOnSegment(px, py, xi, yi, xj, yj, 1e-9)) {
29
+ return true; // Boundary counts as inside
30
+ }
31
+ // Ray casting
32
+ if ((yi > py) !== (yj > py)) {
33
+ const xIntersect = ((xj - xi) * (py - yi)) / (yj - yi) + xi;
34
+ if (px < xIntersect) {
35
+ inside = !inside;
36
+ }
37
+ }
38
+ }
39
+ return inside;
40
+ }
41
+ /**
42
+ * Compute an axis-aligned bounding box (AABB) for an interleaved polygon.
43
+ *
44
+ * Returns a finite bounds object. For empty input, returns all zeros.
45
+ */
46
+ export function boundsOfPolygon(polygon) {
47
+ let xMin = Infinity;
48
+ let yMin = Infinity;
49
+ let xMax = -Infinity;
50
+ let yMax = -Infinity;
51
+ for (let i = 0; i < polygon.length; i += 2) {
52
+ const x = polygon[i];
53
+ const y = polygon[i + 1];
54
+ if (x < xMin)
55
+ xMin = x;
56
+ if (x > xMax)
57
+ xMax = x;
58
+ if (y < yMin)
59
+ yMin = y;
60
+ if (y > yMax)
61
+ yMax = y;
62
+ }
63
+ if (!Number.isFinite(xMin) || !Number.isFinite(yMin) || !Number.isFinite(xMax) || !Number.isFinite(yMax)) {
64
+ return { xMin: 0, yMin: 0, xMax: 0, yMax: 0 };
65
+ }
66
+ return { xMin, yMin, xMax, yMax };
67
+ }
68
+ /**
69
+ * Check if a point lies on a line segment (within tolerance).
70
+ */
71
+ function isPointOnSegment(px, py, x1, y1, x2, y2, tolerance) {
72
+ // Check if point is within bounding box
73
+ const minX = Math.min(x1, x2) - tolerance;
74
+ const maxX = Math.max(x1, x2) + tolerance;
75
+ const minY = Math.min(y1, y2) - tolerance;
76
+ const maxY = Math.max(y1, y2) + tolerance;
77
+ if (px < minX || px > maxX || py < minY || py > maxY) {
78
+ return false;
79
+ }
80
+ // Calculate distance from point to line
81
+ const dx = x2 - x1;
82
+ const dy = y2 - y1;
83
+ const lengthSq = dx * dx + dy * dy;
84
+ if (lengthSq < tolerance * tolerance) {
85
+ // Degenerate segment (point)
86
+ const dist = Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1));
87
+ return dist <= tolerance;
88
+ }
89
+ // Project point onto line
90
+ const t = Math.max(0, Math.min(1, ((px - x1) * dx + (py - y1) * dy) / lengthSq));
91
+ const projX = x1 + t * dx;
92
+ const projY = y1 + t * dy;
93
+ const dist = Math.sqrt((px - projX) * (px - projX) + (py - projY) * (py - projY));
94
+ return dist <= tolerance;
95
+ }
96
+ /**
97
+ * Brute-force lasso selection: test all points against polygon.
98
+ * Returns indices of points inside the polygon.
99
+ */
100
+ export function lassoSelectBruteForce(positions, polygon) {
101
+ const result = new Set();
102
+ const n = positions.length / 2;
103
+ for (let i = 0; i < n; i++) {
104
+ const x = positions[i * 2];
105
+ const y = positions[i * 2 + 1];
106
+ if (pointInPolygon(x, y, polygon)) {
107
+ result.add(i);
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ //# sourceMappingURL=point_in_polygon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point_in_polygon.js","sourceRoot":"","sources":["../../../src/core/selection/point_in_polygon.ts"],"names":[],"mappings":"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"}