1use crate::wgs84::Wgs84;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[repr(i8)]
15pub enum Orientation {
16 Clockwise = -1,
18 InvalidOrientation = 0,
20 CounterClockwise = 1,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[repr(u8)]
27pub enum PolygonType {
28 SimplePolygon = 0,
31 TriangleStrip = 1,
33 TriangleFan = 2,
35 TriangleList = 3,
37 Unknown = 4,
39}
40
41#[derive(Debug, Clone, PartialEq)]
47pub struct Polygon {
48 polygon_type: PolygonType,
49 vertices: Vec<Wgs84>,
50}
51
52impl Polygon {
53 pub fn new(polygon_type: PolygonType) -> Self {
55 Polygon {
56 polygon_type,
57 vertices: Vec::new(),
58 }
59 }
60
61 pub fn with_vertices(polygon_type: PolygonType, vertices: Vec<Wgs84>) -> Self {
63 Polygon {
64 polygon_type,
65 vertices,
66 }
67 }
68
69 pub fn add_vertex(&mut self, position: Wgs84) {
71 self.vertices.push(position);
72 }
73
74 pub fn add_vertices(&mut self, vertices: &[Wgs84]) {
76 self.vertices.extend_from_slice(vertices);
77 }
78
79 pub fn get(&self, index: usize) -> Wgs84 {
81 self.vertices[index]
82 }
83
84 pub fn set(&mut self, index: usize, value: Wgs84) {
86 self.vertices[index] = value;
87 }
88
89 pub fn len(&self) -> usize {
91 self.vertices.len()
92 }
93
94 pub fn is_empty(&self) -> bool {
96 self.vertices.is_empty()
97 }
98
99 pub fn polygon_type(&self) -> PolygonType {
101 self.polygon_type
102 }
103
104 pub fn set_type(&mut self, polygon_type: PolygonType) {
106 self.polygon_type = polygon_type;
107 }
108
109 pub fn is_valid(&self) -> bool {
114 !self.vertices.is_empty()
115 }
116
117 pub fn vertices(&self) -> &[Wgs84] {
119 &self.vertices
120 }
121
122 pub fn vertices_mut(&mut self) -> &mut Vec<Wgs84> {
124 &mut self.vertices
125 }
126
127 pub fn orientation(&self) -> Orientation {
136 let is_supported = self.polygon_type == PolygonType::SimplePolygon
137 || (self.polygon_type == PolygonType::TriangleList && self.vertices.len() == 3);
138 if !is_supported {
139 return Orientation::InvalidOrientation;
140 }
141
142 let n = self.vertices.len();
143 let mut area = 0.0_f64;
144 for i in 0..n {
145 let j = if i + 1 == n { 0 } else { i + 1 };
146 area += self.vertices[i].lon * self.vertices[j].lat;
147 area -= self.vertices[i].lat * self.vertices[j].lon;
148 }
149
150 if area > 0.0 {
151 Orientation::CounterClockwise
152 } else if area < 0.0 {
153 Orientation::Clockwise
154 } else {
155 Orientation::InvalidOrientation
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 fn pts(coords: &[(f64, f64)]) -> Vec<Wgs84> {
165 coords.iter().map(|&(x, y)| Wgs84::new(x, y)).collect()
166 }
167
168 #[test]
169 fn base_is_valid_needs_one_vertex() {
170 let empty = Polygon::new(PolygonType::SimplePolygon);
171 assert!(!empty.is_valid());
172 assert!(empty.is_empty());
173 let mut one = Polygon::new(PolygonType::SimplePolygon);
174 one.add_vertex(Wgs84::new(0.0, 0.0));
175 assert!(one.is_valid());
176 }
177
178 #[test]
179 fn ccw_and_cw() {
180 let ccw = Polygon::with_vertices(
181 PolygonType::SimplePolygon,
182 pts(&[(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)]),
183 );
184 assert_eq!(ccw.orientation(), Orientation::CounterClockwise);
185
186 let cw = Polygon::with_vertices(
187 PolygonType::SimplePolygon,
188 pts(&[(0.0, 0.0), (0.0, 1.0), (1.0, 0.0)]),
189 );
190 assert_eq!(cw.orientation(), Orientation::Clockwise);
191 }
192
193 #[test]
194 fn collinear_is_invalid() {
195 let p = Polygon::with_vertices(
196 PolygonType::SimplePolygon,
197 pts(&[(0.0, 0.0), (1.0, 1.0), (2.0, 2.0)]),
198 );
199 assert_eq!(p.orientation(), Orientation::InvalidOrientation);
200 }
201
202 #[test]
203 fn unsupported_type_is_invalid() {
204 let strip = Polygon::with_vertices(
205 PolygonType::TriangleStrip,
206 pts(&[(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)]),
207 );
208 assert_eq!(strip.orientation(), Orientation::InvalidOrientation);
209
210 let multi = Polygon::with_vertices(
212 PolygonType::TriangleList,
213 pts(&[(0.0, 0.0), (4.0, 0.0), (4.0, 4.0), (0.0, 4.0)]),
214 );
215 assert_eq!(multi.orientation(), Orientation::InvalidOrientation);
216 }
217
218 #[test]
219 fn single_triangle_list_allowed() {
220 let t = Polygon::with_vertices(
221 PolygonType::TriangleList,
222 pts(&[(0.0, 0.0), (1.0, 0.0), (0.0, 1.0)]),
223 );
224 assert_eq!(t.orientation(), Orientation::CounterClockwise);
225 }
226
227 #[test]
228 fn get_set_and_accessors() {
229 let mut p = Polygon::new(PolygonType::Unknown);
230 p.add_vertices(&pts(&[(1.0, 2.0), (3.0, 4.0)]));
231 assert_eq!(p.len(), 2);
232 assert_eq!(p.polygon_type(), PolygonType::Unknown);
233 assert_eq!(p.get(0), Wgs84::new(1.0, 2.0));
234 p.set(0, Wgs84::new(5.0, 6.0));
235 assert_eq!(p.get(0), Wgs84::new(5.0, 6.0));
236 p.set_type(PolygonType::SimplePolygon);
237 assert_eq!(p.polygon_type(), PolygonType::SimplePolygon);
238 assert_eq!(p.vertices().len(), 2);
239 p.vertices_mut().push(Wgs84::new(7.0, 8.0));
240 assert_eq!(p.len(), 3);
241 }
242}