mirror of https://github.com/CGAL/cgal
478 lines
17 KiB
C++
478 lines
17 KiB
C++
// Copyright (c) 1997-2000 Max-Planck-Institute Saarbruecken (Germany).
|
|
// 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) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// Peter Hachenberger <hachenberger@mpi-sb.mpg.de>
|
|
|
|
#ifndef CGAL_SNC_SM_OVERLAYER_H
|
|
#define CGAL_SNC_SM_OVERLAYER_H
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Union_find.h>
|
|
#include <CGAL/Nef_2/Segment_overlay_traits.h>
|
|
#include <CGAL/Nef_2/geninfo.h>
|
|
#include <CGAL/Nef_S2/Sphere_geometry.h>
|
|
#include <CGAL/Nef_S2/SM_decorator.h>
|
|
#include <CGAL/Nef_S2/SM_const_decorator.h>
|
|
#include <CGAL/Nef_S2/SM_overlayer.h>
|
|
#include <CGAL/Nef_3/SNC_structure.h>
|
|
#include <CGAL/Nef_3/SNC_indexed_items.h>
|
|
|
|
#undef CGAL_NEF_DEBUG
|
|
#define CGAL_NEF_DEBUG 131
|
|
#include <CGAL/Nef_2/debug.h>
|
|
|
|
#ifndef CGAL_USE_LEDA
|
|
#define LEDA_MEMORY(t)
|
|
#endif
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
/*{\Manpage {SNC_SM_overlayer}{Refs_}{Overlay in the sphere}{O}}*/
|
|
|
|
template <typename Items, typename SM_decorator_>
|
|
class SNC_SM_overlayer : public SM_overlayer<SM_decorator_> {
|
|
public:
|
|
|
|
typedef SM_decorator_ SM_decorator;
|
|
typedef typename SM_decorator::Map Map;
|
|
typedef SM_overlayer<SM_decorator_> Base;
|
|
typedef SNC_SM_overlayer<Items, SM_decorator_> Self;
|
|
|
|
typedef typename Base::SVertex_handle SVertex_handle;
|
|
typedef typename Base::SHalfedge_handle SHalfedge_handle;
|
|
typedef typename Base::SHalfloop_handle SHalfloop_handle;
|
|
typedef typename Base::SFace_handle SFace_handle;
|
|
typedef typename Base::SVertex_iterator SVertex_iterator;
|
|
typedef typename Base::SHalfedge_iterator SHalfedge_iterator;
|
|
typedef typename Base::SFace_iterator SFace_iterator;
|
|
typedef typename Base::SHalfedge_around_sface_circulator
|
|
SHalfedge_around_sface_circulator;
|
|
|
|
typedef typename Base::Sphere_kernel Sphere_kernel;
|
|
|
|
typedef typename Map::Infi_box Infi_box;
|
|
|
|
public:
|
|
SNC_SM_overlayer(Map* M,
|
|
const Sphere_kernel& G = Sphere_kernel())
|
|
: Base(M,G) {}
|
|
|
|
template <typename Association>
|
|
void simplify(Association&) {
|
|
CGAL_NEF_TRACEN("simplifying");
|
|
|
|
typedef typename CGAL::Union_find<SFace_handle>::handle Union_find_handle;
|
|
CGAL::Unique_hash_map< SFace_handle, Union_find_handle> Pitem(NULL);
|
|
CGAL::Unique_hash_map< SVertex_handle, Union_find_handle> Vitem(NULL);
|
|
CGAL::Union_find< SFace_handle> UF;
|
|
|
|
SFace_iterator f;
|
|
CGAL_forall_sfaces(f,*this) {
|
|
Pitem[f] = UF.make_set(f);
|
|
clear_face_cycle_entries(f);
|
|
}
|
|
|
|
if ( this->has_shalfloop() ) {
|
|
SHalfloop_handle l = this->shalfloop();
|
|
SFace_handle f = *(UF.find(Pitem[l->incident_sface()]));
|
|
link_as_loop(l,f);
|
|
f = *(UF.find(Pitem[l->twin()->incident_sface()]));
|
|
link_as_loop(l->twin(),f);
|
|
}
|
|
|
|
SHalfedge_iterator e, en;
|
|
for(e = this->shalfedges_begin(); e != this->shalfedges_end(); e = en) {
|
|
en = e; ++en; if ( en==e->twin() ) ++en;
|
|
CGAL_NEF_TRACEN("can simplify ? " << PH(e));
|
|
if(!Infi_box::is_sedge_on_infibox(e)) {
|
|
CGAL_NEF_TRACEN(e->mark() << " " <<
|
|
e->incident_sface()->mark() << " " <<
|
|
e->twin()->incident_sface()->mark());
|
|
if (( e->mark() == e->incident_sface()->mark() &&
|
|
e->incident_sface()->mark() == e->twin()->incident_sface()->mark())){
|
|
CGAL_NEF_TRACEN("deleting "<<PH(e));
|
|
if ( !UF.same_set(Pitem[e->incident_sface()],
|
|
Pitem[e->twin()->incident_sface()]) ) {
|
|
|
|
UF.unify_sets( Pitem[e->incident_sface()],
|
|
Pitem[e->twin()->incident_sface()] );
|
|
CGAL_NEF_TRACEN("unioning disjoint faces");
|
|
}
|
|
|
|
CGAL_NEF_TRACEN("is_closed_at_source " << is_closed_at_source(e) <<
|
|
" " << is_closed_at_source(e->twin()));
|
|
|
|
if ( is_closed_at_source(e) )
|
|
Vitem[e->source()] = Pitem[e->incident_sface()];
|
|
|
|
if ( is_closed_at_source(e->twin()))
|
|
Vitem[e->target()] = Pitem[e->incident_sface()];
|
|
|
|
delete_edge_pair(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
CGAL::Unique_hash_map<SHalfedge_handle,bool> linked(false);
|
|
for (e = this->shalfedges_begin(); e != this->shalfedges_end(); ++e) {
|
|
if ( linked[e] ) continue;
|
|
SHalfedge_around_sface_circulator hfc(e),hend(hfc);
|
|
SFace_handle f = *(UF.find( Pitem[e->incident_sface()]));
|
|
CGAL_For_all(hfc,hend) { set_face(hfc,f); linked[hfc]=true; }
|
|
store_sm_boundary_object(e,f);
|
|
}
|
|
|
|
SVertex_iterator v,vn;
|
|
for(v = this->svertices_begin(); v != this->svertices_end(); v=vn) {
|
|
vn=v; ++vn;
|
|
if ( is_isolated(v) ) {
|
|
if(Vitem[v] != NULL) {
|
|
set_face(v,*(UF.find(Vitem[v])));
|
|
CGAL_NEF_TRACEN("incident face of " << PH(v) << " set to " << &*(v->incident_sface()));
|
|
}
|
|
else {
|
|
set_face(v, *(UF.find(Pitem[v->incident_sface()])));
|
|
CGAL_NEF_TRACEN("isolated svertex " << PH(v) <<
|
|
" already has incident face " << &*(v->incident_sface()));
|
|
}
|
|
if ( v->mark() == v->incident_sface()->mark() ) {
|
|
CGAL_NEF_TRACEN("removing isolated vertex"<<PH(v));
|
|
delete_vertex_only(v);
|
|
}
|
|
else
|
|
store_sm_boundary_object(v,v->incident_sface()); // isolated, but should stay
|
|
} else { // v not isolated
|
|
SHalfedge_handle e2 = first_out_edge(v), e1 = e2->sprev();
|
|
if ( has_outdeg_two(v) &&
|
|
v->mark() == e1->mark() && e1->mark() == e2->mark() &&
|
|
e1->circle() == e2->circle() ) {
|
|
CGAL_NEF_TRACEN("collinear at "<<PH(v)<<PH(e1)<<PH(e2));
|
|
if ( e1 == e2 ){
|
|
CGAL_NEF_TRACEN("edge_to_loop");
|
|
convert_edge_to_loop(e1);
|
|
} else {
|
|
CGAL_NEF_TRACEN("merge_edge_pairs");
|
|
merge_edge_pairs_at_target(e1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SFace_iterator fn;
|
|
for (f = fn = this->sfaces_begin(); f != this->sfaces_end(); f=fn) {
|
|
++fn;
|
|
Union_find_handle pit = Pitem[f];
|
|
if ( UF.find(pit) != pit ) {
|
|
CGAL_NEF_TRACEN("delete face " << &*f);
|
|
delete_face_only(f);
|
|
}
|
|
}
|
|
|
|
CGAL_NEF_TRACEN(" ");
|
|
CGAL_NEF_TRACEN("resulting vertex ");
|
|
|
|
CGAL_forall_svertices(vn, *this)
|
|
CGAL_NEF_TRACEN("|" << vn->point() << "|" << vn->mark());
|
|
CGAL_NEF_TRACEN(" ");
|
|
|
|
CGAL_forall_shalfedges(en,*this)
|
|
CGAL_NEF_TRACEN("|" << en->circle() <<
|
|
"|" << en->mark() <<
|
|
" " << en->incident_sface()->mark());
|
|
CGAL_NEF_TRACEN("---------------------");
|
|
}
|
|
|
|
};
|
|
|
|
template <typename SM_decorator_>
|
|
class SNC_SM_overlayer<SNC_indexed_items, SM_decorator_>
|
|
: public SM_overlayer<SM_decorator_> {
|
|
|
|
typedef SM_decorator_ SM_decorator;
|
|
typedef typename SM_decorator::Map Map;
|
|
typedef SM_overlayer<SM_decorator_> Base;
|
|
typedef SNC_SM_overlayer<SNC_indexed_items,
|
|
SM_decorator_> Self;
|
|
|
|
typedef typename Base::SVertex_handle SVertex_handle;
|
|
typedef typename Base::SHalfedge_handle SHalfedge_handle;
|
|
typedef typename Base::SHalfloop_handle SHalfloop_handle;
|
|
typedef typename Base::SFace_handle SFace_handle;
|
|
typedef typename Base::SVertex_iterator SVertex_iterator;
|
|
typedef typename Base::SHalfedge_iterator SHalfedge_iterator;
|
|
typedef typename Base::SFace_iterator SFace_iterator;
|
|
typedef typename Base::SHalfedge_around_sface_circulator
|
|
SHalfedge_around_sface_circulator;
|
|
|
|
typedef typename Base::Sphere_kernel Sphere_kernel;
|
|
|
|
typedef typename Map::Infi_box Infi_box;
|
|
|
|
using SM_decorator::clear_face_cycle_entries;
|
|
using SM_decorator::link_as_loop;
|
|
using SM_decorator::link_as_prev_next_pair;
|
|
using SM_decorator::is_closed_at_source;
|
|
using SM_decorator::is_closed_at_target;
|
|
using SM_decorator::delete_edge_pair;
|
|
using SM_decorator::set_face;
|
|
using SM_decorator::is_isolated;
|
|
using SM_decorator::delete_vertex_only;
|
|
using SM_decorator::delete_face_only;
|
|
using SM_decorator::first_out_edge;
|
|
using SM_decorator::set_first_out_edge;
|
|
using SM_decorator::has_outdeg_two;
|
|
using SM_decorator::store_sm_boundary_object;
|
|
using SM_decorator::is_sm_boundary_object;
|
|
using SM_decorator::undo_sm_boundary_object;
|
|
using SM_decorator::delete_edge_pair_only;
|
|
|
|
public:
|
|
SNC_SM_overlayer(Map* M,
|
|
const Sphere_kernel& G = Sphere_kernel())
|
|
: Base(M,G) {}
|
|
|
|
void convert_edge_to_loop(SHalfedge_handle e) {
|
|
/*{\Mop converts the edge at |v = e->target()| to the unique
|
|
loop |l| of |\Mvar|. |e|, |e->twin()| and |v| are deleted
|
|
in the conversion. \precond there was no loop in |\Mvar|.
|
|
As |e| was entry point of |e->incident_sface()| then |l| takes this role.}*/
|
|
|
|
CGAL_NEF_TRACEN("convert_edge_to_loop "<<PH(e));
|
|
CGAL_assertion( e->source()==e->target() );
|
|
CGAL_assertion( !this->has_shalfloop() );
|
|
SHalfloop_handle l = this->new_shalfloop_pair();
|
|
SVertex_handle v = e->target();
|
|
SFace_handle f1 = e->incident_sface(), f2 = e->twin()->incident_sface();
|
|
if( is_sm_boundary_object(e)) {
|
|
CGAL_assertion( is_sm_boundary_object(e->twin()));
|
|
undo_sm_boundary_object(e,f1); undo_sm_boundary_object(e->twin(),f2);
|
|
}
|
|
link_as_loop(l,f1), link_as_loop(l->twin(),f2);
|
|
l->circle() = e->circle(); l->twin()->circle() = e->twin()->circle();
|
|
l->mark() = l->twin()->mark() = e->mark();
|
|
l->set_index(e->get_index());
|
|
l->twin()->set_index(e->twin()->get_index());
|
|
delete_vertex_only(v);
|
|
delete_edge_pair_only(e);
|
|
}
|
|
|
|
template <typename Association>
|
|
void merge_edge_pairs_at_target(SHalfedge_handle e, Association& A) {
|
|
/*{\Mop merges the edge pairs at |v = e->target()|. |e| and |twin(e)|
|
|
are preserved, |e->snext()|, |twin(e->snext())| and |v| are deleted
|
|
in the merger. \precond |v| has outdegree two. The adjacency at
|
|
|e->source()| and |target(e->snext())| is kept consistent.
|
|
If |e->snext()| was entry point of |e->incident_sface()| then |e| takes this role.
|
|
The same holds for |twin(e->snext())| and |face(twin(e))|.}*/
|
|
|
|
CGAL_NEF_TRACEN("merge_edge_pairs_at_target "<<PH(e));
|
|
SHalfedge_handle en = e->snext(), eno = en->twin(), enn, enno,
|
|
eo = e->twin() ;
|
|
if ( is_closed_at_target(en) ) { enn = eo; enno=e; }
|
|
else { enn = en->snext(), enno = eno->sprev(); }
|
|
SVertex_handle v = e->target(), vn = en->target();
|
|
CGAL_assertion(has_outdeg_two(v));
|
|
SFace_handle f1 = en->incident_sface(), f2 = eno->incident_sface();
|
|
// transfer the opposite face cycles e-en-enn to e-enn
|
|
if ( enn != eno ) {
|
|
link_as_prev_next_pair(e,enn);
|
|
link_as_prev_next_pair(enno,eo);
|
|
} else {
|
|
link_as_prev_next_pair(e,eo);
|
|
}
|
|
// set vertex of e and deal with vertex-halfedge incidence
|
|
eo->source() = vn;
|
|
|
|
CGAL_NEF_TRACEN("rehash " << en->get_index() << " " << e->get_index());
|
|
CGAL_NEF_TRACEN(" " << A.get_hash(en->get_index()) << " " << A.get_hash(e->get_index()));
|
|
CGAL_NEF_TRACEN("rehash " << eno->get_index() << " " << eo->get_index());
|
|
CGAL_NEF_TRACEN(" " << A.get_hash(eno->get_index()) << " " << A.get_hash(eo->get_index()));
|
|
|
|
int index1 = A.get_hash(e->get_index());
|
|
int index2 = A.get_hash(en->get_index());
|
|
if(index2 < index1) {
|
|
A.set_hash(e->get_index(), index2);
|
|
e->set_index(index2);
|
|
} else
|
|
A.set_hash(en->get_index(), index1);
|
|
|
|
index1 = A.get_hash(eo->get_index());
|
|
index2 = A.get_hash(eno->get_index());
|
|
if(index2 < index1) {
|
|
A.set_hash(eo->get_index(), index2);
|
|
eo->set_index(index2);
|
|
} else
|
|
A.set_hash(eno->get_index(), index1);
|
|
|
|
CGAL_NEF_TRACEN("hash sedge " << e->get_index()
|
|
<< "->" << A.get_hash(e->get_index()));
|
|
CGAL_NEF_TRACEN("hash sedge " << en->get_index()
|
|
<< "->" << A.get_hash(en->get_index()));
|
|
CGAL_NEF_TRACEN("hash sedge " << eo->get_index()
|
|
<< "->" << A.get_hash(eo->get_index()));
|
|
CGAL_NEF_TRACEN("hash sedge " << eno->get_index()
|
|
<< "->" << A.get_hash(eno->get_index()));
|
|
|
|
|
|
if ( first_out_edge(vn) == eno ) set_first_out_edge(vn,eo);
|
|
if ( is_sm_boundary_object(en) )
|
|
{ undo_sm_boundary_object(en,f1); store_sm_boundary_object(e,f1); }
|
|
if ( is_sm_boundary_object(eno) )
|
|
{ undo_sm_boundary_object(eno,f2); store_sm_boundary_object(eo,f2); }
|
|
delete_vertex_only(v);
|
|
delete_edge_pair_only(en);
|
|
CGAL_NEF_TRACEN("END "<<PH(e->sprev())<<PH(e)<<PH(e->snext()));
|
|
}
|
|
|
|
template <typename Association>
|
|
void simplify(Association& A) {
|
|
CGAL_NEF_TRACEN("simplifying");
|
|
|
|
typedef typename CGAL::Union_find<SFace_handle>::handle Union_find_handle;
|
|
CGAL::Unique_hash_map< SFace_handle, Union_find_handle> Pitem(NULL);
|
|
CGAL::Unique_hash_map< SVertex_handle, Union_find_handle> Vitem(NULL);
|
|
CGAL::Union_find< SFace_handle> UF;
|
|
|
|
SFace_iterator f;
|
|
CGAL_forall_sfaces(f,*this) {
|
|
Pitem[f] = UF.make_set(f);
|
|
clear_face_cycle_entries(f);
|
|
}
|
|
|
|
if ( this->has_shalfloop() ) {
|
|
SHalfloop_handle l = this->shalfloop();
|
|
SFace_handle f = *(UF.find(Pitem[l->incident_sface()]));
|
|
link_as_loop(l,f);
|
|
f = *(UF.find(Pitem[l->twin()->incident_sface()]));
|
|
link_as_loop(l->twin(),f);
|
|
}
|
|
|
|
SHalfedge_iterator e, en;
|
|
for(e = this->shalfedges_begin(); e != this->shalfedges_end(); e = en) {
|
|
en = e; ++en; if ( en==e->twin() ) ++en;
|
|
CGAL_NEF_TRACEN("can simplify ? " << PH(e));
|
|
if(!Infi_box::is_sedge_on_infibox(e)) {
|
|
CGAL_NEF_TRACEN(e->mark() << " " <<
|
|
e->incident_sface()->mark() << " " <<
|
|
e->twin()->incident_sface()->mark());
|
|
if (( e->mark() == e->incident_sface()->mark() &&
|
|
e->incident_sface()->mark() == e->twin()->incident_sface()->mark())){
|
|
CGAL_NEF_TRACEN("deleting "<<PH(e));
|
|
if ( !UF.same_set(Pitem[e->incident_sface()],
|
|
Pitem[e->twin()->incident_sface()]) ) {
|
|
|
|
UF.unify_sets( Pitem[e->incident_sface()],
|
|
Pitem[e->twin()->incident_sface()] );
|
|
CGAL_NEF_TRACEN("unioning disjoint faces");
|
|
}
|
|
|
|
CGAL_NEF_TRACEN("is_closed_at_source " << is_closed_at_source(e) <<
|
|
" " << is_closed_at_source(e->twin()));
|
|
|
|
if ( is_closed_at_source(e) )
|
|
Vitem[e->source()] = Pitem[e->incident_sface()];
|
|
|
|
if ( is_closed_at_source(e->twin()))
|
|
Vitem[e->target()] = Pitem[e->incident_sface()];
|
|
|
|
delete_edge_pair(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
CGAL::Unique_hash_map<SHalfedge_handle,bool> linked(false);
|
|
for (e = this->shalfedges_begin(); e != this->shalfedges_end(); ++e) {
|
|
if ( linked[e] ) continue;
|
|
SHalfedge_around_sface_circulator hfc(e),hend(hfc);
|
|
SFace_handle f = *(UF.find( Pitem[e->incident_sface()]));
|
|
CGAL_For_all(hfc,hend) { set_face(hfc,f); linked[hfc]=true; }
|
|
store_sm_boundary_object(e,f);
|
|
}
|
|
|
|
SVertex_iterator v,vn;
|
|
for(v = this->svertices_begin(); v != this->svertices_end(); v=vn) {
|
|
vn=v; ++vn;
|
|
if ( is_isolated(v) ) {
|
|
if(Vitem[v] != NULL) {
|
|
set_face(v,*(UF.find(Vitem[v])));
|
|
CGAL_NEF_TRACEN("incident face of " << PH(v) << " set to " << &*(v->incident_sface()));
|
|
}
|
|
else {
|
|
set_face(v, *(UF.find(Pitem[v->incident_sface()])));
|
|
CGAL_NEF_TRACEN("isolated svertex " << PH(v) <<
|
|
" already has incident face " << &*(v->incident_sface()));
|
|
}
|
|
if ( v->mark() == v->incident_sface()->mark() ) {
|
|
CGAL_NEF_TRACEN("removing isolated vertex"<<PH(v));
|
|
delete_vertex_only(v);
|
|
}
|
|
else
|
|
store_sm_boundary_object(v,v->incident_sface()); // isolated, but should stay
|
|
} else { // v not isolated
|
|
SHalfedge_handle e2 = first_out_edge(v), e1 = e2->sprev();
|
|
if ( has_outdeg_two(v) &&
|
|
v->mark() == e1->mark() && e1->mark() == e2->mark() &&
|
|
e1->circle() == e2->circle() ) {
|
|
CGAL_NEF_TRACEN("collinear at "<<PH(v)<<PH(e1)<<PH(e2));
|
|
if ( e1 == e2 ){
|
|
CGAL_NEF_TRACEN("edge_to_loop");
|
|
convert_edge_to_loop(e1);
|
|
} else {
|
|
CGAL_NEF_TRACEN("merge_edge_pairs");
|
|
merge_edge_pairs_at_target(e1, A);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SFace_iterator fn;
|
|
for (f = fn = this->sfaces_begin(); f != this->sfaces_end(); f=fn) {
|
|
++fn;
|
|
Union_find_handle pit = Pitem[f];
|
|
if ( UF.find(pit) != pit ) {
|
|
CGAL_NEF_TRACEN("delete face " << &*f);
|
|
delete_face_only(f);
|
|
}
|
|
}
|
|
|
|
CGAL_NEF_TRACEN(" ");
|
|
CGAL_NEF_TRACEN("resulting vertex ");
|
|
|
|
CGAL_forall_svertices(vn, *this)
|
|
CGAL_NEF_TRACEN("|" << vn->point() << "|" << vn->mark());
|
|
CGAL_NEF_TRACEN(" ");
|
|
|
|
CGAL_assertion_code(CGAL_forall_shalfedges(en,*this)
|
|
CGAL_NEF_TRACEN("|" << en->circle() <<
|
|
"|" << en->mark() <<
|
|
" " << en->incident_sface()->mark()));
|
|
|
|
CGAL_NEF_TRACEN("check indexes");
|
|
CGAL_assertion_code(CGAL_forall_sedges(en, *this)
|
|
CGAL_NEF_TRACEN(en->source()->point() << "->"
|
|
<< en->twin()->source()->point() << " : "
|
|
<< en->get_index() << " "
|
|
<< en->twin()->get_index()));
|
|
CGAL_NEF_TRACEN("---------------------");
|
|
}
|
|
|
|
};
|
|
|
|
CGAL_END_NAMESPACE
|
|
#endif //CGAL_SNC_SM_OVERLAYER_H
|