mirror of https://github.com/CGAL/cgal
1212 lines
39 KiB
C++
1212 lines
39 KiB
C++
// 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 <efif@post.tau.ac.il>
|
|
|
|
/*!
|
|
* 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 <CGAL/Polyhedron_incremental_builder_3.h>
|
|
#include <CGAL/Polyhedron_traits_with_normals_3.h>
|
|
#include <CGAL/Polyhedron_3.h>
|
|
#include <CGAL/HalfedgeDS_vector.h>
|
|
#include <CGAL/IO/Polyhedron_iostream.h>
|
|
#include <CGAL/HalfedgeDS_face_base.h>
|
|
#include <CGAL/Point_3.h>
|
|
#include "CGAL/Aff_transformation_3.h"
|
|
#include <CGAL/aff_transformation_tags.h>
|
|
#include <CGAL/intersections.h>
|
|
#include <CGAL/Polygon_2_algorithms.h>
|
|
|
|
#include <CGAL/Arr_overlay.h>
|
|
#include <CGAL/Cubical_gaussian_map_3.h>
|
|
#include <CGAL/Polyhedral_cgm_arr_dcel.h>
|
|
#include <CGAL/Polyhedral_cgm_overlay.h>
|
|
#include <CGAL/Polyhedral_cgm_change_notification.h>
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <list>
|
|
#include <iostream>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class T_Kernel,
|
|
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
|
|
template <class T>
|
|
#endif
|
|
class T_Dcel = Polyhedral_cgm_arr_dcel>
|
|
class Polyhedral_cgm : public Cubical_gaussian_map_3<T_Kernel,T_Dcel> {
|
|
private:
|
|
typedef Cubical_gaussian_map_3<T_Kernel, T_Dcel> Base;
|
|
typedef Polyhedral_cgm<T_Kernel, T_Dcel> Self;
|
|
|
|
public:
|
|
// Arrangement traits and types:
|
|
typedef typename Base::Arr_traits Arr_traits;
|
|
|
|
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
|
|
typedef T_Dcel<Arr_traits> Dcel;
|
|
#else
|
|
typedef typename T_Dcel::template Dcel<Arr_traits> 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<Self> Change_notification;
|
|
|
|
typedef Polyhedral_cgm_overlay<Self> 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_NT> 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 <class Facet>
|
|
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 <class Refs>
|
|
struct Polyhedron_3_vertex :
|
|
public CGAL::HalfedgeDS_vertex_base<Refs, Tag_true, Point_3>
|
|
{
|
|
typedef CGAL::HalfedgeDS_vertex_base<Refs, Tag_true, Point_3> 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 <class Refs>
|
|
struct Polyhedron_3_halfedge : public CGAL::HalfedgeDS_halfedge_base<Refs> {
|
|
|
|
/*! */
|
|
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 Refs>
|
|
class Polyhedron_3_face :
|
|
public CGAL::HalfedgeDS_face_base<Refs, Tag_true, Vector_3>
|
|
{
|
|
private:
|
|
/*! */
|
|
Projected_normal m_dual;
|
|
|
|
/*! Indicates whether it is a marked face */
|
|
bool m_marked;
|
|
|
|
public:
|
|
typedef CGAL::HalfedgeDS_face_base<Refs, Tag_true, Vector_3> 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 <class Refs, class T_Traits>
|
|
struct Vertex_wrapper {
|
|
typedef Polyhedron_3_vertex<Refs> Vertex;
|
|
};
|
|
template <class Refs, class T_Traits>
|
|
struct Halfedge_wrapper {
|
|
typedef Polyhedron_3_halfedge<Refs> Halfedge;
|
|
};
|
|
template <class Refs, class T_Traits>
|
|
struct Face_wrapper {
|
|
typedef Polyhedron_3_face<Refs> Face;
|
|
};
|
|
};
|
|
|
|
public:
|
|
// Polyhedron public types and methods:
|
|
|
|
typedef CGAL::Polyhedron_traits_with_normals_3<T_Kernel> Polyhedron_traits;
|
|
typedef CGAL::Polyhedron_3<Polyhedron_traits,Polyhedron_items>
|
|
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 HDS, class T_Point_3_iter>
|
|
class Add {
|
|
private:
|
|
typedef CGAL::Polyhedron_incremental_builder_3<HDS> 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 HDS>
|
|
class Add<HDS, Point_3 *> {
|
|
private:
|
|
typedef CGAL::Polyhedron_incremental_builder_3<HDS> 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 HDS, class Point_3_iter>
|
|
class Build_surface : public CGAL::Modifier_base<HDS> {
|
|
private:
|
|
typedef CGAL::Polyhedron_incremental_builder_3<HDS> 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<HDS, Point_3_iter> 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 <class Point_3_iterator>
|
|
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<Polyhedron_halfedgeds,Point_3_iterator>
|
|
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 <class Point_3_iterator>
|
|
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<Point_3>(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 <class Op>
|
|
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 <class Cgm_iter_>
|
|
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 <class Cgm_iter_>
|
|
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
|
|
<Arr::Halfedge_around_vertex_const_circulator*> 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<Point_3>(&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 <class T_Traits,
|
|
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
|
|
template <class T>
|
|
#endif
|
|
class T_Dcel>
|
|
inline
|
|
std::ostream & operator << (std::ostream & out,
|
|
const Cubical_gaussian_map_3<T_Traits,T_Dcel> & cgm)
|
|
{
|
|
typedef Cubical_gaussian_map_3<T_Traits,T_Dcel> 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 <class T_Traits,
|
|
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
|
|
template <class T>
|
|
#endif
|
|
class T_Dcel>
|
|
inline
|
|
std::istream & operator >> (std::istream & in,
|
|
Cubical_gaussian_map_3<T_Traits,T_Dcel> & cgm)
|
|
{
|
|
typedef Cubical_gaussian_map_3<T_Traits,T_Dcel> 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
|