1#[derive(Debug, Clone)]
7pub struct SurfaceParametric {
8 pub control_net: Vec<Vec<[f64; 3]>>,
10}
11impl SurfaceParametric {
12 pub fn new(control_net: Vec<Vec<[f64; 3]>>) -> Self {
14 Self { control_net }
15 }
16 pub fn tensor_bezier(&self, u: f64, v: f64) -> [f64; 3] {
18 let rows = self.control_net.len();
19 if rows == 0 {
20 return [0.0, 0.0, 0.0];
21 }
22 let row_pts: Vec<[f64; 3]> = self
23 .control_net
24 .iter()
25 .map(|row| {
26 let curve = CurveParametric::new(row.clone());
27 curve.bezier_de_casteljau(u)
28 })
29 .collect();
30 let col_curve = CurveParametric::new(row_pts);
31 col_curve.bezier_de_casteljau(v)
32 }
33 pub fn coons_patch(&self, u: f64, v: f64) -> [f64; 3] {
37 if self.control_net.len() < 2 || self.control_net[0].len() < 2 {
38 return [0.0, 0.0, 0.0];
39 }
40 let p00 = self.control_net[0][0];
41 let p01 = self.control_net[0][1];
42 let p10 = self.control_net[1][0];
43 let p11 = self.control_net[1][1];
44 let w00 = (1.0 - u) * (1.0 - v);
45 let w01 = (1.0 - u) * v;
46 let w10 = u * (1.0 - v);
47 let w11 = u * v;
48 [
49 w00 * p00[0] + w01 * p01[0] + w10 * p10[0] + w11 * p11[0],
50 w00 * p00[1] + w01 * p01[1] + w10 * p10[1] + w11 * p11[1],
51 w00 * p00[2] + w01 * p01[2] + w10 * p10[2] + w11 * p11[2],
52 ]
53 }
54 pub fn normal(&self, u: f64, v: f64) -> [f64; 3] {
56 let eps = 1e-4;
57 let pu = self.tensor_bezier((u + eps).min(1.0), v);
58 let pu_neg = self.tensor_bezier((u - eps).max(0.0), v);
59 let pv = self.tensor_bezier(u, (v + eps).min(1.0));
60 let pv_neg = self.tensor_bezier(u, (v - eps).max(0.0));
61 let du = [
62 (pu[0] - pu_neg[0]) / (2.0 * eps),
63 (pu[1] - pu_neg[1]) / (2.0 * eps),
64 (pu[2] - pu_neg[2]) / (2.0 * eps),
65 ];
66 let dv = [
67 (pv[0] - pv_neg[0]) / (2.0 * eps),
68 (pv[1] - pv_neg[1]) / (2.0 * eps),
69 (pv[2] - pv_neg[2]) / (2.0 * eps),
70 ];
71 let n = [
72 du[1] * dv[2] - du[2] * dv[1],
73 du[2] * dv[0] - du[0] * dv[2],
74 du[0] * dv[1] - du[1] * dv[0],
75 ];
76 let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
77 if len < 1e-12 {
78 [0.0, 0.0, 1.0]
79 } else {
80 [n[0] / len, n[1] / len, n[2] / len]
81 }
82 }
83 pub fn sample(&self, nu: usize, nv: usize) -> Vec<Vec<[f64; 3]>> {
85 (0..nu)
86 .map(|i| {
87 let u = i as f64 / (nu - 1).max(1) as f64;
88 (0..nv)
89 .map(|j| {
90 let v = j as f64 / (nv - 1).max(1) as f64;
91 self.tensor_bezier(u, v)
92 })
93 .collect()
94 })
95 .collect()
96 }
97}
98#[derive(Debug, Clone, Copy)]
100pub struct TurtleState {
101 pub x: f64,
103 pub y: f64,
105 pub angle: f64,
107}
108impl TurtleState {
109 pub fn new() -> Self {
111 Self {
112 x: 0.0,
113 y: 0.0,
114 angle: 0.0,
115 }
116 }
117}
118#[derive(Debug, Clone)]
120pub struct PerlinNoise2d {
121 pub(super) perm: Vec<u8>,
123}
124impl PerlinNoise2d {
125 pub fn new(seed: u64) -> Self {
127 let mut perm = (0u8..=255).collect::<Vec<_>>();
128 let mut s = seed;
129 for i in (1..256).rev() {
130 s = s
131 .wrapping_mul(6_364_136_223_846_793_005)
132 .wrapping_add(1_442_695_040_888_963_407);
133 let j = (s >> 33) as usize % (i + 1);
134 perm.swap(i, j);
135 }
136 let mut full = perm.clone();
137 full.extend_from_slice(&perm);
138 Self { perm: full }
139 }
140 fn fade(t: f64) -> f64 {
141 t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
142 }
143 fn lerp(a: f64, b: f64, t: f64) -> f64 {
144 a + t * (b - a)
145 }
146 fn grad2(hash: u8, x: f64, y: f64) -> f64 {
147 match hash & 3 {
148 0 => x + y,
149 1 => -x + y,
150 2 => x - y,
151 _ => -x - y,
152 }
153 }
154 pub fn noise(&self, x: f64, y: f64) -> f64 {
156 let xi = x.floor() as i32;
157 let yi = y.floor() as i32;
158 let xf = x - xi as f64;
159 let yf = y - yi as f64;
160 let u = Self::fade(xf);
161 let v = Self::fade(yf);
162 let aa = self.perm[(self.perm[(xi & 255) as usize] as i32 + (yi & 255)) as usize & 255];
163 let ab =
164 self.perm[(self.perm[(xi & 255) as usize] as i32 + ((yi + 1) & 255)) as usize & 255];
165 let ba =
166 self.perm[(self.perm[((xi + 1) & 255) as usize] as i32 + (yi & 255)) as usize & 255];
167 let bb = self.perm
168 [(self.perm[((xi + 1) & 255) as usize] as i32 + ((yi + 1) & 255)) as usize & 255];
169 let x1 = Self::lerp(Self::grad2(aa, xf, yf), Self::grad2(ba, xf - 1.0, yf), u);
170 let x2 = Self::lerp(
171 Self::grad2(ab, xf, yf - 1.0),
172 Self::grad2(bb, xf - 1.0, yf - 1.0),
173 u,
174 );
175 Self::lerp(x1, x2, v)
176 }
177 pub fn fbm(&self, x: f64, y: f64, octaves: u32, lacunarity: f64, gain: f64) -> f64 {
181 let mut value = 0.0;
182 let mut amplitude = 1.0;
183 let mut frequency = 1.0;
184 let mut max_val = 0.0;
185 for _ in 0..octaves {
186 value += amplitude * self.noise(x * frequency, y * frequency);
187 max_val += amplitude;
188 amplitude *= gain;
189 frequency *= lacunarity;
190 }
191 if max_val > 0.0 { value / max_val } else { 0.0 }
192 }
193 pub fn turbulence(&self, x: f64, y: f64, octaves: u32, lacunarity: f64, gain: f64) -> f64 {
195 let mut value = 0.0;
196 let mut amplitude = 1.0;
197 let mut frequency = 1.0;
198 for _ in 0..octaves {
199 value += amplitude * self.noise(x * frequency, y * frequency).abs();
200 amplitude *= gain;
201 frequency *= lacunarity;
202 }
203 value
204 }
205}
206#[derive(Debug, Clone)]
208pub struct WorleyNoise {
209 pub(super) points: Vec<[f64; 2]>,
211}
212impl WorleyNoise {
213 pub fn new(num_points: usize, seed: u64) -> Self {
215 let mut s = seed;
216 let mut points = Vec::with_capacity(num_points);
217 for _ in 0..num_points {
218 s = s
219 .wrapping_mul(6_364_136_223_846_793_005)
220 .wrapping_add(1_442_695_040_888_963_407);
221 let x = (s >> 11) as f64 / (1u64 << 53) as f64;
222 s = s
223 .wrapping_mul(6_364_136_223_846_793_005)
224 .wrapping_add(1_442_695_040_888_963_407);
225 let y = (s >> 11) as f64 / (1u64 << 53) as f64;
226 points.push([x, y]);
227 }
228 Self { points }
229 }
230 pub fn f1(&self, x: f64, y: f64) -> f64 {
232 self.points
233 .iter()
234 .map(|&[px, py]| {
235 let dx = x - px;
236 let dy = y - py;
237 (dx * dx + dy * dy).sqrt()
238 })
239 .fold(f64::MAX, f64::min)
240 }
241 pub fn f2_minus_f1(&self, x: f64, y: f64) -> f64 {
243 let mut d1 = f64::MAX;
244 let mut d2 = f64::MAX;
245 for &[px, py] in &self.points {
246 let d = ((x - px).powi(2) + (y - py).powi(2)).sqrt();
247 if d < d1 {
248 d2 = d1;
249 d1 = d;
250 } else if d < d2 {
251 d2 = d;
252 }
253 }
254 d2 - d1
255 }
256}
257#[derive(Debug, Clone)]
259pub struct LSystem {
260 pub axiom: String,
262 pub rules: Vec<LSystemRule>,
264 pub angle_increment: f64,
266 pub step_size: f64,
268}
269impl LSystem {
270 pub fn new(
272 axiom: &str,
273 rules: Vec<LSystemRule>,
274 angle_increment_deg: f64,
275 step_size: f64,
276 ) -> Self {
277 Self {
278 axiom: axiom.to_string(),
279 rules,
280 angle_increment: angle_increment_deg.to_radians(),
281 step_size,
282 }
283 }
284 pub fn evolve(&self, generations: u32) -> LSystemState {
286 let mut current = self.axiom.clone();
287 for _ in 0..generations {
288 let mut next = String::new();
289 for ch in current.chars() {
290 if let Some(rule) = self.rules.iter().find(|r| r.predecessor == ch) {
291 next.push_str(&rule.successor);
292 } else {
293 next.push(ch);
294 }
295 }
296 current = next;
297 }
298 LSystemState {
299 string: current,
300 generation: generations,
301 }
302 }
303 pub fn interpret(&self, state: &LSystemState) -> Vec<([f64; 2], [f64; 2])> {
309 let mut segments = Vec::new();
310 let mut turtle = TurtleState::new();
311 let mut stack: Vec<TurtleState> = Vec::new();
312 for ch in state.string.chars() {
313 match ch {
314 'F' | 'G' => {
315 let nx = turtle.x + self.step_size * turtle.angle.cos();
316 let ny = turtle.y + self.step_size * turtle.angle.sin();
317 segments.push(([turtle.x, turtle.y], [nx, ny]));
318 turtle.x = nx;
319 turtle.y = ny;
320 }
321 'f' => {
322 turtle.x += self.step_size * turtle.angle.cos();
323 turtle.y += self.step_size * turtle.angle.sin();
324 }
325 '+' => turtle.angle += self.angle_increment,
326 '-' => turtle.angle -= self.angle_increment,
327 '[' => stack.push(turtle),
328 ']' => {
329 if let Some(s) = stack.pop() {
330 turtle = s;
331 }
332 }
333 _ => {}
334 }
335 }
336 segments
337 }
338 pub fn koch_curve() -> Self {
340 Self::new(
341 "F--F--F",
342 vec![LSystemRule::new('F', "F+F--F+F")],
343 60.0,
344 1.0,
345 )
346 }
347 pub fn sierpinski() -> Self {
349 Self::new(
350 "F-G-G",
351 vec![
352 LSystemRule::new('F', "F-G+F+G-F"),
353 LSystemRule::new('G', "GG"),
354 ],
355 120.0,
356 1.0,
357 )
358 }
359 pub fn dragon_curve() -> Self {
361 Self::new(
362 "FX",
363 vec![
364 LSystemRule::new('X', "X+YF+"),
365 LSystemRule::new('Y', "-FX-Y"),
366 ],
367 90.0,
368 1.0,
369 )
370 }
371 pub fn plant_branching() -> Self {
373 Self::new(
374 "X",
375 vec![
376 LSystemRule::new('X', "F+[[X]-X]-F[-FX]+X"),
377 LSystemRule::new('F', "FF"),
378 ],
379 25.0,
380 1.0,
381 )
382 }
383}
384#[derive(Debug, Clone, Copy)]
386pub struct IfsTransform {
387 pub a: f64,
389 pub b: f64,
391 pub c: f64,
393 pub d: f64,
395 pub e: f64,
397 pub f: f64,
399 pub prob: f64,
401}
402impl IfsTransform {
403 pub fn new(a: f64, b: f64, c: f64, d: f64, e: f64, f_val: f64, prob: f64) -> Self {
405 Self {
406 a,
407 b,
408 c,
409 d,
410 e,
411 f: f_val,
412 prob,
413 }
414 }
415 fn apply(&self, x: f64, y: f64) -> (f64, f64) {
416 (
417 self.a * x + self.b * y + self.e,
418 self.c * x + self.d * y + self.f,
419 )
420 }
421}
422#[derive(Debug, Clone)]
427pub struct ReactionDiffusion {
428 pub width: usize,
430 pub height: usize,
432 pub u: Vec<f64>,
434 pub v: Vec<f64>,
436 pub d_u: f64,
438 pub d_v: f64,
440 pub feed: f64,
442 pub kill: f64,
444}
445impl ReactionDiffusion {
446 pub fn new(width: usize, height: usize, d_u: f64, d_v: f64, feed: f64, kill: f64) -> Self {
455 let size = width * height;
456 let u = vec![1.0; size];
457 let v = vec![0.0; size];
458 Self {
459 width,
460 height,
461 u,
462 v,
463 d_u,
464 d_v,
465 feed,
466 kill,
467 }
468 }
469 pub fn seed_center(&mut self) {
471 let cx = self.width / 2;
472 let cy = self.height / 2;
473 let r = 5;
474 for y in cy.saturating_sub(r)..=(cy + r).min(self.height - 1) {
475 for x in cx.saturating_sub(r)..=(cx + r).min(self.width - 1) {
476 let idx = y * self.width + x;
477 self.u[idx] = 0.5;
478 self.v[idx] = 0.25;
479 }
480 }
481 }
482 fn idx(&self, x: usize, y: usize) -> usize {
483 y * self.width + x
484 }
485 fn laplacian_u(&self, x: usize, y: usize) -> f64 {
486 let i = self.idx(x, y);
487 let left = if x > 0 {
488 self.u[self.idx(x - 1, y)]
489 } else {
490 self.u[self.idx(self.width - 1, y)]
491 };
492 let right = if x + 1 < self.width {
493 self.u[self.idx(x + 1, y)]
494 } else {
495 self.u[self.idx(0, y)]
496 };
497 let up = if y > 0 {
498 self.u[self.idx(x, y - 1)]
499 } else {
500 self.u[self.idx(x, self.height - 1)]
501 };
502 let down = if y + 1 < self.height {
503 self.u[self.idx(x, y + 1)]
504 } else {
505 self.u[self.idx(x, 0)]
506 };
507 left + right + up + down - 4.0 * self.u[i]
508 }
509 fn laplacian_v(&self, x: usize, y: usize) -> f64 {
510 let i = self.idx(x, y);
511 let left = if x > 0 {
512 self.v[self.idx(x - 1, y)]
513 } else {
514 self.v[self.idx(self.width - 1, y)]
515 };
516 let right = if x + 1 < self.width {
517 self.v[self.idx(x + 1, y)]
518 } else {
519 self.v[self.idx(0, y)]
520 };
521 let up = if y > 0 {
522 self.v[self.idx(x, y - 1)]
523 } else {
524 self.v[self.idx(x, self.height - 1)]
525 };
526 let down = if y + 1 < self.height {
527 self.v[self.idx(x, y + 1)]
528 } else {
529 self.v[self.idx(x, 0)]
530 };
531 left + right + up + down - 4.0 * self.v[i]
532 }
533 pub fn step(&mut self, steps: u32, dt: f64) {
535 for _ in 0..steps {
536 let mut du = vec![0.0f64; self.width * self.height];
537 let mut dv = vec![0.0f64; self.width * self.height];
538 for y in 0..self.height {
539 for x in 0..self.width {
540 let i = self.idx(x, y);
541 let u = self.u[i];
542 let v = self.v[i];
543 let uvv = u * v * v;
544 du[i] = self.d_u * self.laplacian_u(x, y) - uvv + self.feed * (1.0 - u);
545 dv[i] = self.d_v * self.laplacian_v(x, y) + uvv - (self.feed + self.kill) * v;
546 }
547 }
548 for i in 0..self.u.len() {
549 self.u[i] = (self.u[i] + dt * du[i]).clamp(0.0, 1.0);
550 self.v[i] = (self.v[i] + dt * dv[i]).clamp(0.0, 1.0);
551 }
552 }
553 }
554}
555#[derive(Debug, Clone)]
557pub struct IteratedFunctionSystem {
558 pub transforms: Vec<IfsTransform>,
560}
561impl IteratedFunctionSystem {
562 pub fn new(transforms: Vec<IfsTransform>) -> Self {
564 Self { transforms }
565 }
566 pub fn barnsley_fern() -> Self {
568 Self::new(vec![
569 IfsTransform::new(0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.01),
570 IfsTransform::new(0.85, 0.04, -0.04, 0.85, 0.0, 1.6, 0.85),
571 IfsTransform::new(0.2, -0.26, 0.23, 0.22, 0.0, 1.6, 0.07),
572 IfsTransform::new(-0.15, 0.28, 0.26, 0.24, 0.0, 0.44, 0.07),
573 ])
574 }
575 pub fn generate(&self, n: usize, seed: u64) -> Vec<[f64; 2]> {
577 if self.transforms.is_empty() {
578 return Vec::new();
579 }
580 let total: f64 = self.transforms.iter().map(|t| t.prob).sum();
581 let mut cum = Vec::with_capacity(self.transforms.len());
582 let mut acc = 0.0;
583 for t in &self.transforms {
584 acc += t.prob / total;
585 cum.push(acc);
586 }
587 let mut x = 0.0f64;
588 let mut y = 0.0f64;
589 let mut s = seed;
590 for _ in 0..20 {
591 s = s
592 .wrapping_mul(6_364_136_223_846_793_005)
593 .wrapping_add(1_442_695_040_888_963_407);
594 let r = (s >> 11) as f64 / (1u64 << 53) as f64;
595 let idx = cum
596 .iter()
597 .position(|&c| r <= c)
598 .unwrap_or(self.transforms.len() - 1);
599 let (nx, ny) = self.transforms[idx].apply(x, y);
600 x = nx;
601 y = ny;
602 }
603 let mut points = Vec::with_capacity(n);
604 for _ in 0..n {
605 s = s
606 .wrapping_mul(6_364_136_223_846_793_005)
607 .wrapping_add(1_442_695_040_888_963_407);
608 let r = (s >> 11) as f64 / (1u64 << 53) as f64;
609 let idx = cum
610 .iter()
611 .position(|&c| r <= c)
612 .unwrap_or(self.transforms.len() - 1);
613 let (nx, ny) = self.transforms[idx].apply(x, y);
614 x = nx;
615 y = ny;
616 points.push([x, y]);
617 }
618 points
619 }
620}
621#[derive(Debug, Clone)]
623pub struct NoiseGeometry;
624impl NoiseGeometry {
625 pub fn perlin2d(seed: u64) -> PerlinNoise2d {
627 PerlinNoise2d::new(seed)
628 }
629 pub fn perlin3d(seed: u64) -> PerlinNoise3d {
631 PerlinNoise3d::new(seed)
632 }
633 pub fn worley(num_points: usize, seed: u64) -> WorleyNoise {
635 WorleyNoise::new(num_points, seed)
636 }
637 pub fn heightmap_fbm(
641 width: usize,
642 height: usize,
643 scale: f64,
644 octaves: u32,
645 seed: u64,
646 ) -> Vec<Vec<f64>> {
647 let noise = PerlinNoise2d::new(seed);
648 (0..height)
649 .map(|row| {
650 (0..width)
651 .map(|col| {
652 let x = col as f64 / width as f64 * scale;
653 let y = row as f64 / height as f64 * scale;
654 noise.fbm(x, y, octaves, 2.0, 0.5)
655 })
656 .collect()
657 })
658 .collect()
659 }
660}
661#[derive(Debug, Clone)]
663pub struct LSystemState {
664 pub string: String,
666 pub generation: u32,
668}
669#[derive(Debug, Clone)]
671pub struct SpaceColonization {
672 pub attractors: Vec<[f64; 3]>,
674 pub nodes: Vec<ColonizationNode>,
676 pub segment_length: f64,
678 pub influence_radius: f64,
680 pub kill_radius: f64,
682}
683impl SpaceColonization {
684 pub fn new(
686 attractors: Vec<[f64; 3]>,
687 root: [f64; 3],
688 segment_length: f64,
689 influence_radius: f64,
690 kill_radius: f64,
691 ) -> Self {
692 let root_node = ColonizationNode {
693 position: root,
694 parent: None,
695 direction: [0.0, 1.0, 0.0],
696 num_attractors: 0,
697 };
698 Self {
699 attractors,
700 nodes: vec![root_node],
701 segment_length,
702 influence_radius,
703 kill_radius,
704 }
705 }
706 fn dist3(a: &[f64; 3], b: &[f64; 3]) -> f64 {
707 let dx = a[0] - b[0];
708 let dy = a[1] - b[1];
709 let dz = a[2] - b[2];
710 (dx * dx + dy * dy + dz * dz).sqrt()
711 }
712 fn normalize3(v: [f64; 3]) -> [f64; 3] {
713 let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
714 if len < 1e-12 {
715 [0.0, 1.0, 0.0]
716 } else {
717 [v[0] / len, v[1] / len, v[2] / len]
718 }
719 }
720 pub fn grow(&mut self) -> usize {
724 if self.attractors.is_empty() {
725 return 0;
726 }
727 let n = self.nodes.len();
728 let mut directions: Vec<[f64; 3]> = vec![[0.0, 0.0, 0.0]; n];
729 let mut influenced: Vec<bool> = vec![false; n];
730 for attr in &self.attractors {
731 let mut closest_idx = None;
732 let mut closest_dist = self.influence_radius;
733 for (i, node) in self.nodes.iter().enumerate() {
734 let d = Self::dist3(attr, &node.position);
735 if d < closest_dist {
736 closest_dist = d;
737 closest_idx = Some(i);
738 }
739 }
740 if let Some(idx) = closest_idx {
741 let node_pos = self.nodes[idx].position;
742 let dir = [
743 attr[0] - node_pos[0],
744 attr[1] - node_pos[1],
745 attr[2] - node_pos[2],
746 ];
747 let norm = Self::normalize3(dir);
748 directions[idx][0] += norm[0];
749 directions[idx][1] += norm[1];
750 directions[idx][2] += norm[2];
751 influenced[idx] = true;
752 }
753 }
754 let mut new_nodes = Vec::new();
755 for (i, &inf) in influenced.iter().enumerate() {
756 if inf {
757 let dir = Self::normalize3(directions[i]);
758 let pos = self.nodes[i].position;
759 let new_pos = [
760 pos[0] + dir[0] * self.segment_length,
761 pos[1] + dir[1] * self.segment_length,
762 pos[2] + dir[2] * self.segment_length,
763 ];
764 new_nodes.push(ColonizationNode {
765 position: new_pos,
766 parent: Some(i),
767 direction: dir,
768 num_attractors: 0,
769 });
770 }
771 }
772 let added = new_nodes.len();
773 self.nodes.extend(new_nodes);
774 let kill_radius = self.kill_radius;
775 let nodes = &self.nodes;
776 self.attractors.retain(|attr| {
777 nodes
778 .iter()
779 .all(|node| Self::dist3(attr, &node.position) > kill_radius)
780 });
781 added
782 }
783 pub fn grow_until_done(&mut self, max_steps: u32) {
785 for _ in 0..max_steps {
786 if self.attractors.is_empty() {
787 break;
788 }
789 self.grow();
790 }
791 }
792}
793#[derive(Debug, Clone)]
795pub struct VoronoiTessellation2d {
796 pub seeds: Vec<[f64; 2]>,
798 pub bounds: [f64; 4],
800}
801impl VoronoiTessellation2d {
802 pub fn new(seeds: Vec<[f64; 2]>, bounds: [f64; 4]) -> Self {
804 Self { seeds, bounds }
805 }
806 pub fn nearest_seed(&self, x: f64, y: f64) -> usize {
808 self.seeds
809 .iter()
810 .enumerate()
811 .map(|(i, &[sx, sy])| (i, (x - sx).powi(2) + (y - sy).powi(2)))
812 .min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal))
813 .map(|(i, _)| i)
814 .unwrap_or(0)
815 }
816 pub fn cell_areas(&self, resolution: usize) -> Vec<f64> {
820 let [x_min, x_max, y_min, y_max] = self.bounds;
821 let total_area = (x_max - x_min) * (y_max - y_min);
822 let n = self.seeds.len();
823 let mut counts = vec![0usize; n];
824 let total_samples = resolution * resolution;
825 for row in 0..resolution {
826 for col in 0..resolution {
827 let x = x_min + (col as f64 + 0.5) / resolution as f64 * (x_max - x_min);
828 let y = y_min + (row as f64 + 0.5) / resolution as f64 * (y_max - y_min);
829 let idx = self.nearest_seed(x, y);
830 counts[idx] += 1;
831 }
832 }
833 counts
834 .iter()
835 .map(|&c| c as f64 / total_samples as f64 * total_area)
836 .collect()
837 }
838 pub fn neighbors(&self, resolution: usize) -> Vec<Vec<usize>> {
840 let [x_min, x_max, y_min, y_max] = self.bounds;
841 let n = self.seeds.len();
842 let mut neighbor_sets: Vec<std::collections::HashSet<usize>> =
843 (0..n).map(|_| std::collections::HashSet::new()).collect();
844 for row in 0..resolution {
845 for col in 0..resolution {
846 let x = x_min + (col as f64 + 0.5) / resolution as f64 * (x_max - x_min);
847 let y = y_min + (row as f64 + 0.5) / resolution as f64 * (y_max - y_min);
848 let idx = self.nearest_seed(x, y);
849 for (dr, dc) in [(-1i32, 0), (1, 0), (0, -1i32), (0, 1)] {
850 let nr = row as i32 + dr;
851 let nc = col as i32 + dc;
852 if nr >= 0 && nr < resolution as i32 && nc >= 0 && nc < resolution as i32 {
853 let nx = x_min + (nc as f64 + 0.5) / resolution as f64 * (x_max - x_min);
854 let ny = y_min + (nr as f64 + 0.5) / resolution as f64 * (y_max - y_min);
855 let nidx = self.nearest_seed(nx, ny);
856 if nidx != idx {
857 neighbor_sets[idx].insert(nidx);
858 neighbor_sets[nidx].insert(idx);
859 }
860 }
861 }
862 }
863 }
864 neighbor_sets
865 .into_iter()
866 .map(|s| s.into_iter().collect())
867 .collect()
868 }
869 pub fn random_seeds(n: usize, bounds: [f64; 4], seed: u64) -> Self {
871 let [x_min, x_max, y_min, y_max] = bounds;
872 let mut s = seed;
873 let mut seeds = Vec::with_capacity(n);
874 for _ in 0..n {
875 s = s
876 .wrapping_mul(6_364_136_223_846_793_005)
877 .wrapping_add(1_442_695_040_888_963_407);
878 let x = x_min + (s >> 11) as f64 / (1u64 << 53) as f64 * (x_max - x_min);
879 s = s
880 .wrapping_mul(6_364_136_223_846_793_005)
881 .wrapping_add(1_442_695_040_888_963_407);
882 let y = y_min + (s >> 11) as f64 / (1u64 << 53) as f64 * (y_max - y_min);
883 seeds.push([x, y]);
884 }
885 Self::new(seeds, bounds)
886 }
887}
888#[derive(Debug, Clone)]
890pub struct FractalGeometry {
891 pub points: Vec<[f64; 2]>,
893}
894impl FractalGeometry {
895 pub fn new(points: Vec<[f64; 2]>) -> Self {
897 Self { points }
898 }
899 pub fn box_counting_dimension(&self, num_scales: usize) -> f64 {
905 if self.points.is_empty() || num_scales < 2 {
906 return 0.0;
907 }
908 let (mut x_min, mut x_max) = (f64::MAX, f64::MIN);
909 let (mut y_min, mut y_max) = (f64::MAX, f64::MIN);
910 for &[x, y] in &self.points {
911 x_min = x_min.min(x);
912 x_max = x_max.max(x);
913 y_min = y_min.min(y);
914 y_max = y_max.max(y);
915 }
916 let extent = (x_max - x_min).max(y_max - y_min).max(1e-10);
917 let mut log_inv_eps = Vec::with_capacity(num_scales);
918 let mut log_count = Vec::with_capacity(num_scales);
919 for k in 1..=num_scales {
920 let eps = extent / (2_f64.powi(k as i32));
921 if eps < 1e-12 {
922 break;
923 }
924 let inv_eps = 1.0 / eps;
925 let mut occupied: std::collections::HashSet<(i64, i64)> =
926 std::collections::HashSet::new();
927 for &[x, y] in &self.points {
928 let ix = ((x - x_min) / eps).floor() as i64;
929 let iy = ((y - y_min) / eps).floor() as i64;
930 occupied.insert((ix, iy));
931 }
932 let n = occupied.len() as f64;
933 if n > 0.0 {
934 log_inv_eps.push(inv_eps.ln());
935 log_count.push(n.ln());
936 }
937 }
938 if log_inv_eps.len() < 2 {
939 return 0.0;
940 }
941 let n = log_inv_eps.len() as f64;
942 let sum_x: f64 = log_inv_eps.iter().sum();
943 let sum_y: f64 = log_count.iter().sum();
944 let sum_xy: f64 = log_inv_eps.iter().zip(&log_count).map(|(x, y)| x * y).sum();
945 let sum_x2: f64 = log_inv_eps.iter().map(|x| x * x).sum();
946 let denom = n * sum_x2 - sum_x * sum_x;
947 if denom.abs() < 1e-12 {
948 return 0.0;
949 }
950 (n * sum_xy - sum_x * sum_y) / denom
951 }
952 pub fn hausdorff_dimension(&self) -> f64 {
957 self.box_counting_dimension(12)
958 }
959 pub fn koch_snowflake(iterations: u32, num_points_per_segment: usize) -> Self {
961 let mut segments: Vec<([f64; 2], [f64; 2])> = vec![
962 ([0.0, 0.0], [1.0, 0.0]),
963 ([1.0, 0.0], [0.5, 0.866_025_4]),
964 ([0.5, 0.866_025_4], [0.0, 0.0]),
965 ];
966 for _ in 0..iterations {
967 let mut new_segments = Vec::new();
968 for (a, b) in &segments {
969 let p1 = *a;
970 let p2 = [a[0] + (b[0] - a[0]) / 3.0, a[1] + (b[1] - a[1]) / 3.0];
971 let p4 = [
972 a[0] + 2.0 * (b[0] - a[0]) / 3.0,
973 a[1] + 2.0 * (b[1] - a[1]) / 3.0,
974 ];
975 let p5 = *b;
976 let mx = (p2[0] + p4[0]) / 2.0;
977 let my = (p2[1] + p4[1]) / 2.0;
978 let dx = p4[0] - p2[0];
979 let dy = p4[1] - p2[1];
980 let p3 = [mx - dy * 3_f64.sqrt() / 2.0, my + dx * 3_f64.sqrt() / 2.0];
981 new_segments.push((p1, p2));
982 new_segments.push((p2, p3));
983 new_segments.push((p3, p4));
984 new_segments.push((p4, p5));
985 }
986 segments = new_segments;
987 }
988 let n = num_points_per_segment.max(2);
989 let mut points = Vec::new();
990 for (a, b) in &segments {
991 for i in 0..n {
992 let t = i as f64 / (n - 1) as f64;
993 points.push([a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])]);
994 }
995 }
996 Self { points }
997 }
998 pub fn sierpinski_triangle(iterations: u32) -> Self {
1000 let mut triangles: Vec<([f64; 2], [f64; 2], [f64; 2])> =
1001 vec![([0.0, 0.0], [1.0, 0.0], [0.5, 0.866_025_4])];
1002 for _ in 0..iterations {
1003 let mut new_triangles = Vec::new();
1004 for (a, b, c) in &triangles {
1005 let ab = [(a[0] + b[0]) / 2.0, (a[1] + b[1]) / 2.0];
1006 let bc = [(b[0] + c[0]) / 2.0, (b[1] + c[1]) / 2.0];
1007 let ca = [(c[0] + a[0]) / 2.0, (c[1] + a[1]) / 2.0];
1008 new_triangles.push((*a, ab, ca));
1009 new_triangles.push((ab, *b, bc));
1010 new_triangles.push((ca, bc, *c));
1011 }
1012 triangles = new_triangles;
1013 }
1014 let mut points = Vec::new();
1015 for (a, b, c) in &triangles {
1016 points.push(*a);
1017 points.push(*b);
1018 points.push(*c);
1019 }
1020 Self { points }
1021 }
1022}
1023#[derive(Debug, Clone)]
1025pub struct LSystemRule {
1026 pub predecessor: char,
1028 pub successor: String,
1030}
1031impl LSystemRule {
1032 pub fn new(predecessor: char, successor: &str) -> Self {
1034 Self {
1035 predecessor,
1036 successor: successor.to_string(),
1037 }
1038 }
1039}
1040#[derive(Debug, Clone, Copy)]
1042pub struct DelaunayTri {
1043 pub indices: [usize; 3],
1045}
1046impl DelaunayTri {
1047 pub fn new(a: usize, b: usize, c: usize) -> Self {
1049 Self { indices: [a, b, c] }
1050 }
1051 pub fn circumcircle(&self, points: &[[f64; 2]]) -> ([f64; 2], f64) {
1053 let [ax, ay] = points[self.indices[0]];
1054 let [bx, by] = points[self.indices[1]];
1055 let [cx, cy] = points[self.indices[2]];
1056 let d = 2.0 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
1057 if d.abs() < 1e-12 {
1058 return ([0.0, 0.0], f64::MAX);
1059 }
1060 let ux = ((ax * ax + ay * ay) * (by - cy)
1061 + (bx * bx + by * by) * (cy - ay)
1062 + (cx * cx + cy * cy) * (ay - by))
1063 / d;
1064 let uy = ((ax * ax + ay * ay) * (cx - bx)
1065 + (bx * bx + by * by) * (ax - cx)
1066 + (cx * cx + cy * cy) * (bx - ax))
1067 / d;
1068 let r2 = (ax - ux).powi(2) + (ay - uy).powi(2);
1069 ([ux, uy], r2)
1070 }
1071 pub fn in_circumcircle(&self, points: &[[f64; 2]], p: [f64; 2]) -> bool {
1073 let ([cx, cy], r2) = self.circumcircle(points);
1074 (p[0] - cx).powi(2) + (p[1] - cy).powi(2) < r2 - 1e-10
1075 }
1076}
1077#[derive(Debug, Clone)]
1079pub struct DelaunayTriangulation2d {
1080 pub points: Vec<[f64; 2]>,
1082 pub triangles: Vec<DelaunayTri>,
1084}
1085impl DelaunayTriangulation2d {
1086 pub fn new(points: Vec<[f64; 2]>) -> Self {
1088 let mut tris = Self::bowyer_watson(&points);
1089 let n = points.len();
1090 tris.retain(|t| t.indices.iter().all(|&i| i < n));
1091 Self {
1092 points,
1093 triangles: tris,
1094 }
1095 }
1096 fn bowyer_watson(points: &[[f64; 2]]) -> Vec<DelaunayTri> {
1097 if points.is_empty() {
1098 return Vec::new();
1099 }
1100 let (mut x_min, mut x_max) = (f64::MAX, f64::MIN);
1101 let (mut y_min, mut y_max) = (f64::MAX, f64::MIN);
1102 for &[x, y] in points {
1103 x_min = x_min.min(x);
1104 x_max = x_max.max(x);
1105 y_min = y_min.min(y);
1106 y_max = y_max.max(y);
1107 }
1108 let dx = x_max - x_min;
1109 let dy = y_max - y_min;
1110 let delta_max = dx.max(dy) * 10.0;
1111 let mid_x = (x_min + x_max) / 2.0;
1112 let mid_y = (y_min + y_max) / 2.0;
1113 let n = points.len();
1114 let mut all_points = points.to_vec();
1115 all_points.push([mid_x - 20.0 * delta_max, mid_y - delta_max]);
1116 all_points.push([mid_x, mid_y + 20.0 * delta_max]);
1117 all_points.push([mid_x + 20.0 * delta_max, mid_y - delta_max]);
1118 let mut triangles = vec![DelaunayTri::new(n, n + 1, n + 2)];
1119 for (pi, &point) in points.iter().enumerate() {
1120 let bad: Vec<usize> = triangles
1121 .iter()
1122 .enumerate()
1123 .filter(|(_, t)| t.in_circumcircle(&all_points, point))
1124 .map(|(i, _)| i)
1125 .collect();
1126 let mut boundary: Vec<(usize, usize)> = Vec::new();
1127 for &bi in &bad {
1128 let t = triangles[bi];
1129 let edges = [
1130 (t.indices[0], t.indices[1]),
1131 (t.indices[1], t.indices[2]),
1132 (t.indices[2], t.indices[0]),
1133 ];
1134 for (e0, e1) in edges {
1135 let shared = bad.iter().filter(|&&bj| bj != bi).any(|&bj| {
1136 let other = triangles[bj];
1137 let other_edges = [
1138 (other.indices[0], other.indices[1]),
1139 (other.indices[1], other.indices[2]),
1140 (other.indices[2], other.indices[0]),
1141 ];
1142 other_edges
1143 .iter()
1144 .any(|&(a, b)| (a == e0 && b == e1) || (a == e1 && b == e0))
1145 });
1146 if !shared {
1147 boundary.push((e0, e1));
1148 }
1149 }
1150 }
1151 let mut keep = vec![true; triangles.len()];
1152 for &bi in &bad {
1153 keep[bi] = false;
1154 }
1155 triangles = triangles
1156 .into_iter()
1157 .zip(keep)
1158 .filter(|(_, k)| *k)
1159 .map(|(t, _)| t)
1160 .collect();
1161 for (e0, e1) in boundary {
1162 triangles.push(DelaunayTri::new(e0, e1, pi));
1163 }
1164 }
1165 triangles
1166 }
1167 pub fn verify_delaunay(&self) -> bool {
1169 for tri in &self.triangles {
1170 for (i, &p) in self.points.iter().enumerate() {
1171 if tri.indices.contains(&i) {
1172 continue;
1173 }
1174 if tri.in_circumcircle(&self.points, p) {
1175 return false;
1176 }
1177 }
1178 }
1179 true
1180 }
1181}
1182#[derive(Debug, Clone)]
1184pub struct CurveParametric {
1185 pub control_points: Vec<[f64; 3]>,
1187}
1188impl CurveParametric {
1189 pub fn new(control_points: Vec<[f64; 3]>) -> Self {
1191 Self { control_points }
1192 }
1193 pub fn bezier_de_casteljau(&self, t: f64) -> [f64; 3] {
1197 let n = self.control_points.len();
1198 if n == 0 {
1199 return [0.0, 0.0, 0.0];
1200 }
1201 let mut pts = self.control_points.clone();
1202 for r in 1..n {
1203 for i in 0..(n - r) {
1204 pts[i] = [
1205 (1.0 - t) * pts[i][0] + t * pts[i + 1][0],
1206 (1.0 - t) * pts[i][1] + t * pts[i + 1][1],
1207 (1.0 - t) * pts[i][2] + t * pts[i + 1][2],
1208 ];
1209 }
1210 }
1211 pts[0]
1212 }
1213 pub fn bezier_bernstein(&self, t: f64) -> [f64; 3] {
1217 if self.control_points.len() != 4 {
1218 return self.bezier_de_casteljau(t);
1219 }
1220 let [p0, p1, p2, p3] = [
1221 self.control_points[0],
1222 self.control_points[1],
1223 self.control_points[2],
1224 self.control_points[3],
1225 ];
1226 let mt = 1.0 - t;
1227 let b0 = mt * mt * mt;
1228 let b1 = 3.0 * mt * mt * t;
1229 let b2 = 3.0 * mt * t * t;
1230 let b3 = t * t * t;
1231 [
1232 b0 * p0[0] + b1 * p1[0] + b2 * p2[0] + b3 * p3[0],
1233 b0 * p0[1] + b1 * p1[1] + b2 * p2[1] + b3 * p3[1],
1234 b0 * p0[2] + b1 * p1[2] + b2 * p2[2] + b3 * p3[2],
1235 ]
1236 }
1237 pub fn bspline_de_boor(&self, t: f64, degree: usize, knots: &[f64]) -> [f64; 3] {
1241 let n = self.control_points.len();
1242 if n == 0 || knots.len() < n + degree + 1 {
1243 return [0.0, 0.0, 0.0];
1244 }
1245 let t = t.clamp(knots[degree], knots[n]);
1246 let mut k = degree;
1247 for i in degree..n {
1248 if t >= knots[i] && t < knots[i + 1] {
1249 k = i;
1250 break;
1251 }
1252 }
1253 if t >= knots[n] {
1254 k = n - 1;
1255 }
1256 let mut d: Vec<[f64; 3]> = (0..=degree)
1257 .map(|j| self.control_points[k - degree + j])
1258 .collect();
1259 for r in 1..=degree {
1260 for j in (r..=degree).rev() {
1261 let i = k - degree + j;
1262 let denom = knots[i + degree - r + 1] - knots[i];
1263 let alpha = if denom.abs() < 1e-12 {
1264 0.0
1265 } else {
1266 (t - knots[i]) / denom
1267 };
1268 d[j] = [
1269 (1.0 - alpha) * d[j - 1][0] + alpha * d[j][0],
1270 (1.0 - alpha) * d[j - 1][1] + alpha * d[j][1],
1271 (1.0 - alpha) * d[j - 1][2] + alpha * d[j][2],
1272 ];
1273 }
1274 }
1275 d[degree]
1276 }
1277 pub fn nurbs(&self, t: f64, degree: usize, knots: &[f64], weights: &[f64]) -> [f64; 3] {
1281 let n = self.control_points.len();
1282 if n == 0 || weights.len() != n {
1283 return [0.0, 0.0, 0.0];
1284 }
1285 let homo_xyz: Vec<[f64; 3]> = self
1286 .control_points
1287 .iter()
1288 .zip(weights)
1289 .map(|(&[x, y, z], &w)| [x * w, y * w, z * w])
1290 .collect();
1291 let w_pts: Vec<[f64; 3]> = weights.iter().map(|&w| [w, 0.0, 0.0]).collect();
1292 let homo_curve = CurveParametric::new(homo_xyz);
1293 let w_curve = CurveParametric::new(w_pts);
1294 let p = homo_curve.bspline_de_boor(t, degree, knots);
1295 let w = w_curve.bspline_de_boor(t, degree, knots)[0];
1296 if w.abs() < 1e-12 {
1297 return [0.0, 0.0, 0.0];
1298 }
1299 [p[0] / w, p[1] / w, p[2] / w]
1300 }
1301 pub fn sample_bezier(&self, n: usize) -> Vec<[f64; 3]> {
1303 (0..n)
1304 .map(|i| {
1305 let t = i as f64 / (n - 1).max(1) as f64;
1306 self.bezier_de_casteljau(t)
1307 })
1308 .collect()
1309 }
1310 pub fn bezier_arc_length(&self, samples: usize) -> f64 {
1312 let pts = self.sample_bezier(samples);
1313 pts.windows(2)
1314 .map(|w| {
1315 let [ax, ay, az] = w[0];
1316 let [bx, by, bz] = w[1];
1317 ((ax - bx).powi(2) + (ay - by).powi(2) + (az - bz).powi(2)).sqrt()
1318 })
1319 .sum()
1320 }
1321}
1322#[derive(Debug, Clone)]
1324pub struct PerlinNoise3d {
1325 pub(super) perm: Vec<u8>,
1326}
1327impl PerlinNoise3d {
1328 pub fn new(seed: u64) -> Self {
1330 let mut perm = (0u8..=255).collect::<Vec<_>>();
1331 let mut s = seed;
1332 for i in (1..256).rev() {
1333 s = s
1334 .wrapping_mul(6_364_136_223_846_793_005)
1335 .wrapping_add(1_442_695_040_888_963_407);
1336 let j = (s >> 33) as usize % (i + 1);
1337 perm.swap(i, j);
1338 }
1339 let mut full = perm.clone();
1340 full.extend_from_slice(&perm);
1341 Self { perm: full }
1342 }
1343 fn fade(t: f64) -> f64 {
1344 t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
1345 }
1346 fn lerp(a: f64, b: f64, t: f64) -> f64 {
1347 a + t * (b - a)
1348 }
1349 fn grad3(hash: u8, x: f64, y: f64, z: f64) -> f64 {
1350 match hash & 15 {
1351 0 => x + y,
1352 1 => -x + y,
1353 2 => x - y,
1354 3 => -x - y,
1355 4 => x + z,
1356 5 => -x + z,
1357 6 => x - z,
1358 7 => -x - z,
1359 8 => y + z,
1360 9 => -y + z,
1361 10 => y - z,
1362 11 => -y - z,
1363 12 => y + x,
1364 13 => -y + z,
1365 14 => y - x,
1366 _ => -y - z,
1367 }
1368 }
1369 fn p(&self, i: usize) -> u8 {
1370 self.perm[i & 511]
1371 }
1372 pub fn noise(&self, x: f64, y: f64, z: f64) -> f64 {
1374 let xi = x.floor() as i32 & 255;
1375 let yi = y.floor() as i32 & 255;
1376 let zi = z.floor() as i32 & 255;
1377 let xf = x - x.floor();
1378 let yf = y - y.floor();
1379 let zf = z - z.floor();
1380 let u = Self::fade(xf);
1381 let v = Self::fade(yf);
1382 let w = Self::fade(zf);
1383 let a = self.p(xi as usize).wrapping_add(yi as u8);
1384 let aa = self.p(a as usize).wrapping_add(zi as u8);
1385 let ab = self.p((a.wrapping_add(1)) as usize).wrapping_add(zi as u8);
1386 let b = self.p((xi + 1) as usize).wrapping_add(yi as u8);
1387 let ba = self.p(b as usize).wrapping_add(zi as u8);
1388 let bb = self.p((b.wrapping_add(1)) as usize).wrapping_add(zi as u8);
1389 Self::lerp(
1390 Self::lerp(
1391 Self::lerp(
1392 Self::grad3(self.p(aa as usize), xf, yf, zf),
1393 Self::grad3(self.p(ba as usize), xf - 1.0, yf, zf),
1394 u,
1395 ),
1396 Self::lerp(
1397 Self::grad3(self.p(ab as usize), xf, yf - 1.0, zf),
1398 Self::grad3(self.p(bb as usize), xf - 1.0, yf - 1.0, zf),
1399 u,
1400 ),
1401 v,
1402 ),
1403 Self::lerp(
1404 Self::lerp(
1405 Self::grad3(self.p((aa.wrapping_add(1)) as usize), xf, yf, zf - 1.0),
1406 Self::grad3(
1407 self.p((ba.wrapping_add(1)) as usize),
1408 xf - 1.0,
1409 yf,
1410 zf - 1.0,
1411 ),
1412 u,
1413 ),
1414 Self::lerp(
1415 Self::grad3(
1416 self.p((ab.wrapping_add(1)) as usize),
1417 xf,
1418 yf - 1.0,
1419 zf - 1.0,
1420 ),
1421 Self::grad3(
1422 self.p((bb.wrapping_add(1)) as usize),
1423 xf - 1.0,
1424 yf - 1.0,
1425 zf - 1.0,
1426 ),
1427 u,
1428 ),
1429 v,
1430 ),
1431 w,
1432 )
1433 }
1434 pub fn fbm(&self, x: f64, y: f64, z: f64, octaves: u32, lacunarity: f64, gain: f64) -> f64 {
1436 let mut value = 0.0;
1437 let mut amplitude = 1.0;
1438 let mut frequency = 1.0;
1439 let mut max_val = 0.0;
1440 for _ in 0..octaves {
1441 value += amplitude * self.noise(x * frequency, y * frequency, z * frequency);
1442 max_val += amplitude;
1443 amplitude *= gain;
1444 frequency *= lacunarity;
1445 }
1446 if max_val > 0.0 { value / max_val } else { 0.0 }
1447 }
1448}
1449#[derive(Debug, Clone)]
1451pub struct ColonizationNode {
1452 pub position: [f64; 3],
1454 pub parent: Option<usize>,
1456 pub direction: [f64; 3],
1458 pub num_attractors: usize,
1460}