// Copyright (c) 2012 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_3/include/CGAL/internal/Lazy_alpha_nt_3.h $ // $Id: Lazy_alpha_nt_3.h 0779373 2020-03-26T13:31:46+01: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_3_H #define CGAL_INTERNAL_LAZY_ALPHA_NT_3_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_3 to K2::(Weighted_)Point_3 // -- Input_traits::(Weighted_)Point_3 to K3::(Weighted_)Point_3 // template < class Input_traits, class Kernel_approx, class Kernel_exact, class Weighted_tag > class Is_traits_point_convertible_3 { typedef typename Kernel_traits::Kernel Kernel_input; typedef typename Input_traits::Point_3 K1P; typedef typename Kernel_approx::Point_3 K2P; typedef typename Kernel_exact::Point_3 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_3 { typedef typename Kernel_traits::Kernel Kernel_input; typedef typename Input_traits::Weighted_point_3 K1WP; typedef typename Kernel_approx::Weighted_point_3 K2WP; typedef typename Kernel_exact::Weighted_point_3 K3WP; public: static const bool value = (Has_conversion::value && Has_conversion::value); }; template struct Input_points_for_lazy_alpha_nt_3 { int nbpts; const T* p0; const T* p1; const T* p2; const T* p3; }; //non-weighted case template struct Types_for_alpha_nt_3 { //Converter types typedef CGAL::Cartesian_converter To_approx; typedef CGAL::Cartesian_converter To_exact; //Point types typedef typename Kernel_approx::Point_3 Approx_point; typedef typename Kernel_exact::Point_3 Exact_point; typedef typename Input_traits::Point_3 Input_point; //Constructions typedef typename Kernel_approx::Compute_squared_radius_3 Approx_squared_radius; typedef typename Kernel_exact::Compute_squared_radius_3 Exact_squared_radius; }; //weighted case template struct Types_for_alpha_nt_3< ::CGAL::Tag_true,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_3 Approx_point; typedef typename Kernel_exact::Weighted_point_3 Exact_point; typedef typename Input_traits::Weighted_point_3 Input_point; //Constructions typedef typename Kernel_approx::Compute_squared_radius_smallest_orthogonal_sphere_3 Approx_squared_radius; typedef typename Kernel_exact::Compute_squared_radius_smallest_orthogonal_sphere_3 Exact_squared_radius; }; template class Lazy_alpha_nt_3{ //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_3 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_3 must be convertible using the Cartesian converter CGAL_static_assertion((Is_traits_point_convertible_3< 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_3 must be convertible using the Cartesian converter CGAL_static_assertion((Is_traits_point_convertible_3< 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_3 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; case 4: exact_ = Exact_squared_radius()( to_exact(*data().p0),to_exact(*data().p1),to_exact(*data().p2),to_exact(*data().p3) ); 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; case 4: approx_ = Approx_squared_radius()( to_approx(*data().p0),to_approx(*data().p1),to_approx(*data().p2),to_approx(*data().p3) ); 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_3() : exact_(Exact_nt(0)),approx_(0) { data().nbpts=0; data().p0=nullptr; data().p1=nullptr; data().p2=nullptr; data().p3=nullptr; } Lazy_alpha_nt_3(double d) : exact_(Exact_nt(d)),approx_(d) { data().nbpts=0; data().p0=nullptr; data().p1=nullptr; data().p2=nullptr; data().p3=nullptr; } Lazy_alpha_nt_3(const Input_point& wp1) { data().nbpts=1; data().p0=&wp1; data().p1=nullptr; data().p2=nullptr; data().p3=nullptr; set_approx(); } Lazy_alpha_nt_3(const Input_point& wp1, const Input_point& wp2) { data().nbpts=2; data().p0=&wp1; data().p1=&wp2; data().p2=nullptr; data().p3=nullptr; set_approx(); } Lazy_alpha_nt_3(const Input_point& wp1, const Input_point& wp2, const Input_point& wp3) { data().nbpts=3; data().p0=&wp1; data().p1=&wp2; data().p2=&wp3; data().p3=nullptr; set_approx(); } Lazy_alpha_nt_3(const Input_point& wp1, const Input_point& wp2, const Input_point& wp3, const Input_point& wp4) { data().nbpts=4; data().p0=&wp1; data().p1=&wp2; data().p2=&wp3; data().p3=&wp4; set_approx(); } #define CGAL_LANT_COMPARE_FUNCTIONS(CMP) \ bool \ operator CMP (const Lazy_alpha_nt_3 &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_3& a){ return os << ::CGAL::to_double(a.approx()); } //small class to select predicate in weighted and unweighted case template struct iCompute_squared_radius_3; template struct iCompute_squared_radius_3 { template typename GeomTraits::Compute_squared_radius_3 operator()(const As& as) const{ return static_cast(as).geom_traits().compute_squared_radius_3_object(); } }; template struct iCompute_squared_radius_3 { template typename GeomTraits::Compute_squared_radius_smallest_orthogonal_sphere_3 operator()(const As& as) const{ return static_cast(as).geom_traits().compute_squared_radius_smallest_orthogonal_sphere_3_object(); } }; template struct Lazy_compute_squared_radius_3 { Type_of_alpha operator() (const Point& p, const Point& q , const Point& r, const Point& s) {return Type_of_alpha(p,q,r,s);} 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_3; template struct Alpha_nt_selector_impl_3 { typedef typename GeomTraits::FT Type_of_alpha; typedef iCompute_squared_radius_3 Compute_squared_radius_3; }; template struct Alpha_nt_selector_impl_3 { typedef Lazy_alpha_nt_3 Type_of_alpha; typedef Lazy_compute_squared_radius_3 Functor; struct Compute_squared_radius_3{ template Functor operator()(const As&){return Functor();} }; }; template struct Alpha_nt_selector_impl_3 { typedef Lazy_alpha_nt_3 Type_of_alpha; typedef Lazy_compute_squared_radius_3 Functor; struct Compute_squared_radius_3{ template Functor operator()(const As&){return Functor();} }; }; template struct Alpha_nt_selector_3 : public Alpha_nt_selector_impl_3< 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_3& 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_3_H