ncollide3d/procedural/path/
arrowhead_cap.rs

1use crate::procedural::path::PolylineCompatibleCap;
2use crate::procedural::utils;
3use na::{self, Isometry3, Point3, Vector3};
4use simba::scalar::RealField;
5
6/// A cap that looks like an arrow.
7pub struct ArrowheadCap<N> {
8    radius_scale: N,
9    front_dist_to_head: N,
10    back_dist_to_head: N,
11}
12
13impl<N: RealField + Copy> ArrowheadCap<N> {
14    /// Creates a cap that looks like an arrow.
15    ///
16    /// # Arguments:
17    /// * `radius_scale` - scale factor of the cap base.
18    /// * `front_dist_to_head` - distance from the path endpoint and the arrow tip.
19    /// * `back_dist_to_head` - distance from the path endpoint and the cap base.
20    pub fn new(radius_scale: N, front_dist_to_head: N, back_dist_to_head: N) -> ArrowheadCap<N> {
21        ArrowheadCap {
22            radius_scale: radius_scale,
23            front_dist_to_head: front_dist_to_head,
24            back_dist_to_head: back_dist_to_head,
25        }
26    }
27
28    fn do_gen_cap(
29        &self,
30        attach_id: u32,
31        pattern: &[Point3<N>],
32        pt: &Point3<N>,
33        dir: &Vector3<N>,
34        closed: bool,
35        negative_shifts: bool,
36        coords: &mut Vec<Point3<N>>,
37        indices: &mut Vec<Point3<u32>>,
38    ) {
39        let front_dist_to_head = if negative_shifts {
40            -self.front_dist_to_head
41        } else {
42            self.front_dist_to_head
43        };
44        let back_dist_to_head = if negative_shifts {
45            -self.back_dist_to_head
46        } else {
47            self.back_dist_to_head
48        };
49        let pointy_thing = *pt + *dir * front_dist_to_head;
50        let start_id = coords.len() as u32;
51        let npts = pattern.len() as u32;
52        let mut attach_id = attach_id;
53
54        if !(self.radius_scale == na::convert(1.0)) || !back_dist_to_head.is_zero() {
55            let mut new_pattern: Vec<Point3<N>> =
56                pattern.iter().map(|p| p * self.radius_scale).collect();
57
58            // NOTE: this is done exactly the same on the PolylinePattern::stroke method.
59            // Refactor?
60            let transform;
61            let back_shift = *dir * back_dist_to_head;
62
63            if dir.x.is_zero() && dir.z.is_zero() {
64                // FIXME: this might not be enough to avoid singularities.
65                transform =
66                    Isometry3::face_towards(&(*pt - back_shift), &(*pt + *dir), &Vector3::x());
67            } else {
68                transform =
69                    Isometry3::face_towards(&(*pt - back_shift), &(*pt + *dir), &Vector3::y());
70            }
71
72            for p in &mut new_pattern {
73                *p = transform * &*p
74            }
75
76            coords.extend(new_pattern.into_iter());
77
78            if closed {
79                utils::push_ring_indices(attach_id, start_id, npts, indices)
80            } else {
81                utils::push_open_ring_indices(attach_id, start_id, npts, indices)
82            }
83
84            attach_id = start_id;
85        }
86
87        if closed {
88            utils::push_degenerate_top_ring_indices(attach_id, coords.len() as u32, npts, indices);
89        } else {
90            utils::push_degenerate_open_top_ring_indices(
91                attach_id,
92                coords.len() as u32,
93                npts,
94                indices,
95            );
96        }
97
98        coords.push(pointy_thing);
99    }
100}
101
102impl<N: RealField + Copy> PolylineCompatibleCap<N> for ArrowheadCap<N> {
103    fn gen_end_cap(
104        &self,
105        attach_id: u32,
106        pattern: &[Point3<N>],
107        pt: &Point3<N>,
108        dir: &Vector3<N>,
109        closed: bool,
110        coords: &mut Vec<Point3<N>>,
111        indices: &mut Vec<Point3<u32>>,
112    ) {
113        let start_indices_id = indices.len();
114
115        self.do_gen_cap(attach_id, pattern, pt, dir, closed, false, coords, indices);
116        utils::reverse_clockwising(&mut indices[start_indices_id..])
117    }
118
119    fn gen_start_cap(
120        &self,
121        attach_id: u32,
122        pattern: &[Point3<N>],
123        pt: &Point3<N>,
124        dir: &Vector3<N>,
125        closed: bool,
126        coords: &mut Vec<Point3<N>>,
127        indices: &mut Vec<Point3<u32>>,
128    ) {
129        self.do_gen_cap(attach_id, pattern, pt, dir, closed, true, coords, indices)
130    }
131}