plt_fullerene/
lib.rs

1#![doc(html_root_url = "https://docs.rs/plotters-fullerene/0.1.4")]
2//! plotters fullerene and polyhedron for Rust
3//!
4
5use 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; // polyhedron::pin::Pin
21use ph_faces::revolution::*;
22use fullerene::Icosahedron;
23use fullerene::{Dodecahedron, DodecahedronCenter};
24use fullerene::{C60, C60Center};
25
26/// mk chart
27#[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; // 0.7; // 1.2;
37      pb.yaw = 0.2; // 0.7; // 0.5;
38      pb.scale = 0.7; // 0.7;
39      pb.into_matrix()
40    });
41    chart.configure_axes().draw().unwrap();
42    chart
43  }}
44}
45
46/// lines
47pub 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
59/// waves mesh
60pub 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
71/// waves3d quad polygons
72pub 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
96/// triangles
97pub 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| // move for borrow k
102        (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)) // must be vec of tuple
108        ).collect::<Vec<_>>()
109      )
110    )
111  ).unwrap();
112}
113
114/// surface3d
115pub 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); // expected f64
124          (fp[0], fp[1], fp[2]) // must be vec of tuple
125        }).collect::<Vec<_>>();
126        Polygon::new(vtx, &BLUE.mix(0.3))
127      }).collect::<Vec<_>>()
128    )
129  ).unwrap();
130}
131
132/// create_png
133pub 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"); // dummy
140  waves(&da[6], "waves"); // dummy
141  waves3d(&da[12], "waves3d"); // dummy
142  triangles(&da[18], "triangles"); // dummy
143
144  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) // -2.25 to 2.125 (q = 9, m = 36)
156  });
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 to 2.25 (q = 9)
171    (-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));
178/*
179  let rtorus24 = RTorus::<f64>::new(2.0, 0.8, 12, 6);
180  surface3d(&da[14], "RTorus24", rtorus24.ph.with_uv(false));
181*/
182  let 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); // 3pi/2
187  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/// tests
204#[cfg(test)]
205mod tests {
206  use super::*;
207
208  /// [-- --nocapture] [-- --show-output]
209  #[test]
210  fn test_plot() {
211    assert_eq!(create_png(), ());
212  }
213}