简体   繁体   中英

Boost::convex_hull of scattered 2-D points in STL container

I have a vector of 2-D points. Lets assume they are of the form std::pair<int,int>. I want to use boost to calculate the convex hull. That's the question. How do I do that?

The only documentation I have found is like a graduate text for a course in rationale and trivia.

Fill in the BLANKS:

#include <iostream>
#include <vector>
#include <utility>

// BLANK boost include-files
// #include <boost/geometry.hpp>
// #include <boost/geometry/geometries/polygon.hpp> // Noop.
// #include <boost/geometry/geometries/adapted/boost_tuple.hpp>
// BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

int main() {
    // Serving suggestion
    std::vector<std::pair<int, int>> A{ { 0,3 },{ 1,4 },{ 2,2 },{ 1,0 }, \
    {0,0},{ 2,0 },{ 0,1 },{ 0,2 },{ 3,1 },{ 3,3 },{ 4,4 },{ 4,3 },{ 4,2 } };

    std::vector<std::pair<int, int>> the_hull; // Fill this, please.

 // BLANK - Boost magic goes here.

    // Print convex hull of A
    for (auto h: the_hull) {
        std::cout << h.first << "," << h.second << "\n";
    }
    std::cout<< std::endl;
    return 0;
}

Note to VC++ users. I had a metric tonne of trouble getting the answers below to compile, using VC++ 2017. I finally got it working. I re-installed boost, using the windows binaries for boost 1.66. Next I had to add the following two lines to the project properties

_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_SCL_SECURE_NO_WARNINGS

The IDE treats those "warnings" as fatal. It is not sufficient to disable all warnings. Furthermore, some of the "deprecation warnings" appear to be finger-wagging from Microsoft, not officially deprecated C++ things.

You can convert vector of points into multipoint type.

#include <iostream>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <boost/geometry/geometries/point_xy.hpp>

BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

int main(){
    typedef boost::geometry::model::d2::point_xy<double> point_type;

    std::vector<std::pair<int, int>> A{ { 0,3 },{ 1,4 },{ 2,2 },{ 1,0 },
    {0,0},{ 2,0 },{ 0,1 },{ 0,2 },{ 3,1 },{ 3,3 },{ 4,4 },{ 4,3 },{ 4,2 } };

    boost::geometry::model::multi_point<point_type> pts;
    for (const auto& pt : A){
        pts.emplace_back(pt.first,pt.second);   
    }

    boost::geometry::model::polygon<point_type> poly;
    boost::geometry::convex_hull (pts, poly);

    std::cout << boost::geometry::wkt(poly) << std::endl;

    std::vector<std::pair<int, int>> the_hull; // Fill this, please.
    for (auto it = poly.outer().begin(); it != poly.outer().end(); ++it)
        the_hull.emplace_back(it->x(), it->y());

    // Print convex hull of A
    for (auto h: the_hull) {
        std::cout << h.first << "," << h.second << "\n";
    }
    return 0;
}

There is a way to do this without copying data from a container to a multi_point and vice versa. You have to register the vector container and the pair as a multi_point and point entity.

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/multi/geometries/register/multi_point.hpp> 

#include<iostream>

BOOST_GEOMETRY_REGISTER_POINT_2D(decltype(std::pair<int, int>{}), int, cs::cartesian, first, second)
BOOST_GEOMETRY_REGISTER_MULTI_POINT(decltype(std::vector<std::pair<int, int>>{}))

int main(){
    std::vector<std::pair<int, int>> A{
        { 0,3 },{ 1,4 },{ 2,2 },{ 1,0 }, { 0,0 }, { 2,0 }, { 0,1 }, { 0,2 },
        { 3,1 },{ 3,3 },{ 4,4 },{ 4,3 }, { 4,2 } 
    };
    std::cout << "A: " << boost::geometry::wkt(A) << std::endl;
    std::vector<std::pair<int, int>> B;
    boost::geometry::convex_hull(A, B);
    std::cout << "B: " << boost::geometry::wkt(B) << std::endl;
}

Output:

A: MULTIPOINT((0 3),(1 4),(2 2),(1 0),(0 0),(2 0),(0 1),(0 2),(3 1),(3 3),(4 4),(4 3),(4 2))
B: MULTIPOINT((0 0),(0 3),(1 4),(4 4),(4 2),(2 0),(0 0)

This works in Fedora 27, gcc 7.2.1, clang++ 4.0.1, Boost 1.64


For Visual C++ 2017, Boost 1.66, it is necessary to add these to properties/C C++/Preprocessor/Preprocessor Definitions

 _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_SCL_SECURE_NO_WARNINGS

The Visual Studio IDE treats those "warnings" as fatal. It is not sufficient to disable all warnings. Furthermore, some of the "deprecation warnings" appear to be Microsoft specific, not officially deprecated C++ things.

You can register your point type std::pair<int,int> with the BOOST_GEOMETRY_REGISTER_POINT_2D macro and then use it. And you don't need multipoint. Here one example. Hope it helps:

#include <iostream>
#include <utility>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/register/point.hpp>
#include <boost/geometry/geometries/polygon.hpp>

using Point = std::pair<int,int>;
BOOST_GEOMETRY_REGISTER_POINT_2D(Point, int, boost::geometry::cs::cartesian, first, second)

int main()
{
    std::vector<Point> v{ { 0,3 },{ 1,4 },{ 2,2 },{ 1,0 },{ 0,0 },{ 2,0 },{ 0,1 },{ 0,2 },{ 3,1 },{ 3,3 },{ 4,4 },{ 4,3 },{ 4,2 } };

    using Polygon = boost::geometry::model::polygon<Point>;
    Polygon poly, hull;
    poly.outer().assign(v.begin(), v.end());
    boost::geometry::convex_hull (poly, hull);

    using boost::geometry::dsv;
    std::cout << "polygon" << dsv(poly) << std::endl
              << "hull: " << dsv(hull) << std::endl;
    return 0;
}

Here the example: https://wandbox.org/permlink/j2XkmLivqcy6EtdU

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM