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).
The generated contours can also easily be serialised to GeoJSON.
Note : This is a port of d3-contour.
Add this to your Cargo.toml
:
toml
[dependencies]
contour = "0.7.0"
and this to your crate root:
rust
extern crate contour;
The API exposes:
- a contour_rings
function, which computes isorings coordinates for one threshold value (returns a Vec
of rings coordinates).
- a ContourBuilder
struct, which computes isorings coordinates for a Vec
of threshold values and transform them in Contour
s (a type containing the threshold value and the geometry as a MultiPolygon, easily serializable to GeoJSON).
Without defining origin and step:
rust
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
```rust let c = ContourBuilder::new(10, 10, true) // x dim., y dim., smoothing .xstep(2) // The horizontal coordinate for the origin of the grid. .ystep(2) // The vertical coordinate for the origin of the grid. .xorigin(100) // The horizontal step for the grid .yorigin(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
:
toml
[dependencies]
contour = { version = "0.7.0", features = ["geojson"] }
```rust let c = ContourBuilder::new(10, 10, true) // x dim., y dim., smoothing .xstep(2) // The horizontal coordinate for the origin of the grid. .ystep(2) // The vertical coordinate for the origin of the grid. .xorigin(100) // The horizontal step for the grid .yorigin(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:
rust
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
}
Demo of this crate compiled to WebAssembly and used from JavaScript : wasmdemocontour.
Licensed under either of
at your option.
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.