8

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.

Community
  • 1
  • 1
politicalEconomist
  • 981
  • 1
  • 12
  • 19

3 Answers3

5

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 // ;-)

Barend Gehrels
  • 967
  • 5
  • 8
  • 1
    **I fixed a few errors in my code to make things line up better with your answer. Thanks so much for responding, unfortunately I am still not getting it. I spent a long time trying to decipher the [documentation for model::polygon](http://www.boost.org/doc/libs/1_53_0/libs/geometry/doc/html/geometry/reference/models/model_polygon.html) and never in a million years would have figured out how to get to the points. Let me ask a few questions: – politicalEconomist Mar 14 '13 at 03:47
  • 1) How did you determine from that the coordinate points in the polygon object are called the *exterior ring*? I see Point, PointList, RingList, points, inner ring, but never *exterior ring*. 2) How did you then determine that the *exterior ring* is stored as std::vector? 3) How did you know to use `exterior_ring()` to access the std::vector? – politicalEconomist Mar 14 '13 at 03:47
  • 4) Even though I understand all of that now I still cannot do all the things I usually expect I can do with a std:vector. For example: double vectSize = boost::geometry::exterior_ring(hull).size(); //returns 8 But trying to access the elements does not work: double element1 = boost::geometry::exterior_ring(hull)[0]; error: cannot convert ‘boost::tuples::tuple’ to ‘double’ in initialization – politicalEconomist Mar 14 '13 at 03:48
  • 1: The model::polygon is just an instance of the Polygon Concept. And exterior_ring does work in general on a Polygon Concept. Boost.Geometry follows the OGC conventions, so that might give some extra light on your questions... It does not need to be a std::vector. It can also be a std::deque, etc. However, it should follow the Boost.Range concept. It is all in the docs (hmm, it should be all in the docs) How did I figure that out... I wrote it. – Barend Gehrels Mar 15 '13 at 18:06
  • 4: You should probably first get yourself comfortable with the standard library. double vectSize=... a C++ programmer should write int vectSize (or better: std::size_t vectSize). After that you try to set a double element1 to the element of the vector, which is a point... A point is not a double, a point contains two (or more) doubles. So you should, in your example, use the Boost.Tuple interface to get either x or y coordinate. So you should be comfortable with Boost.Tuple too... – Barend Gehrels Mar 15 '13 at 18:09
0

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

Deepscorn
  • 802
  • 10
  • 20
0

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 ) );
}
sehe
  • 328,274
  • 43
  • 416
  • 565
Tam
  • 1
  • 1