CGAL 坐标值转换在 5.2.1 中不再起作用

CGAL coordinate value transformation not working anymore in 5.2.1

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

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;

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

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

我的 header 定义

// 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< CGAL::Lazy_exact_nt<CGAL::Gmpq> > 甚至 CGAL::Extended_cartesian< CGAL::Lazy_exact_nt<CGAL::Gmpq> > 吗?

或者我可以设置某个环境变量,以便 CGAL::Exact_predicates_exact_construction_kernel 默认与 CGAL::Gmpq 一起工作,而不是“boost-something”,前提是这不会使事情变得更慢?

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

如果您查看 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行,不算#ifdef)。然后可能会以一种至少可移植到所有基于 GMP 的有理数的方式编写转换器,也许使用 Fraction_traits<FT>::Decompose,尽管这会进行不必要的复制。实际上,直接使用 mpfr_set_q.

从有理类型向 Gmpfr 添加构造函数甚至可能是有意义的