use core::fmt;
use std::io::{self, Write};
use geo::MultiPolygon;
use geo_types::{Geometry, Polygon};
use crate::{
BoundingBox, COORD_SIZE_IN_BYTES, COORD_SIZE_IN_FLOATS, Coord, Coords, InputRelation,
OutputRelation, RelationBetweenShapes, Segment, Zerometry, Zoint, Zollection, ZultiLines,
ZultiPoints, ZultiPolygons, zine::Zine,
};
#[derive(Clone, Copy)]
pub struct Zolygon<'a> {
bounding_box: &'a BoundingBox,
coords: &'a Coords,
}
impl<'a> Zolygon<'a> {
pub fn new(bounding_box: &'a BoundingBox, coords: &'a Coords) -> Self {
Self {
bounding_box,
coords,
}
}
#[inline]
pub unsafe fn from_bytes(data: &'a [u8]) -> Self {
debug_assert!(
data.len() % COORD_SIZE_IN_FLOATS == 0,
"Data length must be a multiple of {COORD_SIZE_IN_FLOATS}"
);
debug_assert!(
data.len() >= COORD_SIZE_IN_FLOATS * 2,
"Data length must be at least 2 coordinates to hold the bounding box"
);
debug_assert!(
data.as_ptr() as usize % COORD_SIZE_IN_FLOATS == 0,
"Data must be aligned to {COORD_SIZE_IN_FLOATS}"
);
let bounding_box = unsafe { BoundingBox::from_bytes(&data[0..COORD_SIZE_IN_BYTES * 2]) };
let coords = unsafe { Coords::from_bytes(&data[COORD_SIZE_IN_BYTES * 2..]) };
Self::new(bounding_box, coords)
}
pub fn write_from_geometry(
writer: &mut impl Write,
geometry: &Polygon<f64>,
) -> Result<(), io::Error> {
BoundingBox::write_from_geometry(writer, geometry.exterior().points())?;
for point in geometry.exterior().points() {
writer.write_all(&point.x().to_ne_bytes())?;
writer.write_all(&point.y().to_ne_bytes())?;
}
Ok(())
}
#[inline]
pub fn bounding_box(&self) -> &'a BoundingBox {
self.bounding_box
}
#[inline]
pub fn coords(&self) -> &'a Coords {
self.coords
}
#[inline]
pub fn segments(&self) -> impl Iterator<Item = Segment<'a>> {
self.coords
.consecutive_pairs()
.map(|coords| unsafe { Segment::from_slice(coords) })
}
#[inline]
pub fn is_empty(&self) -> bool {
self.coords.len() == 0
}
pub fn to_geo(&self) -> geo_types::Polygon<f64> {
geo_types::Polygon::new(
self.coords
.iter()
.map(|coord| geo_types::Point::new(coord.lng(), coord.lat()))
.collect(),
Vec::new(),
)
}
}
impl<'a> fmt::Debug for Zolygon<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Zolygon")
.field("bounding_box", &self.bounding_box)
.field("coords", &self.coords)
.finish()
}
}
impl<'a> RelationBetweenShapes<Coord> for Zolygon<'a> {
fn relation(&self, other: &Coord, relation: InputRelation) -> OutputRelation {
if self.is_empty() || !self.bounding_box.contains_coord(other) {
return relation.to_false().make_disjoint_if_set();
}
let end = other;
let mut buffer = [0.0; COORD_SIZE_IN_FLOATS];
let start = unsafe { Coord::from_slice_mut(&mut buffer) };
*start.lng_mut() = self.bounding_box.left();
*start.lat_mut() = end.lat();
let ray = Segment::from_coord_pair(start, end);
let mut intersections = 0;
for segment in self.segments() {
if segment.intersects(&ray) {
intersections += 1;
}
}
if intersections % 2 == 0 {
relation.to_false().make_disjoint_if_set()
} else {
relation.to_false().make_strict_contains_if_set()
}
}
}
impl<'a> RelationBetweenShapes<Zoint<'a>> for Zolygon<'a> {
fn relation(&self, other: &Zoint<'a>, relation: InputRelation) -> OutputRelation {
self.relation(other.coord(), relation)
}
}
impl<'a> RelationBetweenShapes<ZultiPoints<'a>> for Zolygon<'a> {
fn relation(&self, other: &ZultiPoints<'a>, relation: InputRelation) -> OutputRelation {
let mut output = relation.to_false();
if self.bounding_box().disjoint(other.bounding_box()) {
return output.make_disjoint_if_set();
}
let mut contains = 0;
for coord in other.coords().iter() {
if self.contains(coord) {
contains += 1;
output = output.make_contains_if_set();
if !relation.strict_contains || relation.early_exit {
return output;
}
}
}
if contains == other.len() {
output = output.make_strict_contains_if_set();
}
if output.any_relation() {
output
} else {
output.make_disjoint_if_set()
}
}
}
impl<'a> RelationBetweenShapes<Zine<'a>> for Zolygon<'a> {
fn relation(&self, other: &Zine<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> RelationBetweenShapes<ZultiLines<'a>> for Zolygon<'a> {
fn relation(&self, other: &ZultiLines<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> RelationBetweenShapes<Zolygon<'a>> for Zolygon<'a> {
fn relation(&self, other: &Zolygon<'a>, relation: InputRelation) -> OutputRelation {
let output = relation.to_false();
if self.is_empty() || other.is_empty() || self.bounding_box().disjoint(other.bounding_box())
{
return output.make_disjoint_if_set();
}
for segment in self.segments() {
for other_segment in other.segments() {
if segment.intersects(&other_segment) {
return output.make_intersect_if_set();
}
}
}
let any = self.coords().iter().next().unwrap();
if other.contains(any) {
return output.make_strict_contained_if_set();
}
let any = other.coords().iter().next().unwrap();
if self.contains(any) {
return output.make_strict_contains_if_set();
}
output.make_disjoint_if_set()
}
}
impl<'a> RelationBetweenShapes<ZultiPolygons<'a>> for Zolygon<'a> {
fn relation(&self, other: &ZultiPolygons<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> RelationBetweenShapes<Zollection<'a>> for Zolygon<'a> {
fn relation(&self, other: &Zollection<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> RelationBetweenShapes<Zerometry<'a>> for Zolygon<'a> {
fn relation(&self, other: &Zerometry<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> RelationBetweenShapes<Polygon<f64>> for Zolygon<'a> {
fn relation(&self, other: &Polygon<f64>, relation: InputRelation) -> OutputRelation {
let mut buffer = Vec::new();
Zerometry::write_from_geometry(&mut buffer, &Geometry::Polygon(other.clone())).unwrap();
let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
self.relation(&other, relation)
}
}
impl<'a> RelationBetweenShapes<MultiPolygon<f64>> for Zolygon<'a> {
fn relation(&self, other: &MultiPolygon<f64>, relation: InputRelation) -> OutputRelation {
let mut buffer = Vec::new();
ZultiPolygons::write_from_geometry(&mut buffer, other).unwrap();
let other = unsafe { ZultiPolygons::from_bytes(&buffer) };
self.relation(&other, relation)
}
}
impl<'a> RelationBetweenShapes<Zolygon<'a>> for Polygon<f64> {
fn relation(&self, other: &Zolygon<'a>, relation: InputRelation) -> OutputRelation {
other
.relation(self, relation.swap_contains_relation())
.swap_contains_relation()
}
}
impl<'a> PartialEq<Polygon<f64>> for Zolygon<'a> {
fn eq(&self, other: &Polygon<f64>) -> bool {
if !other.interiors().is_empty() {
return false;
}
self.coords
.iter()
.zip(other.exterior().points())
.all(|(a, b)| a.lng() == b.x() && a.lat() == b.y())
}
}
#[cfg(test)]
mod tests {
use bytemuck::cast_slice;
use geo::{MultiPoint, point, polygon};
use geo_types::{LineString, Point};
use insta::{assert_compact_debug_snapshot, assert_debug_snapshot};
use super::*;
#[test]
fn test_zolygon_binary_format() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: -10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: -10.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let input: &[f64] = cast_slice(&buffer);
assert_debug_snapshot!(input, @r"
[
-10.0,
-10.0,
10.0,
10.0,
-10.0,
0.0,
10.0,
-10.0,
10.0,
10.0,
0.0,
10.0,
-10.0,
0.0,
]
");
let zolygon = unsafe { Zolygon::from_bytes(&buffer) };
insta::assert_debug_snapshot!(zolygon.bounding_box(), @r"
BoundingBox {
bottom_left: Coord {
x: -10.0,
y: -10.0,
},
top_right: Coord {
x: 10.0,
y: 10.0,
},
}
");
insta::assert_debug_snapshot!(zolygon.coords(), @r"
[
Coord {
x: -10.0,
y: 0.0,
},
Coord {
x: 10.0,
y: -10.0,
},
Coord {
x: 10.0,
y: 10.0,
},
Coord {
x: 0.0,
y: 10.0,
},
Coord {
x: -10.0,
y: 0.0,
},
]
");
}
#[test]
fn test_zolygon_empty_binary_format() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(LineString::new(vec![]), Vec::new()),
)
.unwrap();
let input: &[f64] = cast_slice(&buffer);
assert_debug_snapshot!(input, @r"
[
0.0,
0.0,
0.0,
0.0,
]
");
let zolygon = unsafe { Zolygon::from_bytes(&buffer) };
insta::assert_debug_snapshot!(zolygon.bounding_box(), @r"
BoundingBox {
bottom_left: Coord {
x: 0.0,
y: 0.0,
},
top_right: Coord {
x: 0.0,
y: 0.0,
},
}
");
insta::assert_debug_snapshot!(zolygon.coords(), @"[]");
}
#[test]
fn test_zolygon_relation_to_zoint() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let zoint_inside_bytes = buffer.len();
Zoint::write_from_geometry(&mut buffer, &Point::new(5.0, 5.0)).unwrap();
let zoint_outside_bytes = buffer.len();
Zoint::write_from_geometry(&mut buffer, &Point::new(15.0, 15.0)).unwrap();
let zolygon = unsafe { Zolygon::from_bytes(&buffer[..zoint_inside_bytes]) };
let point_inside =
unsafe { Zoint::from_bytes(&buffer[zoint_inside_bytes..zoint_outside_bytes]) };
let point_outside = unsafe { Zoint::from_bytes(&buffer[zoint_outside_bytes..]) };
assert_compact_debug_snapshot!(
zolygon.all_relation(&point_inside),
@"OutputRelation { contains: Some(true), strict_contains: Some(true), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }"
);
assert_compact_debug_snapshot!(
zolygon.all_relation(&point_outside),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_intersects_basic() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 5.0, y: 5.0 },
geo_types::Coord { x: 15.0, y: 5.0 },
geo_types::Coord { x: 15.0, y: 15.0 },
geo_types::Coord { x: 5.0, y: 15.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_intersects_diagonal() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 5.0, y: 7.0 },
geo_types::Coord { x: 8.0, y: 10.0 },
geo_types::Coord { x: 5.0, y: 13.0 },
geo_types::Coord { x: 2.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_intersects_on_edge() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 15.0, y: 0.0 },
geo_types::Coord { x: 15.0, y: 10.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(true), disjoint: Some(false) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_contains() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 1.0, y: 1.0 },
geo_types::Coord { x: 1.0, y: 9.0 },
geo_types::Coord { x: 9.0, y: 9.0 },
geo_types::Coord { x: 9.0, y: 1.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(true), strict_contains: Some(true), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(false), disjoint: Some(false) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_disjoint_basic() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
geo_types::Coord { x: 0.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 15.0, y: 15.0 },
geo_types::Coord { x: 15.0, y: 25.0 },
geo_types::Coord { x: 25.0, y: 25.0 },
geo_types::Coord { x: 25.0, y: 15.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }"
);
}
#[test]
fn test_zolygon_relation_to_zolygon_disjoint_near() {
let mut buffer = Vec::new();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 0.0 },
geo_types::Coord { x: 10.0, y: 10.0 },
]),
Vec::new(),
),
)
.unwrap();
let first = buffer.len();
Zolygon::write_from_geometry(
&mut buffer,
&Polygon::new(
LineString::new(vec![
geo_types::Coord { x: 0.0, y: 1.0 },
geo_types::Coord { x: 10.0, y: 11.0 },
geo_types::Coord { x: 0.0, y: 11.0 },
]),
Vec::new(),
),
)
.unwrap();
let second = buffer.len();
let first_zolygon = unsafe { Zolygon::from_bytes(&buffer[..first]) };
let second_zolygon = unsafe { Zolygon::from_bytes(&buffer[first..second]) };
assert_compact_debug_snapshot!(
first_zolygon.all_relation(&second_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }"
);
assert_compact_debug_snapshot!(
second_zolygon.all_relation(&first_zolygon),
@"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }"
);
}
#[test]
fn test_multi_points_and_polygon() {
let polygon = polygon![
(x: 0., y: 0.),
(x: 1., y: 0.),
(x: 1., y: 1.),
(x: 0., y: 1.),
];
let mut buf = Vec::new();
Zolygon::write_from_geometry(&mut buf, &polygon).unwrap();
let zolygon = unsafe { Zolygon::from_bytes(&buf) };
let inside = point! { x: 0.5, y: 0.5};
let inside2 = point! { x: 0.6, y: 0.6};
let outside = point! { x: 1.5, y: 1.5};
let outside2 = point! { x: 1.6, y: 1.6};
let mp_strict_inside = MultiPoint::new(vec![inside]);
let mp_strict_inside_2 = MultiPoint::new(vec![inside, inside2]);
let mp_strict_outside = MultiPoint::new(vec![outside]);
let mp_strict_outside_2 = MultiPoint::new(vec![outside, outside2]);
let mp_inside = MultiPoint::new(vec![inside, outside]);
let mp_inside2 = MultiPoint::new(vec![inside, inside2, outside]);
let mp_inside4 = MultiPoint::new(vec![inside, outside, outside2]);
let mp_inside3 = MultiPoint::new(vec![inside, inside2, outside, outside2]);
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_strict_inside).unwrap();
let mp_strict_inside = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_strict_inside.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(false), disjoint: Some(false) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_strict_inside_2).unwrap();
let mp_strict_inside_2 = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_strict_inside_2.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(true), intersect: Some(false), disjoint: Some(false) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_strict_outside).unwrap();
let mp_strict_outside = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_strict_outside.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_strict_outside_2).unwrap();
let mp_strict_outside_2 = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_strict_outside_2.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(false), strict_contained: Some(false), intersect: Some(false), disjoint: Some(true) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_inside).unwrap();
let mp_inside = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_inside.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_inside2).unwrap();
let mp_inside2 = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_inside2.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_inside4).unwrap();
let mp_inside4 = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_inside4.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
let mut buf = Vec::new();
ZultiPoints::write_from_geometry(&mut buf, &mp_inside3).unwrap();
let mp_inside3 = unsafe { ZultiPoints::from_bytes(&buf) };
assert_compact_debug_snapshot!(mp_inside3.all_relation(&zolygon), @"OutputRelation { contains: Some(false), strict_contains: Some(false), contained: Some(true), strict_contained: Some(false), intersect: Some(false), disjoint: Some(false) }");
}
proptest::proptest! {
#[test]
fn test_zolygon_round_trip(points: Vec<(f64, f64)>) {
let polygon = Polygon::new(LineString::new(points.iter().map(|(x, y)| geo_types::Coord { x: *x, y: *y }).collect()), Vec::new());
let mut buffer = Vec::new();
Zolygon::write_from_geometry(&mut buffer, &polygon).unwrap();
let zolygon = unsafe { Zolygon::from_bytes(&buffer) };
assert_eq!(zolygon, polygon);
}
}
}