首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >计算多边形并时在CGAL中触发的断言

计算多边形并时在CGAL中触发的断言
EN

Stack Overflow用户
提问于 2016-01-02 13:27:19
回答 1查看 395关注 0票数 1

我正在用Python编写一个将水印应用于字体文件的应用程序。这些图形是带有孔的非凸多边形,由PostScript中定义的bezier样条组成.水印需要与符号合并,而不是重叠。我无法在Python中找到一个库来完成这个任务,所以我使用的是CGAL & C++。我让它在大多数象形文字上运行得很好,但它在其他人身上却神秘地失败了。

最初,我对CGAL印象深刻。它看起来非常全面和复杂,似乎提供了我所需要的所有功能,但是它有一个致命的缺陷--我几乎无法相信--库中没有错误处理。没有错误代码,没有异常,只有断言--但只在调试版本中。在版本构建中,您会得到一个很好的分段错误。此外,这些断言没有揭示问题的性质。

程序只在某些符号上失败。字母e工作得很好,但是它在a上崩溃了。当我试图计算字形与水印的合并时,就会发生崩溃。“a”字形没有什么明显的问题。我的应用程序正确地解析了PostScript,并在QGraphicsView上很好地呈现它。

这个程序需要在服务器上运行,它的输出直接发送给客户,所以它必须是可靠的。我无法从断言失败或分段错误中恢复,那么我能做什么呢?

即使我让它可靠地工作,我怎么能相信它永远不会失败呢?如果有某种错误处理到位,我可以跳过它失败的几个符号,让它们没有水印-不是理想的,但可以接受。我只是不明白这个库的作者们在想些什么;他们花了这么大的精力来提供最全面的几何图形库,只是为了确保它完全不适合使用。

目前看来,我需要自己修改代码,以便以合理的方式处理错误,但这似乎太荒谬了。

我很抱歉,如果我失去耐心,但我已经超过了我的最后期限,我的客户不会关心或理解这些借口。

断言失败发生在Multiset.h的第2141行:

代码语言:javascript
运行
AI代码解释
复制
CGAL_multiset_precondition (comp_f(object, nodeP->object) != LARGER);

当我在BezierPolygonSet上调用join()时,就会发生这种情况。我的类型如下:

代码语言:javascript
运行
AI代码解释
复制
typedef CGAL::CORE_algebraic_number_traits NtTraits;
typedef NtTraits::Rational Rational;
typedef NtTraits::Algebraic Algebraic;

typedef CGAL::Cartesian<Rational> RatKernel;
typedef CGAL::Cartesian<Algebraic> AlgKernel;

typedef RatKernel::Point_2 BezierRatPoint;

typedef CGAL::Arr_Bezier_curve_traits_2<RatKernel, AlgKernel, NtTraits> Traits;

typedef Traits::Point_2 BezierPoint;
typedef Traits::Curve_2 BezierCurve;

typedef CGAL::Gps_traits_2<Traits> BezierTraits;

typedef BezierTraits::X_monotone_curve_2 BezierXMonotoneCurve;
typedef BezierTraits::General_polygon_2 BezierPolygon;
typedef BezierTraits::General_polygon_with_holes_2 BezierPolygonWithHoles;
typedef CGAL::Gps_default_dcel<BezierTraits> BezierDcelTraits;
typedef CGAL::General_polygon_set_2<BezierTraits, BezierDcelTraits> BezierPolygonSet;

任何帮助都将不胜感激。谢谢。

编辑:

我有一个名为几何学的模块,它封装了CGAL代码,并公开了一系列几何原语(点、曲线、LineSegment、CubicBezier、路径)和函数:

代码语言:javascript
运行
AI代码解释
复制
PathList toPathList(const PolyList& polyList);
PolyList toPolyList(const PathList& paths);

Path类有一个名为computeUnion的方法,如下所示:

代码语言:javascript
运行
AI代码解释
复制
PathList Path::computeUnion(const PathList& paths1, const PathList& paths2) {
    PolyList polyList1 = toPolyList(paths1);
    PolyList polyList2 = toPolyList(paths2);

    cgal_wrap::BezierPolygonSet polySet;

    for (auto i : polyList1) {
        polySet.join(i);
    }

    for (auto i : polyList2) {
        polySet.join(i);
    }

    PolyList polyList;
    polySet.polygons_with_holes(std::back_inserter(polyList));

    return toPathList(polyList);
}

当我调用join()时会发生错误。多边形是由这样的路径创建的:

代码语言:javascript
运行
AI代码解释
复制
PolyList toPolyList(const PathList& paths) {
    cgal_wrap::Traits traits;
    cgal_wrap::Traits::Make_x_monotone_2 fnMakeXMonotone = traits.make_x_monotone_2_object();

    cgal_wrap::RatKernel ratKernel;
    cgal_wrap::RatKernel::Equal_2 fnEqual = ratKernel.equal_2_object();

    PolyList polyList; // The final polygons with holes
    cgal_wrap::BezierPolygon outerPoly;
    std::list<cgal_wrap::BezierPolygon> holes;
    std::list<cgal_wrap::BezierXMonotoneCurve> monoCurves;
    bool first = true;
    cgal_wrap::BezierRatPoint firstPoint;

    // For each path in the list
    for (auto i = paths.begin(); i != paths.end(); ++i) {
        const Path& path = *i;

        cgal_wrap::BezierRatPoint prevEndPoint;

        // For each curve in the path
        for (auto j = path.begin(); j != path.end(); ++j) {
            const Curve& curve = **j;

            std::list<cgal_wrap::BezierRatPoint> points;

            if (curve.type() == LineSegment::type) {
                const LineSegment& lseg = dynamic_cast<const LineSegment&>(curve);

                cgal_wrap::BezierRatPoint A = lseg.A();

                if (j != path.begin()) {
                    if (A != prevEndPoint) {
                        // TODO
                        assert(false);
                    }

                    A = prevEndPoint;
                }

                points.push_back(cgal_wrap::BezierRatPoint(A));
                points.push_back(cgal_wrap::BezierRatPoint(lseg.B()));
            }
            else if (curve.type() == CubicBezier::type) {
                const CubicBezier& bezier = dynamic_cast<const CubicBezier&>(curve);

                cgal_wrap::BezierRatPoint A = bezier.A();

                if (j != path.begin()) {
                    if (A != prevEndPoint) {
                        // TODO
                        assert(false);
                    }

                    A = prevEndPoint;
                }

                points.push_back(cgal_wrap::BezierRatPoint(A));
                points.push_back(cgal_wrap::BezierRatPoint(bezier.B()));
                points.push_back(cgal_wrap::BezierRatPoint(bezier.C()));
                points.push_back(cgal_wrap::BezierRatPoint(bezier.D()));
            }

            bool bClosesCurve = false;

            if (!first && Point(points.back()) == Point(firstPoint)) {
                points.pop_back();
                points.push_back(firstPoint);
                bClosesCurve = true;
            }

            prevEndPoint = points.back();

            cgal_wrap::BezierCurve cgalCurve(points.begin(), points.end());
            std::list<CGAL::Object> monoObjs;
            fnMakeXMonotone(cgalCurve, std::back_inserter(monoObjs));

            // Append the x-monotone curves to the list
            cgal_wrap::BezierXMonotoneCurve monoCurve;
            for (auto o = monoObjs.begin(); o != monoObjs.end(); ++o) {
                if (CGAL::assign(monoCurve, *o)) {
                    monoCurves.push_back(monoCurve);
                }
            }

            if (!first) {
                // If this curve closes the current chain, thereby creating a new polygon
                if (bClosesCurve) {

                    // Add the new polygon to the list

                    cgal_wrap::BezierPolygon subPoly(monoCurves.begin(), monoCurves.end());

                    if (subPoly.orientation() == CGAL::COUNTERCLOCKWISE) {
                        if (!outerPoly.is_empty()) {
                            polyList.push_back(cgal_wrap::BezierPolygonWithHoles(outerPoly, holes.begin(), holes.end()));
                            holes.clear();
                        }

                        outerPoly = subPoly;
                    }
                    else {
                        holes.push_back(subPoly);
                    }

                    monoCurves.clear();
                    first = true;
                }
            }
            else {
                // This is the first curve in the chain - store its source point
                firstPoint = cgalCurve.control_point(0);
                first = false;
            }
        }
    }

    polyList.push_back(cgal_wrap::BezierPolygonWithHoles(outerPoly, holes.begin(), holes.end()));

    return polyList;
}

请注意,我非常小心地确保多边形边界没有间隙,方法是将曲线的第一个点n+1设置为曲线的最后一点,以防它们稍有不同。我希望这能解决这个问题,但事实并非如此。我想不出任何其他可能会使这些形状失效的东西。

以下是“e”字形与水印(an )的成功合并。

这是'a‘字形的样子。合并在此字形上失败。

编辑2:

下面是从PostScript解析后构成'a‘字形的曲线。它似乎没有什么问题。就像我说的,渲染的时候看起来没问题。此错误可能发生在将此数据转换为CGAL类型时。线段被转换成带有两个控制点的BezierCurves。我会进一步调查。

代码语言:javascript
运行
AI代码解释
复制
LineSegment[(344, 0), (409, 0)]
CubicBezier[(409, 0), (403, 24), (400, 68), (400, 161)]
LineSegment[(400, 161), (400, 324)]
CubicBezier[(400, 324), (400, 437), (330, 485), (232, 485)]
CubicBezier[(232, 485), (180, 485), (121, 472), (66, 437)]
LineSegment[(66, 437), (94, 385)]
CubicBezier[(94, 385), (127, 405), (167, 424), (224, 424)]
CubicBezier[(224, 424), (283, 424), (326, 392), (326, 320)]
LineSegment[(326, 320), (326, 290)]
LineSegment[(326, 290), (236, 287)]
CubicBezier[(236, 287), (188, 285), (150, 280), (118, 264)]
CubicBezier[(118, 264), (70, 242), (38, 199), (38, 136)]
CubicBezier[(38, 136), (38, 45), (102, -10), (188, -10)]
CubicBezier[(188, -10), (247, -10), (293, 18), (330, 53)]
LineSegment[(330, 53), (344, 0)]
LineSegment[(326, 234), (326, 114)]
CubicBezier[(326, 114), (304, 91), (260, 52), (201, 52)]
CubicBezier[(201, 52), (147, 52), (113, 88), (113, 140)]
CubicBezier[(113, 140), (113, 171), (127, 198), (154, 213)]
CubicBezier[(154, 213), (175, 224), (202, 230), (243, 231)]
LineSegment[(243, 231), (326, 234)]

编辑3:

以下是转换成CGAL曲线后的'a‘字形曲线。请注意,它们在平移之前完全匹配曲线,这意味着它们中没有一个必须被分割成X-单调子曲线;它们肯定都是X-单调的。

代码语言:javascript
运行
AI代码解释
复制
Outer boundary:
2  344 0  409 0 [1] | 344 0 --> 409 0
4  409 0  403 24  400 68  400 161 [1] | 409 0 --> 400 161
2  400 161  400 324 [1] | 400 161 --> 400 324
4  400 324  400 437  330 485  232 485 [1] | 400 324 --> 232 485
4  232 485  180 485  121 472  66 437 [1] | 232 485 --> 66 437
2  66 437  94 385 [1] | 66 437 --> 94 385
4  94 385  127 405  167 424  224 424 [1] | 94 385 --> 224 424
4  224 424  283 424  326 392  326 320 [1] | 224 424 --> 326 320
2  326 320  326 290 [1] | 326 320 --> 326 290
2  326 290  236 287 [1] | 326 290 --> 236 287
4  236 287  188 285  150 280  118 264 [1] | 236 287 --> 118 264
4  118 264  70 242  38 199  38 136 [1] | 118 264 --> 38 136
4  38 136  38 45  102 -10  188 -10 [1] | 38 136 --> 188 -10
4  188 -10  247 -10  293 18  330 53 [1] | 188 -10 --> 330 53
2  330 53  344 0 [1] | 330 53 --> 344 0
Holes:
Hole:
2  326 234  326 114 [1] | 326 234 --> 326 114
4  326 114  304 91  260 52  201 52 [1] | 326 114 --> 201 52
4  201 52  147 52  113 88  113 140 [1] | 201 52 --> 113 140
4  113 140  113 171  127 198  154 213 [1] | 113 140 --> 154 213
4  154 213  175 224  202 230  243 231 [1] | 154 213 --> 243 231
2  243 231  326 234 [1] | 243 231 --> 326 234

当添加到BezierPolygonSet中时,此多边形将导致断言失败。有什么想法吗?

EN

回答 1

Stack Overflow用户

发布于 2016-01-02 22:43:48

  1. 您可以自定义错误处理;请参阅手册
  2. 请附上完整的独立程序。你列出的陈述在我看来没什么不对的。

您可以用多条线近似Bezier曲线,并使用多条线处理整个过程。如果问题是处理Bezier曲线,那么这将解决它。如果这是可以接受的,它也会更有效率。

我们修复了处理Bezier曲线的CGAL组件中的一个bug,即2.h

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34570911

复制
相关文章
C++中派生类成员的访问属性
在派生类中,对基类的继承方式可以有public(公用的)、private (私有的)和protected(保护的)3种。 不同的继承方式决定了基类成员在派生类中的访问属性。 简单地说: (1)  公用继承(public inheritance) 基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。 (2)  私有继承(private inheritance) 基类的公用成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有。 (3)  受保护的继承(protected inheritance) 基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。 保护成员的意思是:  不能被外界引用,但可以被派生类的成员引用。
卡尔曼和玻尔兹曼谁曼
2019/01/25
1.1K0
类的继承 方法和属性的重写
当子类和父类进行同一件事进行不同的操作需要重新写方法(例如电脑鼠标点击打开图片,平板电脑触摸打开图片)
用户2965768
2019/01/28
1.5K0
PHP-私有属性继承和重写
1.3 面向对象三大特性 封装 继承 多态 1.4 私有属性继承和重写 私有属性可以继承但不能重写。 <?php class A { private $name='PHP'; public fun
cwl_java
2022/11/30
6350
JAVA中重写equals()方法的同时要重写hashcode()方法
object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true (2)当obj1.hashCode
xiangzhihong
2018/02/01
1.8K0
派生类的构造过程
1、先基类、后对象、再子类 多继承,初始化顺序跟基类的声明顺序有关,从左到右。 对象 ,与声明类的顺序有关,从上到下。
我与梦想有个约会
2023/10/20
1510
派生类的构造过程
python @property 设置只读属性 重写 getter setter 方法
@property广泛应用在类的定义中,可以让调用者写出简短的代码,就可以重写属性的 get 和 set 方法,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
onety码生
2018/11/21
2.6K0
java中重载和重写的区别
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
全栈程序员站长
2022/09/08
6930
Java中的重载与重写的区别
java中的重载与重写的区别 1、重载发生在本类,重写发生在父类与子类之间; 2、重载的方法名必须相同,重写的方法名相同且返回值类型必须相同; 3、重载的参数列表不同,重写的参数列表必须相同。
全栈程序员站长
2022/07/18
8060
Python中的_new_方法的重写
new方法重写的步骤比较固定,直接上代码吧 # 代码 class MusicPlayer(object): # new方法的重写,是一个静态方法,必须主动传递cls参数 def __new__(cls, *args, **kwargs): # 1.创建对象时,new方法会被自动调用 print("创建对象,分配空间") # 2.为对象分配空间 instance = super().__new__(cls) #
benym
2022/07/14
7810
Java中的重载和重写的区别
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理 重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法
共饮一杯无
2022/11/28
6120
Java中的重载和重写的区别
Java中的多态(重载和重写)
方法重写与方法重载之间的关系:重载发生在同一个类内部的两个方法或多个方法。重写发生在父类和子类之间。
你的明明呐丶
2022/06/27
6070
Java中的多态(重载和重写)
Java中的重载、重写和重构的区别
重载(overloaded): 重载就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
全栈程序员站长
2022/09/08
1.9K0
【说站】python中__new__的重写
1、重写__new__方法一定要return super().__new__(cls)。
很酷的站长
2022/11/23
7280
Java中的方法重载和重写(覆盖)
* 方法重载的判定:同一类中,方法名相同,参数列表不同(参数个数不同,参数列表中对应位置参数类型不同),其他方法返回值
用户7886150
2020/12/14
2.3K0
java中的UrlReWriter(url重写)_源码下载
==============================================
Hongten
2018/09/13
2.1K0
java中的UrlReWriter(url重写)_源码下载
css opacity属性_CSS中的opacity属性[通俗易懂]
With the growing need of making websites, the need for styling them has also increased. Therefore, CSS has become an indispensable part of creating websites. Thus one must be aware of which properties to use while creating a website.
全栈程序员站长
2022/09/01
3.2K0
css opacity属性_CSS中的opacity属性[通俗易懂]
TypeScript中的可选属性和只读属性
可选属性 接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 例如给函数传入的参数对象中只有部分属性赋值了。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面
孙亖
2018/06/07
3K0
你真的了解Override吗,属性能够被重写吗?
最近想到了一个问题,Java的属性能够被Override吗?首先让我们看一下下面这个继承的例子。
三哥
2019/05/07
8130
你真的了解Override吗,属性能够被重写吗?
你真的了解Override吗,属性能够被重写吗?
最近想到了一个问题,Java的属性能够被Override吗?首先让我们看一下下面这个继承的例子。
三哥
2018/12/17
6930
Python使用元类约束派生类中必须实现指定的成员
创建派生类时指定元类,用来控制和约束派生类的创建过程,对派生类中的成员进行一定的限制。
Python小屋屋主
2021/12/29
1K0
Python使用元类约束派生类中必须实现指定的成员

相似问题

重写派生类中属性的特性

15

重写派生类中的NotMapped属性

10

使用派生类重写属性。

41

重写派生类中的公共属性

41

重写派生类中的设计器属性

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档