// Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // 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$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Michael Seel //--------------------------------------------------------------------- // file generated by notangle from Convex_hull_d.lw // please debug or modify web file // mails and bugs: Michael.Seel@mpi-sb.mpg.de // based on LEDA architecture by S. Naeher, C. Uhrig // coding: K. Mehlhorn, M. Seel // debugging and templatization: M. Seel //--------------------------------------------------------------------- #ifndef CGAL_CONVEX_HULL_D_H #define CGAL_CONVEX_HULL_D_H #include #define CGAL_DEPRECATED_HEADER "" #define CGAL_DEPRECATED_MESSAGE_DETAILS \ "The Triangulation package (see https://doc.cgal.org/latest/Triangulation) should be used instead." #include /*{\Manpage {Convex_hull_d}{R}{Convex Hulls}{C}}*/ /*{\Mdefinition An instance |\Mvar| of type |\Mname| is the convex hull of a multi-set |S| of points in $d$-dimensional space. We call |S| the underlying point set and $d$ or |dim| the dimension of the underlying space. We use |dcur| to denote the affine dimension of |S|. The data type supports incremental construction of hulls. The closure of the hull is maintained as a simplicial complex, i.e., as a collection of simplices. The intersection of any two is a face of both\cgalFootnote{The empty set if a facet of every simplex.}. In the sequel we reserve the word simplex for the simplices of dimension |dcur|. For each simplex there is a handle of type |Simplex_handlex| and for each vertex there is a handle of type |Vertex_handle|. Each simplex has $1 + |dcur|$ vertices indexed from $0$ to |dcur|; for a simplex $s$ and an index $i$, |C.vertex(s,i)| returns the $i$-th vertex of $s$. For any simplex $s$ and any index $i$ of $s$ there may or may not be a simplex $t$ opposite to the $i$-th vertex of $s$. The function |C.opposite_simplex(s,i)| returns $t$ if it exists and returns |Simplex_handle()| (the undefined handle) otherwise. If $t$ exists then $s$ and $t$ share |dcur| vertices, namely all but the vertex with index $i$ of $s$ and the vertex with index |C.index_of_vertex_in_opposite_simplex(s,i)| of $t$. Assume that $t$ exists and let |j = C.index_of_vertex_in_opposite_simplex(s,i)|. Then $s =$ |C.opposite_simplex(t,j)| and $i =$ |C.index_of_vertex_in_opposite_simplex(t,j)|. The boundary of the hull is also a simplicial complex. All simplices in this complex have dimension $|dcur| - 1$. For each boundary simplex there is a handle of type |Facet_handle|. Each facet has |dcur| vertices indexed from $0$ to $|dcur| - 1$. If |dcur > 1| then for each facet $f$ and each index $i$, $0 \le i < |dcur|$, there is a facet $g$ opposite to the $i$-th vertex of $f$. The function |C.opposite_facet(f,i)| returns $g$. Two neighboring facets $f$ and $g$ share |dcur - 1| vertices, namely all but the vertex with index $i$ of $f$ and the vertex with index |C.index_of_vertex_in_opposite_facet(f,i)| of $g$. Let |j = C.index_of_vertex_in_opposite_facet(f,i)|. Then |f = C.opposite_facet(g,j)| and |i = C.index_of_vertex_in_opposite_facet(g,j)|.}*/ #include #include #include #include #include #include #include #include namespace CGAL { template class Facet_iterator_rep_; template class Facet_iterator_; template class Facet_iterator_rep_ { CGAL::Unique_hash_map* pvisited_; std::list* pcandidates_; Hull_pointer hull_; Handle current_; friend class Facet_iterator_; void add_candidates() { CGAL_assertion(pvisited_ && pcandidates_ && hull_); for(int i = 1; i <= hull_->current_dimension(); ++i) { Handle f = hull_->opposite_simplex(current_,i); if ( !(*pvisited_)[f] ) { pcandidates_->push_front(f); (*pvisited_)[f] = true; } } } public: Facet_iterator_rep_() : pvisited_(0), pcandidates_(0), hull_(0), current_() {} Facet_iterator_rep_(Hull_pointer p, Handle h) : pvisited_(0), pcandidates_(0), hull_(p), current_(h) {} ~Facet_iterator_rep_() { if (pvisited_) delete pvisited_; if (pcandidates_) delete pcandidates_; } }; template class Facet_iterator_ : private Handle_for > { typedef Facet_iterator_ Self; typedef Facet_iterator_rep_ Rep; typedef Handle_for< Facet_iterator_rep_ > Base; using Base::ptr; public: typedef typename Handle::value_type value_type; typedef typename Handle::pointer pointer; typedef typename Handle::reference reference; typedef typename Handle::difference_type difference_type; typedef std::forward_iterator_tag iterator_category; Facet_iterator_() : Base( Rep() ) {} Facet_iterator_(Hull_pointer p, Handle h) : Base( Rep(p,h) ) { ptr()->pvisited_ = new Unique_hash_map(false); ptr()->pcandidates_ = new std::list; (*(ptr()->pvisited_))[ptr()->current_]=true; ptr()->add_candidates(); } reference operator*() const { return ptr()->current_.operator*(); } pointer operator->() const { return ptr()->current_.operator->(); } Self& operator++() { if ( ptr()->current_ == Handle() ) return *this; if ( ptr()->pcandidates_->empty() ) ptr()->current_ = Handle(); else { ptr()->current_ = ptr()->pcandidates_->back(); ptr()->pcandidates_->pop_back(); ptr()->add_candidates(); } return *this; } Self operator++(int) { Self tmp = *this; ++*this; return tmp; } bool operator==(const Self& x) const { return ptr()->current_ == x.ptr()->current_; } bool operator!=(const Self& x) const { return !operator==(x); } operator Handle() { return ptr()->current_; } }; template class Hull_vertex_iterator_rep_; template class Hull_vertex_iterator_; template class Hull_vertex_iterator_rep_ { CGAL::Unique_hash_map* pvisited_; Hull_pointer hull_; VHandle v_; FHandle f_; int i_; friend class Hull_vertex_iterator_; void advance() { CGAL_assertion(pvisited_ && hull_); if ( f_ == FHandle() ) return; bool search_next = true; ++i_; while ( search_next ) { while(i_ < hull_->current_dimension()) { v_ = hull_->vertex_of_facet(f_,i_); if ( !(*pvisited_)[v_] ) { search_next=false; break; } ++i_; } if ( search_next ) { i_=0; ++f_; } if ( f_ == FHandle() ) { search_next=false; v_ = VHandle(); } } (*pvisited_)[v_] = true; } public: Hull_vertex_iterator_rep_() : pvisited_(0), hull_(0), i_(0) {} Hull_vertex_iterator_rep_(Hull_pointer p, FHandle f) : pvisited_(0), hull_(p), f_(f), i_(-1) {} ~Hull_vertex_iterator_rep_() { if (pvisited_) delete pvisited_; } }; template class Hull_vertex_iterator_ : private Handle_for< Hull_vertex_iterator_rep_ > { typedef Hull_vertex_iterator_ Self; typedef Hull_vertex_iterator_rep_ Rep; typedef Handle_for< Rep > Base; using Base::ptr; public: typedef typename VHandle::value_type value_type; typedef typename VHandle::pointer pointer; typedef typename VHandle::reference reference; typedef typename VHandle::difference_type difference_type; typedef std::forward_iterator_tag iterator_category; Hull_vertex_iterator_() : Base( Rep() ) {} Hull_vertex_iterator_(Hull_pointer p, FHandle f) : Base( Rep(p,f) ) { ptr()->pvisited_ = new Unique_hash_map(false); ptr()->advance(); } reference operator*() const { return ptr()->v_.operator*(); } pointer operator->() const { return ptr()->v_.operator->(); } Self& operator++() { if ( ptr()->v_ == VHandle() ) return *this; ptr()->advance(); return *this; } Self operator++(int) { Self tmp = *this; ++*this; return tmp; } bool operator==(const Self& x) const { return ptr()->v_ == x.ptr()->v_; } bool operator!=(const Self& x) const { return !operator==(x); } operator VHandle() { return ptr()->v_; } }; template struct Point_from_Vertex { typedef Vertex argument_type; typedef Point result_type; result_type& operator()(argument_type& x) const { return x.point(); } const result_type& operator()(const argument_type& x) const { return x.point(); } }; template struct list_collector { std::list

& L_; list_collector(std::list

& L) : L_(L) {} void operator()(H2 f) const { L_.push_back(static_cast

(f)); } }; template class Convex_hull_d : public Regular_complex_d { typedef Regular_complex_d Base; typedef Convex_hull_d Self; public: using Base::new_simplex; using Base::new_vertex; using Base::associate_vertex_with_simplex; using Base::associate_point_with_vertex; using Base::set_neighbor; using Base::kernel; using Base::dcur; /*{\Xgeneralization Regular_complex_d}*/ /*{\Mtypes 6.5}*/ typedef R_ R; /*{\Mtypemember the representation class.}*/ typedef typename R::Point_d Point_d; /*{\Mtypemember the point type.}*/ typedef typename R::Hyperplane_d Hyperplane_d; /*{\Mtypemember the hyperplane type.}*/ typedef typename R::Vector_d Vector_d; typedef typename R::Ray_d Ray_d; typedef typename R::RT RT; typedef std::list Point_list; // make traits types locally available typedef typename Base::Simplex_handle Simplex_handle; /*{\Mtypemember handle for simplices.}*/ typedef typename Base::Simplex_handle Facet_handle; /*{\Mtypemember handle for facets.}*/ typedef typename Base::Vertex_handle Vertex_handle; /*{\Mtypemember handle for vertices.}*/ typedef typename Base::Simplex_iterator Simplex_iterator; /*{\Mtypemember iterator for simplices.}*/ typedef typename Base::Vertex_iterator Vertex_iterator; /*{\Mtypemember iterator for vertices.}*/ typedef Facet_iterator_ Facet_iterator; /*{\Mtypemember iterator for facets.}*/ typedef Hull_vertex_iterator_ Hull_vertex_iterator; /*{\Mtypemember iterator for vertices that are part of the convex hull.}*/ /*{\Mtext Note that each iterator fits the handle concept, i.e. iterators can be used as handles. Note also that all iterator and handle types come also in a const flavor, e.g., |Vertex_const_iterator| is the constant version of |Vertex_iterator|. Thus use the const version whenever the the convex hull object is referenced as constant.}*/ #define CGAL_USING(t) typedef typename Base::t t CGAL_USING(Simplex_const_iterator);CGAL_USING(Vertex_const_iterator); CGAL_USING(Simplex_const_handle);CGAL_USING(Vertex_const_handle); #undef CGAL_USING typedef Simplex_const_handle Facet_const_handle; typedef Facet_iterator_ Facet_const_iterator; typedef Hull_vertex_iterator_ Hull_vertex_const_iterator; typedef typename Point_list::const_iterator Point_const_iterator; /*{\Mtypemember const iterator for all inserted points.}*/ typedef typename Vertex_handle::value_type Vertex; typedef CGAL::Iterator_project< Hull_vertex_const_iterator, Point_from_Vertex, const Point_d&, const Point_d*> Hull_point_const_iterator; /*{\Mtypemember const iterator for all points of the hull.}*/ protected: Point_list all_pnts_; Vector_d quasi_center_; // sum of the vertices of origin simplex Simplex_handle origin_simplex_; // pointer to the origin simplex Facet_handle start_facet_; // pointer to some facet on the surface Vertex_handle anti_origin_; public: // until there are template friend functions possible Point_d center() const // compute center from quasi center { typename R::Vector_to_point_d to_point = kernel().vector_to_point_d_object(); return to_point(quasi_center_/RT(dcur + 1)); } const Vector_d& quasi_center() const { return quasi_center_; } Simplex_const_handle origin_simplex() const { return origin_simplex_; } Hyperplane_d base_facet_plane(Simplex_handle s) const { return s -> hyperplane_of_base_facet(); } Hyperplane_d base_facet_plane(Simplex_const_handle s) const { return s -> hyperplane_of_base_facet(); } bool& visited_mark(Simplex_handle s) const { return s->visited(); } protected: std::size_t num_of_bounded_simplices; std::size_t num_of_unbounded_simplices; std::size_t num_of_visibility_tests; std::size_t num_of_vertices; void compute_equation_of_base_facet(Simplex_handle s); /*{\Xop computes the equation of the base facet of $s$ and sets the |base_facet| member of $s$. The equation is normalized such that the origin simplex lies in the negative halfspace.}*/ bool is_base_facet_visible(Simplex_handle s, const Point_d& x) const { typename R::Has_on_positive_side_d has_on_positive_side = kernel().has_on_positive_side_d_object(); return has_on_positive_side(s->hyperplane_of_base_facet(),x); } /*{\Xop returns true if $x$ sees the base facet of $s$, i.e., lies in its positive halfspace.}*/ bool contains_in_base_facet(Simplex_handle s, const Point_d& x) const; /*{\Xop returns true if $x$ lies in the closure of the base facet of $s$.}*/ void visibility_search(Simplex_handle S, const Point_d& x, std::list& visible_simplices, std::size_t& num_of_visited_simplices, int& location, Facet_handle& f) const; /*{\Xop adds all unmarked unbounded simplices with $x$-visible base facet to |visible_simplices| and marks them. In |location| the procedure returns the position of |x| with respect to the current hull: $-1$ for inside, $0$ for on the the boundary, and $+1$ for outside; the initial value of |location| for the outermost call must be $-1$. If $x$ is contained in the boundary of |\Mvar| then a facet incident to $x$ is returned in $f$.}*/ void clear_visited_marks(Simplex_handle s) const; /*{\Xop removes the mark bits from all marked simplices reachable from $s$.}*/ void dimension_jump(Simplex_handle S, Vertex_handle x); /*{\Xop Adds a new vertex $x$ to the triangulation. The point associated with $x$ lies outside the affine hull of the current point set. }*/ void visible_facets_search(Simplex_handle S, const Point_d& x, std::list< Facet_handle >& VisibleFacets, std::size_t& num_of_visited_facets) const; public: /*{\Mcreation 3}*/ Convex_hull_d(int d, const R& Kernel = R()); /*{\Mcreate creates an instance |\Mvar| of type |\Mtype|. The dimension of the underlying space is $d$ and |S| is initialized to the empty point set. The traits class |R| specifies the models of all types and the implementations of all geometric primitives used by the convex hull class. The default model is one of the $d$-dimensional representation classes (e.g., |Homogeneous_d|).}*/ protected: /*{\Mtext The data type |\Mtype| offers neither copy constructor nor assignment operator.}*/ Convex_hull_d(const Self&); Convex_hull_d& operator=(const Self&); public: /*{\Moperations 3}*/ /*{\Mtext All operations below that take a point |x| as argument have the common precondition that |x| is a point of ambient space.}*/ int dimension() const { return Base::dimension(); } /*{\Mop returns the dimension of ambient space}*/ int current_dimension() const { return Base::current_dimension(); } /*{\Mop returns the affine dimension |dcur| of $S$.}*/ Point_d associated_point(Vertex_handle v) const { return Base::associated_point(v); } /*{\Mop returns the point associated with vertex $v$.}*/ Point_d associated_point(Vertex_const_handle v) const { return Base::associated_point(v); } Vertex_handle vertex_of_simplex(Simplex_handle s, int i) const { return Base::vertex(s,i); } /*{\Mop returns the vertex corresponding to the $i$-th vertex of $s$.\\ \precond $0 \leq i \leq |dcur|$. }*/ Vertex_const_handle vertex_of_simplex(Simplex_const_handle s, int i) const { return Base::vertex(s,i); } Point_d point_of_simplex(Simplex_handle s,int i) const { return associated_point(vertex_of_simplex(s,i)); } /*{\Mop same as |C.associated_point(C.vertex_of_simplex(s,i))|. }*/ Point_d point_of_simplex(Simplex_const_handle s,int i) const { return associated_point(vertex_of_simplex(s,i)); } Simplex_handle opposite_simplex(Simplex_handle s,int i) const { return Base::opposite_simplex(s,i); } /*{\Mop returns the simplex opposite to the $i$-th vertex of $s$ (|Simplex_handle()| if there is no such simplex). \precond $0 \leq i \leq |dcur|$. }*/ Simplex_const_handle opposite_simplex(Simplex_const_handle s,int i) const { return Base::opposite_simplex(s,i); } int index_of_vertex_in_opposite_simplex(Simplex_handle s,int i) const { return Base::index_of_opposite_vertex(s,i); } /*{\Mop returns the index of the vertex opposite to the $i$-th vertex of $s$. \precond $0 \leq i \leq |dcur|$ and there is a simplex opposite to the $i$-th vertex of $s$. }*/ int index_of_vertex_in_opposite_simplex(Simplex_const_handle s,int i) const { return Base::index_of_opposite_vertex(s,i); } Simplex_handle simplex(Vertex_handle v) const { return Base::simplex(v); } /*{\Mop returns a simplex of which $v$ is a node. Note that this simplex is not unique. }*/ Simplex_const_handle simplex(Vertex_const_handle v) const { return Base::simplex(v); } int index(Vertex_handle v) const { return Base::index(v); } /*{\Mop returns the index of $v$ in |simplex(v)|.}*/ int index(Vertex_const_handle v) const { return Base::index(v); } Vertex_handle vertex_of_facet(Facet_handle f, int i) const { return vertex_of_simplex(f,i+1); } /*{\Mop returns the vertex corresponding to the $i$-th vertex of $f$. \precond $0 \leq i < |dcur|$. }*/ Vertex_const_handle vertex_of_facet(Facet_const_handle f, int i) const { return vertex_of_simplex(f,i+1); } Point_d point_of_facet(Facet_handle f, int i) const { return point_of_simplex(f,i+1); } /*{\Mop same as |C.associated_point(C.vertex_of_facet(f,i))|.}*/ Point_d point_of_facet(Facet_const_handle f, int i) const { return point_of_simplex(f,i+1); } Facet_handle opposite_facet(Facet_handle f, int i) const { return opposite_simplex(f,i+1); } /*{\Mop returns the facet opposite to the $i$-th vertex of $f$ (|Facet_handle()| if there is no such facet). \precond $0 \leq i < |dcur|$ and |dcur > 1|. }*/ Facet_const_handle opposite_facet(Facet_const_handle f, int i) const { return opposite_simplex(f,i+1); } int index_of_vertex_in_opposite_facet(Facet_handle f, int i) const { return index_of_vertex_in_opposite_simplex(f,i+1) - 1; } /*{\Mop returns the index of the vertex opposite to the $i$-th vertex of $f$. \precond $0 \leq i < |dcur|$ and |dcur > 1|.}*/ int index_of_vertex_in_opposite_facet(Facet_const_handle f, int i) const { return index_of_vertex_in_opposite_simplex(f,i+1) - 1; } Hyperplane_d hyperplane_supporting(Facet_handle f) const { return f -> hyperplane_of_base_facet(); } /*{\Mop returns a hyperplane supporting facet |f|. The hyperplane is oriented such that the interior of |\Mvar| is on the negative side of it. \precond |f| is a facet of |\Mvar| and |dcur > 1|.}*/ Hyperplane_d hyperplane_supporting(Facet_const_handle f) const { return f -> hyperplane_of_base_facet(); } Vertex_handle insert(const Point_d& x); /*{\Mop adds point |x| to the underlying set of points. If $x$ is equal to (the point associated with) a vertex of the current hull this vertex is returned and its associated point is changed to $x$. If $x$ lies outside the current hull, a new vertex |v| with associated point $x$ is added to the hull and returned. In all other cases, i.e., if $x$ lies in the interior of the hull or on the boundary but not on a vertex, the current hull is not changed and |Vertex_handle()| is returned. If |CGAL_CHECK_EXPENSIVE| is defined then the validity check |is_valid(true)| is executed as a post condition.}*/ template void insert(Forward_iterator first, Forward_iterator last) { while (first != last) insert(*first++); } /*{\Mop adds |S = set [first,last)| to the underlying set of points. If any point |S[i]| is equal to (the point associated with) a vertex of the current hull its associated point is changed to |S[i]|.}*/ bool is_dimension_jump(const Point_d& x) const /*{\Mop returns true if $x$ is not contained in the affine hull of |S|.}*/ { if (current_dimension() == dimension()) return false; typename R::Contained_in_affine_hull_d contained_in_affine_hull = kernel().contained_in_affine_hull_d_object(); return ( !contained_in_affine_hull(origin_simplex_->points_begin(), origin_simplex_->points_begin()+current_dimension()+1,x) ); } std::list facets_visible_from(const Point_d& x); /*{\Mop returns the list of all facets that are visible from |x|.\\ \precond |x| is contained in the affine hull of |S|.}*/ Bounded_side bounded_side(const Point_d& x); /*{\Mop returns |ON_BOUNDED_SIDE| (|ON_BOUNDARY|,|ON_UNBOUNDED_SIDE|) if |x| is contained in the interior (lies on the boundary, is contained in the exterior) of |\Mvar|. \precond |x| is contained in the affine hull of |S|.}*/ bool is_unbounded_simplex(Simplex_handle S) const { return vertex_of_simplex(S,0) == anti_origin_; } bool is_unbounded_simplex(Simplex_const_handle S) const { return vertex_of_simplex(S,0) == anti_origin_; } bool is_bounded_simplex(Simplex_handle S) const { return vertex_of_simplex(S,0) != anti_origin_; } bool is_bounded_simplex(Simplex_const_handle S) const { return vertex_of_simplex(S,0) != anti_origin_; } void clear(int d) /*{\Mop reinitializes |\Mvar| to an empty hull in $d$-dimensional space.}*/ { typename R::Construct_vector_d create = kernel().construct_vector_d_object(); quasi_center_ = create(d,NULL_VECTOR); anti_origin_ = Vertex_handle(); origin_simplex_ = Simplex_handle(); all_pnts_.clear(); Base::clear(d); num_of_vertices = 0; num_of_unbounded_simplices = num_of_bounded_simplices = 0; num_of_visibility_tests = 0; } std::size_t number_of_vertices() const /*{\Mop returns the number of vertices of |\Mvar|.}*/ { return num_of_vertices; } std::size_t number_of_facets() const /*{\Mop returns the number of facets of |\Mvar|.}*/ { return num_of_unbounded_simplices; } std::size_t number_of_simplices() const /*{\Mop returns the number of bounded simplices of |\Mvar|.}*/ { return num_of_bounded_simplices; } void print_statistics() /*{\Mop gives information about the size of the current hull and the number of visibility tests performed.}*/ { std::cout << "Convex_hull_d (" << current_dimension() << "/" << dimension() << ") - statistic" << std::endl; std::cout<<" # points = " << all_pnts_.size() << std::endl; std::cout<<" # vertices = " << num_of_vertices << std::endl; std::cout<<" # unbounded simplices = " << num_of_unbounded_simplices << std::endl; std::cout<<" # bounded simplices = " << num_of_bounded_simplices << std::endl; std::cout<<" # visibility tests = " << num_of_visibility_tests << std::endl; } class chull_has_double_coverage {}; class chull_has_local_non_convexity {}; class chull_has_center_on_wrong_side_of_hull_facet {}; bool is_valid(bool throw_exceptions = false) const; /*{\Mop checks the validity of the data structure. If |throw_exceptions == thrue| then the program throws the following exceptions to inform about the problem.\\ [[chull_has_center_on_wrong_side_of_hull_facet]] the hyperplane supporting a facet has the wrong orientation.\\ [[chull_has_local_non_convexity]] a ridge is locally non convex.\\ [[chull_has_double_coverage]] the hull has a winding number larger than 1. }*/ template void initialize(Forward_iterator first, Forward_iterator last) /*{\Xop initializes the complex with the set |S = set [first,last)|. The initialization uses the quickhull approach.}*/ { CGAL_assertion(current_dimension()==-1); Vertex_handle z; Forward_iterator it(first); std::list< Point_d > OtherPoints; typename std::list< Point_d >::iterator pit, pred; while ( it != last ) { Point_d x = *it++; if ( current_dimension() == -1 ) { Simplex_handle outer_simplex; // a pointer to the outer simplex dcur = 0; // we jump from dimension - 1 to dimension 0 origin_simplex_ = new_simplex(); num_of_bounded_simplices ++; outer_simplex = new_simplex(); num_of_unbounded_simplices ++; start_facet_ = origin_simplex_; z = new_vertex(x); num_of_vertices ++; associate_vertex_with_simplex(origin_simplex_,0,z); // z is the only point and the peak associate_vertex_with_simplex(outer_simplex,0,anti_origin_); set_neighbor(origin_simplex_,0,outer_simplex,0); typename R::Point_to_vector_d to_vector = kernel().point_to_vector_d_object(); quasi_center_ = to_vector(x); } else if ( is_dimension_jump(x) ) { dcur++; z = new_vertex(x); num_of_vertices++; typename R::Point_to_vector_d to_vector = kernel().point_to_vector_d_object(); quasi_center_ = quasi_center_ + to_vector(x); dimension_jump(origin_simplex_, z); clear_visited_marks(origin_simplex_); Simplex_iterator S; forall_rc_simplices(S,*this) compute_equation_of_base_facet(S); num_of_unbounded_simplices += num_of_bounded_simplices; if (dcur > 1) { start_facet_ = opposite_simplex(origin_simplex_,dcur); CGAL_assertion(vertex_of_simplex(start_facet_,0)==Vertex_handle()); } } else { OtherPoints.push_back(x); } } all_pnts_.insert(all_pnts_.end(),first,last); // what is the point of this line? ... //int dcur = current_dimension(); Unique_hash_map > PointsOf; std::list FacetCandidates; typename R::Oriented_side_d side_of = kernel().oriented_side_d_object(); for (int i=0; i<=dcur; ++i) { Simplex_handle f = opposite_simplex(origin_simplex_,i); Hyperplane_d h = f->hyperplane_of_base_facet(); std::list& L = PointsOf[f]; pit = OtherPoints.begin(); while ( pit != OtherPoints.end() ) { if ( side_of(h,*pit) == ON_POSITIVE_SIDE ) { L.push_back(*pit); pred=pit; ++pit; OtherPoints.erase(pred); } else ++pit; // not above h } if ( !L.empty() ) FacetCandidates.push_back(f); } OtherPoints.clear(); while ( !FacetCandidates.empty() ) { Facet_handle f = *FacetCandidates.begin(); FacetCandidates.pop_front(); Hyperplane_d h = f->hyperplane_of_base_facet(); std::list& L = PointsOf[f]; if (L.empty()) { CGAL_assertion( is_bounded_simplex(f) ); continue; } Point_d p = *L.begin(); typename R::Value_at_d value_at = kernel().value_at_d_object(); RT maxdist = value_at(h,p), dist; for (pit = ++L.begin(); pit != L.end(); ++pit) { dist = value_at(h,*pit); if ( dist > maxdist ) { maxdist = dist; p = *pit; } } num_of_visibility_tests += L.size(); std::size_t num_of_visited_facets = 0; std::list VisibleFacets; VisibleFacets.push_back(f); visible_facets_search(f, p, VisibleFacets, num_of_visited_facets); num_of_visibility_tests += num_of_visited_facets; num_of_bounded_simplices += VisibleFacets.size(); clear_visited_marks(f); ++num_of_vertices; Vertex_handle z = new_vertex(p); std::list NewSimplices; typename std::list::iterator it; CGAL_assertion(OtherPoints.empty()); for (it = VisibleFacets.begin(); it != VisibleFacets.end(); ++it) { OtherPoints.splice(OtherPoints.end(),PointsOf[*it]); Facet_handle S = *it; associate_vertex_with_simplex(S,0,z); for (int k = 1; k <= dcur; ++k) { if (!is_base_facet_visible(opposite_simplex(S,k),p)) { Simplex_handle T = new_simplex(); NewSimplices.push_back(T); /* set the vertices of T as described above */ for (int i = 1; i < dcur; i++) { if ( i != k ) associate_vertex_with_simplex(T,i,vertex_of_simplex(S,i)); } if (k != dcur) associate_vertex_with_simplex(T,k,vertex_of_simplex(S,dcur)); associate_vertex_with_simplex(T,dcur,z); associate_vertex_with_simplex(T,0,anti_origin_); /* in the above, it is tempting to drop the tests ( i != k ) and ( k != dcur ) since the subsequent lines after will correct the erroneous assignment. This reasoning is fallacious as the procedure assoc_vertex_with_simplex also the internal data of the third argument. */ /* compute the equation of its base facet */ compute_equation_of_base_facet(T); /* record adjacency information for the two known neighbors */ set_neighbor(T,dcur,opposite_simplex(S,k), index_of_vertex_in_opposite_simplex(S,k)); set_neighbor(T,0,S,k); } } } num_of_unbounded_simplices -= VisibleFacets.size(); if ( vertex_of_simplex(start_facet_,0) != Vertex_handle() ) start_facet_ = *(--NewSimplices.end()); CGAL_assertion( vertex_of_simplex(start_facet_,0)==Vertex_handle() ); for (it = NewSimplices.begin(); it != NewSimplices.end(); ++it) { Simplex_handle Af = *it; for (int k = 1; k < dcur ; k++) { // neighbors 0 and dcur are already known if (opposite_simplex(Af,k) == Simplex_handle()) { // we have not performed the walk in the opposite direction yet Simplex_handle T = opposite_simplex(Af,0); int y1 = 0; while ( vertex_of_simplex(T,y1) != vertex_of_simplex(Af,k) ) y1++; // exercise: show that we can also start with y1 = 1 int y2 = index_of_vertex_in_opposite_simplex(Af,0); while ( vertex_of_simplex(T,0) == z ) { // while T has peak x do find new y_1 */ int new_y1 = 0; while (vertex_of_simplex(opposite_simplex(T,y1),new_y1) != vertex_of_simplex(T,y2)) new_y1++; // exercise: show that we can also start with new_y1 = 1 y2 = index_of_vertex_in_opposite_simplex(T,y1); T = opposite_simplex(T,y1); y1 = new_y1; } set_neighbor(Af,k,T,y1); // update adjacency information } } } for (it = NewSimplices.begin(); it != NewSimplices.end(); ++it) { Facet_handle f = *it; CGAL_assertion( is_unbounded_simplex(f) ); Hyperplane_d h = f->hyperplane_of_base_facet(); std::list& L = PointsOf[f]; pit = OtherPoints.begin(); while ( pit != OtherPoints.end() ) { if ( side_of(h,*pit) == ON_POSITIVE_SIDE ) { L.push_back(*pit); pred=pit; ++pit; OtherPoints.erase(pred); } else ++pit; // not above h } if ( !L.empty() ) FacetCandidates.push_back(f); } OtherPoints.clear(); } #ifdef CGAL_CHECK_EXPENSIVE CGAL_assertion(is_valid(true)); #endif } /*{\Mtext \headerline{Lists and Iterators} \setopdims{3.5cm}{3.5cm}}*/ Vertex_iterator vertices_begin() { return Base::vertices_begin(); } /*{\Mop returns an iterator to start iteration over all vertices of |\Mvar|.}*/ Vertex_iterator vertices_end() { return Base::vertices_end(); } /*{\Mop the past the end iterator for vertices.}*/ Simplex_iterator simplices_begin() { return Base::simplices_begin(); } /*{\Mop returns an iterator to start iteration over all simplices of |\Mvar|.}*/ Simplex_iterator simplices_end() { return Base::simplices_end(); } /*{\Mop the past the end iterator for simplices.}*/ Facet_iterator facets_begin() { return Facet_iterator(this,start_facet_); } /*{\Mop returns an iterator to start iteration over all facets of |\Mvar|.}*/ Facet_iterator facets_end() { return Facet_iterator(); } /*{\Mop the past the end iterator for facets.}*/ Hull_vertex_iterator hull_vertices_begin() { return Hull_vertex_iterator(this,facets_begin()); } /*{\Mop returns an iterator to start iteration over all hull vertex of |\Mvar|. Remember that the hull is a simplicial complex.}*/ Hull_vertex_iterator hull_vertices_end() { return Hull_vertex_iterator(); } /*{\Mop the past the end iterator for hull vertices.}*/ Point_const_iterator points_begin() const { return all_pnts_.begin(); } /*{\Mop returns the start iterator for all points that have been inserted to construct |\Mvar|.}*/ Point_const_iterator points_end() const { return all_pnts_.end(); } /*{\Mop returns the past the end iterator for all points.}*/ Hull_point_const_iterator hull_points_begin() const { return Hull_point_const_iterator(hull_vertices_begin()); } /*{\Mop returns an iterator to start iteration over all inserted points that are part of the convex hull |\Mvar|. Remember that the hull is a simplicial complex.}*/ Hull_point_const_iterator hull_points_end() const { return Hull_point_const_iterator(hull_vertices_end()); } /*{\Mop returns the past the end iterator for points of the hull.}*/ Vertex_const_iterator vertices_begin() const { return Base::vertices_begin(); } Vertex_const_iterator vertices_end() const { return Base::vertices_end(); } Simplex_const_iterator simplices_begin() const { return Base::simplices_begin(); } Simplex_const_iterator simplices_end() const { return Base::simplices_end(); } Facet_const_iterator facets_begin() const { return Facet_const_iterator(this,start_facet_); } Facet_const_iterator facets_end() const { return Facet_const_iterator(); } Hull_vertex_const_iterator hull_vertices_begin() const { return Hull_vertex_const_iterator(this,facets_begin()); } Hull_vertex_const_iterator hull_vertices_end() const { return Hull_vertex_const_iterator(); } /* We distinguish cases according to the current dimension. If the dimension is less than one then the hull has no facets, if the dimension is one then the hull has two facets which we extract by a scan through the set of all simplices, and if the hull has dimension at least two the boundary is a connected set and we construct the list of facets by depth first search starting at |start_facet_|.*/ /*{\Mtext\setopdims{5.5cm}{3.5cm}}*/ template void visit_all_facets(const Visitor& V) const /*{\Mop each facet of |\Mvar| is visited by the visitor object |V|. |V| has to have a function call operator:\\ |void operator()(Facet_handle) const|}*/ { if (current_dimension() > 1) { Unique_hash_map visited(false); std::list candidates; candidates.push_back(start_facet_); visited[start_facet_] = true; Facet_handle current; while ( !candidates.empty() ) { current = *(candidates.begin()); candidates.pop_front(); CGAL_assertion(vertex_of_simplex(current,0)==Vertex_handle()); V(current); for(int i = 1; i <= dcur; ++i) { Facet_handle f = opposite_simplex(current,i); if ( !visited[f] ) { candidates.push_back(f); visited[f] = true; } } } } else if ( current_dimension() == 1 ) { V(start_facet_); } } const std::list& all_points() const /*{\Mop returns a list of all points in |\Mvar|.}*/ { return all_pnts_; } std::list all_vertices() /*{\Mop returns a list of all vertices of |\Mvar| (also interior ones).}*/ { return Base::all_vertices(); } std::list all_vertices() const { return Base::all_vertices(); } std::list all_simplices() /*{\Mop returns a list of all simplices in |\Mvar|.}*/ { return Base::all_simplices(); } std::list all_simplices() const { return Base::all_simplices(); } std::list all_facets() /*{\Mop returns a list of all facets of |\Mvar|.}*/ { std::list L; list_collector visitor(L); visit_all_facets(visitor); return L; } std::list all_facets() const { std::list L; list_collector visitor(L); visit_all_facets(visitor); return L; } #define forall_ch_vertices(x,CH)\ for(x = (CH).vertices_begin(); x != (CH).vertices_end(); ++x) #define forall_ch_simplices(x,CH)\ for(x = (CH).simplices_begin(); x != (CH).simplices_end(); ++x) #define forall_ch_facets(x,CH)\ for(x = (CH).facets_begin(); x != (CH).facets_end(); ++x) /*{\Mtext \headerline{Iteration Statements} {\bf forall\_ch\_vertices}($v,C$) $\{$ ``the vertices of $C$ are successively assigned to $v$'' $\}$ {\bf forall\_ch\_simplices}($s,C$) $\{$ ``the simplices of $C$ are successively assigned to $s$'' $\}$ {\bf forall\_ch\_facets}($f,C$) $\{$ ``the facets of $C$ are successively assigned to $f$'' $\}$ }*/ /*{\Mimplementation The implementation of type |\Mtype| is based on \cgalCite{cms:fourresults} and \cgalCite{BMS:degeneracy}. The details of the implementation can be found in the implementation document available at the download site of this package. The time and space requirements are input dependent. Let $C_1$, $C_2$, $C_3$, \ldots be the sequence of hulls constructed and for a point $x$ let $k_i$ be the number of facets of $C_i$ that are visible from $x$ and that are not already facets of $C_{i-1}$. Then the time for inserting $x$ is $O(|dim| \sum_i k_i)$ and the number of new simplices constructed during the insertion of $x$ is the number of facets of the hull which were not already facets of the hull before the insertion. The data type |\Mtype| is derived from |Regular_complex_d|. The space requirement of regular complexes is essentially $12(|dim| +2)$ bytes times the number of simplices plus the space for the points. |\Mtype| needs an additional $8 + (4 + x)|dim|$ bytes per simplex where $x$ is the space requirement of the underlying number type and an additional $12$ bytes per point. The total is therefore $(16 + x)|dim| + 32$ bytes times the number of simplices plus $28 + x \cdot |dim|$ bytes times the number of points.}*/ /*{\Mtext\headerline{Traits requirements} |\Mname| requires the following types from the kernel traits |R|: \begin{Mverb} Point_d Vector_d Ray_d Hyperplane_d \end{Mverb} and uses the following function objects from the kernel traits: \begin{Mverb} Construct_vector_d Construct_hyperplane_d Vector_to_point_d / Point_to_vector_d Orientation_d Orthogonal_vector_d Oriented_side_d / Has_on_positive_side_d Affinely_independent_d Contained_in_simplex_d Contained_in_affine_hull_d Intersect_d \end{Mverb} }*/ }; // Convex_hull_d template Convex_hull_d::Convex_hull_d(int d, const R& Kernel) : Base(d,Kernel) { origin_simplex_ = Simplex_handle(); start_facet_ = Facet_handle(); anti_origin_ = Vertex_handle(); num_of_vertices = 0; num_of_unbounded_simplices = num_of_bounded_simplices = 0; num_of_visibility_tests = 0; typename R::Construct_vector_d create = kernel().construct_vector_d_object(); quasi_center_ = create(d,NULL_VECTOR); } template bool Convex_hull_d:: contains_in_base_facet(Simplex_handle s, const Point_d& x) const { typename R::Contained_in_simplex_d contained_in_simplex = kernel().contained_in_simplex_d_object(); return contained_in_simplex(s->points_begin()+1, s->points_begin()+current_dimension()+1,x); } template void Convex_hull_d:: compute_equation_of_base_facet(Simplex_handle S) { typename R::Construct_hyperplane_d hyperplane_through_points = kernel().construct_hyperplane_d_object(); S->set_hyperplane_of_base_facet( hyperplane_through_points( S->points_begin()+1, S->points_begin()+1+current_dimension(), center(), ON_NEGATIVE_SIDE)); // skip the first point ! #ifdef CGAL_CHECK_EXPENSIVE { /* Let us check */ typename R::Oriented_side_d side = kernel().oriented_side_d_object(); for (int i = 1; i <= current_dimension(); i++) CGAL_assertion_msg(side(S->hyperplane_of_base_facet(), point_of_simplex(S,i)) == ON_ORIENTED_BOUNDARY, " hyperplane does not support base "); CGAL_assertion_msg(side(S->hyperplane_of_base_facet(),center()) == ON_NEGATIVE_SIDE, " hyperplane has quasi center on wrong side "); } #endif } template typename Convex_hull_d::Vertex_handle Convex_hull_d::insert(const Point_d& x) { Vertex_handle z = Vertex_handle(); all_pnts_.push_back(x); if (current_dimension() == -1) { Simplex_handle outer_simplex; // a pointer to the outer simplex dcur = 0; // we jump from dimension - 1 to dimension 0 origin_simplex_ = new_simplex(); num_of_bounded_simplices ++; outer_simplex = new_simplex(); num_of_unbounded_simplices ++; start_facet_ = origin_simplex_; z = new_vertex(x); num_of_vertices ++; associate_vertex_with_simplex(origin_simplex_,0,z); // z is the only point and the peak associate_vertex_with_simplex(outer_simplex,0,anti_origin_); set_neighbor(origin_simplex_,0,outer_simplex,0); typename R::Point_to_vector_d to_vector = kernel().point_to_vector_d_object(); quasi_center_ = to_vector(x); } else if ( is_dimension_jump(x) ) { dcur++; z = new_vertex(x); num_of_vertices++; typename R::Point_to_vector_d to_vector = kernel().point_to_vector_d_object(); quasi_center_ = quasi_center_ + to_vector(x); dimension_jump(origin_simplex_, z); clear_visited_marks(origin_simplex_); Simplex_iterator S; forall_rc_simplices(S,*this) compute_equation_of_base_facet(S); num_of_unbounded_simplices += num_of_bounded_simplices; if (dcur > 1) { start_facet_ = opposite_simplex(origin_simplex_,dcur); CGAL_assertion(vertex_of_simplex(start_facet_,0)==Vertex_handle()); } } else { if ( current_dimension() == 0 ) { z = vertex_of_simplex(origin_simplex_,0); associate_point_with_vertex(z,x); return z; } std::list visible_simplices; int location = -1; Facet_handle f; std::size_t num_of_visited_simplices = 0; visibility_search(origin_simplex_, x, visible_simplices, num_of_visited_simplices, location, f); num_of_visibility_tests += num_of_visited_simplices; #ifdef COUNTS cout << "\nthe number of visited simplices in this iteration is "; cout << num_of_visited_simplices << endl; #endif clear_visited_marks(origin_simplex_); #ifdef COUNTS cout << "\nthe number of bounded simplices constructed "; cout << " in this iteration is " << visible_simplices.size() << endl; #endif num_of_bounded_simplices += visible_simplices.size(); switch (location) { case -1: return Vertex_handle(); case 0: { for (int i = 0; i < current_dimension(); i++) { if ( x == point_of_facet(f,i) ) { z = vertex_of_facet(f,i); associate_point_with_vertex(z,x); return z; } } return Vertex_handle(); } case 1: { num_of_vertices++; z = new_vertex(x); std::list NewSimplices; // list of new simplices typename std::list::iterator it; for (it = visible_simplices.begin(); it != visible_simplices.end(); ++it) { Simplex_handle S = *it; associate_vertex_with_simplex(S,0,z); for (int k = 1; k <= dcur; k++) { if (!is_base_facet_visible(opposite_simplex(S,k),x)) { Simplex_handle T = new_simplex(); NewSimplices.push_back(T); /* set the vertices of T as described above */ for (int i = 1; i < dcur; i++) { if ( i != k ) associate_vertex_with_simplex(T,i,vertex_of_simplex(S,i)); } if (k != dcur) associate_vertex_with_simplex(T,k,vertex_of_simplex(S,dcur)); associate_vertex_with_simplex(T,dcur,z); associate_vertex_with_simplex(T,0,anti_origin_); /* in the above, it is tempting to drop the tests ( i != k ) and ( k != dcur ) since the subsequent lines after will correct the erroneous assignment. This reasoning is fallacious as the procedure assoc_vertex_with_simplex also the internal data of the third argument. */ /* compute the equation of its base facet */ compute_equation_of_base_facet(T); /* record adjacency information for the two known neighbors */ set_neighbor(T,dcur,opposite_simplex(S,k), index_of_vertex_in_opposite_simplex(S,k)); set_neighbor(T,0,S,k); } } } num_of_unbounded_simplices -= visible_simplices.size(); if ( vertex_of_simplex(start_facet_,0) != Vertex_handle() ) start_facet_ = *(--NewSimplices.end()); CGAL_assertion( vertex_of_simplex(start_facet_,0)==Vertex_handle() ); for (it = NewSimplices.begin(); it != NewSimplices.end(); ++it) { Simplex_handle Af = *it; for (int k = 1; k < dcur ; k++) { // neighbors 0 and dcur are already known if (opposite_simplex(Af,k) == Simplex_handle()) { // we have not performed the walk in the opposite direction yet Simplex_handle T = opposite_simplex(Af,0); int y1 = 0; while ( vertex_of_simplex(T,y1) != vertex_of_simplex(Af,k) ) y1++; // exercise: show that we can also start with y1 = 1 int y2 = index_of_vertex_in_opposite_simplex(Af,0); while ( vertex_of_simplex(T,0) == z ) { // while T has peak x do find new y_1 */ int new_y1 = 0; while (vertex_of_simplex(opposite_simplex(T,y1),new_y1) != vertex_of_simplex(T,y2)) new_y1++; // exercise: show that we can also start with new_y1 = 1 y2 = index_of_vertex_in_opposite_simplex(T,y1); T = opposite_simplex(T,y1); y1 = new_y1; } set_neighbor(Af,k,T,y1); // update adjacency information } } } } } } #ifdef CGAL_CHECK_EXPENSIVE CGAL_assertion(is_valid(true)); #endif return z; } template void Convex_hull_d:: visibility_search(Simplex_handle S, const Point_d& x, std::list< Simplex_handle >& visible_simplices, std::size_t& num_of_visited_simplices, int& location, Simplex_handle& f) const { num_of_visited_simplices ++; S->visited() = true; // we have visited S and never come back ... for(int i = 0; i <= current_dimension(); ++i) { Simplex_handle T = opposite_simplex(S,i); // for all neighbors T of S if ( !T->visited() ) { typename R::Oriented_side_d side_of = kernel().oriented_side_d_object(); int side = side_of(T->hyperplane_of_base_facet(),x); if ( is_unbounded_simplex(T) ) { if ( side == ON_POSITIVE_SIDE ) { // T is an unbounded simplex with x-visible base facet visible_simplices.push_back(T); location = 1; } if ( side == ON_ORIENTED_BOUNDARY && location == -1 && contains_in_base_facet(T,x) ) { location = 0; f = T; return; } } if ( side == ON_POSITIVE_SIDE || (side == ON_ORIENTED_BOUNDARY && location == -1) ) { visibility_search(T,x,visible_simplices, num_of_visited_simplices,location,f); // do the recursive search } } // end visited else { } } // end for } template void Convex_hull_d::clear_visited_marks(Simplex_handle S) const { S->visited() = false; // clear the visit - bit for(int i = 0; i <= current_dimension(); i++) // for all neighbors of S if (opposite_simplex(S,i)->visited()) // if the i - th neighbor has been visited clear_visited_marks(opposite_simplex(S,i)); // clear its bit recursively } template std::list< typename Convex_hull_d::Simplex_handle > Convex_hull_d::facets_visible_from(const Point_d& x) { std::list visible_simplices; int location = -1; // intialization is important std::size_t num_of_visited_simplices = 0; // irrelevant Facet_handle f; // irrelevant visibility_search(origin_simplex_, x, visible_simplices, num_of_visited_simplices, location, f); clear_visited_marks(origin_simplex_); return visible_simplices; } template Bounded_side Convex_hull_d::bounded_side(const Point_d& x) { if ( is_dimension_jump(x) ) return ON_UNBOUNDED_SIDE; std::list visible_simplices; int location = -1; // intialization is important std::size_t num_of_visited_simplices = 0; // irrelevant Facet_handle f; visibility_search(origin_simplex_, x, visible_simplices, num_of_visited_simplices, location, f); clear_visited_marks(origin_simplex_); switch (location) { case -1: return ON_BOUNDED_SIDE; case 0: return ON_BOUNDARY; case 1: return ON_UNBOUNDED_SIDE; } CGAL_error(); return ON_BOUNDARY; // never come here } template void Convex_hull_d:: dimension_jump(Simplex_handle S, Vertex_handle x) { Simplex_handle S_new; S->visited() = true; associate_vertex_with_simplex(S,dcur,x); if ( !is_unbounded_simplex(S) ) { // S is bounded S_new = new_simplex(); set_neighbor(S,dcur,S_new,0); associate_vertex_with_simplex(S_new,0,anti_origin_); for (int k = 1; k <= dcur; k++) { associate_vertex_with_simplex(S_new,k,vertex_of_simplex(S,k-1)); } } /* visit unvisited neighbors 0 to dcur - 1 */ for (int k = 0; k <= dcur - 1; k++) { if ( !opposite_simplex(S,k) -> visited() ) { dimension_jump(opposite_simplex(S,k), x); } } /* the recursive calls ensure that all neighbors exist */ if ( is_unbounded_simplex(S) ) { set_neighbor(S,dcur,opposite_simplex(opposite_simplex(S,0),dcur), index_of_vertex_in_opposite_simplex(S,0) + 1); } else { for (int k = 0; k < dcur; k++) { if ( is_unbounded_simplex(opposite_simplex(S,k)) ) { // if F' is unbounded set_neighbor(S_new,k + 1,opposite_simplex(S,k),dcur); // the neighbor of S_new opposite to v is S' and // x is in position dcur } else { // F' is bounded set_neighbor(S_new,k + 1,opposite_simplex(opposite_simplex(S,k),dcur), index_of_vertex_in_opposite_simplex(S,k) + 1); // neighbor of S_new opposite to v is S_new' // the vertex opposite to v remains the same but ... // remember the shifting of the vertices one step to the right } } } } template bool Convex_hull_d::is_valid(bool throw_exceptions) const { this->check_topology(); if (current_dimension() < 1) return true; /* Recall that center() gives us the center-point of the origin simplex. We check whether it is locally inside with respect to all hull facets. */ typename R::Oriented_side_d side = kernel().oriented_side_d_object(); Point_d centerpoint = center(); Simplex_const_iterator S; forall_rc_simplices(S,*this) { if ( is_unbounded_simplex(S) && side(S->hyperplane_of_base_facet(),centerpoint) != ON_NEGATIVE_SIDE) { if (throw_exceptions) throw chull_has_center_on_wrong_side_of_hull_facet(); return false; } } /* next we check convexity at every ridge. Let |S| be any hull simplex and let |v| be any vertex of its base facet. The vertex opposite to |v| must not be on the positive side of the base facet.*/ forall_rc_simplices(S,*this) { if ( is_unbounded_simplex(S) ) { for (int i = 1; i <= dcur; i++) { int k = index_of_vertex_in_opposite_simplex(S,i); if (side(S->hyperplane_of_base_facet(), point_of_simplex(opposite_simplex(S,i),k)) == ON_POSITIVE_SIDE) { if (throw_exceptions) throw chull_has_local_non_convexity(); return false; } } } } /* next we select one hull facet */ Simplex_const_handle selected_hull_simplex; forall_rc_simplices(S,*this) { if ( is_unbounded_simplex(S) ) { selected_hull_simplex = S; break; } } /* we compute the center of gravity of the base facet of the hull simplex */ typename R::Point_to_vector_d to_vector = kernel().point_to_vector_d_object(); typename R::Vector_to_point_d to_point = kernel().vector_to_point_d_object(); typename R::Construct_vector_d create = kernel().construct_vector_d_object(); Vector_d center_of_hull_facet = create(dimension(),NULL_VECTOR); for (int i = 1; i <= current_dimension(); i++) { center_of_hull_facet = center_of_hull_facet + to_vector(point_of_simplex(selected_hull_simplex,i)); } Point_d center_of_hull_facet_point = to_point(center_of_hull_facet/RT(dcur)); /* we set up the ray from the center to the center of the hull facet */ Ray_d l(centerpoint, center_of_hull_facet_point); /* and check whether it intersects the interior of any hull facet */ typename R::Contained_in_simplex_d contained_in_simplex = kernel().contained_in_simplex_d_object(); typename R::Intersect_d intersect = kernel().intersect_d_object(); forall_rc_simplices(S,*this) { if ( is_unbounded_simplex(S) && S != selected_hull_simplex ) { Point_d p; Object op; Hyperplane_d h = S->hyperplane_of_base_facet(); if ( (op = intersect(l,h), assign(p,op)) ) { if ( contained_in_simplex(S->points_begin()+1, S->points_begin()+1+current_dimension(),p) ) { if ( throw_exceptions ) throw chull_has_double_coverage(); return false; } } } } return true; } template void Convex_hull_d:: visible_facets_search(Simplex_handle S, const Point_d& x, std::list< Facet_handle >& VisibleFacets, std::size_t& num_of_visited_facets) const { ++num_of_visited_facets; S->visited() = true; // we have visited S and never come back ... for(int i = 1; i <= current_dimension(); ++i) { Simplex_handle T = opposite_simplex(S,i); // for all neighbors T of S if ( !T->visited() ) { typename R::Oriented_side_d side_of = kernel().oriented_side_d_object(); int side = side_of(T->hyperplane_of_base_facet(),x); CGAL_assertion( is_unbounded_simplex(T) ); if ( side == ON_POSITIVE_SIDE ) { VisibleFacets.push_back(T); visible_facets_search(T,x,VisibleFacets,num_of_visited_facets); // do the recursive search } } // end visited } // end for } } //namespace CGAL #endif // CGAL_CONVEX_HULL_D_H