1use serde::{Deserialize, Serialize};
2
3use num::complex::Complex64;
4
5use log::{log_enabled, Level};
6
7use num::cast;
8
9use std::sync::atomic::{AtomicU64, Ordering};
10
11pub mod coloring;
12pub mod frame;
13pub mod gradient;
14pub mod post_processing;
15pub mod sampler;
16pub mod viewport;
17
18#[derive(Serialize, Deserialize, Clone, Copy)]
26#[serde(untagged)]
27pub enum ComplexNumber {
28 Cartesian { re: f64, im: f64 },
29 Polar { r: f64, theta: f64 },
30}
31
32impl From<&ComplexNumber> for Complex64 {
33 fn from(cn: &ComplexNumber) -> Self {
34 match cn {
35 ComplexNumber::Cartesian { re, im } => Self::new(*re, *im),
36 ComplexNumber::Polar { r, theta } => {
37 Self::from_polar(*r, *theta)
38 }
39 }
40 }
41}
42
43impl From<ComplexNumber> for Complex64 {
44 fn from(cn: ComplexNumber) -> Self {
45 Self::from(&cn)
46 }
47}
48
49#[must_use]
53pub fn finite_attractor(
54 z0: Complex64,
55 c: Complex64,
56 p: usize,
57) -> Option<(Complex64, Complex64)> {
58 let mut zz = z0;
59
60 for _ in 0..64 {
61 let mut z = zz;
62 let mut dz = Complex64::new(1., 0.);
63
64 for _ in 0..p {
65 dz = 2. * z * dz;
66 z = z.powi(2) + c;
67 }
68
69 let zz_new = zz - (z - zz) / (dz - 1.);
70
71 if (zz_new - zz).norm_sqr() <= 1e-20 {
72 return Some((z, dz));
73 }
74
75 zz = zz_new;
76 }
77
78 None
79}
80
81pub enum ProgressPrinter {
85 Info(InfoProgressPrinter),
86 Disabled,
87}
88
89impl ProgressPrinter {
90 #[must_use]
91 pub fn new(n: u64, interval: u64) -> Self {
92 if log_enabled!(Level::Info) {
93 Self::Info(InfoProgressPrinter::new(n, interval))
94 } else {
95 Self::Disabled
96 }
97 }
98
99 pub fn increment(&self) {
100 if let Self::Info(info) = self {
101 info.increment();
102 }
103 }
104}
105
106pub struct InfoProgressPrinter {
107 counter: AtomicU64,
108 n: u64,
109 n_f64: f64,
110 interval: u64,
111}
112
113impl InfoProgressPrinter {
114 #[must_use]
121 pub fn new(n: u64, interval: u64) -> Self {
122 Self {
123 counter: AtomicU64::new(0),
124 n,
125 n_f64: cast::<_, f64>(n).unwrap(),
126 interval,
127 }
128 }
129
130 pub fn increment(&self) {
138 let i = self.counter.fetch_add(1, Ordering::SeqCst);
139
140 if i % self.interval == self.interval - 1 || i == self.n - 1 {
141 let p = cast::<_, f64>(i).unwrap() / self.n_f64 * 100.;
142 print!("{}/{} iterations done ({:.2}%)\r", i + 1, self.n, p);
143 }
144 }
145}