contour-rs
Computes isorings and contour polygons by applying marching squares to a rectangular array of numeric values.
Outputs ring coordinates or polygons contours (represented using geo-types MultiPolygons).
For each threshold value, the contour polygon are representing the area where the input values are greater than or equal to the threshold value.
The generated contours can also easily be serialised to GeoJSON.
Note : This is a port of d3-contour.
Usage
Add this to your Cargo.toml
:
[dependencies]
contour = "0.9.0"
and this to your crate root:
extern crate contour;
The API exposes:
-
a
ContourBuilder
struct, which computes isorings coordinates for aVec
of threshold values and transform them either :- in
Contour
s (a type containing the threshold value and the geometry as aMultiPolygon
, easily serializable to GeoJSON), or, - in
Line
s (a type containing the threshold value and the geometry as aMultiLineString
, easily serializable to GeoJSON).
- in
-
a
contour_rings
function, which computes isorings coordinates for a single threshold value (returns aVec
of rings coordinates - this is what is used internally by theContourBuilder
).
ContourBuilder
is the recommended way to use this crate, as it is more flexible and easier to use (it enables to specify the origin and the step of the grid, and to smooth the contours, while contour_rings
only speak in grid coordinates and doesn't smooth the resulting rings).
Example:
Without defining origin and step:
let c = ContourBuilder::new(10, 10, false); // x dim., y dim., smoothing
let res = c.contours(&vec![
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
], &[0.5])?; // values, thresholds
With origin and step
let c = ContourBuilder::new(10, 10, true) // x dim., y dim., smoothing
.x_step(2) // The horizontal coordinate for the origin of the grid.
.y_step(2) // The vertical coordinate for the origin of the grid.
.x_origin(100) // The horizontal step for the grid
.y_origin(200); // The vertical step for the grid
let res = c.contours(&[
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
], &[0.5]).unwrap(); // values, thresholds
Using the geojson
feature
The geojson
feature is not enabled by default, so you need to specify it in your Cargo.toml
:
[dependencies]
contour = { version = "0.8.0", features = ["geojson"] }
let c = ContourBuilder::new(10, 10, true) // x dim., y dim., smoothing
.x_step(2) // The horizontal coordinate for the origin of the grid.
.y_step(2) // The vertical coordinate for the origin of the grid.
.x_origin(100) // The horizontal step for the grid
.y_origin(200); // The vertical step for the grid
let res = c.contours(&[
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 1., 1., 0., 1., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
], &[0.5]).unwrap(); // values, thresholds
println!("{:?}", res[0].to_geojson()); // prints the GeoJSON representation of the first contour
Output:
Feature {
bbox: None,
geometry: Some(Geometry {
bbox: None,
value: MultiPolygon([
[[
[110.0, 215.0], [110.0, 213.0], [110.0, 211.0], [110.0, 209.0],
[110.0, 207.0], [109.0, 206.0], [107.0, 206.0], [106.0, 207.0],
[106.0, 209.0], [106.0, 211.0], [106.0, 213.0], [106.0, 215.0],
[107.0, 216.0], [109.0, 216.0], [110.0, 215.0]
]],
[[
[114.0, 215.0], [114.0, 213.0], [114.0, 211.0], [114.0, 209.0],
[114.0, 207.0], [113.0, 206.0], [112.0, 207.0], [112.0, 209.0],
[112.0, 211.0], [112.0, 213.0], [112.0, 215.0], [113.0, 216.0],
[114.0, 215.0]
]]
]),
foreign_members: None
}),
id: None,
properties: Some({"threshold": Number(0.5)}),
foreign_members: None
}
WASM demo
Demo of this crate compiled to WebAssembly and used from JavaScript : wasm_demo_contour.
contour-isobands crate (from mthh/contour-isobands-rs repository)
Difference with theWhile this crate computes isolines (cf. wikipedia:Marching_squares) and their corresponding polygons (i.e. polygons that contain all points above the threshold defined for a given isoline), contour-isobands-rs computes isobands (cf. wikipedia:Marching_squares#Isobands) and their corresponding polygons (i.e. contour polygons that contain all points between a minimum and a maximum bound).
Depending on the desired use of the result, the contour-isobands
crate may be more suitable than this contour
crate.
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.