// Copyright (c) 2003-2004 INRIA Sophia-Antipolis (France). // 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. // // $Source: /CVSROOT/CGAL/Packages/Mesh_2/include/CGAL/Mesher_level.h,v $ // $Revision: 1.10 $ $Date: 2004/11/18 14:22:26 $ // $Name: $ // // Author(s) : Laurent RINEAU #ifndef CGAL_MESHER_LEVEL_H #define CGAL_MESHER_LEVEL_H #include namespace CGAL { struct Null_mesh_visitor { const Null_mesh_visitor& previous_level() const { return *this; } template void before_conflicts(E, P) const {} template void before_insertion(E, P, Z) const {} template void after_insertion(V) const {} template void after_no_insertion(E, P, Z) const {} }; struct Null_mesher_level { template void refine(Visitor) {} template std::pair test_point_conflict_from_superior(P, Z) { return std::make_pair(true, true); } bool is_algorithm_done() const { return true; } template bool try_to_insert_one_point(Visitor) { return true; } template bool one_step(Visitor) { return true; } }; // end Null_mesher_level template < class Triangulation_traits, /**< Traits class that defines operations from the trianguilation. */ class Derived, /**< Derived class, that implements methods */ class Element, /**< Type of elements that this level refines. */ class Previous = Null_mesher_level /**< Previous level type, defaults to \c Null_level */ > class Mesher_level { public: /** Type of triangulation that is meshed. */ typedef typename Triangulation_traits::Triangulation Triangulation; /** Type of point that are inserted into the triangulation. */ typedef typename Triangulation_traits::Point Point; /** Type of vertex handles that are returns by insertions into the triangulation. */ typedef typename Triangulation_traits::Vertex_handle Vertex_handle; /** Type of the conflict zone for a point that can be inserted. */ typedef typename Triangulation_traits::Zone Zone; typedef Element Element_type; typedef Previous Previous_level; private: /** \name Private member functions */ /** Curiously recurring template pattern. */ //@{ Derived& derived() { return static_cast(*this); } const Derived& derived() const { return static_cast(*this); } //@} /** \name Private member datas */ Previous& previous_level; /**< The previous level of the refinement process. */ public: typedef Mesher_level Self; /** \name CONSTRUCTORS */ Mesher_level(Previous_level& previous) : previous_level(previous) { } /** \name FUNCTIONS IMPLEMENTED IN THE CLASS \c Derived */ /** Access to the triangulation */ //@{ Triangulation& triangulation() { return derived().get_triangulation_ref(); } const Triangulation& triangulation() const { return derived().get_triangulation_ref(); } //@} /** Access to the triangulation traits */ //@{ Triangulation_traits& triangulation_traits() { return derived().get_triangulation_traits(); } const Triangulation_traits& triangulation_traits() const { return derived().get_triangulation_traits(); } //@} /** Called before the first refinement, to initialized the queue of elements that should be refined. */ void scan_triangulation() { derived().do_scan_triangulation(); } /** Tells if, as regards the elements of type \c Element, the refinement is done. */ bool no_longer_element_to_refine() { return derived().is_no_longer_element_to_refine(); } /** Retrieves the next element that could be refined. */ Element get_next_element() { return derived().do_get_next_element(); } /** Remove from the list the next element that could be refined. */ void pop_next_element() { derived().do_pop_next_element(); } /** Gives the point that should be inserted to refine the element \c e */ Point refinement_point(const Element& e) { return derived().get_refinement_point(e); } /** Actions before testing conflicts for point \c p and element \c e */ template void before_conflicts(const Element& e, const Point& p, Mesh_visitor& visitor) { visitor.before_conflicts(e, p); derived().do_before_conflicts(e, p); } /** Tells if, as regards this level of the refinement process, if the point conflicts with something, and do what is needed. The return type is made of two booleans: - the first one tells if the point can be inserted, - in case of, the first one is \c false, the second one tells if the tested element should be reconsidered latter. */ std::pair private_test_point_conflict(const Point& p, Zone& zone) { return derived().do_private_test_point_conflict(p, zone); } /** Tells if, as regards this level of the refinement process, if the point conflicts with something, and do what is needed. The return type is made of two booleans: - the first one tells if the point can be inserted, - in case of, the first one is \c false, the second one tells if the tested element should be reconsidered latter. This function is called by the superior level, if any. */ std::pair test_point_conflict_from_superior(const Point& p, Zone& zone) { return derived().do_test_point_conflict_from_superior(p, zone); } /** * Actions before inserting the point \c p in order to refine the * element \c e. The zone of conflicts is \c zone. */ template void before_insertion(Element& e, const Point& p, Zone& zone, Mesh_visitor& visitor) { visitor.before_insertion(e, p, zone); derived().do_before_insertion(e, p, zone); } /** Actions after having inserted the point. * \param vh is the vertex handle of the inserted point, * \param visitor is the visitor. */ template void after_insertion(Vertex_handle vh, Mesh_visitor& visitor) { derived().do_after_insertion(vh); visitor.after_insertion(vh); } /** Actions after testing conflicts for point \c p and element \c e * if no point is inserted. */ template void after_no_insertion(const Element& e, const Point& p, Zone& zone, Mesh_visitor& visitor) { derived().do_after_no_insertion(e, p, zone); visitor.after_no_insertion(e, p, zone); } /** DEFAULT IMPLEMENTATION FUNCTIONS * * This bunch of functions should be implemented in the derived class: * * Tr& get_triangulation_ref(); * const Tr& get_triangulation_ref(); * * void do_scan_triangulation(); * * bool is_no_longer_element_to_refine(); * * Element do_get_next_element(); * * void pop_next_element(); * * Point get_refinement_point(Element); * * * The next ones have default implementations that do nothing: * */ // void do_before_conflicts(const Element&, const Point&) // { // } // void do_after_no_insertion(Element, Point, Zone) // { // } // std::pair // do_private_test_point_conflict(Point, Zone) // { // return std::make_pair(true, true); // } // std::pair // do_test_point_conflict_from_superior(Point, Zone) // { // return std::make_pair(true, true); // } // void do_before_insertion(Element, Point, Zone) // { // } // void do_after_insertion(Vertex_handle) // { // } /** \name MESHING PROCESS * * The following functions use the functions that are implemented in the * derived classes. * */ /** * Tells it the algorithm is done, regarding elements of type \c Element * or elements of previous levels. */ bool is_algorithm_done() { return ( previous_level.is_algorithm_done() && no_longer_element_to_refine() ); } /** Refines elements of this level and previous levels. */ template void refine(Mesh_visitor& visitor) { while(! is_algorithm_done() ) { previous_level.refine(visitor.previous_level()); if(! no_longer_element_to_refine() ) process_one_element(visitor); } } /** * This function takes one element from the queue, and try to refine * it. It returns \c true if one point has been inserted. * @todo Merge with try_to_refine_element(). */ template bool process_one_element(Mesh_visitor& visitor) { Element e = get_next_element(); const std::pair result = try_to_refine_element(e, visitor); if(result.second) pop_next_element(); return result.first; } template std::pair try_to_refine_element(Element e, Mesh_visitor& visitor) { const Point& p = refinement_point(e); before_conflicts(e, p, visitor); Zone zone = triangulation_traits().get_conflicts_zone(triangulation(), p); const std::pair result = test_point_conflict(p, zone); if(result.first) { before_insertion(e, p, zone, visitor); Vertex_handle v = triangulation_traits().insert(triangulation(), p, zone); after_insertion(v, visitor); return std::make_pair(true, true); } else after_no_insertion(e, p, zone, visitor); return result; } /** Return (can_split_the_element, drop_element). */ std::pair test_point_conflict(const Point& p, Zone& zone) { const std::pair result = previous_level.test_point_conflict_from_superior(p, zone); if( result.first == false ) return result; return private_test_point_conflict(p, zone); } /** \name STEP BY STEP FUNCTIONS */ /** * Inserts exactly one point, if possible, and returns \c false if no * point has been inserted because the algorithm is done. */ template bool try_to_insert_one_point(Mesh_visitor& visitor) { while(! is_algorithm_done() ) { if( previous_level.try_to_insert_one_point(visitor.previous_level()) ) return true; if(! no_longer_element_to_refine() ) if( process_one_element(visitor) ) return true; } return false; } /** * Applies one step of the algorithm: tries to refine one element of * previous level or one element of this level. Return \c false iff * is_algorithm_done()==true . */ template bool one_step(Mesh_visitor& visitor) { if( ! previous_level.is_algorithm_done() ) previous_level.one_step(visitor.previous_level()); else if( ! no_longer_element_to_refine() ) process_one_element(visitor); return ! is_algorithm_done(); } }; // end Mesher_level } // end namespace CGAL #endif // CGAL_MESHER_LEVEL_H