ncollide3d/procedural/
cylinder.rs

1use super::utils;
2use super::{IndexBuffer, TriMesh};
3use na;
4use na::{Point2, Vector3};
5use simba::scalar::RealField;
6
7/// Generates a cylinder with a given height and diameter.
8pub fn cylinder<N: RealField + Copy>(diameter: N, height: N, nsubdiv: u32) -> TriMesh<N> {
9    let mut cylinder = unit_cylinder(nsubdiv);
10
11    cylinder.scale_by(&Vector3::new(diameter, height, diameter));
12
13    cylinder
14}
15
16/// Generates a cylinder with unit height and diameter.
17pub fn unit_cylinder<N: RealField + Copy>(nsubdiv: u32) -> TriMesh<N> {
18    let two_pi = N::two_pi();
19    let invsubdiv = na::one::<N>() / na::convert(nsubdiv as f64);
20    let dtheta = two_pi * invsubdiv;
21    let mut coords = Vec::new();
22    let mut indices = Vec::new();
23    let mut normals: Vec<Vector3<N>>;
24
25    utils::push_circle(
26        na::convert(0.5),
27        nsubdiv,
28        dtheta,
29        na::convert(-0.5),
30        &mut coords,
31    );
32
33    normals = coords.iter().map(|p| p.coords).collect();
34
35    utils::push_circle(
36        na::convert(0.5),
37        nsubdiv,
38        dtheta,
39        na::convert(0.5),
40        &mut coords,
41    );
42
43    utils::push_ring_indices(0, nsubdiv, nsubdiv, &mut indices);
44    utils::push_filled_circle_indices(0, nsubdiv, &mut indices);
45    utils::push_filled_circle_indices(nsubdiv, nsubdiv, &mut indices);
46
47    let len = indices.len();
48    let bottom_start_id = len - (nsubdiv as usize - 2);
49    utils::reverse_clockwising(&mut indices[bottom_start_id..]);
50
51    let mut indices = utils::split_index_buffer(&indices[..]);
52
53    /*
54     * Compute uvs.
55     */
56    // bottom ring uvs
57    let mut uvs = Vec::with_capacity(coords.len());
58    let mut curr_u = N::zero();
59    for _ in 0..nsubdiv {
60        uvs.push(Point2::new(curr_u, na::zero()));
61        curr_u = curr_u + invsubdiv;
62    }
63
64    // top ring uvs
65    curr_u = na::zero();
66    for _ in 0..nsubdiv {
67        uvs.push(Point2::new(curr_u, na::one()));
68        curr_u = curr_u + invsubdiv;
69    }
70
71    /*
72     * Adjust normals.
73     */
74    for n in normals.iter_mut() {
75        n.x = n.x * na::convert(2.0);
76        n.y = na::zero();
77        n.z = n.z * na::convert(2.0);
78    }
79
80    normals.push(Vector3::y()); // top cap
81    normals.push(-Vector3::y()); // bottom cap
82    let nlen = normals.len() as u32;
83
84    let top_start_id = len - 2 * (nsubdiv as usize - 2);
85
86    for i in indices[..top_start_id].iter_mut() {
87        if i.x.y >= nsubdiv {
88            i.x.y = i.x.y - nsubdiv;
89        }
90        if i.y.y >= nsubdiv {
91            i.y.y = i.y.y - nsubdiv;
92        }
93        if i.z.y >= nsubdiv {
94            i.z.y = i.z.y - nsubdiv;
95        }
96    }
97
98    for i in indices[top_start_id..bottom_start_id].iter_mut() {
99        i.x.y = nlen - 2;
100        i.y.y = nlen - 2;
101        i.z.y = nlen - 2;
102    }
103
104    for i in indices[bottom_start_id..].iter_mut() {
105        i.x.y = nlen - 1;
106        i.y.y = nlen - 1;
107        i.z.y = nlen - 1;
108    }
109
110    TriMesh::new(
111        coords,
112        Some(normals),
113        Some(uvs),
114        Some(IndexBuffer::Split(indices)),
115    )
116}