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<double>
避免浮点溢出的方式)
用大整数来表示几何问题很好,但是
出于这个原因,作为一种解决方法,使用跨越距离最多为 (int)std::sqrt((double)std::numeric_limits<int>::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 类型?