// Copyright (c) 1997-2001 Freie Universitaet Berlin (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Sven Schoenherr , Bernd Gaertner #ifndef CGAL_OPTIMISATION_ELLIPSE_2_H #define CGAL_OPTIMISATION_ELLIPSE_2_H #include #include #ifndef CGAL_IO_FORWARD_DECL_WINDOW_STREAM_H # include #endif CGAL_BEGIN_NAMESPACE // Class interface // =============== template < class K_ > class Optimisation_ellipse_2 { /* friend std::ostream& operator << <> ( std::ostream&, const Optimisation_ellipse_2&); friend std::istream& operator >> <> ( std::istream&, Optimisation_ellipse_2 &); friend CGAL::Window_stream& operator << <> ( CGAL::Window_stream&, const Optimisation_ellipse_2&); */ public: // types typedef K_ K; typedef typename K_::RT RT; typedef typename K_::FT FT; typedef typename K::Point_2 Point; typedef typename K::Conic_2 Conic; /************************************************************************** WORKAROUND: Some compilers are unable to match member functions defined outside the class template. Therefore, all member functions are implemented in the class interface. // creation Optimisation_ellipse_2( ); void set( ); void set( const Point& p); void set( const Point& p, const Point& q); void set( const Point& p1, const Point& p2, const Point& p3); void set( const Point& p1, const Point& p2, const Point& p3, const Point& p4); void set( const Point& p1, const Point& p2, const Point& p3, const Point& p4, const Point& p5); // access functions int number_of_boundary_points() // equality tests bool operator == ( const Optimisation_ellipse_2& e) const; bool operator != ( const Optimisation_ellipse_2& e) const; // predicates CGAL::Bounded_side bounded_side( const Point& p) const; bool has_on_bounded_side ( const Point& p) const; bool has_on_boundary ( const Point& p) const; bool has_on_unbounded_side ( const Point& p) const; bool is_empty ( ) const; bool is_degenerate( ) const; **************************************************************************/ /* private: */ // private data members int n_boundary_points; // number of boundary points Point boundary_point1, boundary_point2, boundary_point3, boundary_point4, boundary_point5; // <= 5 support point Conic conic1, conic2; // two conics // this gradient vector has dr=0 and is used in testing the // position of a point relative to an ellipse through 4 points mutable RT dr, ds, dt, du, dv, dw; mutable bool d_values_set; // this gradient vector is just conic2 - conic1 and is used in // obtaining an explicit conic representing an ellipse through 4 poinnts mutable RT er, es, et, eu, ev, ew; mutable bool e_values_set; // needed in bounded-side predicate over ellipse with 4 support points mutable Conic helper_ellipse; // needed in bounded-side predicate over mutable bool helper_ellipse_set; mutable Conic helper_conic; // also needed in bounded-side test // ============================================================================ // Class implementation // ==================== public: // Constructor // ----------- inline Optimisation_ellipse_2( ) : er(0), es(0), et(0), eu(0), ev(0), ew(0) { } // Set functions // ------------- inline void set( ) { n_boundary_points = 0; } inline void set( const Point& p) { n_boundary_points = 1; boundary_point1 = p; } inline void set( const Point& p, const Point& q) { n_boundary_points = 2; CGAL_optimisation_precondition(boundary_point1 == p); boundary_point2 = q; } inline void set( const Point& p1, const Point& p2, const Point& p3) { n_boundary_points = 3; CGAL_optimisation_precondition(boundary_point1 == p1); CGAL_optimisation_precondition(boundary_point2 == p2); boundary_point3 = p3; conic1.set_ellipse( p1, p2, p3); } inline void set( const Point& p1, const Point& p2, const Point& p3, const Point& p4) { n_boundary_points = 4; CGAL_optimisation_precondition(boundary_point1 == p1); CGAL_optimisation_precondition(boundary_point2 == p2); CGAL_optimisation_precondition(boundary_point3 == p3); boundary_point4 = p4; Conic::set_two_linepairs( p1, p2, p3, p4, conic1, conic2); d_values_set = false; e_values_set = false; helper_ellipse_set = false; } void set_d_values() const { if (!d_values_set) { dr = RT( 0); ds = conic1.r() * conic2.s() - conic2.r() * conic1.s(), dt = conic1.r() * conic2.t() - conic2.r() * conic1.t(), du = conic1.r() * conic2.u() - conic2.r() * conic1.u(), dv = conic1.r() * conic2.v() - conic2.r() * conic1.v(), dw = conic1.r() * conic2.w() - conic2.r() * conic1.w(); d_values_set = true; } } void set_e_values() const { if (!e_values_set) { er = conic2.r() - conic1.r(); es = conic2.s() - conic1.s(); et = conic2.t() - conic1.t(); eu = conic2.u() - conic1.u(); ev = conic2.v() - conic1.v(); ew = conic2.w() - conic1.w(); e_values_set = true; } } void set_helper_ellipse () const { if (!helper_ellipse_set) { helper_ellipse.set_ellipse( conic1, conic2); helper_ellipse.analyse(); CGAL_optimisation_assertion (helper_ellipse.is_ellipse()); helper_ellipse_set= true; } } void set( const Point& p1, const Point& p2, const Point& p3, const Point& p4, const Point& p5) { // uses the fact that the conic to be constructed has already // been computed in preceding bounded-side test over a 4-point // ellipse conic1 = helper_conic; n_boundary_points = 5; CGAL_optimisation_precondition(boundary_point1 == p1); CGAL_optimisation_precondition(boundary_point2 == p2); CGAL_optimisation_precondition(boundary_point3 == p3); CGAL_optimisation_precondition(boundary_point4 == p4); boundary_point5 = p5; } // Access functions // ---------------- inline int number_of_boundary_points( ) const { return( n_boundary_points); } template void double_conic(DoubleConic_2& e) const { double r,s,t,u,v,w; double_coefficients(r,s,t,u,v,w); e.set(r,s,t,u,v,w); // actually, we would have to call e.analyse() now to get // a clean conic, but since this is only internal stuff // right now, the call is omitted to save time } void double_coefficients (double &r, double &s,double &t, double &u, double &v, double &w) const { // just like double_conic, but we only get the coefficients CGAL_optimisation_precondition( ! is_degenerate()); double tau = 0.0; if ( n_boundary_points == 4) { set_e_values(); tau = conic1.vol_minimum( er, es, et, eu, ev, ew); } r = CGAL::to_double( conic1.r()) + tau*CGAL::to_double( er); s = CGAL::to_double( conic1.s()) + tau*CGAL::to_double( es); t = CGAL::to_double( conic1.t()) + tau*CGAL::to_double( et); u = CGAL::to_double( conic1.u()) + tau*CGAL::to_double( eu); v = CGAL::to_double( conic1.v()) + tau*CGAL::to_double( ev); w = CGAL::to_double( conic1.w()) + tau*CGAL::to_double( ew); } // Equality tests // -------------- bool operator == ( const Optimisation_ellipse_2& e) const { if ( n_boundary_points != e.n_boundary_points) return( false); switch ( n_boundary_points) { case 0: return( true); case 1: return( boundary_point1 == e.boundary_point1); case 2: return( ( ( boundary_point1 == e.boundary_point1) && ( boundary_point2 == e.boundary_point2)) || ( ( boundary_point1 == e.boundary_point2) && ( boundary_point2 == e.boundary_point1))); case 3: case 5: return( conic1 == e.conic1); case 4: return( ( ( conic1 == e.conic1) && ( conic2 == e.conic2)) || ( ( conic1 == e.conic2) && ( conic2 == e.conic1))); default: CGAL_optimisation_assertion( ( n_boundary_points >= 0) && ( n_boundary_points <= 5)); } // keeps g++ happy return( false); } inline bool operator != ( const Optimisation_ellipse_2& e) const { return( ! operator == ( e)); } // Predicates // ---------- inline CGAL::Bounded_side bounded_side( const Point& p) const { switch ( n_boundary_points) { case 0: return( CGAL::ON_UNBOUNDED_SIDE); case 1: return( ( p == boundary_point1) ? CGAL::ON_BOUNDARY : CGAL::ON_UNBOUNDED_SIDE); case 2: return( ( p == boundary_point1) || ( p == boundary_point2) || ( CGAL::are_ordered_along_line( boundary_point1, p, boundary_point2)) ? CGAL::ON_BOUNDARY : CGAL::ON_UNBOUNDED_SIDE); case 3: case 5: return( conic1.convex_side( p)); case 4: { helper_conic.set( conic1, conic2, p); helper_conic.analyse(); if ( !helper_conic.is_ellipse()) { set_helper_ellipse(); return( helper_ellipse.convex_side( p)); } else { set_d_values(); int tau_star = helper_conic.vol_derivative( dr, ds, dt, du, dv, dw); return( CGAL::Bounded_side( CGAL_NTS sign( tau_star))); } } default: CGAL_optimisation_assertion( ( n_boundary_points >= 0) && ( n_boundary_points <= 5) ); } // keeps g++ happy return( CGAL::Bounded_side( 0)); } inline bool has_on_bounded_side( const Point& p) const { return( bounded_side( p) == CGAL::ON_BOUNDED_SIDE); } inline bool has_on_boundary( const Point& p) const { return( bounded_side( p) == CGAL::ON_BOUNDARY); } inline bool has_on_unbounded_side( const Point& p) const { return( bounded_side( p) == CGAL::ON_UNBOUNDED_SIDE); } inline bool is_empty( ) const { return( n_boundary_points == 0); } inline bool is_degenerate( ) const { return( n_boundary_points < 3); } bool is_circle( ) const { switch ( n_boundary_points) { case 0: return false; // the empty set is not a circle case 1: return true; case 2: return false; // a segment is not a circle case 3: case 5: return conic1.is_circle(); case 4: // the smallest ellipse through four points is // a circle only if the four points are cocircular; // if so, compute this circle (as a conic) and check // its volume derivative if (CGAL::ON_BOUNDARY != CGAL::side_of_bounded_circle (boundary_point1, boundary_point2, boundary_point3, boundary_point4)) { return false; } else { // ok, they are cocircular, now get the circle and check it Conic c; c.set_circle(boundary_point1, boundary_point2, boundary_point3); set_d_values(); return (CGAL_NTS is_zero (c.vol_derivative (dr, ds, dt, du, dv, dw))); } default: CGAL_optimisation_assertion( ( n_boundary_points >= 0) && ( n_boundary_points <= 5) ); return false; } } }; // Function declarations // ===================== // I/O // --- template < class K_ > std::ostream& operator << ( std::ostream&, const CGAL::Optimisation_ellipse_2&); template < class K_ > std::istream& operator >> ( std::istream&, CGAL::Optimisation_ellipse_2&); CGAL_END_NAMESPACE #ifdef CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION # include #endif #endif // CGAL_OPTIMISATION_ELLIPSE_2_H // ===== EOF ==================================================================