Search code examples
computational-geometrynumericcgal

Converting coordinate values in CGAL


From CGAL I am currently using the following package: Boolean operations on polygons

As I am interested in polygons which can have, besides line segments, as edges also circle segments, I use the following build-up for my basic typedefs:

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;

As shown in the types above, I have two Point-types namely Point_2 which is Kernel::Point_2 and what I called Point_2t which is Traits_2::Point_2.

The difference between them is, that Point_2 has rational coordinates x(), y() whereas Point_2t has coordinates in Q(alpha) where Q stands for the rational field and alpha is the square-root of a rational number.

Or, to say it otherwise, the coordinates for Point_2 are in Kernel::FT, whereas the coordinates of Point_2t are in Traits_2::CoordNT.

So converting from Point_2 to Point_2t is no problem, but I have to convert also from Point_2t to Point_2, hopefully in a way which gives control over the lost precision.

Reading through the documentation and using the autocomplete feature of eclipse, I made up the following routines:

const int use_precision = 100;

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)
{
    Kernel::FT a0_val = z.a0();
    Kernel::FT a1_val = z.a1();
    Kernel::FT root_val = z.root();

    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;

    Kernel::FT xx2 = xx1;
    Kernel::FT yy2 = yy1;

    Point_2 pp(xx2, yy2);
    return pp;
}

Essentially I convert the coordinates from Traits_2::CoordNT into the form

(*) a0 + a1 * sqrt(root)

with a0, a1, root from Kernel::FT (=rational field), then convert a0, a1, root into Gmpq rationals, these into Gmpfr with 100 decimals precision, then evaluate the expression (*) and convert back into Gmpq and then Kernel::FT. All conversions are (more or less) just done by assignments and automatic conversion by CGAL.

In my tests, this worked seemingly correct, but I am still not 100% sure, if, according to the CGAL definitions, the sqrt(root) expression in (*) always means the positive square-root.

I looked through the definition:

description of sqrt-extended Number type in CGAL

but even then I am not totally convinced, that only the positive value of sqrt(root) is taken.

So my question to those, who understand the CGAL system in this point fully:

Are my conversion routines above correct in assuming always the positive value of the root to be taken?


Solution

  • Yes, you are right. In CGAL Sqrt_extension, in the expression a0+a1√(root), the square root is always positive or null.