Search code examples
c++boostbufferpolygonboost-geometry

Poor or incorrect results when using Boost Geometry for polygon buffering


I am using Boost::Geometry::Buffer to create an inner offset, or dilation, of irregularly shaped polygons. The image below shows an example input and output. The original polygon is displayed in white and the offset polygon is displayed in purple. There are two sets of extraneous lines on the right side of the purple polygon (seen as the thicker/brighter regions) and a long extraneous spike on the left.

Example output from Boost::Geometry::Buffer

The polygon used in the example is pretty basic. It lacks any kind of symmetry, but has no sharp turns or jagged edges. The raw data for the input polygon is this list of Cartesian points:

x: 61.2101898, y: 81.9854202
x: 61.3715706, y: 82.0616913
x: 61.4335442, y: 82.1924744
x: 61.4778328, y: 82.2606735
x: 61.5202942, y: 82.3236465
x: 61.5283432, y: 82.3527832
x: 61.5431557, y: 82.4063950
x: 61.5221367, y: 82.4381790
x: 61.3944855, y: 82.4706116
x: 61.3497124, y: 82.4679184
x: 61.3284111, y: 82.4674301
x: 61.1539803, y: 82.3401947
x: 61.1297760, y: 82.2854843
x: 61.0671043, y: 82.1489639
x: 61.0682831, y: 82.0264740
x: 61.0667953, y: 82.0112915
x: 61.0663414, y: 82.0066376
x: 61.0707321, y: 81.9976196
x: 61.0998306, y: 81.9980850
x: 61.2101898, y: 81.9854202

This is the code that I am using to generate the offset polygon:

namespace bg = boost::geometry;
typedef bg::model::d2::point_xy<float> BoostPoint;
typedef bg::model::polygon<BoostPoint> BoostPolygon;
typedef bg::model::multi_polygon<BoostPolygon> BoostMultipolygon;

std::vector<BoostPoint> points;
BoostPoint tmpPoint;
BoostPolygon input;
BoostMultipolygon output;

/* currentContour is a pointer to a non-Boost specialized polygon
*  structure. It contains a bool indicating clockwise/counterclockwise
*  direction and a list of lines, each line defined by two x-y points.
*  For each line, point 2 follows point 1 in the clockwise/counterclockwise
*  direction of that polygon.
*/

if (currentContour->clockwise) {
    for (int line = 0; line < currentContour->lines.size(); line++) {
        bg::set<0>(tmpPoint, currentContour->lines[line].x1);
        bg::set<1>(tmpPoint, currentContour->lines[line].y1);
        points.push_back(tmpPoint);
    }
    // Add last point to wrap back around to starting point.
    bg::set<0>(tmpPoint, currentContour->lines.back().x2);
    bg::set<1>(tmpPoint, currentContour->lines.back().y2);
    points.push_back(tmpPoint);
}
else {
    for (int line = currentContour->lines.size() - 1; line >= 0; line--) {
        bg::set<0>(tmpPoint, currentContour->lines[line].x2);
        bg::set<1>(tmpPoint, currentContour->lines[line].y2);
        points.push_back(tmpPoint);
    }
    // Add last point to wrap back around to starting point.
    bg::set<0>(tmpPoint, currentContour->lines.front().x1);
    bg::set<1>(tmpPoint, currentContour->lines.front().y1);
    points.push_back(tmpPoint);
}

// Transfer points to polygon object.
bg::assign_points(input, points);
// Declare boost strategies for buffer function.
bg::strategy::buffer::distance_symmetric<double> distance_strategy(-0.05);
bg::strategy::buffer::join_miter join_strategy;
bg::strategy::buffer::end_round end_strategy;
bg::strategy::buffer::point_circle point_strategy;
bg::strategy::buffer::side_straight side_strategy;
// Perform polygon buffering.
bg::buffer(input, output, distance_strategy, side_strategy, join_strategy,
    end_strategy, point_strategy);

Boost is a major reputable library, so I have a hard time believing that its geometry APIs would fail on a polygon so simple. Why am I getting those extraneous lines? If any additional information would be helpful, I will be happy to provide it.


Solution

  • Boost::geometry::strategy::buffer::join_miter had a bug that caused this behavior before version 1.71. Updating boost should fix this problem.

    Relevant GitHub issue: https://github.com/boostorg/geometry/issues/596