use serde::{Deserialize, Serialize};
use num::complex::Complex64;
use log::{log_enabled, Level};
use num::cast;
use std::sync::atomic::{AtomicU64, Ordering};
pub mod coloring;
pub mod frame;
pub mod gradient;
pub mod post_processing;
pub mod sampler;
pub mod viewport;
#[derive(Serialize, Deserialize, Clone, Copy)]
#[serde(untagged)]
pub enum ComplexNumber {
Cartesian { re: f64, im: f64 },
Polar { r: f64, theta: f64 },
}
impl From<&ComplexNumber> for Complex64 {
fn from(cn: &ComplexNumber) -> Self {
match cn {
ComplexNumber::Cartesian { re, im } => Self::new(*re, *im),
ComplexNumber::Polar { r, theta } => {
Self::from_polar(*r, *theta)
}
}
}
}
impl From<ComplexNumber> for Complex64 {
fn from(cn: ComplexNumber) -> Self {
Self::from(&cn)
}
}
#[must_use]
pub fn finite_attractor(
z0: Complex64,
c: Complex64,
p: usize,
) -> Option<(Complex64, Complex64)> {
let mut zz = z0;
for _ in 0..64 {
let mut z = zz;
let mut dz = Complex64::new(1., 0.);
for _ in 0..p {
dz = 2. * z * dz;
z = z.powi(2) + c;
}
let zz_new = zz - (z - zz) / (dz - 1.);
if (zz_new - zz).norm_sqr() <= 1e-20 {
return Some((z, dz));
}
zz = zz_new;
}
None
}
pub enum ProgressPrinter {
Info(InfoProgressPrinter),
Disabled,
}
impl ProgressPrinter {
#[must_use]
pub fn new(n: u64, interval: u64) -> Self {
if log_enabled!(Level::Info) {
Self::Info(InfoProgressPrinter::new(n, interval))
} else {
Self::Disabled
}
}
pub fn increment(&self) {
if let Self::Info(info) = self {
info.increment();
}
}
}
pub struct InfoProgressPrinter {
counter: AtomicU64,
n: u64,
n_f64: f64,
interval: u64,
}
impl InfoProgressPrinter {
#[must_use]
pub fn new(n: u64, interval: u64) -> Self {
Self {
counter: AtomicU64::new(0),
n,
n_f64: cast::<_, f64>(n).unwrap(),
interval,
}
}
pub fn increment(&self) {
let i = self.counter.fetch_add(1, Ordering::SeqCst);
if i % self.interval == self.interval - 1 || i == self.n - 1 {
let p = cast::<_, f64>(i).unwrap() / self.n_f64 * 100.;
print!("{}/{} iterations done ({:.2}%)\r", i + 1, self.n, p);
}
}
}