Crate geojson[][src]

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.toml, 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::{to_value, Map};

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 a Feature is an Option
  • GeometryCollections contain other Geometry 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 on geojson, iterating over its features field, yielding Option<Feature>.
  • process each Feature, accessing its Value field, yielding Option<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::{quick_collection, GeoJson};
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();

A Geojson may be converted to a geo_types::Geometry<f64> like so:

use geojson::GeoJson;
use geo_types::Geometry;
use std::convert::TryInto;
use std::str::FromStr;
let geojson_str = r#"
{
 "type": "Feature",
 "properties": {},
 "geometry": {
   "type": "Point",
   "coordinates": [
     -0.13583511114120483,
     51.5218870403801
   ]
 }
}
"#;
let geojson = GeoJson::from_str(geojson_str).unwrap();
// Turn the GeoJSON string into a geo_types Geometry
let geom: geo_types::Geometry<f64> = geojson.try_into().unwrap();

Caveats

  • Round-tripping with intermediate processing using the geo types may not produce identical output, as e.g. outer Polygon rings are automatically closed.
  • geojson attempts to output valid geometries. In particular, it may re-orient Polygon 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.

Re-exports

pub use crate::errors::Error;

Modules

errors

Module for all GeoJSON-related errors

feature

Structs

Feature

Feature Objects

FeatureCollection

Feature Collection Objects

Geometry

Geometry Objects

Enums

GeoJson

GeoJSON Objects

Value

The underlying value for a Geometry.

Functions

quick_collectiongeo-types

A shortcut for producing geo_types GeometryCollection objects from arbitrary valid GeoJSON input.

Type Definitions

Bbox

Bounding Boxes

LineStringType
PointType
PolygonType
Position

Positions