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