Boost Polygon:euclidean_distance 的问题

Posted

技术标签:

【中文标题】Boost Polygon:euclidean_distance 的问题【英文标题】:Boost Polygon: Issue with euclidean_distance 【发布时间】:2016-06-14 06:54:17 【问题描述】:

我有以下代码应该计算两个矩形之间的欧几里得距离。我使用 GCC 4.7.3 和 Boost v1.58.0 编译

#include <iostream>
#include <cmath>
#include <boost/polygon/polygon.hpp>
#include <boost/geometry.hpp>

namespace gtl = boost::polygon;
using namespace boost::polygon::operators;

typedef gtl::rectangle_data<int> LayoutRectangle;

int main(int argc, char** argv)

    LayoutRectangle t(16740130,29759232,16740350,29760652);
    LayoutRectangle n(16808130,29980632,16808350,29982052);

    std::cout << gtl::euclidean_distance(t, n) << std::endl;

    std::cout << gtl::euclidean_distance(t, n, gtl::HORIZONTAL) << " "
              << gtl::euclidean_distance(t, n, gtl::VERTICAL) << std::endl;

    std::cout << gtl::square_euclidean_distance(t, n) << std::endl;
    std::cout << std::sqrt(gtl::square_euclidean_distance(t, n)) << std::endl;
    std::cout << (int) std::sqrt(gtl::square_euclidean_distance(t, n)) << std::endl;

    return 0;

上面的代码产生了以下输出:

38022.6
67780 219980
52985328800
230185
230185

正确答案是 230185。现在如果我去查看 boost 多边形库中 euclidean_distance() 的实现,我会看到:

  template <typename rectangle_type, typename rectangle_type_2>
  typename enable_if< typename gtl_and_3<y_r_edist2, typename is_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type,
                                                          typename is_rectangle_concept<typename geometry_concept<rectangle_type_2>::type>::type>::type,
                       typename rectangle_distance_type<rectangle_type>::type>::type
  euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) 
    double val = (int)square_euclidean_distance(lvalue, rvalue);
    return std::sqrt(val);
  

这看起来与我的代码中给出正确答案 (230185) 的 std::sqrt(gtl::square_eclidean_distance(t,n)) 行相同。那么为什么我用gtl::euclidean_distance() 得到38022.6?我在这里没有看到什么?

【问题讨论】:

在做了一些调查之后,对我来说它看起来像是一个错误。 svn.boost.org/trac/boost/ticket/12268 【参考方案1】:

看起来内部计算正在溢出。 我不认为这是一个 library 错误,该库与底层(未选中)int 类型一起使用不正确。 (但是,我在最后提到的库中有一个不同的错误。)

尝试使用更小的问题“整数表示”:

例如:

LayoutRectangle t(167402,297592,167404,297607);
LayoutRectangle n(168082,299806,168084,299821);

不幸的是,整数算术中没有通用的解决方案,除了 0) 使用更高的精度可以给你一些东西,1) 缩放问题 2) 使用多精度,3) 使用有理算术和整数部分

(对于浮点,解决方案只是对组件进行规范化,这就是std::abs for std::complex&lt;double&gt; 避免浮点溢出的方式)

用大整数来表示几何问题很好,但是 出于这个原因,作为一种解决方法,使用跨越距离最多为 (int)std::sqrt((double)std::numeric_limits&lt;int&gt;::max()/2) = 2^15 = 32768 的坐标。 这是一个令人惊讶的小数字。

完整代码:

#include <iostream>
#include <cmath>
#include <boost/polygon/polygon.hpp>
#include <boost/geometry.hpp>

int main()

namespace gtl = boost::polygon;
using namespace boost::polygon::operators;

typedef gtl::rectangle_data<int> LayoutRectangle;

    LayoutRectangle t(167401,297592,167403,297606);
    LayoutRectangle n(168081,299806,168083,299820);

    std::cout << gtl::euclidean_distance(t, n) << std::endl;

    std::cout << gtl::euclidean_distance(t, n, gtl::HORIZONTAL) << " "
              << gtl::euclidean_distance(t, n, gtl::VERTICAL) << std::endl;

    std::cout << gtl::square_euclidean_distance(t, n) << std::endl;
    std::cout << std::sqrt(gtl::square_euclidean_distance(t, n)) << std::endl;
    std::cout << (int) std::sqrt(gtl::square_euclidean_distance(t, n)) << std::endl;


输出:

2302.1
678 2200
5299684
2302.1
2302

这是预期的结果。


查看代码,似乎库中存在错误,不是因为它会溢出,而是因为内部计算被强制转换为 int 而不是底层的 generic 整数数据类型。这意味着即使您使用多精度整数,结果也可能会溢出。

【讨论】:

以上是关于Boost Polygon:euclidean_distance 的问题的主要内容,如果未能解决你的问题,请参考以下文章

未能使用boost :: geometry :: model :: polygon

boost::geometry::Polygon 和“有向”折线的交集

Boost Polygon:euclidean_distance 的问题

(如何)在 boost 几何中创建自己的多边形类型并使用 multi_polygon 类型?

使用具有线段属性的Boost :: Geometry Polygon布尔值/交叉点

用孔收缩/扩展多边形的轮廓