/ concept-collection / qhull-wasm-demo
Sign in
concept-collection / qhull-wasm-demo
qhull-wasm-demo / src / points.ts
70 lines · 2.2 KBBlameHistoryRaw
1// Point-set generators used by the demos and benchmarks.
3/** Deterministic PRNG so demos are reproducible across reloads. */
4export function mulberry32(seed: number): () => number {
5 let a = seed >>> 0
6 return () => {
7 a |= 0
8 a = (a + 0x6d2b79f5) | 0
9 let t = Math.imul(a ^ (a >>> 15), 1 | a)
10 t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
11 return ((t ^ (t >>> 14)) >>> 0) / 4294967296
12 }
15export type Dist2D = 'uniform' | 'disk' | 'gaussian' | 'grid'
16export type Dist3D = 'uniform' | 'sphere' | 'gaussian'
18/** N 2D points in roughly the unit square, by distribution. */
19export function points2D(n: number, dist: Dist2D, seed = 1): number[][] {
20 const r = mulberry32(seed)
21 const pts: number[][] = []
22 if (dist === 'grid') {
23 const side = Math.ceil(Math.sqrt(n))
24 for (let i = 0; i < n; i++) {
25 const gx = (i % side) / (side - 1 || 1)
26 const gy = Math.floor(i / side) / (side - 1 || 1)
27 const j = 0.15 / side
28 pts.push([gx + (r() - 0.5) * j, gy + (r() - 0.5) * j])
29 }
30 return pts
31 }
32 for (let i = 0; i < n; i++) {
33 if (dist === 'uniform') {
34 pts.push([r(), r()])
35 } else if (dist === 'disk') {
36 const a = r() * 2 * Math.PI
37 const rad = Math.sqrt(r()) * 0.5
38 pts.push([0.5 + rad * Math.cos(a), 0.5 + rad * Math.sin(a)])
39 } else {
40 pts.push([0.5 + gaussian(r) * 0.15, 0.5 + gaussian(r) * 0.15])
41 }
42 }
43 return pts
46/** N 3D points, by distribution. */
47export function points3D(n: number, dist: Dist3D, seed = 1): number[][] {
48 const r = mulberry32(seed)
49 const pts: number[][] = []
50 for (let i = 0; i < n; i++) {
51 if (dist === 'uniform') {
52 pts.push([r() - 0.5, r() - 0.5, r() - 0.5])
53 } else if (dist === 'sphere') {
54 // uniform on the unit sphere surface
55 const u = r() * 2 - 1
56 const phi = r() * 2 * Math.PI
57 const s = Math.sqrt(1 - u * u)
58 pts.push([s * Math.cos(phi) * 0.5, s * Math.sin(phi) * 0.5, u * 0.5])
59 } else {
60 pts.push([gaussian(r) * 0.2, gaussian(r) * 0.2, gaussian(r) * 0.2])
61 }
62 }
63 return pts
66function gaussian(r: () => number): number {
67 // Box-Muller
68 const u = Math.max(r(), 1e-12)
69 return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * r())
moveopenescclose