Skip to content

Commit

Permalink
Adds Ewkt dialect (#155)
Browse files Browse the repository at this point in the history
This PR adds:
- `enum wkt::WktDialect`
- `WktWriter::with_dims`
- `struct EwktString` and `struct EwktStr`
- `ToWkt::to_ewkt`
- `ToWkt::to_wkt_with_opts`

---------

Co-authored-by: Aurèle Nitoref <aurele.nitoref@icloud.com>
Co-authored-by: Yuri Astrakhan <yuriastrakhan@gmail.com>
  • Loading branch information
3 people authored Aug 12, 2023
1 parent ece8dfe commit 5e92027
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 42 deletions.
28 changes: 9 additions & 19 deletions geozero-shp/tests/reader.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use dbase::FieldValue;
use geozero::geojson::GeoJsonWriter;
use geozero::wkt::WktWriter;
use geozero::{FeatureProperties, ProcessorSink};
use geozero::{CoordDimensions, FeatureProperties, ProcessorSink};
use std::fs::File;
use std::io::BufReader;
use std::str::from_utf8;
Expand Down Expand Up @@ -178,8 +178,7 @@ fn point() -> Result<(), geozero_shp::Error> {
fn pointzm() -> Result<(), geozero_shp::Error> {
let reader = geozero_shp::Reader::from_path("./tests/data/pointm.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xym());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -188,8 +187,7 @@ fn pointzm() -> Result<(), geozero_shp::Error> {

let reader = geozero_shp::Reader::from_path("./tests/data/pointz.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -213,8 +211,7 @@ fn multipoint() -> Result<(), geozero_shp::Error> {
fn multipointzm() -> Result<(), geozero_shp::Error> {
let reader = geozero_shp::Reader::from_path("./tests/data/multipointz.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -241,9 +238,7 @@ fn line() -> Result<(), geozero_shp::Error> {
fn linezm() -> Result<(), geozero_shp::Error> {
let reader = geozero_shp::Reader::from_path("./tests/data/linez.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyzm());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -252,8 +247,7 @@ fn linezm() -> Result<(), geozero_shp::Error> {

let reader = geozero_shp::Reader::from_path("./tests/data/linez.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true; // return XYZ only
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -272,8 +266,7 @@ fn linezm() -> Result<(), geozero_shp::Error> {

let reader = geozero_shp::Reader::from_path("./tests/data/linem.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xym());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand Down Expand Up @@ -326,9 +319,7 @@ fn polygon() -> Result<(), geozero_shp::Error> {
fn polygonzm() -> Result<(), geozero_shp::Error> {
let reader = geozero_shp::Reader::from_path("./tests/data/polygonz.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyzm());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand All @@ -337,8 +328,7 @@ fn polygonzm() -> Result<(), geozero_shp::Error> {

let reader = geozero_shp::Reader::from_path("./tests/data/polygonm.shp")?;
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xym());
reader.iter_geometries(&mut writer).next();
assert_eq!(
from_utf8(&wkt_data).unwrap(),
Expand Down
8 changes: 3 additions & 5 deletions geozero/src/geojson/geojson_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ mod test {
use super::*;
use crate::geojson::GeoJsonWriter;
use crate::wkt::WktWriter;
use crate::{ProcessToSvg, ToJson, ToWkt};
use crate::{CoordDimensions, ProcessToSvg, ToJson, ToWkt};
use std::fs::File;

#[test]
Expand All @@ -306,16 +306,14 @@ mod test {
fn geometries3d() -> Result<()> {
let geojson = r#"{"type": "LineString", "coordinates": [[1,1,10],[2,2,20]]}"#;
let mut wkt_data: Vec<u8> = Vec::new();
let mut out = WktWriter::new(&mut wkt_data);
out.dims.z = true;
let mut out = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
assert!(read_geojson_geom(&mut geojson.as_bytes(), &mut out).is_ok());
let wkt = std::str::from_utf8(&wkt_data).unwrap();
assert_eq!(wkt, "LINESTRING(1 1 10,2 2 20)");

let geojson = r#"{"type": "LineString", "coordinates": [[1,1],[2,2]]}"#;
let mut wkt_data: Vec<u8> = Vec::new();
let mut out = WktWriter::new(&mut wkt_data);
out.dims.z = true;
let mut out = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
assert!(read_geojson_geom(&mut geojson.as_bytes(), &mut out).is_ok());
let wkt = std::str::from_utf8(&wkt_data).unwrap();
assert_eq!(wkt, "LINESTRING(1 1,2 2)");
Expand Down
3 changes: 1 addition & 2 deletions geozero/src/geos/geos_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,7 @@ mod test {
let ggeom = GGeometry::new_from_wkt(wkt).unwrap();

let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
assert!(process_geom(&ggeom, &mut writer).is_ok());

assert_eq!(std::str::from_utf8(&wkt_data).unwrap(), wkt);
Expand Down
2 changes: 1 addition & 1 deletion geozero/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
//! | MVT | [mvt::tile::Feature] | XY | [mvt::tile::Layer] | [ToMvt] | [MvtWriter](mvt::MvtWriter) |
//! | SVG | - | XY | - | [ToSvg] | [SvgWriter](svg::SvgWriter) |
//! | WKB | [Wkb](wkb::Wkb), [Ewkb](wkb::Ewkb), [GpkgWkb](wkb::GpkgWkb) | XYZM | - | [ToWkb] | [WkbWriter](wkb::WkbWriter) |
//! | WKT | [wkt::WktStr], [wkt::WktString] | XYZM | [wkt::WktReader], [wkt::WktStr], [wkt::WktString] | [ToWkt] | [WktWriter](wkt::WktWriter) |
//! | WKT | [wkt::WktStr], [wkt::WktString], [wkt::EwktStr], [wkt::EwktString] | XYZM | [wkt::WktReader], [wkt::WktStr], [wkt::WktString] | [ToWkt] | [WktWriter](wkt::WktWriter) |

#![warn(clippy::uninlined_format_args)]
#![allow(
Expand Down
20 changes: 12 additions & 8 deletions geozero/src/wkb/wkb_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,21 @@ impl GeozeroGeometry for GpkgWkb {
/// Process WKB geometry.
pub fn process_wkb_geom<R: Read, P: GeomProcessor>(raw: &mut R, processor: &mut P) -> Result<()> {
let info = read_wkb_header(raw)?;
processor.srid(info.srid)?;
process_wkb_geom_n(raw, &info, read_wkb_header, 0, processor)
}

/// Process EWKB geometry.
pub fn process_ewkb_geom<R: Read, P: GeomProcessor>(raw: &mut R, processor: &mut P) -> Result<()> {
let info = read_ewkb_header(raw)?;
processor.srid(info.srid)?;
process_wkb_geom_n(raw, &info, read_ewkb_header, 0, processor)
}

/// Process GPKG geometry.
pub fn process_gpkg_geom<R: Read, P: GeomProcessor>(raw: &mut R, processor: &mut P) -> Result<()> {
let info = read_gpkg_header(raw)?;
processor.srid(info.srid)?;
process_wkb_geom_n(raw, &info, read_wkb_header, 0, processor)
}

Expand Down Expand Up @@ -441,7 +444,7 @@ fn process_curvepolygon<R: Read, P: GeomProcessor>(
mod test {
use super::*;
use crate::wkt::WktWriter;
use crate::ToWkt;
use crate::{CoordDimensions, ToWkt};

#[test]
fn ewkb_format() {
Expand All @@ -465,9 +468,7 @@ mod test {

// Process all dimensions
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
writer.dims.m = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyzm());
assert!(process_ewkb_geom(&mut ewkb.as_slice(), &mut writer).is_ok());
assert_eq!(
std::str::from_utf8(&wkt_data).unwrap(),
Expand All @@ -484,8 +485,7 @@ mod test {
assert!(info.has_z);

let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = true;
let mut writer = WktWriter::with_dims(&mut wkt_data, CoordDimensions::xyz());
assert!(process_ewkb_geom(&mut ewkb.as_slice(), &mut writer).is_ok());
assert_eq!(
std::str::from_utf8(&wkt_data).unwrap(),
Expand Down Expand Up @@ -595,8 +595,12 @@ mod test {
fn ewkb_to_wkt(ewkb_str: &str, with_z: bool) -> String {
let ewkb = hex::decode(ewkb_str).unwrap();
let mut wkt_data: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut wkt_data);
writer.dims.z = with_z;
let dims = if with_z {
CoordDimensions::xyz()
} else {
CoordDimensions::xy()
};
let mut writer = WktWriter::with_dims(&mut wkt_data, dims);
assert_eq!(
process_ewkb_geom(&mut ewkb.as_slice(), &mut writer).map_err(|e| e.to_string()),
Ok(())
Expand Down
54 changes: 49 additions & 5 deletions geozero/src/wkt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,47 @@ pub use wkt_writer::*;

pub(crate) mod conversion {
use crate::error::Result;
use crate::wkt::WktWriter;
use crate::wkt::{WktDialect, WktWriter};
use crate::{CoordDimensions, GeozeroGeometry};

/// Convert to WKT.
pub trait ToWkt {
/// Convert to 2D WKT String.
fn to_wkt(&self) -> Result<String>;
/// Convert to EWKT String.
fn to_ewkt(&self, srid: Option<i32>) -> Result<String>;
/// Convert to WKT String with dimensions.
fn to_wkt_ndim(&self, dims: CoordDimensions) -> Result<String>;
/// Convert to WKT String with srid, dimensions and dialect.
fn to_wkt_with_opts(
&self,
dialect: WktDialect,
dims: CoordDimensions,
srid: Option<i32>,
) -> Result<String>;
}

impl<T: GeozeroGeometry> ToWkt for T {
fn to_wkt(&self) -> Result<String> {
self.to_wkt_ndim(CoordDimensions::default())
self.to_wkt_with_opts(WktDialect::Wkt, CoordDimensions::default(), None)
}

fn to_ewkt(&self, srid: Option<i32>) -> Result<String> {
self.to_wkt_with_opts(WktDialect::Ewkt, CoordDimensions::xyzm(), srid)
}

fn to_wkt_ndim(&self, dims: CoordDimensions) -> Result<String> {
self.to_wkt_with_opts(WktDialect::Wkt, dims, None)
}

fn to_wkt_with_opts(
&self,
dialect: WktDialect,
dims: CoordDimensions,
srid: Option<i32>,
) -> Result<String> {
let mut out: Vec<u8> = Vec::new();
let mut writer = WktWriter::new(&mut out);
writer.dims = dims;
let mut writer = WktWriter::with_opts(&mut out, dialect, dims, srid);
self.process_geom(&mut writer)?;
String::from_utf8(out).map_err(|_| {
crate::error::GeozeroError::Geometry("Invalid UTF-8 encoding".to_string())
Expand All @@ -40,7 +62,8 @@ pub(crate) mod conversion {
mod wkb {
use crate::error::Result;
use crate::wkb::{FromWkb, WkbDialect};
use crate::wkt::{WktString, WktWriter};
use crate::wkt::{EwktString, WktDialect, WktString, WktWriter};
use crate::CoordDimensions;
use std::io::Read;

impl FromWkb for WktString {
Expand All @@ -54,4 +77,25 @@ mod wkb {
Ok(WktString(wkt))
}
}

impl FromWkb for EwktString {
fn from_wkb<R: Read>(rdr: &mut R, dialect: WkbDialect) -> Result<Self> {
let mut out: Vec<u8> = Vec::new();
let mut writer =
WktWriter::with_opts(&mut out, WktDialect::Ewkt, CoordDimensions::xyzm(), None);
crate::wkb::process_wkb_type_geom(rdr, &mut writer, dialect)?;
let wkt = String::from_utf8(out).map_err(|_| {
crate::error::GeozeroError::Geometry("Invalid UTF-8 encoding".to_string())
})?;
Ok(EwktString(wkt))
}
}
}

/// WKB dialect.
#[derive(Default, PartialEq, Debug, Clone, Copy)]
pub enum WktDialect {
#[default]
Wkt,
Ewkt,
}
6 changes: 6 additions & 0 deletions geozero/src/wkt/wkt_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ impl GeozeroDatasource for WktStr<'_> {
}
}

/// WKT String.
#[derive(Debug)]
pub struct EwktString(pub String);

pub struct EwktStr<'a>(pub &'a str);

/// Wkt Reader.
pub struct WktReader<'a, R: Read>(pub &'a mut R);

Expand Down
Loading

0 comments on commit 5e92027

Please sign in to comment.