Skip to content

Commit

Permalink
Make ContourBuilder generic over the raster data type
Browse files Browse the repository at this point in the history
Signed-off-by: netthier <[email protected]>
  • Loading branch information
netthier committed Apr 29, 2024
1 parent 5995459 commit 2977db8
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 124 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ license = "MIT OR Apache-2.0"

[dependencies]
geojson = { version = ">=0.16, <=0.24", optional = true }
geo-types= { version = "0.7" }
geo-types = { version = "0.7" }
lazy_static = "1.0"
serde_json = { version = "^1.0", optional = true }
serde = { version = "1.0", optional = true }
rustc-hash = "1.0"
slab = "0.4"
num-traits = "0.2"

[dev-dependencies]
serde_json = "^1.0"

[features]
geojson = ["dep:geojson", "dep:serde_json"]
geojson = ["dep:geojson", "dep:serde_json", "dep:serde"]
f32 = []

[package.metadata.docs.rs]
Expand Down
3 changes: 1 addition & 2 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
extern crate contour;
extern crate test;

use contour::contour_rings;
use contour::ContourBuilder;
use contour::{contour_rings, ContourBuilder};
use test::{black_box, Bencher};

#[rustfmt::skip]
Expand Down
12 changes: 8 additions & 4 deletions examples/ex.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use contour::{ContourBuilder, Float};
use geojson::{FeatureCollection, GeoJson};
use std::fs::File;
use std::io::{BufWriter, Write};
use std::{
fs::File,
io::{BufWriter, Write},
};

fn main() {
let pot_pop_fr = include_str!("../tests/fixtures/pot_pop_fr.json");
Expand Down Expand Up @@ -46,7 +48,8 @@ fn main() {
let features = contours
.iter()
.map(|contour| contour.to_geojson())
.collect::<Vec<geojson::Feature>>();
.collect::<Result<Vec<geojson::Feature>, _>>()
.unwrap();

let geojson_str = GeoJson::from(FeatureCollection {
bbox: None,
Expand Down Expand Up @@ -91,7 +94,8 @@ fn main() {
let features = contours
.iter()
.map(|contour| contour.to_geojson())
.collect::<Vec<geojson::Feature>>();
.collect::<Result<Vec<geojson::Feature>, _>>()
.unwrap();

let geojson_str = GeoJson::from(FeatureCollection {
bbox: None,
Expand Down
32 changes: 17 additions & 15 deletions src/band.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,38 @@
use crate::Float;
use crate::{Float, GridValue};
use geo_types::MultiPolygon;

/// An isoband has the geometry and min / max values of a contour ring, built by [`ContourBuilder`].
#[derive(Debug, Clone)]
pub struct Band {
pub struct Band<V: GridValue> {
pub(crate) geometry: MultiPolygon<Float>,
pub(crate) min_v: Float,
pub(crate) max_v: Float,
pub(crate) min_v: V,
pub(crate) max_v: V,
}

impl Band {
impl<V: GridValue> Band<V> {
/// Borrow the [`MultiPolygon`](geo_types::MultiPolygon) geometry of this contour.
pub fn geometry(&self) -> &MultiPolygon<Float> {
&self.geometry
}

/// Get the owned polygons and thresholds (min and max) of this band.
pub fn into_inner(self) -> (MultiPolygon<Float>, Float, Float) {
pub fn into_inner(self) -> (MultiPolygon<Float>, V, V) {
(self.geometry, self.min_v, self.max_v)
}

/// Get the minimum value used to construct this band.
pub fn min_v(&self) -> Float {
pub fn min_v(&self) -> V {
self.min_v
}

/// Get the maximum value used to construct this band.
pub fn max_v(&self) -> Float {
pub fn max_v(&self) -> V {
self.max_v
}
}

#[cfg(feature = "geojson")]
#[cfg(feature = "geojson")]
impl<V: GridValue + serde::Serialize> Band<V> {
/// Convert the band to a struct from the `geojson` crate.
///
/// To get a string representation, call to_geojson().to_string().
Expand All @@ -53,21 +55,21 @@ impl Band {
/// # 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
/// ], &[0.5, 1.5, 2.5]).unwrap();
///
/// let geojson_string = contours[0].to_geojson().to_string();
/// let geojson_string = contours[0].to_geojson().unwrap().to_string();
///
/// assert_eq!(&geojson_string[0..27], r#"{"geometry":{"coordinates":"#);
/// ```
pub fn to_geojson(&self) -> geojson::Feature {
pub fn to_geojson(&self) -> crate::Result<geojson::Feature> {
let mut properties = geojson::JsonObject::with_capacity(2);
properties.insert("min_v".to_string(), self.min_v.into());
properties.insert("max_v".to_string(), self.max_v.into());
properties.insert("min_v".to_string(), serde_json::to_value(self.min_v)?);
properties.insert("max_v".to_string(), serde_json::to_value(self.max_v)?);

geojson::Feature {
Ok(geojson::Feature {
bbox: None,
geometry: Some(geojson::Geometry::from(self.geometry())),
id: None,
properties: Some(properties),
foreign_members: None,
}
})
}
}
29 changes: 17 additions & 12 deletions src/contour.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
use crate::Float;
use crate::{Float, GridValue};
use geo_types::MultiPolygon;

/// A contour has the geometry and threshold of a contour ring, built by [`ContourBuilder`].
#[derive(Debug, Clone)]
pub struct Contour {
pub struct Contour<V: GridValue> {
pub(crate) geometry: MultiPolygon<Float>,
pub(crate) threshold: Float,
pub(crate) threshold: V,
}

impl Contour {
impl<V: GridValue> Contour<V> {
/// Borrow the [`MultiPolygon`](geo_types::MultiPolygon) geometry of this contour.
pub fn geometry(&self) -> &MultiPolygon<Float> {
&self.geometry
}

/// Get the owned polygons and threshold of this contour.
pub fn into_inner(self) -> (MultiPolygon<Float>, Float) {
pub fn into_inner(self) -> (MultiPolygon<Float>, V) {
(self.geometry, self.threshold)
}

/// Get the threshold used to construct this contour.
pub fn threshold(&self) -> Float {
pub fn threshold(&self) -> V {
self.threshold
}
}

#[cfg(feature = "geojson")]
#[cfg(feature = "geojson")]
impl<V: GridValue + serde::Serialize> Contour<V> {
/// Convert the contour to a struct from the `geojson` crate.
///
/// To get a string representation, call to_geojson().to_string().
Expand All @@ -47,20 +49,23 @@ impl Contour {
/// # 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
/// ], &[0.5]).unwrap();
///
/// let geojson_string = contours[0].to_geojson().to_string();
/// let geojson_string = contours[0].to_geojson().unwrap().to_string();
///
/// assert_eq!(&geojson_string[0..27], r#"{"geometry":{"coordinates":"#);
/// ```
pub fn to_geojson(&self) -> geojson::Feature {
pub fn to_geojson(&self) -> crate::Result<geojson::Feature> {
let mut properties = geojson::JsonObject::with_capacity(1);
properties.insert("threshold".to_string(), self.threshold.into());
properties.insert(
"threshold".to_string(),
serde_json::to_value(self.threshold)?,
);

geojson::Feature {
Ok(geojson::Feature {
bbox: None,
geometry: Some(geojson::Geometry::from(self.geometry())),
id: None,
properties: Some(properties),
foreign_members: None,
}
})
}
}
Loading

0 comments on commit 2977db8

Please sign in to comment.