Skip to main content

egml_core/model/geometry/primitives/
line_string.rs

1use crate::model::geometry::primitives::{AbstractCurve, AsAbstractCurve, AsAbstractCurveMut};
2use crate::model::geometry::{DirectPosition, Envelope};
3use crate::{Error, impl_abstract_curve_traits};
4use nalgebra::Isometry3;
5
6/// An ordered sequence of two or more coordinate positions forming a 1-D curve.
7///
8/// Corresponds to `gml:LineString` in [OGC 07-036 §10.4.4](https://docs.ogc.org/is/07-036/07-036.pdf).
9#[derive(Debug, Clone, PartialEq, Default)]
10pub struct LineString {
11    pub(crate) abstract_curve: AbstractCurve,
12    points: Vec<DirectPosition>,
13}
14
15impl LineString {
16    /// Creates a new `LineString` from an ordered list of positions.
17    ///
18    /// # Errors
19    ///
20    /// Returns [`Error::TooFewElements`] if `points` contains fewer than 2 entries.
21    /// Returns [`Error::AdjacentDuplicatePositions`] if adjacent positions are equal.
22    pub fn new(abstract_curve: AbstractCurve, points: Vec<DirectPosition>) -> Result<Self, Error> {
23        if let Some((index, window)) = points.windows(2).enumerate().find(|(_, w)| w[0] == w[1]) {
24            return Err(Error::AdjacentDuplicatePositions {
25                index,
26                position: window[0],
27            });
28        }
29        if points.len() < 2 {
30            return Err(Error::TooFewElements {
31                geometry: "gml:LineString",
32                minimum: 2,
33                spec: Some("OGC 07-036 §10.4.4"),
34                id: None,
35                detail: None,
36            });
37        }
38
39        Ok(Self {
40            abstract_curve,
41            points,
42        })
43    }
44
45    /// Returns the ordered positions of this line string.
46    pub fn points(&self) -> &[DirectPosition] {
47        &self.points
48    }
49
50    /// Applies a rigid-body transform to all positions in place.
51    pub fn apply_transform(&mut self, m: &Isometry3<f64>) {
52        self.points.iter_mut().for_each(|p| {
53            p.apply_transform(m);
54        });
55    }
56
57    pub fn compute_envelope(&self) -> Envelope {
58        Envelope::from_points(&self.points).expect("line string must have valid points")
59    }
60}
61
62impl AsAbstractCurve for LineString {
63    fn abstract_curve(&self) -> &AbstractCurve {
64        &self.abstract_curve
65    }
66}
67
68impl AsAbstractCurveMut for LineString {
69    fn abstract_curve_mut(&mut self) -> &mut AbstractCurve {
70        &mut self.abstract_curve
71    }
72}
73
74impl_abstract_curve_traits!(LineString);