Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the coordinates of points from a Boost Geometry polygon

I have a simple DLL doing some calculations with Boost Geometry polygons. (Mostly intersections and differences.) Since the DLL will be most likely called from C# code, and from Delphi and who knows from where else, I should convert the result into arrays that everything can handle.

UPDATE: I had simplified and somewhat corrected my code. The new code looks completely different, uses a completely different approach (for_each_point), and somehow still doesn't compile.

My new code:

#include <vector>
#include <boost/range.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>

using namespace boost::geometry;

typedef boost::geometry::model::point
    <
        double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>
    > spherical_point;
class PointAggregator {
private :
    double *x, *y;
    int count;

public :
    PointAggregator(int size) {
        x = (double*) malloc(sizeof(double) * size);
        y = (double*) malloc(sizeof(double) * size);
        count = 0;
    }

    ~PointAggregator() {
        free(x);
        free(y);
    }

    inline void operator()(spherical_point& p) {
        x[count] = get<0>(p);
        y[count] = get<1>(p);
        count++;
    }

    void GetResult(double *resultX, double *resultY) {
        resultX = x;
        resultY = y;
    }
};

void VectorToArray(std::vector<model::polygon<spherical_point>> resultVector, double x[], double y[], int *count) {
    int i = 0;      
    for (std::vector<model::polygon<spherical_point>>::iterator it = resultVector.begin(); it != resultVector.end(); ++it) {
        if (boost::size(*it) >= 2) {
            *count = boost::size(*it);
            PointAggregator* pa = new PointAggregator(*count);
            boost::geometry::for_each_point(*it, *pa);
            pa->GetResult(x, y);
            delete(pa);
            break;
        }       
    }
}

The current compilation errors are:

  1. error C2039: 'type' : is not a member of 'boost::mpl::eval_if_c' iterator.hpp 63
  2. error C3203: 'type' : unspecialized class template can't be used as a template argument for template parameter 'Iterator', expected a real type difference_type.hpp 25
  3. error C2955: 'boost::type' : use of class template requires template argument list difference_type.hpp 25
  4. error C2955: 'boost::iterator_difference' : use of class template requires template argument list difference_type.hpp 26

Which ones don't look like they have anything to do with this part of code (my filename is geometry.cpp), but everything else that uses Boost Geometry is commented out and I still get these errors, so...

Here is my bad code that I had previously (edited by sehe)

(I'm new to C++ and Boost so I might have missed some basic concept while putting code from the internet together.) I assume that I can just not iterate through a polygon that easily and I missed the non-trivial part, or that a polygon can not be used as a ring, or iterations are just not the way I thought they are, or I have no idea what else can be wrong. What did I do wrong?

like image 490
ytg Avatar asked Oct 11 '11 06:10

ytg


2 Answers

Ok, I think I've got what you're looking for here. I still don't quite understand why you're looking for this range of what I assume to be points greater than or equal to 2, but I figured out how to get it to compile when using boost::size() at least.

First off, realize that the first parameter of the function

void VectorToArray(std::vector<model::polygon<spherical_point> > resultVector, double x[], double y[], int *count)
{
...
}

is a std::vector containing instances of type model::polygon.

This means that when you dereference your iterator ...defined as

std::vector<model::polygon<spherical_point> >::iterator it

the rvalue is a model::polygon.

boost::model::polygon is NOT in and of itself Boost.Range compatible. boost::model::polygon is a type containing 5 member functions ....

inline ring_type const& outer() const { return m_outer; }
inline inner_container_type const& inners() const { return m_inners; }
inline ring_type& outer() { return m_outer; }
inline inner_container_type & inners() { return m_inners; }
inline void clear()
{
    m_outer.clear();
    m_inners.clear();
} 

This means that your *it (ie, a model::polygon) is limited to calling only those functions.

What it looks like you want to do is grab either the outer ring or one of the inner rings of each polygon in the vector (not sure which , inner or outer), and see if the range of whatever in that ring is greater than or equal to 2.

To do this, we must do some more mpl and typedef.

typedef boost::geometry::model::point<double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > spherical_point; // your definition of a spherical_point
typedef boost::geometry::model::polygon<spherical_point> polygon; //consolidation of template args for a polygon
typedef boost::geometry::ring_type<polygon>::type ring_type; // define a ring_type that can handle your spherical_point by way of the polygon typedef.
typedef boost::geometry::interior_type<polygon>::type int_type; //define a interior_type  that can handle your spherical_point 

To complete this and just up and get it "working" I decided to assume you wanted the "outer" ring for your range limit conditional.

Here is, to me, compiling code, on gcc 4.1.1 with boost 1.48. I leave whether the logic is correct up to someone else.

using namespace boost::geometry;
typedef boost::geometry::model::point<double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree> > spherical_point;
typedef boost::geometry::model::polygon<spherical_point> polygon;
typedef boost::geometry::ring_type<polygon>::type ring_type;
typedef boost::geometry::interior_type<polygon>::type int_type;

class PointAggregator 
{
private :
    double *x, *y;
    int count;

public :
    PointAggregator(int size) 
    {
        x = (double*) malloc(sizeof(double) * size);
        y = (double*) malloc(sizeof(double) * size);
        count = 0;
    }

    ~PointAggregator() 
    {
        free(x);
        free(y);
    }

    inline void operator()(spherical_point& p) 
    {
        x[count] = get<0>(p);
        y[count] = get<1>(p);
        count++;
    }

    void GetResult(double *resultX, double *resultY) 
    {
        resultX = x;
        resultY = y;
    }
};

void VectorToArray(std::vector<model::polygon<spherical_point> > resultVector, double x[], double y[], int *count) 
{
    for (std::vector<model::polygon<spherical_point> >::iterator it = resultVector.begin(); it != resultVector.end(); ++it) 
    {
      model::polygon<spherical_point> tmpPoly;
      tmpPoly = (*it);

      boost::geometry::ring_type<polygon>::type somering = tmpPoly.outer(); //typed it all out again instead of using ring_type since the complier was complaining and i didn't wanna get into it.
      int ringsize = boost::size(somering);
      if(ringsize >= 2)
      {

          *count = ringsize;
          PointAggregator* pa = new PointAggregator(*count);
          boost::geometry::for_each_point(*it, *pa);
          pa->GetResult(x, y);
          delete(pa);
          break;
      }
    }
}
like image 174
sbrett Avatar answered Sep 21 '22 03:09

sbrett


I found a few things that needed to be fixed:

  1. One issue I see is in your templates. Be sure to put spaces!
  2. boost range works on containers or ranges that hold begin, end pairs
  3. Iterators represents something like a pointer to an object. Getting the size of the iterator will not do what you want. You need to either use boost::size of a whole container, or std::distance(begin_iterator,end_iterator).

Here is a version that compiles:

#include <vector>
#include <boost/range.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>

using namespace boost::geometry;

typedef boost::geometry::model::point
    <
        double, 2, boost::geometry::cs::spherical_equatorial<boost::geometry::degree>
    > spherical_point;
class PointAggregator {
private :
    double *x, *y;
    int count;

public :
    PointAggregator(int size) {
        x = (double*) malloc(sizeof(double) * size);
        y = (double*) malloc(sizeof(double) * size);
        count = 0;
    }

    ~PointAggregator() {
        free(x);
        free(y);
    }

    inline void operator()(spherical_point& p) {
        x[count] = get<0>(p);
        y[count] = get<1>(p);
        count++;
    }

    void GetResult(double *resultX, double *resultY) {
        resultX = x;
        resultY = y;
    }
};

// added spaces to the close brackets >> becomes > >
void VectorToArray(std::vector<model::polygon<spherical_point> > resultVector, double x[], double y[], int *count) {
    for (std::vector<model::polygon<spherical_point> >::iterator it = resultVector.begin(); it != resultVector.end(); ++it) {
        if (boost::size(resultVector) >= 2) {
            // getting the size of the whole container
            *count = boost::size(resultVector);
            PointAggregator* pa = new PointAggregator(*count);
            boost::geometry::for_each_point(*it, *pa);
            pa->GetResult(x, y);
            delete(pa);
            break;
        }       
    }
}
like image 20
Andrew Hundt Avatar answered Sep 19 '22 03:09

Andrew Hundt