parry2d/shape/
polyline.rs

1use crate::bounding_volume::Aabb;
2use crate::math::{Isometry, Point, Real, Vector};
3use crate::partitioning::{Bvh, BvhBuildStrategy};
4use crate::query::{PointProjection, PointQueryWithLocation};
5use crate::shape::composite_shape::CompositeShape;
6use crate::shape::{FeatureId, Segment, SegmentPointLocation, Shape, TypedCompositeShape};
7#[cfg(feature = "alloc")]
8use alloc::vec::Vec;
9
10use crate::query::details::NormalConstraints;
11
12#[derive(Clone, Debug)]
13#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
14#[cfg_attr(
15    feature = "rkyv",
16    derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
17    archive(check_bytes)
18)]
19/// A polyline shape formed by connected line segments.
20///
21/// A polyline is a sequence of line segments (edges) connecting vertices. It can be open
22/// (not forming a closed loop) or closed (where the last vertex connects back to the first).
23/// Polylines are commonly used for paths, boundaries, and 2D/3D curves.
24///
25/// # Structure
26///
27/// A polyline consists of:
28/// - **Vertices**: Points in 2D or 3D space
29/// - **Indices**: Pairs of vertex indices defining each segment
30/// - **BVH**: Bounding Volume Hierarchy for fast spatial queries
31///
32/// # Properties
33///
34/// - **Composite shape**: Made up of multiple segments
35/// - **1-dimensional**: Has length but no volume
36/// - **Flexible topology**: Can be open or closed, branching or linear
37/// - **Accelerated queries**: Uses BVH for efficient collision detection
38///
39/// # Use Cases
40///
41/// Polylines are ideal for:
42/// - **Paths and roads**: Navigation paths, road networks
43/// - **Terrain boundaries**: Cliff edges, coastlines, level boundaries
44/// - **Outlines**: 2D shape outlines, contours
45/// - **Wire frames**: Simplified representations of complex shapes
46/// - **Motion paths**: Character movement paths, camera rails
47///
48/// # Example
49///
50/// ```rust
51/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
52/// use parry3d::shape::Polyline;
53/// use nalgebra::Point3;
54///
55/// // Create a simple L-shaped polyline
56/// let vertices = vec![
57///     Point3::origin(),
58///     Point3::new(1.0, 0.0, 0.0),
59///     Point3::new(1.0, 1.0, 0.0),
60/// ];
61///
62/// // Indices are automatically generated to connect consecutive vertices
63/// let polyline = Polyline::new(vertices, None);
64///
65/// // The polyline has 2 segments: (0,1) and (1,2)
66/// assert_eq!(polyline.num_segments(), 2);
67/// assert_eq!(polyline.vertices().len(), 3);
68/// # }
69/// ```
70///
71/// # Custom Connectivity
72///
73/// You can provide custom indices to create non-sequential connections:
74///
75/// ```rust
76/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
77/// use parry2d::shape::Polyline;
78/// use nalgebra::Point2;
79///
80/// // Create a triangle polyline (closed loop)
81/// let vertices = vec![
82///     Point2::origin(),
83///     Point2::new(1.0, 0.0),
84///     Point2::new(0.5, 1.0),
85/// ];
86///
87/// // Manually specify edges to create a closed triangle
88/// let indices = vec![
89///     [0, 1],  // Bottom edge
90///     [1, 2],  // Right edge
91///     [2, 0],  // Left edge (closes the loop)
92/// ];
93///
94/// let polyline = Polyline::new(vertices, Some(indices));
95/// assert_eq!(polyline.num_segments(), 3);
96/// # }
97/// ```
98pub struct Polyline {
99    bvh: Bvh,
100    vertices: Vec<Point<Real>>,
101    indices: Vec<[u32; 2]>,
102}
103
104impl Polyline {
105    /// Creates a new polyline from a vertex buffer and an optional index buffer.
106    ///
107    /// This is the main constructor for creating a polyline. If no indices are provided,
108    /// the vertices will be automatically connected in sequence (vertex 0 to 1, 1 to 2, etc.).
109    ///
110    /// # Arguments
111    ///
112    /// * `vertices` - A vector of points defining the polyline vertices
113    /// * `indices` - Optional vector of `[u32; 2]` pairs defining which vertices connect.
114    ///   If `None`, vertices are connected sequentially.
115    ///
116    /// # Returns
117    ///
118    /// A new `Polyline` with an internal BVH for accelerated queries.
119    ///
120    /// # Example
121    ///
122    /// ```
123    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
124    /// use parry3d::shape::Polyline;
125    /// use nalgebra::Point3;
126    ///
127    /// // Create a zigzag path with automatic sequential connections
128    /// let vertices = vec![
129    ///     Point3::origin(),
130    ///     Point3::new(1.0, 1.0, 0.0),
131    ///     Point3::new(2.0, 0.0, 0.0),
132    ///     Point3::new(3.0, 1.0, 0.0),
133    /// ];
134    /// let polyline = Polyline::new(vertices, None);
135    /// assert_eq!(polyline.num_segments(), 3);
136    /// # }
137    /// ```
138    ///
139    /// # Custom Connectivity Example
140    ///
141    /// ```
142    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
143    /// use parry2d::shape::Polyline;
144    /// use nalgebra::Point2;
145    ///
146    /// // Create a square with custom indices
147    /// let vertices = vec![
148    ///     Point2::origin(),
149    ///     Point2::new(1.0, 0.0),
150    ///     Point2::new(1.0, 1.0),
151    ///     Point2::new(0.0, 1.0),
152    /// ];
153    ///
154    /// // Define edges to form a closed square
155    /// let indices = vec![
156    ///     [0, 1], [1, 2], [2, 3], [3, 0]
157    /// ];
158    ///
159    /// let square = Polyline::new(vertices, Some(indices));
160    /// assert_eq!(square.num_segments(), 4);
161    ///
162    /// // Each segment connects the correct vertices
163    /// let first_segment = square.segment(0);
164    /// assert_eq!(first_segment.a, Point2::origin());
165    /// assert_eq!(first_segment.b, Point2::new(1.0, 0.0));
166    /// # }
167    /// ```
168    pub fn new(vertices: Vec<Point<Real>>, indices: Option<Vec<[u32; 2]>>) -> Self {
169        let indices =
170            indices.unwrap_or_else(|| (0..vertices.len() as u32 - 1).map(|i| [i, i + 1]).collect());
171        let leaves = indices.iter().enumerate().map(|(i, idx)| {
172            let aabb =
173                Segment::new(vertices[idx[0] as usize], vertices[idx[1] as usize]).local_aabb();
174            (i, aabb)
175        });
176
177        // NOTE: we apply no dilation factor because we won't
178        // update this tree dynamically.
179        let bvh = Bvh::from_iter(BvhBuildStrategy::Binned, leaves);
180
181        Self {
182            bvh,
183            vertices,
184            indices,
185        }
186    }
187
188    /// Computes the axis-aligned bounding box of this polyline in world space.
189    ///
190    /// The AABB is the smallest box aligned with the world axes that fully contains
191    /// the polyline after applying the given position/rotation transformation.
192    ///
193    /// # Arguments
194    ///
195    /// * `pos` - The position and orientation (isometry) of the polyline in world space
196    ///
197    /// # Returns
198    ///
199    /// An `Aabb` that bounds the transformed polyline
200    ///
201    /// # Example
202    ///
203    /// ```
204    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
205    /// use parry3d::shape::Polyline;
206    /// use nalgebra::{Point3, Isometry3, Translation3};
207    ///
208    /// // Create a polyline along the X axis
209    /// let vertices = vec![
210    ///     Point3::origin(),
211    ///     Point3::new(2.0, 0.0, 0.0),
212    /// ];
213    /// let polyline = Polyline::new(vertices, None);
214    ///
215    /// // Compute AABB at the origin
216    /// let identity = Isometry3::identity();
217    /// let aabb = polyline.aabb(&identity);
218    /// assert_eq!(aabb.mins.x, 0.0);
219    /// assert_eq!(aabb.maxs.x, 2.0);
220    ///
221    /// // Compute AABB after translating by (10, 5, 0)
222    /// let translated = Isometry3::from_parts(
223    ///     Translation3::new(10.0, 5.0, 0.0),
224    ///     nalgebra::UnitQuaternion::identity()
225    /// );
226    /// let aabb_translated = polyline.aabb(&translated);
227    /// assert_eq!(aabb_translated.mins.x, 10.0);
228    /// assert_eq!(aabb_translated.maxs.x, 12.0);
229    /// # }
230    /// ```
231    pub fn aabb(&self, pos: &Isometry<Real>) -> Aabb {
232        self.bvh.root_aabb().transform_by(pos)
233    }
234
235    /// Gets the local axis-aligned bounding box of this polyline.
236    ///
237    /// This returns the AABB in the polyline's local coordinate system (before any
238    /// transformation is applied). It's more efficient than `aabb()` when you don't
239    /// need to transform the polyline.
240    ///
241    /// # Returns
242    ///
243    /// An `Aabb` that bounds the polyline in local space
244    ///
245    /// # Example
246    ///
247    /// ```
248    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
249    /// use parry2d::shape::Polyline;
250    /// use nalgebra::Point2;
251    ///
252    /// // Create a rectangular polyline
253    /// let vertices = vec![
254    ///     Point2::new(-1.0, -2.0),
255    ///     Point2::new(3.0, -2.0),
256    ///     Point2::new(3.0, 4.0),
257    ///     Point2::new(-1.0, 4.0),
258    /// ];
259    /// let polyline = Polyline::new(vertices, None);
260    ///
261    /// // Get the local AABB
262    /// let aabb = polyline.local_aabb();
263    ///
264    /// // The AABB should contain all vertices
265    /// assert_eq!(aabb.mins.x, -1.0);
266    /// assert_eq!(aabb.mins.y, -2.0);
267    /// assert_eq!(aabb.maxs.x, 3.0);
268    /// assert_eq!(aabb.maxs.y, 4.0);
269    /// # }
270    /// ```
271    pub fn local_aabb(&self) -> Aabb {
272        self.bvh.root_aabb()
273    }
274
275    /// The BVH acceleration structure for this polyline.
276    pub fn bvh(&self) -> &Bvh {
277        &self.bvh
278    }
279
280    /// Returns the number of segments (edges) in this polyline.
281    ///
282    /// Each segment connects two vertices. For a polyline with `n` vertices and
283    /// sequential connectivity, there are `n-1` segments. For custom connectivity,
284    /// the number of segments equals the number of index pairs.
285    ///
286    /// # Returns
287    ///
288    /// The total number of line segments
289    ///
290    /// # Example
291    ///
292    /// ```
293    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
294    /// use parry3d::shape::Polyline;
295    /// use nalgebra::Point3;
296    ///
297    /// // Sequential polyline: 5 vertices -> 4 segments
298    /// let vertices = vec![
299    ///     Point3::origin(),
300    ///     Point3::new(1.0, 0.0, 0.0),
301    ///     Point3::new(2.0, 0.0, 0.0),
302    ///     Point3::new(3.0, 0.0, 0.0),
303    ///     Point3::new(4.0, 0.0, 0.0),
304    /// ];
305    /// let polyline = Polyline::new(vertices.clone(), None);
306    /// assert_eq!(polyline.num_segments(), 4);
307    ///
308    /// // Custom connectivity: can have different number of segments
309    /// let indices = vec![[0, 4], [1, 3]]; // Only 2 segments
310    /// let custom = Polyline::new(vertices, Some(indices));
311    /// assert_eq!(custom.num_segments(), 2);
312    /// # }
313    /// ```
314    pub fn num_segments(&self) -> usize {
315        self.indices.len()
316    }
317
318    /// Returns an iterator over all segments in this polyline.
319    ///
320    /// Each segment is returned as a [`Segment`] object with two endpoints.
321    /// The iterator yields exactly `num_segments()` items.
322    ///
323    /// # Returns
324    ///
325    /// An exact-size iterator that yields `Segment` instances
326    ///
327    /// # Example
328    ///
329    /// ```
330    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
331    /// use parry2d::shape::Polyline;
332    /// use nalgebra::Point2;
333    ///
334    /// // Create a triangle
335    /// let vertices = vec![
336    ///     Point2::origin(),
337    ///     Point2::new(1.0, 0.0),
338    ///     Point2::new(0.5, 1.0),
339    /// ];
340    /// let polyline = Polyline::new(vertices, None);
341    ///
342    /// // Iterate over all segments
343    /// let mut total_length = 0.0;
344    /// for segment in polyline.segments() {
345    ///     total_length += segment.length();
346    /// }
347    ///
348    /// // Calculate expected perimeter (not closed, so 2 sides only)
349    /// assert!(total_length > 2.0);
350    ///
351    /// // Collect all segments into a vector
352    /// let segments: Vec<_> = polyline.segments().collect();
353    /// assert_eq!(segments.len(), 2);
354    /// # }
355    /// ```
356    pub fn segments(&self) -> impl ExactSizeIterator<Item = Segment> + '_ {
357        self.indices.iter().map(move |ids| {
358            Segment::new(
359                self.vertices[ids[0] as usize],
360                self.vertices[ids[1] as usize],
361            )
362        })
363    }
364
365    /// Returns the segment at the given index.
366    ///
367    /// This retrieves a specific segment by its index. Indices range from `0` to
368    /// `num_segments() - 1`. If you need to access multiple segments, consider
369    /// using the `segments()` iterator instead.
370    ///
371    /// # Arguments
372    ///
373    /// * `i` - The index of the segment to retrieve (0-based)
374    ///
375    /// # Returns
376    ///
377    /// A `Segment` representing the edge at index `i`
378    ///
379    /// # Panics
380    ///
381    /// Panics if `i >= num_segments()`
382    ///
383    /// # Example
384    ///
385    /// ```
386    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
387    /// use parry3d::shape::Polyline;
388    /// use nalgebra::Point3;
389    ///
390    /// let vertices = vec![
391    ///     Point3::origin(),
392    ///     Point3::new(1.0, 0.0, 0.0),
393    ///     Point3::new(2.0, 1.0, 0.0),
394    /// ];
395    /// let polyline = Polyline::new(vertices, None);
396    ///
397    /// // Get the first segment (connects vertex 0 to vertex 1)
398    /// let seg0 = polyline.segment(0);
399    /// assert_eq!(seg0.a, Point3::origin());
400    /// assert_eq!(seg0.b, Point3::new(1.0, 0.0, 0.0));
401    /// assert_eq!(seg0.length(), 1.0);
402    ///
403    /// // Get the second segment (connects vertex 1 to vertex 2)
404    /// let seg1 = polyline.segment(1);
405    /// assert_eq!(seg1.a, Point3::new(1.0, 0.0, 0.0));
406    /// assert_eq!(seg1.b, Point3::new(2.0, 1.0, 0.0));
407    /// # }
408    /// ```
409    pub fn segment(&self, i: u32) -> Segment {
410        let idx = self.indices[i as usize];
411        Segment::new(
412            self.vertices[idx[0] as usize],
413            self.vertices[idx[1] as usize],
414        )
415    }
416
417    /// Transforms  the feature-id of a segment to the feature-id of this polyline.
418    pub fn segment_feature_to_polyline_feature(
419        &self,
420        segment: u32,
421        _feature: FeatureId,
422    ) -> FeatureId {
423        // TODO: return a vertex feature when it makes sense.
424        #[cfg(feature = "dim2")]
425        return FeatureId::Face(segment);
426        #[cfg(feature = "dim3")]
427        return FeatureId::Edge(segment);
428    }
429
430    /// Returns a slice containing all vertices of this polyline.
431    ///
432    /// Vertices are the points that define the polyline. Segments connect
433    /// pairs of these vertices according to the index buffer.
434    ///
435    /// # Returns
436    ///
437    /// A slice of all vertex points
438    ///
439    /// # Example
440    ///
441    /// ```
442    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
443    /// use parry2d::shape::Polyline;
444    /// use nalgebra::Point2;
445    ///
446    /// let vertices = vec![
447    ///     Point2::origin(),
448    ///     Point2::new(1.0, 0.0),
449    ///     Point2::new(1.0, 1.0),
450    /// ];
451    /// let polyline = Polyline::new(vertices.clone(), None);
452    ///
453    /// // Access all vertices
454    /// let verts = polyline.vertices();
455    /// assert_eq!(verts.len(), 3);
456    /// assert_eq!(verts[0], Point2::origin());
457    /// assert_eq!(verts[1], Point2::new(1.0, 0.0));
458    /// assert_eq!(verts[2], Point2::new(1.0, 1.0));
459    ///
460    /// // You can iterate over vertices
461    /// for (i, vertex) in polyline.vertices().iter().enumerate() {
462    ///     println!("Vertex {}: {:?}", i, vertex);
463    /// }
464    /// # }
465    /// ```
466    pub fn vertices(&self) -> &[Point<Real>] {
467        &self.vertices[..]
468    }
469
470    /// Returns a slice containing all segment indices.
471    ///
472    /// Each index is a pair `[u32; 2]` representing a segment connecting two vertices.
473    /// The first element is the index of the segment's start vertex, and the second
474    /// is the index of the end vertex.
475    ///
476    /// # Returns
477    ///
478    /// A slice of all segment index pairs
479    ///
480    /// # Example
481    ///
482    /// ```
483    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
484    /// use parry3d::shape::Polyline;
485    /// use nalgebra::Point3;
486    ///
487    /// let vertices = vec![
488    ///     Point3::origin(),
489    ///     Point3::new(1.0, 0.0, 0.0),
490    ///     Point3::new(2.0, 0.0, 0.0),
491    /// ];
492    ///
493    /// // With automatic indices
494    /// let polyline = Polyline::new(vertices.clone(), None);
495    /// let indices = polyline.indices();
496    /// assert_eq!(indices.len(), 2);
497    /// assert_eq!(indices[0], [0, 1]); // First segment: vertex 0 -> 1
498    /// assert_eq!(indices[1], [1, 2]); // Second segment: vertex 1 -> 2
499    ///
500    /// // With custom indices
501    /// let custom_indices = vec![[0, 2], [1, 0]];
502    /// let custom = Polyline::new(vertices, Some(custom_indices));
503    /// assert_eq!(custom.indices()[0], [0, 2]);
504    /// assert_eq!(custom.indices()[1], [1, 0]);
505    /// # }
506    /// ```
507    pub fn indices(&self) -> &[[u32; 2]] {
508        &self.indices
509    }
510
511    /// A flat view of the index buffer of this mesh.
512    pub fn flat_indices(&self) -> &[u32] {
513        unsafe {
514            let len = self.indices.len() * 2;
515            let data = self.indices.as_ptr() as *const u32;
516            core::slice::from_raw_parts(data, len)
517        }
518    }
519
520    /// Computes a scaled version of this polyline.
521    ///
522    /// This consumes the polyline and returns a new one with all vertices scaled
523    /// component-wise by the given scale vector. The connectivity (indices) remains
524    /// unchanged, but the BVH is rebuilt to reflect the new geometry.
525    ///
526    /// # Arguments
527    ///
528    /// * `scale` - The scaling factors for each axis
529    ///
530    /// # Returns
531    ///
532    /// A new polyline with scaled vertices
533    ///
534    /// # Example
535    ///
536    /// ```
537    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
538    /// use parry2d::shape::Polyline;
539    /// use nalgebra::{Point2, Vector2};
540    ///
541    /// let vertices = vec![
542    ///     Point2::new(1.0, 2.0),
543    ///     Point2::new(3.0, 4.0),
544    /// ];
545    /// let polyline = Polyline::new(vertices, None);
546    ///
547    /// // Scale by 2x in X and 3x in Y
548    /// let scaled = polyline.scaled(&Vector2::new(2.0, 3.0));
549    ///
550    /// // Check scaled vertices
551    /// assert_eq!(scaled.vertices()[0], Point2::new(2.0, 6.0));
552    /// assert_eq!(scaled.vertices()[1], Point2::new(6.0, 12.0));
553    /// # }
554    /// ```
555    ///
556    /// # Note
557    ///
558    /// This method consumes `self`. If you need to keep the original polyline,
559    /// clone it first:
560    ///
561    /// ```
562    /// # #[cfg(all(feature = "dim3", feature = "f32"))] {
563    /// use parry3d::shape::Polyline;
564    /// use nalgebra::{Point3, Vector3};
565    ///
566    /// let vertices = vec![Point3::origin(), Point3::new(1.0, 0.0, 0.0)];
567    /// let original = Polyline::new(vertices, None);
568    ///
569    /// // Clone before scaling if you need to keep the original
570    /// let scaled = original.clone().scaled(&Vector3::new(2.0, 2.0, 2.0));
571    ///
572    /// // Both polylines still exist
573    /// assert_eq!(original.vertices()[1].x, 1.0);
574    /// assert_eq!(scaled.vertices()[1].x, 2.0);
575    /// # }
576    /// ```
577    pub fn scaled(mut self, scale: &Vector<Real>) -> Self {
578        self.vertices
579            .iter_mut()
580            .for_each(|pt| pt.coords.component_mul_assign(scale));
581        let mut bvh = self.bvh.clone();
582        bvh.scale(scale);
583        Self {
584            bvh,
585            vertices: self.vertices,
586            indices: self.indices,
587        }
588    }
589
590    /// Reverses the orientation of this polyline.
591    ///
592    /// This operation:
593    /// 1. Swaps the start and end vertex of each segment (reversing edge direction)
594    /// 2. Reverses the order of segments in the index buffer
595    /// 3. Rebuilds the BVH to maintain correct acceleration structure
596    ///
597    /// After reversing, traversing the polyline segments in order will visit
598    /// the same geometry but in the opposite direction.
599    ///
600    /// # Example
601    ///
602    /// ```
603    /// # #[cfg(all(feature = "dim2", feature = "f32"))] {
604    /// use parry2d::shape::Polyline;
605    /// use nalgebra::Point2;
606    ///
607    /// let vertices = vec![
608    ///     Point2::origin(),
609    ///     Point2::new(1.0, 0.0),
610    ///     Point2::new(2.0, 0.0),
611    /// ];
612    /// let mut polyline = Polyline::new(vertices, None);
613    ///
614    /// // Original: segment 0 goes from vertex 0 to 1, segment 1 from 1 to 2
615    /// assert_eq!(polyline.indices()[0], [0, 1]);
616    /// assert_eq!(polyline.indices()[1], [1, 2]);
617    ///
618    /// // Reverse the polyline
619    /// polyline.reverse();
620    ///
621    /// // After reversing: order is flipped and directions are swapped
622    /// // The last segment becomes first, with swapped endpoints
623    /// assert_eq!(polyline.indices()[0], [2, 1]);
624    /// assert_eq!(polyline.indices()[1], [1, 0]);
625    /// # }
626    /// ```
627    ///
628    /// # Use Cases
629    ///
630    /// This is useful for:
631    /// - Correcting winding order for 2D shapes
632    /// - Reversing path direction for navigation
633    /// - Ensuring consistent edge orientation in connected components
634    pub fn reverse(&mut self) {
635        for idx in &mut self.indices {
636            idx.swap(0, 1);
637        }
638
639        self.indices.reverse();
640
641        // Rebuild the bvh since the segment indices no longer map to the correct element.
642        // TODO PERF: should the Bvh have a function for efficient leaf index remapping?
643        //            Probably not worth it unless this function starts showing up as a
644        //            bottleneck for someone.
645        let leaves = self.segments().map(|seg| seg.local_aabb()).enumerate();
646        let bvh = Bvh::from_iter(BvhBuildStrategy::Binned, leaves);
647        self.bvh = bvh;
648    }
649
650    /// Extracts the connected components of this polyline, consuming `self`.
651    ///
652    /// This method is currently quite restrictive on the kind of allowed input. The polyline
653    /// represented by `self` must already have an index buffer sorted such that:
654    /// - Each connected component appears in the index buffer one after the other, i.e., a
655    ///   connected component of this polyline must be a contiguous range of this polyline’s
656    ///   index buffer.
657    /// - Each connected component is closed, i.e., each range of this polyline index buffer
658    ///   `self.indices[i_start..=i_end]` forming a complete connected component, we must have
659    ///   `self.indices[i_start][0] == self.indices[i_end][1]`.
660    /// - The indices for each component must already be in order, i.e., if the segments
661    ///   `self.indices[i]` and `self.indices[i + 1]` are part of the same connected component then
662    ///   we must have `self.indices[i][1] == self.indices[i + 1][0]`.
663    ///
664    /// # Output
665    /// Returns the set of polylines. If the inputs fulfill the constraints mentioned above, each
666    /// polyline will be a closed loop with consistent edge orientations, i.e., for all indices `i`,
667    /// we have `polyline.indices[i][1] == polyline.indices[i + 1][0]`.
668    ///
669    /// The orientation of each closed loop (clockwise or counterclockwise) are identical to their
670    /// original orientation in `self`.
671    pub fn extract_connected_components(&self) -> Vec<Polyline> {
672        let vertices = self.vertices();
673        let indices = self.indices();
674
675        if indices.is_empty() {
676            // Polyline is empty, return empty Vec
677            Vec::new()
678        } else {
679            let mut components = Vec::new();
680
681            let mut start_i = 0; // Start position of component
682            let mut start_node = indices[0][0]; // Start vertex index of component
683
684            let mut component_vertices = Vec::new();
685            let mut component_indices: Vec<[u32; 2]> = Vec::new();
686
687            // Iterate over indices, building polylines as we go
688            for (i, idx) in indices.iter().enumerate() {
689                component_vertices.push(vertices[idx[0] as usize]);
690
691                if idx[1] != start_node {
692                    // Keep scanning and adding data
693                    component_indices.push([(i - start_i) as u32, (i - start_i + 1) as u32]);
694                } else {
695                    // Start node reached: build polyline and start next component
696                    component_indices.push([(i - start_i) as u32, 0]);
697                    components.push(Polyline::new(
698                        core::mem::take(&mut component_vertices),
699                        Some(core::mem::take(&mut component_indices)),
700                    ));
701
702                    if i + 1 < indices.len() {
703                        // More components to find
704                        start_node = indices[i + 1][0];
705                        start_i = i + 1;
706                    }
707                }
708            }
709
710            components
711        }
712    }
713
714    /// Perform a point projection assuming a solid interior based on a counter-clock-wise orientation.
715    ///
716    /// This is similar to `self.project_local_point_and_get_location` except that the resulting
717    /// `PointProjection::is_inside` will be set to true if the point is inside of the area delimited
718    /// by this polyline, assuming that:
719    /// - This polyline isn’t self-crossing.
720    /// - This polyline is closed with `self.indices[i][1] == self.indices[(i + 1) % num_indices][0]` where
721    ///   `num_indices == self.indices.len()`.
722    /// - This polyline is oriented counter-clockwise.
723    /// - In 3D, the polyline is assumed to be fully coplanar, on a plane with normal given by
724    ///   `axis`.
725    ///
726    /// These properties are not checked.
727    pub fn project_local_point_assuming_solid_interior_ccw(
728        &self,
729        point: Point<Real>,
730        #[cfg(feature = "dim3")] axis: u8,
731    ) -> (PointProjection, (u32, SegmentPointLocation)) {
732        let mut proj = self.project_local_point_and_get_location(&point, false);
733        let segment1 = self.segment((proj.1).0);
734
735        #[cfg(feature = "dim2")]
736        let normal1 = segment1.normal();
737        #[cfg(feature = "dim3")]
738        let normal1 = segment1.planar_normal(axis);
739
740        if let Some(normal1) = normal1 {
741            proj.0.is_inside = match proj.1 .1 {
742                SegmentPointLocation::OnVertex(i) => {
743                    let dir2 = if i == 0 {
744                        let adj_seg = if proj.1 .0 == 0 {
745                            self.indices().len() as u32 - 1
746                        } else {
747                            proj.1 .0 - 1
748                        };
749
750                        assert_eq!(segment1.a, self.segment(adj_seg).b);
751                        -self.segment(adj_seg).scaled_direction()
752                    } else {
753                        assert_eq!(i, 1);
754                        let adj_seg = (proj.1 .0 + 1) % self.indices().len() as u32;
755                        assert_eq!(segment1.b, self.segment(adj_seg).a);
756
757                        self.segment(adj_seg).scaled_direction()
758                    };
759
760                    let dot = normal1.dot(&dir2);
761                    // TODO: is this threshold too big? This corresponds to an angle equal to
762                    //       abs(acos(1.0e-3)) = (90 - 0.057) degrees.
763                    //       We did encounter some cases where this was needed, but perhaps the
764                    //       actual problem was an issue with the SegmentPointLocation (which should
765                    //       perhaps have been Edge instead of Vertex)?
766                    let threshold = 1.0e-3 * dir2.norm();
767                    if dot.abs() > threshold {
768                        // If the vertex is a reentrant vertex, then the point is
769                        // inside. Otherwise, it is outside.
770                        dot >= 0.0
771                    } else {
772                        // If the two edges are collinear, we can’t classify the vertex.
773                        // So check against the edge’s normal instead.
774                        (point - proj.0.point).dot(&normal1) <= 0.0
775                    }
776                }
777                SegmentPointLocation::OnEdge(_) => (point - proj.0.point).dot(&normal1) <= 0.0,
778            };
779        }
780
781        proj
782    }
783}
784
785impl CompositeShape for Polyline {
786    fn map_part_at(
787        &self,
788        i: u32,
789        f: &mut dyn FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>),
790    ) {
791        let tri = self.segment(i);
792        f(None, &tri, None)
793    }
794
795    fn bvh(&self) -> &Bvh {
796        &self.bvh
797    }
798}
799
800impl TypedCompositeShape for Polyline {
801    type PartShape = Segment;
802    type PartNormalConstraints = ();
803
804    #[inline(always)]
805    fn map_typed_part_at<T>(
806        &self,
807        i: u32,
808        mut f: impl FnMut(
809            Option<&Isometry<Real>>,
810            &Self::PartShape,
811            Option<&Self::PartNormalConstraints>,
812        ) -> T,
813    ) -> Option<T> {
814        let seg = self.segment(i);
815        Some(f(None, &seg, None))
816    }
817
818    #[inline(always)]
819    fn map_untyped_part_at<T>(
820        &self,
821        i: u32,
822        mut f: impl FnMut(Option<&Isometry<Real>>, &dyn Shape, Option<&dyn NormalConstraints>) -> T,
823    ) -> Option<T> {
824        let seg = self.segment(i);
825        Some(f(None, &seg, None))
826    }
827}