import { createNoise2D } from 'simplex-noise'; // Seeded random number generator export function LCG(seed: number) { return function () { seed = Math.imul(48271, seed) | 0 % 2147483647; return (seed & 2147483647) / 2147483648; }; } export type Vec2 = [number, number]; export type Vec3 = [number, number, number]; export function distance2D(a: Vec2, b: Vec2) { const dx = a[0] - b[0]; const dy = a[1] - b[1]; return Math.sqrt(dx * dx + dy * dy); } export function distance3D(a: Vec3, b: Vec3) { const dx = a[0] - b[0]; const dy = a[1] - b[1]; const dz = a[2] - b[2]; return Math.sqrt(dx * dx + dy * dy + dz * dz); } // Generate points for a hanging cable between two points (catenary/sag) export function generateCatenaryCurve( p1: Vec3, p2: Vec3, sag: number, segments: number = 10 ): Vec3[] { const points: Vec3[] = []; for (let i = 0; i <= segments; i++) { const t = i / segments; const x = p1[0] + (p2[0] - p1[0]) * t; const z = p1[2] + (p2[2] - p1[2]) * t; // Linear interpolation of height const baseHeight = p1[1] + (p2[1] - p1[1]) * t; // Add parabolic sag // t ranges from 0 to 1. Parabola that is 0 at ends and 1 in middle is 4 * t * (1 - t) const sagOffset = 4 * t * (1 - t) * sag; const y = baseHeight - sagOffset; points.push([x, y, z]); } return points; } // Simple terrain height function combining multiple frequencies export function getTerrainHeight(noise2D: ReturnType, x: number, z: number): number { // We want a gigantic, hilly planet. We'll use low frequency noise. const n1 = noise2D(x * 0.002, z * 0.002) * 40; // Main hills const n2 = noise2D(x * 0.01, z * 0.01) * 10; // Smaller details return n1 + n2; } // Helper: Place points within a radius using rejection sampling to avoid overlap export function generateClusteredPoints( rng: () => number, center: Vec2, count: number, radius: number, minDist: number ): Vec2[] { const points: Vec2[] = []; let attempts = 0; const maxAttempts = count * 50; while (points.length < count && attempts < maxAttempts) { attempts++; const angle = rng() * Math.PI * 2; // Square root for uniform distribution in a circle const r = Math.sqrt(rng()) * radius; const p: Vec2 = [ center[0] + Math.cos(angle) * r, center[1] + Math.sin(angle) * r ]; let valid = true; for (const other of points) { if (distance2D(p, other) < minDist) { valid = false; break; } } if (valid) { points.push(p); } } return points; }