【问题标题】:CGAL coordinate value transformation not working anymore in 5.2.1CGAL 坐标值转换在 5.2.1 中不再起作用
【发布时间】:2021-04-17 19:06:40
【问题描述】:

在我的一个项目中,我曾经将坐标值从 Kernel::FT 转换为 CGAL::Gmpq 并返回。该代码不再使用与以前相同的内核选择进行编译,即

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;

但是我尝试了另一种方法,但不确定它是否完全等同于前一种,所有编译都没有错误:

typedef CGAL::Cartesian< CGAL::Lazy_exact_nt<CGAL::Gmpq> > Kernel;

我的标题定义

// the following kernel gives no error
//typedef CGAL::Cartesian< CGAL::Lazy_exact_nt<CGAL::Gmpq> > Kernel;

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_2                                   Point_2;
typedef Kernel::Circle_2                                  Circle_2;
typedef Kernel::Line_2                                    Line_2;
typedef CGAL::Gps_circle_segment_traits_2<Kernel>         Traits_2;

typedef CGAL::General_polygon_set_2<Traits_2>             Polygon_set_2;
typedef Traits_2::General_polygon_2                       Polygon_2;
typedef Traits_2::General_polygon_with_holes_2            Polygon_with_holes_2;
typedef Traits_2::Curve_2                                 Curve_2;
typedef Traits_2::X_monotone_curve_2                      X_monotone_curve_2;
typedef Traits_2::Point_2                                 Point_2t;
typedef Traits_2::CoordNT                                 coordnt;
typedef CGAL::Arrangement_2<Traits_2>                     Arrangement_2;
typedef Arrangement_2::Face_handle                        Face_handle;

失败的代码

CGAL::Gmpfr convert(CGAL::Gmpq z)
{
    CGAL::Gmpz num = z.numerator();
    CGAL::Gmpz den = z.denominator();

    CGAL::Gmpfr num_f(num);
    CGAL::Gmpfr den_f(den);

    return num_f/den_f;
}



CGAL::Gmpfr convert(Traits_2::CoordNT z, int use_precision)
{
    Kernel::FT a0_val = z.a0();
    Kernel::FT a1_val = z.a1();
    Kernel::FT root_val = z.root();

    //the following three lines give errors
    CGAL::Gmpq a0_q = a0_val.exact();
    CGAL::Gmpq a1_q = a1_val.exact();
    CGAL::Gmpq root_q = root_val.exact();


    CGAL::Gmpfr a0_f = convert(a0_q);
    CGAL::Gmpfr a1_f = convert(a1_q);
    CGAL::Gmpfr root_f = convert(root_q);

    CGAL::Gmpfr res = a0_f + a1_f * root_f.sqrt(use_precision);

    return res;
}


Point_2 convert(Point_2t p)
{
    CGAL::Gmpfr xx = convert(p.x());
    CGAL::Gmpfr yy = convert(p.y());

    CGAL::Gmpq xx1 = xx;
    CGAL::Gmpq yy1 = yy;
    
    // the following two lines give errors
    Kernel::FT xx2 = xx1;
    Kernel::FT yy2 = yy1;

    Point_2 pp(xx2, yy2);

    return pp;
}

错误(前三个和后两个基本相同):

cgal.cpp:48:32: error: conversion from ‘CGAL::Lazy<CGAL::Interval_nt<false>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>, CGAL::To_interval<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> > >::ET {aka boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>}’ to non-scalar type ‘CGAL::Gmpq’ requested
  CGAL::Gmpq a0_q = a0_val.exact();
                    ~~~~~~~~~~~~^~
cgal.cpp:49:32: error: conversion from ‘CGAL::Lazy<CGAL::Interval_nt<false>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>, CGAL::To_interval<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> > >::ET {aka boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>}’ to non-scalar type ‘CGAL::Gmpq’ requested
  CGAL::Gmpq a1_q = a1_val.exact();
                    ~~~~~~~~~~~~^~
cgal.cpp:50:36: error: conversion from ‘CGAL::Lazy<CGAL::Interval_nt<false>, boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>, CGAL::To_interval<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> > >::ET {aka boost::multiprecision::number<boost::multiprecision::backends::gmp_rational>}’ to non-scalar type ‘CGAL::Gmpq’ requested
  CGAL::Gmpq root_q = root_val.exact();
                      ~~~~~~~~~~~~~~^~
cgal.cpp: In function ‘Point_2 convert(Point_2t)’:
cgal.cpp:71:19: error: conversion from ‘CGAL::Gmpq’ to non-scalar type ‘CGAL::Lazy_kernel_generic_base<CGAL::Simple_cartesian<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >, CGAL::Simple_cartesian<CGAL::Interval_nt<false> >, CGAL::Cartesian_converter<CGAL::Simple_cartesian<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >, CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >, CGAL::Epeck>::FT {aka CGAL::Lazy_exact_nt<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >}’ requested
  Kernel::FT xx2 = xx1;
                   ^~~
cgal.cpp:72:19: error: conversion from ‘CGAL::Gmpq’ to non-scalar type ‘CGAL::Lazy_kernel_generic_base<CGAL::Simple_cartesian<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >, CGAL::Simple_cartesian<CGAL::Interval_nt<false> >, CGAL::Cartesian_converter<CGAL::Simple_cartesian<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >, CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >, CGAL::Epeck>::FT {aka CGAL::Lazy_exact_nt<boost::multiprecision::number<boost::multiprecision::backends::gmp_rational> >}’ requested
  Kernel::FT yy2 = yy1;

似乎默认内核CGAL::Exact_predicates_exact_constructions_kernel 现在有一个与“boost-something”相关的坐标编号类型,这不再与CGAL::Gmpq 兼容。

鉴于我想使用与CGAL::Exact_predicates_exact_constructions_kernel 等效的最快内核,该问题的最佳解决方案是什么?

我应该切换到CGAL::Cartesian&lt; CGAL::Lazy_exact_nt&lt;CGAL::Gmpq&gt; &gt; 甚至是CGAL::Extended_cartesian&lt; CGAL::Lazy_exact_nt&lt;CGAL::Gmpq&gt; &gt;吗?

或者我可以设置一个特定的环境变量,以便 CGAL::Exact_predicates_exact_construction_kernel 默认使用 CGAL::Gmpq 而不是“boost-something”,前提是这不会让事情变慢?

或者我可以在 CGAL 5.2.1 中使用一些新引入的转换运算符/函数重写有问题的行。我现在不知道?

【问题讨论】:

  • 为了更准确地了解 Marc 提出的最简单的解决方法,您可以在包含任何 CGAL 文件之前在 cpp 源中定义 #define CGAL_DO_NOT_USE_BOOST_MP,并在 cmake 级别设置 CGAL_WITH_GMPXX=OFF
  • 感谢你们(Marc Glisse 和 sloriot)的建议 - 我可以通过提供编译标志 -DCGAL_DO_NOT_USE_BOOST_MP 使代码再次工作。我目前不知道如何设置 cmake 变量,因为我使用 qmake 项目设置(以及使用 CGAL 的仅标头设置)。 CGAL 是否从 CGAL::Gmpq 默认更改为 boost::rational 因为性能更好?
  • 是的,性能更好(对于某些应用程序,不是全部),这也是未来向多线程迈出的有益一步。

标签: computational-geometry numeric cgal


【解决方案1】:

如果您查看CGAL/Exact_predicates_exact_constructions_kernel.h 以了解 Epeck 是如何定义的,您可以使用 Gmpq 定义您自己的 Epeck 版本

class Kernel
  : public Type_equality_wrapper<
             Lazy_kernel_base< Simple_cartesian<Gmpq>,
                               Simple_cartesian<Interval_nt_advanced>,
                               Cartesian_converter< Simple_cartesian<Gmpq>,
                                                    Simple_cartesian<Interval_nt_advanced> >,
                               Kernel>,
             Kernel >
{};

(您可能需要全部添加CGAL::

默认选择的有理类型取决于可用的类型,它可以来自 boost.Multiprecision(您可以使用 CGAL_DO_NOT_USE_BOOST_MP 禁用该选择)。如果定义了 CGAL_USE_GMPXX,它可以来自 GMPXX。也可以是Gmpq(CGAL_USE_GMP但不是CGAL_USE_GMPXX)、leda_rational等

我知道这种可变性对于像您这样关心类型的不常见情况可能并不理想... 我从未使用过 Gmpfr,但是从 mpz_class 和 mpz_int 添加类似于 Gmpz 的构造函数应该不难(你想在 github 上提交增强请求,还是自己编写?它可能是 1-liner ,不包括#ifdef)。然后有可能以至少可移植到所有基于 GMP 的理性的方式编写您的转换器,也许使用Fraction_traits&lt;FT&gt;::Decompose,尽管这会做不必要的复制。实际上,直接使用 mpfr_set_q 将有理类型的构造函数添加到 Gmpfr 甚至可能是有意义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2016-03-28
    • 2017-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多