#![doc(html_root_url = "https://docs.rs/plotters-fullerene/0.1.4")]
use plotters::prelude::*;
use plotters::coord::Shift;
use num::Float;
use ph_faces::{PHF, TUV, f_to_f64};
use ph_faces::tetra::*;
use ph_faces::cube::*;
use ph_faces::octa::*;
use ph_faces::sphere::*;
use ph_faces::cylinder::*;
use ph_faces::capsule::*;
use ph_faces::cone::*;
use ph_faces::torus::*;
use ph_faces::pipe::*;
use ph_faces::polyhedron; use ph_faces::revolution::*;
use fullerene::Icosahedron;
use fullerene::{Dodecahedron, DodecahedronCenter};
use fullerene::{C60, C60Center};
#[macro_export]
macro_rules! mk_chart {
($rt: ident, $name: expr) => {{
let mut chart = ChartBuilder::on($rt)
.margin(20)
.caption($name, ("sans-serif", 40))
.build_cartesian_3d(-3.0..3.0, -3.0..3.0, -3.0..3.0)
.unwrap();
chart.with_projection(|mut pb| {
pb.pitch = 0.5; pb.yaw = 0.2; pb.scale = 0.7; pb.into_matrix()
});
chart.configure_axes().draw().unwrap();
chart
}}
}
pub fn lines<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
let mut chart = mk_chart!(rt, name);
chart.draw_series(
LineSeries::new(
(-100..100).map(|y| y as f64 / 100.0).map(|y|
((y * 10.0).sin(), y, (y * 10.0).cos())
),
&RED
)
).unwrap();
}
pub fn waves<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
let mut chart = mk_chart!(rt, name);
chart.draw_series(
SurfaceSeries::xoz(
(-25..25).map(|v| v as f64 / 10.0),
(-25..25).map(|v| v as f64 / 10.0),
|x: f64, z: f64| (x * x + z * z).cos()
).style(&BLUE.mix(0.2))
).unwrap();
}
pub fn waves3d<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
let mut chart = mk_chart!(rt, name);
let mut d = vec![];
for x in (-25..25).map(|v| v as f64 / 10.0) {
let mut row = vec![];
for z in (-25..25).map(|v| v as f64 / 10.0) {
row.push((x, (x * x + z * z).cos(), z));
}
d.push(row);
}
chart.draw_series(
(0..49).map(|x| std::iter::repeat(x).zip(0..49))
.flatten()
.map(|(x, z)| {
Polygon::new(vec![
d[x][z],
d[x+1][z],
d[x+1][z+1],
d[x][z+1]
], &BLUE.mix(0.3))
})
).unwrap();
}
pub fn triangles<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
let mut chart = mk_chart!(rt, name);
chart.draw_series(
(0..3).into_iter().flat_map(|k|
(0..4).into_iter().flat_map(move |j| (0..5).into_iter().map(|i|
Polygon::new(vec![
(-1.0 + k as f64, -2.0 + i as f64, -1.5 + j as f64),
(-1.0 + k as f64, -2.0 + i as f64, -0.5 + j as f64),
(k as f64, -2.0 + i as f64, -1.5 + j as f64)
], &BLUE.mix(0.3)) ).collect::<Vec<_>>()
)
)
).unwrap();
}
pub fn surface3d<F: Float, DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>,
name: &str, phf: PHF<F>) {
let mut chart = mk_chart!(rt, name);
chart.draw_series(
phf.iter().flat_map(|f|
f.iter().map(|t| {
let vtx = t.iter().map(|v| {
let (p, _uv) = v.puv();
let fp = f_to_f64(p); (fp[0], fp[1], fp[2]) }).collect::<Vec<_>>();
Polygon::new(vtx, &BLUE.mix(0.3))
}).collect::<Vec<_>>()
)
).unwrap();
}
pub fn create_png() {
let fname = "./images/polyhedron.png";
let rt = BitMapBackend::new(fname, (1920, 1280)).into_drawing_area();
rt.fill(&WHITE).unwrap();
let da = rt.split_evenly((4, 6));
lines(&da[0], "spiral"); waves(&da[6], "waves"); waves3d(&da[12], "waves3d"); triangles(&da[18], "triangles");
let tetra = Tetra::<f64>::new(1.0);
surface3d(&da[1], "Tetra", tetra.ph.with_uv(false));
let cube = Cube::<f64>::new(1.0);
surface3d(&da[2], "Cube", cube.ph.with_uv(false));
let cubec = CubeCenter::<f64>::new(1.0);
surface3d(&da[3], "CubeCenter", cubec.ph.with_uv(false));
let octa = Octa::<f64>::new(1.0);
surface3d(&da[4], "Octa", octa.ph.with_uv(false));
let revo = Revolution::<f64>::new(1.0, 9, 6, (true, true),
|n: u16, m: u16| -> (f64, f64) {
(-2.25 + 4.5 * n as f64 / m as f64, 1.0) });
surface3d(&da[5], "Revolution", revo.ph.with_uv(false));
let rsphere = RSphere::<f64>::new(1.0, 6);
surface3d(&da[7], "RSphere", rsphere.ph.with_uv(false));
let cylinder = Cylinder::<f64>::new(1.0, 4.0, 6);
surface3d(&da[8], "Cylinder", cylinder.ph.with_uv(false));
let capsule = Capsule::<f64>::new(1.0, 3.0, 6);
surface3d(&da[9], "Capsule", capsule.ph.with_uv(false));
let cone = Cone::<f64>::new(1.0, 4.0, 6);
surface3d(&da[10], "Cone", cone.ph.with_uv(false));
let q = 9;
let s = q * 2 + 1;
let tbl = (0..s).into_iter().map(|sn| { (-2.25 + 4.5 * sn as f64 / (s - 1) as f64, 1.0)
}).collect::<Vec<_>>();
let revo_tbl = Revolution::<f64>::from_tbl(1.0, q, 6, (true, true), &tbl);
surface3d(&da[11], "Revo Table", revo_tbl.ph.with_uv(false));
let torus24 = Torus::<f64>::new(2.0, 0.8, 6, 6);
surface3d(&da[13], "Torus24", torus24.ph.with_uv(false));
let ring24 = Ring::<f64>::new(2.0, 0.1, 0.8, 12, 6);
surface3d(&da[14], "Ring24", ring24.ph.with_uv(false));
let tube = Tube::<f64>::new(2.0, 1.6, 4.0, 6);
surface3d(&da[15], "Tube", tube.ph.with_uv(false));
let halfpipe = HalfPipe::<f64>::new(4.712388980, 2.4, 2.0, 4.0, 6); surface3d(&da[16], "HalfPipe", halfpipe.ph.with_uv(false));
let pin = polyhedron::pin::Pin::<f64>::new(0.4, 8, 6);
surface3d(&da[17], "Pin", pin.ph.with_uv(false));
let icosa = Icosahedron::<f64>::new(1.0);
surface3d(&da[19], "Icosahedron", icosa.ph.with_uv(false));
let dodeca = Dodecahedron::<f64>::new(1.0);
surface3d(&da[20], "Dodecahedron", dodeca.ph.with_uv(false));
let dodecac = DodecahedronCenter::<f64>::new(1.0);
surface3d(&da[21], "DodecahedronCenter", dodecac.ph.with_uv(false));
let c60 = C60::<f64>::new(1.0);
surface3d(&da[22], "C60", c60.ph.with_uv(false));
let c60c = C60Center::<f64>::new(1.0);
surface3d(&da[23], "C60Center", c60c.ph.with_uv(false));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_plot() {
assert_eq!(create_png(), ());
}
}