georust / geozero

Zero-Copy reading and writing of geospatial data.
Apache License 2.0
321 stars 30 forks source link

Documentation for basic usage of geozero-shp #86

Open jose-lpa opened 1 year ago

jose-lpa commented 1 year ago

Hello, and thank you for this project.

I am trying to do a simple newbie program that, given an ESRI Shapefile as input, it outputs the geometries as GeoJSON.

I have been trying to use the geozero-shp crate, simply following the short example that can be found on its README, without any luck. It seems the example is incorrect, or it might have been outdated by outer changes on its dependencies.

I wrote this program:

use geozero::geojson::GeoJsonWriter;

fn main() {
    let path = "/home/jose/Downloads/ne_10m_admin_0_sovereignty/ne_10m_admin_0_sovereignty.shp";
    let reader = geozero_shp::Reader::from_path(path).unwrap();
    let mut json: Vec<u8> = Vec::new();
    let data = reader.iter_features(GeoJsonWriter::new(&mut json)).unwrap();
}

and when I run it, it doesn't seem that GeoJsonWriter is a valid thing to pass to the processor argument:

jose@uranium ~/C/e/shp_ingestor (master) [101]> cargo run -- /home/jose/Downloads/ne_10m_admin_0_sovereignty/ne_10m_admin_0_sovereignty.shp
   Compiling shp_ingestor v0.1.0 (/home/jose/Code/experimental/shp_ingestor)
error[E0277]: the trait bound `GeoJsonWriter<'_, Vec<u8>>: geozero::feature_processor::FeatureProcessor` is not satisfied
   --> src/main.rs:8:37
    |
8   |     let data = reader.iter_features(GeoJsonWriter::new(&mut json)).unwrap();
    |                       ------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `geozero::feature_processor::FeatureProcessor` is not implemented for `GeoJsonWriter<'_, Vec<u8>>`
    |                       |
    |                       required by a bound introduced by this call
    |
    = help: the following other types implement trait `geozero::feature_processor::FeatureProcessor`:
              geozero::ProcessorSink
              geozero::multiplex::Multiplexer<P1, P2>
note: required by a bound in `Reader::<T>::iter_features`
   --> /home/jose/.cargo/registry/src/github.com-1ecc6299db9ec823/geozero-shp-0.3.1/src/reader.rs:161:29
    |
161 |     pub fn iter_features<P: FeatureProcessor>(
    |                             ^^^^^^^^^^^^^^^^ required by this bound in `Reader::<T>::iter_features`

error[E0277]: the trait bound `GeoJsonWriter<'_, Vec<u8>>: geozero::feature_processor::FeatureProcessor` is not satisfied
  --> src/main.rs:8:16
   |
8  |     let data = reader.iter_features(GeoJsonWriter::new(&mut json)).unwrap();
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `geozero::feature_processor::FeatureProcessor` is not implemented for `GeoJsonWriter<'_, Vec<u8>>`
   |
   = help: the following other types implement trait `geozero::feature_processor::FeatureProcessor`:
             geozero::ProcessorSink
             geozero::multiplex::Multiplexer<P1, P2>
note: required by a bound in `ShapeRecordIterator`
  --> /home/jose/.cargo/registry/src/github.com-1ecc6299db9ec823/geozero-shp-0.3.1/src/reader.rs:39:35
   |
39 | pub struct ShapeRecordIterator<P: FeatureProcessor, T: Read + Seek> {
   |                                   ^^^^^^^^^^^^^^^^ required by this bound in `ShapeRecordIterator`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `shp_ingestor` due to 2 previous errors

Is there any documentation or code examples where I can see how this crate is used?

Thank you.

michaelkirk commented 1 year ago

I'm going to move your issue to the geozero repository, since it seems to be about geozero.

jose-lpa commented 1 year ago

It is indeed about geozero-shp. I had multiple tabs opened with Rust georust repos and I opened the issue in the wrong one :man_facepalming: Apologies for the mistake, and thank you very much for moving the issue here @michaelkirk

pka commented 1 year ago

There is a test for converting Shp to GeoJSON: https://github.com/georust/geozero/blob/f8bcaaabc6bd6b596957b74f84aef3b2518ffee3/geozero-shp/tests/reader.rs#L49

emirror-de commented 8 months ago

Hey, are there any updates on this? I created a new project, copied the test you mentioned in there and renamed it to fn main. It results in the same error message.

However, the tests are passing and if I use the test as example in the geozero-shp crate it also works.

To reproduce, create a new binary with:

Cargo.toml

[package]
name = "geozero-test"
version = "0.1.0"
edition = "2021"

[dependencies]
geozero-shp = "0.4"
geozero = "0.11"

src/main.rs

use geozero::geojson::GeoJsonWriter;
use std::str::from_utf8;

fn main() -> Result<(), geozero_shp::Error> {
    let reader = geozero_shp::Reader::from_path("./tests/data/poly.shp")?;
    let mut json: Vec<u8> = Vec::new();
    let cnt = reader
        .iter_features(&mut GeoJsonWriter::new(&mut json))?
        .count();
    assert_eq!(cnt, 10);
    assert_eq!(
        &from_utf8(&json).unwrap()[0..80],
        r#"{
"type": "FeatureCollection",
"features": [{"type": "Feature", "properties": {""#
    );
    assert_eq!(
        &from_utf8(&json).unwrap()[json.len()-100..],
        "2],[479658.59375,4764670],[479640.09375,4764721],[479735.90625,4764752],[479750.6875,4764702]]]]}}]}"
    );
    Ok(())
}

Edit: Using Rust 1.74

nyurik commented 8 months ago

I just tried it, this is indeed really weird! Debugging... but if anyone has any ideas, please post

nyurik commented 8 months ago

Ah, silly me - I think you are copy/pasting test code from a development (unpublished) version. When I added this to cargo.toml, it worked (I have geozero cloned in a parallel dir). I think all this was done by @michaelkirk in https://github.com/georust/geozero/commit/bee32bc983fa8ddd11318743709fee6032a662ac

[patch.crates-io]
geozero = { path = "../../geozero/geozero" }
geozero-shp = { path = "../../geozero/geozero-shp" }
emirror-de commented 8 months ago

Ah that makes sense, I did not work with patching yet. Thanks for the fast reponse!

nyurik commented 8 months ago

Just don't use it for any production code :) Patching is for experiments, and for when you have multiple crates in the same repo that depend on one another, and you need to modify them at the same time.

emirror-de commented 8 months ago

Ok nice to know. I am now using { path = "" } instead of the version number until a new release will be uploaded :+1: