rustgeojsonshapefile

How do I convert the shape values in a shapefile to a JSON string?


I'm trying to convert from Shape to a JSON string but I couldn't create a string for Polygon, I searched but I couldn't find something that helps me.

In the code shows other types different to polygon bbox and rings, but with these types I can't get structure of polygon

Full code from function

[dependencies]
shapefile = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
use shapefile::{ShapeReader, Shape,  Polygon};
use serde_json::to_string;
use serde::Serialize;

fn shapes_to_json(path: &str) -> String {
    let mut reader = match ShapeReader::from_path(path) {
        Ok(reader) => reader,
        Err(_) => return String::new(),
    };

    let mut geometries = Vec::new();

    for shape in reader.iter_shapes() {
        match shape {
            Ok(Shape::Point(point)) => {
                geometries.push(Geometry::Point {
                    coordinates: [point.x, point.y],
                });
            },
            Ok(Shape::Polyline(polyline)) => {
                let parts: Vec<Vec<[f64; 2]>> = polyline.parts().iter().map(|part| {
                    part.iter().map(|p| [p.x, p.y]).collect()
                }).collect();
                geometries.push(Geometry::LineString {
                    coordinates: parts.concat(),
                });
            },
            /// The error is here
            Ok(Shape::Polygon(Polygon { points, parts })) => {
                geometries.push(Geometry::Polygon {
                    coordinates: parts_to_coords(&parts, &points),
                });
            },
            Err(_) => continue, // Skip or log errors
            _ => {} // Optionally handle or skip other geometry types
        }
    }

    // Convert the vector of geometries to JSON string
    to_string(&geometries).unwrap_or_else(|_| String::new())
}

Message error from RUST console:

error[E0026]: struct `GenericPolygon` does not have fields named `points`, `parts`
  --> src/main.rs:94:41
   |
94 |             Ok(Shape::Polygon(Polygon { points, parts })) => {
   |                                         ^^^^^^  ^^^^^ struct `GenericPolygon` does not have these fields

error: pattern requires `..` due to inaccessible fields
  --> src/main.rs:94:31
   |
94 |             Ok(Shape::Polygon(Polygon { points, parts })) => {
   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: ignore the inaccessible and unused fields
   |
94 |             Ok(Shape::Polygon(Polygon { points, parts, .. })) => {
   |                                                      ++++

error[E0425]: cannot find function `parts_to_coords` in this scope
  --> src/main.rs:96:34
   |
96 |                     coordinates: parts_to_coords(&parts, &points),
   |                                  ^^^^^^^^^^^^^^^ not found in this scope

Optional

I'm trying extract the JSON from shape file with this library, but if you know others ways for extract the JSON share me that and I can test 😉


Solution

  • Later of months I could find the solution:

    The polygon has a method called .rings() that has all coordinates of polygon, was delay and annoying but I can :)

    use shapefile::{ShapeReader, Shape,  Polygon};
    use serde_json::to_string;
    use serde::Serialize;
    
    #[derive(Serialize)]
    #[serde(tag = "type")]
    pub enum Geometry {
        Point {
            coordinates: [f64; 2],
        },
        Polygon {
            coordinates: Vec<Vec<[f64; 2]>>,
        },
        LineString {
            coordinates: Vec<[f64; 2]>,
        },
    }
    
    fn shapes_to_json(path: &str) -> String {
        let mut reader = match ShapeReader::from_path(path) {
            Ok(reader) => reader,
            Err(_) => return String::new(),
        };
    
        let mut geometries = Vec::new();
    
        for shape in reader.iter_shapes() {
            match shape {
                Ok(Shape::Point(point)) => {
                    geometries.push(Geometry::Point {
                        coordinates: [point.x, point.y],
                    });
                },
                Ok(Shape::Polyline(polyline)) => {
                    let parts: Vec<Vec<[f64; 2]>> = polyline.parts().iter().map(|part| {
                        part.iter().map(|p| [p.x, p.y]).collect()
                    }).collect();
                    geometries.push(Geometry::LineString {
                        coordinates: parts.concat(),
                    });
                },
                /// The error is here
                Ok(Shape::Polygon(polygon)) => {                
                    let mut geometry:Vec<Vec<[f64; 2]>> = Vec::new();
                    for ring in polygon.rings() {
                        let mut index:usize=0;
                        let mut sub_geometry:Vec<[f64; 2]> = Vec::new();
                        loop {                        
                            let coordinates:[f64; 2] = [ring[index].x, ring[index].y];
                            sub_geometry.push(coordinates);
                            if index+1 == ring.len() {
                                break;
                            }
                            index += 1;
                        };
                        geometry.push(sub_geometry);
                        
                    }
    
                    geometries.push(Geometry::Polygon {
                        coordinates: geometry
                    });
                    continue;
                },
                Err(_) => continue, // Skip or log errors
                _ => {} // Optionally handle or skip other geometry types
            }
        }
    
        // Convert the vector of geometries to JSON string
        to_string(&geometries).unwrap_or_else(|_| String::new())
    }
    ``