【问题标题】:Using boost geometry to check if two lines have an intersection使用 boost 几何检查两条线是否有交点
【发布时间】:2017-01-07 03:50:12
【问题描述】:

是否可以使用 boost::geometry 来检查两条线段(每条线段由二维中的两个点给出)是否相互交叉?如果这是可能的,boost::geometry 是否也允许检查特殊情况,例如只有一个点(数字上)在另一条线上,或者两条线相等?

【问题讨论】:

  • 只是为了让我的问题更准确:我的意思是两条线段

标签: c++ boost geometry numerical-methods boost-geometry


【解决方案1】:

如果您专门谈论 Boost.Geometry API,当然是可以的。

您的代码应大致如下所示

#include <boost/geometry/geometries/segment.hpp> 
#include <boost/geometry/algorithms/intersection.hpp>

typedef boost::geometry::model::segment<Point> Segment;
Segment AB( Point(x1,y1), Point(x2,y2) );
Segment CD; //similar code

bool result = boost::geometry::intersects(AB, CD);

如果需要交点:

std::vector<Point> output; 
boost::geometry::intersection(AB, CD, output);

现在输出将有 0、1 或 2 个点,具体取决于位置。

当然,您的 Point 类型应该与 Boost.Geometry 概念“兼容”。以下代码将使 QPointF 兼容:

#include <boost/geometry/geometries/register/point.hpp>
BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET(QPointF, qreal, cs::cartesian, x, y, setX, setY);

【讨论】:

  • 作为 Boost 的新手,您介意在最后一部分详细说明合规性吗?我真的不明白那里的意思。
  • Boost.Geometry 中的类和函数使用某些元编程技巧来访问点的坐标。如果您尝试将它们与您的自定义类 Point 一起使用,您可能会遇到很多编译错误。类似于 BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET 的宏向 Boost.Geometry 解释如何访问或修改您的自定义类 Point。
【解决方案2】:

你问两条线是否相交。两条线将永远相交,除非它们平行。

以下算法可帮助您计算线段是否与线相交。它的工作原理如下:通过 3 个点的坐标计算行列式

x1 y1 1
x2 y2 1
x3 y3 1

其中 (x1;y1) 和 (x2;y2) 是代表您的直线的点, (x3; y3) 代表您的第三个点(您的线段的极端之一)。如果行列式为正,则 (x3; y3) 从 (x1;y1) 到 (x2;y2) 的向量向右,如果为负,则向右。如果行列式为 0,则该点在线上。

你需要做的就是对线段的一个极端应用这个算法两次,对另一个极端应用一次,如果行列式的乘积为负,则相交,否则不相交。

如果两条线段相交,您可以进一步计算。您所要做的就是两次应用相同的想法,只是第二次您的 (x1;y1) 和 (x2;y2) 将是您用于 (x3;y3) 和新 (x3;y3) 的值旧的 (x1;y1) 和 (x2;y2)。

我在“Sarrus 算法”下学习了这个算法,所以谷歌搜索它可能会给出更好的解释。

【讨论】:

  • 我想过,它并不适用于所有极端情况。想想第一条线段 [0,0] -> [1,1] 和第二条线段 [2,2] -> [3,3]。粗略地说,线段不相交,但两个行列式都为零,因为两条线段都是同一条(无限)线的一部分。
  • 你可以很容易地检查这个特定情况 - 你可以从 2 个点计算线函数,并比较斜率和系数,然后检查它们是否不重叠。
【解决方案3】:

不使用 BOOST_GEOMETRY_REGISTER_POINT_2D_GET_SET 的初学者示例

namespace bg = boost::geometry;

typedef bg::model::point<double, 2, bg::cs::cartesian> point_t;
typedef bg::model::segment<point_t> segment_t;

segment_t seg1(point_t(0.0, 0.0), point_t(5.0, 5.0));
segment_t seg2(point_t(10.0, 5.0), point_t(5.0, 0.0));

bool result = boost::geometry::intersects(seg1, seg2);

【讨论】:

    【解决方案4】:

    您可以尝试使用the intersection algorithm。如果线相交,则 输出将是非空的。

    【讨论】:

    • 很有趣,但效率高吗?我只是对两条线是否相交感兴趣,我不需要生成的相交几何。更重要的是,这个函数的数值稳定性如何?如果一个点包含在另一条线的 epsilon 环境中,它会如何表现?
    • 等等,你在 2D 中。答案是“是的,除非两条线是平行的”。
    • @anjruu 我认为他的意思是两条线段
    • 哦,那没关系。我不知道 boost::geometry::intersection 的数值稳定性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多