10
votes

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?

2
Are you getting compilation errors or are you searching for a logic error? What exactly is not working for you?sbrett
I updated my code. Since I can't compile I don't know if I'm doing things right semantically at all, so I'm looking for any kind of error I made.ytg
The boost version I had on my system was 1.35, so I updated to whatever it is they have on the SVN (a soon to be 1.48 I think). I'm able to get past the problems regarding not having boost::geometry and see exactly what kind of errors you are getting, and it's messy, but there's not that many. From what I can tell just by looking at it, the boost::size method defined as part of what I believe to be boost_range, does not seem to know how to handle your model::polygon<spherical_point>. After looking at the boost range reference, I noticed that it mentioned required functions such as range_begin.sbrett
Ok, you're going to have to clarify one more thing, and that is what the logic is behind your if (boost::size(*it) >= 2) conditional. If you're trying to see if some part of the polygon is >= 2 or whether this is the 2nd element in the vector... Do you want information pertaining to the enumerated position of the polygon object inside the resultVector or do you want information pertaining to the polygon object itself, such as the number of spherical_points within it?sbrett
Well, that (boost::size(*it) >= 2) was there to make sure that one of the rings (I was aiming for the outer ring, but that just wasn't the proper way of doing it) has at least 2 points. Which should have been >=3 or >2, otherwise it's quite "pointless" to talk about polygons :)ytg

2 Answers

4
votes

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;
        }       
    }
}
5
votes

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;
      }
    }
}