ID 字段在自定义点类中间歇性丢失

2021-12-24 00:00:00 c++ boost boost-geometry

我正在构建一个需要处理几何的 C++ 程序.我一直在尝试让 boost::geometry 工作,但我遇到了以下问题.我的点需要维护一个 ID 值或其他识别标签(我需要将它们链接到存储在其他对象中的属性).我可以使用 BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET 成功注册这一点并执行 boost::geometry 操作,但是当我用它执行任何操作时 boost::geometry 似乎在没有 id 值的情况下创建了我的观点的新副本.

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.

使用带有自定义点的 boost::geometry 是否有什么我遗漏的地方,这将使我能够做我想做的事情,或者我是否必须重新考虑我的接近并找到其他方法来做我想做的事情?

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?

以下代码显示了一个示例点类(int id 是标识符)以及编译和运行的代码示例(使用适当的 #include>namespace 声明)但它不断删除我的点 ID:

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:

点类:

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

复制构造函数:

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

测试代码:

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:
";

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

detect_enter();

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

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

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

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:
";

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

detect_enter();

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

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

推荐答案

正如 sehe 所指出的,库只知道如何访问 My_Point 的 X 和 Y 坐标.此外,rotate_transformer 只知道如何旋转点的几何部分,它不知道您正在存储 ID 并且您想复制它们.您可以尝试为此编写自己的策略.类似(未测试):

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

它类似于 std::transform() 的使用方式.您必须传递一个 UnaryOperation,它可以按照您喜欢的方式转换 Range 的元素.Boost.Geometry 策略用于此目的.

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.

顺便说一句,这是一个简单的案例,您只需手动复制/设置 ID.

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

另一件事是 bg::transform() 适用于任意几何体,因此您可以在那里传递多边形(但是您需要另一个多边形):

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

使用 append() 您可以直接将点附加到多边形.我认为没有必要使用临时 std::vector.

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

另外,请记住,某些算法会创建全新的几何图形,包含新的点,例如intersection()convex_hull() 所以 ID 可能不应该被复制,或者不是全部.

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.

最后但并非最不重要的一点是,我猜测某些算法可能会导致您的场景出现问题,这可能取决于算法.所以请随意提问.还可以考虑订阅 Boost.Geometry 邮件列表.这是与开发人员取得联系、提出新功能建议、报告错误等的好地方.

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.

相关文章