1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3
4mod bounding_box;
5mod coord;
6mod coords;
7mod relation;
8mod segment;
9#[cfg(test)]
10mod test;
11mod zine;
12mod zoint;
13mod zollection;
14mod zolygon;
15mod zulti_lines;
16mod zulti_points;
17mod zulti_polygons;
18
19use std::{io, mem};
20
21pub use bounding_box::BoundingBox;
22pub use coord::Coord;
23pub(crate) use coord::{COORD_SIZE_IN_BYTES, COORD_SIZE_IN_FLOATS};
24pub use coords::Coords;
25use geo::LineString;
26use geo_types::{Geometry, MultiPolygon, Polygon};
27pub use relation::{InputRelation, OutputRelation, RelationBetweenShapes};
28pub use segment::Segment;
29pub use zine::Zine;
30pub use zoint::Zoint;
31pub use zollection::Zollection;
32pub use zolygon::Zolygon;
33pub use zulti_lines::ZultiLines;
34pub use zulti_points::ZultiPoints;
35pub use zulti_polygons::ZultiPolygons;
36
37#[derive(Debug, Clone, Copy)]
39pub enum Zerometry<'a> {
40 Point(Zoint<'a>),
42 MultiPoints(ZultiPoints<'a>),
44 Line(Zine<'a>),
46 MultiLines(ZultiLines<'a>),
48 Polygon(Zolygon<'a>),
50 MultiPolygon(ZultiPolygons<'a>),
52 Collection(Zollection<'a>),
54}
55
56impl<'a> Zerometry<'a> {
57 #[inline]
63 pub unsafe fn from_bytes(data: &'a [u8]) -> Result<Self, std::io::Error> {
64 if data.len() < mem::size_of::<u64>() {
65 return Err(io::Error::new(
66 io::ErrorKind::UnexpectedEof,
67 format!(
68 "Was expecting at least {} bytes but found {}",
69 mem::size_of::<u64>(),
70 data.len()
71 ),
72 ));
73 }
74 let tag = u64::from_ne_bytes(
75 data[..mem::size_of::<u64>()]
76 .try_into()
77 .map_err(io::Error::other)?,
78 );
79 let data = &data[mem::size_of::<u64>()..];
80 match tag {
81 0 => Ok(Zerometry::Point(unsafe { Zoint::from_bytes(data) })),
82 1 => Ok(Zerometry::MultiPoints(unsafe {
83 ZultiPoints::from_bytes(data)
84 })),
85 2 => Ok(Zerometry::Polygon(unsafe { Zolygon::from_bytes(data) })),
86 3 => Ok(Zerometry::MultiPolygon(unsafe {
87 ZultiPolygons::from_bytes(data)
88 })),
89 4 => Ok(Zerometry::Line(unsafe { Zine::from_bytes(data) })),
91 5 => Ok(Zerometry::MultiLines(unsafe {
92 ZultiLines::from_bytes(data)
93 })),
94 6 => Ok(Zerometry::Collection(unsafe {
95 Zollection::from_bytes(data)
96 })),
97 _ => Err(std::io::Error::new(
98 std::io::ErrorKind::InvalidData,
99 "Invalid zerometry tag",
100 )),
101 }
102 }
103
104 pub fn write_from_geometry(
109 writer: &mut Vec<u8>,
110 geometry: &Geometry<f64>,
111 ) -> Result<(), std::io::Error> {
112 match geometry {
114 Geometry::Point(point) => {
115 writer.extend_from_slice(&0_u64.to_ne_bytes());
116 Zoint::write_from_geometry(writer, point)?;
117 }
118 Geometry::MultiPoint(multi_point) => {
119 writer.extend_from_slice(&1_u64.to_ne_bytes());
120 ZultiPoints::write_from_geometry(writer, multi_point)?;
121 }
122 Geometry::Polygon(polygon) => {
123 writer.extend_from_slice(&2_u64.to_ne_bytes());
124 Zolygon::write_from_geometry(writer, polygon)?;
125 }
126 Geometry::MultiPolygon(multi_polygon) => {
127 writer.extend_from_slice(&3_u64.to_ne_bytes());
128 ZultiPolygons::write_from_geometry(writer, multi_polygon)?;
129 }
130 Geometry::LineString(line_string) => {
131 writer.extend_from_slice(&4_u64.to_ne_bytes());
132 Zine::write_from_geometry(writer, line_string)?;
133 }
134 Geometry::MultiLineString(multi_line_string) => {
135 writer.extend_from_slice(&5_u64.to_ne_bytes());
136 ZultiLines::write_from_geometry(writer, multi_line_string)?;
137 }
138 Geometry::GeometryCollection(collection) => {
139 writer.extend_from_slice(&6_u64.to_ne_bytes());
140 Zollection::write_from_geometry(writer, collection)?;
141 }
142 Geometry::Line(line) => {
144 let line = LineString::new(vec![line.start, line.end]);
145 Self::write_from_geometry(writer, &line.into())?;
146 }
147 Geometry::Rect(rect) => {
148 Self::write_from_geometry(writer, &rect.to_polygon().into())?;
149 }
150 Geometry::Triangle(triangle) => {
151 Self::write_from_geometry(writer, &triangle.to_polygon().into())?;
152 }
153 }
154 Ok(())
155 }
156
157 #[inline]
159 pub fn to_point(&self) -> Option<Zoint<'_>> {
160 match self {
161 Zerometry::Point(a) => Some(*a),
162 _ => None,
163 }
164 }
165
166 #[inline]
168 pub fn to_multi_points(&self) -> Option<ZultiPoints<'_>> {
169 match self {
170 Zerometry::MultiPoints(a) => Some(*a),
171 _ => None,
172 }
173 }
174
175 #[inline]
177 pub fn to_line(&self) -> Option<Zine<'_>> {
178 match self {
179 Zerometry::Line(a) => Some(*a),
180 _ => None,
181 }
182 }
183
184 #[inline]
186 pub fn to_zulti_lines(&self) -> Option<ZultiLines<'_>> {
187 match self {
188 Zerometry::MultiLines(a) => Some(*a),
189 _ => None,
190 }
191 }
192
193 #[inline]
195 pub fn to_polygon(&self) -> Option<Zolygon<'_>> {
196 match self {
197 Zerometry::Polygon(a) => Some(*a),
198 _ => None,
199 }
200 }
201
202 #[inline]
204 pub fn to_multi_polygon(&self) -> Option<ZultiPolygons<'_>> {
205 match self {
206 Zerometry::MultiPolygon(a) => Some(*a),
207 _ => None,
208 }
209 }
210
211 #[inline]
213 pub fn to_collection(&self) -> Option<Zollection<'_>> {
214 match self {
215 Zerometry::Collection(a) => Some(*a),
216 _ => None,
217 }
218 }
219
220 pub fn to_geo(&self) -> geo_types::Geometry<f64> {
224 match self {
225 Zerometry::Point(a) => Geometry::Point(a.to_geo()),
226 Zerometry::MultiPoints(a) => Geometry::MultiPoint(a.to_geo()),
227 Zerometry::Line(a) => Geometry::LineString(a.to_geo()),
228 Zerometry::MultiLines(a) => Geometry::MultiLineString(a.to_geo()),
229 Zerometry::Polygon(a) => Geometry::Polygon(a.to_geo()),
230 Zerometry::MultiPolygon(a) => Geometry::MultiPolygon(a.to_geo()),
231 Zerometry::Collection(zollection) => Geometry::GeometryCollection(zollection.to_geo()),
232 }
233 }
234}
235
236impl<'a> From<Zoint<'a>> for Zerometry<'a> {
237 #[inline]
238 fn from(point: Zoint<'a>) -> Self {
239 Zerometry::Point(point)
240 }
241}
242
243impl<'a> From<ZultiPoints<'a>> for Zerometry<'a> {
244 #[inline]
245 fn from(points: ZultiPoints<'a>) -> Self {
246 Zerometry::MultiPoints(points)
247 }
248}
249
250impl<'a> From<Zolygon<'a>> for Zerometry<'a> {
251 #[inline]
252 fn from(polygon: Zolygon<'a>) -> Self {
253 Zerometry::Polygon(polygon)
254 }
255}
256
257impl<'a> From<ZultiPolygons<'a>> for Zerometry<'a> {
258 #[inline]
259 fn from(polygon: ZultiPolygons<'a>) -> Self {
260 Zerometry::MultiPolygon(polygon)
261 }
262}
263
264impl<'a> RelationBetweenShapes<Zoint<'a>> for Zerometry<'a> {
265 fn relation(&self, other: &Zoint, relation: InputRelation) -> OutputRelation {
266 match self {
267 Zerometry::Point(a) => a.relation(other, relation),
268 Zerometry::MultiPoints(a) => a.relation(other, relation),
269 Zerometry::Line(a) => a.relation(other, relation),
270 Zerometry::MultiLines(a) => a.relation(other, relation),
271 Zerometry::Polygon(a) => a.relation(other, relation),
272 Zerometry::MultiPolygon(a) => a.relation(other, relation),
273 Zerometry::Collection(a) => a.relation(other, relation),
274 }
275 }
276}
277
278impl<'a> RelationBetweenShapes<ZultiPoints<'a>> for Zerometry<'a> {
279 fn relation(&self, other: &ZultiPoints, relation: InputRelation) -> OutputRelation {
280 match self {
281 Zerometry::Point(a) => a.relation(other, relation),
282 Zerometry::MultiPoints(a) => a.relation(other, relation),
283 Zerometry::Line(a) => a.relation(other, relation),
284 Zerometry::MultiLines(a) => a.relation(other, relation),
285 Zerometry::Polygon(a) => a.relation(other, relation),
286 Zerometry::MultiPolygon(a) => a.relation(other, relation),
287 Zerometry::Collection(a) => a.relation(other, relation),
288 }
289 }
290}
291
292impl<'a> RelationBetweenShapes<Zine<'a>> for Zerometry<'a> {
293 fn relation(&self, other: &Zine, relation: InputRelation) -> OutputRelation {
294 match self {
295 Zerometry::Point(a) => a.relation(other, relation),
296 Zerometry::MultiPoints(a) => a.relation(other, relation),
297 Zerometry::MultiLines(a) => a.relation(other, relation),
298 Zerometry::Line(a) => a.relation(other, relation),
299 Zerometry::Polygon(a) => a.relation(other, relation),
300 Zerometry::MultiPolygon(a) => a.relation(other, relation),
301 Zerometry::Collection(a) => a.relation(other, relation),
302 }
303 }
304}
305
306impl<'a> RelationBetweenShapes<ZultiLines<'a>> for Zerometry<'a> {
307 fn relation(&self, other: &ZultiLines, relation: InputRelation) -> OutputRelation {
308 match self {
309 Zerometry::Point(a) => a.relation(other, relation),
310 Zerometry::MultiPoints(a) => a.relation(other, relation),
311 Zerometry::MultiLines(a) => a.relation(other, relation),
312 Zerometry::Line(a) => a.relation(other, relation),
313 Zerometry::Polygon(a) => a.relation(other, relation),
314 Zerometry::MultiPolygon(a) => a.relation(other, relation),
315 Zerometry::Collection(a) => a.relation(other, relation),
316 }
317 }
318}
319
320impl<'a> RelationBetweenShapes<Zolygon<'a>> for Zerometry<'a> {
321 fn relation(&self, other: &Zolygon, relation: InputRelation) -> OutputRelation {
322 match self {
323 Zerometry::Point(a) => a.relation(other, relation),
324 Zerometry::MultiPoints(a) => a.relation(other, relation),
325 Zerometry::MultiLines(a) => a.relation(other, relation),
326 Zerometry::Line(a) => a.relation(other, relation),
327 Zerometry::Polygon(a) => a.relation(other, relation),
328 Zerometry::MultiPolygon(a) => a.relation(other, relation),
329 Zerometry::Collection(a) => a.relation(other, relation),
330 }
331 }
332}
333
334impl<'a> RelationBetweenShapes<ZultiPolygons<'a>> for Zerometry<'a> {
335 fn relation(&self, other: &ZultiPolygons, relation: InputRelation) -> OutputRelation {
336 match self {
337 Zerometry::Point(a) => a.relation(other, relation),
338 Zerometry::MultiPoints(a) => a.relation(other, relation),
339 Zerometry::MultiLines(a) => a.relation(other, relation),
340 Zerometry::Line(a) => a.relation(other, relation),
341 Zerometry::Polygon(a) => a.relation(other, relation),
342 Zerometry::MultiPolygon(a) => a.relation(other, relation),
343 Zerometry::Collection(a) => a.relation(other, relation),
344 }
345 }
346}
347
348impl<'a> RelationBetweenShapes<Zollection<'a>> for Zerometry<'a> {
349 fn relation(&self, other: &Zollection, relation: InputRelation) -> OutputRelation {
350 match self {
351 Zerometry::Point(a) => a.relation(other, relation),
352 Zerometry::MultiPoints(a) => a.relation(other, relation),
353 Zerometry::MultiLines(a) => a.relation(other, relation),
354 Zerometry::Line(a) => a.relation(other, relation),
355 Zerometry::Polygon(a) => a.relation(other, relation),
356 Zerometry::MultiPolygon(a) => a.relation(other, relation),
357 Zerometry::Collection(a) => a.relation(other, relation),
358 }
359 }
360}
361
362impl<'a> RelationBetweenShapes<Zerometry<'a>> for Zerometry<'a> {
363 fn relation(&self, other: &Zerometry, relation: InputRelation) -> OutputRelation {
364 match other {
365 Zerometry::Point(a) => self.relation(a, relation),
366 Zerometry::MultiPoints(a) => self.relation(a, relation),
367 Zerometry::Line(a) => a.relation(other, relation),
368 Zerometry::MultiLines(a) => self.relation(a, relation),
369 Zerometry::Polygon(a) => self.relation(a, relation),
370 Zerometry::MultiPolygon(a) => self.relation(a, relation),
371 Zerometry::Collection(a) => self.relation(a, relation),
372 }
373 }
374}
375
376impl<'a> RelationBetweenShapes<Geometry<f64>> for Zerometry<'a> {
377 fn relation(&self, other: &Geometry<f64>, relation: InputRelation) -> OutputRelation {
378 let mut buffer = Vec::new();
379 Zerometry::write_from_geometry(&mut buffer, other).unwrap();
380 let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
381 self.relation(&other, relation)
382 }
383}
384
385impl<'a> RelationBetweenShapes<Zerometry<'a>> for Geometry<f64> {
386 fn relation(&self, other: &Zerometry<'a>, relation: InputRelation) -> OutputRelation {
387 let mut buffer = Vec::new();
388 Zerometry::write_from_geometry(&mut buffer, self).unwrap();
389 let this = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
390 this.relation(other, relation)
391 }
392}
393
394impl<'a> RelationBetweenShapes<Polygon<f64>> for Zerometry<'a> {
395 fn relation(&self, other: &Polygon<f64>, relation: InputRelation) -> OutputRelation {
396 let mut buffer = Vec::new();
397 Zerometry::write_from_geometry(&mut buffer, &Geometry::Polygon(other.clone())).unwrap();
398 let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
399 self.relation(&other, relation)
400 }
401}
402
403impl<'a> RelationBetweenShapes<MultiPolygon<f64>> for Zerometry<'a> {
404 fn relation(&self, other: &MultiPolygon<f64>, relation: InputRelation) -> OutputRelation {
405 let mut buffer = Vec::new();
406 Zerometry::write_from_geometry(&mut buffer, &Geometry::MultiPolygon(other.clone()))
407 .unwrap();
408 let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
409 self.relation(&other, relation)
410 }
411}
412
413impl PartialEq<Geometry> for Zerometry<'_> {
414 fn eq(&self, other: &Geometry) -> bool {
415 match (self, other) {
416 (Zerometry::Point(zoint), Geometry::Point(point)) => zoint.eq(point),
417 (Zerometry::MultiPoints(zulti_points), Geometry::MultiPoint(multi_point)) => {
418 zulti_points.eq(multi_point)
419 }
420 (Zerometry::Line(zine), Geometry::LineString(line_string)) => zine.eq(line_string),
421 (Zerometry::MultiLines(zulti_lines), Geometry::MultiLineString(multi_line_string)) => {
422 zulti_lines.eq(multi_line_string)
423 }
424 (Zerometry::Polygon(zolygon), Geometry::Polygon(polygon)) => zolygon.eq(polygon),
425 (Zerometry::MultiPolygon(zulti_polygon), Geometry::MultiPolygon(multi_polygon)) => {
426 zulti_polygon.eq(multi_polygon)
427 }
428 _ => false,
429 }
430 }
431}
432
433#[cfg(test)]
434mod zerometry_test {
435 use geo_types::geometry;
436
437 use crate::Zerometry;
438
439 #[test]
440 fn naive_point_roundtrip() {
441 let point = geometry::Geometry::Point(geometry::Point::new(45.0, 65.0));
442 let mut buf = Vec::new();
443 Zerometry::write_from_geometry(&mut buf, &point).unwrap();
444 let zoint = unsafe { Zerometry::from_bytes(&buf).unwrap() };
445 assert_eq!(zoint, point);
446 }
447
448 #[test]
449 fn naive_multi_point_roundtrip() {
450 let multi_point = geometry::Geometry::MultiPoint(geometry::MultiPoint::new(vec![]));
451 let mut buf = Vec::new();
452 Zerometry::write_from_geometry(&mut buf, &multi_point).unwrap();
453 let zulti_point = unsafe { Zerometry::from_bytes(&buf).unwrap() };
454 assert_eq!(zulti_point, multi_point);
455
456 let multi_point = geometry::Geometry::MultiPoint(geometry::MultiPoint::new(vec![
457 geometry::Point::new(45.0, 65.0),
458 geometry::Point::new(46.0, 66.0),
459 geometry::Point::new(44.0, 64.0),
460 geometry::Point::new(45.0, 65.0),
461 ]));
462 let mut buf = Vec::new();
463 Zerometry::write_from_geometry(&mut buf, &multi_point).unwrap();
464 let zulti_point = unsafe { Zerometry::from_bytes(&buf).unwrap() };
465 assert_eq!(zulti_point, multi_point);
466 }
467
468 #[test]
469 fn naive_line_string_roundtrip() {
470 let line_string = geometry::Geometry::LineString(geometry::LineString::new(vec![]));
471 let mut buf = Vec::new();
472 Zerometry::write_from_geometry(&mut buf, &line_string).unwrap();
473 let zine_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
474 assert_eq!(zine_string, line_string);
475
476 let line_string = geometry::Geometry::LineString(geometry::LineString::new(vec![
477 geometry::Coord { x: 45.0, y: 25.0 },
478 geometry::Coord { x: 46.0, y: 24.0 },
479 geometry::Coord { x: 45.0, y: 25.0 },
480 ]));
481 let mut buf = Vec::new();
482 Zerometry::write_from_geometry(&mut buf, &line_string).unwrap();
483 let zine_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
484 assert_eq!(zine_string, line_string);
485 }
486
487 #[test]
488 fn naive_multi_line_string_roundtrip() {
489 let multi_line_string =
490 geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![]));
491 let mut buf = Vec::new();
492 Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
493 let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
494 assert_eq!(zulti_line_string, multi_line_string);
495
496 let multi_line_string =
497 geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![
498 geometry::LineString::new(vec![
499 geometry::Coord { x: 45.0, y: 25.0 },
500 geometry::Coord { x: 46.0, y: 24.0 },
501 geometry::Coord { x: 45.0, y: 25.0 },
502 ]),
503 geometry::LineString::new(vec![]),
504 geometry::LineString::new(vec![
505 geometry::Coord { x: 66.0, y: 46.0 },
506 geometry::Coord { x: 47.0, y: 34.0 },
507 geometry::Coord { x: 66.0, y: 26.0 },
508 ]),
509 ]));
510 let mut buf = Vec::new();
511 Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
512 let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
513 assert_eq!(zulti_line_string, multi_line_string);
514
515 let multi_line_string =
516 geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![
517 geometry::LineString::new(vec![
518 geometry::Coord { x: 45.0, y: 25.0 },
519 geometry::Coord { x: 46.0, y: 24.0 },
520 geometry::Coord { x: 45.0, y: 25.0 },
521 ]),
522 geometry::LineString::new(vec![
523 geometry::Coord { x: 55.0, y: 25.0 },
524 geometry::Coord { x: 46.0, y: 34.0 },
525 geometry::Coord { x: 55.0, y: 25.0 },
526 ]),
527 geometry::LineString::new(vec![
528 geometry::Coord { x: 66.0, y: 46.0 },
529 geometry::Coord { x: 47.0, y: 34.0 },
530 geometry::Coord { x: 66.0, y: 26.0 },
531 ]),
532 ]));
533 let mut buf = Vec::new();
534 Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
535 let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
536 assert_eq!(zulti_line_string, multi_line_string);
537 }
538
539 #[test]
540 fn naive_polygon_roundtrip() {
541 let polygon = geometry::Geometry::Polygon(geometry::Polygon::new(
542 geometry::LineString::new(vec![]),
543 vec![],
544 ));
545 let mut buf = Vec::new();
546 Zerometry::write_from_geometry(&mut buf, &polygon).unwrap();
547 let zolygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
548 assert_eq!(zolygon, polygon);
549
550 let polygon = geometry::Geometry::Polygon(geometry::Polygon::new(
551 geometry::LineString::new(vec![
552 geometry::Coord { x: 66.0, y: 46.0 },
553 geometry::Coord { x: 47.0, y: 34.0 },
554 geometry::Coord { x: 66.0, y: 26.0 },
555 ]),
556 vec![],
557 ));
558 let mut buf = Vec::new();
559 Zerometry::write_from_geometry(&mut buf, &polygon).unwrap();
560 let zolygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
561 assert_eq!(zolygon, polygon);
562 }
563
564 #[test]
565 fn naive_multi_polygon_roundtrip() {
566 let multi_polygon = geometry::Geometry::MultiPolygon(geometry::MultiPolygon::new(vec![]));
567 let mut buf = Vec::new();
568 Zerometry::write_from_geometry(&mut buf, &multi_polygon).unwrap();
569 let zulti_polygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
570 assert_eq!(zulti_polygon, multi_polygon);
571
572 let multi_polygon = geometry::Geometry::MultiPolygon(geometry::MultiPolygon::new(vec![
573 geometry::Polygon::new(
574 geometry::LineString::new(vec![
575 geometry::Coord { x: 66.0, y: 46.0 },
576 geometry::Coord { x: 47.0, y: 34.0 },
577 geometry::Coord { x: 66.0, y: 26.0 },
578 ]),
579 vec![],
580 ),
581 geometry::Polygon::new(
582 geometry::LineString::new(vec![
583 geometry::Coord { x: 86.0, y: 48.0 },
584 geometry::Coord { x: 67.0, y: 36.0 },
585 geometry::Coord { x: 86.0, y: 28.0 },
586 ]),
587 vec![],
588 ),
589 ]));
590 let mut buf = Vec::new();
591 Zerometry::write_from_geometry(&mut buf, &multi_polygon).unwrap();
592 let zulti_polygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
593 assert_eq!(zulti_polygon, multi_polygon);
594 }
595
596 #[test]
597 fn naive_geometry_collection_roundtrip() {
598 }
607}