mirror of https://github.com/CGAL/cgal
1464 lines
38 KiB
C++
1464 lines
38 KiB
C++
// Copyright (c) 1997 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.
|
|
//
|
|
// $Source$
|
|
// $Revision$ $Date$
|
|
// $Name$
|
|
//
|
|
// Author(s) : Iddo Hanniel <hanniel@math.tau.ac.il>
|
|
// Oren Nechushtan <theoren@math.tau.ac.il>
|
|
#ifndef CGAL_TOPOLOGICAL_MAP_H
|
|
#define CGAL_TOPOLOGICAL_MAP_H
|
|
|
|
#include <CGAL/HalfedgeDS_iterator.h>
|
|
#include <CGAL/Planar_map_2/Pm_traits_wrap_2.h>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class Dcel >
|
|
class Topological_map
|
|
{
|
|
|
|
protected:
|
|
typedef typename Dcel::Vertex dvertex;
|
|
typedef typename Dcel::Halfedge dedge;
|
|
typedef typename Dcel::Face dface;
|
|
|
|
public:
|
|
typedef typename Dcel::Size Size;
|
|
typedef typename Dcel::size_type size_type;
|
|
typedef typename Dcel::difference_type difference_type;
|
|
typedef typename Dcel::difference_type Difference;
|
|
|
|
typedef typename Dcel::iterator_category iterator_category;
|
|
|
|
// These extra (internal) typedefs are necessary to make
|
|
// SunPro CC 4.2 happy. (And they are used.)
|
|
typedef typename Dcel::Vertex_iterator TR_VI;
|
|
typedef typename Dcel::Vertex_const_iterator TR_C_VI;
|
|
|
|
typedef typename Dcel::Halfedge_iterator TR_HI;
|
|
typedef typename Dcel::Halfedge_const_iterator TR_C_HI;
|
|
|
|
typedef typename Dcel::Edge_iterator TR_EI;
|
|
typedef typename Dcel::Edge_const_iterator TR_C_EI;
|
|
|
|
typedef typename Dcel::Face_iterator TR_FI;
|
|
typedef typename Dcel::Face_const_iterator TR_C_FI;
|
|
|
|
typedef typename Dcel::Face::Holes_iterator TR_HOI;
|
|
typedef typename Dcel::Face::Holes_const_iterator TR_C_HOI;
|
|
|
|
public:
|
|
class Vertex;
|
|
class Halfedge;
|
|
class Face;
|
|
|
|
//in VC class's private members aren't available in nested classes
|
|
#if _MSC_VER>=1100
|
|
friend Face;
|
|
#endif
|
|
|
|
typedef I_HalfedgeDS_iterator<
|
|
TR_VI,
|
|
Vertex,
|
|
Difference, iterator_category> Vertex_iterator;
|
|
|
|
typedef I_HalfedgeDS_const_iterator<
|
|
TR_C_VI, TR_VI,
|
|
Vertex,
|
|
Difference, iterator_category> Vertex_const_iterator;
|
|
|
|
typedef I_HalfedgeDS_iterator<
|
|
TR_HI,
|
|
Halfedge,
|
|
Difference, iterator_category> Halfedge_iterator;
|
|
|
|
typedef I_HalfedgeDS_const_iterator<
|
|
TR_C_HI, TR_HI,
|
|
Halfedge,
|
|
Difference, iterator_category> Halfedge_const_iterator;
|
|
|
|
typedef I_HalfedgeDS_iterator<
|
|
TR_EI,
|
|
Halfedge,
|
|
Difference, iterator_category> Edge_iterator;
|
|
|
|
typedef I_HalfedgeDS_const_iterator<
|
|
TR_C_EI, TR_EI,
|
|
Halfedge,
|
|
Difference, iterator_category> Edge_const_iterator;
|
|
|
|
typedef I_HalfedgeDS_iterator<
|
|
TR_FI,
|
|
Face,
|
|
Difference, iterator_category> Face_iterator;
|
|
|
|
typedef I_HalfedgeDS_const_iterator<
|
|
TR_C_FI, TR_FI,
|
|
Face,
|
|
Difference, iterator_category> Face_const_iterator;
|
|
|
|
typedef _HalfedgeDS_facet_circ<
|
|
Halfedge,
|
|
Halfedge_iterator,
|
|
Forward_circulator_tag> Ccb_halfedge_circulator;
|
|
|
|
typedef _HalfedgeDS_vertex_circ<
|
|
Halfedge,
|
|
Halfedge_iterator,
|
|
Forward_circulator_tag> Halfedge_around_vertex_circulator;
|
|
|
|
typedef _HalfedgeDS_facet_const_circ<
|
|
Halfedge,
|
|
Halfedge_const_iterator,
|
|
Forward_circulator_tag> Ccb_halfedge_const_circulator;
|
|
|
|
typedef _HalfedgeDS_vertex_const_circ<
|
|
Halfedge,
|
|
Halfedge_const_iterator,
|
|
Forward_circulator_tag> Halfedge_around_vertex_const_circulator;
|
|
|
|
typedef I_HalfedgeDS_iterator<
|
|
TR_HOI,
|
|
Ccb_halfedge_circulator,
|
|
Difference, std::bidirectional_iterator_tag> Holes_iterator;
|
|
|
|
typedef I_HalfedgeDS_const_iterator<
|
|
TR_C_HOI, TR_HOI,
|
|
Ccb_halfedge_const_circulator,
|
|
Difference, std::bidirectional_iterator_tag> Holes_const_iterator;
|
|
|
|
|
|
|
|
typedef Vertex_iterator Vertex_handle;
|
|
typedef Halfedge_iterator Halfedge_handle;
|
|
typedef Face_iterator Face_handle;
|
|
|
|
typedef Vertex_const_iterator Vertex_const_handle;
|
|
typedef Halfedge_const_iterator Halfedge_const_handle;
|
|
typedef Face_const_iterator Face_const_handle;
|
|
|
|
|
|
/**************************************************************/
|
|
/********************* V e r t e x ****************************/
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
class Vertex : public Dcel::Vertex
|
|
{
|
|
public:
|
|
typedef typename Dcel::Vertex Base;
|
|
|
|
Vertex()
|
|
{}
|
|
|
|
|
|
// Vertex(dvertex *v) : dvertex(*v)
|
|
Vertex(Base *v) : Base(*v)
|
|
{}
|
|
|
|
|
|
// Vertex(dvertex& v) : dvertex(v)
|
|
Vertex(Base& v) : Base(v)
|
|
{}
|
|
|
|
|
|
bool is_incident_edge(Halfedge_const_handle e) const
|
|
{
|
|
return (&(*(e->source())) == this) || (&(*(e->target())) == this);
|
|
}
|
|
|
|
bool is_incident_face(Face_const_handle f) const
|
|
{
|
|
// const typename Dcel::Halfedge* e_ptr=(dvertex::halfedge());
|
|
const typename Dcel::Halfedge* e_ptr=(Base::halfedge());
|
|
|
|
do{
|
|
if ( e_ptr->face() == &(*f) )
|
|
return true;
|
|
|
|
e_ptr=e_ptr->opposite()->next();
|
|
// } while (e_ptr != dvertex::halfedge());
|
|
} while (e_ptr != Base::halfedge());
|
|
|
|
return false;
|
|
}
|
|
|
|
unsigned int degree() const
|
|
{
|
|
// const typename Dcel::Halfedge* e=dvertex::halfedge();
|
|
const typename Dcel::Halfedge* e=Base::halfedge();
|
|
const typename Dcel::Halfedge* e1=e;
|
|
int n=0;
|
|
if (e1!=NULL)
|
|
{
|
|
do {
|
|
n++;
|
|
e1=e1->next()->opposite();
|
|
} while (e1!=e);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
Halfedge_around_vertex_circulator incident_halfedges()
|
|
{
|
|
//return Halfedge_around_vertex_circulator(TR_HI(dvertex::halfedge()));
|
|
return Halfedge_around_vertex_circulator(TR_HI(Base::halfedge()));
|
|
}
|
|
|
|
Halfedge_around_vertex_const_circulator incident_halfedges() const
|
|
{
|
|
//return
|
|
//Halfedge_around_vertex_const_circulator(TR_C_HI(dvertex::halfedge()));
|
|
return
|
|
Halfedge_around_vertex_const_circulator(TR_C_HI(Base::halfedge()));
|
|
}
|
|
|
|
private:
|
|
// void set_halfedge(Halfedge* h) {dvertex::set_halfedge(h);}
|
|
void set_halfedge(Halfedge* h) {Base::set_halfedge(h);}
|
|
|
|
};
|
|
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
/********************* Halfedge *******************************/
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
class Halfedge : public Dcel::Halfedge
|
|
{
|
|
public:
|
|
typedef typename Dcel::Halfedge Base;
|
|
|
|
Halfedge()
|
|
{}
|
|
|
|
// Halfedge(dedge *e) : dedge(*e) {}
|
|
Halfedge(Base *e) : Base(*e) {}
|
|
|
|
// Halfedge(dedge& e) : dedge(e) {}
|
|
Halfedge(Base& e) : Base(e) {}
|
|
|
|
|
|
Vertex_handle source()
|
|
{
|
|
// return TR_VI(dedge::opposite()->vertex());
|
|
return TR_VI(Base::opposite()->vertex());
|
|
}
|
|
|
|
Vertex_const_handle source() const
|
|
{
|
|
// return TR_C_VI(dedge::opposite()->vertex());
|
|
return TR_C_VI(Base::opposite()->vertex());
|
|
}
|
|
|
|
Vertex_handle target()
|
|
{
|
|
//return TR_VI(dedge::vertex());
|
|
return TR_VI(Base::vertex());
|
|
}
|
|
|
|
Vertex_const_handle target() const
|
|
{
|
|
//return TR_C_VI(dedge::vertex());
|
|
return TR_C_VI(Base::vertex());
|
|
}
|
|
|
|
Face_handle face()
|
|
{
|
|
//return TR_FI(dedge::face());
|
|
return TR_FI(Base::face());
|
|
}
|
|
|
|
Face_const_handle face() const
|
|
{
|
|
//return TR_C_FI(dedge::face());
|
|
return TR_C_FI(Base::face());
|
|
}
|
|
|
|
Halfedge_handle twin()
|
|
{
|
|
//return TR_HI(dedge::opposite());
|
|
return TR_HI(Base::opposite());
|
|
}
|
|
|
|
Halfedge_const_handle twin() const
|
|
{
|
|
//return TR_C_HI(dedge::opposite());
|
|
return TR_C_HI(Base::opposite());
|
|
}
|
|
|
|
Halfedge_handle next_halfedge()
|
|
{
|
|
//return TR_HI(dedge::next());
|
|
return TR_HI(Base::next());
|
|
}
|
|
|
|
Halfedge_const_handle next_halfedge() const
|
|
{
|
|
//return TR_C_HI(dedge::next());
|
|
return TR_C_HI(Base::next());
|
|
}
|
|
|
|
|
|
Ccb_halfedge_circulator ccb()
|
|
{
|
|
return Ccb_halfedge_circulator(TR_HI(this));
|
|
}
|
|
|
|
Ccb_halfedge_const_circulator ccb() const
|
|
{
|
|
return Ccb_halfedge_const_circulator(TR_C_HI(this));
|
|
}
|
|
|
|
|
|
private: //hide from users the underlying structure
|
|
//void set_next( Halfedge* h) { dedge::set_next(h);}
|
|
void set_next( Halfedge* h) { Base::set_next(h);}
|
|
//void set_vertex( Vertex* ve) { dedge::set_vertex(ve);}
|
|
void set_vertex( Vertex* ve) { Base::set_vertex(ve);}
|
|
//void set_face( Face* face) { dedge::set_face(face);}
|
|
void set_face( Face* face) { Base::set_face(face);}
|
|
|
|
};
|
|
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
/********************* F a c e ********************************/
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
class Face : public Dcel::Face
|
|
{
|
|
public:
|
|
typedef typename Dcel::Face Base;
|
|
|
|
#ifndef _MSC_VER
|
|
// the following two typedefs are needed for compilation on irix64 (CC7.30)
|
|
typedef typename Topological_map<Dcel>::Holes_iterator
|
|
Holes_iterator;
|
|
typedef typename Topological_map<Dcel>::Holes_const_iterator
|
|
Holes_const_iterator;
|
|
#endif
|
|
|
|
Face()
|
|
{}
|
|
|
|
Face(Base *f) : Base(*f) {}
|
|
|
|
Face(Base& f) : Base(f) {}
|
|
|
|
|
|
bool is_unbounded() const
|
|
{
|
|
// face is not bounded iff it has no outer boundary
|
|
return (Base::halfedge() == NULL);
|
|
}
|
|
|
|
|
|
// must explicitly say Topological_map::Holes_iterator. Otherwise
|
|
// the CC compiler thinks we mean Base::Holes_iterator.
|
|
Holes_iterator holes_begin()
|
|
{
|
|
return TR_HOI(Base::holes_begin());
|
|
}
|
|
|
|
Holes_const_iterator holes_begin() const
|
|
{
|
|
return TR_C_HOI(Base::holes_begin());
|
|
}
|
|
|
|
Holes_iterator holes_end()
|
|
{
|
|
return TR_HOI(Base::holes_end());
|
|
}
|
|
|
|
Holes_const_iterator holes_end() const
|
|
{
|
|
return TR_C_HOI(Base::holes_end());
|
|
}
|
|
|
|
bool is_halfedge_on_inner_ccb(Halfedge_const_handle e)
|
|
#if !(_MSC_VER>=1100)
|
|
const
|
|
#endif
|
|
|
|
{
|
|
dedge* dummy;
|
|
return (/*Topological_map<Dcel>::*/
|
|
is_halfedge_on_inner_ccb(&(*e),
|
|
(typename Dcel::Face*)this,
|
|
dummy));
|
|
// oren corrections (dummy parameter - for bug in MSC)
|
|
}
|
|
|
|
bool is_halfedge_on_outer_ccb(Halfedge_const_handle e)
|
|
#if !(_MSC_VER>=1100)
|
|
const
|
|
#endif
|
|
{
|
|
dedge* dummy;
|
|
return /*Topological_map<Dcel>::*/
|
|
is_halfedge_on_outer_ccb(&(*e),this,dummy);
|
|
// oren corrections (dummy parameter - bug in MSC)
|
|
}
|
|
|
|
bool does_outer_ccb_exist() const
|
|
{
|
|
return Base::halfedge() != NULL;
|
|
}
|
|
|
|
Halfedge_handle halfedge_on_outer_ccb()
|
|
{
|
|
CGAL_precondition(does_outer_ccb_exist());
|
|
return TR_HI(Base::halfedge());
|
|
}
|
|
|
|
Halfedge_const_handle halfedge_on_outer_ccb() const
|
|
{
|
|
CGAL_precondition(does_outer_ccb_exist());
|
|
return TR_C_HI(Base::halfedge());
|
|
}
|
|
|
|
|
|
Ccb_halfedge_circulator outer_ccb()
|
|
{
|
|
CGAL_precondition(does_outer_ccb_exist());
|
|
return (halfedge_on_outer_ccb())->ccb();
|
|
}
|
|
|
|
Ccb_halfedge_const_circulator outer_ccb() const
|
|
{
|
|
CGAL_precondition(does_outer_ccb_exist());
|
|
return (halfedge_on_outer_ccb())->ccb();
|
|
}
|
|
|
|
private:
|
|
void set_halfedge( Halfedge* h) { Base::set_halfedge(h);}
|
|
|
|
void add_hole(Halfedge* h) {Base::add_hole(h);}
|
|
|
|
};
|
|
|
|
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
/********************* Topological_map *******************/
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
|
|
Topological_map()
|
|
: d()
|
|
{
|
|
u_face = d.new_face();
|
|
u_face->set_halfedge(NULL);
|
|
}
|
|
|
|
|
|
|
|
//INSERTIONS
|
|
|
|
|
|
//insertion from vertices may invalidate the holes containers (since a new
|
|
//face can be created which contains some of the holes of the old face.
|
|
//to validate the containers the function move_hole should be called.
|
|
|
|
//if a new face is created, returns the halfedge on the new face.
|
|
//the new face will ALWAYS (by definition) be the one from v1->v2 (==e1)
|
|
//this sets a requirement on the user!!! (since a topological pm can't
|
|
//know if v1->v2 is on the new face or v2->v1)
|
|
|
|
//since there can be a number of edges from the vertices, and we can't
|
|
//know topologically which will be in the new face and which will be
|
|
//outside, this should be provided by the user - defining prev1 and
|
|
//prev2 (previous to v1,v2 resp.) the planar map will define this
|
|
//geometrically using the one previous to the curve clock wise.
|
|
|
|
Halfedge_handle insert_at_vertices( Halfedge_handle previous1,
|
|
Halfedge_handle previous2) ;
|
|
//moves ONE hole from f1 to f2
|
|
void move_hole(Holes_iterator e, Face_handle f1, Face_handle f2);
|
|
|
|
|
|
Halfedge_handle insert_from_vertex(Halfedge_handle previous) ;
|
|
|
|
Halfedge_handle insert_in_face_interior(Face_handle f) ;
|
|
|
|
|
|
Halfedge_handle split_edge (Halfedge_handle e ) ;
|
|
|
|
Halfedge_handle merge_edge (Halfedge_handle e1, Halfedge_handle e2) ;
|
|
|
|
//returns the merged face after the deletion
|
|
Face_handle remove_edge(Halfedge_handle e) ;
|
|
|
|
|
|
Face_handle unbounded_face()
|
|
{
|
|
return TR_FI(u_face);
|
|
}
|
|
|
|
Face_const_handle unbounded_face() const {
|
|
return TR_C_FI(u_face);
|
|
}
|
|
|
|
Face_iterator faces_begin()
|
|
{
|
|
return TR_FI(d.faces_begin());
|
|
}
|
|
|
|
Face_const_iterator faces_begin() const
|
|
{
|
|
return TR_C_FI(d.faces_begin());
|
|
}
|
|
|
|
Face_iterator faces_end()
|
|
{
|
|
return TR_FI(d.faces_end());
|
|
}
|
|
|
|
Face_const_iterator faces_end() const
|
|
{
|
|
return TR_C_FI(d.faces_end());
|
|
}
|
|
|
|
Halfedge_iterator halfedges_begin()
|
|
{
|
|
return TR_HI(d.halfedges_begin());
|
|
}
|
|
|
|
Halfedge_const_iterator halfedges_begin() const
|
|
{
|
|
return TR_C_HI(d.halfedges_begin());
|
|
}
|
|
|
|
Halfedge_iterator halfedges_end()
|
|
{
|
|
return TR_HI(d.halfedges_end());
|
|
}
|
|
|
|
Halfedge_const_iterator halfedges_end() const
|
|
{
|
|
return TR_C_HI(d.halfedges_end());
|
|
}
|
|
|
|
Edge_iterator edges_begin()
|
|
{
|
|
return TR_EI(d.edges_begin());
|
|
}
|
|
|
|
Edge_const_iterator edges_begin() const
|
|
{
|
|
return TR_C_EI(d.edges_begin());
|
|
}
|
|
|
|
Edge_iterator edges_end()
|
|
{
|
|
return TR_EI(d.edges_end());
|
|
}
|
|
|
|
Edge_const_iterator edges_end() const
|
|
{
|
|
return TR_C_EI(d.edges_end());
|
|
}
|
|
|
|
Vertex_iterator vertices_begin()
|
|
{
|
|
return TR_VI(d.vertices_begin());
|
|
}
|
|
|
|
Vertex_const_iterator vertices_begin() const
|
|
{
|
|
return TR_C_VI(d.vertices_begin());
|
|
}
|
|
|
|
Vertex_iterator vertices_end()
|
|
{
|
|
return TR_VI(d.vertices_end());
|
|
}
|
|
|
|
Vertex_const_iterator vertices_end() const
|
|
{
|
|
return TR_C_VI(d.vertices_end());
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
d.delete_all();
|
|
u_face = NULL;
|
|
u_face = d.new_face();
|
|
u_face->set_halfedge(NULL);
|
|
}
|
|
|
|
void assign(const Topological_map<Dcel> &tpm)
|
|
{
|
|
d.delete_all();
|
|
u_face = NULL;
|
|
u_face = (Face*)d.assign(tpm.d, tpm.u_face);
|
|
}
|
|
|
|
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
/*********** Topological_map_2 - validity checks ********/
|
|
/**************************************************************/
|
|
/**************************************************************/
|
|
|
|
bool is_valid(Vertex_const_handle v
|
|
#if _MSC_VER>=1100 // VC template bug
|
|
,Vertex* dummy=NULL
|
|
#endif
|
|
) const
|
|
{
|
|
bool valid = true;
|
|
|
|
// check if every edge from v has v as its target
|
|
Halfedge_around_vertex_const_circulator ec = v->incident_halfedges();
|
|
Halfedge_around_vertex_const_circulator start = ec;
|
|
do {
|
|
if ((*ec).target() != v)
|
|
{
|
|
valid = false;
|
|
}
|
|
++ec;
|
|
} while (ec != start);
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
bool is_valid(Halfedge_const_handle e
|
|
#if _MSC_VER>=1100 // VC template bug
|
|
,Halfedge* dummy=NULL
|
|
#endif
|
|
) const
|
|
{
|
|
//check relations with next
|
|
if (e->target() != e->next_halfedge()->source())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool is_valid(const Ccb_halfedge_const_circulator& start,
|
|
Face_const_handle f) const
|
|
{
|
|
bool valid = true;
|
|
Ccb_halfedge_const_circulator circ = start;
|
|
|
|
do {
|
|
if ((*circ).face() != f)
|
|
valid = false;
|
|
++circ;
|
|
} while (circ != start);
|
|
|
|
return valid;
|
|
}
|
|
|
|
bool is_valid(Face_const_handle f
|
|
#if _MSC_VER>=1100 // VC template bug
|
|
,Face* dummy=NULL
|
|
#endif
|
|
) const
|
|
|
|
{
|
|
bool valid = true;
|
|
|
|
// check if all edges of f (on all ccb's) refer to f (as their face)
|
|
Holes_const_iterator iccbit;
|
|
Ccb_halfedge_const_circulator ccb_circ;
|
|
|
|
if (f->does_outer_ccb_exist())
|
|
{
|
|
ccb_circ = f->outer_ccb();
|
|
if (!is_valid(ccb_circ, f))
|
|
valid = false;
|
|
}
|
|
|
|
for (iccbit = f->holes_begin(); iccbit != f->holes_end(); ++iccbit)
|
|
{
|
|
ccb_circ = *iccbit;
|
|
if (!is_valid(ccb_circ, f))
|
|
valid = false;
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
bool is_valid() const
|
|
{
|
|
bool valid = true;
|
|
|
|
Vertex_const_iterator vi;
|
|
for (vi = vertices_begin(); vi != vertices_end(); ++vi)
|
|
{
|
|
if (!is_valid(vi))
|
|
{//an iterator is used for a handle
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
Halfedge_const_iterator ei;
|
|
for (ei = halfedges_begin(); ei != halfedges_end(); ++ei)
|
|
{
|
|
if (!is_valid(ei))
|
|
valid = false;
|
|
}
|
|
|
|
Face_const_iterator fi;
|
|
for (fi = faces_begin(); fi != faces_end(); ++fi)
|
|
{
|
|
if (!is_valid(fi))
|
|
valid = false;
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/********************* counting functions ***********************/
|
|
/******************************************************************/
|
|
|
|
Size number_of_faces() const
|
|
{
|
|
return d.size_of_faces();
|
|
}
|
|
|
|
|
|
//counts every halfedge (i.e always even)
|
|
Size number_of_halfedges() const
|
|
{
|
|
return d.size_of_halfedges();
|
|
}
|
|
|
|
Size number_of_vertices() const
|
|
{
|
|
return d.size_of_vertices();
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
//PRIVATE IMPLEMENTATIONS
|
|
//---------------------------------------------------------------
|
|
|
|
private:
|
|
//find previous halfedge of given halfedge
|
|
typename Dcel::Halfedge* get_prev( typename Dcel::Halfedge* de)
|
|
{
|
|
//find previous halfedge of de
|
|
typename Dcel::Halfedge* prev=de;
|
|
do {
|
|
if (prev->next()==de) break;
|
|
prev=prev->next();
|
|
}while (prev!=de); //assumes a loop to itself is unacceptable
|
|
CGAL_assertion(prev!=de);
|
|
|
|
return prev;
|
|
}
|
|
|
|
|
|
bool find_and_erase_hole(typename Dcel::Halfedge* e, typename Dcel::Face* f)
|
|
{
|
|
typename Dcel::Face::Holes_iterator it=f->holes_begin();
|
|
bool ret=false;
|
|
for (; it!=f->holes_end(); ++it) {
|
|
if ( (*it)==e ) {
|
|
f->erase_hole(it);
|
|
ret=true;
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
protected:
|
|
Dcel d;
|
|
dface* u_face;
|
|
};
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// implementation
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
template <class Dcel>
|
|
bool is_halfedge_on_inner_ccb(const typename Dcel::Halfedge* e,
|
|
typename Dcel::Face* f,
|
|
typename Dcel::Halfedge* &iccb)
|
|
{
|
|
typedef typename Dcel::Vertex dvertex;
|
|
typedef typename Dcel::Halfedge dedge;
|
|
typedef typename Dcel::Face dface;
|
|
//move over all holes in face and check
|
|
for (typename dface::Holes_iterator dhi=f->holes_begin();
|
|
dhi!=f->holes_end();
|
|
++dhi)
|
|
{
|
|
iccb=(*dhi);
|
|
const typename Dcel::Halfedge* aux=iccb;
|
|
do
|
|
{
|
|
if (aux==e)
|
|
return true;
|
|
aux=aux->next() ;
|
|
} while (aux!=(*dhi));
|
|
}
|
|
iccb=NULL;
|
|
return false;
|
|
}
|
|
|
|
//returns the representative halfedge of outer ccb in occb, or false
|
|
template <class Dcel>
|
|
bool is_halfedge_on_outer_ccb(const typename Dcel::Halfedge* e,
|
|
typename Dcel::Face* f,
|
|
typename Dcel::Halfedge* &occb)
|
|
{
|
|
typedef typename Dcel::Vertex dvertex;
|
|
typedef typename Dcel::Halfedge dedge;
|
|
typedef typename Dcel::Face dface;
|
|
occb=f->halfedge();
|
|
if ( occb ) { //if f isn't the unbounded face
|
|
const typename Dcel::Halfedge* aux=occb;
|
|
do
|
|
{
|
|
if (aux==e)
|
|
return true;
|
|
aux=aux->next();
|
|
}while (aux!=f->halfedge());
|
|
}
|
|
|
|
occb=NULL;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//insertion from vertices may invalidate the holes containers (since a new
|
|
//face can be created which contains some of the holes of the old face.
|
|
//to validate the containers the function move_hole should be called.
|
|
|
|
|
|
//if a new face is created, returns the halfedge on the new face. the
|
|
//new face will ALWAYS (by definition) be the one from v1->v2
|
|
//(==previous1->e1->..) this sets a requirement on the user!!! (since
|
|
//a topological pm can't know if v1->v2 is on the new face or v2->v1)
|
|
|
|
//since there can be a number of edges from the vertices, and we can't
|
|
//know topologically which will be in the new face and which will be
|
|
//outside, this should be provided by the user - defining prev1 and
|
|
//prev2 (previous to v1,v2 resp.) the planar map will define this
|
|
//geometrically using the one previous to the curve clock wise.
|
|
//prev1->target() is v1
|
|
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Halfedge_handle
|
|
Topological_map<Dcel>::
|
|
insert_at_vertices(Halfedge_handle previous1, Halfedge_handle previous2)
|
|
{
|
|
// vertices should be distinct
|
|
CGAL_precondition(previous1->target()!=previous2->target());
|
|
|
|
typename Dcel::Halfedge *prev1=&(*previous1), *prev2=&(*previous2);
|
|
|
|
typename Dcel::Vertex* dv1=prev1->vertex();
|
|
typename Dcel::Vertex* dv2=prev2->vertex();
|
|
|
|
CGAL_precondition(prev1->face()==prev2->face());
|
|
|
|
typename Dcel::Face* df=prev1->face();
|
|
|
|
//will hold represantative halfedge of prev1/2
|
|
typename Dcel::Halfedge *ccb1,*ccb2;
|
|
if (!(is_halfedge_on_outer_ccb<Dcel>(prev1,df,ccb1)) )
|
|
is_halfedge_on_inner_ccb<Dcel>(prev1,df,ccb1);
|
|
if (!(is_halfedge_on_outer_ccb<Dcel>(prev2,df,ccb2)) )
|
|
is_halfedge_on_inner_ccb<Dcel>(prev2,df,ccb2);
|
|
|
|
|
|
bool ccb1_is_inner = !(ccb1==df->halfedge());
|
|
bool ccbs_equal = (ccb1 == ccb2);
|
|
|
|
typename Dcel::Halfedge* e1=d.new_edge();
|
|
typename Dcel::Halfedge* e2=e1->opposite();
|
|
e1->set_vertex(dv1);
|
|
e2->set_vertex(dv2);
|
|
|
|
e1->set_next(prev1->next());
|
|
e2->set_next(prev2->next());
|
|
|
|
prev1->set_next(e2);
|
|
prev2->set_next(e1);
|
|
|
|
//Cases:
|
|
//a. ccb1!=ccb2 (at least one is inner ccb) - no face added
|
|
if (!ccbs_equal) {
|
|
e1->set_face(df);
|
|
e2->set_face(df);
|
|
|
|
//remove ONE inner ccb from df
|
|
if (ccb1_is_inner) {
|
|
//ccb1 becomes part of ccb2
|
|
find_and_erase_hole(ccb1,df);
|
|
}
|
|
else {
|
|
//ccb2 becomes part of ccb1
|
|
find_and_erase_hole(ccb2,df);
|
|
}
|
|
|
|
return TR_HI(e2);
|
|
}
|
|
|
|
//b. ccb1==ccb2
|
|
//new face is created
|
|
//the new face will ALWAYS (by definition) be the one from v1->v2 (==e2)
|
|
//this sets a requirement on the user!!!
|
|
|
|
//the planar map will define this geometrically
|
|
//(by finding the leftmost halfedge
|
|
//(or left-down) when going from v1 to v2 (visiting v1 only once!!) and
|
|
//checking if it is up or down, if it is up then send v1->v2 else
|
|
//send v2->v1)
|
|
|
|
typename Dcel::Face* nf = d.new_face();
|
|
|
|
//b.1 the vertices are on outer ccb
|
|
if (! ccb1_is_inner) {
|
|
e2->set_face(nf);
|
|
e1->set_face(df);
|
|
|
|
nf->set_halfedge(e2); //set the represantative edge to be e2
|
|
df->set_halfedge(e1);
|
|
|
|
//set the face pointer for all halfedges of e2 to nf
|
|
ccb2=e2->next();
|
|
while (ccb2!=e2)
|
|
{
|
|
ccb2->set_face(nf);
|
|
ccb2=ccb2->next();
|
|
}
|
|
}
|
|
|
|
//b.2 the vertices are on an inner ccb
|
|
else {
|
|
|
|
e1->set_face(df);
|
|
e2->set_face(nf);
|
|
|
|
nf->set_halfedge(e2);
|
|
|
|
ccb2=e2->next();
|
|
while (ccb2!=e2)
|
|
{
|
|
ccb2->set_face(nf);
|
|
ccb2=ccb2->next();
|
|
}
|
|
|
|
//remove ccb1 from holes_container (maybe it is now inside the new face)
|
|
find_and_erase_hole(ccb1,df);
|
|
df->add_hole(e1);
|
|
|
|
}
|
|
|
|
return TR_HI(e2);
|
|
}
|
|
|
|
|
|
template<class Dcel>
|
|
void
|
|
Topological_map<Dcel>::
|
|
move_hole(Holes_iterator e, Face_handle f1, Face_handle f2)
|
|
{
|
|
//move hole from df1 to df2 and set face pointer of each edge on hole to df1
|
|
typename Dcel::Face* df1=&(*f1);
|
|
typename Dcel::Face* df2=&(*f2);
|
|
|
|
//set face pointers to df1
|
|
typename Dcel::Halfedge* last=&(*(*(e)));
|
|
typename Dcel::Halfedge* first=last;
|
|
do {
|
|
first->set_face(df2);
|
|
first=first->next();
|
|
} while (first!=last) ;
|
|
|
|
//copy to df2
|
|
df2->add_hole(first);
|
|
df1->erase_hole(e.current_iterator());
|
|
|
|
}
|
|
|
|
|
|
//returns halfedge which is previous->next
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Halfedge_handle
|
|
Topological_map<Dcel>::
|
|
insert_from_vertex(Halfedge_handle previous)
|
|
{
|
|
typename Dcel::Halfedge* prev=&(*previous);
|
|
typename Dcel::Face* df=prev->face();
|
|
|
|
typename Dcel::Vertex* dv1=prev->vertex();
|
|
|
|
typename Dcel::Vertex* dv2=d.new_vertex(); //the new vertex
|
|
typename Dcel::Halfedge* h1=d.new_edge();
|
|
|
|
typename Dcel::Halfedge* h2=h1->opposite();
|
|
|
|
h1->set_vertex(dv1);
|
|
h2->set_vertex(dv2);
|
|
|
|
h1->set_face(df);
|
|
h2->set_face(df);
|
|
|
|
dv2->set_halfedge(h2);
|
|
|
|
h2->set_next(h1);
|
|
h1->set_next(prev->next());
|
|
|
|
prev->set_next(h2);
|
|
|
|
return TR_HI(h2);
|
|
}
|
|
|
|
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Halfedge_handle
|
|
Topological_map<Dcel>::
|
|
insert_in_face_interior(Face_handle f)
|
|
{
|
|
typename Dcel::Vertex* v1=d.new_vertex();
|
|
typename Dcel::Vertex* v2=d.new_vertex();
|
|
|
|
typename Dcel::Halfedge* h1 = d.new_edge();
|
|
typename Dcel::Halfedge* h2 = h1->opposite();
|
|
|
|
typename Dcel::Face* fp =&(*f);
|
|
|
|
h1->set_next(h2);
|
|
h1->set_vertex(v1);
|
|
h1->set_face(fp);
|
|
|
|
h2->set_next(h1);
|
|
h2->set_vertex(v2);
|
|
h2->set_face(fp);
|
|
|
|
v1->set_halfedge(h1);
|
|
v2->set_halfedge(h2);
|
|
|
|
fp->add_hole(h1);
|
|
|
|
return TR_HI(h1);
|
|
}
|
|
|
|
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Halfedge_handle
|
|
Topological_map<Dcel>::
|
|
split_edge (Halfedge_handle e)
|
|
{
|
|
typename Dcel::Halfedge* e1=&(*e);
|
|
typename Dcel::Halfedge* e2=e1->opposite();
|
|
|
|
//find previous halfedge of e2
|
|
typename Dcel::Halfedge* prev2=get_prev(e2);
|
|
|
|
typename Dcel::Vertex* v=d.new_vertex();
|
|
|
|
typename Dcel::Halfedge* e3=d.new_edge();
|
|
typename Dcel::Halfedge* e4=e3->opposite();
|
|
|
|
v->set_halfedge(e4);
|
|
|
|
if (e1->next()!=e2)
|
|
e3->set_next(e1->next());
|
|
else
|
|
e3->set_next(e4);
|
|
|
|
e4->set_vertex(v);
|
|
e3->set_face(e1->face());
|
|
e4->set_next(e2);
|
|
e3->set_vertex(e1->vertex());
|
|
e4->set_face(e2->face());
|
|
|
|
e1->vertex()->set_halfedge(e3); //makes the incident halfedge e3
|
|
//(so if e1 was the incident halfedge it comes instead ) - changed
|
|
|
|
if (prev2!=e1)
|
|
prev2->set_next(e4);
|
|
//otherwise e3->set_next(e4) - taken care above
|
|
|
|
e1->set_next(e3);
|
|
e1->set_vertex(v);
|
|
|
|
return TR_HI(e1);
|
|
}
|
|
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Halfedge_handle
|
|
Topological_map<Dcel>::
|
|
merge_edge (Halfedge_handle e1, Halfedge_handle e2)
|
|
{
|
|
//check e1->e2 and that degree(e1.target)==2 (i.e no other edge connected)
|
|
CGAL_assertion(e1->target()==e2->source());
|
|
CGAL_assertion(e1->target()->degree()==2);
|
|
|
|
typename Dcel::Halfedge* de1=&(*e1);
|
|
typename Dcel::Halfedge* de1t=de1->opposite();
|
|
typename Dcel::Halfedge* de2=&(*e2);
|
|
typename Dcel::Halfedge* de2t=de2->opposite();
|
|
|
|
typename Dcel::Vertex* v=de1->vertex();
|
|
|
|
typename Dcel::Face* f=de2->face();
|
|
typename Dcel::Face* ft=de1t->face();
|
|
|
|
|
|
//at the end de1 and de1t will remain and de2t,de2 will be deleted
|
|
//check if they are a "represantative" of a hole or outer ccb of face
|
|
if (f->halfedge()==de2)
|
|
f->set_halfedge(de1);
|
|
else {
|
|
if (find_and_erase_hole(de2,f))
|
|
f->add_hole(de1);
|
|
}
|
|
|
|
if (ft->halfedge()==de2t)
|
|
ft->set_halfedge(de1t);
|
|
else {
|
|
if (find_and_erase_hole(de2t,f))
|
|
f->add_hole(de1t);
|
|
}
|
|
|
|
//in case de2 is representative halfedge of the target vertex
|
|
de2->vertex()->set_halfedge(de1);
|
|
|
|
if (de2->next() != de2t) { //de2 is not a tip of antenna
|
|
//find previous halfedge of de2t
|
|
typename Dcel::Halfedge* prev2=get_prev(de2t);
|
|
de1->set_next(de2->next());
|
|
prev2->set_next(de1t);
|
|
}
|
|
else {
|
|
de1->set_next(de1t);
|
|
}
|
|
|
|
de1->set_vertex(de2->vertex());
|
|
|
|
d.delete_edge(de2);
|
|
d.delete_vertex(v);
|
|
|
|
return TR_HI(de1);
|
|
}
|
|
|
|
|
|
template<class Dcel>
|
|
typename Topological_map<Dcel>::Face_handle
|
|
Topological_map<Dcel>::
|
|
remove_edge(Halfedge_handle e)
|
|
{
|
|
typename Dcel::Halfedge* de1=&(*e);
|
|
typename Dcel::Halfedge* de2=de1->opposite();
|
|
typename Dcel::Face* df1=de1->face();
|
|
typename Dcel::Face* df2=de2->face();
|
|
|
|
typename Dcel::Halfedge* prev1;
|
|
typename Dcel::Halfedge* prev2;
|
|
|
|
//CASES:
|
|
|
|
if (df1==df2) { //case a. antenna - no face deleted
|
|
|
|
if (de1->next()==de2 && de2->next()==de1) {
|
|
//a.1 only one edge as a hole
|
|
if (!find_and_erase_hole(de1,df1))
|
|
find_and_erase_hole(de2,df1);
|
|
d.delete_vertex(de2->vertex());
|
|
d.delete_vertex(de1->vertex());
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df1);
|
|
}
|
|
|
|
|
|
if (de1->next()==de2 || de2->next()==de1) {
|
|
//a.2 a tip of the antenna
|
|
if (de1->next()==de2) { //de1 points at the tip
|
|
prev1=get_prev(de1);
|
|
prev1->set_next(de2->next());
|
|
|
|
//check if they are a represantative halfedge if so exchange
|
|
if (df1->halfedge()==de2)
|
|
df1->set_halfedge(prev1);
|
|
else {
|
|
if (find_and_erase_hole(de2,df1))
|
|
df1->add_hole(prev1);
|
|
}
|
|
|
|
if (df1->halfedge()==de1)
|
|
df1->set_halfedge(prev1);
|
|
else {
|
|
if (find_and_erase_hole(de1,df1))
|
|
df1->add_hole(prev1);
|
|
}
|
|
|
|
//check if de2 is incident halfedge of de2->vertex and if so -
|
|
//change to prev1 (iddo 16/6)
|
|
if (de2->vertex()->halfedge() == de2)
|
|
de2->vertex()->set_halfedge(prev1);
|
|
|
|
d.delete_vertex(de1->vertex()); //changed to conform with HDS
|
|
}
|
|
else { //de2 points at the tip - find previous halfedge of de2
|
|
prev2=get_prev(de2);
|
|
prev2->set_next(de1->next());
|
|
|
|
//check if they are represantative halfedge if so exchange
|
|
if (df1->halfedge()==de2)
|
|
df1->set_halfedge(prev2);
|
|
else {
|
|
if (find_and_erase_hole(de2,df1))
|
|
df1->add_hole(prev2);
|
|
}
|
|
|
|
if (df1->halfedge()==de1)
|
|
df1->set_halfedge(prev2);
|
|
else {
|
|
if (find_and_erase_hole(de1,df1))
|
|
df1->add_hole(prev2);
|
|
}
|
|
|
|
//check if de1 is incident halfedge of de1->vertex and if so -
|
|
//change to prev2
|
|
if (de1->vertex()->halfedge() == de1)
|
|
de1->vertex()->set_halfedge(prev2) ;
|
|
|
|
d.delete_vertex(de2->vertex());
|
|
}
|
|
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df1);
|
|
}
|
|
|
|
//a.3 a middle of an antenna - a new hole is created
|
|
prev1=get_prev(de1);
|
|
prev2=get_prev(de2);
|
|
|
|
//find the ccb of de1/de2
|
|
typename Dcel::Halfedge *ccb1;
|
|
if (is_halfedge_on_outer_ccb<Dcel>(prev1,df1,ccb1)) {
|
|
//antenna is connected to outer ccb, split a hole from it.
|
|
//we assume in this case that de1->next is the hole
|
|
//(to be determined genoetrically by the user)
|
|
|
|
df1->add_hole(de1->next());
|
|
df1->set_halfedge(prev1);
|
|
}
|
|
|
|
else { //antenna is a hole - split it into two holes
|
|
is_halfedge_on_inner_ccb<Dcel>(prev1,df1,ccb1);
|
|
#ifndef CGAL_NO_ASSERTIONS // in order to avoid warnings
|
|
bool hole_found =
|
|
#endif
|
|
find_and_erase_hole(ccb1,df1);
|
|
CGAL_assertion(hole_found) ;//ccb1 must be a hole in df1
|
|
df1->add_hole(prev1);
|
|
df1->add_hole(prev2);
|
|
}
|
|
|
|
prev1->set_next(de2->next());
|
|
prev2->set_next(de1->next());
|
|
|
|
//check if de1 is incident halfedge of de1->vertex() and if so change to
|
|
//prev2 same for de2
|
|
if (de1->vertex()->halfedge() == de1)
|
|
de1->vertex()->set_halfedge(prev2);
|
|
|
|
if (de2->vertex()->halfedge() == de2)
|
|
de2->vertex()->set_halfedge(prev1);
|
|
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df1);
|
|
}
|
|
|
|
else { //case b. edge between faces - merge faces
|
|
typename Dcel::Halfedge* ccb;
|
|
bool de1_is_on_hole=!(is_halfedge_on_outer_ccb<Dcel>(de1,df1,ccb));
|
|
bool de2_is_on_hole=!(is_halfedge_on_outer_ccb<Dcel>(de2,df2,ccb));
|
|
if ( !de1_is_on_hole && !de2_is_on_hole ) {
|
|
//b.1 both halfedges are on outer boundary
|
|
prev1=get_prev(de1);
|
|
prev2=get_prev(de2);
|
|
|
|
//arbitrarily df2 will be removed - change all edges so point to df1
|
|
//set the face pointer for all halfedges of df2 to df1
|
|
typename Dcel::Halfedge* aux=de2->next();
|
|
while (aux!=de2)
|
|
{
|
|
aux->set_face(df1);
|
|
aux=aux->next();
|
|
}
|
|
|
|
//move holes from df2 to df1 and set face pointer of each edge on
|
|
//hole to df1
|
|
typename Dcel::Face::Holes_iterator hi = df2->holes_begin();
|
|
for ( ; hi!=df2->holes_end(); ++hi) {
|
|
//set face pointers to df1
|
|
typename Dcel::Halfedge* aux1=(*hi);
|
|
do {
|
|
aux1->set_face(df1);
|
|
aux1=aux1->next();
|
|
} while (aux1!=(*hi)) ;
|
|
}
|
|
//copy the holes to the holes list of df1
|
|
for (hi = df2->holes_begin(); hi!=df2->holes_end(); ++hi) {
|
|
df1->add_hole(*hi);
|
|
}
|
|
df2->erase_holes(df2->holes_begin(),df2->holes_end());
|
|
|
|
//check if represantative edge
|
|
if (de1==df1->halfedge())
|
|
df1->set_halfedge(prev1);
|
|
|
|
//check if de1 is incident halfedge of de1->vertex() and if so change to
|
|
//prev2 same for de2
|
|
if (de1->vertex()->halfedge() == de1)
|
|
de1->vertex()->set_halfedge(prev2);
|
|
|
|
if (de2->vertex()->halfedge() == de2)
|
|
de2->vertex()->set_halfedge(prev1);
|
|
|
|
|
|
prev1->set_next(de2->next());
|
|
prev2->set_next(de1->next());
|
|
|
|
d.delete_face(df2);
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df1);
|
|
}
|
|
else { //edge is on a hole
|
|
prev1=get_prev(de1);
|
|
prev2=get_prev(de2);
|
|
|
|
if (de1_is_on_hole) { //df1 is the outer face df2 was the hole
|
|
//df2 will be removed - change all edges so point to df1
|
|
//set the face pointer for all halfedges of df2 to df1
|
|
typename Dcel::Halfedge* aux=de2->next();
|
|
while (aux!=de2) {
|
|
aux->set_face(df1);
|
|
aux=aux->next();
|
|
}
|
|
|
|
//move holes from df2 to df1 and set face pointer of each edge on
|
|
//hole to df1
|
|
|
|
typename Dcel::Face::Holes_iterator hi = df2->holes_begin();
|
|
for ( ; hi!=df2->holes_end(); ++hi) {
|
|
//set face pointers to df1
|
|
typename Dcel::Halfedge* aux1=(*hi);
|
|
do {
|
|
aux1->set_face(df1);
|
|
aux1=aux1->next();
|
|
} while (aux1!=(*hi)) ;
|
|
}
|
|
//copy to the holes list of df1
|
|
for (hi = df2->holes_begin(); hi!=df2->holes_end(); ++hi) {
|
|
df1->add_hole(*hi);
|
|
}
|
|
df2->erase_holes(df2->holes_begin(),df2->holes_end());
|
|
|
|
|
|
//check if de1 is a represantative hole of df1 (it is not on the outer)
|
|
if (find_and_erase_hole(de1,df1))
|
|
df1->add_hole(prev1);
|
|
|
|
//check if de1 is incident halfedge of de1->vertex() and if so change to
|
|
//prev2 same for de2
|
|
if (de1->vertex()->halfedge() == de1)
|
|
de1->vertex()->set_halfedge(prev2);
|
|
|
|
if (de2->vertex()->halfedge() == de2)
|
|
de2->vertex()->set_halfedge(prev1);
|
|
|
|
|
|
|
|
prev1->set_next(de2->next());
|
|
prev2->set_next(de1->next());
|
|
|
|
d.delete_face(df2);
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df1);
|
|
}
|
|
else { //df2 is the outer face
|
|
//erase df1
|
|
//df1 will be removed - change all edges so point to df2
|
|
typename Dcel::Halfedge* aux=de1->next();
|
|
while (aux!=de1) {
|
|
aux->set_face(df2);
|
|
aux=aux->next();
|
|
}
|
|
|
|
//move holes from df1 to df2 and set face pointer of each edge on
|
|
//hole to df1
|
|
|
|
typename Dcel::Face::Holes_iterator hi = df1->holes_begin();
|
|
for ( ; hi!=df1->holes_end(); ++hi) {
|
|
//set face pointers to df2
|
|
typename Dcel::Halfedge* aux1=(*hi);
|
|
do {
|
|
aux1->set_face(df2);
|
|
aux1=aux1->next();
|
|
} while (aux1!=(*hi)) ;
|
|
}
|
|
//copy to the holes list of df2
|
|
for (hi = df1->holes_begin(); hi!=df1->holes_end(); ++hi) {
|
|
df2->add_hole(*hi);
|
|
}
|
|
df1->erase_holes(df1->holes_begin(),df1->holes_end());
|
|
|
|
//check if de2 is a represantative hole of df2
|
|
if (find_and_erase_hole(de2,df2))
|
|
df2->add_hole(prev2);
|
|
|
|
//check if de1 is incident halfedge of de1->vertex() and if so change to
|
|
//to prev2 same for de2
|
|
if (de1->vertex()->halfedge() == de1)
|
|
de1->vertex()->set_halfedge(prev2);
|
|
|
|
if (de2->vertex()->halfedge() == de2)
|
|
de2->vertex()->set_halfedge(prev1);
|
|
|
|
prev1->set_next(de2->next());
|
|
prev2->set_next(de1->next());
|
|
|
|
d.delete_face(df1);
|
|
d.delete_edge(de1);
|
|
|
|
return TR_FI(df2);
|
|
|
|
} //df2 is outer..
|
|
} //edge is on a hole..
|
|
} //case b. (face deleted)
|
|
}
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif // CGAL_TOPOLOGICAL_MAP_H
|
|
// EOF
|