chore(workspace): add gitea repository url to all packages
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 3m48s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 3m48s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 4s
This commit is contained in:
98
components/home/hero-webgl/math.ts
Normal file
98
components/home/hero-webgl/math.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
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<typeof createNoise2D>, 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;
|
||||
}
|
||||
Reference in New Issue
Block a user