【问题标题】:Precondition exception when intersecting polygons in CGAL在 CGAL 中与多边形相交时的前提条件异常
【发布时间】:2017-06-19 22:47:20
【问题描述】:

我正在使用 CGAL 来计算两个凸多边形相交的面积。一个简短的演示代码发布在this问题的接受答案中。但是,当我修改该代码以使用我感兴趣的多边形时,CGAL 会从 CGAL::intersection() 例程的深处引发运行时异常。

这是一个简短的示例代码,它是从上面链接的 SO 问题中复制和粘贴的,除了它使用我自己的多边形并打印有关每个多边形的一些诊断信息以显示它们是凸的并使用逆时针绕组顺序。

#include <iostream>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/Polygon_2_algorithms.h>


typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_2 Point;
typedef CGAL::Polygon_2<K> Polygon_2;
typedef CGAL::Polygon_with_holes_2<K> Polygon_with_holes_2;
using std::cout; using std::endl;


int main(){
    bool IsSimple, IsConvex, IsClockwise;
    double Area;

    // Define the polygons. P is long and skinny, Q is 20 equally
    // spaced points around a circle of radius 0.025. The top-right
    // corner of P protudes into Q.
    int np=7;
    int nq=20;
    Point points[]={
        Point( 2.67905949256324049657e-02,-2.36307305336680428809e-02),
        Point( 2.19804738309115066386e-02, 1.25954939609798088895e-02),
        Point( 3.24142504626934169210e-03, 8.27109808759729503436e-03),
        Point(-7.07297020897392769712e-02,-1.31780902623212625713e-01),
        Point(-1.72945875771868884385e+00,-4.33625989924519217311e+00),
        Point(-5.64696462817379796206e+00,-2.91346747524371210147e+01),
        Point(-5.66016394049875870564e+00,-4.95259849820236013329e+01)};
    Point points2[]={
        Point( 2.50000000000000013878e-02, 0.00000000000000000000e+00),
        Point( 2.37764129073788424429e-02, 7.72542485937368662852e-03),
        Point( 2.02254248593736890571e-02, 1.46946313073118266929e-02),
        Point( 1.46946313073118284276e-02, 2.02254248593736890571e-02),
        Point( 7.72542485937368836324e-03, 2.37764129073788424429e-02),
        Point( 1.53080849893419158600e-18, 2.49999999999999979183e-02),
        Point(-7.72542485937368489379e-03, 2.37764129073788424429e-02),
        Point(-1.46946313073118232234e-02, 2.02254248593736890571e-02),
        Point(-2.02254248593736890571e-02, 1.46946313073118284276e-02),
        Point(-2.37764129073788424429e-02, 7.72542485937368923060e-03),
        Point(-2.50000000000000013878e-02, 3.06161699786838317201e-18),
        Point(-2.37764129073788424429e-02,-7.72542485937368402643e-03),
        Point(-2.02254248593736925266e-02,-1.46946313073118232234e-02),
        Point(-1.46946313073118318970e-02,-2.02254248593736890571e-02),
        Point(-7.72542485937369096533e-03,-2.37764129073788389734e-02),
        Point(-4.59242549680257437283e-18,-2.50000000000000013878e-02),
        Point( 7.72542485937368229171e-03,-2.37764129073788424429e-02),
        Point( 1.46946313073118214887e-02,-2.02254248593736925266e-02),
        Point( 2.02254248593736855877e-02,-1.46946313073118318970e-02),
        Point( 2.37764129073788389734e-02,-7.72542485937369183269e-03)};
    Polygon_2 polyP(points, points+np);
    Polygon_2 polyQ(points2, points2+nq);

    // Print some properties of polygon P. It is simple, convex, and CCW
    // oriented
    CGAL::set_pretty_mode(cout);
    cout << "created the polygon P:" << endl;
    cout << polyP << endl;
    cout << endl;
    IsSimple    = polyP.is_simple();
    IsConvex    = polyP.is_convex();
    IsClockwise = (polyP.orientation() == CGAL::CLOCKWISE);
    Area      = polyP.area();
    cout << "polygon P is";
    if (!IsSimple) cout << " not";
    cout << " simple." << endl;
    cout << "polygon P is";
    if (!IsConvex) cout << " not";
    cout << " convex." << endl;
    cout << "polygon P is";
    if (!IsClockwise) cout << " not";
    cout << " clockwise oriented." << endl;
    cout << "the area of polygon P is " << Area << endl;
    cout << endl;

    // Print some properties of polygon Q. It is simple, convex, and CCW
    // oriented
    cout << "created the polygon Q:" << endl;
    cout << polyQ << endl;
    cout << endl;
    IsSimple    = polyQ.is_simple();
    IsConvex    = polyQ.is_convex();
    IsClockwise = (polyQ.orientation() == CGAL::CLOCKWISE);
    Area      = polyQ.area();
    cout << "polygon Q is";
    if (!IsSimple) cout << " not";
    cout << " simple." << endl;
    cout << "polygon Q is";
    if (!IsConvex) cout << " not";
    cout << " convex." << endl;
    cout << "polygon Q is";
    if (!IsClockwise) cout << " not";
    cout << " clockwise oriented." << endl;
    cout << "the area of polygon Q is " << Area << endl;
    cout << endl;

    // Compute the intersection
    std::list<Polygon_with_holes_2> polyI;
    CGAL::intersection(polyP, polyQ, std::back_inserter(polyI));

    double totalArea = 0;
    typedef std::list<Polygon_with_holes_2>::iterator LIT;
    for(LIT lit = polyI.begin(); lit!=polyI.end(); lit++){
        totalArea+=lit->outer_boundary().area();
    }
    cout << "TotalArea::" << totalArea;

    return 0;
}

这是测试程序的输出。

created the polygon P:
Polygon_2(
  PointC2(0.0267906, -0.0236307)
  PointC2(0.0219805, 0.0125955)
  PointC2(0.00324143, 0.0082711)
  PointC2(-0.0707297, -0.131781)
  PointC2(-1.72946, -4.33626)
  PointC2(-5.64696, -29.1347)
  PointC2(-5.66016, -49.526)
)


polygon P is simple.
polygon P is convex.
polygon P is not clockwise oriented.
the area of polygon P is 71.1027

created the polygon Q:
Polygon_2(
  PointC2(0.025, 0)
  PointC2(0.0237764, 0.00772542)
  PointC2(0.0202254, 0.0146946)
  PointC2(0.0146946, 0.0202254)
  PointC2(0.00772542, 0.0237764)
  PointC2(1.53081e-18, 0.025)
  PointC2(-0.00772542, 0.0237764)
  PointC2(-0.0146946, 0.0202254)
  PointC2(-0.0202254, 0.0146946)
  PointC2(-0.0237764, 0.00772542)
  PointC2(-0.025, 3.06162e-18)
  PointC2(-0.0237764, -0.00772542)
  PointC2(-0.0202254, -0.0146946)
  PointC2(-0.0146946, -0.0202254)
  PointC2(-0.00772542, -0.0237764)
  PointC2(-4.59243e-18, -0.025)
  PointC2(0.00772542, -0.0237764)
  PointC2(0.0146946, -0.0202254)
  PointC2(0.0202254, -0.0146946)
  PointC2(0.0237764, -0.00772542)
)


polygon Q is simple.
polygon Q is convex.
polygon Q is not clockwise oriented.
the area of polygon Q is 0.00193136

terminate called after throwing an instance of 'CGAL::Precondition_exception'
  what():  CGAL ERROR: precondition violation!
Expr: (m_traits.compare_y_at_x_2_object()(p, cv) == EQUAL) && compare_xy(cv.left(), p) == SMALLER && compare_xy(cv.right(), p) == LARGER
File: /usr/local/include/CGAL/Arr_segment_traits_2.h
Line: 706
Aborted (core dumped)

我不明白是什么导致了错误。任何帮助将不胜感激。

【问题讨论】:

  • 我用过 CGAL,但我讨厌它。它是如此不透明,以至于几乎无法使用。我认为它的开发人员认为它非常聪明,但他们制作了一个完全不透明的 API。没有专门的CGAL论坛,可以求助吗?
  • 碰巧,CGAL suggests 使用 CGAL 标签在 SO 上发布问题。我可以提交错误报告,但我认为问题更可能是操作员错误而不是 CGAL 错误。
  • 将CGAL::Simple_cartesian&lt;double&gt; 替换为CGAL::Exact_predicates_exact_constructions_kernel。见here

标签: c++ computational-geometry intersection cgal polygons


【解决方案1】:

我可以重现此错误(在带有 clang++ 的 MacOS 上使用 CGAL 4.9)。据我了解,这种类型的未捕获异常不应该发生,换句话说,您已经发现了 CGAL 中的错误。因此,请按照错误消息中的说明提交错误报告 –– 您没有发布的部分(或者可能因为版本不同而没有得到?):

说明:参考http://www.cgal.org/bug_report.html的错误报告说明

libc++abi.dylib:以 CGAL::Precondition_exception 类型的未捕获异常终止:CGAL 错误:违反前提条件!

Expr: (m_traits.compare_y_at_x_2_object()(p, cv) == EQUAL) && compare_xy(cv.left(), p) == SMALLER && compare_xy(cv.right(), p) == LARGER

文件:/usr/local/include/CGAL/Arr_segment_traits_2.h 行:706

据我从该文件中可以看出,在给定分割点的情况下,函数 throwing 将一条曲线分割成两条子曲线。前提是分割点在曲线上,不是终点。显然,是否满足这个先决条件是调用者的问题,是另一个 CGAL 例程。换句话说,您的输入没有任何问题。问题在于 CGAL 实现,或者更准确地说,是它处理所用数字表示不精确的方式。


编辑以下 sloriot 的评论。

如果我替换

typedef CGAL::Simple_cartesian<double> K;

与

typedef CGAL::Exact_predicates_exact_constructions_kernel K;

并为Area 和totalArea 使用适当的类型(我只是分别使用了auto 和decltype(Area)),代码编译(您必须将其链接到libgmp 和libmpfr)并运行没有崩溃,报告

totalArea::0.000876944

【讨论】:

  • 切换到Exact_predicates_exact_constructions_kernel 解决了我的问题。此外,我的输出(从 4.9 版开始)是逐字记录的,所以奇怪的是您的输出包含我没有的信息。我在 Linux 上使用 g++,所以这可能是造成差异的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 2011-09-26
  • 2015-09-21
  • 2011-12-10
相关资源
最近更新 更多