// LP solver for kernel #include #include // Taken from http://www.qhull.org/html/qhalf.htm // If you do not know an interior point for the halfspaces, use linear programming // to find one. Assume, n halfspaces defined by: aj*x1+bj*x2+cj*x3+dj>=0, j=1..n. // Perform the following linear program: // max(x5) aj*x1+bj*x2+cj*x3+dj*x4-x5>=0, j=1..n // Then, if [x1,x2,x3,x4,x5] is an optimal m_solution with x4,x5>0 we get: // aj*(x1/x4)+bj*(x2/x4)+cj*(x3/x4)+dj>=(x5/x4)>0, j=1..n // and conclude that the point [x1/x4,x2/x4,x3/x4] is in the interior of all // the halfspaces. Note that x5 is optimal, so this point is "way in" the // interior (good for precision errors). // After finding an interior point, the rest of the intersection algorithm is // from Preparata & Shamos ['85, p. 316, "A simple case ..."]. Translate the // halfspaces so that the interior point is the origin. Calculate the dual // polytope. The dual polytope is the convex hull of the vertices dual to the // original faces in regard to the unit sphere (i.e., halfspaces at distance // d from the origin are dual to vertices at distance 1/d). Then calculate // the resulting polytope, which is the dual of the dual polytope, and // translate the origin back to the interior point [S. Spitz and S. Teller]. // NOTE: We changed this to max(x4) under constraints aj*x1+bj*x2+cj*x3+dj-x4>=0, j=1..n // i.e. aj*x1+bj*x2+cj*x3-x4 >= -dj, j=1..n // Then, if [x1,x2,x3,x4] is an optimal m_solution with x4 > 0 we pick // the point [x1,x2,x3] as inside point. template class Polyhedron_kernel { private: // basic types typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point; typedef typename Kernel::Plane_3 Plane; typedef typename Kernel::Triangle_3 Triangle; // program and solution types typedef CGAL::Quadratic_program LP; typedef typename CGAL::Quadratic_program_solution Solution; typedef typename Solution::Variable_value_iterator Variable_value_iterator; // linear program Solution m_solution; Point m_inside_point; public: Polyhedron_kernel() {} ~Polyhedron_kernel() {} public: Point& inside_point() { return m_inside_point; } const Point& inside_point() const { return m_inside_point; } unsigned int number_of_iterations() { return m_solution.number_of_iterations(); } public: template < class InputIterator > bool solve(InputIterator begin, InputIterator end) { // solve linear program with constraints Ax >= b LP lp(CGAL::LARGER,false); // column indices const int index_x1 = 0; const int index_x2 = 1; const int index_x3 = 2; const int index_x4 = 3; int j = 0; InputIterator it; for(it = begin; it != end; it++, j++) { const Triangle& triangle = *it; const Point& a = triangle[0]; const Point& b = triangle[1]; const Point& c = triangle[2]; Plane plane(a,c,b); // note a c b to get inward normal Vector normal = unit_normal(plane); FT aj = normal.x(); FT bj = normal.y(); FT cj = normal.z(); // constraint (line j): aj * x1 + bj * x2 + cj * x3 - x4 >= -dj lp.set_a(index_x1, j, aj); // aj * x1 lp.set_a(index_x2, j, bj); // bj * x2 lp.set_a(index_x3, j, cj); // cj * x3 lp.set_a(index_x4, j, -1.0); // -x4 // right hand side (>= -dj) FT dj = distance_to_origin(plane) * CGAL::sign(plane.d()); lp.set_b(j, -dj); } // objective function -> max x4 (negative sign set because // the lp solver always minimizes an objective function) lp.set_c(index_x4,-1.0); // add constraints over x4 (>= 0). somewhat redundant // constraint as we later test for x4 > 0 lp.set_l(index_x4,true,0.0); // solve the linear program m_solution = CGAL::solve_linear_program(lp, ET()); if(m_solution.is_infeasible()) return false; if(!m_solution.is_optimal()) return false; // get variables Variable_value_iterator X = m_solution.variable_values_begin(); // Problem: X[0], X[1], ..., X[3] are proxy objects from // boost::facade_iterator. Those proxy objects are of type // operator_brackets_proxy, which // is castable to a number type. In CGAL::to_double, the // automatic selection of a Real_embeddable_traits does not // work with such proxy objects (whose type is not // recognized). That is why we need to select the // Real_embeddable_traits manually, and create a functor // to_double manually. -- Laurent Rineau, 2008/09/04 typedef CGAL::Real_embeddable_traits RE_traits; typename RE_traits::To_double to_double; // solution if x4 > 0 double x4 = to_double(X[3]); if(x4 <= 0.0) return false; // define inside point as (x1;x2;x3) double x1 = to_double(X[0]); double x2 = to_double(X[1]); double x3 = to_double(X[2]); m_inside_point = Point(x1,x2,x3); return true; } Vector unit_normal(const Plane& plane) { Vector n = plane.orthogonal_vector(); return n / std::sqrt(n * n); } FT distance_to_origin(const Plane& plane) { return std::sqrt(CGAL::squared_distance(Point(CGAL::ORIGIN),plane)); } }; template void get_triangles(Polyhedron& polyhedron, OutputIterator out) { typedef typename Polyhedron::Facet_iterator Facet_iterator; typedef typename Polyhedron::Halfedge_handle Halfedge_handle; for(Facet_iterator f = polyhedron.facets_begin(); f != polyhedron.facets_end(); f++) { Halfedge_handle he = f->halfedge(); const Point& a = he->vertex()->point(); const Point& b = he->next()->vertex()->point(); const Point& c = he->next()->next()->vertex()->point(); *out++ = Triangle(a,b,c); } }