// Copyright (c) 2005 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under // the terms of the Q Public License version 1.0. // See the file LICENSE.QPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // // Author(s) : Efi Fogel /*! * Polyhedral _cgm is a data dtructure that represents a 3D convex polyhedron. * This representation represents the 2D surface boundary of the shape. In * particular, it represents the 2D polygonal cells that define the 2D surface * of a polyhedron. The representation consists of 6 arrangements each * representing a portion of the polyhedron surface-boundary with overlaps * between them. We project the normals of each facet of the polyhedron onto * the faces of the unit cube (in fact we use a 2-unit cube centered at the * origin). A arrangement is formed on each face of the unit cube as follows: * Each interesection of a polyhedron facet-normal with a cube face define a * vertex in the arrangement of that face. We connect vertices that were * generated by normals of adjacent facets. This forms a arrangement bounded by * a rectangle on each cubic face. */ #ifndef CGAL_POLYHEDRAL_CGM_H #define CGAL_POLYHEDRAL_CGM_H #include #include #include #include #include #include #include #include "CGAL/Aff_transformation_3.h" #include #include #include #include #include #include #include #include #include #include #include #include CGAL_BEGIN_NAMESPACE template #endif class T_Dcel = Polyhedral_cgm_arr_dcel> class Polyhedral_cgm : public Cubical_gaussian_map_3 { private: typedef Cubical_gaussian_map_3 Base; typedef Polyhedral_cgm Self; public: // Arrangement traits and types: typedef typename Base::Arr_traits Arr_traits; #ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM typedef T_Dcel Dcel; #else typedef typename T_Dcel::template Dcel Dcel; #endif typedef typename Base::Arrangement Arr; typedef typename Base::Corner_id Corner_id; typedef typename Base::Projected_normal Projected_normal; typedef typename Base::Halfedge_around_vertex_const_circulator Halfedge_around_vertex_const_circulator; typedef typename Base::Arr_vertex_handle Arr_vertex_handle; typedef typename Base::Arr_halfedge_handle Arr_halfedge_handle; typedef typename Base::Arr_halfedge_const_handle Arr_halfedge_const_handle; typedef typename Base::Arr_face_handle Arr_face_handle; typedef typename Base::Arr_vertex_const_handle Arr_vertex_const_handle; typedef typename Base::Arr_vertex_iterator Arr_vertex_iterator; typedef typename Base::Arr_vertex_const_iterator Arr_vertex_const_iterator; typedef typename Base::Arr_halfedge_iterator Arr_halfedge_iterator; typedef typename Base::Arr_halfedge_const_iterator Arr_halfedge_const_iterator; typedef typename Base::Arr_face_iterator Arr_face_iterator; typedef typename Base::Arr_ccb_halfedge_circulator Arr_ccb_halfedge_circulator; typedef typename Base::Arr_ccb_halfedge_const_circulator Arr_ccb_halfedge_const_circulator; typedef typename Base::Arr_hole_iterator Arr_hole_iterator; typedef typename Base::Arr_halfedge_around_vertex_const_circulator Arr_halfedge_around_vertex_const_circulator; typedef typename Base::Arr_vertex Arr_vertex; typedef typename Arr_vertex::Vertex_location Vertex_location; typedef typename Base::Kernel Kernel; typedef typename Kernel::FT FT; typedef typename Kernel::Point_3 Point_3; typedef typename Kernel::Vector_3 Vector_3; typedef typename Kernel::Plane_3 Plane_3; typedef typename Kernel::Aff_transformation_3 Aff_transformation_3; typedef typename Kernel::Orientation_2 Orientation_2; typedef typename Arr_traits::Point_2 Point_2; typedef typename Arr_traits::Curve_2 Curve_2; typedef typename Arr_traits::X_monotone_curve_2 X_monotone_curve_2; typedef Polyhedral_cgm_change_notification Change_notification; typedef Polyhedral_cgm_overlay Polyhedral_cgm_overlay; private: typedef CGAL::Tag_true Tag_true; typedef CGAL::Tag_false Tag_false; // Inexact types: typedef float Approximate_NT; typedef CGAL::Cartesian Approximate_kernel; typedef Approximate_kernel::Point_3 Approximate_point_3; typedef Approximate_kernel::Vector_3 Approximate_vector_3; /*! Transforms a (planar) facet into a normal */ struct Normal_vector { template typename Facet::Plane_3 operator()(Facet & f) { typename Facet::Halfedge_handle h = f.halfedge(); // Facet::Plane_3 is the normal vector type. We assume the // CGAL Kernel here and use its global functions. #if 0 const Point_3 & x = h->vertex()->point(); const Point_3 & y = h->next()->vertex()->point(); const Point_3 & z = h->next()->next()->vertex()->point(); #endif Vector_3 normal = CGAL::cross_product(h->next()->vertex()->point() - h->vertex()->point(), h->next()->next()->vertex()->point() - h->next()->vertex()->point()); FT sqr_length = normal.squared_length(); double tmp = CGAL::to_double(sqr_length); return normal / CGAL::sqrt(tmp); } }; // The extended Polyhedron vertex type template struct Polyhedron_3_vertex : public CGAL::HalfedgeDS_vertex_base { typedef CGAL::HalfedgeDS_vertex_base Base; typedef typename Base::Point Point; /*! An inexact representation (good for computing the sphere bound and * rendering) \todo move to Cubical_gaussian_map_geo */ Approximate_point_3 m_approximate_point; /*! Indicates whether it is a marked vertex */ bool m_marked; /*! Constructor */ Polyhedron_3_vertex() : Base(), m_marked(false) {} /*! Constructor */ Polyhedron_3_vertex(const Point & p) : Base(p), m_marked(false) {} /*! Obtain the mutable (geometrical) point */ Point & point() { return Base::point(); } /*! Obtain the constant (geometrical) point */ const Point & point () const { return Base::point(); } /* \todo move to Cubical_gaussian_map_geo */ void set_approximate_point(const Approximate_point_3 & point) { m_approximate_point = point; } /* \todo move to Cubical_gaussian_map_geo */ const Approximate_point_3 & get_approximate_point(void) const { return m_approximate_point; } /*! Set the "marked" flag */ void set_marked(bool marked) { m_marked = marked; } /*! Obtain the "marked" flag */ bool get_marked() const { return m_marked; } }; // The extended Polyhedron halfedge type template struct Polyhedron_3_halfedge : public CGAL::HalfedgeDS_halfedge_base { /*! */ bool m_flag; /*! Indicates whether it is a marked vertex */ bool m_marked; /*! */ Polyhedron_3_halfedge() : m_flag(false), m_marked(false) {} /*! Set the "marked" flag */ void set_marked(bool marked) { m_marked = marked; } /*! Obtain the "marked" flag */ bool get_marked() const { return m_marked; } }; /*! Represnts a polyhedron facet */ template class Polyhedron_3_face : public CGAL::HalfedgeDS_face_base { private: /*! */ Projected_normal m_dual; /*! Indicates whether it is a marked face */ bool m_marked; public: typedef CGAL::HalfedgeDS_face_base Base; typedef typename Base::Plane Plane; /*! Constructor */ Polyhedron_3_face() : m_marked(false) {} /*! Delegate */ Plane & plane() { return Base::plane(); } const Plane & plane() const { return Base::plane(); } /*! \brief obtains the dual structure */ Projected_normal & get_dual() { return m_dual; } /*! Set the "marked" flag */ void set_marked(bool marked) { m_marked = marked; } /*! Obtain the "marked" flag */ bool get_marked() const { return m_marked; } /*! Compute the central projection */ void compute_projection(void) { m_dual.compute_projection(plane()); m_dual.set_is_real(true); } }; // An items type using my halfedge. struct Polyhedron_items : public CGAL::Polyhedron_items_3 { template struct Vertex_wrapper { typedef Polyhedron_3_vertex Vertex; }; template struct Halfedge_wrapper { typedef Polyhedron_3_halfedge Halfedge; }; template struct Face_wrapper { typedef Polyhedron_3_face Face; }; }; public: // Polyhedron public types and methods: typedef CGAL::Polyhedron_traits_with_normals_3 Polyhedron_traits; typedef CGAL::Polyhedron_3 Polyhedron; typedef typename Polyhedron::Vertex Polyhedron_vertex; typedef Point_3 Polyhedron_point; typedef Vector_3 Polyhedron_normal; typedef typename Polyhedron::HalfedgeDS Polyhedron_halfedgeds; typedef typename Polyhedron::Vertex_handle Polyhedron_vertex_handle; typedef typename Polyhedron::Vertex_const_handle Polyhedron_vertex_const_handle; typedef typename Polyhedron::Facet_handle Polyhedron_facet_handle; typedef typename Polyhedron::Facet_const_handle Polyhedron_facet_const_handle; typedef typename Polyhedron::Vertex_iterator Polyhedron_vertex_iterator; typedef typename Polyhedron::Edge_iterator Polyhedron_edge_iterator; typedef typename Polyhedron::Halfedge_const_handle Polyhedron_halfedge_const_handle; typedef typename Polyhedron::Facet_iterator Polyhedron_facet_iterator; typedef typename Polyhedron::Facet_const_iterator Polyhedron_facet_const_iterator; typedef typename Polyhedron::Halfedge_around_facet_circulator Polyhedron_halfedge_around_facet_circulator; typedef typename Polyhedron::Halfedge_around_facet_const_circulator Polyhedron_halfedge_around_facet_const_circulator; typedef typename Polyhedron::Halfedge_around_vertex_circulator Polyhedron_halfedge_around_vertex_circulator; /*! \brief obtains the polyhedral representation of the polyhedron */ const Polyhedron & get_polyhedron() const { return m_polyhedron; } /*! \brief returns the polyhedron number of vertices */ unsigned int polyhedron_size_of_vertices() const { return m_polyhedron.size_of_vertices(); } /*! \brief begin iterator of polyhedron facets */ Polyhedron_vertex_iterator polyhedron_vertices_begin() { return m_polyhedron.vertices_begin(); } /*! \brief end iterator of polyhedron facets */ Polyhedron_vertex_iterator polyhedron_vertices_end() { return m_polyhedron.vertices_end(); } private: typedef unsigned int * Coord_index_iter; /*! Stores a point in inexact number type in the vertex * \todo move to Cubical_gaussian_map_geo */ struct Convert_approximate_point { void operator()(Polyhedron_vertex & vertex) { const Point_3 & point = vertex.point(); float x = CGAL::to_double(point.x()); float y = CGAL::to_double(point.y()); float z = CGAL::to_double(point.z()); Approximate_point_3 approximate_point(x, y, z); vertex.set_approximate_point(approximate_point); } }; /*! Add a point */ template class Add { private: typedef CGAL::Polyhedron_incremental_builder_3 Builder; Builder & m_B; public: Add(Builder & B) : m_B(B) {} Polyhedron_vertex_handle operator()(T_Point_3_iter pi) { typedef typename HDS::Vertex Vertex; typedef typename Vertex::Point Point; return m_B.add_vertex(Point((*pi)[0], (*pi)[1], (*pi)[2])); } }; /*! Specialized add a point */ template class Add { private: typedef CGAL::Polyhedron_incremental_builder_3 Builder; Builder & m_B; public: Add(Builder & B) : m_B(B) {} Polyhedron_vertex_handle operator()(Point_3 * pi) { std::cout << "Add: " << *pi << std::endl; return m_B.add_vertex(*pi); } }; /*! */ template class Build_surface : public CGAL::Modifier_base { private: typedef CGAL::Polyhedron_incremental_builder_3 Builder; typedef typename Builder::size_type size_type; /*! The begin iterator of the points */ const Point_3_iter & m_points_begin; /*! The end iterator of the points */ const Point_3_iter & m_points_end; /*! The number of points */ size_type m_num_points; /*! The begin iterator of the indices */ const Coord_index_iter & m_indices_begin; /*! The end iterator of the indices */ const Coord_index_iter & m_indices_end; /*! The number of facest */ size_type m_num_facets; /*! The index of the marked vertex */ unsigned int m_marked_vertex_index; /*! The index of the marked edge */ unsigned int m_marked_edge_index; /*! The index of the marked face */ unsigned int m_marked_facet_index; public: /*! Constructor */ Build_surface(const Point_3_iter & points_begin, const Point_3_iter & points_end, unsigned int num_points, const Coord_index_iter & indices_begin, const Coord_index_iter & indices_end, unsigned int num_facets) : m_points_begin(points_begin), m_points_end(points_end), m_num_points(num_points), m_indices_begin(indices_begin), m_indices_end(indices_end), m_num_facets(num_facets), m_marked_vertex_index(0), m_marked_edge_index(0), m_marked_facet_index(0) {} /*! Destructor */ virtual ~Build_surface() {} /*! Set the marked-vertex index */ void set_marked_vertex_index(unsigned int id) {m_marked_vertex_index = id;} /*! Set the marked-edge index */ void set_marked_edge_index(unsigned int id) {m_marked_edge_index = id;} /*! Set the marked-face index */ void set_marked_facet_index(unsigned int id) {m_marked_facet_index = id;} /*! builds the polyhedron */ void operator()(HDS & hds) { // Postcondition: `hds' is a valid polyhedral surface. Builder B(hds, true); B.begin_surface(m_num_points, m_num_facets); // Add the points: unsigned int counter = 0; Add add(B); for (Point_3_iter pi = m_points_begin; pi != m_points_end; ++pi) { Polyhedron_vertex_handle vh = add(pi); if (counter == m_marked_vertex_index) vh->set_marked(true); ++counter; } // Add the facets: bool facet_ended = true; counter = 0; for (Coord_index_iter ii = m_indices_begin; ii != m_indices_end; ++ii) { int index = *ii; if (facet_ended) { Polyhedron_facet_handle fh = B.begin_facet(); if (counter == m_marked_facet_index) fh->set_marked(true); B.add_vertex_to_facet(index); facet_ended = false; continue; } if (index != -1) { B.add_vertex_to_facet(index); continue; } B.end_facet(); facet_ended = true; ++counter; } B.end_surface(); } }; private: /*! The gravity center */ Point_3 m_center; /*! Indicates whether the polyhedron has been built */ bool m_dirty_polyhedron; /*! Indicated whether the center has been calculated */ bool m_dirty_center; /*! The actual polyhedron object */ Polyhedron m_polyhedron; /*! The change notification function object */ Change_notification * m_change_notification; /*! The index of the marked vertex */ unsigned int m_marked_vertex_index; /*! The index of the marked edge */ unsigned int m_marked_edge_index; /*! The index of the marked face */ unsigned int m_marked_facet_index; /*! */ Polyhedron_vertex_const_handle m_src_vertex; /*! */ Polyhedron_vertex_const_handle m_trg_vertex; /*! */ Polyhedron_halfedge_const_handle m_halfedge; /*! \brief converts */ Vertex_location num_faces_2_vertex_location(unsigned int num_faces) { CGAL_assertion(num_faces); return (num_faces == 1) ? Arr_vertex::Interior : ((num_faces == 2) ? Arr_vertex::Edge : Arr_vertex::Corner); } /*! */ class Face_nop_op { public: void operator()(Arr_face_handle fh) { } }; /*! \brief calculates the center of the polyhedron */ void calculate_center() { // Reset the "visited" flag: reset_faces(); // Count them: Face_nop_op op; unsigned int vertices_num = 0; for (unsigned int i = 0; i < NUM_FACES; i++) { Arr & arr = m_arrangements[i]; Arr_face_handle fi = arr.faces_begin(); // Skip the unbounded face for (fi++; fi != arr.faces_end(); fi++) { if (fi->get_is_set()) continue; vertices_num++; const Point_3 & p = fi->get_point(); Vector_3 v = p - CGAL::ORIGIN; m_center = m_center + v; process_boundary_faces(fi, op); } } FT num((int)vertices_num); FT x = m_center.x() / num; FT y = m_center.y() / num; FT z = m_center.z() / num; m_center = Point_3(x, y, z); m_dirty_center = false; } /*! \brief updates the polyhedron */ template void update_polyhedron(const Point_3_iterator & points_begin, const Point_3_iterator & points_end, unsigned int num_points, const Coord_index_iter indices_begin, Coord_index_iter indices_end, unsigned int num_facets) { /*! The builder */ Build_surface surface(points_begin, points_end, num_points, indices_begin, indices_end, num_facets); surface.set_marked_vertex_index(m_marked_vertex_index); surface.set_marked_edge_index(m_marked_edge_index); surface.set_marked_facet_index(m_marked_facet_index); m_polyhedron.delegate(surface); // Mark the marked (half) edges: unsigned int counter = 0; Polyhedron_edge_iterator ei; for (ei = m_polyhedron.edges_begin(); ei != m_polyhedron.edges_end(); ++ei) { if (counter == m_marked_edge_index) { // Mark both halfedges: ei->set_marked(true); ei->opposite()->set_marked(true); } ++counter; } #if 0 if (!m_polyhedron.normalized_border_is_valid()) m_polyhedron.normalize_border(); #else m_polyhedron.normalize_border(); #endif #if 1 std::transform(m_polyhedron.facets_begin(), m_polyhedron.facets_end(), m_polyhedron.planes_begin(), Normal_vector()); #endif /*! \todo move to Cubical_gaussian_map_geo */ std::for_each(m_polyhedron.vertices_begin(), m_polyhedron.vertices_end(), Convert_approximate_point()); m_dirty_polyhedron = false; } /*! Compute the central projections */ void compute_projections() { // Initialize the arrangements with the boundary curves: init_arrangements(); // Compute the central projection of each facet-normal: for (Polyhedron_facet_iterator fi = m_polyhedron.facets_begin(); fi != m_polyhedron.facets_end(); ++fi) { fi->compute_projection(); } // Traverse all vertices: for (Polyhedron_vertex_iterator src = m_polyhedron.vertices_begin(); src != m_polyhedron.vertices_end(); ++src) { // For each vertex, traverse incident faces: Polyhedron_halfedge_around_vertex_circulator hec = src->vertex_begin(); CGAL_assertion(CGAL::circulator_size(hec) >= 3); Polyhedron_halfedge_around_vertex_circulator begin_hec = hec; Polyhedron_halfedge_around_vertex_circulator next_hec = hec; next_hec++; do { if (!next_hec->m_flag) { Projected_normal & dual1 = hec->facet()->get_dual(); Projected_normal & dual2 = next_hec->facet()->get_dual(); m_src_vertex = src; m_trg_vertex = next_hec->opposite()->vertex(); m_halfedge = next_hec; insert(dual1, dual2, true); next_hec->m_flag = true; next_hec->opposite()->m_flag = true; if (m_change_notification) { for (unsigned int i = 0; i < 3; ++i) { if (dual1.is_vertex_set(i)) { Arr_vertex_handle & vh = dual1.get_vertex(i); m_change_notification->update_dual_face(hec->facet(), vh); } if (dual2.is_vertex_set(i)) { Arr_vertex_handle & vh = dual2.get_vertex(i); m_change_notification->update_dual_face(next_hec->facet(), vh); } } } } hec = next_hec; next_hec++; } while (hec != begin_hec); } // Process the corners: process_corners(); //! \todo eliminate this call!!! // Process the edges: process_edges(); // Update the point of the vertex-less cubic faces: update_point(); } /*! Update the point of the vertex-less cubic faces */ void update_point() { for (unsigned int i = 0; i < NUM_FACES; i++) { Arr & arr = m_arrangements[i]; // If there are more than 1 face excluding the unbounded face, continue if (arr.number_of_faces() != 2) continue; Arr_face_iterator fi = arr.faces_begin(); ++fi; // skip the unbounded face // If the point of the face is set already, continue if (fi->get_is_set()) continue; Arr_ccb_halfedge_circulator hec = fi->outer_ccb(); Arr_ccb_halfedge_circulator hec_begin = hec; do { if (hec->get_is_real()) { ++hec; continue; } Arr_face_handle adjacent_face = find_adjacent_face(hec); fi->set_point(adjacent_face->get_point()); if (m_change_notification) m_change_notification->update_dual_vertex(adjacent_face, fi); break; } while(hec != hec_begin); } } /*! Reset the "visited" flag. In fact we overload the "is_set" flag, and * use as the "visited" flag. This function must be called before the * recursive function process_boundary_faces() is invoked. */ void reset_faces() { for (unsigned int i = 0; i < NUM_FACES; i++) { Arr & pm = m_arrangements[i]; Arr_face_handle fi = pm.faces_begin(); // Skip the unbounded face for (fi++; fi != pm.faces_end(); fi++) { fi->set_is_set(false); } } } public: /*! Parameter-less Constructor */ Polyhedral_cgm() : m_dirty_polyhedron(true), m_dirty_center(true), m_change_notification(NULL), m_marked_vertex_index(0), m_marked_edge_index(0), m_marked_facet_index(0) { // The m_corner_vertices are set to NULL by their default constructor } /*! Initialize a cubical Gaussian map */ template void init(const Point_3_iterator & points_begin, const Point_3_iterator & points_end, unsigned int num_points, const Coord_index_iter indices_begin, Coord_index_iter indices_end, unsigned int num_facets, Change_notification * cn = NULL) { m_change_notification = cn; // Update the polyhedron: if (m_dirty_polyhedron) update_polyhedron(points_begin, points_end, num_points, indices_begin, indices_end, num_facets); #if 0 std::copy(m_polyhedron.points_begin(), m_polyhedron.points_end(), std::ostream_iterator(std::cout, "\n")); #endif compute_projections(); // compute the central projections } /*! Copy Constructor */ Polyhedral_cgm(const Polyhedral_cgm & cgm) { // Not implemented yet! CGAL_assertion(0); } /*! Destructor */ virtual ~Polyhedral_cgm() { clear(); } /*! \brief clears the internal representation and auxiliary data structures */ void clear() { m_polyhedron.clear(); m_dirty_polyhedron = true; m_dirty_center = true; Base::clear(); } /*! Processe all planar faces that are mapped to by a single polytope vertex */ template void process_boundary_faces(Arr_face_handle fh, Op op) { op(fh); fh->set_is_set(true); Arr_ccb_halfedge_circulator hec = fh->outer_ccb(); Arr_ccb_halfedge_circulator hec_begin = hec; do { // Process only artificial halfedges: if (!hec->get_is_real()) { // Find the planar face in the adjacent cube face: Arr_face_handle face = find_adjacent_face(hec); if (!face->get_is_set()) { process_boundary_faces(face, op); } } hec++; } while(hec != hec_begin); } /*! Compute the minkowski sum */ template void minkowsi_sum(Cgm_iter_ begin, Cgm_iter_ end) { // Compute the overlays: overlay(begin, end); // Initialize the corners: init_corners(); // Process the corners: process_corners(); // Process the edges: process_edges(); #if 0 /* Is there a collision? * \todo this doeasn't belong here */ CGAL::Oriented_side side = oriented_side(CGAL::ORIGIN); std::cout << ((side == CGAL::ON_ORIENTED_BOUNDARY) ? "On boundary" : ((side == CGAL::ON_POSITIVE_SIDE) ? "Outside" : "Inside")) << std::endl; Projected_normal dual; side = oriented_side(CGAL::ORIGIN, dual, false); std::cout << ((side == CGAL::ON_ORIENTED_BOUNDARY) ? "On boundary" : ((side == CGAL::ON_POSITIVE_SIDE) ? "Outside" : "Inside")) << std::endl; #endif // print_stat(); } /*! Compute the overlay */ template void overlay(Cgm_iter_ & begin, Cgm_iter_ & end) { Polyhedral_cgm * gm1 = *begin++; Polyhedral_cgm * gm2 = *begin; for (unsigned int i = 0; i < NUM_FACES; ++i) { Arr & arr = m_arrangements[i]; Arr & arr1 = gm1->m_arrangements[i]; Arr & arr2 = gm2->m_arrangements[i]; #if 0 Arr_halfedge_const_iterator hi; std::cout << "Arrangement 1" << std::endl; for (hi = arr1.halfedges_begin(); hi != arr1.halfedges_end(); ++hi) std::cout << hi->curve() << std::endl; std::cout << "Arrangement 2" << std::endl; for (hi = arr2.halfedges_begin(); hi != arr2.halfedges_end(); ++hi) std::cout << hi->curve() << std::endl; #endif // Compute the overlay: Polyhedral_cgm_overlay cgm_overlay; cgm_overlay.set_face_id(i); CGAL::overlay(arr1, arr2, arr, cgm_overlay); } } /*! \brief computes the orientation of a point relative to the polyhedron */ CGAL::Oriented_side oriented_side(const Point_3 & p) { for (unsigned int i = 0; i < NUM_FACES; i++) { const Arr & pm = m_arrangements[i]; Arr_vertex_const_iterator vit; for (vit = pm.vertices_begin(); vit != pm.vertices_end(); ++vit) { if (!vit->get_is_real()) continue; const Plane_3 & plane = vit->get_plane(); CGAL::Oriented_side side = plane.oriented_side(p); if (side == CGAL::ON_NEGATIVE_SIDE) continue; return side; } } return CGAL::ON_NEGATIVE_SIDE; } /*! Compute the orientation of a point relative to the polyhedron * \param p the query point * \param dual if hint is true, the projection of a normal vector onto the * unit cube used as a hint, or a starting point. We start the local walk on * the polyhedron surface with this facet. The ending facet is returned * through this reference parameter. * \param hint indicates whether the dual is a valid hint. * \return the side orientation of the given point with respect to the * polyhedron. One of ON_ORIENTED_BOUNDARY, CGAL, ON_POSITIVE_SIDE, or * ON_NEGATIVE_SIDE */ CGAL::Oriented_side oriented_side(const Point_3 & p, Projected_normal & dual, bool hint) { #if 0 if (!hint) { if (m_dirty_center) calculate_center(); Point_3 origin(CGAL::ORIGIN); if (m_center == origin) return CGAL::ON_NEGATIVE_SIDE; Vector_3 normal = p - m_center; dual.compute_projection(normal); } // Find the id of the first arrangement the point maps to: unsigned int faces_mask = dual.get_faces_mask(); unsigned int id; for (id = 0; id < NUM_FACES; ++id) if (faces_mask & s_mask[id]) break; CGAL_assertion(id < NUM_FACES); // Map the projected normal to a planar point in the respective arrangement: const Point_3 & proj_p = dual.get_projected_normal(); unsigned int j = (id + 1) % 3; unsigned int k = (id + 2) % 3; Point_2 planar_p = (id < 3) ? Point_2(proj_p[k], proj_p[j]) : Point_2(proj_p[j], proj_p[k]); // Find the vertex that is a mapping of a facet and is near the planar // point: Vertex_handle vh = find_nearest_real_vertex(id, planar_p); unsigned int deg = degree(vh); Arr_halfedge_around_vertex_const_circulator hecs[deg]; if (vh->get_is_real()) { Arr::Halfedge_around_vertex_const_circulator hec = vh->incident_halfedges(); Arr_halfedge_around_vertex_const_circulator hec_start = hec; unsigned int l = 0; do { hecs[l++] = hec++; } while (hec != hec_start); } else { Halfedge_around_vertex_collector collector(hecs); process_boundary_halfedges(vh, collector); } T_Kernel::Ray_3 ray(m_center, p); const Plane_3 & plane = vh->get_plane(); T_Kernel kernel; CGAL::Object res = kernel.intersect_2_object()(plane, ray); const Point_3 * q3_ptr = CGAL::object_cast(&res)); CGAL_assertion(q3_ptr != NULL); Point_2 q2 = plane.to_2d(*q3_ptr); Point_2 poly[deg]; for (unsigned int l = 0; l < deg; ++l) { poly[l] = plane.to_2d(hecs[l]->face()->get_point()); } CGAL::Oriented_side side = CGAL::oriented_side_2(poly, &poly[deg], q2, kernel); if (side != CGAL::ON_POSITIVE_SIDE) { std::cout << "known!" << std::endl; return plane.oriented_side(p); } #endif std::cout << "Unknown" << std::endl; return CGAL::ON_ORIENTED_BOUNDARY; } /*! \brief returns the degree of a given vertex */ unsigned int degree(Arr_vertex_const_handle vh) { if (vh->get_location() == Arr_vertex::Interior) return vh->degree(); unsigned int counter = 0; Halfedge_around_vertex_const_circulator hec(vh->incident_halfedges()); Halfedge_around_vertex_const_circulator begin_hec = hec; do { counter++; ++hec; } while (hec != begin_hec); return counter; } /*! \brief obtains the number of (primal) vertices */ unsigned int number_of_vertices() { // Reset the "visited" flag: reset_faces(); // Count them: Face_nop_op op; unsigned int dual_faces_num = 0; for (unsigned int i = 0; i < NUM_FACES; i++) { Arr & pm = m_arrangements[i]; Arr_face_handle fi = pm.faces_begin(); // Skip the unbounded face for (fi++; fi != pm.faces_end(); fi++) { if (fi->get_is_set()) continue; dual_faces_num++; process_boundary_faces(fi, op); } } return dual_faces_num; } /*! \brief obtains the number of (primal) edges */ unsigned int number_of_edges() { unsigned int number_of_halfedges = 0; unsigned int num_real_edges = 0; for (unsigned int i = 0; i < NUM_FACES; i++) { const Arr & pm = m_arrangements[i]; // Traverse all halfedge: Arr_halfedge_const_iterator he; for (he = pm.halfedges_begin(); he != pm.halfedges_end(); ++he) { if (he->get_is_real() && he->source()->get_is_real()) { number_of_halfedges++; } } /* Traverse the most outer boundary of the connected component. That is, * the cubeic face. Each real halfedge on this path is counted twice * above, and must be subtracted from the total accordingly */ // Find the first halfedge incident to the unbounded face: Arr_vertex_const_handle vh = m_corner_vertices[i][0]; Arr_halfedge_around_vertex_const_circulator hec = vh->incident_halfedges(); Arr_halfedge_around_vertex_const_circulator begin_hec = hec; do { if (hec->face()->is_unbounded()) break; ++hec; } while (hec != begin_hec); CGAL_assertion(hec->face()->is_unbounded()); // Traverse the most outer boundary of the connected component: begin_hec = hec; do { if (hec->get_is_real()) num_real_edges++; hec = hec->next(); } while (hec != begin_hec); } return number_of_halfedges / 2 - num_real_edges / 2; } /*! \brief obtains the number of (primal) facecs */ unsigned int number_of_facets() const { unsigned int i; unsigned int dual_vertices_num = 0; unsigned int dual_corner_vertices_num = 0; unsigned int dual_edge_vertices_num = 0; for (i = 0; i < NUM_FACES; i++) { const Arr & pm = m_arrangements[i]; Arr_vertex_const_iterator vit; for (vit = pm.vertices_begin(); vit != pm.vertices_end(); ++vit) { if (vit->get_is_real()) { dual_vertices_num++; if (vit->get_location() == Arr_vertex::Corner) dual_corner_vertices_num++; else if (vit->get_location() == Arr_vertex::Edge) dual_edge_vertices_num++; } } } // Corner vertices are counted 3 times and edge vertices are counted twice: return dual_vertices_num - dual_edge_vertices_num / 2 - 2 * dual_corner_vertices_num / 3; } /*! \brief print statistics */ void print_stat() { #if 1 Base::print_stat(); unsigned int faces_num = number_of_facets(); unsigned int edges_num = number_of_edges(); unsigned int vertices_num = number_of_vertices(); std::cout << "Polyhedron" << ", no. facets: " << faces_num << ", no. edges: " << edges_num << ", no. vertices: " << vertices_num << std::endl; #endif #if 0 if (!m_dirty_polyhedron) { CGAL_assertion(vertices_num == m_polyhedron.size_of_vertices()); CGAL_assertion(edges_num == m_polyhedron.size_of_halfedges()/2); CGAL_assertion(faces_num == m_polyhedron.size_of_facets()); } #endif } /*! Set the marked-vertex index */ void set_marked_vertex_index(unsigned int id) {m_marked_vertex_index = id;} /*! Set the marked-edge index */ void set_marked_edge_index(unsigned int id) {m_marked_edge_index = id;} /*! Set the marked-face index */ void set_marked_facet_index(unsigned int id) {m_marked_facet_index = id;} /*! Handle the introduction of a new boundary edge */ virtual void handle_new_boundary_edge(Arr_halfedge_handle edge) { if (!edge->face()->is_unbounded()) { edge->face()->set_point(m_trg_vertex->point()); if (m_change_notification) { m_change_notification->update_dual_vertex(m_trg_vertex, edge->face()); m_change_notification->update_dual_halfedge(m_halfedge, edge); } } else { edge->twin()->face()->set_point(m_src_vertex->point()); if (m_change_notification) { m_change_notification->update_dual_vertex(m_src_vertex, edge->twin()->face()); m_change_notification->update_dual_halfedge(m_halfedge, edge->twin()); } } } /*! Handle the introduction of a new edge */ virtual void handle_new_edge(Arr_halfedge_handle edge) { Arr_face_handle src_face = edge->twin()->face(); Arr_face_handle trg_face = edge->face(); src_face->set_point(m_src_vertex->point()); trg_face->set_point(m_trg_vertex->point()); if (m_change_notification) { m_change_notification->update_dual_vertex(m_src_vertex, src_face); m_change_notification->update_dual_vertex(m_trg_vertex, trg_face); m_change_notification->update_dual_halfedge(m_halfedge, edge); m_change_notification->update_dual_halfedge(m_halfedge, edge->twin()); } } }; #if 0 /*! output operator */ inline std::ostream & operator<<(std::ostream & os, const Cubical_gaussian_map_3::Projected_normal & dual) { return os << dual.get_projected_normal() << ", " << std::hex << dual.get_faces_mask() << ", " << dual.get_num_faces(); } #endif #if 0 //! \todo This doesn't work for some reasons??? /*! Exporter * Recall that default template arguments may not be used in function templates */ template #endif class T_Dcel> inline std::ostream & operator << (std::ostream & out, const Cubical_gaussian_map_3 & cgm) { typedef Cubical_gaussian_map_3 Cgm; for (unsigned int i = 0; i < Cubical_gaussian_map_3::NUM_FACES; ++i) { const typename Cgm::Arrangement & pm = cgm.get_arrangement(i); out << pm; } return out; } /*! Importer * Recall that default template arguments may not be used in function templates */ template #endif class T_Dcel> inline std::istream & operator >> (std::istream & in, Cubical_gaussian_map_3 & cgm) { typedef Cubical_gaussian_map_3 Cgm; for (unsigned int i = 0; i < Cubical_gaussian_map_3::NUM_FACES; ++i) { const typename Cgm::Arrangement & pm = cgm.get_arrangement(i); pm >> in; } return in; } #endif CGAL_END_NAMESPACE #endif