### 3 releases (breaking)

0.3.0 | Mar 20, 2023 |
---|---|

0.2.0 | Mar 14, 2023 |

0.1.0 | Mar 14, 2023 |

#**67** in Geospatial

**AGPL-3.0-or-later**

320KB

3K
SLoC

# Contour-isobands-rs

Compute isobands *(i.e. contour polygons which enclose all the points of a grid included
between two given values)* by applying marching squares to an array of values.

## Usage

### Basics

Add the following to your

:`Cargo .toml`

`[``dependencies``]`
`contour-isobands ``=` `"`0.3.0`"`

Then, you can use the

to compute isobands:`ContourBuilder`

`use` `contour_isobands``::``{`ContourBuilder`,` Band`}``;`
`let` values `=` `vec!``[`
`1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,`
`1.``,` `5.``,` `5.``,` `5.``,` `5.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `15.``,` `15.``,` `15.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `10.``,` `10.``,` `10.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `5.``,` `5.``,` `5.``,` `5.``,` `1.``,`
`1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,`
`]``;`
`//` These intervals will compute 3 bands:
`//` - the first one will contain all points between 1 (included) and 5 (excluded)
`//` - the second one will contain all points between 5 (included) and 7 (excluded)
`//` - the third one will contain all points between 7 (included) and 15 (included)
`let` intervals `=` `vec!``[``1.``,` `5.``,` `7.``,` `15.``]``;`
`let` result`:` `Vec``<`Band`>` `=` `ContourBuilder``::`new`(``7``,` `6``)`
`.``use_quad_tree``(``true``)`
`.``contours``(``&`values`,` `&`intervals`)``?``;`
`assert_eq!``(`result`.``len``(``)``,` `3``)``;`

The result is a vector of

structs, each one containing a geometry (`Band`

) and the minimum and maximum values of the band.`MultiPolygon <f64>`

Note that you can specify the coordinates of the grid and the distance between points (on x- and y-axis)
using the

, `x_origin`

, `y_origin`

and `x_step`

parameters of the `y_step`

constructor :`ContourBuilder`

`let` result`:` `Vec``<`Band`>` `=` `ContourBuilder``::`new`(``7``,` `6``)`
`.``x_origin``(``-``6.``144721``)`
`.``y_origin``(``51.``781713``)`
`.``x_step``(``0.``118759``)`
`.``y_step``(``-``0.``089932``)`
`.``use_quad_tree``(``true``)`
`.``contours``(``&`values`,` `&`intervals`)``?``;`

`geojson`

feature

`geojson`

Each

struct contains a geometry (`Band`

) and the minimum and maximum values of the band.
It can be serialized to geojson using the `MultiPolygon <f64>`

`geojson`

feature:`[``dependencies``]`
`contour-isobands = { version = "0.3.0", features ``=` `[``"`geojson`"``]` }

`use` `contour_isobands``::``{`ContourBuilder`,` Band`}``;`
`use` `geojson``::``{`Feature`,` FeatureCollection`}``;`
`let` values `=` `vec!``[`
`1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,`
`1.``,` `5.``,` `5.``,` `5.``,` `5.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `15.``,` `15.``,` `15.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `10.``,` `10.``,` `10.``,` `5.``,` `1.``,`
`1.``,` `5.``,` `5.``,` `5.``,` `5.``,` `5.``,` `1.``,`
`1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,` `1.``,`
`]``;`
`let` intervals `=` `vec!``[``1.``,` `5.``,` `7.``,` `15.``]``;`
`let` result `=` `ContourBuilder``::`new`(``7``,` `6``)`
`.``use_quad_tree``(``true``)`
`.``contours``(``&`values`,` `&`intervals`)``?``;`
`let` features `=` result`.``iter``(``)`
`.``map``(``|``band``|` `band``.``to_geojson``(``)``)`
`.``collect``::``<``Vec``<``geojson``::`Feature`>``>``(``)``;`
`let` geojson_string `=` `GeoJson``::`from`(`
FeatureCollection `{`
bbox`:` `None``,`
features`,`
foreign_members`:` `None``,`
`}``)``.``to_string``(``)``;`

Note that the polygons exterior rings are oriented in the counter-clockwise direction, while the interior rings are oriented in the clockwise direction (in accordance with the GeoJSON RFC 7946 specification).

`parallel`

feature

`parallel`

`[``dependencies``]`
`contour-isobands = { version = "0.3.0", features ``=` `[``"`parallel`"``]` }

The

feature enables the use of the `parallel`

crate to parallelize the computation of the isobands.
By enabling this feature, the `rayon`

struct exposes a `ContourBuilder`

method :`par_contours`

`let` result`:` `Vec``<`Band`>` `=` `ContourBuilder``::`new`(``7``,` `6``)`
`.``x_origin``(``-``6.``144721``)`
`.``y_origin``(``51.``781713``)`
`.``x_step``(``0.``118759``)`
`.``y_step``(``-``0.``089932``)`
`.``use_quad_tree``(``true``)`
`.``par_contours``(``&`values`,` `&`intervals`)``?``;`

Note that you can still use the

method if you don't want
to use parallelism (indeed, on small grids, the overhead of parallelism can be higher than the gain).`contours`

## WASM demo

A demo of this crate, compiled to WebAssembly, is available on https://mthh.github.io/contour-isobands-wasm/.

## Difference with the contour crate (from `mthh``/`contour`-`rs

repository)

`mthh`

`/`contour`-`rsThe contour crate computes isolines
(cf. wikipedia:Marching_squares) and
use them to compute their corresponding contour polygons *(i.e. polygons that contain all points above the threshold defined
for a given isoline)* and isobands *(i.e. contour polygons that contain all points between
a minimum and a maximum bound)*.
This

is dedicated to isobands, also uses marching squares
(cf. wikipedia:Marching_squares#Isobands)
but uses a slightly different implementation for the disambiguation of saddle points.
It also offers parallel computation of isobands using the `contour-isobands-rs`

crate, which can be beneficial
when computing isobands on large grids and with many thresholds.`rayon`

## Licence

Since this is mostly a port of https://github.com/RaumZeit/MarchingSquares.js which is licenced under the Affero General Public License v3.0, this project is also licenced under the Affero General Public License v3.0. See the LICENSE file for details.

#### Dependencies

~0.7–1.3MB

~27K SLoC