#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
mod bounding_box;
mod coord;
mod coords;
mod relation;
mod segment;
#[cfg(test)]
mod test;
mod zine;
mod zoint;
mod zollection;
mod zolygon;
mod zulti_lines;
mod zulti_points;
mod zulti_polygons;
use std::{io, mem};
pub use bounding_box::BoundingBox;
pub use coord::Coord;
pub(crate) use coord::{COORD_SIZE_IN_BYTES, COORD_SIZE_IN_FLOATS};
pub use coords::Coords;
use geo::LineString;
use geo_types::{Geometry, MultiPolygon, Polygon};
pub use relation::{InputRelation, OutputRelation, RelationBetweenShapes};
pub use segment::Segment;
pub use zine::Zine;
pub use zoint::Zoint;
pub use zollection::Zollection;
pub use zolygon::Zolygon;
pub use zulti_lines::ZultiLines;
pub use zulti_points::ZultiPoints;
pub use zulti_polygons::ZultiPolygons;
#[derive(Debug, Clone, Copy)]
pub enum Zerometry<'a> {
Point(Zoint<'a>),
MultiPoints(ZultiPoints<'a>),
Line(Zine<'a>),
MultiLines(ZultiLines<'a>),
Polygon(Zolygon<'a>),
MultiPolygon(ZultiPolygons<'a>),
Collection(Zollection<'a>),
}
impl<'a> Zerometry<'a> {
#[inline]
pub unsafe fn from_bytes(data: &'a [u8]) -> Result<Self, std::io::Error> {
if data.len() < mem::size_of::<u64>() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
format!(
"Was expecting at least {} bytes but found {}",
mem::size_of::<u64>(),
data.len()
),
));
}
let tag = u64::from_ne_bytes(
data[..mem::size_of::<u64>()]
.try_into()
.map_err(io::Error::other)?,
);
let data = &data[mem::size_of::<u64>()..];
match tag {
0 => Ok(Zerometry::Point(unsafe { Zoint::from_bytes(data) })),
1 => Ok(Zerometry::MultiPoints(unsafe {
ZultiPoints::from_bytes(data)
})),
2 => Ok(Zerometry::Polygon(unsafe { Zolygon::from_bytes(data) })),
3 => Ok(Zerometry::MultiPolygon(unsafe {
ZultiPolygons::from_bytes(data)
})),
4 => Ok(Zerometry::Line(unsafe { Zine::from_bytes(data) })),
5 => Ok(Zerometry::MultiLines(unsafe {
ZultiLines::from_bytes(data)
})),
6 => Ok(Zerometry::Collection(unsafe {
Zollection::from_bytes(data)
})),
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Invalid zerometry tag",
)),
}
}
pub fn write_from_geometry(
writer: &mut Vec<u8>,
geometry: &Geometry<f64>,
) -> Result<(), std::io::Error> {
match geometry {
Geometry::Point(point) => {
writer.extend_from_slice(&0_u64.to_ne_bytes());
Zoint::write_from_geometry(writer, point)?;
}
Geometry::MultiPoint(multi_point) => {
writer.extend_from_slice(&1_u64.to_ne_bytes());
ZultiPoints::write_from_geometry(writer, multi_point)?;
}
Geometry::Polygon(polygon) => {
writer.extend_from_slice(&2_u64.to_ne_bytes());
Zolygon::write_from_geometry(writer, polygon)?;
}
Geometry::MultiPolygon(multi_polygon) => {
writer.extend_from_slice(&3_u64.to_ne_bytes());
ZultiPolygons::write_from_geometry(writer, multi_polygon)?;
}
Geometry::LineString(line_string) => {
writer.extend_from_slice(&4_u64.to_ne_bytes());
Zine::write_from_geometry(writer, line_string)?;
}
Geometry::MultiLineString(multi_line_string) => {
writer.extend_from_slice(&5_u64.to_ne_bytes());
ZultiLines::write_from_geometry(writer, multi_line_string)?;
}
Geometry::GeometryCollection(collection) => {
writer.extend_from_slice(&6_u64.to_ne_bytes());
Zollection::write_from_geometry(writer, collection)?;
}
Geometry::Line(line) => {
let line = LineString::new(vec![line.start, line.end]);
Self::write_from_geometry(writer, &line.into())?;
}
Geometry::Rect(rect) => {
Self::write_from_geometry(writer, &rect.to_polygon().into())?;
}
Geometry::Triangle(triangle) => {
Self::write_from_geometry(writer, &triangle.to_polygon().into())?;
}
}
Ok(())
}
#[inline]
pub fn to_point(&self) -> Option<Zoint<'_>> {
match self {
Zerometry::Point(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_multi_points(&self) -> Option<ZultiPoints<'_>> {
match self {
Zerometry::MultiPoints(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_line(&self) -> Option<Zine<'_>> {
match self {
Zerometry::Line(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_zulti_lines(&self) -> Option<ZultiLines<'_>> {
match self {
Zerometry::MultiLines(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_polygon(&self) -> Option<Zolygon<'_>> {
match self {
Zerometry::Polygon(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_multi_polygon(&self) -> Option<ZultiPolygons<'_>> {
match self {
Zerometry::MultiPolygon(a) => Some(*a),
_ => None,
}
}
#[inline]
pub fn to_collection(&self) -> Option<Zollection<'_>> {
match self {
Zerometry::Collection(a) => Some(*a),
_ => None,
}
}
pub fn to_geo(&self) -> geo_types::Geometry<f64> {
match self {
Zerometry::Point(a) => Geometry::Point(a.to_geo()),
Zerometry::MultiPoints(a) => Geometry::MultiPoint(a.to_geo()),
Zerometry::Line(a) => Geometry::LineString(a.to_geo()),
Zerometry::MultiLines(a) => Geometry::MultiLineString(a.to_geo()),
Zerometry::Polygon(a) => Geometry::Polygon(a.to_geo()),
Zerometry::MultiPolygon(a) => Geometry::MultiPolygon(a.to_geo()),
Zerometry::Collection(zollection) => Geometry::GeometryCollection(zollection.to_geo()),
}
}
}
impl<'a> From<Zoint<'a>> for Zerometry<'a> {
#[inline]
fn from(point: Zoint<'a>) -> Self {
Zerometry::Point(point)
}
}
impl<'a> From<ZultiPoints<'a>> for Zerometry<'a> {
#[inline]
fn from(points: ZultiPoints<'a>) -> Self {
Zerometry::MultiPoints(points)
}
}
impl<'a> From<Zolygon<'a>> for Zerometry<'a> {
#[inline]
fn from(polygon: Zolygon<'a>) -> Self {
Zerometry::Polygon(polygon)
}
}
impl<'a> From<ZultiPolygons<'a>> for Zerometry<'a> {
#[inline]
fn from(polygon: ZultiPolygons<'a>) -> Self {
Zerometry::MultiPolygon(polygon)
}
}
impl<'a> RelationBetweenShapes<Zoint<'a>> for Zerometry<'a> {
fn relation(&self, other: &Zoint, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<ZultiPoints<'a>> for Zerometry<'a> {
fn relation(&self, other: &ZultiPoints, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<Zine<'a>> for Zerometry<'a> {
fn relation(&self, other: &Zine, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<ZultiLines<'a>> for Zerometry<'a> {
fn relation(&self, other: &ZultiLines, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<Zolygon<'a>> for Zerometry<'a> {
fn relation(&self, other: &Zolygon, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<ZultiPolygons<'a>> for Zerometry<'a> {
fn relation(&self, other: &ZultiPolygons, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<Zollection<'a>> for Zerometry<'a> {
fn relation(&self, other: &Zollection, relation: InputRelation) -> OutputRelation {
match self {
Zerometry::Point(a) => a.relation(other, relation),
Zerometry::MultiPoints(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => a.relation(other, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::Polygon(a) => a.relation(other, relation),
Zerometry::MultiPolygon(a) => a.relation(other, relation),
Zerometry::Collection(a) => a.relation(other, relation),
}
}
}
impl<'a> RelationBetweenShapes<Zerometry<'a>> for Zerometry<'a> {
fn relation(&self, other: &Zerometry, relation: InputRelation) -> OutputRelation {
match other {
Zerometry::Point(a) => self.relation(a, relation),
Zerometry::MultiPoints(a) => self.relation(a, relation),
Zerometry::Line(a) => a.relation(other, relation),
Zerometry::MultiLines(a) => self.relation(a, relation),
Zerometry::Polygon(a) => self.relation(a, relation),
Zerometry::MultiPolygon(a) => self.relation(a, relation),
Zerometry::Collection(a) => self.relation(a, relation),
}
}
}
impl<'a> RelationBetweenShapes<Geometry<f64>> for Zerometry<'a> {
fn relation(&self, other: &Geometry<f64>, relation: InputRelation) -> OutputRelation {
let mut buffer = Vec::new();
Zerometry::write_from_geometry(&mut buffer, other).unwrap();
let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
self.relation(&other, relation)
}
}
impl<'a> RelationBetweenShapes<Zerometry<'a>> for Geometry<f64> {
fn relation(&self, other: &Zerometry<'a>, relation: InputRelation) -> OutputRelation {
let mut buffer = Vec::new();
Zerometry::write_from_geometry(&mut buffer, self).unwrap();
let this = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
this.relation(other, relation)
}
}
impl<'a> RelationBetweenShapes<Polygon<f64>> for Zerometry<'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 Zerometry<'a> {
fn relation(&self, other: &MultiPolygon<f64>, relation: InputRelation) -> OutputRelation {
let mut buffer = Vec::new();
Zerometry::write_from_geometry(&mut buffer, &Geometry::MultiPolygon(other.clone()))
.unwrap();
let other = unsafe { Zerometry::from_bytes(&buffer).unwrap() };
self.relation(&other, relation)
}
}
impl PartialEq<Geometry> for Zerometry<'_> {
fn eq(&self, other: &Geometry) -> bool {
match (self, other) {
(Zerometry::Point(zoint), Geometry::Point(point)) => zoint.eq(point),
(Zerometry::MultiPoints(zulti_points), Geometry::MultiPoint(multi_point)) => {
zulti_points.eq(multi_point)
}
(Zerometry::Line(zine), Geometry::LineString(line_string)) => zine.eq(line_string),
(Zerometry::MultiLines(zulti_lines), Geometry::MultiLineString(multi_line_string)) => {
zulti_lines.eq(multi_line_string)
}
(Zerometry::Polygon(zolygon), Geometry::Polygon(polygon)) => zolygon.eq(polygon),
(Zerometry::MultiPolygon(zulti_polygon), Geometry::MultiPolygon(multi_polygon)) => {
zulti_polygon.eq(multi_polygon)
}
_ => false,
}
}
}
#[cfg(test)]
mod zerometry_test {
use geo_types::geometry;
use crate::Zerometry;
#[test]
fn naive_point_roundtrip() {
let point = geometry::Geometry::Point(geometry::Point::new(45.0, 65.0));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &point).unwrap();
let zoint = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zoint, point);
}
#[test]
fn naive_multi_point_roundtrip() {
let multi_point = geometry::Geometry::MultiPoint(geometry::MultiPoint::new(vec![]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_point).unwrap();
let zulti_point = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_point, multi_point);
let multi_point = geometry::Geometry::MultiPoint(geometry::MultiPoint::new(vec![
geometry::Point::new(45.0, 65.0),
geometry::Point::new(46.0, 66.0),
geometry::Point::new(44.0, 64.0),
geometry::Point::new(45.0, 65.0),
]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_point).unwrap();
let zulti_point = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_point, multi_point);
}
#[test]
fn naive_line_string_roundtrip() {
let line_string = geometry::Geometry::LineString(geometry::LineString::new(vec![]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &line_string).unwrap();
let zine_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zine_string, line_string);
let line_string = geometry::Geometry::LineString(geometry::LineString::new(vec![
geometry::Coord { x: 45.0, y: 25.0 },
geometry::Coord { x: 46.0, y: 24.0 },
geometry::Coord { x: 45.0, y: 25.0 },
]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &line_string).unwrap();
let zine_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zine_string, line_string);
}
#[test]
fn naive_multi_line_string_roundtrip() {
let multi_line_string =
geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_line_string, multi_line_string);
let multi_line_string =
geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![
geometry::LineString::new(vec![
geometry::Coord { x: 45.0, y: 25.0 },
geometry::Coord { x: 46.0, y: 24.0 },
geometry::Coord { x: 45.0, y: 25.0 },
]),
geometry::LineString::new(vec![]),
geometry::LineString::new(vec![
geometry::Coord { x: 66.0, y: 46.0 },
geometry::Coord { x: 47.0, y: 34.0 },
geometry::Coord { x: 66.0, y: 26.0 },
]),
]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_line_string, multi_line_string);
let multi_line_string =
geometry::Geometry::MultiLineString(geometry::MultiLineString::new(vec![
geometry::LineString::new(vec![
geometry::Coord { x: 45.0, y: 25.0 },
geometry::Coord { x: 46.0, y: 24.0 },
geometry::Coord { x: 45.0, y: 25.0 },
]),
geometry::LineString::new(vec![
geometry::Coord { x: 55.0, y: 25.0 },
geometry::Coord { x: 46.0, y: 34.0 },
geometry::Coord { x: 55.0, y: 25.0 },
]),
geometry::LineString::new(vec![
geometry::Coord { x: 66.0, y: 46.0 },
geometry::Coord { x: 47.0, y: 34.0 },
geometry::Coord { x: 66.0, y: 26.0 },
]),
]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_line_string).unwrap();
let zulti_line_string = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_line_string, multi_line_string);
}
#[test]
fn naive_polygon_roundtrip() {
let polygon = geometry::Geometry::Polygon(geometry::Polygon::new(
geometry::LineString::new(vec![]),
vec![],
));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &polygon).unwrap();
let zolygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zolygon, polygon);
let polygon = geometry::Geometry::Polygon(geometry::Polygon::new(
geometry::LineString::new(vec![
geometry::Coord { x: 66.0, y: 46.0 },
geometry::Coord { x: 47.0, y: 34.0 },
geometry::Coord { x: 66.0, y: 26.0 },
]),
vec![],
));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &polygon).unwrap();
let zolygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zolygon, polygon);
}
#[test]
fn naive_multi_polygon_roundtrip() {
let multi_polygon = geometry::Geometry::MultiPolygon(geometry::MultiPolygon::new(vec![]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_polygon).unwrap();
let zulti_polygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_polygon, multi_polygon);
let multi_polygon = geometry::Geometry::MultiPolygon(geometry::MultiPolygon::new(vec![
geometry::Polygon::new(
geometry::LineString::new(vec![
geometry::Coord { x: 66.0, y: 46.0 },
geometry::Coord { x: 47.0, y: 34.0 },
geometry::Coord { x: 66.0, y: 26.0 },
]),
vec![],
),
geometry::Polygon::new(
geometry::LineString::new(vec![
geometry::Coord { x: 86.0, y: 48.0 },
geometry::Coord { x: 67.0, y: 36.0 },
geometry::Coord { x: 86.0, y: 28.0 },
]),
vec![],
),
]));
let mut buf = Vec::new();
Zerometry::write_from_geometry(&mut buf, &multi_polygon).unwrap();
let zulti_polygon = unsafe { Zerometry::from_bytes(&buf).unwrap() };
assert_eq!(zulti_polygon, multi_polygon);
}
#[test]
fn naive_geometry_collection_roundtrip() {
}
}