Skip to content

Commit

Permalink
geojson: demarcate collections
Browse files Browse the repository at this point in the history
This allows WKT to emit a single top level item
And allows for lossless roundtripping of geojson->fgb->geojson
  • Loading branch information
michaelkirk committed Sep 12, 2022
1 parent 0c3d620 commit f07e33e
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 24 deletions.
39 changes: 16 additions & 23 deletions geozero/src/geojson/geojson_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ pub fn read_geojson<R: Read, P: FeatureProcessor>(mut reader: R, processor: &mut
}

pub fn read_geojson_fc<R: Read, P: FeatureProcessor>(reader: R, processor: &mut P) -> Result<()> {
let mut idx = 0;
for feature in FeatureReader::from_reader(reader).features() {
processor.dataset_begin(None)?;
for (idx, feature) in FeatureReader::from_reader(reader).features().enumerate(){
process_geojson_feature(&feature?, idx, processor)?;
idx += 1;
}
processor.dataset_end()?;
Ok(())
}

Expand All @@ -83,22 +83,15 @@ fn process_geojson<P: FeatureProcessor>(gj: &GeoGeoJson, processor: &mut P) -> R
GeoGeoJson::FeatureCollection(ref collection) => {
processor.dataset_begin(None)?;
for (idx, feature) in collection.features.iter().enumerate() {
processor.feature_begin(idx as u64)?;
if let Some(ref properties) = feature.properties {
processor.properties_begin()?;
process_properties(properties, processor)?;
processor.properties_end()?;
}
if let Some(ref geometry) = feature.geometry {
processor.geometry_begin()?;
process_geojson_geom_n(geometry, idx, processor)?;
processor.geometry_end()?;
}
processor.feature_end(idx as u64)?;
process_geojson_feature(feature, idx, processor)?
}
processor.dataset_end()?;
}
GeoGeoJson::Feature(ref feature) => process_geojson_feature(feature, 0, processor)?,
GeoGeoJson::Feature(ref feature) => {
processor.dataset_begin(None)?;
process_geojson_feature(feature, 0, processor)?;
processor.dataset_end()?;
}
GeoGeoJson::Geometry(ref geometry) => {
process_geojson_geom_n(geometry, 0, processor)?;
}
Expand All @@ -112,7 +105,6 @@ fn process_geojson_feature<P: FeatureProcessor>(
idx: usize,
processor: &mut P,
) -> Result<()> {
processor.dataset_begin(None)?;
if feature.geometry.is_some() || feature.properties.is_some() {
processor.feature_begin(idx as u64)?;
if let Some(ref properties) = feature.properties {
Expand All @@ -127,14 +119,14 @@ fn process_geojson_feature<P: FeatureProcessor>(
}
processor.feature_end(idx as u64)?;
}
processor.dataset_end()?;
Ok(())
}

/// Process top-level GeoJSON items (geometry only)
fn process_geojson_geom<P: GeomProcessor>(gj: &GeoGeoJson, processor: &mut P) -> Result<()> {
match *gj {
GeoGeoJson::FeatureCollection(ref collection) => {
processor.geometrycollection_begin(collection.features.len(), 0)?;
for (idx, geometry) in collection
.features
.iter()
Expand All @@ -144,6 +136,7 @@ fn process_geojson_geom<P: GeomProcessor>(gj: &GeoGeoJson, processor: &mut P) ->
{
process_geojson_geom_n(geometry, idx, processor)?;
}
processor.geometrycollection_end(0)?;
}
GeoGeoJson::Feature(ref feature) => {
if let Some(ref geometry) = feature.geometry {
Expand Down Expand Up @@ -367,7 +360,7 @@ mod test {
let mut wkt_data: Vec<u8> = Vec::new();
assert!(read_geojson_fc(geojson.as_bytes(), &mut WktWriter::new(&mut wkt_data)).is_ok());
let wkt = std::str::from_utf8(&wkt_data).unwrap();
assert_eq!(wkt, "MULTIPOLYGON(((173.020375 -40.919052,173.247234 -41.331999,173.958405 -40.926701,174.247587 -41.349155,174.248517 -41.770008,173.876447 -42.233184,173.22274 -42.970038,172.711246 -43.372288,173.080113 -43.853344,172.308584 -43.865694,171.452925 -44.242519,171.185138 -44.897104,170.616697 -45.908929,169.831422 -46.355775,169.332331 -46.641235,168.411354 -46.619945,167.763745 -46.290197,166.676886 -46.219917,166.509144 -45.852705,167.046424 -45.110941,168.303763 -44.123973,168.949409 -43.935819,169.667815 -43.555326,170.52492 -43.031688,171.12509 -42.512754,171.569714 -41.767424,171.948709 -41.514417,172.097227 -40.956104,172.79858 -40.493962,173.020375 -40.919052)),((174.612009 -36.156397,175.336616 -37.209098,175.357596 -36.526194,175.808887 -36.798942,175.95849 -37.555382,176.763195 -37.881253,177.438813 -37.961248,178.010354 -37.579825,178.517094 -37.695373,178.274731 -38.582813,177.97046 -39.166343,177.206993 -39.145776,176.939981 -39.449736,177.032946 -39.879943,176.885824 -40.065978,176.508017 -40.604808,176.01244 -41.289624,175.239567 -41.688308,175.067898 -41.425895,174.650973 -41.281821,175.22763 -40.459236,174.900157 -39.908933,173.824047 -39.508854,173.852262 -39.146602,174.574802 -38.797683,174.743474 -38.027808,174.697017 -37.381129,174.292028 -36.711092,174.319004 -36.534824,173.840997 -36.121981,173.054171 -35.237125,172.636005 -34.529107,173.007042 -34.450662,173.551298 -35.006183,174.32939 -35.265496,174.612009 -36.156397)))");
assert_eq!(wkt, "GEOMETRYCOLLECTION(MULTIPOLYGON(((173.020375 -40.919052,173.247234 -41.331999,173.958405 -40.926701,174.247587 -41.349155,174.248517 -41.770008,173.876447 -42.233184,173.22274 -42.970038,172.711246 -43.372288,173.080113 -43.853344,172.308584 -43.865694,171.452925 -44.242519,171.185138 -44.897104,170.616697 -45.908929,169.831422 -46.355775,169.332331 -46.641235,168.411354 -46.619945,167.763745 -46.290197,166.676886 -46.219917,166.509144 -45.852705,167.046424 -45.110941,168.303763 -44.123973,168.949409 -43.935819,169.667815 -43.555326,170.52492 -43.031688,171.12509 -42.512754,171.569714 -41.767424,171.948709 -41.514417,172.097227 -40.956104,172.79858 -40.493962,173.020375 -40.919052)),((174.612009 -36.156397,175.336616 -37.209098,175.357596 -36.526194,175.808887 -36.798942,175.95849 -37.555382,176.763195 -37.881253,177.438813 -37.961248,178.010354 -37.579825,178.517094 -37.695373,178.274731 -38.582813,177.97046 -39.166343,177.206993 -39.145776,176.939981 -39.449736,177.032946 -39.879943,176.885824 -40.065978,176.508017 -40.604808,176.01244 -41.289624,175.239567 -41.688308,175.067898 -41.425895,174.650973 -41.281821,175.22763 -40.459236,174.900157 -39.908933,173.824047 -39.508854,173.852262 -39.146602,174.574802 -38.797683,174.743474 -38.027808,174.697017 -37.381129,174.292028 -36.711092,174.319004 -36.534824,173.840997 -36.121981,173.054171 -35.237125,172.636005 -34.529107,173.007042 -34.450662,173.551298 -35.006183,174.32939 -35.265496,174.612009 -36.156397))))");
Ok(())
}

Expand Down Expand Up @@ -400,11 +393,11 @@ mod test {
let wkt = std::str::from_utf8(&wkt_data).unwrap();
assert_eq!(
&wkt[0..100],
"POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.671004121125236),POINT(15.7989"
"GEOMETRYCOLLECTION(POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.67100412112"
);
assert_eq!(
&wkt[wkt.len()-100..],
"06510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551)"
"6510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551))"
);
Ok(())
}
Expand All @@ -417,11 +410,11 @@ mod test {
let wkt = std::str::from_utf8(&wkt_data).unwrap();
assert_eq!(
&wkt[0..100],
"POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.671004121125236),POINT(15.7989"
"GEOMETRYCOLLECTION(POINT(32.533299524864844 0.583299105614628),POINT(30.27500161597942 0.67100412112"
);
assert_eq!(
&wkt[wkt.len()-100..],
"06510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551)"
"6510862875),POINT(103.85387481909902 1.294979325105942),POINT(114.18306345846304 22.30692675357551))"
);
Ok(())
}
Expand Down
11 changes: 10 additions & 1 deletion geozero/src/wkt/wkt_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,16 @@ impl<W: Write> GeomProcessor for WktWriter<'_, W> {

impl<W: Write> PropertyProcessor for WktWriter<'_, W> {}

impl<W: Write> FeatureProcessor for WktWriter<'_, W> {}
impl<W: Write> FeatureProcessor for WktWriter<'_, W> {
// Feature Collections may contain multiple geometries, so we need to wrap
// them in a GeometryCollection to ensure we output valid geometry.
fn dataset_begin(&mut self, _name: Option<&str>) -> Result<()> {
self.geometrycollection_begin(0, 0)
}
fn dataset_end(&mut self) -> Result<()> {
self.geometrycollection_end(0)
}
}

#[cfg(test)]
mod test {
Expand Down

0 comments on commit f07e33e

Please sign in to comment.