使用Boost Polygon的减法结果不正确

Incorrect subtract result using Boost Polygon

本文关键字:结果 不正确 Boost Polygon 使用      更新时间:2023-10-16

我有以下两个输入多边形,我想为它们计算一个相减多边形:

A:

* (0, 8)
/ 
/   
/     
(-3, 0) *-------* (3, 0)

B:

(-1, 2) *-----* (1, 2)
|     |
(-1, 1) *-----* (1, 1)

因此,我想计算A - B,它应该得到一个带有正方形切口的三角形。使用Boost Polygon进行计算会导致带有切口的不正确的部分三角形。画起来很难;结果三角形的缺失部分由三角形CCD_ 2表示。我使用以下代码来计算减法:

#include <boost/polygon/polygon.hpp>
namespace bp = boost::polygon;
int main()
{
using Polygon = bp::polygon_data<int>;
using Point = bp::point_data<int>;
using PolygonSet = bp::polygon_set_data<int>;
using SimplePolygons = std::vector<bp::polygon_data<int>>;
using namespace boost::polygon::operators;
Polygon A;
{
std::vector<Point> points{{-3, 0}, {3, 0}, {0, 8}};
bp::set_points(A, points.begin(), points.end());
}
Polygon B;
{
std::vector<Point> points{{-1, 1}, {1, 1}, {1, 2}, {-1, 2}};
bp::set_points(B, points.begin(), points.end());
}
PolygonSet result{A - B};
SimplePolygons simplePolygons;
result.get<SimplePolygons>(simplePolygons);
for (const auto& polygon : simplePolygons)
{
for (const Point& p : polygon)
{
std::cout << '(' << std::to_string(p.x()) << ", " << std::to_string(p.y()) << ")n";
}
}
return 0;
}

这将打印组成剪切三角形的以下后续点:

(3, 0)
(1, 2)
(1, 1)
(-1, 1)
(-1, 2)
(1, 2)
(0, 8)
(-3, 0)
(3, 0)

因此,结果中缺少边缘(1, 2) => (3, 0)(3, 0) => (0, 8)。结果中缺少输入三角形的右上角部分。

正确的输出可能如下所示:

(3, 0)
(1, 2)
(1, 1)
(-1, 1)
(-1, 2)
(1, 2)
(3, 0)
(0, 8)
(-3, 0)
(3, 0)

这是Boost Polygon中的一个错误吗?我是在某种程度上错误地使用了库,还是缺少了其他东西?

一些附加信息:

  • 我使用的是GCC 7.2.0,Boost 1.60.0。Boost Polygon自那以后就没有更新过,所以升级Boost很可能没有帮助
  • 使用double而不是int参数化点类型和所有其他几何类型并不能解决此问题
  • 例如,使用轴对齐的矩形计算切口不会出现问题
  • 对于我的应用程序,我想使用Boost Polygon而不是Boost Geometry,因为它提供了多边形钥匙孔断裂支持

回答我自己的问题。。。

Boost Polygon在编写时考虑到了整数数据类型。来自文件:

通常,数据类型应该定义std::numeric_limits,并且是类似整数的。并非所有算法都支持浮点坐标类型,目前通常不适合与库一起使用(http://www.boost.org/doc/libs/1_60_0/libs/polygon/doc/gtl_coordinate_concept.htm)

我怀疑这是我不完全理解的某种精度问题。事实上,例如,按1000因子缩放所有输入坐标确实会产生正确的多边形:

(3000, 0)
(1000, 5333)
(1000, 2000)
(1000, 1000)
(-1000, 1000)
(-1000, 2000)
(1000, 2000)
(1000, 5333)
(0, 8000)
(-3000, 0)
(3000, 0)

因此,对于原始输入,钥匙孔断裂算法似乎有意在边(3, 0) -> (0, 8)上添加一个新的顶点,从该顶点进入"钥匙孔多边形"。它可以在整数网格位置上创建的最佳顶点是(0, 8)。所以这个结果代表了一个近似值。

事实上,为算法提供类似的输入,即三角形边缘上存在良好的候选顶点,确实会产生正确的输出。一个这样的输入三角形将是例如CCD_ 10。

我认为这是锁孔破裂算法的一个限制。