8
votes

How do I get a boost::geometry polygon into an STL object?

I am sure this must be simple because I cannot find examples anywhere in the documentation. Yet I have spent about 4 full work days trying to do this tiny thing. I am new to C++ (long time R programer), but these small data conversion things are driving me insane.

Yes there is a question whose title is much like mine: Getting the coordinates of points from a Boost Geometry polygon

But the code is so complex (and the poster kept changed it so many times) that I cannot make heads or tails of it, nor can I imagine that other C++ newbies will be able to.

This is a simple example that should translate to some of the other boost::geometry data types, so hopefully anyone can follow it.

 #include <iostream>

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

 BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

 //One thing I tried is a function to use with `for_each_point()` so I set that up first.

  template <typename Point>
  void get_coordinates(Point const& p)
  {
  using boost::geometry::get;
  std::cout << get<0>(p) get<1>(p) << std::endl;
  }

  int main()
  {
  typedef boost::tuple<double, double> point;
  typedef boost::geometry::model::polygon<point> polygon;

  polygon poly;
  boost::geometry::read_wkt("polygon((2.0 1.3, 2.4 1.7, 2.8 1.8, 3.4 1.2, 3.7 1.6, 3.4 2.0, 4.1 3.0, 5.3 2.6, 5.4 1.2, 4.9 0.8, 2.9 0.7, 2.0 1.3))", poly);

   polygon hull;
   boost::geometry::convex_hull(poly, hull);

 // Now I know I can `dsv()` and print to the screen like this:

  using boost::geometry::dsv;
  std::cout
    << "hull: " << dsv(hull) << std::endl;

  // And/Or I can use my function with for_each_point()



  boost::geometry::for_each_point(hull, get_coordinates<point>);

return 0;
}

How do I get these coordinates into an STL container? I would prefer two std::vector one for x and one for y, but anything will do.

3

3 Answers

5
votes

Polygons are already in a STL container format, the boost::geometry::polygon is has its exterior ring and interior rings stored a std::vector, by default.

What you might want (considering your comments) is:

  polygon hull;
  boost::geometry::convex_hull(poly, hull);
  boost::geometry::for_each_point(boost::geometry::exterior_ring(hull), get_coordinates<point>);

This will work if you correct your get_coordinates function to (note the << usage):

  template <typename Point>
  void get_coordinates(Point const& p)
  {
      using boost::geometry::get;
      std::cout << get<0>(p) << ", " << get<1>(p) << std::endl;
  }

And change your comment indicators to // ;-)

0
votes

For example:

boost::geometry::model::polygon<Point> polygon;
polygon.outer().push_back( point );

So, polygon.outer() is std::vector (external one, as Barend Gehrels said). See here: boost reference

0
votes

You can use iterators with the boost models to iterate over all the points and add them to whatever kind of container you like.

Polygon models are slightly more complicated because they have a single outer, and potentially multiple inner, rings.

Assuming you want all the points in the outer ring of the "hull" object (or any polygon, including the original "poly"), just iterate over it and add them to a standard vector point-by-point.

If you want a vector of x, and a vector of y, use the same method.

::std::vector< point > hullPoints;
::std::vector< double > hullXPoints;
::std::vector< double > hullYPoints;

// the auto keyword makes declaring iterators easy
for ( auto hullIterator = hull.outer().begin;
      hullIterator != hull.outer().end();
      ++hullIterator )
{
     // for a vector of point types, just add the points one by one
     hullPoints.push_back( *hullIterator );

     // for vectors of x and y, extract the x/y from the point
     hullXPoints.push_back( get<0>( *hullIterator ) );
     hullYPoints.push_back( get<1>( *hullIterator ) );
}