1use crate::search::*;
2
3#[derive(Debug, Clone, PartialEq, Serialize)]
8#[serde(tag = "type")]
9pub enum Shape {
10 #[serde(rename = "point")]
12 Point {
13 coordinates: Coordinate,
15 },
16
17 #[serde(rename = "linestring")]
19 LineString {
20 coordinates: Vec<Coordinate>,
22 },
23
24 #[serde(rename = "polygon")]
28 Polygon {
29 coordinates: Vec<Vec<Coordinate>>,
31 },
32
33 #[serde(rename = "multipoint")]
35 MultiPoint {
36 coordinates: Vec<Coordinate>,
38 },
39
40 #[serde(rename = "multilinestring")]
42 MultiLineString {
43 coordinates: Vec<Vec<Coordinate>>,
45 },
46
47 #[serde(rename = "multipolygon")]
49 MultiPolygon {
50 coordinates: Vec<Vec<Vec<Coordinate>>>,
52 },
53
54 #[serde(rename = "envelope")]
57 Envelope {
58 coordinates: (Coordinate, Coordinate),
60 },
61
62 #[serde(rename = "geometrycollection")]
65 GeometryCollection {
66 geometries: Vec<Shape>,
68 },
69}
70
71impl Shape {
72 pub fn point<T>(coordinates: T) -> Self
74 where
75 T: Into<Coordinate>,
76 {
77 Self::Point {
78 coordinates: coordinates.into(),
79 }
80 }
81
82 pub fn line_string<T>(coordinates: T) -> Self
84 where
85 T: IntoIterator,
86 T::Item: Into<Coordinate>,
87 {
88 Self::LineString {
89 coordinates: coordinates.into_iter().map(Into::into).collect(),
90 }
91 }
92
93 pub fn polygon<T>(coordinates: T) -> Self
95 where
96 T: IntoIterator,
97 T::Item: IntoIterator,
98 <T::Item as IntoIterator>::Item: Into<Coordinate>,
99 {
100 Self::Polygon {
101 coordinates: coordinates
102 .into_iter()
103 .map(|x| x.into_iter().map(Into::into).collect())
104 .collect(),
105 }
106 }
107
108 pub fn multi_point<T>(coordinates: T) -> Self
110 where
111 T: IntoIterator,
112 T::Item: Into<Coordinate>,
113 {
114 Self::MultiPoint {
115 coordinates: coordinates.into_iter().map(Into::into).collect(),
116 }
117 }
118
119 pub fn multi_line_string<T>(coordinates: T) -> Self
121 where
122 T: IntoIterator,
123 T::Item: IntoIterator,
124 <T::Item as IntoIterator>::Item: Into<Coordinate>,
125 {
126 Self::MultiLineString {
127 coordinates: coordinates
128 .into_iter()
129 .map(|x| x.into_iter().map(Into::into).collect())
130 .collect(),
131 }
132 }
133
134 pub fn multi_polygon<T>(coordinates: T) -> Self
136 where
137 T: IntoIterator,
138 T::Item: IntoIterator,
139 <T::Item as IntoIterator>::Item: IntoIterator,
140 <<T::Item as IntoIterator>::Item as IntoIterator>::Item: Into<Coordinate>,
141 {
142 Self::MultiPolygon {
143 coordinates: coordinates
144 .into_iter()
145 .map(|x| {
146 x.into_iter()
147 .map(|y| y.into_iter().map(Into::into).collect())
148 .collect()
149 })
150 .collect(),
151 }
152 }
153
154 pub fn envelope<T>(top_left: T, bottom_right: T) -> Self
156 where
157 T: Into<Coordinate>,
158 {
159 Self::Envelope {
160 coordinates: (top_left.into(), bottom_right.into()),
161 }
162 }
163
164 pub fn geometry_collection<T>(geometries: T) -> Self
166 where
167 T: IntoIterator,
168 T::Item: Into<Self>,
169 {
170 Self::GeometryCollection {
171 geometries: geometries.into_iter().map(Into::into).collect(),
172 }
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 use crate::util::*;
180
181 #[test]
182 fn serialization() {
183 assert_serialize(
184 Shape::point([-77.0, 38.0]),
185 json!({
186 "type": "point",
187 "coordinates": [-77.0, 38.0]
188 }),
189 );
190
191 assert_serialize(
192 Shape::line_string([[-77.0, 38.0], [-77.0, 38.0]]),
193 json!({
194 "type": "linestring",
195 "coordinates": [[-77.0, 38.0], [-77.0, 38.0]]
196 }),
197 );
198
199 assert_serialize(
200 Shape::polygon([
201 vec![
202 [-17.0, 10.0],
203 [16.0, 15.0],
204 [12.0, 0.0],
205 [16.0, -15.0],
206 [-17.0, -10.0],
207 [-17.0, 10.0],
208 ],
209 vec![[18.2, 8.2], [-18.8, 8.2], [-10.8, -8.8], [18.2, 8.2]],
210 ]),
211 json!({
212 "type": "polygon",
213 "coordinates": [
214 [
215 [-17.0, 10.0],
216 [16.0, 15.0],
217 [12.0, 0.0],
218 [16.0, -15.0],
219 [-17.0, -10.0],
220 [-17.0, 10.0],
221 ],
222 [
223 [18.2, 8.2],
224 [-18.8, 8.2],
225 [-10.8, -8.8],
226 [18.2, 8.2],
227 ],
228 ]
229 }),
230 );
231
232 assert_serialize(
233 Shape::multi_point([[-77.0, 38.0], [-77.0, 38.0]]),
234 json!({
235 "type": "multipoint",
236 "coordinates": [[-77.0, 38.0], [-77.0, 38.0]]
237 }),
238 );
239
240 assert_serialize(
241 Shape::multi_line_string([
242 [[12.0, 2.0], [13.0, 2.0], [13.0, 3.0], [12.0, 3.0]],
243 [[10.0, 0.0], [11.0, 0.0], [11.0, 1.0], [10.0, 1.0]],
244 [[10.2, 0.2], [10.8, 0.2], [10.8, 0.8], [12.0, 0.8]],
245 ]),
246 json!({
247 "type": "multilinestring",
248 "coordinates": [
249 [[12.0, 2.0], [13.0, 2.0], [13.0, 3.0], [12.0, 3.0]],
250 [[10.0, 0.0], [11.0, 0.0], [11.0, 1.0], [10.0, 1.0]],
251 [[10.2, 0.2], [10.8, 0.2], [10.8, 0.8], [12.0, 0.8]],
252 ]
253 }),
254 );
255
256 assert_serialize(
257 Shape::multi_polygon([
258 vec![
259 vec![
260 [-17.0, 10.0],
261 [16.0, 15.0],
262 [12.0, 0.0],
263 [16.0, -15.0],
264 [-17.0, -10.0],
265 [-17.0, 10.0],
266 ],
267 vec![[18.2, 8.2], [-18.8, 8.2], [-10.8, -8.8], [18.2, 8.2]],
268 ],
269 vec![vec![
270 [-15.0, 8.0],
271 [16.0, 15.0],
272 [12.0, 0.0],
273 [16.0, -15.0],
274 [-17.0, -10.0],
275 [-15.0, 8.0],
276 ]],
277 ]),
278 json!({
279 "type": "multipolygon",
280 "coordinates": [
281 [
282 [
283 [-17.0, 10.0],
284 [16.0, 15.0],
285 [12.0, 0.0],
286 [16.0, -15.0],
287 [-17.0, -10.0],
288 [-17.0, 10.0],
289 ],
290 [
291 [18.2, 8.2],
292 [-18.8, 8.2],
293 [-10.8, -8.8],
294 [18.2, 8.2],
295 ],
296 ],
297 [
298 [
299 [-15.0, 8.0],
300 [16.0, 15.0],
301 [12.0, 0.0],
302 [16.0, -15.0],
303 [-17.0, -10.0],
304 [-15.0, 8.0],
305 ]
306 ],
307 ]
308 }),
309 );
310
311 assert_serialize(
312 Shape::envelope([-77.0, 38.0], [-77.0, 38.0]),
313 json!({
314 "type": "envelope",
315 "coordinates": [[-77.0, 38.0], [-77.0, 38.0]]
316 }),
317 );
318
319 assert_serialize(
320 Shape::geometry_collection([
321 Shape::envelope([-77.0, 38.0], [-77.0, 38.0]),
322 Shape::point([-77.0, 38.0]),
323 ]),
324 json!({
325 "type": "geometrycollection",
326 "geometries": [
327 {
328 "type": "envelope",
329 "coordinates": [[-77.0, 38.0], [-77.0, 38.0]]
330 },
331 {
332 "type": "point",
333 "coordinates": [-77.0, 38.0]
334 },
335 ]
336 }),
337 );
338 }
339}