ID field intermittently lost in custom point class

℡╲_俬逩灬. 提交于 2019-12-17 16:53:27

问题


I'm building a C++ program which needs to handle geometry. I have been trying to get boost::geometry to work, but I am having the following issue. My points need to maintain an ID value or other identifying tag (I need to link them to properties stored in other objects). I can successfully register this point using BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET and carry out boost::geometry operations, however the moment I carry out any operations with it boost::geometry seems to create new copies of my point without the id value.

Is there something I'm missing about using boost::geometry with custom points that would make it possible to do what I'm trying to do, or do I have to re-think my approach and find some other way to do what I'm trying to do?

The following code shows an example point class (int id is the identifier) and also a sample of code which compiles and runs (with appropriate #include and namespace declarations) however it keeps removing my point IDs:

point class:

class My_Point
{
public:

    My_Point(const My_Point &p);
    My_Point(double x = 0.0, double y = 0.0, int new_id = 0);

    const double Get_X() const;
    const double Get_Y() const;

    void Set_X(double new_x);
    void Set_Y(double new_y);

    const int Get_ID() const;
    void Set_ID(int new_id);

private:
    int id;
    double x;
    double y;
}

copy constructor:

My_Point::My_Point(const My_Point &p) {
    Set_X(p.Get_X());
    Set_Y(p.Get_Y());
    Set_ID(p.Get_ID());
} 

test code:

void TestPolygon()
{
vector < My_Point > p;

p.push_back(My_Point(0.0, 0.0, 0));
p.push_back(My_Point(1.0, 0.0, 1));
p.push_back(My_Point(1.0, 1.0, 2));
p.push_back(My_Point(0.0, 1.0, 3));
p.push_back(My_Point(0.0, 0.0, 4));

cout << "Initial points are:\n";

for (int i = 0, n = p.size(); i < n; i++)
{
    cout << point_to_string(p.at(i)) << "\n";
}

detect_enter();

polygon<My_Point> poly;
append(poly, p);

//this code gives each point with an incorrect id of 0
cout << "Polygon points are:\n";

for (int i = 0, n = poly.outer().size(); i < n; i++)
{
    cout << point_to_string(poly.outer().at(i)) << "\n";
}

detect_enter();

strategy::transform::rotate_transformer<degree, double, 2, 2> rotate(45.0);

for (int i = 0, n = poly.outer().size(); i < n; i++)
{
    transform(poly.outer().at(i), poly.outer().at(i), rotate);
}

vector<My_Point> p2;
p2 = poly.outer();

//this code gives an incorrect id of 0.
cout << "Final points are:\n";

for (int i = 0, n = p2.size(); i < n; i++)
{
    cout << point_to_string(p2.at(i)) << "\n";
}

detect_enter();

//this code gives the correct id values as expected.
cout << "Original points were:\n";

for (int i = 0, n = p.size(); i < n; i++)
{
    cout << point_to_string(p.at(i)) << "\n";
}
}

回答1:


As sehe pointed out, the library only knows how to access X and Y coordinates of My_Point. Furthermore, the rotate_transformer only knows how to rotate the geometrical part of your Points, it isn't aware that you're storing IDs and that you'd like to copy them. You could try to write your own strategy for this. Something like (not tested):

struct my_rotate_transformer
    : public strategy::transform::rotate_transformer<degree, double, 2, 2>
{
    typedef strategy::transform::rotate_transformer<degree, double, 2, 2> base_t;

    my_rotate_transformer(double angle)
        : base_t(angle)
    {}  

    template <typename P1, typename P2>
    bool apply(P1 const& p1, P2& p2) const
    {
        p2.Set_ID(p1.Get_ID());
        return base_t::apply(p1, p2);
    }
}

It's similar to the way how std::transform() can be used. You must pass a UnaryOperation which transforms the elements of a Range the way you like it. In Boost.Geometry strategies are used for this purpose.

Btw, it's a simple case, you could just manually copy/set the IDs.

Another thing is that bg::transform() works for arbitrary Geometry so you could just pass Polygons there (however you need another Polygon for this):

polygon<My_Point> poly_in;
polygon<My_Point> poly_out;
bg::transform(poly_in, poly_out, my_rotate_transformer(45))

Using append() you can directly append Points to Polygon. There is no need to use temporary std::vector, I think.

Also, have in mind that some algorithms creates entirely new Geometries, containing new Points, e.g. intersection() or convex_hull() so IDs probably shouldn't be copied, or not all of them.

And last but not least, I'm guessing that some algorithms may cause problems in your scenario, it probably depends on the algorithm. So feel free to ask questions. Consider also subscribing to Boost.Geometry mailing list. It's a good place for getting in touch with the developers, proposing new features, reporting bugs, etc.




回答2:


You carry out a BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET. The thing is, this tells the library how to set the x and y values. It never tells the library how to set an ID value (or that it is even there).

So, the library will simply construct an identical point, logically, by using the setters for x and y, and of course, you'll be stuck with no id.



来源:https://stackoverflow.com/questions/29056414/id-field-intermittently-lost-in-custom-point-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!