[−][src]Crate geojson
Introduction
The geojson
crate reads and writes GeoJSON
(IETF RFC 7946) files,
optionally using serde
for serialisation. Crate users are encouraged to familiarise themselves with the spec,
as the crate is structured around it.
Structure of the Crate
GeoJSON can contain one of three top-level objects, reflected in the top-level geojson::GeoJson
enum members of the same name:
With FeatureCollection
being the most commonly used, since it can contain multiple child objects.
A FeatureCollection
contains Feature
objects, each of which contains a Geometry
object, which may be empty.
A potentially complicating factor is the GeometryCollection
geometry type, which can contain
one more Geometry
objects, including nested GeometryCollection
objects.
The use of GeometryCollection
is discouraged, however.
If your primary use case for this crate is ingesting GeoJSON
strings in order to process geometries
using the algorithms in the geo
crate, you can do so by enabling the geo-types
feature in
your cargo.html
, and using the quick_collection
function to
parse GeoJson
objects into
a geo_types::GeometryCollection
.
See here for details.
This crate uses serde
for serialization.
To get started, add geojson
to your Cargo.toml
:
[dependencies]
geojson= "*"
Examples
Reading
use geojson::GeoJson; let geojson_str = r#" { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "Point", "coordinates": [ -0.13583511114120483, 51.5218870403801 ] } } ] } "#; let geojson = geojson_str.parse::<GeoJson>().unwrap();
Writing
Writing geojson
depends on the serialization framework because some structs
(like Feature
) use json values for properties.
use serde_json; use serde_json::{Map, to_value}; let mut properties = Map::new(); properties.insert( String::from("name"), to_value("Firestone Grill").unwrap(), );
GeoJson
can then be serialized by calling to_string
:
use geojson::{Feature, GeoJson, Geometry, Value}; let geometry = Geometry::new( Value::Point(vec![-120.66029,35.2812]) ); let geojson = GeoJson::Feature(Feature { bbox: None, geometry: Some(geometry), id: None, properties: Some(properties), foreign_members: None }); let geojson_string = geojson.to_string();
Parsing
GeoJSON's spec is quite simple, but it has several subtleties that must be taken into account when parsing it:
- The
geometry
field of aFeature
is anOption
GeometryCollection
s contain otherGeometry
objects, and can nest.
Here's a minimal example which will parse valid GeoJSON without taking ownership of it.
use geojson::{GeoJson, Geometry, Value}; /// Process top-level GeoJSON items fn process_geojson(gj: &GeoJson) { match *gj { GeoJson::FeatureCollection(ref ctn) => for feature in &ctn.features { if let Some(ref geom) = feature.geometry { match_geometry(geom) } }, GeoJson::Feature(ref feature) => { if let Some(ref geom) = feature.geometry { match_geometry(geom) } } GeoJson::Geometry(ref geometry) => match_geometry(geometry), } } /// Process GeoJSON geometries fn match_geometry(geom: &Geometry) { match geom.value { Value::Polygon(_) => println!("Matched a Polygon"), Value::MultiPolygon(_) => println!("Matched a MultiPolygon"), Value::GeometryCollection(ref gc) => { println!("Matched a GeometryCollection"); // GeometryCollections contain other Geometry types, and can nest // we deal with this by recursively processing each geometry for geometry in gc { match_geometry(geometry) } } // Point, LineString, and their Multi– counterparts _ => println!("Matched some other geometry"), } } fn main() { let geojson_str = r#" { "type": "GeometryCollection", "geometries": [ {"type": "Point", "coordinates": [0,1]}, {"type": "MultiPoint", "coordinates": [[-1,0],[1,0]]}, {"type": "LineString", "coordinates": [[-1,-1],[1,-1]]}, {"type": "MultiLineString", "coordinates": [ [[-2,-2],[2,-2]], [[-3,-3],[3,-3]] ]}, {"type": "Polygon", "coordinates": [ [[-5,-5],[5,-5],[0,5],[-5,-5]], [[-4,-4],[4,-4],[0,4],[-4,-4]] ]}, { "type": "MultiPolygon", "coordinates": [[ [[-7,-7],[7,-7],[0,7],[-7,-7]], [[-6,-6],[6,-6],[0,6],[-6,-6]] ],[ [[-9,-9],[9,-9],[0,9],[-9,-9]], [[-8,-8],[8,-8],[0,8],[-8,-8]]] ]}, {"type": "GeometryCollection", "geometries": [ {"type": "Polygon", "coordinates": [ [[-5.5,-5.5],[5,-5],[0,5],[-5,-5]], [[-4,-4],[4,-4],[0,4],[-4.5,-4.5]] ]} ]} ] } "#; let geojson = geojson_str.parse::<GeoJson>().unwrap(); process_geojson(&geojson); }
Conversion to Geo objects
The TryFrom
trait provides
fallible conversions to Geo types from GeoJSON Value
enums,
allowing them to be measured or used in calculations. Conversely, From
is
implemented on the Value
enum variants to allow conversion from Geo
types.
In most cases it is assumed that you want to convert GeoJSON into geo
primitive types in order to process, transform, or measure them:
match
ongeojson
, iterating over itsfeatures
field, yieldingOption<Feature>
.- process each
Feature
, accessing itsValue
field, yieldingOption<Value>
.
Each Value
represents a primitive type, such as a
coordinate, point, linestring, polygon, or its multi- equivalent, and each of these has
an equivalent geo
primitive type, which you can convert to using the std::convert::TryFrom
trait.
Unifying these features, the quick_collection
function accepts a GeoJson
enum
and processes it, producing a GeometryCollection
whose members can be transformed, measured, rotated, etc using the algorithms and functions in
the geo
crate:
use geojson::{GeoJson, quick_collection}; use geo_types::GeometryCollection; let geojson_str = r#" { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": {}, "geometry": { "type": "Point", "coordinates": [ -0.13583511114120483, 51.5218870403801 ] } } ] } "#; let geojson = geojson_str.parse::<GeoJson>().unwrap(); // Turn the GeoJSON string into a geo_types GeometryCollection let mut collection: GeometryCollection<f64> = quick_collection(&geojson).unwrap();
Caveats
- Round-tripping with intermediate processing using the
geo
types may not produce identical output, as e.g. outerPolygon
rings are automatically closed. geojson
attempts to output valid geometries. In particular, it may re-orientPolygon
rings when serialising.
The geojson_example
and
polylabel_cmd
crates contain example
implementations which may be useful if you wish to perform this kind of processing yourself and require
more granular control over performance and / or memory allocation.
Modules
feature |
Structs
Feature | Feature Objects |
FeatureCollection | Feature Collection Objects |
Geometry | Geometry Objects |
Enums
Error | Error when reading a GeoJSON object from a str or Object |
GeoJson | GeoJSON Objects |
Value | The underlying value for a |
Functions
quick_collection | A shortcut for producing |
Type Definitions
Bbox | Bounding Boxes |
LineStringType | |
PointType | |
PolygonType | |
Position | Positions |