egml_core/model/geometry/primitives/
polygon.rs

1use crate::Error;
2use crate::model::base::AbstractGml;
3use crate::model::geometry::{DirectPosition, Envelope, LinearRing, Triangle, TriangulatedSurface};
4use crate::operations::geometry::Geometry;
5use crate::operations::surface::Surface;
6use crate::operations::triangulate::Triangulate;
7use nalgebra::Isometry3;
8use rayon::prelude::*;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct Polygon {
12    pub abstract_gml: AbstractGml,
13    pub exterior: LinearRing,
14    pub interior: Vec<LinearRing>,
15}
16
17impl Polygon {
18    pub fn new(
19        abstract_gml: AbstractGml,
20        exterior: LinearRing,
21        interior: Vec<LinearRing>,
22    ) -> Result<Self, Error> {
23        Ok(Self {
24            abstract_gml,
25            exterior,
26            interior,
27        })
28    }
29
30    pub fn get_envelope(&self) -> Envelope {
31        self.exterior.envelope()
32    }
33}
34
35impl Geometry for Polygon {
36    fn points(&self) -> Vec<&DirectPosition> {
37        let mut all_points = Vec::new();
38        all_points.extend(self.exterior.points());
39
40        for ring in &self.interior {
41            all_points.extend(ring.points().iter());
42        }
43
44        all_points
45    }
46
47    fn apply_transform(&mut self, m: &Isometry3<f64>) {
48        self.exterior.apply_transform(m);
49
50        self.interior.par_iter_mut().for_each(|p| {
51            p.apply_transform(m);
52        });
53    }
54}
55
56impl Surface for Polygon {
57    fn outer_boundary_points(&self) -> Vec<&DirectPosition> {
58        self.exterior.outer_boundary_points()
59    }
60}
61
62impl Triangulate for Polygon {
63    fn triangulate(&self) -> Result<TriangulatedSurface, Error> {
64        let mut exterior_buf = Vec::new();
65        let mut all_direct_positions: Vec<&DirectPosition> = self.exterior.points();
66        all_direct_positions.extend(self.interior.iter().flat_map(|x| x.points()));
67
68        let linear_ring_lengths: Vec<usize> = {
69            let mut vec = vec![self.exterior.points().len()];
70            vec.extend(self.interior.iter().map(|x| x.points().len()));
71            vec
72        };
73        let hole_indices: Vec<usize> = linear_ring_lengths
74            .iter()
75            .scan(0, |sum, e| {
76                *sum += e;
77                Some(*sum)
78            })
79            .take(linear_ring_lengths.len() - 1)
80            .collect();
81
82        let vertices = all_direct_positions
83            .iter()
84            .map(|p| p.coords())
85            .collect::<Vec<_>>();
86        earcut::utils3d::project3d_to_2d(&vertices, vertices.len(), &mut exterior_buf);
87
88        let mut triangle_indices: Vec<usize> = vec![];
89        let mut earcut = earcut::Earcut::new();
90        earcut.earcut(
91            exterior_buf.iter().copied(),
92            &hole_indices,
93            &mut triangle_indices,
94        );
95
96        let triangles: Vec<Triangle> = triangle_indices
97            .chunks(3)
98            .map(|x| {
99                let vertex_a = all_direct_positions[x[0]];
100                let vertex_b = all_direct_positions[x[1]];
101                let vertex_c = all_direct_positions[x[2]];
102                Triangle::new(*vertex_a, *vertex_b, *vertex_c).expect("should work")
103            })
104            .collect::<Vec<_>>();
105
106        let triangulated_surface = TriangulatedSurface::new(triangles)?;
107        Ok(triangulated_surface)
108    }
109}
110
111#[cfg(test)]
112mod test {
113    use super::*;
114
115    #[test]
116    fn test_polygon_triangulation() {
117        let abstract_gml =
118            AbstractGml::new("exterior_linear_ring_id".to_string().try_into().unwrap());
119        let linear_ring_exterior = LinearRing::new(
120            abstract_gml,
121            vec![
122                DirectPosition::new(0.0, 0.0, 0.0).expect("should work"),
123                DirectPosition::new(1.0, 0.0, 0.0).expect("should work"),
124                DirectPosition::new(1.0, 1.0, 2.0).expect("should work"),
125                DirectPosition::new(0.0, 1.0, 2.0).expect("should work"),
126            ],
127        )
128        .expect("should work");
129
130        let abstract_gml = AbstractGml::new("polygon_id".to_string().try_into().unwrap());
131        let polygon =
132            Polygon::new(abstract_gml, linear_ring_exterior, vec![]).expect("should work");
133        let triangulated_surface = polygon.triangulate().expect("should work");
134        assert_eq!(triangulated_surface.number_of_patches(), 2);
135    }
136
137    #[test]
138    fn test_polygon_with_interior_triangulation() {
139        let abstract_gml =
140            AbstractGml::new("exterior_linear_ring_id".to_string().try_into().unwrap());
141        let linear_ring_exterior = LinearRing::new(
142            abstract_gml,
143            vec![
144                DirectPosition::new(0.0, 0.0, 0.0).expect("should work"),
145                DirectPosition::new(1.0, 0.0, 0.0).expect("should work"),
146                DirectPosition::new(1.0, 1.0, 2.0).expect("should work"),
147                DirectPosition::new(0.0, 1.0, 2.0).expect("should work"),
148                DirectPosition::new(0.0, 1.0, 3.0).expect("should work"),
149                DirectPosition::new(0.0, 1.0, 5.0).expect("should work"),
150            ],
151        )
152        .expect("should work");
153
154        let abstract_gml =
155            AbstractGml::new("interior_linear_ring_id".to_string().try_into().unwrap());
156        let linear_ring_interior = LinearRing::new(
157            abstract_gml,
158            vec![
159                DirectPosition::new(0.5, 0.0, 0.0).expect("should work"),
160                DirectPosition::new(1.0, 0.0, 0.0).expect("should work"),
161                DirectPosition::new(1.0, 1.0, 2.0).expect("should work"),
162                DirectPosition::new(0.5, 1.0, 2.0).expect("should work"),
163            ],
164        )
165        .expect("should work");
166
167        let abstract_gml = AbstractGml::new("polygon_id".to_string().try_into().unwrap());
168        let polygon = Polygon::new(
169            abstract_gml,
170            linear_ring_exterior,
171            vec![linear_ring_interior.clone(), linear_ring_interior.clone()],
172        )
173        .expect("should work");
174        let triangulated_surface = polygon.triangulate().expect("should work");
175        // assert_eq!(triangulated_surface.number_of_patches(), 2);
176    }
177}