#computational-geometry #gis #polygon #algorithm #label #position #geospatial

polylabel

A Rust implementation of the Polylabel algorithm for finding optimum polygon label positions

39 releases (stable)

3.2.0 Feb 26, 2024
3.1.0 Nov 28, 2023
2.5.0 Jul 13, 2023
2.4.3 Mar 14, 2023
0.1.6 Oct 12, 2016

#72 in Geospatial

Download history 72/week @ 2024-07-15 85/week @ 2024-07-22 45/week @ 2024-07-29 109/week @ 2024-08-05 107/week @ 2024-08-12 46/week @ 2024-08-19 34/week @ 2024-08-26 311/week @ 2024-09-02 48/week @ 2024-09-16 134/week @ 2024-09-23 24/week @ 2024-09-30 41/week @ 2024-10-07 46/week @ 2024-10-14 39/week @ 2024-10-21 5/week @ 2024-10-28

132 downloads per month
Used in 3 crates

MIT license

400KB
630 lines

Test and Build Coverage Status

Polylabel-rs

A Rust implementation of the Polylabel algorithm

The orange dot is the polygon centroid. The teal dot is the ideal label position. Red boxes show the search space. GIF

You can generate this visualisation yourself by cloning this repo, switching to the visualise branch, and opening the visualise.ipynb Jupyter notebook, then stepping through the cells. You can also easily visualise a Polygon of your own using the notebook.

How to Use

extern crate polylabel;
use polylabel::polylabel;

extern crate geo;
use geo::{Point, Polygon};

let coords = vec![
    (0.0, 0.0),
    (4.0, 0.0),
    (4.0, 1.0),
    (1.0, 1.0),
    (1.0, 4.0),
    (0.0, 4.0),
    (0.0, 0.0)
];
let poly = Polygon::new(coords.into(), vec![]);
let label_pos = polylabel(&poly, &0.10);
// Point(0.5625, 0.5625)

Command-Line Tool

A command-line tool is available: cargo install polylabel_cmd. This enables the polylabel command, which takes a GeoJSON file as input, as well as an optional (-t / --tolerance) tolerance value. See more at crates.io.

Documentation

https://docs.rs/polylabel

FFI

Enable the Cargo ffi and headers features to enable this functionality

Call polylabel_ffi with the following three mandatory arguments:

  • Array (a struct with two fields):
    • data: a void pointer to an array of two-element c_double arrays, each of which represents a point on the exterior Polygon shell)
    • len: the length of the data array, a size_t
  • WrapperArray (a struct with two fields):
    • data: a void pointer to an array of Arrays, each entry representing an interior Polygon ring. Empty if there are no rings.
    • len: the length of the data array, a size_t. 0 if it's empty.
  • tolerance, a c_double

The function returns a struct with two c_double fields:

  • x_pos
  • y_pos

Headers are provided in the include directory. A Python example is available in ffi.py

An auto-generated header file is available at include/header.h

Performance vs Accuracy

Using a 4-core 2.3 GHz Intel Core i5, finding a label position on a ~9k-vertex polygon (representing the Norwegian mainland) using a tolerance of 1.0 takes around 9 ms. Depending upon the dimensions of your polygon(s), you may require a higher tolerance (i.e. a smaller number). See here for some guidance on the accuracy provided by each decimal place.

Binaries

are available in releases.

License

MIT

Dependencies

~9MB
~136K SLoC