// Copyright (c) 1997-2000 ETH Zurich (Switzerland). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Polytope_distance_d/include/CGAL/Width_3.h $ // $Id: Width_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) : Thomas Herrmann, Lutz Kettner #ifndef CGAL_WIDTH_3_H #define CGAL_WIDTH_3_H #include #include #include #include #include #include #include #include #include #include namespace CGAL { template class Width_3 { // +----------------------------------------------------------------------+ // | Typedef Area | // +----------------------------------------------------------------------+ private: typedef Traits_ Traits; typedef typename Traits::Point_3 Point_3; typedef typename Traits::Vector_3 Vector_3; typedef typename Traits::Plane_3 Plane_3; typedef typename Traits::RT RT; // +----------------------------------------------------------------------+ // | Variable Declaration | // +----------------------------------------------------------------------+ private: //the current best plane coefficients: e1:Ax+By+Cz+1=0 // e2:Ax+By+Cz+D=0 RT A,B,C,D,K; // Width itself RT WNum,WDenom; // Planes and directions are derived from these variables // A list with all quadruples A/K, B/K, C/K, D/K std::vector< std::vector > allsolutions; // A list with all quadruples that give an optimal solution std::vector< std::vector > alloptimal; //The traits class object Traits tco; //The new origin to know how to translate back Point_3 neworigin; // +----------------------------------------------------------------------+ // | Access to Private Variables | // +----------------------------------------------------------------------+ public: void get_width_coefficients(RT& a, RT& b, RT& c, RT& d, RT& k) { d=-A*neworigin.hx()-B*neworigin.hy()-C*neworigin.hz()+D*neworigin.hw(); k=-A*neworigin.hx()-B*neworigin.hy()-C*neworigin.hz()+K*neworigin.hw(); a=A*neworigin.hw(); b=B*neworigin.hw(); c=C*neworigin.hw(); #ifdef GCD_COMPUTATION simplify_solution(a,b,c,d,k); #endif } void get_squared_width(RT& num, RT& denom) { num=WNum; denom=WDenom; } Vector_3 get_build_direction() { return tco.make_vector(A,B,C); } void get_width_planes(Plane_3& e1, Plane_3& e2) { RT a,b,c,d,k; get_width_coefficients(a,b,c,d,k); e1=tco.make_plane(a,b,c,d); e2=tco.make_plane(a,b,c,k); } void get_all_build_directions(std::vector& alldir) { typename std::vector< std::vector >::iterator it=alloptimal.begin(); RT a,b,c; while(it!=alloptimal.end()) { a=(*it)[0]; b=(*it)[1]; c=(*it)[2]; #ifdef GCD_COMPUTATION RT dummy1=0; RT dummy2=0; simplify_solution(a,b,c,dummy1,dummy2); #endif Vector_3 dir=tco.make_vector(a,b,c); alldir.push_back(dir); ++it; } } int get_number_of_optimal_solutions() { return int(alloptimal.size()); } int get_number_of_possible_solutions() { return int(allsolutions.size()); } void get_all_possible_solutions(std::vector< std::vector >& allsol) { allsol.clear(); typename std::vector< std::vector >::iterator it=allsolutions.begin(); while(it!=allsolutions.end()) { RT d=-((*it)[0])*neworigin.hx()-((*it)[1])*neworigin.hy() -((*it)[2])*neworigin.hz()+((*it)[3])*neworigin.hw(); RT k=-((*it)[0])*neworigin.hx()-((*it)[1])*neworigin.hy() -((*it)[2])*neworigin.hz()+((*it)[4])*neworigin.hw(); RT a=((*it)[0])*neworigin.hw(); RT b=((*it)[1])*neworigin.hw(); RT c=((*it)[2])*neworigin.hw(); #ifdef GCD_COMPUTATION simplify_solution(a,b,c,d,k); #endif std::vector sol; sol.push_back(a); sol.push_back(b); sol.push_back(c); sol.push_back(d); sol.push_back(k); allsol.push_back(sol); ++it; } } // +----------------------------------------------------------------------+ // | The Con- and Destructors | // +----------------------------------------------------------------------+ public: Width_3(): A(0), B(0), C(0), D(2), K(1), WNum(0), WDenom(1) {} template Width_3( InputIterator begin, InputIterator beyond): A(0), B(0), C(0), D(2), K(1), WNum(0), WDenom(1) { INFOMSG(INFO,"Waiting for new HDS to build class Width_Polyhedron!" < LocalPolyhedron; LocalPolyhedron P; convex_hull_3( begin, beyond, P, CHT()); width_3_convex(P); } template Width_3(InputPolyhedron& Poly): A(0), B(0), C(0), D(2), K(1), WNum(0), WDenom(1) { // Compute convex hull with new width_polyhedron structure INFOMSG(INFO,"Working with extern additional data structures."); width_3_convex(Poly); } ~Width_3() { allsolutions.clear(); alloptimal.clear(); } // +----------------------------------------------------------------------+ // | Begin of private function area | // +----------------------------------------------------------------------+ private: // Just to remember: // E1: -axh - byh - czh - kwh <= 0 axh + byh + czh + kwh >= 0 // E2: axh + byh + czh + dwh <= 0 // VF-pair: 3xE1 + 1xE2 // EE-pair: 2xE1 + 2xE2 // plane equation in facets: Ax + By + Cz + 1 = 0 // ax + by + cz + k = 0 (A=a/k,...) //----------------------------- //---Combinatorial functions--- //----------------------------- // *** PREPARATION_CHECK *** //--------------------------- //This function determines the next facet if the halfedge e is a //valable halfedge over which we can rotate. If so fnext is returned. //PRECONDITION: e is the LAST edge in the go_on or impassable list! template bool preparation_check(InputDA& dao, Halfedge_handle_& e, Facet_handle_& fnext, std::vector& go_on, std::vector& imp) { //If the halfedge flag impassable is set then we can pop e from the stack //of the possibale go_on edges DEBUGMSG(PREPARATION_CHECK,"\nBegin PREPARATION_CHECK"); DEBUGENDL(PREPARATION_CHECK,"Edge e: "<opposite()->vertex()->point() <<" --> ",e->vertex()->point()); CGAL_precondition(go_on.back()==e); DEBUGMSG(ASSERTION_OUTPUT,"e is last element on stack go_on. " <<"ASSERTION OK."); if ( dao.is_impassable(e) ) { DEBUGMSG(PREPARATION_CHECK," is impassable. Erase from go_on."); go_on.pop_back(); DEBUGMSG(PREPARATION_CHECK,"End PREPARATION_CHECK"); return false; } else { //If the opposite halfedge of e is already visited, then we insert //e in the impassable list an pop e from the stack of the go_on edges typename InputDA::Halfedge_handle h=e->opposite(); if(dao.is_visited(h)) { DEBUGMSG(PREPARATION_CHECK," has a visited opposite edge. Set " <<"impassable flag, push on impassable stack and erase" <<" from go_on"); imp.push_back(e); dao.set_impassable_flag(h,true); go_on.pop_back(); DEBUGMSG(PREPARATION_CHECK,"End PREPARATION_CHECK"); return false; } else { DEBUGMSG(PREPARATION_CHECK," is a valable candidate. Compute next " <<"facet and erase from go_on. Set visited flag of all to " <<"fnext incident edges."); //e is a valable candidate. Thus set fnext to the next facet we visit fnext=h->facet(); //Delete e from go_on and insert the edges of fnext (except opposite //of e) in the go_on list go_on.pop_back(); typename InputDA::Halfedge_handle h0=h; h=h->next(); while ( h!=h0) { DEBUGENDL(PREPARATION_CHECK,"Adding edge to go_on stack: ", h->opposite()->vertex()->point()<<" --> " <vertex()->point()); go_on.push_back(h); dao.set_visited_flag(h,true); h=h->next(); } DEBUGMSG(PREPARATION_CHECK,"End PREPARATION_CHECK"); return true; } } } // *** NEIGHBORS_OF *** //---------------------- //To compute the neighbors of a vertex. The vertex is implicitely given //as the vertex the halfedge points to. template void neighbors_of(const Halfedge_handle_& h, std::vector& V) { DEBUGMSG(NEIGHBORS_OF,"\nBegin NEIGHBORS_OF"); DEBUGENDL(NEIGHBORS_OF,"Determining the neighbors of: ", h->vertex()->point()); Halfedge_handle_ e=h; Halfedge_handle_ e0=e->opposite(); V.clear(); V.push_back(e0->vertex()); e=e->next(); //Now go around the vertex and store the neighbor vertices while ( e!=e0 ) { V.push_back(e->vertex()); e=e->opposite()->next(); } #if NEIGHBORS_OF typename std::vector::iterator vtxit=V.begin(); while(vtxit!=V.end()) { DEBUGENDL(NEIGHBORS_OF,"Neighbor: ",(*vtxit)->point()); ++vtxit; } #endif DEBUGMSG(NEIGHBORS_OF,"End NEIGHBORS_OF"); } //During the algorithm we have to build union and minus set //of two sets and check wheater two sets are cutting each othe ror not // *** SETMINUS *** //------------------ //Builds the set A\B where the set A is changed template void setminus(std::vector& res, const std::vector& without) { DEBUGMSG(SETMINUS,"\nBegin SETMINUS"); typename std::vector::iterator resit; typename std::vector::const_iterator withoutit=without.begin(); //Scan through all elements of without and check if they are also in res. //If so delete the element from res. while(withoutit!=without.end()) { resit=std::find(res.begin(),res.end(),*withoutit); if ( resit!=res.end() ) { CGAL_assertion((*resit)->point()==(*withoutit)->point()); DEBUGMSG(ASSERTION_OUTPUT,"Found an element to erase. ASSERTION OK."); DEBUGENDL(SETMINUS,"Erase point: ",(*resit)->point()); res.erase(resit); } ++withoutit; } DEBUGMSG(SETMINUS,"End SETMINUS"); } // *** SETUNION *** //------------------ //Builds the union of two sets A and B. The result is stored in A //POSTCONDITION: Every element in A is stored once. template void setunion(std::vector&res, std::vector& uni) { DEBUGMSG(SETUNION,"\nBegin SETUNION"); typename std::vector::iterator uniit=uni.begin(); typename std::vector::iterator resit; //Scan the uni set and add every new element in res while(uniit!=uni.end()) { resit=std::find(res.begin(),res.end(),*uniit); if ( resit==res.end() ) { DEBUGENDL(SETUNION,"Insert new point: ",(*uniit)->point()); res.push_back(*uniit); } ++uniit; } DEBUGMSG(SETUNION,"End SETUNION"); } // *** SETCUT *** //---------------- //Checks if two sets are cutting each other or not (the common elements are //not determined template bool setcut(std::vector& AA, std::vector& BB) { DEBUGMSG(SETCUT,"\nBegin SETCUT"); typename std::vector::iterator Ait=AA.begin(); typename std::vector::iterator Bfindit; while(Ait!=AA.end()) { Bfindit=std::find(BB.begin(),BB.end(),*Ait); if (Bfindit!=BB.end()) { DEBUGMSG(SETCUT,"The sets are cutting each other. Return true."); DEBUGMSG(SETCUT,"End SETCUT"); return true; } ++Ait; } DEBUGMSG(SETCUT,"No common element detected. Return false"); DEBUGMSG(SETCUT,"End SETCUT"); return false; } // ---Numerical functions--- // ************************* // *** COMPUTE_PLANE_EQUATION *** //-------------------------------- //We don't take the standard plane equation computation from CGAL, //because in the context of the width the coefficients have to //satisfy a system of linear inequations. //PRECONDITION: (0,0,0) is strictly inside the convex hull //POSTCONDITION:(0,0,0) is on the positive side of the plane <==> the normal // vector of the plane points to the side where (0,0,0) lies template void compute_plane_equation(InputDA, const Facet_handle_& f) { DEBUGMSG(COMPUTE_PLANE_EQUATION,"\nBegin COMPUTE_PLANE_EQUATION"); DEBUGENDL(COMPUTE_PLANE_EQUATION,"Compute plane equations of facet f: (" <halfedge()->opposite()->vertex()->point()<<"), (", f->halfedge()->vertex()->point()<<"), (" <halfedge()->next()->vertex()->point()<<")"); typename InputDA::Halfedge_handle e = f->halfedge(); typename InputDA::PolyPoint p,q,r; q = e -> opposite() -> vertex() -> point(); p = e -> vertex() -> point(); r = e -> next() -> vertex() -> point(); CGAL_assertion(r!=p && r!=q && p!=q); DEBUGMSG(ASSERTION_OUTPUT,"There are 3 different points. ASSERTION OK."); RT a,b,c,k; solve_3x3(InputDA(),p,q,r,a,b,c,k); f->plane()=tco.make_plane(a,b,c,k); DEBUGENDL(COMPUTE_PLANE_EQUATION,"Plane Coefficients: ",f->plane()); DEBUGMSG(COMPUTE_PLANE_EQUATION,"End COMPUTE_PLANE_EQUATION"); } // *** SOLVE_3X3 *** //------------------- //To solve a special 3x3 system. The rows of the coefficient matrix //are the (homogeneous) x,y,z-coordinates of points and the right //hand side is the homogeneous part of the point times the provided //coefficient. The system is solved with Cramer's Rule. The sign of //the coefficients is chosen in a way that (0,0,0) lies on the positive //side of the plane. template void solve_3x3(InputDA, const PolyPoint_& p, const PolyPoint_& q, const PolyPoint_& r, RT& a, RT& b, RT& c, RT& k) { DEBUGMSG(SOLVE_3X3,"\nBegin SOLVE_3X3"); RT px,py,pz,ph; tco.get_point_coordinates(p,px,py,pz,ph); RT qx,qy,qz,qh; tco.get_point_coordinates(q,qx,qy,qz,qh); RT rx,ry,rz,rh; tco.get_point_coordinates(r,rx,ry,rz,rh); CGAL_assertion(ph>0 && qh>0 && rh>0); DEBUGMSG(ASSERTION_OUTPUT,"All homogeneous parts >0. ASSERTION OK."); DEBUGMSG(SOLVE_3X3,"Matrix:"); DEBUGENDL(SOLVE_3X3,"",px<<" "< bool solve_4x4(InputDA, const PolyPoint_& p, const PolyPoint_& q, const PolyPoint_& r, const PolyPoint_& v, RT& a, RT& b, RT& c, RT& d, RT& k) { DEBUGMSG(SOLVE_4X4,"\nBegin SOLVE_4X4"); RT px,py,pz,ph; tco.get_point_coordinates(p,px,py,pz,ph); RT qx,qy,qz,qh; tco.get_point_coordinates(q,qx,qy,qz,qh); RT rx,ry,rz,rh; tco.get_point_coordinates(r,rx,ry,rz,rh); RT vx,vy,vz,vh; tco.get_point_coordinates(v,vx,vy,vz,vh); CGAL_assertion(ph>0 && qh>0 && vh>0 && rh>0); DEBUGMSG(ASSERTION_OUTPUT,"All homogeneous parts >0. ASSERTION OK."); DEBUGMSG(SOLVE_4X4,"Matrix: "); DEBUGENDL(SOLVE_4X4,"",px<<" "<k) { DEBUGMSG(SOLVE_4X4,"d>k: Interchange d and k"); RT tmp=d; d=k; k=tmp; CGAL_assertion(a*px+b*py+c*pz+d*ph==0); CGAL_assertion(a*qx+b*qy+c*qz+d*qh==0); CGAL_assertion(a*rx+b*ry+c*rz+k*rh==0); CGAL_assertion(a*vx+b*vy+c*vz+k*vh==0); DEBUGMSG(ASSERTION_OUTPUT,"Interchanged k and d. All Assertions ok."); } if (a==0 && b==0 && c==0) { DEBUGENDL(SOLVE_4X4,"Solution of 4x4:\n ",a< bool check_feasibility(InputDA, const RT& a, const RT& b, const RT& c, const RT& d, const RT& k, const std::vector& V) { DEBUGMSG(CHECK_FEASIBILITY,"\nBegin CHECK_FEASIBILITY"); if (d==k) { DEBUGMSG(CHECK_FEASIBILITY,"The planes e1 and e2 are the same. " <<"Not a feasible solution."); DEBUGMSG(CHECK_FEASIBILITY,"End CHECK_FEASIBILITY"); return false; } typename std::vector::const_iterator it=V.begin(); RT tmp; while ( it!=V.end() ) { RT px,py,pz,ph; tco.get_point_coordinates((*it)->point(),px,py,pz,ph); tmp = a*px+b*py+c*pz; //Check if the restrictions according to p are satisfied if (tmp+k*ph < 0 || tmp + d*ph > 0) { #if CHECK_FEASIBILITY DEBUGENDL(CHECK_FEASIBILITY,"Restriction to point ", (*it)->point()<<" failed."); if (tmp+k*ph < 0){ DEBUGENDL(CHECK_FEASIBILITY,"E1 not satisfied: ",tmp+k*ph); } else { DEBUGENDL(CHECK_FEASIBILITY,"E2 not satisfied: ",tmp+d*ph); } #endif DEBUGMSG(CHECK_FEASIBILITY,"Feasibility Check failed."); DEBUGMSG(CHECK_FEASIBILITY,"End CHECK_FEASIBILITY"); return false; } ++it; } //All restrictions are satisfied, thus the check returns true DEBUGMSG(CHECK_FEASIBILITY,"Feasibility Check was successful."); DEBUGMSG(CHECK_FEASIBILITY,"End CHECK_FEASIBILITY"); return true; } #if GCD_COMPUTATION // *** GCD *** //------------- //To compute the gcd of 2 integer numbers //PRECONDITION: abs(IntNum) must be defined! // %-operator must be defined! template IntNum gcd(const IntNum& a, const IntNum& b) { DEBUGMSG(GCD_OUTPUT,"\nBegin GCD"); DEBUGENDL(GCD_OUTPUT,"Compute gcd of ",a<<" and "< void simplify_solution(IntNum& a, IntNum& b, IntNum& c, IntNum& d, IntNum& k) { DEBUGMSG(SIMPLIFY_SOLUTION,"\nBegin SIMPLIFY_SOLUTION"); IntNum r=gcd(a,b); IntNum s=gcd(c,d); IntNum t=gcd(r,s); IntNum g=gcd(t,k); CGAL_assertion(g*(a/g)==a); a=a/g; CGAL_assertion(g*(b/g)==b); b=b/g; CGAL_assertion(g*(c/g)==c); c=c/g; CGAL_assertion(g*(d/g)==d); d=d/g; CGAL_assertion(g*(k/g)==k); k=k/g; DEBUGENDL(SIMPLIFY_SOLUTION,"Simplified solutions: ",a<<" "< void initial_VF_pair(InputDA& dao, Facet_handle_& f, Polyhedron_& P, std::vector& go_on) { DEBUGMSG(INITIAL_VF_PAIR,"\nBegin INITIAL_VF_PAIR"); DEBUGENDL(INITIAL_VF_PAIR,"Compute initial VF-pair with facet f: (" <halfedge()->opposite()->vertex()->point()<<"), (", f->halfedge()->vertex()->point()<<"), (" <halfedge()->next()->vertex()->point()<<")"); typedef typename InputDA::Vertex_handle Vertex_handle; //Compute the facet. ==> e2 is fixed tco.get_plane_coefficients(f->plane(),A,B,C,K); CGAL_assertion(K>0); DEBUGMSG(ASSERTION_OUTPUT,"K greater (strictly) than 0. ASSERTION OK."); //Start with an impossible configuration for the still unknown //coefficient D=K, ie plane E1 == plane E2 D=K; DEBUGENDL(INITIAL_VF_PAIR,"Starting with values:\nA:",A< apv; #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || (!defined(CGAL_KERNEL_CHECK_EXPENSIVE) && !defined(CGAL_CHECK_EXPENSIVE))\ || defined(NDEBUG)) typename InputDA::Vertex_iterator vtxitass = P.vertices_begin(); while(vtxitass!=P.vertices_end()) { RT px,py,pz,ph; tco.get_point_coordinates((*vtxitass).point(),px,py,pz,ph); CGAL_expensive_assertion(ph>0); CGAL_expensive_assertion(A*px+B*py+C*pz+K*ph>=0); ++vtxitass; } DEBUGMSG(ASSERTION_OUTPUT,"All points satisfy restriction " <<"type E1. ASSERTION OK>"); #endif typename InputDA::Vertex_iterator vtxit=P.vertices_begin(); RT maxdist=0; RT hompart=1; //Try every point to be an/the antipodal vertex of the facet f. Take the //one with the bigest distance from E1 DEBUGENDL(INITIAL_VF_PAIR,"Plane E1:",f->plane()); while (vtxit != P.vertices_end() ) { RT pix, piy, piz, pih; tco.get_point_coordinates((*vtxit).point(),pix,piy,piz,pih); DEBUGENDL(INITIAL_VF_PAIR,"Try Point: ",(*vtxit).point()); //Compute the sign of the distance from pi to the current plane e2 RT distpie1=A*pix + B*piy + C*piz; DEBUGENDL(INITIAL_VF_PAIR,"Distance from p to current plane e1: ", distpie1*hompart); //If pi is not between e1 and e2, compute a new plane e2 through pi //If pi is also ON the current plane e2, then insert pi in the list //of current antipodal vertices of the facet f if (hompart*distpie1 >= pih*maxdist) { DEBUGMSG(INITIAL_VF_PAIR,"Distance of this point is greater (or equal)" <<" than all the distances before." <<"Change plane antipodal vertices."); if (hompart*distpie1 > pih*maxdist) { DEBUGMSG(INITIAL_VF_PAIR,"Compute new plane e2!"); apv.clear(); hompart=pih; maxdist=distpie1; } apv.push_back(vtxit); } ++vtxit; } A=A*hompart; B=B*hompart; C=C*hompart; D=-maxdist; K=K*hompart; #ifdef GCD_COMPUTATION simplify_solution(A,B,C,D,K); #endif DEBUGENDL(INITIAL_VF_PAIR,"Initial Plane E1: ",A<<" "<=0); CGAL_expensive_assertion(A*px+B*py+C*pz+D*ph<=0); DEBUGENDL(ASSERTION_OUTPUT,"Restriction values: E1:", A*px+B*py+C*pz+K*ph<<" and E2: "< sol; sol.push_back(A); sol.push_back(B); sol.push_back(C); sol.push_back(D); sol.push_back(K); allsolutions.push_back(sol); alloptimal.push_back(sol); //Compute the squared width with the determined coefficients WNum=(K-D)*(K-D); WDenom=A*A+B*B+C*C; DEBUGENDL(INITIAL_VF_PAIR,"Initial squared width: ", WNum<<"/"<halfedge(); go_on.push_back(e); dao.set_visited_flag(e,true); typename InputDA::Halfedge_handle e0 = e; e = e->next(); while ( e != e0 ) { go_on.push_back(e); dao.set_visited_flag(e,true); e=e->next(); } DEBUGMSG(INITIAL_VF_PAIR,"End INITIAL_VF_PAIR"); } // *** CHECK_ABOUT_VF_PAIRS *** //------------------------------ //This function checks if a facet and a subset of a given set of vertices //build a vertex facet pair template bool check_about_VF_pairs(InputDA& dao, Facet_handle_& f, const std::vector& V) { DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"\nBegin CHECK_ABOUT_VF_PAIRS"); DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"Check, if f has antipodal vertices in " <<"a set."); RT a,b,c,d,k; typename std::vector ::const_iterator vtxit=V.begin(); std::vector W; typename std::vector ::iterator neighborit; bool feasible=false; std::vector apv; std::vector visited_points; while (vtxit!=V.end()) { RT vx,vy,vz,vh; tco.get_point_coordinates((*vtxit)->point(),vx,vy,vz,vh); tco.get_plane_coefficients(f->plane(),a,b,c,k); //assume plane e2 parallel to e1 through v: e2:axh+byh+czh+d=0 d = -a*vx - b*vy - c*vz; CGAL_assertion(vh > 0); DEBUGMSG(ASSERTION_OUTPUT,"vh is greater than zero (strictly). " <<"ASSERTION OK."); a=tco.get_a(f->plane())*vh; b=tco.get_b(f->plane())*vh; c=tco.get_c(f->plane())*vh; k=tco.get_d(f->plane())*vh; CGAL_assertion(a*vx+b*vy+c*vz+k*vh>=0); CGAL_assertion(a*vx+b*vy+c*vz+d*vh==0); DEBUGMSG(ASSERTION_OUTPUT,"Checked: Point on the right side of e1, and " <<"on e2. ASSERTION OK>"); //If v lies on plane e1 then we can continue (v is not antipodal) if (d == k) { CGAL_assertion(a*vx+b*vy+c*vz+k*vh==0); DEBUGENDL(CHECK_ABOUT_VF_PAIRS,"Point "<<(*vtxit)->point() <<" lies on plane ",f->plane()<<". Continue."); ++vtxit; continue; } CGAL_assertion(a*vx+b*vy+c*vz+k*vh>0); DEBUGMSG(ASSERTION_OUTPUT,"v not on e1. ASSERTION OK."); //Else we look if we can find a witness in the neighborhood of v that //shows that v is not an antipodal vertex of f neighbors_of((*vtxit)->halfedge(),W); //Assume there is no witness for infeasibility feasible = true; //Scan all possible witnesses while(!W.empty()) { neighborit=W.begin(); visited_points.push_back(*neighborit); RT nx,ny,nz,nh; tco.get_point_coordinates((*neighborit)->point(),nx,ny,nz,nh); //Check if n (neighbor of v) satisfies restriction type e2 //with the presumed plane e2, ie anx+bny+cnz-Dv<=0 CGAL_assertion(a*nx+b*ny+c*nz+k*nh>=0); DEBUGMSG(ASSERTION_OUTPUT,"Restrictions E1 is satisfied. " <<"ASSERTION OK."); if ( a*nx+b*ny+c*nz+d*nh >= 0 ) { //Could be a violation. Now check if v and n lie on the //same plane. If so no violation, othervise we can break if (a*nx+b*ny+c*nz+d*nh == 0 ) { DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"Additional Antipodal Vertex " <<"found. Expanding "<<"set of witnesses."); //v and n are both (so far) antipodal vertices ==>EF-pair apv.push_back(*neighborit); //There could now be more witnesses that give violating //restrictions. Therefore compute the new neighbors of n std::vector Wnew; neighbors_of((*neighborit)->halfedge(),Wnew); //Erase v from the vertices to be considered as new witnesses typename std::vector ::iterator res= std::find(Wnew.begin(),Wnew.end(),*vtxit); if ( res!=Wnew.end() ) Wnew.erase(res); //Erase all the elements we already considered from the new //set of witnesses setminus(Wnew,visited_points); //Erase the neighbor vertex itself from the set of witnesses W.erase(neighborit); //Compute the new whole set of witnesses, that is add the //remaining new ones to the old set of witnesses setunion(W,Wnew); } else { DEBUGENDL(CHECK_ABOUT_VF_PAIRS,"Violation found. Not a feasible " <<"solution. Violated Point:",(*neighborit)->point()); //there is a violation, so do a break feasible = false; break; } } else { DEBUGENDL(CHECK_ABOUT_VF_PAIRS,"Restriction E2 also satisfied by " <<"point:",(*neighborit)->point()); //There is no violating restriction according to the vertex n //Erase it from the set of witnesses W.erase(neighborit); } } //end while(!W.empty()) //Now we can determine if we have a feasible solution or not. Because //the feasible flag can only be set to false during the while-loop //we can be sure of the feasibility of our solution (no witness found) //if feasible is false then we have found a witness that v is not an //antipodal vertex. So we go on in the list of possible antipodal //vertices otherwise. if (feasible == true) { DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"All witnesses checked. " <<"Update width and antipodal vertices. Return true"); apv.push_back(*vtxit); #ifdef GCD_COMPUTATION simplify_solution(a,b,c,d,k); #endif update_width(a,b,c,d,k); dao.set_antipodal_vertices(f,apv); #ifdef VF_PAIR_OUTPUT DEBUGENDL(VF_PAIR_OUTPUT,"Antipodal vertices of plane: ", f->plane()); typename std::vector::iterator cavfpit=apv.begin(); while(cavfpit!=apv.end()) { DEBUGENDL(VF_PAIR_OUTPUT,"Antipodal Vertex: ", (*cavfpit)->point()); ++cavfpit; } #endif DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"End CHECK_ABOUT_VF_PAIRS"); return true; } ++vtxit; }//end while(vtxit!=V.end()) //If we could not return with antipodal vertices we return false DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"No new VF-pair found. Return false."); DEBUGMSG(CHECK_ABOUT_VF_PAIRS,"End CHECK_ABOUT_VF_PAIRS"); return false; } // *** UPDATE_WIDTH *** //---------------------- //This function we use to update the current best width. The old width is //compared with a new provided one and the better solution will we taken //as the new width. This function also saves all the possible quadruples //to be the width of the point set. void update_width(RT& a, RT& b, RT& c, RT& d, RT& k) { //Update the list of all possible solutions DEBUGMSG(UPDATE_WIDTH,"\nBegin UPDATE_WIDTH"); std::vector sol; sol.push_back(a); sol.push_back(b); sol.push_back(c); sol.push_back(d); sol.push_back(k); allsolutions.push_back(sol); //Compute the squared width provided by the new solution RT tocompareNum=(k-d)*(k-d); RT tocompareDenom=(a*a+b*b+c*c); DEBUGENDL(UPDATE_WIDTH,"New possible width: ",tocompareNum <<" / "<= tocompareNum*WDenom) { if (WNum*tocompareDenom > tocompareNum*WDenom){ DEBUGMSG(UPDATE_WIDTH,"Optimal width changes"); WNum=tocompareNum; WDenom=tocompareDenom; alloptimal.clear(); alloptimal.push_back(sol); A=a; B=b; C=c; D=d; K=k; } else { //now we have an additional optimal solution alloptimal.push_back(sol); } }//end if equal or better width DEBUGMSG(UPDATE_WIDTH,"End UPDATE_WIDTH"); } // *** EE_COMPUTATION *** //------------------------ //During the 3rd phase of the width-algorithm we have to rotate planes to //enumerate all possible edge-edge pairs. This rotating (in primal context) //resp. tracking edges (in the dual context) is made by the following //function. The edge we rotate about is called e. To ensure only to //enumerate a pair once (...only going forward) we need a set of //already visited vertices (Visited) and a set of vertices from that we know //they are antipodal to the first facet (V). In this function we don't //know the antipodal vertices of the second facet. template void EE_computation(InputDA, Halfedge_handle_& e, std::vector& V, std::vector& Visited, std::vector& Nnew) { DEBUGMSG(EE_COMPUTATION,"\nBegin EE_COMPUTATION"); //Compute end points of e and two witnesses: Each in one of the two //facets participating Point_3 p,q; p=e->opposite()->vertex()->point(); q=e->vertex()->point(); typename InputDA::Vertex_handle w1=e->next()->vertex(); typename InputDA::Vertex_handle w2=e->opposite()->next()->vertex(); //prepare for the rotating procedure Nnew.clear(); typename std::vector ::iterator vtxit=V.begin(); //Consider all the vertices in V. EE-pairs consist of p,q and the //vertex v in V and another neighbor vertex of v while(vtxit != V.end() ) { std::vector R; neighbors_of((*vtxit)->halfedge(),R); std::vector Witnesses; //The set of witnesses are all neighbor vertices of v (=R) and the //two vertices "on the other side" that ensure not rotating too far Witnesses.push_back(w1); Witnesses.push_back(w2); setunion(Witnesses,R); //The neighbor vertices of v that are also in the basic set V are of no //interest, so we exclude them setminus(R,V); //The set of all vertices we have already visited is also of no interest setminus(R,Visited); typename std::vector ::iterator rit=R.begin(); //Now look at the modified set of neighbor vertices. For each neighbor r //we assume (p,q) and (v,r) to be an EE-pair and want then to find //witnesses that against this quadruple. If no such witness exist //(p,q) and (v,r) are a legal EE-pair. In that case we break the //quest and update all the sets Visited Nnew and V. If we have considered //all vertices v in V and all the respective r in R and if we have //not found a legal EE-pair, then an error occurs while (rit!=R.end()) { RT a,b,c,d,k; //It could be that the system is not uniquely solvable we only want to //enumerate proper solutions no degenerate ones if(solve_4x4(InputDA(),p,q,(*rit)->point(),(*vtxit)->point(), a,b,c,d,k)){ DEBUGMSG(EE_COMPUTATION,"Now we check if the provided " <<"solution is a feasible one."); #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || (!defined(CGAL_KERNEL_CHECK_EXPENSIVE) && !defined(CGAL_CHECK_EXPENSIVE))\ || defined(NDEBUG)) RT px,py,pz,ph; tco.get_point_coordinates(p,px,py,pz,ph); CGAL_expensive_assertion(a*px+b*py+c*pz+k*ph>=0); CGAL_expensive_assertion(a*px+b*py+c*pz+d*ph<=0); tco.get_point_coordinates(q,px,py,pz,ph); CGAL_expensive_assertion(a*px+b*py+c*pz+k*ph>=0); CGAL_expensive_assertion(a*px+b*py+c*pz+d*ph<=0); tco.get_point_coordinates((*rit)->point(),px,py,pz,ph); CGAL_expensive_assertion(a*px+b*py+c*pz+k*ph>=0); CGAL_expensive_assertion(a*px+b*py+c*pz+d*ph<=0); tco.get_point_coordinates((*vtxit)->point(),px,py,pz,ph); CGAL_expensive_assertion(a*px+b*py+c*pz+k*ph>=0); CGAL_expensive_assertion(a*px+b*py+c*pz+d*ph<=0); DEBUGMSG(ASSERTION_OUTPUT,"All restrictions to the 4 points " <<"are satisfied. ASSERTION OK."); #endif if (check_feasibility(InputDA(),a,b,c,d,k,Witnesses)) { DEBUGMSG(EE_COMPUTATION,"Update Width and compute all " <<"active restrictions"); //Therefore we update the width update_width(a,b,c,d,k); //The next region we consider (because we only go forward) //contains (at least) r Nnew.push_back(*rit); //Now we look if we are in a special case, that is we look if //other restrictions according to neighboring vertices of r //are also active. If so Nnew is expanded we them. std::vector S; neighbors_of((*rit)->halfedge(),S); //Because we only go forward we exclude v from the neighbor set S std::vector vtemp; vtemp.push_back(*vtxit); setminus(S,vtemp); //The check of more than 4 active restrictions begins typename std::vector ::iterator sit; while(!S.empty()) { sit=S.begin(); RT sx,sy,sz,sh; tco.get_point_coordinates((*sit)->point(),sx,sy,sz,sh); if (a*sx+b*sy+c*sz+d*sh==0) { //This special case occurs now. Thus we extend Nnew Nnew.push_back(*sit); //In the neighborhood of this new active vertex could //also be other new active vertices but we are only interested //in new ones std::vector T; neighbors_of((*sit)->halfedge(),T); S.erase(sit); setunion(S,T); T.clear(); T.push_back(*vtxit); setminus(S,T); setminus(S,Nnew); } else { //s is not active and we can erase it S.erase(sit); } } //end while (!S.empty()) //Since we have now enumerated all EE-pairs with the active //restrictions according to p,q and v we can now leave //Nnew contains now all new active restrictions DEBUGMSG(EE_COMPUTATION,"End EE_COMPUTATION"); return; } //end if (feasible) }//end if(proper) //Try next r ++rit; }//end while(!R.empty()) //Try new v ++vtxit; } //There must be a new EE-pair. If not, an error occurs std::cerr<<"No new EE-pair found!"< void EE_pairs(InputDA& dao, Halfedge_handle_& e, std::vector& impassable) { DEBUGMSG(EE_PAIRS,"\nBegin EE_PAIRS"); Point_3 p,q; p=e->opposite()->vertex()->point(); q=e->vertex()->point(); typename InputDA::Vertex_handle w1=e->next()->vertex(); typename InputDA::Vertex_handle w2=e->opposite()->next()->vertex(); typename InputDA::Facet_handle f1=e->facet(); typename InputDA::Facet_handle f2=e->opposite()->facet(); std::vector V1; std::vector V2; dao.get_antipodal_vertices(f1,V1); dao.get_antipodal_vertices(f2,V2); std::vector N,V,Visited; V=V1; bool do_break = false; while (!setcut(V,V2)) { do_break = false; typename std::vector ::iterator vtxit=V.begin(); std::vector R; while (vtxit!=V.end()) { neighbors_of((*vtxit)->halfedge(),R); std::vector Witnesses; Witnesses.push_back(w1); Witnesses.push_back(w2); setunion(Witnesses,R); setminus(R,V); setminus(R,Visited); typename std::vector ::iterator rit=R.begin(); while (rit!=R.end()) { RT a,b,c,d,k; //It could be that the system is not uniquely solvable we only want //to enumerate proper solutions no degenerate ones if(solve_4x4(InputDA(),p,q,(*rit)->point(),(*vtxit)->point(), a,b,c,d,k)){ if (check_feasibility(InputDA(),a,b,c,d,k,Witnesses)) { update_width(a,b,c,d,k); N.push_back(*rit); std::vector S; neighbors_of((*rit)->halfedge(),S); setminus(S,V); typename std::vector ::iterator sit; while(!S.empty()) { sit=S.begin(); RT sx,sy,sz,sh; tco.get_point_coordinates((*sit)->point(),sx,sy,sz,sh); if (a*sx+b*sy+c*sz+d*sh== 0) { N.push_back(*sit); std::vector T; neighbors_of((*sit)->halfedge(),T); S.erase(sit); setunion(S,T); T.clear(); T.push_back(*vtxit); setminus(S,T); setminus(S,N); } else { S.erase(sit); } }//end while (!S.empty()) do_break=true; break; }//if (feasible) }//if(proper) ++rit; }//end while(!R.empty()) if (do_break == true) break; ++vtxit; }//end while(!V.end()) setunion(Visited,V); V=N; } impassable.pop_back(); //Go on with next edge DEBUGMSG(EE_PAIRS,"End EE_PAIRS"); } // *** ORIGIN_INSIDE_CH *** //------------------------- // To ensure that zero lies completly inside the convex hull of a point set. // Returns true if the point set is not coplanar, false otherwise // PRECONDITION: Iterator range has at least 3 points template bool origin_inside_CH(Vertex_iterator_& start, Vertex_iterator_& beyond, InputDA){ DEBUGMSG(ORIGIN_INSIDE_CH,"\nBegin ORIGIN_INSIDE_CH"); typename InputDA::Vertex_iterator first=start; //Take 4 points that build a tetrahedron. This tetrahedron is also //contained in the convex hull of the points. Thus every point //in/on this tetrahedron is a valable point for a new origin typename InputDA::PolyPoint p,q,r,s; p=(*first).point(); ++first; q=(*first).point(); ++first; r=(*first).point(); ++first; RT px,py,pz,ph,qx,qy,qz,qh,rx,ry,rz,rh; tco.get_point_coordinates(p,px,py,pz,ph); tco.get_point_coordinates(q,qx,qy,qz,qh); tco.get_point_coordinates(r,rx,ry,rz,rh); CGAL_assertion(ph>0 && qh>0 && rh>0); RT tmpa,tmpb,tmpc,tmpk; tmpk=px*(qy*rz-ry*qz)-qx*(py*rz-ry*pz)+rx*(py*qz-qy*pz); tmpa=-ph*(qy*rz-ry*qz)+qh*(py*rz-ry*pz)-rh*(py*qz-qy*pz); tmpb=px*(rh*qz-qh*rz)-qx*(rh*pz-ph*rz)+rx*(qh*pz-ph*qz); tmpc=px*(ry*qh-qy*rh)-qx*(ry*ph-py*rh)+rx*(qy*ph-py*qh); #ifdef GCD_COMPUTATION RT dummy=0; DEBUGENDL(ORIGIN_INSIDE_CH,"Solution of 3x3 (before GCD " <<"computation):\n",tmpa< sol; sol.push_back(A); sol.push_back(B); sol.push_back(C); sol.push_back(D); sol.push_back(K); allsolutions.push_back(sol); alloptimal.push_back(sol); DEBUGMSG(ORIGIN_INSIDE_CH,"End ORIGIN_INSIDE_CH"); return false; } else { s=(*first).point(); RT sx,sy,sz,sh; tco.get_point_coordinates(s,sx,sy,sz,sh); //Ensure that the 4 points are not coplanar. If so take another 4th point while (tmpa*sx+tmpb*sy+tmpc*sz+tmpk*sh==0 && first!=beyond) { s=(*first).point(); tco.get_point_coordinates(s,sx,sy,sz,sh); ++first; } //If we could not find a valable 4th point, then the set of the points //is coplanar. Therefore the width is zero and we can terminate the //algorithm if (tmpa*sx+tmpb*sy+tmpc*sz+tmpk*sh==0) { DEBUGMSG(ORIGIN_INSIDE_CH,"n coplanar Points. Compute plane through " <<"these points. Width=0."); WNum=0; WDenom=1; A=tmpa; B=tmpb; C=tmpc; K=tmpk; DEBUGENDL(ORIGIN_INSIDE_CH,"Solution of 3x3:\n",A< sol; sol.push_back(A); sol.push_back(B); sol.push_back(C); sol.push_back(D); sol.push_back(K); allsolutions.push_back(sol); alloptimal.push_back(sol); DEBUGMSG(ORIGIN_INSIDE_CH,"End ORIGIN_INSIDE_CH"); return false; } else { //Take center of tetrahedron pqrs RT ux,uy,uz,uh,vx,vy,vz,vh,nox,noy,noz,noh; ux=px*qh+ph*qx; vx=rx*sh+rh*sx; uy=py*qh+ph*qy; vy=ry*sh+rh*sy; uz=pz*qh+ph*qz; vz=rz*sh+rh*sz; uh=RT(2)*ph*qh; vh=RT(2)*rh*sh; nox=ux*vh+uh*vx; noy=uy*vh+uh*vy; noz=uz*vh+uh*vz; noh=RT(2)*uh*vh; neworigin=tco.make_point(nox,noy,noz,noh); CGAL_assertion(noh!=0); DEBUGENDL(ORIGIN_INSIDE_CH,"New Origin: ",neworigin); //Translate all the points first=start; while(first!=beyond) { typename InputDA::PolyPoint tmp=(*first).point(); RT tmpx,tmpy,tmpz,tmph; tco.get_point_coordinates(tmp,tmpx,tmpy,tmpz,tmph); RT newx,newy,newz,newh; newx=tmpx*noh-tmph*nox; newy=tmpy*noh-tmph*noy; newz=tmpz*noh-tmph*noz; newh=tmph*noh; DEBUGENDL(ORIGIN_INSIDE_CH,"Old Point: ",(*first).point()); #ifdef GCD_COMPUTATION RT dummy=0; simplify_solution(newx,newy,newz,newh,dummy); #endif (*first).point()=tco.make_point(newx,newy,newz,newh); DEBUGENDL(ORIGIN_INSIDE_CH,"New Point: ",(*first).point()); ++first; } DEBUGMSG(ORIGIN_INSIDE_CH,"Zero now inside polyhedron."); DEBUGMSG(ORIGIN_INSIDE_CH,"End ORIGIN_INSIDE_CH"); return true; } } } /* ****************************************************** */ /* *** --- *** The main enumeration functions *** --- *** */ /* ****************************************************** */ template void width_3_convex(InputPolyhedron &P) { DEBUGMSG(WIDTH_3_CONVEX,"\nBegin WIDTH_3_CONVEX"); typedef CGAL::Width_3_internal::Data_access DA; typedef typename DA::Facet_handle Facet_handle; typedef typename DA::Vertex_handle Vertex_handle; typedef typename DA::Halfedge_handle Halfedge_handle; typedef typename DA::Vertex_iterator Vertex_iterator; //Ensure that Polyhedron has at least one vertex CGAL_assertion_msg(P.size_of_vertices()>2, "Can not compute width of a 0, 1 or 2-vertex polyhedron"); Vertex_iterator first=P.vertices_begin(); Vertex_iterator beyond=P.vertices_end(); //Begin with Phase 2 if (origin_inside_CH(first,beyond,DA())) { DEBUGMSG(WIDTH_3_CONVEX,"Origin is now Inside the Polyhedron. " < go_on; std::vector impassable; //Ensure that the plane equations are determined because of the //compare operator in DA Facet_handle feq=P.facets_begin(); while(feq!=P.facets_end()) { compute_plane_equation(DA(),feq); ++feq; } DEBUGMSG(WIDTH_3_CONVEX,"All plane equations of all facets computed."); //ensure all flags are false #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || defined(NDEBUG)) int halfedgecount=0; #endif Halfedge_handle esf=P.halfedges_begin(); while(esf!=P.halfedges_end()) { #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || defined(NDEBUG)) ++halfedgecount; #endif DEBUGENDL(EDGE_INITIALIZING,"Edge e: " <opposite()->vertex()->point() <<" --> ",esf->vertex()->point()); dao.set_visited_flag(esf,false); dao.set_impassable_flag(esf,false); ++esf; } #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || defined(NDEBUG)) CGAL_assertion(int(P.size_of_halfedges())==halfedgecount); DEBUGENDL(WIDTH_3_CONVEX,"Visited all ",halfedgecount <<" halfedges. ASSERTION OK."); CGAL_assertion(dao.size_of_visited()==halfedgecount); CGAL_assertion(dao.size_of_impassable()==halfedgecount); DEBUGMSG(WIDTH_3_CONVEX,"Map sizes of visited and impassable " <<"halfedges are correct. ASSERTION OK."); #endif DEBUGMSG(WIDTH_3_CONVEX,"All flags set to false."); //Now begin with the main enumeration Facet_handle f = P.facets_begin(); initial_VF_pair(dao,f,P,go_on); #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || (!defined(CGAL_KERNEL_CHECK_EXPENSIVE) && !defined(CGAL_CHECK_EXPENSIVE))\ || defined(NDEBUG)) Vertex_iterator vtxass=P.vertices_begin(); while(vtxass!=P.vertices_end()) { RT px,py,pz,ph; tco.get_point_coordinates(vtxass->point(),px,py,pz,ph); CGAL_expensive_assertion(A*px+B*py+C*pz+K*ph>=0); CGAL_expensive_assertion(A*px+B*py+C*pz+D*ph<=0); ++vtxass; } //Assert that the initial facet has antipodal vertices //and that all incident edges are visited (flag=true) but //that the impassable flag is not set yet. std::vector avass; dao.get_antipodal_vertices(f,avass); DEBUGENDL(ASSERTION_OUTPUT,"Size of avass: ",avass.size()); CGAL_expensive_assertion(avass.size()!=0); Halfedge_handle eass=f->halfedge(); Halfedge_handle eass0=eass; CGAL_expensive_assertion(dao.is_visited(eass)); CGAL_expensive_assertion(!dao.is_impassable(eass)); eass=eass->next(); while (eass != eass0) { CGAL_expensive_assertion(dao.is_visited(eass)); CGAL_expensive_assertion(!dao.is_impassable(eass)); eass=eass->next(); } DEBUGMSG(ASSERTION_OUTPUT,"All edges of the first initial facet " <<"has a visited flag."); #endif // Begin Phase 3 Facet_handle fnext; Halfedge_handle e; std::vector Visited; std::vector N; std::vector Nnew; //While there still exist an edge we can rotate an incident facet with //known antipodal vertices in the other facet with unknown antipodal //vertices then do this rotation while ( !go_on.empty()) { DEBUGENDL(WIDTH_3_CONVEX,"Size of go_on: ",go_on.size()); #ifdef GO_ON_OUTPUT DEBUGMSG(GO_ON_OUTPUT,"Edges on stack go_on:"); typename std::vector::iterator goonit=go_on.begin(); while(goonit!=go_on.end()) { DEBUGENDL(GO_ON_OUTPUT,"Edge: ", (*goonit)->opposite()->vertex()->point()<<" --> " <<(*goonit)->vertex()->point()); ++goonit; } #endif //Take last edge on stack go_on e=go_on.back(); //Check if e is a proper edge or not. If so determine fnext if (preparation_check(dao,e,fnext,go_on,impassable)) { DEBUGMSG(WIDTH_3_CONVEX,"Preparation Check successful"); //f is the facet of which we know the antipodal vertices f=e->facet(); Visited.clear(); dao.get_antipodal_vertices(f,N); CGAL_assertion (!N.empty()); DEBUGMSG(ASSERTION_OUTPUT,"f has some antipodal vertices. Assertion " <<"successful."); while(!check_about_VF_pairs(dao,fnext,N)) { DEBUGMSG(WIDTH_3_CONVEX,"No new VF-pair. Continue (Begin) " <<"rotation of the planes."); EE_computation(DA(),e,N,Visited,Nnew); DEBUGMSG(WIDTH_3_CONVEX,"Planes have been rotated. Check now " <<"for a new VF-pair"); setunion(Visited,N); N=Nnew; } } } #if !(defined(CGAL_KERNEL_NO_ASSERTIONS) || defined(CGAL_NO_ASSERTIONS) \ || (!defined(CGAL_KERNEL_CHECK_EXPENSIVE) && !defined(CGAL_CHECK_EXPENSIVE))\ || defined(NDEBUG)) Facet_handle fass=P.facets_begin(); while(fass!=P.facets_end()) { std::vector apvass; dao.get_antipodal_vertices(fass,apvass); DEBUGENDL(ASSERTION,"Current checking facet: ",fass->plane()); CGAL_assertion(!apvass.empty()); ++fass; } DEBUGMSG(ASSERTION,"All facets have antipodal vertices. " <<"ASSERTION OK."); Facet_handle fec = P.facets_begin(); std::vector fakego_on; DA daoec; while(fec!=P.facets_end()) { std::vector avec; std::vector avivf; initial_VF_pair(daoec,fec,P,fakego_on); daoec.get_antipodal_vertices(fec,avec); dao.get_antipodal_vertices(fec,avivf); CGAL_assertion(int(avivf.size())==int(avec.size())); CGAL_assertion(int(avec.size())>0); DEBUGENDL(EXPENSIVE_CHECKS_OUTPUT,"Antipodal vertices of facet: (" <halfedge()->opposite()->vertex()->point() <<"), (",fec->halfedge()->vertex()->point()<<"), (" <halfedge()->next()->vertex()->point()<<")"); std::vector::iterator vtxit=avec.begin(); while(vtxit!=avec.end()) { std::vector::iterator it; it=std::find(avivf.begin(),avivf.end(),*vtxit); CGAL_assertion(it!=avivf.end()); DEBUGENDL(EXPENSIVE_CHECKS_OUTPUT,"Antipodal vertex: ", (*vtxit)->point()); ++vtxit; } ++fec; } DEBUGMSG(EXPENSIVE_CHECKS_OUTPUT,"All VF-pairs verified. " <<"Expensive Check successful."); // // This assertion should not currently be true since the convex hull // polyhedron is triangulated; no postprocessing is done to merge coplanar // neighboring facets. // // CGAL_assertion(dao.size_of_antipodal_vertices() // ==int(P.size_of_facets())); #endif //Begin with phase 4. As long as the set of impassable edges is not empty //rotate one of the planes into the other sharing the impassable edge while(!impassable.empty()) { //Take top edge on stack impassable e=impassable.back(); EE_pairs(dao,e,impassable); //In EE_pairs the top element will be removed } } DEBUGMSG(WIDTH_3_CONVEX,"Width computed."); } }; } //namespace CGAL #endif