#![doc(html_root_url = "https://docs.rs/Fullerene/0.1.6")]
pub mod c60;
pub mod dodecahedron;
pub mod icosahedron;
pub use c60::{C60, C60Center};
pub use dodecahedron::{Dodecahedron, DodecahedronCenter};
pub use icosahedron::Icosahedron;
use num::Float;
pub fn sum_f3<F: Float>(vs: &Vec<[F; 3]>) -> Vec<F> {
vs.iter().fold(vec![<F>::from(0).unwrap(); 3], |s, p|
s.iter().zip(p.iter()).map(|(&q, &p)| q + p).collect())
}
pub fn avg_f3<F: Float>(vs: &Vec<[F; 3]>) -> Vec<F> {
let n = <F>::from(vs.len()).unwrap();
sum_f3(vs).iter().map(|&v| v / n).collect()
}
pub fn center_indexed<F: Float>(idx: &[u8], vtx: &Vec<[F; 3]>) -> [F; 3] {
let p = avg_f3(&idx.iter().map(|&i| vtx[i as usize]).collect());
p.as_slice().try_into().unwrap()
}
pub fn divide_int<F: Float>(p: &[F; 3], q: &[F; 3], m: i32, n: i32) -> [F; 3] {
let mf = <F>::from(m).unwrap();
let nf = <F>::from(n).unwrap();
let sf = mf + nf;
p.iter().zip(q.iter()).map(|(&a, &b)|
(nf * a + mf * b) / sf).collect::<Vec<_>>().as_slice().try_into().unwrap()
}
pub fn divide_ext<F: Float>(p: &[F; 3], q: &[F; 3], m: i32, n: i32) -> [F; 3] {
divide_int(p, q, m, -n)
}
pub fn f_to_f32<F: Float>(v: &[F]) -> Vec<f32> {
v.iter().map(|i| i.to_f32().unwrap()).collect()
}
pub fn f_to_f64<F: Float>(v: &[F]) -> Vec<f64> {
v.iter().map(|i| i.to_f64().unwrap()).collect()
}
pub type PHF<F> = Vec<Vec<Vec<([F; 3], [F; 2])>>>;
pub trait TUV<F: Float> {
fn get_uv_f(&self, n: usize, i: usize, k: usize, c: bool,
r: f64, s: f64, o: [f64; 2]) -> [F; 2] { if c && k == 0 { [<F>::from(o[0] + 0.5).unwrap(), <F>::from(o[1] + 0.5).unwrap()]
} else {
let (m, j) = match c {
true => (n, (i + k - 1) % n), false => (n + 2, if k == 0 { 0 } else { i + k }) };
let t = 2.0 * std::f64::consts::PI * j as f64 / m as f64 + r;
let uv = [(1.0 + s * t.cos()) / 2.0, 1.0 - (1.0 + s * t.sin()) / 2.0];
[<F>::from(o[0] + uv[0]).unwrap(), <F>::from(o[1] + uv[1]).unwrap()]
}
}
fn get_uv_t(&self, f: usize, v: usize, i: usize,
r: f64, s: f64, o: [f64; 2]) -> [F; 2]; fn ref_vtx(&self) -> &Vec<[F; 3]>;
fn ref_tri(&self) -> &Vec<Vec<[u8; 3]>>;
fn with_uv(&self, tf: bool) -> PHF<F>;
fn phf(&self, tf: bool, c: bool) -> PHF<F> {
self.ref_tri().iter().enumerate().map(|(fi, f)|
f.iter().enumerate().map(|(vi, v)|
v.iter().enumerate().map(|(ii, &i)| {
self.gen_uv(i as usize, tf, fi, f.len(), vi, ii, c)
}).collect()
).collect()
).collect()
}
fn gen_uv(&self, i: usize, tf: bool,
fi: usize, n: usize, vi: usize, ii: usize, c: bool) -> ([F; 3], [F; 2]) {
let r = std::f64::consts::PI / 2.0; let s = 1.0f64; let o = [0.0f64, 0.0f64]; let p = self.ref_vtx()[i];
let uv = match tf {
true => self.get_uv_t(fi, vi, ii, 0.0f64, s, o), false => self.get_uv_f(n, vi, ii, c, r, s, o) };
(p, uv)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icosahedron() {
let icosa32 = Icosahedron::new(1.0f32);
assert_eq!(icosa32.tri.len(), 20);
assert_eq!(icosa32.vtx.len(), 12);
let s32 = format!("{:?}", icosa32.vtx[0]);
println!("{}", s32);
assert_eq!(s32, "[0.0, -1.0, -1.618034]");
let icosa64 = Icosahedron::new(1.0f64);
assert_eq!(icosa64.tri.len(), 20);
assert_eq!(icosa64.vtx.len(), 12);
let s64 = format!("{:?}", icosa64.vtx[0]);
println!("{}", s64);
assert_eq!(s64, "[0.0, -1.0, -1.618033988749895]");
}
#[test]
fn test_dodecahedron() {
let dodeca32 = Dodecahedron::<f32>::new(1.0f32);
assert_eq!(dodeca32.tri.len(), 12); assert_eq!(dodeca32.vtx.len(), 20);
let dodeca64 = Dodecahedron::<f64>::new(1.0f64);
assert_eq!(dodeca64.tri.len(), 12); assert_eq!(dodeca64.vtx.len(), 20);
}
#[test]
fn test_dodecahedron_center() {
let dodeca32_center = DodecahedronCenter::new(1.0f32);
assert_eq!(dodeca32_center.tri.len(), 12); assert_eq!(dodeca32_center.vtx.len(), 32); let dodeca64_center = DodecahedronCenter::new(1.0f64);
assert_eq!(dodeca64_center.tri.len(), 12); assert_eq!(dodeca64_center.vtx.len(), 32);
let mt = [
[[20, 0, 4], [20, 4, 3], [20, 3, 2], [20, 2, 1], [20, 1, 0]], [[21, 4, 0], [21, 0, 7], [21, 7, 6], [21, 6, 5], [21, 5, 4]], [[22, 0, 1], [22, 1, 9], [22, 9, 8], [22, 8, 7], [22, 7, 0]], [[23, 1, 2], [23, 2, 11], [23, 11, 10], [23, 10, 9], [23, 9, 1]], [[24, 2, 3], [24, 3, 13], [24, 13, 12], [24, 12, 11], [24, 11, 2]], [[25, 3, 4], [25, 4, 5], [25, 5, 14], [25, 14, 13], [25, 13, 3]], [[26, 15, 14], [26, 14, 5], [26, 5, 6], [26, 6, 16], [26, 16, 15]], [[27, 16, 6], [27, 6, 7], [27, 7, 8], [27, 8, 17], [27, 17, 16]], [[28, 17, 8], [28, 8, 9], [28, 9, 10], [28, 10, 18], [28, 18, 17]], [[29, 18, 10], [29, 10, 11], [29, 11, 12], [29, 12, 19], [29, 19, 18]], [[30, 19, 12], [30, 12, 13], [30, 13, 14], [30, 14, 15], [30, 15, 19]], [[31, 19, 15], [31, 15, 16], [31, 16, 17], [31, 17, 18], [31, 18, 19]] ];
assert_eq!(dodeca32_center.tri, mt);
assert_eq!(dodeca64_center.tri, mt);
}
#[test]
fn test_fullerene() {
let c60_32 = C60::<f32>::new(1.0f32);
assert_eq!(c60_32.tri.len(), 32); assert_eq!(c60_32.vtx.len(), 60);
let c60_64 = C60::<f64>::new(1.0f64);
assert_eq!(c60_64.tri.len(), 32); assert_eq!(c60_64.vtx.len(), 60);
}
#[test]
fn test_fullerene_center() {
let c60_32_center = C60Center::new(1.0f32);
assert_eq!(c60_32_center.tri.len(), 32); assert_eq!(c60_32_center.vtx.len(), 92); let c60_64_center = C60Center::new(1.0f64);
assert_eq!(c60_64_center.tri.len(), 32); assert_eq!(c60_64_center.vtx.len(), 92); }
}