1
votes

I'm using boost geometry to manage some polygons, and I need to both expand and shrink them by given amounts. I'm using boost::geometry::buffer to accomplish this, and I'm wondering if there's a better alternative. My concern is that if I expand, say, a rectangle I end up with a polygon with 12 vertices (8 of them being irrelevant). Here's some sample code:

#include <iostream>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

using point_t = boost::geometry::model::d2::point_xy<double>;
using polygon_t = boost::geometry::model::polygon<point_t>;
using mpolygon_t = boost::geometry::model::multi_polygon<polygon_t>;

mpolygon_t expand_polygon(const polygon_t& polygon,
                          const double distance) {
    mpolygon_t scaled_polygon;
    // DistanceStrategy is symmetric; want straight lines (no curves)
    boost::geometry::strategy::buffer::distance_symmetric<double>
      distance_strategy{distance};

    // SideStrategy is straight; grow equally on all sides
    boost::geometry::strategy::buffer::side_straight side_strategy;

    // JoinStrategy is miter; 1.0 as limit; Sharp (not rounded) joins
    boost::geometry::strategy::buffer::join_miter join_strategy;

    // EndStrategy is flat; flat (not rounded) ends
    boost::geometry::strategy::buffer::end_flat end_strategy;

    // PointStrategy is square; squares, not circles, if poly is just a point
    boost::geometry::strategy::buffer::point_square point_strategy;

    boost::geometry::buffer(polygon, scaled_polygon,
                            distance_strategy,
                            side_strategy,
                            join_strategy,
                            end_strategy,
                            point_strategy);

    // return scaled polygon offset by supplied distance
    return scaled_polygon;
}

int main() {
    using boost::geometry::get;
    polygon_t rect;
    boost::geometry::read_wkt("POLYGON((5 5,5 8,8 8,8 5, 5 5))", rect);
    mpolygon_t expanded_mpoly = expand_polygon(rect, 1.0);
    auto list_coordinates = [](const point_t& pt) {
                                std::cout.precision(std::numeric_limits<double>::max_digits10);
                                std::cout << "vertex(" << get<0>(pt)
                                          << ", " << get<1>(pt) << ")" << std::endl;
                            };
    boost::geometry::for_each_point(expanded_mpoly, list_coordinates);

    return 0;
}

And here's the output:

vertex(4, 5)
vertex(4, 8)
vertex(4, 9)
vertex(5, 9)
vertex(8, 9)
vertex(9, 9)
vertex(9, 8)
vertex(9, 5)
vertex(9, 4)
vertex(8, 4)
vertex(5, 4)
vertex(4, 4)
vertex(4, 5)

Is there a strategy argument that I need to provide? Some other fiefdom of boost I should be looking at?

1

1 Answers

2
votes

Boost contains simplify algorithm (it uses Ramer–Douglas–Peucker algorithm). For example in your polygon there are 3 points p1,p2,p3, we calculate the distance between point p2 and the line |p1p3| , if this distance is less than the given epsilon value , p2 point is removed from polygon. So if you use this function with very small value of epsilon (to remove collinear points) you can remove all redundant points from all edges your polygon. Try this

mpolygon_t out; // to hold new geometry
boost::geometry::simplify(expanded_mpoly,out,0.00001); // very small epsilon value
auto list_coordinates = [](const point_t& pt) {
                            std::cout.precision(std::numeric_limits<double>::max_digits10);
                            std::cout << "vertex(" << get<0>(pt)
                                      << ", " << get<1>(pt) << ")" << std::endl;
                        };
boost::geometry::for_each_point(out, list_coordinates); // print out

as output you see

vertex(9, 9)
vertex(9, 4)
vertex(4, 4)
vertex(4, 9)
vertex(9, 9)