ncollide3d/procedural/path/
polyline_pattern.rs
1use crate::procedural::path::{CurveSampler, PathSample, StrokePattern};
2use crate::procedural::trimesh::{IndexBuffer, TriMesh};
3use crate::procedural::utils;
4use na::{self, Isometry3, Point2, Point3, RealField, Vector3};
5
6pub struct PolylinePattern<N: RealField + Copy, C1, C2> {
8 pattern: Vec<Point3<N>>,
9 closed: bool,
10 last_start_id: u32,
11 start_cap: C1,
12 end_cap: C2,
13}
14
15pub trait PolylineCompatibleCap<N: RealField + Copy> {
17 fn gen_start_cap(
19 &self,
20 attach_id: u32,
21 pattern: &[Point3<N>],
22 pt: &Point3<N>,
23 dir: &Vector3<N>,
24 closed: bool,
25 coords: &mut Vec<Point3<N>>,
26 indices: &mut Vec<Point3<u32>>,
27 );
28
29 fn gen_end_cap(
31 &self,
32 attach_id: u32,
33 pattern: &[Point3<N>],
34 pt: &Point3<N>,
35 dir: &Vector3<N>,
36 closed: bool,
37 coords: &mut Vec<Point3<N>>,
38 indices: &mut Vec<Point3<u32>>,
39 );
40}
41
42impl<N, C1, C2> PolylinePattern<N, C1, C2>
43where
44 N: RealField + Copy,
45 C1: PolylineCompatibleCap<N>,
46 C2: PolylineCompatibleCap<N>,
47{
48 pub fn new(
50 pattern: &[Point2<N>],
51 closed: bool,
52 start_cap: C1,
53 end_cap: C2,
54 ) -> PolylinePattern<N, C1, C2> {
55 let mut coords3d = Vec::with_capacity(pattern.len());
56
57 for v in pattern.iter() {
58 coords3d.push(Point3::new(v.x.clone(), v.y.clone(), na::zero()));
59 }
60
61 PolylinePattern {
62 pattern: coords3d,
63 closed: closed,
64 last_start_id: 0,
65 start_cap: start_cap,
66 end_cap: end_cap,
67 }
68 }
69}
70
71impl<N, C1, C2> StrokePattern<N> for PolylinePattern<N, C1, C2>
72where
73 N: RealField + Copy,
74 C1: PolylineCompatibleCap<N>,
75 C2: PolylineCompatibleCap<N>,
76{
77 fn stroke<C: CurveSampler<N>>(&mut self, sampler: &mut C) -> TriMesh<N> {
78 let mut vertices = Vec::new();
79 let mut indices = Vec::new();
80 let npts = self.pattern.len() as u32;
81 loop {
85 let next = sampler.next();
86
87 match next {
89 PathSample::StartPoint(ref pt, ref dir)
90 | PathSample::InnerPoint(ref pt, ref dir)
91 | PathSample::EndPoint(ref pt, ref dir) => {
92 let mut new_polyline = self.pattern.clone();
93 let transform;
94
95 if dir.x.is_zero() && dir.z.is_zero() {
96 transform = Isometry3::face_towards(pt, &(*pt + *dir), &Vector3::x());
98 } else {
99 transform = Isometry3::face_towards(pt, &(*pt + *dir), &Vector3::y());
100 }
101
102 for p in &mut new_polyline {
103 *p = transform * &*p;
104 }
105
106 let new_start_id = vertices.len() as u32;
107
108 vertices.extend(new_polyline.into_iter());
109
110 if new_start_id != 0 {
111 if self.closed {
112 utils::push_ring_indices(
113 new_start_id,
114 self.last_start_id,
115 npts,
116 &mut indices,
117 );
118 } else {
119 utils::push_open_ring_indices(
120 new_start_id,
121 self.last_start_id,
122 npts,
123 &mut indices,
124 );
125 }
126
127 self.last_start_id = new_start_id;
128 }
129 }
130 PathSample::EndOfSample => {
131 return TriMesh::new(vertices, None, None, Some(IndexBuffer::Unified(indices)))
132 }
133 }
134
135 match next {
138 PathSample::StartPoint(ref pt, ref dir) => {
139 self.start_cap.gen_start_cap(
140 0,
141 &self.pattern,
142 pt,
143 dir,
144 self.closed,
145 &mut vertices,
146 &mut indices,
147 );
148 }
149 PathSample::EndPoint(ref pt, ref dir) => {
150 self.end_cap.gen_end_cap(
151 vertices.len() as u32 - npts,
152 &self.pattern,
153 pt,
154 dir,
155 self.closed,
156 &mut vertices,
157 &mut indices,
158 );
159 }
160 _ => {}
161 }
162 }
163 }
164}