// Copyright (c) 2012, 2017 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.2/Alpha_shapes_2/include/CGAL/internal/Lazy_alpha_nt_2.h $ // $Id: Lazy_alpha_nt_2.h 254d60f 2019-10-19T15:23:19+02:00 Sébastien Loriot // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Sébastien Loriot // Mael Rouxel-Labbé #ifndef CGAL_INTERNAL_LAZY_ALPHA_NT_2_H #define CGAL_INTERNAL_LAZY_ALPHA_NT_2_H #include #include #include #include #include #include #include #include #include namespace CGAL { namespace internal { // check whether Cartesian_converter can do the following conversions // -- Input_traits::(Weighted_)Point_2 to K2::(Weighted_)Point_2 // -- Input_traits::(Weighted_)Point_2 to K3::(Weighted_)Point_2 // template < class Input_traits, class Kernel_approx, class Kernel_exact, class Weighted_tag > class Is_traits_point_convertible_2 { typedef typename Kernel_traits::Kernel Kernel_input; typedef typename Input_traits::Point_2 K1P; typedef typename Kernel_approx::Point_2 K2P; typedef typename Kernel_exact::Point_2 K3P; public: static const bool value = (Has_conversion::value && Has_conversion::value); }; template < class Input_traits, class Kernel_approx, class Kernel_exact > class Is_traits_point_convertible_2 { typedef typename Kernel_traits::Kernel Kernel_input; typedef typename Input_traits::Weighted_point_2 K1WP; typedef typename Kernel_approx::Weighted_point_2 K2WP; typedef typename Kernel_exact::Weighted_point_2 K3WP; public: static const bool value = (Has_conversion::value && Has_conversion::value); }; template struct Input_points_for_lazy_alpha_nt_2 { int nbpts; const T* p0; const T* p1; const T* p2; }; //non-weighted case template struct Types_for_alpha_nt_2 { //Converter types typedef CGAL::Cartesian_converter To_approx; typedef CGAL::Cartesian_converter To_exact; //Point types typedef typename Kernel_approx::Point_2 Approx_point; typedef typename Kernel_exact::Point_2 Exact_point; typedef typename Input_traits::Point_2 Input_point; //Constructions typedef typename Kernel_approx::Compute_squared_radius_2 Approx_squared_radius; typedef typename Kernel_exact::Compute_squared_radius_2 Exact_squared_radius; }; //weighted case template struct Types_for_alpha_nt_2< ::CGAL::Tag_true /* Weighted_tag */, Input_traits, Kernel_input, Kernel_approx, Kernel_exact > { //Converter types typedef CGAL::Cartesian_converter To_approx; typedef CGAL::Cartesian_converter To_exact; //Point types typedef typename Kernel_approx::Weighted_point_2 Approx_point; typedef typename Kernel_exact::Weighted_point_2 Exact_point; typedef typename Input_traits::Weighted_point_2 Input_point; //Constructions typedef typename Kernel_approx::Compute_squared_radius_smallest_orthogonal_circle_2 Approx_squared_radius; typedef typename Kernel_exact::Compute_squared_radius_smallest_orthogonal_circle_2 Exact_squared_radius; }; template class Lazy_alpha_nt_2 { //NT & kernels typedef CGAL::Interval_nt NT_approx; //Gmpq or Quotient typedef Exact_field_selector::Type NT_exact; typedef CGAL::Simple_cartesian Kernel_approx; typedef CGAL::Simple_cartesian Kernel_exact; typedef typename Kernel_traits::Kernel Kernel_input; //Helper class for weighted and non-weighted case typedef Types_for_alpha_nt_2 Types; //Converters typedef typename Types::To_approx To_approx; typedef typename Types::To_exact To_exact; //Constructions class typedef typename Types::Approx_squared_radius Approx_squared_radius; typedef typename Types::Exact_squared_radius Exact_squared_radius; //Point typedef typename Types::Approx_point Approx_point; typedef typename Types::Exact_point Exact_point; typedef typename Types::Input_point Input_point; //Convertion functions Approx_point to_approx(const Input_point& wp) const { // The traits class' Point_2 must be convertible using the Cartesian converter CGAL_static_assertion((Is_traits_point_convertible_2< Input_traits, Kernel_approx, Kernel_exact, Weighted_tag>::value)); To_approx converter; return converter(wp); } Exact_point to_exact(const Input_point& wp) const { // The traits class' Point_2 must be convertible using the Cartesian converter CGAL_static_assertion((Is_traits_point_convertible_2< Input_traits, Kernel_approx, Kernel_exact, Weighted_tag>::value)); To_exact converter; return converter(wp); } //members //the members can be updated when calling method exact() mutable boost::optional exact_; mutable NT_approx approx_; //private functions typedef Input_points_for_lazy_alpha_nt_2 Data_vector; Data_vector input_points; const Data_vector& data() const{ return input_points;} Data_vector& data(){ return input_points;} static double & relative_precision_of_to_double_internal() { CGAL_STATIC_THREAD_LOCAL_VARIABLE(double, relative_precision_of_to_double, 0.00001); return relative_precision_of_to_double; } public: static const double & get_relative_precision_of_to_double() { return relative_precision_of_to_double_internal(); } static void set_relative_precision_of_to_double(double d) { CGAL_assertion((0 < d) & (d < 1)); relative_precision_of_to_double_internal() = d; } typedef NT_exact Exact_nt; typedef NT_approx Approximate_nt; void update_exact() const { switch(data().nbpts) { case 1: exact_ = Exact_squared_radius()( to_exact(*data().p0) ); break; case 2: exact_ = Exact_squared_radius()( to_exact(*data().p0),to_exact(*data().p1) ); break; case 3: exact_ = Exact_squared_radius()( to_exact(*data().p0),to_exact(*data().p1),to_exact(*data().p2) ); break; default: CGAL_assertion(false); } } void set_approx() { switch(data().nbpts) { case 1: approx_ = Approx_squared_radius()( to_approx(*data().p0) ); break; case 2: approx_ = Approx_squared_radius()( to_approx(*data().p0),to_approx(*data().p1) ); break; case 3: approx_ = Approx_squared_radius()( to_approx(*data().p0),to_approx(*data().p1),to_approx(*data().p2) ); break; default: CGAL_assertion(false); } } const NT_exact& exact() const { if (exact_ == boost::none) { update_exact(); approx_=to_interval(*exact_); } return *exact_; } const NT_approx& approx() const { return approx_; } //Constructors Lazy_alpha_nt_2() : exact_(Exact_nt(0)), approx_(0) { data().nbpts=0; data().p0=nullptr; data().p1=nullptr; data().p2=nullptr; } Lazy_alpha_nt_2(double d) : exact_(Exact_nt(d)), approx_(d) { data().nbpts=0; data().p0=nullptr; data().p1=nullptr; data().p2=nullptr; } Lazy_alpha_nt_2(const Input_point& wp0) { data().nbpts=1; data().p0=&wp0; data().p1=nullptr; data().p2=nullptr; set_approx(); } Lazy_alpha_nt_2(const Input_point& wp0, const Input_point& wp1) { data().nbpts=2; data().p0=&wp0; data().p1=&wp1; data().p2=nullptr; set_approx(); } Lazy_alpha_nt_2(const Input_point& wp0, const Input_point& wp1, const Input_point& wp2) { data().nbpts=3; data().p0=&wp0; data().p1=&wp1; data().p2=&wp2; set_approx(); } #define CGAL_LANT_COMPARE_FUNCTIONS(CMP) \ bool \ operator CMP (const Lazy_alpha_nt_2 &other) const \ { \ Uncertain res = this->approx() CMP other.approx(); \ if (res.is_certain()) \ return res; \ else \ return this->exact() CMP other.exact(); \ } \ CGAL_LANT_COMPARE_FUNCTIONS(<) CGAL_LANT_COMPARE_FUNCTIONS(>) CGAL_LANT_COMPARE_FUNCTIONS(>=) CGAL_LANT_COMPARE_FUNCTIONS(<=) CGAL_LANT_COMPARE_FUNCTIONS(==) CGAL_LANT_COMPARE_FUNCTIONS(!=) #undef CGAL_LANT_COMPARE_FUNCTIONS }; template std::ostream& operator<< (std::ostream& os, const Lazy_alpha_nt_2& a){ return os << ::CGAL::to_double(a.approx()); } // small classes to select the functors in weighted or unweighted cases template struct iCompute_squared_radius_2; template struct iCompute_squared_radius_2 { template typename GeomTraits::Compute_squared_radius_2 operator()(const As& as) const { return static_cast(as).geom_traits(). compute_squared_radius_2_object(); } }; template struct iCompute_squared_radius_2 { template typename GeomTraits::Compute_squared_radius_smallest_orthogonal_circle_2 operator()(const As& as) const { return static_cast(as).geom_traits(). compute_squared_radius_smallest_orthogonal_circle_2_object(); } }; template struct iSide_of_bounded_circle_2; template struct iSide_of_bounded_circle_2 { template typename GeomTraits::Side_of_bounded_circle_2 operator()(const As& as) const { return static_cast(as).geom_traits(). side_of_bounded_circle_2_object(); } }; template struct iSide_of_bounded_circle_2 { template typename GeomTraits::Power_side_of_bounded_power_circle_2 operator()(const As& as) const { return static_cast(as).geom_traits(). power_side_of_bounded_power_circle_2_object(); } }; template struct Lazy_compute_squared_radius_2 { Type_of_alpha operator()(const Point& p, const Point& q, const Point& r) { return Type_of_alpha(p,q,r); } Type_of_alpha operator()(const Point& p, const Point& q) { return Type_of_alpha(p,q); } Type_of_alpha operator()(const Point& p) { return Type_of_alpha(p); } }; template struct Alpha_nt_selector_impl_2; template struct Alpha_nt_selector_impl_2 { typedef typename GeomTraits::FT Type_of_alpha; typedef iCompute_squared_radius_2 Compute_squared_radius_2; typedef iSide_of_bounded_circle_2 Side_of_bounded_circle_2; }; template struct Alpha_nt_selector_impl_2 { typedef Lazy_alpha_nt_2< GeomTraits, true /* mode */, Tag_false /* Weighted_tag */> Type_of_alpha; typedef Lazy_compute_squared_radius_2< Type_of_alpha, typename GeomTraits::Point_2> Functor; struct Compute_squared_radius_2 { template Functor operator()(const As&){return Functor();} }; typedef iSide_of_bounded_circle_2 Side_of_bounded_circle_2; }; template struct Alpha_nt_selector_impl_2 { typedef Lazy_alpha_nt_2< GeomTraits, true /* mode */, Tag_true /* Weighted_tag */> Type_of_alpha; typedef Lazy_compute_squared_radius_2< Type_of_alpha, typename GeomTraits::Weighted_point_2> Functor; struct Compute_squared_radius_2 { template Functor operator()(const As&){return Functor();} }; typedef iSide_of_bounded_circle_2 Side_of_bounded_circle_2; }; template struct Alpha_nt_selector_2 : public Alpha_nt_selector_impl_2< GeomTraits, // If the base traits is already exact then we don't need to do anything, // and we can simply directly use the traits class Boolean_tag::value && ExactAlphaComparisonTag::value >, Weighted_tag> { }; } // namespace internal template double to_double(const internal::Lazy_alpha_nt_2& a) { double r; if (fit_in_double(a.approx(), r)) return r; // If it isn't precise enough, // we trigger the exact computation first, // which will refine the approximation. if (!has_smaller_relative_precision(a.approx(), a.get_relative_precision_of_to_double())) a.exact(); return CGAL_NTS to_double(a.approx()); } } // namespace CGAL #endif // CGAL_INTERNAL_LAZY_ALPHA_NT_2_H