ncollide3d/shape/
polyline.rs

1//! 2d line strip, 3d polyline.
2
3use crate::bounding_volume::{self, BoundingVolume, AABB};
4use crate::math::{Isometry, Point, Vector, DIM};
5use crate::partitioning::{BVHImpl, BVT};
6use crate::query::{
7    Contact, ContactKinematic, ContactPrediction, ContactPreprocessor, LocalShapeApproximation,
8    NeighborhoodGeometry,
9};
10use crate::shape::{CompositeShape, DeformableShape, DeformationsType, FeatureId, Segment, Shape};
11use na::{self, Point2, RealField, Unit};
12use std::iter;
13use std::ops::Range;
14use std::slice;
15
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[derive(Clone)]
18struct DeformationInfos<N: RealField + Copy> {
19    margin: N,
20    curr_timestamp: usize,
21    timestamps: Vec<usize>,
22    ref_vertices: Vec<Point<N>>,
23    seg_to_update: Vec<usize>,
24}
25
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[derive(Clone)]
28pub struct PolylineEdge<N: RealField + Copy> {
29    pub indices: Point2<usize>,
30    bvt_leaf: usize,
31    pub normal: Option<Unit<Vector<N>>>, // FIXME: useless in 3D
32}
33
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35#[derive(Clone)]
36pub struct PolylineVertex {
37    pub adj_edges: Range<usize>,
38    pub adj_vertices: Range<usize>,
39}
40
41/// A polygonal line.
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43#[derive(Clone)]
44pub struct Polyline<N: RealField + Copy> {
45    bvt: BVT<usize, AABB<N>>,
46    points: Vec<Point<N>>,
47    vertices: Vec<PolylineVertex>,
48    edges: Vec<PolylineEdge<N>>,
49    adj_edge_list: Vec<usize>,
50    // NOTE: the adj_vertex_list could be deduced from the adj_edge_list.
51    adj_vertex_list: Vec<usize>,
52    deformations: DeformationInfos<N>,
53    oriented: bool, // FIXME: useless in 3D
54}
55
56impl<N: RealField + Copy> Polyline<N> {
57    /// Builds a new polyline.
58    pub fn new(points: Vec<Point<N>>, indices: Option<Vec<Point2<usize>>>) -> Polyline<N> {
59        let indices = indices.unwrap_or(
60            (0..)
61                .map(|i| Point2::new(i, i + 1))
62                .take(points.len() - 1)
63                .collect(),
64        );
65        let mut leaves = Vec::with_capacity(indices.len());
66        let mut vertices: Vec<PolylineVertex> = iter::repeat(PolylineVertex {
67            adj_edges: 0..0,
68            adj_vertices: 0..0,
69        })
70        .take(points.len())
71        .collect();
72        let mut edges = Vec::with_capacity(indices.len());
73
74        let adj_edge_list = Self::adj_edge_list(&indices, &mut vertices);
75        let adj_vertex_list = Self::adj_vertex_list(&indices, &mut vertices);
76
77        {
78            let is = &*indices;
79
80            for (i, is) in is.iter().enumerate() {
81                let segment = Segment::new(points[is.x], points[is.y]);
82                let normal = segment.normal();
83
84                let bv = segment.local_aabb();
85                leaves.push((i, bv.clone()));
86                edges.push(PolylineEdge {
87                    indices: *is,
88                    bvt_leaf: 0, // Will be set later.
89                    normal,
90                })
91            }
92        }
93
94        let bvt = BVT::new_balanced(leaves);
95
96        // Set edge.bvt_leaf
97        for (i, leaf) in bvt.leaves().iter().enumerate() {
98            edges[*leaf.data()].bvt_leaf = i;
99        }
100
101        let deformations = DeformationInfos {
102            margin: na::convert(0.1), // FIXME: find a better way to define the margin.
103            curr_timestamp: 0,
104            timestamps: Vec::new(),
105            ref_vertices: Vec::new(),
106            seg_to_update: Vec::new(),
107        };
108
109        Polyline {
110            bvt,
111            points,
112            deformations,
113            vertices,
114            edges,
115            adj_edge_list,
116            adj_vertex_list,
117            oriented: false,
118        }
119    }
120
121    fn adj_vertex_list(edges: &[Point2<usize>], vertices: &mut [PolylineVertex]) -> Vec<usize> {
122        let mut num_neighbors: Vec<usize> = iter::repeat(0).take(vertices.len()).collect();
123
124        for e in edges {
125            num_neighbors[e.x] += 1;
126            num_neighbors[e.y] += 1;
127        }
128
129        let mut total_num_nbh = 0;
130
131        for (num_nbh, vtx) in num_neighbors.iter().zip(vertices.iter_mut()) {
132            vtx.adj_vertices = total_num_nbh..total_num_nbh + num_nbh;
133            total_num_nbh += num_nbh;
134        }
135
136        let mut adj_vertex_list: Vec<usize> = iter::repeat(0).take(total_num_nbh).collect();
137
138        // Build the adjacency list.
139        for n in &mut num_neighbors {
140            *n = 0;
141        }
142
143        for e in edges.iter() {
144            adj_vertex_list[vertices[e.x].adj_vertices.start + num_neighbors[e.x]] = e.y;
145            adj_vertex_list[vertices[e.y].adj_vertices.start + num_neighbors[e.y]] = e.x;
146
147            num_neighbors[e.x] += 1;
148            num_neighbors[e.y] += 1;
149        }
150
151        adj_vertex_list
152    }
153
154    fn adj_edge_list(edges: &[Point2<usize>], vertices: &mut [PolylineVertex]) -> Vec<usize> {
155        let mut num_neighbors: Vec<usize> = iter::repeat(0).take(vertices.len()).collect();
156
157        for idx in edges {
158            num_neighbors[idx.x] += 1;
159            num_neighbors[idx.y] += 1;
160        }
161
162        let mut total_num_nbh = 0;
163
164        for (num_nbh, vtx) in num_neighbors.iter().zip(vertices.iter_mut()) {
165            vtx.adj_edges = total_num_nbh..total_num_nbh + num_nbh;
166            total_num_nbh += num_nbh;
167        }
168
169        let mut adj_edge_list: Vec<usize> = iter::repeat(0).take(total_num_nbh).collect();
170
171        // Build the adjacency list.
172        for n in &mut num_neighbors {
173            *n = 0;
174        }
175
176        for (i, idx) in edges.iter().enumerate() {
177            adj_edge_list[vertices[idx.x].adj_edges.start + num_neighbors[idx.x]] = i;
178            adj_edge_list[vertices[idx.y].adj_edges.start + num_neighbors[idx.y]] = i;
179
180            num_neighbors[idx.x] += 1;
181            num_neighbors[idx.y] += 1;
182        }
183
184        adj_edge_list
185    }
186
187    /// A polyline shaped like a quad, in the x-y plane.
188    pub fn quad(nx: usize, ny: usize) -> Self {
189        let mut vertices = Vec::new();
190        let step_x = N::one() / na::convert(nx as f64);
191        let step_y = N::one() / na::convert(ny as f64);
192        let _0_5: N = na::convert(0.5);
193
194        for i in 0..=nx {
195            vertices.push(xy_point(step_x * na::convert(i as f64) - _0_5, -_0_5));
196        }
197        for j in 1..=ny {
198            vertices.push(xy_point(_0_5, step_y * na::convert(j as f64) - _0_5));
199        }
200        for i in 1..=nx {
201            vertices.push(xy_point(_0_5 - step_x * na::convert(i as f64), _0_5));
202        }
203        for j in 1..ny {
204            vertices.push(xy_point(-_0_5, _0_5 - step_y * na::convert(j as f64)));
205        }
206
207        let mut indices: Vec<_> = (0..)
208            .map(|i| Point2::new(i, i + 1))
209            .take(vertices.len() - 1)
210            .collect();
211        indices.push(Point2::new(vertices.len() - 1, 0));
212
213        Polyline::new(vertices, Some(indices))
214    }
215
216    /// The polyline's AABB.
217    #[inline]
218    pub fn aabb(&self) -> &AABB<N> {
219        self.bvt
220            .root_bounding_volume()
221            .expect("An empty Polyline has no AABB.")
222    }
223
224    /// The points of this polyline.
225    #[inline]
226    pub fn points(&self) -> &[Point<N>] {
227        &self.points
228    }
229
230    /// The edges of this polyline.
231    #[inline]
232    pub fn edges(&self) -> &[PolylineEdge<N>] {
233        &self.edges
234    }
235
236    /// Whether this polyline is considered is oriented or not.
237    ///
238    /// By default a polyline is not oriented.
239    #[inline]
240    pub fn oriented(&self) -> bool {
241        self.oriented
242    }
243
244    /// Whether this polyline is considered as oriented or not.
245    ///
246    /// This is determined at the initialization of the polyline.
247    #[inline]
248    pub fn set_oriented(&mut self, oriented: bool) {
249        self.oriented = oriented
250    }
251
252    /// Face containing feature.
253    #[inline]
254    pub fn edge_containing_feature(&self, id: FeatureId) -> usize {
255        match id {
256            FeatureId::Vertex(i) => self.adj_edge_list[self.vertices[i].adj_edges.start],
257            #[cfg(feature = "dim3")]
258            FeatureId::Edge(i) => i,
259            FeatureId::Face(i) => i % self.edges.len(),
260            _ => panic!("Feature ID cannot be unknown."),
261        }
262    }
263
264    /// Converts a segment FeatureId to a polyline FeatureId.
265    #[inline]
266    pub fn segment_feature_to_polyline_feature(
267        &self,
268        edge_id: usize,
269        feature: FeatureId,
270    ) -> FeatureId {
271        let edge = &self.edges[edge_id];
272        match feature {
273            FeatureId::Vertex(i) => FeatureId::Vertex(edge.indices[i]),
274            #[cfg(feature = "dim3")]
275            FeatureId::Edge(_) => FeatureId::Edge(edge_id),
276            FeatureId::Face(i) => {
277                if i == 0 {
278                    FeatureId::Face(edge_id)
279                } else {
280                    FeatureId::Face(edge_id + self.edges.len())
281                }
282            }
283            FeatureId::Unknown => FeatureId::Unknown,
284        }
285    }
286
287    /// The segment of the `i`-th edge on this polyline.
288    #[inline]
289    pub fn edge_segment(&self, i: usize) -> Segment<N> {
290        let edge = &self.edges[i];
291        Segment::new(self.points[edge.indices.x], self.points[edge.indices.y])
292    }
293
294    /// Gets the i-th polyline element.
295    #[inline]
296    pub fn segment_at(&self, i: usize) -> Segment<N> {
297        let idx = self.edges[i].indices;
298        Segment::new(self.points[idx.x], self.points[idx.y])
299    }
300
301    /// The optimization structure used by this polyline.
302    #[inline]
303    pub fn bvt(&self) -> &BVT<usize, AABB<N>> {
304        &self.bvt
305    }
306
307    /// Tests that the given `dir` is on the tangent cone of the `i`th vertex
308    /// of this polyline.
309    #[cfg(feature = "dim3")]
310    pub fn vertex_tangent_cone_contains_dir(
311        &self,
312        _i: usize,
313        _deformations: Option<&[N]>,
314        _dir: &Unit<Vector<N>>,
315    ) -> bool {
316        return false;
317    }
318
319    /// Tests that the given `dir` is on the tangent cone of the `i`th vertex
320    /// of this polyline.
321    #[cfg(feature = "dim2")]
322    pub fn vertex_tangent_cone_contains_dir(
323        &self,
324        i: usize,
325        deformations: Option<&[N]>,
326        dir: &Unit<Vector<N>>,
327    ) -> bool {
328        if !self.oriented {
329            return false;
330        }
331
332        let v = &self.vertices[i];
333
334        if let Some(coords) = deformations {
335            for adj_edge in &self.adj_edge_list[v.adj_edges.clone()] {
336                let indices = self.edges[*adj_edge].indices * DIM;
337                let seg = Segment::new(
338                    Point::from_slice(&coords[indices.x..indices.x + DIM]),
339                    Point::from_slice(&coords[indices.y..indices.y + DIM]),
340                );
341
342                if seg.scaled_normal().dot(dir) > N::zero() {
343                    return false;
344                }
345            }
346        } else {
347            for adj_edge in &self.adj_edge_list[v.adj_edges.clone()] {
348                let edge = &self.edges[*adj_edge];
349
350                if let Some(ref n) = edge.normal {
351                    if n.dot(dir) > N::zero() {
352                        return false;
353                    }
354                }
355            }
356        }
357
358        true
359    }
360
361    /// Applies in-place a transformation to this polyline.
362    pub fn transform_by(&mut self, transform: &Isometry<N>) {
363        for pt in &mut self.points {
364            *pt = transform * *pt
365        }
366    }
367
368    /// Applies a transformation to this polyline.
369    #[inline]
370    pub fn transformed(mut self, t: &Isometry<N>) -> Self {
371        self.transform_by(t);
372        self
373    }
374
375    /// Applies in-place a non-uniform scale to this polyline.
376    pub fn scale_by(&mut self, scale: &Vector<N>) {
377        for pt in &mut self.points {
378            pt.coords.component_mul_assign(scale)
379        }
380    }
381
382    /// Applies a non-uniform scale to this polyline.
383    #[inline]
384    pub fn scaled(mut self, s: &Vector<N>) -> Self {
385        self.scale_by(s);
386        self
387    }
388
389    /// Returns `true` if the given feature is a FeatureId::Face and
390    /// identifies a backface of this polyline.
391    #[inline]
392    pub fn is_backface(&self, feature: FeatureId) -> bool {
393        if let FeatureId::Face(i) = feature {
394            i >= self.edges.len()
395        } else {
396            false
397        }
398    }
399
400    /// Tests that the given `dir` is on the polar of the tangent cone of the `i`th vertex
401    /// of this polyline.
402    pub fn vertex_tangent_cone_polar_contains_dir(
403        &self,
404        i: usize,
405        dir: &Unit<Vector<N>>,
406        sin_ang_tol: N,
407    ) -> bool {
408        let v = &self.vertices[i];
409
410        for adj_vtx in &self.adj_vertex_list[v.adj_vertices.clone()] {
411            let edge_dir = self.points[i] - self.points[*adj_vtx];
412
413            // FIXME: don't compute the norm every time.
414            if edge_dir.dot(dir) < -sin_ang_tol * edge_dir.norm() {
415                return false;
416            }
417        }
418
419        true
420    }
421
422    /// Tests that the given `dir` is on the tangent cone of the `i`th edge
423    /// of this polyline.
424    #[cfg(feature = "dim3")]
425    pub fn edge_tangent_cone_contains_dir(
426        &self,
427        _i: usize,
428        _deformations: Option<&[N]>,
429        _dir: &Unit<Vector<N>>,
430    ) -> bool {
431        return false;
432    }
433
434    /// Tests that the given `dir` is on the tangent cone of the `i`th edge
435    /// of this polyline.
436    #[cfg(feature = "dim2")]
437    pub fn edge_tangent_cone_contains_dir(
438        &self,
439        i: usize,
440        deformations: Option<&[N]>,
441        dir: &Unit<Vector<N>>,
442    ) -> bool {
443        if !self.oriented {
444            return false;
445        }
446
447        let normal;
448
449        if let Some(coords) = deformations {
450            let indices = self.edges[i % self.edges.len()].indices * DIM;
451            let seg = Segment::new(
452                Point::from_slice(&coords[indices.x..indices.x + DIM]),
453                Point::from_slice(&coords[indices.y..indices.y + DIM]),
454            );
455
456            if i >= self.edges.len() {
457                normal = -seg.scaled_normal();
458            } else {
459                normal = seg.scaled_normal();
460            }
461        } else {
462            if i >= self.edges.len() {
463                normal = -self.edges[i - self.edges.len()]
464                    .normal
465                    .map(|n| n.into_inner())
466                    .unwrap_or(Vector::zeros());
467            } else {
468                normal = self.edges[i]
469                    .normal
470                    .map(|n| n.into_inner())
471                    .unwrap_or(Vector::zeros());
472            }
473        }
474
475        normal.dot(dir) <= N::zero()
476    }
477
478    /// Tests whether the polar of the tangent cone of the i-th edge of this polyline
479    /// contains the direction `dir` considering the cosinus of an angular tolerance `cos_ang_tol`.
480    pub fn edge_tangent_cone_polar_contains_dir(
481        &self,
482        i: usize,
483        dir: &Unit<Vector<N>>,
484        cos_ang_tol: N,
485    ) -> bool {
486        let normal;
487
488        if i >= self.edges.len() {
489            normal = -self.edges[i - self.edges.len()]
490                .normal
491                .map(|n| n.into_inner())
492                .unwrap_or(Vector::zeros());
493        } else {
494            normal = self.edges[i]
495                .normal
496                .map(|n| n.into_inner())
497                .unwrap_or(Vector::zeros());
498        }
499
500        normal.dot(dir) >= cos_ang_tol
501    }
502
503    /// (Not yet implemented) Tests whether the polar of the tangent cone of the specified feature of
504    /// this polyline contains the direction `dir` considering the sinus and cosinus of an angular tolerance.
505    pub fn tangent_cone_polar_contains_dir(
506        &self,
507        _feature: FeatureId,
508        _dir: &Unit<Vector<N>>,
509        _sin_ang_tol: N,
510        _cos_ang_tol: N,
511    ) -> bool {
512        unimplemented!()
513        /*
514        match feature {
515            FeatureId::Edge(i) => self.edge_tangent_cone_polar_contains_dir(i, dir, cos_ang_tol),
516            FeatureId::Vertex(i) => self.vertex_tangent_cone_polar_contains_dir(i, dir, sin_ang_tol),
517            FeatureId::Unknown => false
518        }
519        */
520    }
521
522    fn init_deformation_infos(&mut self) -> bool {
523        if self.deformations.ref_vertices.is_empty() {
524            self.deformations.timestamps = iter::repeat(0).take(self.edges.len()).collect();
525            self.deformations.ref_vertices = self.points.clone();
526            true
527        } else {
528            false
529        }
530    }
531}
532
533impl<N: RealField + Copy> CompositeShape<N> for Polyline<N> {
534    #[inline]
535    fn nparts(&self) -> usize {
536        self.edges.len()
537    }
538
539    #[inline(always)]
540    fn map_part_at(
541        &self,
542        i: usize,
543        m: &Isometry<N>,
544        f: &mut dyn FnMut(&Isometry<N>, &dyn Shape<N>),
545    ) {
546        let element = self.segment_at(i);
547        f(m, &element)
548    }
549
550    fn map_part_and_preprocessor_at(
551        &self,
552        i: usize,
553        m: &Isometry<N>,
554        prediction: &ContactPrediction<N>,
555        f: &mut dyn FnMut(&Isometry<N>, &dyn Shape<N>, &dyn ContactPreprocessor<N>),
556    ) {
557        let element = self.segment_at(i);
558        let proc = PolylineContactProcessor::new(self, m, i, prediction);
559        f(m, &element, &proc)
560    }
561
562    #[inline]
563    fn aabb_at(&self, i: usize) -> AABB<N> {
564        self.bvt
565            .leaf(self.edges[i].bvt_leaf)
566            .bounding_volume()
567            .clone()
568    }
569
570    #[inline]
571    fn bvh(&self) -> BVHImpl<N, usize, AABB<N>> {
572        BVHImpl::BVT(&self.bvt)
573    }
574}
575
576impl<N: RealField + Copy> DeformableShape<N> for Polyline<N> {
577    fn deformations_type(&self) -> DeformationsType {
578        DeformationsType::Vectors
579    }
580
581    /// Updates all the degrees of freedom of this shape.
582    fn set_deformations(&mut self, coords: &[N]) {
583        assert!(
584            coords.len() >= self.points.len() * DIM,
585            "Set deformations error: dimension mismatch."
586        );
587        let is_first_init = self.init_deformation_infos();
588        self.deformations.curr_timestamp += 1;
589
590        // There is a bit of unsafe code in order to perform a memcopy for
591        // efficiency reasons when the mapping between degrees of freedom
592        // is trivial.
593        unsafe {
594            let len = self.points.len();
595            let coords_ptr = coords.as_ptr() as *const Point<N>;
596            let coords_pt: &[Point<N>] = slice::from_raw_parts(coords_ptr, len);
597            self.points.copy_from_slice(coords_pt);
598        }
599
600        for (target, pt) in self.points.iter_mut().enumerate() {
601            let ref_pt = &mut self.deformations.ref_vertices[target];
602            let sq_dist_to_ref = na::distance_squared(pt, ref_pt);
603
604            if is_first_init || sq_dist_to_ref > self.deformations.margin * self.deformations.margin
605            {
606                // We have to update the adjacent bounding volumes.
607                // Note that they can be duplicates on `seg_to_update`.
608                // Those duplicates will be filtered using timestamps in the next for loop.
609                let ids = self.vertices[target].adj_edges.clone();
610                self.deformations
611                    .seg_to_update
612                    .extend_from_slice(&self.adj_edge_list[ids]);
613                *ref_pt = *pt;
614            }
615        }
616
617        // Update normals.
618        for e in &mut self.edges {
619            let seg = Segment::new(self.points[e.indices.x], self.points[e.indices.y]);
620            e.normal = seg.normal();
621        }
622
623        // Apply the bounding volumes changes.
624        for seg_id in self.deformations.seg_to_update.drain(..) {
625            if self.deformations.timestamps[seg_id] != self.deformations.curr_timestamp {
626                // Update the BV.
627                let idx = &self.edges[seg_id].indices;
628                let mut new_bv = bounding_volume::local_point_cloud_aabb(&[
629                    self.points[idx.x],
630                    self.points[idx.y],
631                ]);
632                new_bv.loosen(self.deformations.margin);
633                self.bvt
634                    .set_leaf_bounding_volume(self.edges[seg_id].bvt_leaf, new_bv, false);
635                self.deformations.timestamps[seg_id] = self.deformations.curr_timestamp;
636            }
637        }
638
639        // FIXME: measure efficiency with a non-zero margin.
640        self.bvt.refit(N::zero())
641    }
642
643    fn update_local_approximation(&self, coords: &[N], approx: &mut LocalShapeApproximation<N>) {
644        match approx.feature {
645            FeatureId::Vertex(i) => {
646                approx.point = Point::from_slice(&coords[i * DIM..(i + 1) * DIM]);
647                approx.geometry = NeighborhoodGeometry::Point;
648            }
649            #[cfg(feature = "dim3")]
650            FeatureId::Edge(i) => {
651                let edge = &self.edges[i];
652                let pid1 = edge.indices.x * DIM;
653                let pid2 = edge.indices.y * DIM;
654                let seg = Segment::new(
655                    Point::from_slice(&coords[pid1..pid1 + DIM]),
656                    Point::from_slice(&coords[pid2..pid2 + DIM]),
657                );
658                approx.point = seg.a;
659
660                if let Some(dir) = seg.direction() {
661                    approx.geometry = NeighborhoodGeometry::Line(dir);
662                } else {
663                    approx.geometry = NeighborhoodGeometry::Point;
664                }
665            }
666            #[cfg(feature = "dim3")]
667            FeatureId::Face(_) => unreachable!(),
668            #[cfg(feature = "dim2")]
669            FeatureId::Face(mut i) => {
670                let is_backface = i >= self.edges.len();
671                if is_backface {
672                    i -= self.edges.len();
673                }
674
675                let edge = &self.edges[i];
676                let pid1 = edge.indices.x * DIM;
677                let pid2 = edge.indices.y * DIM;
678                let seg = Segment::new(
679                    Point::from_slice(&coords[pid1..pid1 + DIM]),
680                    Point::from_slice(&coords[pid2..pid2 + DIM]),
681                );
682
683                approx.point = seg.a;
684
685                if let Some(n) = seg.normal() {
686                    if !is_backface {
687                        approx.geometry = NeighborhoodGeometry::Plane(n);
688                    } else {
689                        approx.geometry = NeighborhoodGeometry::Plane(-n);
690                    }
691                } else {
692                    approx.geometry = NeighborhoodGeometry::Point;
693                }
694            }
695            _ => panic!(
696                "Encountered invalid triangle feature: {:?}.",
697                approx.feature
698            ),
699        }
700    }
701}
702
703#[allow(dead_code)]
704struct PolylineContactProcessor<'a, N: RealField + Copy> {
705    polyline: &'a Polyline<N>,
706    pos: &'a Isometry<N>,
707    edge_id: usize,
708    prediction: &'a ContactPrediction<N>,
709}
710
711impl<'a, N: RealField + Copy> PolylineContactProcessor<'a, N> {
712    pub fn new(
713        polyline: &'a Polyline<N>,
714        pos: &'a Isometry<N>,
715        edge_id: usize,
716        prediction: &'a ContactPrediction<N>,
717    ) -> Self {
718        PolylineContactProcessor {
719            polyline,
720            pos,
721            edge_id,
722            prediction,
723        }
724    }
725}
726
727impl<'a, N: RealField + Copy> ContactPreprocessor<N> for PolylineContactProcessor<'a, N> {
728    fn process_contact(
729        &self,
730        _c: &mut Contact<N>,
731        kinematic: &mut ContactKinematic<N>,
732        is_first: bool,
733    ) -> bool {
734        // Fix the feature ID.
735        let feature = if is_first {
736            kinematic.feature1()
737        } else {
738            kinematic.feature2()
739        };
740
741        let edge = &self.polyline.edges()[self.edge_id];
742        let actual_feature = match feature {
743            FeatureId::Vertex(i) => FeatureId::Vertex(edge.indices[i]),
744            #[cfg(feature = "dim3")]
745            FeatureId::Edge(_) => FeatureId::Edge(self.edge_id),
746            FeatureId::Face(i) => {
747                if i == 0 {
748                    FeatureId::Face(self.edge_id)
749                } else {
750                    FeatureId::Face(self.edge_id + self.polyline.edges().len())
751                }
752            }
753            FeatureId::Unknown => FeatureId::Unknown,
754        };
755
756        if is_first {
757            kinematic.set_feature1(actual_feature);
758        } else {
759            kinematic.set_feature2(actual_feature);
760        }
761
762        /*
763        // TODO: Test the validity of the LMD.
764        if c.depth > N::zero() {
765            true
766        } else {
767            let local_dir = self.pos.inverse_transform_unit_vector(&c.normal);
768
769            if is_first {
770                self.polyline.tangent_cone_polar_contains_dir(actual_feature, &local_dir, self.prediction.sin_angular1(), self.prediction.cos_angular1())
771            } else {
772                self.polyline.tangent_cone_polar_contains_dir(actual_feature, &-local_dir, self.prediction.sin_angular2(), self.prediction.cos_angular2())
773            }
774        }*/
775        true
776    }
777}
778
779#[cfg(feature = "dim2")]
780fn xy_point<N: RealField + Copy>(x: N, y: N) -> Point<N> {
781    Point::new(x, y)
782}
783
784#[cfg(feature = "dim3")]
785fn xy_point<N: RealField + Copy>(x: N, y: N) -> Point<N> {
786    Point::new(x, y, N::zero())
787}