1#[allow(unused_imports)]
6use super::functions::*;
7use rand::RngExt;
8use std::collections::HashMap;
9
10pub struct Lacunarity;
15impl Lacunarity {
16 #[allow(dead_code)]
23 pub fn gliding_box(grid: &[Vec<bool>], box_size: usize) -> f64 {
24 let rows = grid.len();
25 if rows == 0 || box_size == 0 {
26 return 0.0;
27 }
28 let cols = grid[0].len();
29 if box_size > rows || box_size > cols {
30 return 0.0;
31 }
32 let mut masses = Vec::new();
33 for r in 0..=(rows - box_size) {
34 for c in 0..=(cols - box_size) {
35 let mut mass = 0u64;
36 for dr in 0..box_size {
37 for dc in 0..box_size {
38 if grid[r + dr][c + dc] {
39 mass += 1;
40 }
41 }
42 }
43 masses.push(mass as f64);
44 }
45 }
46 if masses.is_empty() {
47 return 0.0;
48 }
49 let n = masses.len() as f64;
50 let mean = masses.iter().sum::<f64>() / n;
51 if mean.abs() < 1e-15 {
52 return 0.0;
53 }
54 let variance = masses.iter().map(|&m| (m - mean).powi(2)).sum::<f64>() / n;
55 variance / (mean * mean) + 1.0
56 }
57 #[allow(dead_code)]
61 pub fn from_points(points: &[Point2], resolution: usize, box_size: usize) -> f64 {
62 if points.is_empty() || resolution == 0 {
63 return 0.0;
64 }
65 let (min_x, max_x, min_y, max_y) = FractalDimension::bounding_box(points);
66 let dx = (max_x - min_x).max(1e-15);
67 let dy = (max_y - min_y).max(1e-15);
68 let mut grid = vec![vec![false; resolution]; resolution];
69 for p in points {
70 let ix = (((p.x - min_x) / dx) * (resolution - 1) as f64)
71 .round()
72 .clamp(0.0, (resolution - 1) as f64) as usize;
73 let iy = (((p.y - min_y) / dy) * (resolution - 1) as f64)
74 .round()
75 .clamp(0.0, (resolution - 1) as f64) as usize;
76 grid[iy][ix] = true;
77 }
78 Self::gliding_box(&grid, box_size)
79 }
80 #[allow(dead_code)]
84 pub fn multiscale(grid: &[Vec<bool>], box_sizes: &[usize]) -> Vec<(usize, f64)> {
85 box_sizes
86 .iter()
87 .map(|&bs| (bs, Self::gliding_box(grid, bs)))
88 .collect()
89 }
90}
91pub struct SierpinskiArrowhead;
93impl SierpinskiArrowhead {
94 pub fn lsystem() -> LSystem {
96 LSystem::new(
97 vec!['F', 'G', '+', '-'],
98 vec![
99 ProductionRule::new('F', "G-F-G"),
100 ProductionRule::new('G', "F+G+F"),
101 ],
102 "F",
103 )
104 }
105 pub fn theoretical_dimension() -> f64 {
107 (3.0_f64).ln() / (2.0_f64).ln()
108 }
109 pub fn generate(generations: usize, step_size: f64) -> Vec<(Point2, Point2)> {
111 let ls = Self::lsystem();
112 ls.turtle_interpret(generations, step_size, 60.0)
113 }
114}
115#[derive(Debug, Clone)]
117pub struct IteratedFunctionSystem {
118 pub transforms: Vec<AffineTransform2D>,
120 pub probabilities: Vec<f64>,
122}
123impl IteratedFunctionSystem {
124 pub fn new(transforms: Vec<AffineTransform2D>, probabilities: Vec<f64>) -> Self {
128 if transforms.is_empty() {
129 return Self {
130 transforms: Vec::new(),
131 probabilities: Vec::new(),
132 };
133 }
134 assert_eq!(
135 transforms.len(),
136 probabilities.len(),
137 "transforms and probabilities must have equal length"
138 );
139 Self {
140 transforms,
141 probabilities,
142 }
143 }
144 pub fn with_equal_probabilities(transforms: Vec<AffineTransform2D>) -> Self {
146 let n = transforms.len();
147 assert!(n > 0, "IFS must have at least one transform");
148 let prob = 1.0 / n as f64;
149 let probabilities = vec![prob; n];
150 Self {
151 transforms,
152 probabilities,
153 }
154 }
155 pub fn chaos_game(&self, start: Point2, iterations: usize, skip: usize) -> Vec<Point2> {
161 use rand::RngExt;
162 let mut rng = rand::rng();
163 let mut point = start;
164 let mut points = Vec::with_capacity(iterations.saturating_sub(skip));
165 let cumulative = self.cumulative_distribution();
166 for i in 0..iterations {
167 let r: f64 = rng.random_range(0.0..1.0);
168 let idx = cumulative
169 .iter()
170 .position(|&c| r < c)
171 .unwrap_or(self.transforms.len() - 1);
172 point = self.transforms[idx].apply(&point);
173 if i >= skip {
174 points.push(point);
175 }
176 }
177 points
178 }
179 pub fn deterministic_iterate(
184 &self,
185 initial_points: &[Point2],
186 generations: usize,
187 ) -> Vec<Point2> {
188 let mut current = initial_points.to_vec();
189 for _ in 0..generations {
190 let mut next = Vec::with_capacity(current.len() * self.transforms.len());
191 for t in &self.transforms {
192 for p in ¤t {
193 next.push(t.apply(p));
194 }
195 }
196 current = next;
197 }
198 current
199 }
200 pub fn num_transforms(&self) -> usize {
202 self.transforms.len()
203 }
204 pub fn barnsley_fern() -> Self {
206 let transforms = vec![
207 AffineTransform2D::new(0.0, 0.0, 0.0, 0.16, 0.0, 0.0),
208 AffineTransform2D::new(0.85, 0.04, -0.04, 0.85, 0.0, 1.6),
209 AffineTransform2D::new(0.20, -0.26, 0.23, 0.22, 0.0, 1.6),
210 AffineTransform2D::new(-0.15, 0.28, 0.26, 0.24, 0.0, 0.44),
211 ];
212 let probabilities = vec![0.01, 0.85, 0.07, 0.07];
213 Self::new(transforms, probabilities)
214 }
215 pub fn generate(&self, n: usize, seed: u64) -> Vec<[f64; 2]> {
219 if self.transforms.is_empty() {
220 return Vec::new();
221 }
222 let cumulative = self.cumulative_distribution();
223 let mut x = 0.0_f64;
224 let mut y = 0.0_f64;
225 let mut rng_state = seed;
226 let mut points = Vec::with_capacity(n);
227 for _ in 0..n {
229 rng_state = rng_state
230 .wrapping_mul(6364136223846793005)
231 .wrapping_add(1442695040888963407);
232 let r = ((rng_state >> 33) as f64) / (u32::MAX as f64);
233 let idx = cumulative
234 .iter()
235 .position(|&c| r < c)
236 .unwrap_or(self.transforms.len() - 1);
237 let t = &self.transforms[idx];
238 let nx = t.a * x + t.b * y + t.e;
239 let ny = t.c * x + t.d * y + t.f;
240 x = nx;
241 y = ny;
242 points.push([x, y]);
243 }
244 points
245 }
246 fn cumulative_distribution(&self) -> Vec<f64> {
248 let mut cum = Vec::with_capacity(self.probabilities.len());
249 let mut acc = 0.0;
250 for &p in &self.probabilities {
251 acc += p;
252 cum.push(acc);
253 }
254 cum
255 }
256}
257#[derive(Debug, Clone)]
259pub struct ProductionRule {
260 pub predecessor: char,
262 pub successor: String,
264}
265impl ProductionRule {
266 pub fn new(predecessor: char, successor: impl Into<String>) -> Self {
268 Self {
269 predecessor,
270 successor: successor.into(),
271 }
272 }
273}
274pub struct MandelbrotSet {
279 pub max_iter: u32,
281 pub escape_radius_sq: f64,
283}
284impl MandelbrotSet {
285 pub fn new(max_iter: u32, escape_radius: f64) -> Self {
287 Self {
288 max_iter,
289 escape_radius_sq: escape_radius * escape_radius,
290 }
291 }
292 pub fn default_set() -> Self {
294 Self::new(256, 2.0)
295 }
296 pub fn escape_time(&self, cr: f64, ci: f64) -> Option<u32> {
301 let mut zr = 0.0;
302 let mut zi = 0.0;
303 for i in 0..self.max_iter {
304 let zr2 = zr * zr;
305 let zi2 = zi * zi;
306 if zr2 + zi2 > self.escape_radius_sq {
307 return Some(i);
308 }
309 zi = 2.0 * zr * zi + ci;
310 zr = zr2 - zi2 + cr;
311 }
312 None
313 }
314 pub fn smooth_escape_time(&self, cr: f64, ci: f64) -> f64 {
318 let mut zr = 0.0;
319 let mut zi = 0.0;
320 for i in 0..self.max_iter {
321 let zr2 = zr * zr;
322 let zi2 = zi * zi;
323 if zr2 + zi2 > self.escape_radius_sq {
324 let modulus = (zr2 + zi2).sqrt();
325 let mu = i as f64 - modulus.ln().ln() / (2.0_f64).ln();
326 return mu;
327 }
328 zi = 2.0 * zr * zi + ci;
329 zr = zr2 - zi2 + cr;
330 }
331 self.max_iter as f64
332 }
333 pub fn is_in_set(&self, cr: f64, ci: f64) -> bool {
335 self.escape_time(cr, ci).is_none()
336 }
337 pub fn is_boundary(&self, cr: f64, ci: f64, delta: f64) -> bool {
342 let center = self.is_in_set(cr, ci);
343 let offsets = [(delta, 0.0), (-delta, 0.0), (0.0, delta), (0.0, -delta)];
344 for (dr, di) in offsets {
345 if self.is_in_set(cr + dr, ci + di) != center {
346 return true;
347 }
348 }
349 false
350 }
351 #[allow(dead_code)]
357 pub fn area_monte_carlo(
358 &self,
359 x_min: f64,
360 x_max: f64,
361 y_min: f64,
362 y_max: f64,
363 num_samples: usize,
364 ) -> f64 {
365 let mut rng = rand::rng();
366 let mut count = 0usize;
367 for _ in 0..num_samples {
368 let cr = rng.random_range(x_min..x_max);
369 let ci = rng.random_range(y_min..y_max);
370 if self.is_in_set(cr, ci) {
371 count += 1;
372 }
373 }
374 let rect_area = (x_max - x_min) * (y_max - y_min);
375 rect_area * count as f64 / num_samples as f64
376 }
377 pub fn render_grid(
381 &self,
382 x_min: f64,
383 x_max: f64,
384 y_min: f64,
385 y_max: f64,
386 width: usize,
387 height: usize,
388 ) -> Vec<Vec<Option<u32>>> {
389 let dx = (x_max - x_min) / width as f64;
390 let dy = (y_max - y_min) / height as f64;
391 (0..height)
392 .map(|j| {
393 let ci = y_min + (j as f64 + 0.5) * dy;
394 (0..width)
395 .map(|i| {
396 let cr = x_min + (i as f64 + 0.5) * dx;
397 self.escape_time(cr, ci)
398 })
399 .collect()
400 })
401 .collect()
402 }
403}
404pub struct HilbertCurveMap;
409impl HilbertCurveMap {
410 #[allow(dead_code)]
412 pub fn d2xy(n: u32, d: u32) -> (u32, u32) {
413 let mut rx: u32;
414 let mut ry: u32;
415 let mut x = 0_u32;
416 let mut y = 0_u32;
417 let mut d = d;
418 let mut s = 1_u32;
419 while s < n {
420 rx = if (d & 2) != 0 { 1 } else { 0 };
421 ry = if (d & 1) != 0 {
422 if rx == 0 { 1 } else { 0 }
423 } else {
424 0
425 };
426 Self::rot(s, &mut x, &mut y, rx, ry);
427 x += s * rx;
428 y += s * ry;
429 d /= 4;
430 s *= 2;
431 }
432 (x, y)
433 }
434 #[allow(dead_code)]
436 pub fn xy2d(n: u32, x: u32, y: u32) -> u32 {
437 let mut rx: u32;
438 let mut ry: u32;
439 let mut d = 0_u32;
440 let mut x = x;
441 let mut y = y;
442 let mut s = n / 2;
443 while s > 0 {
444 rx = if (x & s) > 0 { 1 } else { 0 };
445 ry = if (y & s) > 0 { 1 } else { 0 };
446 d += s * s * ((3 * rx) ^ ry);
447 Self::rot(s, &mut x, &mut y, rx, ry);
448 s /= 2;
449 }
450 d
451 }
452 #[allow(dead_code)]
454 fn rot(n: u32, x: &mut u32, y: &mut u32, rx: u32, ry: u32) {
455 if ry == 0 {
456 if rx == 1 {
457 *x = n.wrapping_sub(1).wrapping_sub(*x);
458 *y = n.wrapping_sub(1).wrapping_sub(*y);
459 }
460 std::mem::swap(x, y);
461 }
462 }
463 #[allow(dead_code)]
467 pub fn generate_path(n: u32) -> Vec<(u32, u32)> {
468 let total = n * n;
469 (0..total).map(|d| Self::d2xy(n, d)).collect()
470 }
471}
472pub struct FractalTerrain;
476impl FractalTerrain {
477 #[allow(dead_code)]
483 pub fn diamond_square(power: u32, roughness: f64, seed_corners: [f64; 4]) -> Vec<Vec<f64>> {
484 let size = (1 << power) + 1;
485 let mut grid = vec![vec![0.0_f64; size]; size];
486 let last = size - 1;
487 grid[0][0] = seed_corners[0];
488 grid[0][last] = seed_corners[1];
489 grid[last][0] = seed_corners[2];
490 grid[last][last] = seed_corners[3];
491 let mut rng = rand::rng();
492 let mut step = last;
493 let mut scale = 1.0_f64;
494 while step > 1 {
495 let half = step / 2;
496 let mut y = 0;
497 while y < last {
498 let mut x = 0;
499 while x < last {
500 let avg = (grid[y][x]
501 + grid[y][x + step]
502 + grid[y + step][x]
503 + grid[y + step][x + step])
504 / 4.0;
505 grid[y + half][x + half] = avg + rng.random_range(-scale..scale);
506 x += step;
507 }
508 y += step;
509 }
510 let mut y = 0;
511 while y <= last {
512 let x_start = if (y / half).is_multiple_of(2) {
513 half
514 } else {
515 0
516 };
517 let mut x = x_start;
518 while x <= last {
519 let mut sum = 0.0;
520 let mut count = 0.0;
521 if y >= half {
522 sum += grid[y - half][x];
523 count += 1.0;
524 }
525 if y + half <= last {
526 sum += grid[y + half][x];
527 count += 1.0;
528 }
529 if x >= half {
530 sum += grid[y][x - half];
531 count += 1.0;
532 }
533 if x + half <= last {
534 sum += grid[y][x + half];
535 count += 1.0;
536 }
537 grid[y][x] = sum / count + rng.random_range(-scale..scale);
538 x += step;
539 }
540 y += half;
541 }
542 step = half;
543 scale *= roughness;
544 }
545 grid
546 }
547 #[allow(dead_code)]
552 pub fn midpoint_displacement_1d(
553 power: u32,
554 roughness: f64,
555 h_left: f64,
556 h_right: f64,
557 ) -> Vec<f64> {
558 let size = (1 << power) + 1;
559 let mut heights = vec![0.0_f64; size];
560 heights[0] = h_left;
561 heights[size - 1] = h_right;
562 let mut rng = rand::rng();
563 let mut step = size - 1;
564 let mut scale = 1.0_f64;
565 while step > 1 {
566 let half = step / 2;
567 let mut i = half;
568 while i < size {
569 let left = heights[i - half];
570 let right = if i + half < size {
571 heights[i + half]
572 } else {
573 heights[size - 1]
574 };
575 heights[i] = (left + right) / 2.0 + rng.random_range(-scale..scale);
576 i += step;
577 }
578 step = half;
579 scale *= roughness;
580 }
581 heights
582 }
583 #[allow(dead_code)]
585 pub fn rms_roughness(grid: &[Vec<f64>]) -> f64 {
586 let mut sum = 0.0;
587 let mut count = 0usize;
588 let mut mean = 0.0;
589 for row in grid {
590 for &h in row {
591 mean += h;
592 count += 1;
593 }
594 }
595 if count == 0 {
596 return 0.0;
597 }
598 mean /= count as f64;
599 for row in grid {
600 for &h in row {
601 sum += (h - mean).powi(2);
602 }
603 }
604 (sum / count as f64).sqrt()
605 }
606 #[allow(dead_code)]
608 pub fn height_range(grid: &[Vec<f64>]) -> (f64, f64) {
609 let mut lo = f64::MAX;
610 let mut hi = f64::MIN;
611 for row in grid {
612 for &h in row {
613 if h < lo {
614 lo = h;
615 }
616 if h > hi {
617 hi = h;
618 }
619 }
620 }
621 (lo, hi)
622 }
623}
624pub struct FractalMesh;
629impl FractalMesh {
630 #[allow(dead_code)]
635 pub fn from_heightmap(grid: &[Vec<f64>], spacing: f64) -> (Vec<[f64; 3]>, Vec<[usize; 3]>) {
636 let rows = grid.len();
637 if rows == 0 {
638 return (Vec::new(), Vec::new());
639 }
640 let cols = grid[0].len();
641 let mut vertices = Vec::with_capacity(rows * cols);
642 for (r, row) in grid.iter().enumerate() {
643 for (c, &h) in row.iter().enumerate() {
644 vertices.push([c as f64 * spacing, h, r as f64 * spacing]);
645 }
646 }
647 let mut triangles = Vec::new();
648 for r in 0..(rows - 1) {
649 for c in 0..(cols - 1) {
650 let i0 = r * cols + c;
651 let i1 = i0 + 1;
652 let i2 = i0 + cols;
653 let i3 = i2 + 1;
654 triangles.push([i0, i2, i1]);
655 triangles.push([i1, i2, i3]);
656 }
657 }
658 (vertices, triangles)
659 }
660 #[allow(dead_code)]
662 pub fn surface_area(vertices: &[[f64; 3]], triangles: &[[usize; 3]]) -> f64 {
663 let mut area = 0.0;
664 for tri in triangles {
665 let a = vertices[tri[0]];
666 let b = vertices[tri[1]];
667 let c = vertices[tri[2]];
668 let ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
669 let ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
670 let cross = [
671 ab[1] * ac[2] - ab[2] * ac[1],
672 ab[2] * ac[0] - ab[0] * ac[2],
673 ab[0] * ac[1] - ab[1] * ac[0],
674 ];
675 area += (cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]).sqrt() / 2.0;
676 }
677 area
678 }
679 #[allow(dead_code)]
681 pub fn expected_counts(rows: usize, cols: usize) -> (usize, usize) {
682 let verts = rows * cols;
683 let tris = if rows > 1 && cols > 1 {
684 2 * (rows - 1) * (cols - 1)
685 } else {
686 0
687 };
688 (verts, tris)
689 }
690}
691pub struct HilbertCurve;
693impl HilbertCurve {
694 pub fn lsystem() -> LSystem {
696 LSystem::new(
697 vec!['A', 'B', 'F', '+', '-'],
698 vec![
699 ProductionRule::new('A', "+BF-AFA-FB+"),
700 ProductionRule::new('B', "-AF+BFB+FA-"),
701 ],
702 "A",
703 )
704 }
705 pub fn generate(generations: usize, step_size: f64) -> Vec<(Point2, Point2)> {
707 let ls = Self::lsystem();
708 ls.turtle_interpret(generations, step_size, 90.0)
709 }
710}
711pub struct FractalDimension;
713impl FractalDimension {
714 pub fn box_counting(points: &[Point2], num_scales: usize) -> (f64, f64) {
720 if points.is_empty() || num_scales < 2 {
721 return (0.0, 0.0);
722 }
723 let (min_x, max_x, min_y, max_y) = Self::bounding_box(points);
724 let extent = (max_x - min_x).max(max_y - min_y).max(1e-15);
725 let mut log_eps = Vec::with_capacity(num_scales);
726 let mut log_n = Vec::with_capacity(num_scales);
727 for i in 0..num_scales {
728 let epsilon = extent / (2.0_f64).powi(i as i32 + 1);
729 if epsilon < 1e-15 {
730 break;
731 }
732 let mut occupied = std::collections::HashSet::new();
733 for p in points {
734 let ix = ((p.x - min_x) / epsilon).floor() as i64;
735 let iy = ((p.y - min_y) / epsilon).floor() as i64;
736 occupied.insert((ix, iy));
737 }
738 let count = occupied.len() as f64;
739 if count > 0.0 {
740 log_eps.push(epsilon.ln());
741 log_n.push(count.ln());
742 }
743 }
744 if log_eps.len() < 2 {
745 return (0.0, 0.0);
746 }
747 let (slope, r_sq) = Self::linear_regression(&log_eps, &log_n);
748 (-slope, r_sq)
749 }
750 pub fn correlation_dimension(points: &[Point2], num_scales: usize) -> (f64, f64) {
755 let n = points.len();
756 if n < 10 || num_scales < 2 {
757 return (0.0, 0.0);
758 }
759 let mut max_dist = 0.0_f64;
760 let mut min_dist = f64::MAX;
761 let num_pairs = n * (n - 1) / 2;
762 let mut distances = Vec::with_capacity(num_pairs);
763 for i in 0..n {
764 for j in (i + 1)..n {
765 let d = points[i].distance(&points[j]);
766 distances.push(d);
767 if d > max_dist {
768 max_dist = d;
769 }
770 if d > 0.0 && d < min_dist {
771 min_dist = d;
772 }
773 }
774 }
775 if max_dist < 1e-15 {
776 return (0.0, 0.0);
777 }
778 distances.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
779 let mut log_r = Vec::with_capacity(num_scales);
780 let mut log_c = Vec::with_capacity(num_scales);
781 let r_min = min_dist.max(max_dist * 0.001);
782 let r_max = max_dist * 0.5;
783 let ratio = (r_max / r_min).powf(1.0 / (num_scales as f64 - 1.0));
784 for i in 0..num_scales {
785 let r = r_min * ratio.powi(i as i32);
786 let count = distances.partition_point(|&d| d <= r);
787 if count > 0 {
788 let c = count as f64 / num_pairs as f64;
789 log_r.push(r.ln());
790 log_c.push(c.ln());
791 }
792 }
793 if log_r.len() < 2 {
794 return (0.0, 0.0);
795 }
796 let (slope, r_sq) = Self::linear_regression(&log_r, &log_c);
797 (slope, r_sq)
798 }
799 pub fn hausdorff_estimate(points: &[Point2], num_scales: usize) -> f64 {
803 if points.is_empty() || num_scales < 4 {
804 return 0.0;
805 }
806 let (dim1, _) = Self::box_counting(points, num_scales);
807 let half = num_scales / 2;
808 let (dim2, _) = Self::box_counting(points, half);
809 0.6 * dim1 + 0.4 * dim2
810 }
811 pub(super) fn bounding_box(points: &[Point2]) -> (f64, f64, f64, f64) {
813 let mut min_x = f64::MAX;
814 let mut max_x = f64::MIN;
815 let mut min_y = f64::MAX;
816 let mut max_y = f64::MIN;
817 for p in points {
818 if p.x < min_x {
819 min_x = p.x;
820 }
821 if p.x > max_x {
822 max_x = p.x;
823 }
824 if p.y < min_y {
825 min_y = p.y;
826 }
827 if p.y > max_y {
828 max_y = p.y;
829 }
830 }
831 (min_x, max_x, min_y, max_y)
832 }
833 fn linear_regression(x: &[f64], y: &[f64]) -> (f64, f64) {
835 let n = x.len() as f64;
836 let sum_x: f64 = x.iter().sum();
837 let sum_y: f64 = y.iter().sum();
838 let sum_xy: f64 = x.iter().zip(y.iter()).map(|(xi, yi)| xi * yi).sum();
839 let sum_x2: f64 = x.iter().map(|xi| xi * xi).sum();
840 let sum_y2: f64 = y.iter().map(|yi| yi * yi).sum();
841 let denom = n * sum_x2 - sum_x * sum_x;
842 if denom.abs() < 1e-30 {
843 return (0.0, 0.0);
844 }
845 let slope = (n * sum_xy - sum_x * sum_y) / denom;
846 let ss_tot = sum_y2 - sum_y * sum_y / n;
847 let ss_res = sum_y2 - slope * sum_xy - (sum_y - slope * sum_x) * sum_y / n;
848 let r_sq = if ss_tot.abs() > 1e-30 {
849 1.0 - ss_res / ss_tot
850 } else {
851 0.0
852 };
853 (slope, r_sq.clamp(0.0, 1.0))
854 }
855}
856pub struct SierpinskiTriangle;
861impl SierpinskiTriangle {
862 pub fn ifs() -> IteratedFunctionSystem {
864 let transforms = vec![
865 AffineTransform2D::new(0.5, 0.0, 0.0, 0.5, 0.0, 0.0),
866 AffineTransform2D::new(0.5, 0.0, 0.0, 0.5, 0.5, 0.0),
867 AffineTransform2D::new(0.5, 0.0, 0.0, 0.5, 0.25, 0.433),
868 ];
869 IteratedFunctionSystem::with_equal_probabilities(transforms)
870 }
871 pub fn theoretical_dimension() -> f64 {
873 (3.0_f64).ln() / (2.0_f64).ln()
874 }
875 pub fn generate(num_points: usize) -> Vec<Point2> {
877 let ifs = Self::ifs();
878 ifs.chaos_game(Point2::new(0.0, 0.0), num_points + 100, 100)
879 }
880}
881#[derive(Debug, Clone, Copy, PartialEq)]
885pub struct AffineTransform2D {
886 pub a: f64,
888 pub b: f64,
890 pub c: f64,
892 pub d: f64,
894 pub e: f64,
896 pub f: f64,
898}
899impl AffineTransform2D {
900 pub fn new(a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> Self {
902 Self { a, b, c, d, e, f }
903 }
904 pub fn identity() -> Self {
906 Self::new(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
907 }
908 pub fn rotation(angle_rad: f64) -> Self {
910 let cos = angle_rad.cos();
911 let sin = angle_rad.sin();
912 Self::new(cos, -sin, sin, cos, 0.0, 0.0)
913 }
914 pub fn scaling(sx: f64, sy: f64) -> Self {
916 Self::new(sx, 0.0, 0.0, sy, 0.0, 0.0)
917 }
918 pub fn translation(tx: f64, ty: f64) -> Self {
920 Self::new(1.0, 0.0, 0.0, 1.0, tx, ty)
921 }
922 pub fn apply(&self, p: &Point2) -> Point2 {
924 Point2 {
925 x: self.a * p.x + self.b * p.y + self.e,
926 y: self.c * p.x + self.d * p.y + self.f,
927 }
928 }
929 pub fn compose(&self, other: &AffineTransform2D) -> AffineTransform2D {
933 AffineTransform2D {
934 a: other.a * self.a + other.b * self.c,
935 b: other.a * self.b + other.b * self.d,
936 c: other.c * self.a + other.d * self.c,
937 d: other.c * self.b + other.d * self.d,
938 e: other.a * self.e + other.b * self.f + other.e,
939 f: other.c * self.e + other.d * self.f + other.f,
940 }
941 }
942 pub fn determinant(&self) -> f64 {
944 self.a * self.d - self.b * self.c
945 }
946 pub fn inverse(&self) -> Option<AffineTransform2D> {
948 let det = self.determinant();
949 if det.abs() < 1e-15 {
950 return None;
951 }
952 let inv_det = 1.0 / det;
953 let a = self.d * inv_det;
954 let b = -self.b * inv_det;
955 let c = -self.c * inv_det;
956 let d = self.a * inv_det;
957 let e = -(a * self.e + b * self.f);
958 let f = -(c * self.e + d * self.f);
959 Some(AffineTransform2D { a, b, c, d, e, f })
960 }
961 pub fn contractivity(&self) -> f64 {
963 (self.a * self.a + self.b * self.b + self.c * self.c + self.d * self.d).sqrt()
964 }
965}
966#[derive(Debug, Clone, PartialEq, Eq)]
968pub enum OrbitType {
969 Escaping,
971 FixedPoint,
973 Periodic(usize),
975 Bounded,
977}
978pub struct KochSnowflake;
983impl KochSnowflake {
984 #[allow(dead_code)]
986 pub fn theoretical_dimension() -> f64 {
987 (4.0_f64).ln() / (3.0_f64).ln()
988 }
989 #[allow(dead_code)]
992 pub fn generate(generations: usize, side_length: f64) -> Vec<(Point2, Point2)> {
993 let h = side_length * (3.0_f64).sqrt() / 2.0;
994 let vertices = [
995 Point2::new(0.0, 0.0),
996 Point2::new(side_length, 0.0),
997 Point2::new(side_length / 2.0, h),
998 ];
999 let mut segments = Vec::new();
1000 for i in 0..3 {
1001 let a = vertices[i];
1002 let b = vertices[(i + 1) % 3];
1003 Self::subdivide(a, b, generations, &mut segments);
1004 }
1005 segments
1006 }
1007 #[allow(dead_code)]
1009 fn subdivide(a: Point2, b: Point2, depth: usize, out: &mut Vec<(Point2, Point2)>) {
1010 if depth == 0 {
1011 out.push((a, b));
1012 return;
1013 }
1014 let dx = b.x - a.x;
1015 let dy = b.y - a.y;
1016 let p1 = Point2::new(a.x + dx / 3.0, a.y + dy / 3.0);
1017 let p3 = Point2::new(a.x + 2.0 * dx / 3.0, a.y + 2.0 * dy / 3.0);
1018 let cos60 = 0.5_f64;
1019 let sin60 = (3.0_f64).sqrt() / 2.0;
1020 let mx = dx / 3.0;
1021 let my = dy / 3.0;
1022 let apex = Point2::new(
1023 p1.x + mx * cos60 - my * sin60,
1024 p1.y + mx * sin60 + my * cos60,
1025 );
1026 Self::subdivide(a, p1, depth - 1, out);
1027 Self::subdivide(p1, apex, depth - 1, out);
1028 Self::subdivide(apex, p3, depth - 1, out);
1029 Self::subdivide(p3, b, depth - 1, out);
1030 }
1031 #[allow(dead_code)]
1033 pub fn segment_count(n: usize) -> usize {
1034 3 * 4_usize.pow(n as u32)
1035 }
1036 #[allow(dead_code)]
1038 pub fn perimeter(n: usize, side_length: f64) -> f64 {
1039 3.0 * side_length * (4.0 / 3.0_f64).powi(n as i32)
1040 }
1041 #[allow(dead_code)]
1043 pub fn area(n: usize, side_length: f64) -> f64 {
1044 let a0 = (3.0_f64).sqrt() / 4.0 * side_length * side_length;
1045 let mut area = a0;
1046 for k in 1..=n {
1047 let num_new = 3 * 4_usize.pow((k - 1) as u32);
1048 let triangle_side = side_length / 3.0_f64.powi(k as i32);
1049 let triangle_area = (3.0_f64).sqrt() / 4.0 * triangle_side * triangle_side;
1050 area += num_new as f64 * triangle_area;
1051 }
1052 area
1053 }
1054}
1055pub struct Multifractal;
1061impl Multifractal {
1062 #[allow(dead_code)]
1068 pub fn generalized_dimension(points: &[Point2], q: f64, num_scales: usize) -> (f64, f64) {
1069 if points.is_empty() || num_scales < 2 {
1070 return (0.0, 0.0);
1071 }
1072 let (min_x, max_x, min_y, max_y) = FractalDimension::bounding_box(points);
1073 let extent = (max_x - min_x).max(max_y - min_y).max(1e-15);
1074 let n_total = points.len() as f64;
1075 let mut log_eps = Vec::with_capacity(num_scales);
1076 let mut log_partition = Vec::with_capacity(num_scales);
1077 for i in 0..num_scales {
1078 let epsilon = extent / (2.0_f64).powi(i as i32 + 1);
1079 if epsilon < 1e-15 {
1080 break;
1081 }
1082 let mut box_counts: HashMap<(i64, i64), usize> = HashMap::new();
1083 for p in points {
1084 let ix = ((p.x - min_x) / epsilon).floor() as i64;
1085 let iy = ((p.y - min_y) / epsilon).floor() as i64;
1086 *box_counts.entry((ix, iy)).or_insert(0) += 1;
1087 }
1088 if (q - 1.0).abs() < 1e-10 {
1089 let mut entropy = 0.0;
1090 for &count in box_counts.values() {
1091 let pi = count as f64 / n_total;
1092 if pi > 0.0 {
1093 entropy -= pi * pi.ln();
1094 }
1095 }
1096 if entropy > 0.0 {
1097 log_eps.push(epsilon.ln());
1098 log_partition.push(entropy);
1099 }
1100 } else {
1101 let partition: f64 = box_counts
1102 .values()
1103 .map(|&count| (count as f64 / n_total).powf(q))
1104 .sum();
1105 if partition > 0.0 {
1106 log_eps.push(epsilon.ln());
1107 log_partition.push(partition.ln());
1108 }
1109 }
1110 }
1111 if log_eps.len() < 2 {
1112 return (0.0, 0.0);
1113 }
1114 let (slope, r_sq) = FractalDimension::linear_regression(&log_eps, &log_partition);
1115 if (q - 1.0).abs() < 1e-10 {
1116 (-slope, r_sq)
1117 } else {
1118 (slope / (q - 1.0), r_sq)
1119 }
1120 }
1121 #[allow(dead_code)]
1125 pub fn spectrum(points: &[Point2], q_values: &[f64], num_scales: usize) -> Vec<(f64, f64)> {
1126 q_values
1127 .iter()
1128 .map(|&q| {
1129 let (dq, _) = Self::generalized_dimension(points, q, num_scales);
1130 (q, dq)
1131 })
1132 .collect()
1133 }
1134 #[allow(dead_code)]
1141 pub fn singularity_spectrum(dq_spectrum: &[(f64, f64)]) -> Vec<(f64, f64)> {
1142 if dq_spectrum.len() < 3 {
1143 return Vec::new();
1144 }
1145 let tau: Vec<(f64, f64)> = dq_spectrum
1146 .iter()
1147 .map(|&(q, dq)| (q, (q - 1.0) * dq))
1148 .collect();
1149 let mut result = Vec::new();
1150 for i in 1..(tau.len() - 1) {
1151 let dq = tau[i + 1].0 - tau[i - 1].0;
1152 if dq.abs() < 1e-15 {
1153 continue;
1154 }
1155 let alpha = (tau[i + 1].1 - tau[i - 1].1) / dq;
1156 let f_alpha = tau[i].0 * alpha - tau[i].1;
1157 result.push((alpha, f_alpha));
1158 }
1159 result
1160 }
1161}
1162pub struct DragonCurve;
1164impl DragonCurve {
1165 pub fn lsystem() -> LSystem {
1167 LSystem::new(
1168 vec!['F', 'G', '+', '-'],
1169 vec![
1170 ProductionRule::new('F', "F+G"),
1171 ProductionRule::new('G', "F-G"),
1172 ],
1173 "F",
1174 )
1175 }
1176 pub fn generate(generations: usize, step_size: f64) -> Vec<(Point2, Point2)> {
1178 let ls = Self::lsystem();
1179 ls.turtle_interpret(generations, step_size, 90.0)
1180 }
1181}
1182pub struct BarnsleyFern;
1187impl BarnsleyFern {
1188 pub fn ifs() -> IteratedFunctionSystem {
1190 let transforms = vec![
1191 AffineTransform2D::new(0.0, 0.0, 0.0, 0.16, 0.0, 0.0),
1192 AffineTransform2D::new(0.85, 0.04, -0.04, 0.85, 0.0, 1.6),
1193 AffineTransform2D::new(0.20, -0.26, 0.23, 0.22, 0.0, 1.6),
1194 AffineTransform2D::new(-0.15, 0.28, 0.26, 0.24, 0.0, 0.44),
1195 ];
1196 let probabilities = vec![0.01, 0.85, 0.07, 0.07];
1197 IteratedFunctionSystem::new(transforms, probabilities)
1198 }
1199 pub fn generate(num_points: usize) -> Vec<Point2> {
1201 let ifs = Self::ifs();
1202 ifs.chaos_game(Point2::new(0.0, 0.0), num_points + 200, 200)
1203 }
1204}
1205#[derive(Debug, Clone, Copy, PartialEq)]
1207pub struct Point3 {
1208 pub x: f64,
1210 pub y: f64,
1212 pub z: f64,
1214}
1215impl Point3 {
1216 pub fn new(x: f64, y: f64, z: f64) -> Self {
1218 Self { x, y, z }
1219 }
1220 #[allow(dead_code)]
1222 pub fn distance(&self, other: &Point3) -> f64 {
1223 ((self.x - other.x).powi(2) + (self.y - other.y).powi(2) + (self.z - other.z).powi(2))
1224 .sqrt()
1225 }
1226}
1227#[derive(Debug, Clone)]
1233pub struct LSystem {
1234 pub alphabet: Vec<char>,
1236 pub rules: HashMap<char, String>,
1238 pub axiom: String,
1240 pub angle_deg: f64,
1242 pub step_size: f64,
1244}
1245#[derive(Debug, Clone)]
1247pub struct LSystemEvolution {
1248 pub string: String,
1250 pub generation: usize,
1252}
1253impl LSystem {
1254 pub fn new(alphabet: Vec<char>, rules: Vec<ProductionRule>, axiom: impl Into<String>) -> Self {
1256 let mut rule_map = HashMap::new();
1257 for rule in rules {
1258 rule_map.insert(rule.predecessor, rule.successor);
1259 }
1260 Self {
1261 alphabet,
1262 rules: rule_map,
1263 axiom: axiom.into(),
1264 angle_deg: 90.0,
1265 step_size: 1.0,
1266 }
1267 }
1268 pub fn koch_curve() -> Self {
1270 let mut ls = Self::new(vec!['F'], vec![ProductionRule::new('F', "F+F-F-F+F")], "F");
1271 ls.angle_deg = 90.0;
1272 ls
1273 }
1274 pub fn sierpinski() -> Self {
1276 let mut ls = Self::new(
1277 vec!['A', 'B'],
1278 vec![
1279 ProductionRule::new('A', "B-A-B"),
1280 ProductionRule::new('B', "A+B+A"),
1281 ],
1282 "A",
1283 );
1284 ls.angle_deg = 60.0;
1285 ls
1286 }
1287 pub fn dragon_curve() -> Self {
1289 let mut ls = Self::new(
1290 vec!['X', 'Y'],
1291 vec![
1292 ProductionRule::new('X', "X+YF+"),
1293 ProductionRule::new('Y', "-FX-Y"),
1294 ],
1295 "FX",
1296 );
1297 ls.angle_deg = 90.0;
1298 ls
1299 }
1300 pub fn plant_branching() -> Self {
1302 let mut ls = Self::new(
1303 vec!['X', 'F'],
1304 vec![
1305 ProductionRule::new('X', "F+[[X]-X]-F[-FX]+X"),
1306 ProductionRule::new('F', "FF"),
1307 ],
1308 "X",
1309 );
1310 ls.angle_deg = 25.0;
1311 ls
1312 }
1313 pub fn evolve(&self, n: usize) -> LSystemEvolution {
1315 LSystemEvolution {
1316 string: self.iterate(n),
1317 generation: n,
1318 }
1319 }
1320 pub fn interpret(&self, state: &LSystemEvolution) -> Vec<(Point2, Point2)> {
1322 let angle_rad = self.angle_deg * std::f64::consts::PI / 180.0;
1323 let step = self.step_size;
1324 let mut x = 0.0_f64;
1325 let mut y = 0.0_f64;
1326 let mut heading = 0.0_f64;
1327 let mut stack: Vec<(f64, f64, f64)> = Vec::new();
1328 let mut segments = Vec::new();
1329 for ch in state.string.chars() {
1330 match ch {
1331 'F' | 'G' | 'A' | 'B' => {
1332 let nx = x + step * heading.cos();
1333 let ny = y + step * heading.sin();
1334 segments.push((Point2::new(x, y), Point2::new(nx, ny)));
1335 x = nx;
1336 y = ny;
1337 }
1338 '+' => heading += angle_rad,
1339 '-' => heading -= angle_rad,
1340 '[' => stack.push((x, y, heading)),
1341 ']' => {
1342 if let Some((sx, sy, sh)) = stack.pop() {
1343 x = sx;
1344 y = sy;
1345 heading = sh;
1346 }
1347 }
1348 _ => {}
1349 }
1350 }
1351 segments
1352 }
1353 pub fn iterate(&self, n: usize) -> String {
1355 let mut current = self.axiom.clone();
1356 for _ in 0..n {
1357 let mut next = String::with_capacity(current.len() * 2);
1358 for ch in current.chars() {
1359 if let Some(replacement) = self.rules.get(&ch) {
1360 next.push_str(replacement);
1361 } else {
1362 next.push(ch);
1363 }
1364 }
1365 current = next;
1366 }
1367 current
1368 }
1369 pub fn iterate_length(&self, n: usize) -> usize {
1371 let mut lengths: HashMap<char, usize> = HashMap::new();
1372 for &ch in &self.alphabet {
1373 lengths.insert(ch, 1);
1374 }
1375 for _ in 0..n {
1376 let mut new_lengths: HashMap<char, usize> = HashMap::new();
1377 for &ch in &self.alphabet {
1378 if let Some(replacement) = self.rules.get(&ch) {
1379 let len: usize = replacement
1380 .chars()
1381 .map(|c| lengths.get(&c).copied().unwrap_or(1))
1382 .sum();
1383 new_lengths.insert(ch, len);
1384 } else {
1385 new_lengths.insert(ch, *lengths.get(&ch).unwrap_or(&1));
1386 }
1387 }
1388 lengths = new_lengths;
1389 }
1390 self.axiom
1391 .chars()
1392 .map(|c| lengths.get(&c).copied().unwrap_or(1))
1393 .sum()
1394 }
1395 pub fn turtle_interpret(
1405 &self,
1406 n: usize,
1407 step_size: f64,
1408 angle_deg: f64,
1409 ) -> Vec<(Point2, Point2)> {
1410 let string = self.iterate(n);
1411 let angle_rad = angle_deg * std::f64::consts::PI / 180.0;
1412 let mut x = 0.0_f64;
1413 let mut y = 0.0_f64;
1414 let mut heading = 0.0_f64;
1415 let mut stack: Vec<(f64, f64, f64)> = Vec::new();
1416 let mut segments = Vec::new();
1417 for ch in string.chars() {
1418 match ch {
1419 'F' | 'G' => {
1420 let nx = x + step_size * heading.cos();
1421 let ny = y + step_size * heading.sin();
1422 segments.push((Point2::new(x, y), Point2::new(nx, ny)));
1423 x = nx;
1424 y = ny;
1425 }
1426 '+' => {
1427 heading += angle_rad;
1428 }
1429 '-' => {
1430 heading -= angle_rad;
1431 }
1432 '[' => {
1433 stack.push((x, y, heading));
1434 }
1435 ']' => {
1436 if let Some((sx, sy, sh)) = stack.pop() {
1437 x = sx;
1438 y = sy;
1439 heading = sh;
1440 }
1441 }
1442 _ => {}
1443 }
1444 }
1445 segments
1446 }
1447 pub fn add_rule(&mut self, predecessor: char, successor: impl Into<String>) {
1449 let succ: String = successor.into();
1450 self.rules.insert(predecessor, succ);
1451 if !self.alphabet.contains(&predecessor) {
1452 self.alphabet.push(predecessor);
1453 }
1454 }
1455}
1456pub struct JuliaSet {
1460 pub cr: f64,
1462 pub ci: f64,
1464 pub max_iter: u32,
1466 pub escape_radius_sq: f64,
1468}
1469impl JuliaSet {
1470 pub fn new(cr: f64, ci: f64, max_iter: u32, escape_radius: f64) -> Self {
1472 Self {
1473 cr,
1474 ci,
1475 max_iter,
1476 escape_radius_sq: escape_radius * escape_radius,
1477 }
1478 }
1479 pub fn classic() -> Self {
1481 Self::new(-0.7, 0.27015, 256, 2.0)
1482 }
1483 pub fn dendrite() -> Self {
1485 Self::new(0.0, 1.0, 256, 2.0)
1486 }
1487 pub fn escape_time(&self, zr: f64, zi: f64) -> Option<u32> {
1489 let mut zr = zr;
1490 let mut zi = zi;
1491 for i in 0..self.max_iter {
1492 let zr2 = zr * zr;
1493 let zi2 = zi * zi;
1494 if zr2 + zi2 > self.escape_radius_sq {
1495 return Some(i);
1496 }
1497 let new_zi = 2.0 * zr * zi + self.ci;
1498 zr = zr2 - zi2 + self.cr;
1499 zi = new_zi;
1500 }
1501 None
1502 }
1503 pub fn is_in_set(&self, zr: f64, zi: f64) -> bool {
1505 self.escape_time(zr, zi).is_none()
1506 }
1507 pub fn classify_orbit(&self, zr: f64, zi: f64) -> OrbitType {
1509 let mut zr = zr;
1510 let mut zi = zi;
1511 let mut history_r = Vec::with_capacity(self.max_iter as usize);
1512 let mut history_i = Vec::with_capacity(self.max_iter as usize);
1513 for _ in 0..self.max_iter {
1514 let zr2 = zr * zr;
1515 let zi2 = zi * zi;
1516 if zr2 + zi2 > self.escape_radius_sq {
1517 return OrbitType::Escaping;
1518 }
1519 history_r.push(zr);
1520 history_i.push(zi);
1521 let new_zi = 2.0 * zr * zi + self.ci;
1522 zr = zr2 - zi2 + self.cr;
1523 zi = new_zi;
1524 }
1525 let n = history_r.len();
1526 if n < 2 {
1527 return OrbitType::Bounded;
1528 }
1529 let last_r = history_r[n - 1];
1530 let last_i = history_i[n - 1];
1531 for period in 1..=16.min(n - 1) {
1532 let prev_r = history_r[n - 1 - period];
1533 let prev_i = history_i[n - 1 - period];
1534 let dr = (last_r - prev_r).abs();
1535 let di = (last_i - prev_i).abs();
1536 if dr < 1e-10 && di < 1e-10 {
1537 if period == 1 {
1538 return OrbitType::FixedPoint;
1539 }
1540 return OrbitType::Periodic(period);
1541 }
1542 }
1543 OrbitType::Bounded
1544 }
1545 pub fn smooth_escape_time(&self, zr: f64, zi: f64) -> f64 {
1547 let mut zr = zr;
1548 let mut zi = zi;
1549 for i in 0..self.max_iter {
1550 let zr2 = zr * zr;
1551 let zi2 = zi * zi;
1552 if zr2 + zi2 > self.escape_radius_sq {
1553 let modulus = (zr2 + zi2).sqrt();
1554 let mu = i as f64 - modulus.ln().ln() / (2.0_f64).ln();
1555 return mu;
1556 }
1557 let new_zi = 2.0 * zr * zi + self.ci;
1558 zr = zr2 - zi2 + self.cr;
1559 zi = new_zi;
1560 }
1561 self.max_iter as f64
1562 }
1563 pub fn render_grid(
1565 &self,
1566 x_min: f64,
1567 x_max: f64,
1568 y_min: f64,
1569 y_max: f64,
1570 width: usize,
1571 height: usize,
1572 ) -> Vec<Vec<Option<u32>>> {
1573 let dx = (x_max - x_min) / width as f64;
1574 let dy = (y_max - y_min) / height as f64;
1575 (0..height)
1576 .map(|j| {
1577 let zi = y_min + (j as f64 + 0.5) * dy;
1578 (0..width)
1579 .map(|i| {
1580 let zr = x_min + (i as f64 + 0.5) * dx;
1581 self.escape_time(zr, zi)
1582 })
1583 .collect()
1584 })
1585 .collect()
1586 }
1587}
1588#[derive(Debug, Clone, Copy, PartialEq)]
1590pub struct Aabb3 {
1591 pub min: Point3,
1593 pub max: Point3,
1595}
1596impl Aabb3 {
1597 pub fn new(min: Point3, max: Point3) -> Self {
1599 Self { min, max }
1600 }
1601 #[allow(dead_code)]
1603 pub fn side(&self) -> f64 {
1604 self.max.x - self.min.x
1605 }
1606 #[allow(dead_code)]
1608 pub fn volume(&self) -> f64 {
1609 (self.max.x - self.min.x) * (self.max.y - self.min.y) * (self.max.z - self.min.z)
1610 }
1611 #[allow(dead_code)]
1613 pub fn center(&self) -> Point3 {
1614 Point3::new(
1615 (self.min.x + self.max.x) / 2.0,
1616 (self.min.y + self.max.y) / 2.0,
1617 (self.min.z + self.max.z) / 2.0,
1618 )
1619 }
1620}
1621pub struct MortonCurve;
1626impl MortonCurve {
1627 #[allow(dead_code)]
1631 pub fn encode(x: u32, y: u32) -> u64 {
1632 Self::spread_bits(x as u64) | (Self::spread_bits(y as u64) << 1)
1633 }
1634 #[allow(dead_code)]
1636 pub fn decode(code: u64) -> (u32, u32) {
1637 let x = Self::compact_bits(code) as u32;
1638 let y = Self::compact_bits(code >> 1) as u32;
1639 (x, y)
1640 }
1641 #[allow(dead_code)]
1643 fn spread_bits(mut v: u64) -> u64 {
1644 v &= 0x0000_0000_FFFF_FFFF;
1645 v = (v | (v << 16)) & 0x0000_FFFF_0000_FFFF;
1646 v = (v | (v << 8)) & 0x00FF_00FF_00FF_00FF;
1647 v = (v | (v << 4)) & 0x0F0F_0F0F_0F0F_0F0F;
1648 v = (v | (v << 2)) & 0x3333_3333_3333_3333;
1649 v = (v | (v << 1)) & 0x5555_5555_5555_5555;
1650 v
1651 }
1652 #[allow(dead_code)]
1654 fn compact_bits(mut v: u64) -> u64 {
1655 v &= 0x5555_5555_5555_5555;
1656 v = (v | (v >> 1)) & 0x3333_3333_3333_3333;
1657 v = (v | (v >> 2)) & 0x0F0F_0F0F_0F0F_0F0F;
1658 v = (v | (v >> 4)) & 0x00FF_00FF_00FF_00FF;
1659 v = (v | (v >> 8)) & 0x0000_FFFF_0000_FFFF;
1660 v = (v | (v >> 16)) & 0x0000_0000_FFFF_FFFF;
1661 v
1662 }
1663 #[allow(dead_code)]
1667 pub fn generate_path(n: u32) -> Vec<(u32, u32)> {
1668 let total = n * n;
1669 let mut pairs: Vec<(u64, u32, u32)> = Vec::with_capacity(total as usize);
1670 for y in 0..n {
1671 for x in 0..n {
1672 pairs.push((Self::encode(x, y), x, y));
1673 }
1674 }
1675 pairs.sort_by_key(|&(code, _, _)| code);
1676 pairs.iter().map(|&(_, x, y)| (x, y)).collect()
1677 }
1678 #[allow(dead_code)]
1680 pub fn encode_3d(x: u32, y: u32, z: u32) -> u64 {
1681 Self::spread_bits_3d(x as u64)
1682 | (Self::spread_bits_3d(y as u64) << 1)
1683 | (Self::spread_bits_3d(z as u64) << 2)
1684 }
1685 #[allow(dead_code)]
1687 fn spread_bits_3d(mut v: u64) -> u64 {
1688 v &= 0x001F_FFFF;
1689 v = (v | (v << 32)) & 0x001F_0000_0000_FFFF;
1690 v = (v | (v << 16)) & 0x001F_0000_FF00_00FF;
1691 v = (v | (v << 8)) & 0x100F_00F0_0F00_F00F;
1692 v = (v | (v << 4)) & 0x10C3_0C30_C30C_30C3;
1693 v = (v | (v << 2)) & 0x1249_2492_4924_9249;
1694 v
1695 }
1696}
1697#[derive(Debug, Clone, Copy, PartialEq)]
1699pub struct Point2 {
1700 pub x: f64,
1702 pub y: f64,
1704}
1705impl Point2 {
1706 pub fn new(x: f64, y: f64) -> Self {
1708 Self { x, y }
1709 }
1710 pub fn distance(&self, other: &Point2) -> f64 {
1712 ((self.x - other.x).powi(2) + (self.y - other.y).powi(2)).sqrt()
1713 }
1714 pub fn distance_sq(&self, other: &Point2) -> f64 {
1716 (self.x - other.x).powi(2) + (self.y - other.y).powi(2)
1717 }
1718}
1719pub struct MengerSponge;
1725impl MengerSponge {
1726 #[allow(dead_code)]
1728 pub fn theoretical_dimension() -> f64 {
1729 (20.0_f64).ln() / (3.0_f64).ln()
1730 }
1731 #[allow(dead_code)]
1735 pub fn generate(level: usize, origin: Point3, size: f64) -> Vec<Aabb3> {
1736 if level == 0 {
1737 return vec![Aabb3::new(
1738 origin,
1739 Point3::new(origin.x + size, origin.y + size, origin.z + size),
1740 )];
1741 }
1742 let sub = size / 3.0;
1743 let mut cubes = Vec::new();
1744 for ix in 0..3_u8 {
1745 for iy in 0..3_u8 {
1746 for iz in 0..3_u8 {
1747 let center_count = u8::from(ix == 1) + u8::from(iy == 1) + u8::from(iz == 1);
1748 if center_count >= 2 {
1749 continue;
1750 }
1751 let o = Point3::new(
1752 origin.x + ix as f64 * sub,
1753 origin.y + iy as f64 * sub,
1754 origin.z + iz as f64 * sub,
1755 );
1756 cubes.extend(Self::generate(level - 1, o, sub));
1757 }
1758 }
1759 }
1760 cubes
1761 }
1762 #[allow(dead_code)]
1764 pub fn cube_count(level: usize) -> usize {
1765 20_usize.pow(level as u32)
1766 }
1767 #[allow(dead_code)]
1769 pub fn total_volume(level: usize) -> f64 {
1770 (20.0 / 27.0_f64).powi(level as i32)
1771 }
1772}
1773pub struct KochCurve;
1778impl KochCurve {
1779 pub fn lsystem() -> LSystem {
1781 LSystem::new(
1782 vec!['F', '+', '-'],
1783 vec![ProductionRule::new('F', "F+F--F+F")],
1784 "F",
1785 )
1786 }
1787 pub fn theoretical_dimension() -> f64 {
1789 (4.0_f64).ln() / (3.0_f64).ln()
1790 }
1791 pub fn generate(generations: usize, step_size: f64) -> Vec<(Point2, Point2)> {
1793 let ls = Self::lsystem();
1794 ls.turtle_interpret(generations, step_size, 60.0)
1795 }
1796 pub fn segment_count(n: usize) -> usize {
1798 4_usize.pow(n as u32)
1799 }
1800}