Crate geo_buffer

source ·
Expand description

The geo-buffer crate provides methods to buffer (to inflate or deflate) certain primitive geometric types in the GeoRust ecosystem via a straight skeleton.

This crate can handle simple polygons properly as well as non-convex polygons, (valid) sets of polygons, and polygons with one or more holes. Note that each method assumes valid primitives as a parameter, but Polygon/MultiPolygon modules do not enforce this validity automatically nor does this crate. (See more details on ‘Validity’ section in Polygon/MultiPolygon and OGC standards.)

This crate use a straight skeleton to buffer (multi-)polygons. You can also get a straight skeleton separately by proper methods.

For now, the only viable geometric primitives are Polygon and MultiPolygon (the rest of the primitives will be added as well).

Quick Guide

The buffer_polygon() function (resp. buffer_multi_polygon() function) produces a MultiPolygon after applying an offset operation to the given Polygon (resp. MultiPolygon). The absolute value of the argument passed with determines the distance between each edge of the result multi-polygon and the original input. The sign determines the direction where the result expands. Positive values mean it going outward — that is, it inflates, — and negative values mean going inward — it deflates —.

Each code snippets below is a brief guide to use this crate. Click ‘Result’ to expand the visualized result. (The red polygon designates the input, and the orange one designates the results.)

Example 1

You can manipulate a polygon with ease by a single function call.

use geo_buffer::buffer_polygon;
use geo::{Polygon, MultiPolygon, LineString};
 
let p1 = Polygon::new(
    LineString::from(vec![(0., 0.), (1., 0.), (1., 1.), (0., 1.)]), vec![],
);
let p2: MultiPolygon = buffer_polygon(&p1, -0.2);
 
let expected_exterior = LineString::from(vec![(0.2, 0.2), (0.8, 0.2), (0.8, 0.8), (0.2, 0.8), (0.2, 0.2)]);
assert_eq!(&expected_exterior, p2.0[0].exterior())
 
Result

Example 2

This example shows the case where the polygon is split while it deflates.

use geo_buffer::buffer_polygon;
use geo::{Polygon, MultiPolygon, LineString};
 
let p1 = Polygon::new(
    LineString::from(vec![(0., 0.), (4., 0.), (4., 4.), (2., 1.), (0., 4.)]), vec![],
);
let p2: MultiPolygon = buffer_polygon(&p1, -0.45);
 
Result

Example 3

You can apply this function to a set of Polygons (i.e. MultiPolygon). The constituent polygons may be integrated while they expand.

use geo_buffer::buffer_multi_polygon;
use geo::{Polygon, MultiPolygon, LineString};
 
let p1 = Polygon::new(
    LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.)]), vec![],
);
let p2 = Polygon::new(
    LineString::from(vec![(3., 3.), (5., 3.), (5., 5.), (3., 5.)]), vec![],
);
let mp1 = MultiPolygon::new(vec![p1, p2]);
let mp2 = buffer_multi_polygon(&mp1, 0.9);
 
Result

Example 4

If you want to apply this function to each member (and not want to unify them), just traversing over an iterator and collecting them will be fine. (You can get a vector of MultiPolygons thanks to the ‘turbofish’ syntax:::<>.)

use geo_buffer::buffer_polygon;
use geo::{Polygon, MultiPolygon, LineString};
 
let p1 = Polygon::new(
    LineString::from(vec![(0., 0.), (2., 0.), (2., 2.), (0., 2.)]), vec![],
);
let p2 = Polygon::new(
    LineString::from(vec![(3., 3.), (5., 3.), (5., 5.), (3., 5.)]), vec![],
);
let mp1 = MultiPolygon::new(vec![p1, p2]);
let mp2 = mp1.0.iter().map(|x| buffer_polygon(x, 0.9)).collect::<Vec<_>>();
 
Result

Reference

This is a Rust implementation of this paper12. (See also Notes below.)

Notes

It has been shown that the algorithm presented in this paper is incorrect.3 Thus we slightly modified the algorithm for some edge cases.


  1. Felkel, Petr; Obdržálek, Štěpán (1998), “Straight skeleton implementation”, SCCG 98: Proceedings of the 14th Spring Conference on Computer Graphics, pp. 210–218. 

  2. The implementation of the straight skeleton algorithm in CGAL (The Computational Geometry Algorithms Library) is also based on this paper. 

  3. Huber, Stefan (2012), Computing Straight Skeletons and Motorcycle Graphs: Theory and Practice, Shaker Verlag. 

Modules

  • This module provides a conceptual structure of points and half-lines.

Structs

  • This structure conceptually represents a point or a vector on the 2-dimensional Cartesian plane.
  • This structure conceptually represents a half-line (which also known as “Ray”).

Functions

  • This function returns the buffered (multi-)polygon of the given multi-polygon. This function creates a miter-joint-like corners around each convex vertex.
  • This function returns the buffered (multi-)polygon of the given multi-polygon, but creates a rounded corners around each convex vertex. Therefore, distance from each point on border of the buffered polygon to the closest points on the given polygon is (approximately) equal.
  • This function returns the buffered (multi-)polygon of the given polygon. This function creates a miter-joint-like corners around each convex vertex.
  • This function returns the buffered (multi-)polygon of the given polygon, but creates a rounded corners around each convex vertex. Therefore, distance from each point on border of the buffered polygon to the closest points on the given polygon is (approximately) equal. Click ‘Result’ below to see how this function works.
  • This function returns a set of LineSting which represents an instantiated straight skeleton of the given multi-polygon. Each segment of the straight skeleton is represented as a single LineString, and the returned vector is a set of these LineStrings. If either endpoints of a LineString is infinitely far from the other, then this LineString will be clipped to one which has shorter length. The order of these LineStrings is arbitrary. (There is no gauranteed order on segments of the straight skeleton.)
  • This function returns a set of LineSting which represents an instantiated straight skeleton of the given polygon. Each segment of the straight skeleton is represented as a single LineString, and the returned vector is a set of these LineStrings. If either endpoints of a LineString is infinitely far from the other, then this LineString will be clipped to one which has shorter length. The order of these LineStrings is arbitrary. (There is no gauranteed order on segments of the straight skeleton.)