1#![doc(html_root_url = "https://docs.rs/plotters-fullerene/0.1.4")]
2use plotters::prelude::*;
6use plotters::coord::Shift;
7
8use num::Float;
9
10use ph_faces::{PHF, TUV, f_to_f64};
11use ph_faces::tetra::*;
12use ph_faces::cube::*;
13use ph_faces::octa::*;
14use ph_faces::sphere::*;
15use ph_faces::cylinder::*;
16use ph_faces::capsule::*;
17use ph_faces::cone::*;
18use ph_faces::torus::*;
19use ph_faces::pipe::*;
20use ph_faces::polyhedron; use ph_faces::revolution::*;
22use fullerene::Icosahedron;
23use fullerene::{Dodecahedron, DodecahedronCenter};
24use fullerene::{C60, C60Center};
25
26#[macro_export]
28macro_rules! mk_chart {
29 ($rt: ident, $name: expr) => {{
30 let mut chart = ChartBuilder::on($rt)
31 .margin(20)
32 .caption($name, ("sans-serif", 40))
33 .build_cartesian_3d(-3.0..3.0, -3.0..3.0, -3.0..3.0)
34 .unwrap();
35 chart.with_projection(|mut pb| {
36 pb.pitch = 0.5; pb.yaw = 0.2; pb.scale = 0.7; pb.into_matrix()
40 });
41 chart.configure_axes().draw().unwrap();
42 chart
43 }}
44}
45
46pub fn lines<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
48 let mut chart = mk_chart!(rt, name);
49 chart.draw_series(
50 LineSeries::new(
51 (-100..100).map(|y| y as f64 / 100.0).map(|y|
52 ((y * 10.0).sin(), y, (y * 10.0).cos())
53 ),
54 &RED
55 )
56 ).unwrap();
57}
58
59pub fn waves<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
61 let mut chart = mk_chart!(rt, name);
62 chart.draw_series(
63 SurfaceSeries::xoz(
64 (-25..25).map(|v| v as f64 / 10.0),
65 (-25..25).map(|v| v as f64 / 10.0),
66 |x: f64, z: f64| (x * x + z * z).cos()
67 ).style(&BLUE.mix(0.2))
68 ).unwrap();
69}
70
71pub fn waves3d<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
73 let mut chart = mk_chart!(rt, name);
74 let mut d = vec![];
75 for x in (-25..25).map(|v| v as f64 / 10.0) {
76 let mut row = vec![];
77 for z in (-25..25).map(|v| v as f64 / 10.0) {
78 row.push((x, (x * x + z * z).cos(), z));
79 }
80 d.push(row);
81 }
82 chart.draw_series(
83 (0..49).map(|x| std::iter::repeat(x).zip(0..49))
84 .flatten()
85 .map(|(x, z)| {
86 Polygon::new(vec![
87 d[x][z],
88 d[x+1][z],
89 d[x+1][z+1],
90 d[x][z+1]
91 ], &BLUE.mix(0.3))
92 })
93 ).unwrap();
94}
95
96pub fn triangles<DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>, name: &str) {
98 let mut chart = mk_chart!(rt, name);
99 chart.draw_series(
100 (0..3).into_iter().flat_map(|k|
101 (0..4).into_iter().flat_map(move |j| (0..5).into_iter().map(|i|
103 Polygon::new(vec![
104 (-1.0 + k as f64, -2.0 + i as f64, -1.5 + j as f64),
105 (-1.0 + k as f64, -2.0 + i as f64, -0.5 + j as f64),
106 (k as f64, -2.0 + i as f64, -1.5 + j as f64)
107 ], &BLUE.mix(0.3)) ).collect::<Vec<_>>()
109 )
110 )
111 ).unwrap();
112}
113
114pub fn surface3d<F: Float, DB: DrawingBackend>(rt: &DrawingArea<DB, Shift>,
116 name: &str, phf: PHF<F>) {
117 let mut chart = mk_chart!(rt, name);
118 chart.draw_series(
119 phf.iter().flat_map(|f|
120 f.iter().map(|t| {
121 let vtx = t.iter().map(|v| {
122 let (p, _uv) = v.puv();
123 let fp = f_to_f64(p); (fp[0], fp[1], fp[2]) }).collect::<Vec<_>>();
126 Polygon::new(vtx, &BLUE.mix(0.3))
127 }).collect::<Vec<_>>()
128 )
129 ).unwrap();
130}
131
132pub fn create_png() {
134 let fname = "./images/polyhedron.png";
135 let rt = BitMapBackend::new(fname, (1920, 1280)).into_drawing_area();
136 rt.fill(&WHITE).unwrap();
137 let da = rt.split_evenly((4, 6));
138
139 lines(&da[0], "spiral"); waves(&da[6], "waves"); waves3d(&da[12], "waves3d"); triangles(&da[18], "triangles"); let tetra = Tetra::<f64>::new(1.0);
145 surface3d(&da[1], "Tetra", tetra.ph.with_uv(false));
146 let cube = Cube::<f64>::new(1.0);
147 surface3d(&da[2], "Cube", cube.ph.with_uv(false));
148 let cubec = CubeCenter::<f64>::new(1.0);
149 surface3d(&da[3], "CubeCenter", cubec.ph.with_uv(false));
150 let octa = Octa::<f64>::new(1.0);
151 surface3d(&da[4], "Octa", octa.ph.with_uv(false));
152
153 let revo = Revolution::<f64>::new(1.0, 9, 6, (true, true),
154 |n: u16, m: u16| -> (f64, f64) {
155 (-2.25 + 4.5 * n as f64 / m as f64, 1.0) });
157 surface3d(&da[5], "Revolution", revo.ph.with_uv(false));
158
159 let rsphere = RSphere::<f64>::new(1.0, 6);
160 surface3d(&da[7], "RSphere", rsphere.ph.with_uv(false));
161 let cylinder = Cylinder::<f64>::new(1.0, 4.0, 6);
162 surface3d(&da[8], "Cylinder", cylinder.ph.with_uv(false));
163 let capsule = Capsule::<f64>::new(1.0, 3.0, 6);
164 surface3d(&da[9], "Capsule", capsule.ph.with_uv(false));
165 let cone = Cone::<f64>::new(1.0, 4.0, 6);
166 surface3d(&da[10], "Cone", cone.ph.with_uv(false));
167
168 let q = 9;
169 let s = q * 2 + 1;
170 let tbl = (0..s).into_iter().map(|sn| { (-2.25 + 4.5 * sn as f64 / (s - 1) as f64, 1.0)
172 }).collect::<Vec<_>>();
173 let revo_tbl = Revolution::<f64>::from_tbl(1.0, q, 6, (true, true), &tbl);
174 surface3d(&da[11], "Revo Table", revo_tbl.ph.with_uv(false));
175
176 let torus24 = Torus::<f64>::new(2.0, 0.8, 6, 6);
177 surface3d(&da[13], "Torus24", torus24.ph.with_uv(false));
178let ring24 = Ring::<f64>::new(2.0, 0.1, 0.8, 12, 6);
183 surface3d(&da[14], "Ring24", ring24.ph.with_uv(false));
184 let tube = Tube::<f64>::new(2.0, 1.6, 4.0, 6);
185 surface3d(&da[15], "Tube", tube.ph.with_uv(false));
186 let halfpipe = HalfPipe::<f64>::new(4.712388980, 2.4, 2.0, 4.0, 6); surface3d(&da[16], "HalfPipe", halfpipe.ph.with_uv(false));
188 let pin = polyhedron::pin::Pin::<f64>::new(0.4, 8, 6);
189 surface3d(&da[17], "Pin", pin.ph.with_uv(false));
190
191 let icosa = Icosahedron::<f64>::new(1.0);
192 surface3d(&da[19], "Icosahedron", icosa.ph.with_uv(false));
193 let dodeca = Dodecahedron::<f64>::new(1.0);
194 surface3d(&da[20], "Dodecahedron", dodeca.ph.with_uv(false));
195 let dodecac = DodecahedronCenter::<f64>::new(1.0);
196 surface3d(&da[21], "DodecahedronCenter", dodecac.ph.with_uv(false));
197 let c60 = C60::<f64>::new(1.0);
198 surface3d(&da[22], "C60", c60.ph.with_uv(false));
199 let c60c = C60Center::<f64>::new(1.0);
200 surface3d(&da[23], "C60Center", c60c.ph.with_uv(false));
201}
202
203#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
210 fn test_plot() {
211 assert_eq!(create_png(), ());
212 }
213}