cgal/Extension_Packages/Nuage_III/include/NUAGE/Extract_surface.h

2073 lines
61 KiB
C++

#ifndef NUAGE_EXTRACT_SURFACE_H
#define NUAGE_EXTRACT_SURFACE_H
// In order to deactivate Geomview:
// #define BLIND
// In order to deactivate lazy evaluation:
// #define NOLAZY
#include <CGAL/basic.h>
#include <CGAL/squared_distance_3.h>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <vector>
#include <list>
// This iterator allows to visit all contours. It has the particularity
// that it visits the entry point of the contour twice. This allows to
// detect that the traversal of the border is finished. One more increment
// brings us to the next vertex.
template < class Surface>
class Extract_surface_boundary_iterator {
private:
Extract_surface_boundary_iterator(){}
public:
typedef typename Surface::Finite_vertices_iterator Finite_vertices_iterator;
typedef Extract_surface_boundary_iterator<Surface> Self;
typedef typename Surface::Vertex_handle Vertex_handle;
typedef typename Surface::Vertex Vertex;
const Surface& S;
int mark;
Finite_vertices_iterator first_vertex;
Vertex_handle pos;
bool first, last;
Extract_surface_boundary_iterator(const Surface& S_, int m)
: S(S_), mark(m), first_vertex(S.triangulation().finite_vertices_begin()), pos(first_vertex)
{
if (pos->number_of_incident_border() == 0){
advance_to_next_boundary();
}
first = true;
last = false;
}
Extract_surface_boundary_iterator(const Surface& S_)
: S(S_), pos(NULL)
{}
Extract_surface_boundary_iterator(const Self& s)
: S(s.S), mark(s.mark), first_vertex(s.first_vertex), pos(s.pos), first(s.first), last(s.last)
{}
bool operator==(const Self &s) const
{
return pos == s.pos;
}
bool operator!=(const Self &s) const
{
return pos != s.pos;
}
Self operator++()
{
if(pos == NULL) {
return *this;
}
if(first){
advance_on_boundary();
first = false;
} else if (last) {
advance_to_next_boundary();
first = true;
last = false;
} else {
advance_on_boundary();
if(&*pos == &*first_vertex){
last = true;
}
}
return *this;
}
Vertex_handle operator*()
{
return pos;
}
void advance_on_boundary()
{
if(pos == NULL) {
return;
}
pos = pos->first_incident()->first;
pos->set_post_mark(mark);
}
void advance_to_next_boundary()
{
if(pos == NULL) {
return;
}
do {
first_vertex++;
} while((first_vertex != S.triangulation().finite_vertices_end()) &&
(! ((first_vertex->is_on_border())
&& ! first_vertex->is_post_marked(mark))));
if(first_vertex != S.triangulation().finite_vertices_end()) {
pos = first_vertex;
pos->set_post_mark(mark);
} else {
pos = NULL;
}
}
};
template <class Triangulation, class Kernel>
class Extract_surface {
public:
typedef Triangulation Triangulation_3;
typedef Extract_surface<Triangulation_3,Kernel> Extract;
typedef typename Triangulation_3::Geom_traits Geom_traits;
typedef typename Geom_traits::Point_3 P;
//typedef CGAL::Kernel_traits<P> Kernel;
typedef typename Kernel::FT coord_type; //af: why does this not compile???
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Triangle_3 Triangle;
typedef typename Kernel::Sphere_3 Sphere;
typedef typename Triangulation_3::Cell Cell;
typedef typename Triangulation_3::Vertex Vertex;
typedef typename Triangulation_3::Edge Edge;
typedef typename Triangulation_3::Facet Facet;
typedef typename Triangulation_3::Cell_handle Cell_handle;
typedef typename Triangulation_3::Vertex_handle Vertex_handle;
typedef typename Triangulation_3::Cell_circulator Cell_circulator;
typedef typename Triangulation_3::Facet_circulator Facet_circulator;
typedef typename Triangulation_3::Locate_type Locate_type;
typedef typename Triangulation_3::Finite_cells_iterator Finite_cells_iterator;
typedef typename Triangulation_3::Finite_facets_iterator Finite_facets_iterator;
typedef typename Triangulation_3::Finite_vertices_iterator Finite_vertices_iterator;
typedef typename Triangulation_3::Finite_edges_iterator Finite_edges_iterator;
typedef typename Triangulation_3::All_cells_iterator All_cells_iterator;
typedef typename Triangulation_3::All_facets_iterator All_facets_iterator;
typedef typename Triangulation_3::All_vertices_iterator All_vertices_iterator;
typedef typename Triangulation_3::All_edges_iterator All_edges_iterator;
typedef typename Triangulation_3::Vertex::Edge_IFacet Edge_IFacet;
typedef typename Triangulation_3::Vertex::IO_edge_type IO_edge_type;
typedef typename Triangulation_3::Vertex::criteria criteria;
typedef typename Triangulation_3::Vertex::Radius_edge_type Radius_edge_type;
typedef typename Triangulation_3::Vertex::Border_elt Border_elt;
typedef typename Triangulation_3::Vertex::Next_border_elt Next_border_elt;
typedef typename Triangulation_3::Vertex::Radius_ptr_type Radius_ptr_type;
typedef typename Triangulation_3::Vertex::Incidence_request_iterator Incidence_request_iterator;
typedef typename Triangulation_3::Vertex::Incidence_request_elt Incidence_request_elt;
typedef std::pair< Vertex_handle, Vertex_handle > Edge_like;
typedef CGAL::Triple< Vertex_handle, Vertex_handle, Vertex_handle > Facet_like;
typedef std::list< Facet_like > Additional_facets_list;
typedef typename Additional_facets_list::iterator Additional_facets_iterator;
typedef std::multimap< criteria, IO_edge_type*,
std::less<criteria> > Ordered_border_type;
typedef typename Ordered_border_type::iterator Ordered_border_iterator;
enum Validation_case {not_valid, not_valid_connecting_case, final_case,
ear_case, exterior_case, connecting_case};
//=====================================================================
//=====================================================================
private:
Triangulation_3& T;
Ordered_border_type _ordered_border;
Additional_facets_list _additional_facets_list;
int _number_of_border;
const coord_type SLIVER_ANGULUS; // = sampling quality of the surface
coord_type DELTA; // = sampling quality of the border
coord_type K, min_K;
const coord_type eps;
const coord_type inv_eps_2; // 1/(eps^2)
const coord_type eps_3; // test de ^3 donc points tel 1e-7 soit petit
const criteria STANDBY_CANDIDATE;
const criteria STANDBY_CANDIDATE_BIS;
const criteria NOT_VALID_CANDIDATE;
//---------------------------------------------------------------------
CGAL::Timer t1;
//---------------------------------------------------------------------
//Pour une visu correcte
//pour retenir les facettes selectionnees
int _vh_number;
int _facet_number;
//---------------------------------------------------------------------
//Pour le post traitement
mutable int _postprocessing_counter;
int _size_before_postprocessing;
std::list<Point> outliers;
public:
Extract_surface(Triangulation_3& T_, double delta)
: T(T_), _number_of_border(1), SLIVER_ANGULUS(.86), DELTA(delta), min_K(HUGE_VAL),
eps(1e-7), inv_eps_2(coord_type(1)/(eps*eps)), eps_3(eps*eps*eps),
STANDBY_CANDIDATE(3), STANDBY_CANDIDATE_BIS(STANDBY_CANDIDATE+1),
NOT_VALID_CANDIDATE(STANDBY_CANDIDATE+2), _vh_number(T.number_of_vertices()), _facet_number(0),
_postprocessing_counter(0), _size_before_postprocessing(0)
{}
~Extract_surface()
{}
Triangulation_3&
triangulation() const
{
return T;
}
int number_of_facets() const
{
return _facet_number;
}
int number_of_vertices() const
{
return _vh_number;
}
int number_of_outliers() const
{
return outliers.size();
}
typedef typename std::list<Point>::const_iterator Outlier_iterator;
Outlier_iterator outliers_begin() const
{
return outliers.begin();
}
Outlier_iterator outliers_end() const
{
return outliers.end();
}
typedef Extract_surface_boundary_iterator<Extract> Boundary_iterator;
Boundary_iterator boundaries_begin() const
{
return Boundary_iterator(*this, get_next_mark());
}
Boundary_iterator boundaries_end() const
{
return Boundary_iterator(*this);
}
int get_next_mark() const
{
_postprocessing_counter++;
return _postprocessing_counter;
}
//=====================================================================
// The next functions come from utilities.h
//=====================================================================
Next_border_elt* get_border_elt(const Vertex_handle& v1, const Vertex_handle& v2)
{
return v1->get_border_elt(v2);
}
//public
IO_edge_type* get_border_IO_elt(const Vertex_handle& v1, const Vertex_handle& v2)
{
return &get_border_elt(v1,v2)->second.first.second;
}
IO_edge_type* set_border_elt(const Vertex_handle& v1, const Vertex_handle& v2,
const Border_elt& e)
{
v1->set_next_border_elt(Next_border_elt (v2, e));
return get_border_IO_elt(v1, v2);
}
IO_edge_type* set_again_border_elt(const Vertex_handle& v1, const Vertex_handle& v2,
const Border_elt& e)
{
get_border_elt(v1,v2)->second = e;
return get_border_IO_elt(v1, v2);
}
//---------------------------------------------------------------------
//af: Why does key get changed??
bool is_border_elt(Edge_like& key, Border_elt& result) const
{
Next_border_elt* it12 = key.first->get_border_elt(key.second);
if (it12 != NULL)
{
result = it12->second;
return true;
}
Next_border_elt* it21 = key.second->get_border_elt(key.first);
if (it21 != NULL)
{
result = it21->second;
std::swap(key.first, key.second);
return true;
}
return false;
}
//---------------------------------------------------------------------
bool is_border_elt(Edge_like& key) const {
Next_border_elt* it12 = key.first->get_border_elt(key.second);
if (it12 != NULL)
{
return true;
}
Next_border_elt* it21 = key.second->get_border_elt(key.first);
if (it21 != NULL)
{
std::swap(key.first, key.second);
return true;
}
return false;
}
//---------------------------------------------------------------------
bool is_ordered_border_elt(const Edge_like& key, Border_elt& result) const
{
Next_border_elt* it12 = key.first->get_border_elt(key.second);
if (it12 != NULL)
{
result = it12->second;
return true;
}
return false;
}
//---------------------------------------------------------------------
void
remove_border_elt(const Edge_like& ordered_key)
{
ordered_key.first->remove_border_edge(ordered_key.second);
}
//---------------------------------------------------------------------
bool is_ordered_border_elt(const Edge_like& e,
IO_edge_type* &ptr) const
{
Vertex_handle v1 = e.first;
Next_border_elt* it12 = v1->get_border_elt(e.second);
if (it12 != NULL)
{
ptr = &it12->second.first.second;
return true;
}
return false;
}
//---------------------------------------------------------------------
void set_incidence_request(const Vertex_handle& v,
const criteria& value,
const Edge_like& e)
{
Incidence_request_elt incident_elt(value, e);
v->set_incidence_request(incident_elt);
}
//---------------------------------------------------------------------
bool is_interior_edge(const Edge_like& key) const
// pour gerer certaines aretes interieures: a savoir celle encore connectee au
// bord (en fait seule, les aretes interieures reliant 2 bords nous
// interressent...)
{
return (key.first->is_interior_edge(key.second)||
key.second->is_interior_edge(key.first));
}
//---------------------------------------------------------------------
#ifndef NOLAZY
coord_type get_lazy_squared_radius(const Cell_handle& c)
{
if (c->get_lazy_squared_radius() != NULL)
return *(c->get_lazy_squared_radius());
c->set_lazy_squared_radius
(CGAL::squared_radius(c->vertex(0)->point(),
c->vertex(1)->point(),
c->vertex(2)->point(),
c->vertex(3)->point()));
return *(c->get_lazy_squared_radius());
}
Point get_lazy_circumcenter(const Cell_handle& c)
{
if (c->get_lazy_circumcenter() != NULL)
return *(c->get_lazy_circumcenter());
c->set_lazy_circumcenter
(CGAL::circumcenter(c->vertex(0)->point(),
c->vertex(1)->point(),
c->vertex(2)->point(),
c->vertex(3)->point()));
return *(c->get_lazy_circumcenter());
}
#endif //NOLAZY
//---------------------------------------------------------------------
Edge_IFacet inc_facet_circ(const Edge_IFacet& e) const
{
Cell_handle c = e.first.first;
int i = e.second;
int i1 = e.first.second, i2 = e.first.third;
int i3 = (6 - e.second - i1 - i2);
Cell_handle n = c->neighbor(i);
int j1 = n->index(c->vertex(i1)), j2 = n->index(c->vertex(i2));
int j = n->index(c->vertex(i3));
return Edge_IFacet(Edge(n, j1, j2), j);
}
//---------------------------------------------------------------------
Edge_IFacet dec_facet_circ(const Edge_IFacet& e) const
{
Cell_handle c = e.first.first;
int i = e.second;
int i1 = e.first.second, i2 = e.first.third;
int i3 = (6 - e.second - i1 - i2);
Cell_handle n = c->neighbor(i3);
int j1 = n->index(c->vertex(i1)), j2 = n->index(c->vertex(i2));
int j = n->index(c->vertex(i));
return Edge_IFacet(Edge(n, j1, j2), j);
}
//---------------------------------------------------------------------
bool
my_coplanar(const Point& p, const Point& q,
const Point& r, const Point& s) const
{
coord_type qpx = q.x()-p.x();
coord_type qpy = q.y()-p.y();
coord_type qpz = q.z()-p.z();
coord_type rpx = r.x()-p.x();
coord_type rpy = r.y()-p.y();
coord_type rpz = r.z()-p.z();
coord_type spx = s.x()-p.x();
coord_type spy = s.y()-p.y();
coord_type spz = s.z()-p.z();
coord_type den = CGAL::det3x3_by_formula(qpx,qpy,qpz,
rpx,rpy,rpz,
spx,spy,spz);
return (CGAL_NTS abs(den) < eps_3);
}
//---------------------------------------------------------------------
bool
my_collinear(const Point& p, const Point& q, const Point& s) const
{
coord_type psx = p.x()-s.x();
coord_type psy = p.y()-s.y();
coord_type psz = p.z()-s.z();
coord_type qsx = q.x()-s.x();
coord_type qsy = q.y()-s.y();
coord_type qsz = q.z()-s.z();
coord_type rsx = psy*qsz-psz*qsy;
coord_type rsy = psz*qsx-psx*qsz;
coord_type rsz = psx*qsy-psy*qsx;
coord_type den = CGAL::det3x3_by_formula(psx,psy,psz,
qsx,qsy,qsz,
rsx,rsy,rsz);
return (CGAL_NTS abs(den) < eps_3);
}
//---------------------------------------------------------------------
void
visu_facet(const Cell_handle& c, const int& i)
{
c->select_facet(i);
_facet_number++;
c->set_facet_number(i, _facet_number);
}
int number_of_border_edges()
{
int _border_count(0);
for(Finite_edges_iterator e_it=T.finite_edges_begin();
e_it!=T.finite_edges_end();
e_it++)
{
Cell_handle c = (*e_it).first;
int i1 = (*e_it).second, i2 = (*e_it).third;
Edge_like key(c->vertex(i1), c->vertex(i2));
if (is_border_elt(key))
_border_count++;
}
return _border_count;
}
// eof utilities.h
//=====================================================================
//=====================================================================
coord_type get_smallest_radius_delaunay_sphere(const Cell_handle& c,
const int& index) const
{
int i1, i2, i3;
Cell_handle n = c->neighbor(index);
// lazy evaluation ...
coord_type value = c->get_smallest_radius(index);
if ((value >= 0)&&(n->get_smallest_radius(n->index(c)) == value))
return value;
const Point& cp0 = c->vertex(index)->point();
const Point& cp1 = c->vertex((index+1) & 3)->point();
const Point& cp2 = c->vertex((index+2) & 3)->point();
const Point& cp3 = c->vertex((index+3) & 3)->point();
const Point& np0 = n->vertex(0)->point();
const Point& np1 = n->vertex(1)->point();
const Point& np2 = n->vertex(2)->point();
const Point& np3 = n->vertex(3)->point();
bool c_is_plane(my_coplanar(cp0, cp1, cp2, cp3));
bool n_is_plane(my_coplanar(np0, np1, np2, np3));
bool c_is_infinite(T.is_infinite(c));
bool n_is_infinite(T.is_infinite(n));
if ((c_is_plane && n_is_plane)||
(c_is_plane && n_is_infinite)||
(n_is_plane && c_is_infinite)||
my_collinear(cp1, cp2, cp3))
value = HUGE_VAL;
else
{
if (c_is_infinite||n_is_infinite||c_is_plane||n_is_plane)
{
int ind;
Cell_handle cc;
if(c_is_infinite||c_is_plane)
{
cc = n;
ind = n->index(c);
}
else
{
cc = c;
ind = index;
}
i1 = (ind+1) & 3;
i2 = (ind+2) & 3;
i3 = (ind+3) & 3;
const Point& pp0 = cc->vertex(ind)->point();
const Point& pp1 = cc->vertex(i1)->point();
const Point& pp2 = cc->vertex(i2)->point();
const Point& pp3 = cc->vertex(i3)->point();
Sphere facet_sphere(pp1, pp2, pp3);
if (CGAL::squared_distance(facet_sphere.center(), pp0) <
facet_sphere.squared_radius())
{
#ifndef NOLAZY
value = get_lazy_squared_radius(cc);
#else
value = CGAL::squared_radius(pp0, pp1, pp2, pp3);
#endif //NOLAZY
}
else
value = facet_sphere.squared_radius();
}
else
{
Point cc, cn;
#ifndef NOLAZY
cc = get_lazy_circumcenter(c);
cn = get_lazy_circumcenter(n);
#else
cc = CGAL::circumcenter(cp0, cp1, cp2, cp3);
cn = CGAL::circumcenter(np0, np1, np2, np3);
#endif //NOLAZY
// computation of the distance of cp1 to the dual segment cc, cn...
Vector V(cc - cn), Vc(cc - cp1), Vn(cp1 - cn);
coord_type ac(V * Vc), an(V * Vn), norm_V(V * V);
if ((ac > 0) && (an > 0))
{
value = (Vc*Vc) - ac*ac/norm_V;
if ((value < 0)||(norm_V > inv_eps_2))
value = CGAL::squared_radius(cp1, cp2, cp3);
}
else
{
if (ac <= 0)
value = CGAL::squared_distance(cc, cp1);
else // (an <= 0)
value = CGAL::squared_distance(cn, cp1);
}
}
}
// stockage des valeurs deja calculee...
c->set_smallest_radius(index, value);
n->set_smallest_radius(n->index(c), value);
return value;
}
//---------------------------------------------------------------------
Radius_edge_type compute_value(const Edge_IFacet& e)
{
Cell_handle c = e.first.first;
int i = e.second;
int i1 = e.first.second, i2 = e.first.third;
int i3 = 6 - e.second - i1 - i2;
Edge_IFacet e_it = e, predone = dec_facet_circ(e);
Cell_handle c_predone = predone.first.first;
coord_type min_valueP = NOT_VALID_CANDIDATE, min_valueA = HUGE_VAL;
Facet min_facet, min_facetA;
bool border_facet(false);
coord_type pscal;//, prec_pliure = e.third;
const Point& p1 = c->vertex(i1)->point();
const Point& p2 = c->vertex(i2)->point();
const Point& pc = c->vertex(i3)->point();
Vector P2P1 = p1-p2, P2Pn, PnP1;
Vector v2, v1 = CGAL::cross_product(pc-p2, P2P1);
coord_type norm, norm1 = v1*v1;
coord_type norm12 = P2P1*P2P1;
//int count(0);
e_it = inc_facet_circ(e_it);
bool succ_start(true);
do
{
Cell_handle neigh = e_it.first.first;
Facet facet_it(neigh, e_it.second);
if (!T.is_infinite(facet_it))
// &&!CGAL::collinear(p1, p2, pc) en principe inutile car HUGE_VAL ???
{
int n_ind = facet_it.second;
int n_i1 = e_it.first.second;
int n_i2 = e_it.first.third;
int n_i3 = 6 - n_ind - n_i1 - n_i2;
coord_type tmp = get_smallest_radius_delaunay_sphere(neigh, n_ind);
// bool is_on_same_border
// (neigh->vertex(n_i3)->is_on_border(result12.second));
Edge_like el1(neigh->vertex(n_i1),neigh->vertex(n_i3)),
el2(neigh->vertex(n_i2),neigh->vertex(n_i3));
// si on veut ne s'autoriser que le meme bord pour vni3
// if ((neigh->vertex(n_i3)->is_exterior() || is_on_same_border)&&
// si on veut pouvoir connecter des bords differents
// if (neigh->vertex(n_i3)->not_interior()&&
if ((tmp != HUGE_VAL)&&
neigh->vertex(n_i3)->not_interior()&&
(!is_interior_edge(el1))&&(!is_interior_edge(el2)))
{
const Point& pn = neigh->vertex(n_i3)->point();
P2Pn = pn-p2;
v2 = CGAL::cross_product(P2P1,P2Pn);
//pas necessaire de normer pour un bon echantillon:
// on peut alors tester v1*v2 >= 0
norm = CGAL::sqrt(norm1 * (v2*v2));
pscal = v1*v2;
//SLIVER_ANGULUS represente la qualite d'echantillonnage de la
//surface
bool sliver_facet = ((succ_start || (neigh == c_predone))&&
(pscal <= -SLIVER_ANGULUS*norm));
if (succ_start) succ_start = false;
if (!sliver_facet)
{
if (tmp < min_valueA)
{
PnP1 = p1-pn;
// DELTA represente la qualite d'echantillonnage du bord
border_facet = !((P2P1*P2Pn >=
-DELTA*CGAL::sqrt(norm12*(P2Pn*P2Pn)))&&
(P2P1*PnP1 >=
-DELTA*CGAL::sqrt(norm12*(PnP1*PnP1))));
min_facetA = facet_it;
min_valueA = tmp;
min_valueP = pscal/norm;
}
}
}
}
//count++;
e_it = inc_facet_circ(e_it);
}
while(e_it.first.first != c);
criteria value;
if ((min_valueA == HUGE_VAL) || border_facet) // bad facets case
{
//std::cout << "aucune facette candidate parmi " << count-1 << std::endl;
min_facet = Facet(c, i); // !!! sans aucune signification....
value = NOT_VALID_CANDIDATE; // Attention a ne pas inserer dans PQ
}
else
{
min_facet = min_facetA;
//si on considere seulement la pliure value appartient a [0, 2]
//value = coord_type(1) - min_valueP;
// si la pliure est bonne on note suivant le alpha sinon on prend en compte la
// pliure seule... pour discriminer entre les bons slivers...
// si on veut discriminer les facettes de bonnes pliures plus finement
// alors -(1+1/min_valueA) app a [-inf, -1]
// -min_valueP app a [-1, 1]
if (min_valueP > SLIVER_ANGULUS)
value = -(coord_type(1) + coord_type(1)/min_valueA);
else
{
//on refuse une trop grande non-uniformite
coord_type tmp = get_smallest_radius_delaunay_sphere(c, i);
if (min_valueA <= K * tmp)
value = - min_valueP;
else
{
value = STANDBY_CANDIDATE; // tres mauvais candidat mauvaise pliure
// + grand alpha... a traiter plus tard....
min_K =
std::min(min_K,
min_valueA/tmp);
}
}
}
Cell_handle n = min_facet.first;
int ni1 = n->index(c->vertex(i1)), ni2 = n->index(c->vertex(i2));
return
Radius_edge_type(value, IO_edge_type(e, Edge_IFacet
(Edge(n, ni1, ni2),
min_facet.second)));
}
//=====================================================================
//=====================================================================
bool
init(const bool& re_init)
{
Facet min_facet;
coord_type min_value = HUGE_VAL;
int i1, i2, i3;
if (!re_init)
for(Finite_facets_iterator facet_it = T.finite_facets_begin();
facet_it != T.finite_facets_end();
facet_it++)
{
coord_type value = get_smallest_radius_delaunay_sphere((*facet_it).first,
(*facet_it).second);
if (value < min_value)
{
min_facet = *facet_it;
min_value = value;
}
}
else //if (re_init)
for(Finite_facets_iterator facet_it = T.finite_facets_begin();
facet_it != T.finite_facets_end();
facet_it++)
{
Cell_handle c = (*facet_it).first;
int index = (*facet_it).second;
if (c->vertex((index+1) & 3)->is_exterior())
if (c->vertex((index+2) & 3)->is_exterior())
if (c->vertex((index+3) & 3)->is_exterior())
{
coord_type value = get_smallest_radius_delaunay_sphere(c, index);
if (value < min_value)
{
min_facet = *facet_it;
min_value = value;
}
}
}
if (min_value != HUGE_VAL)
{
Cell_handle c_min = min_facet.first;
int ind = min_facet.second;
i1 = (ind+1) & 3;
i2 = (ind+2) & 3;
i3 = (ind+3) & 3;
Radius_edge_type e12, e23, e31;
e12 = compute_value(Edge_IFacet(Edge(c_min, i1, i2), ind));
e23 = compute_value(Edge_IFacet(Edge(c_min, i2, i3), ind));
e31 = compute_value(Edge_IFacet(Edge(c_min, i3, i1), ind));
IO_edge_type* p12 = set_border_elt(c_min->vertex(i1), c_min->vertex(i2),
Border_elt(e12, _number_of_border));
IO_edge_type* p23 = set_border_elt(c_min->vertex(i2), c_min->vertex(i3),
Border_elt(e23, _number_of_border));
IO_edge_type* p31 = set_border_elt(c_min->vertex(i3), c_min->vertex(i1),
Border_elt(e31, _number_of_border));
c_min->vertex(i1)->inc_mark();
c_min->vertex(i2)->inc_mark();
c_min->vertex(i3)->inc_mark();
// if (e12.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type (e12.first, p12));
// if (e23.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type (e23.first, p23));
// if (e31.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type (e31.first, p31));
// Pour une visu correcte_e_it_bis
visu_facet(c_min, ind);
return true;
}
return false;
}
//---------------------------------------------------------------------
// test de reciprocite avant de recoller une oreille anti-singularite
int
test_merge(const Edge_like& ordered_key, const Border_elt& result,
const Vertex_handle& v, const coord_type& ear_alpha)
{
Edge_IFacet Ifacet = result.first.second.first;
const Point& p1 = (ordered_key.first)->point();
const Point& p2 = (ordered_key.second)->point();
const Point& pc = v->point();
Cell_handle neigh = Ifacet.first.first;
int n_ind = Ifacet.second;
int n_i1 = Ifacet.first.second;
int n_i2 = Ifacet.first.third;
int n_i3 = (6 - n_ind - n_i1 - n_i2);
const Point& pn = neigh->vertex(n_i3)->point();
Vector v1 = CGAL::cross_product(pc-p2,p1-p2),
v2 = CGAL::cross_product(p1-p2,pn-p2);
coord_type norm = CGAL::sqrt((v1*v1)*(v2*v2));
if (v1*v2 > SLIVER_ANGULUS*norm)
return 1; // label bonne pliure sinon:
if (ear_alpha <= K*get_smallest_radius_delaunay_sphere(neigh, n_ind))
return 2; // label alpha coherent...
return 0; //sinon oreille a rejeter...
}
//---------------------------------------------------------------------
void
_ordered_map_erase(const criteria& value, const IO_edge_type* pkey)
{
int number_of_conflict = _ordered_border.count(value);
int verif(0);
if (number_of_conflict == 1)
{
_ordered_border.erase(_ordered_border.find(value));
verif++;
}
if (number_of_conflict > 1)
{
Ordered_border_iterator elt_it =
_ordered_border.find(value);
// si ca foire jamais on peut s'areter des que l'elt
// est trouve!!!
for(int jj=0; (jj<number_of_conflict)&&(verif<1); jj++)
{
if (((long) elt_it->second) == ((long) pkey))
{
_ordered_border.erase(elt_it);
verif++;
}
elt_it++;
}
}
if (verif > 1)
{
std::cerr << "+++Problem with key: " << value <<
" containing " << number_of_conflict << " elts." << std::endl;
std::cerr << " " << verif <<
" elts removed from _ordered_border" << std::endl;
}
}
//---------------------------------------------------------------------
void
force_merge(const Edge_like& ordered_key, const Border_elt& result)
{
// Border_map_iterator bord_it = _border_map.find(key);
criteria value = result.first.first;
IO_edge_type* pkey = get_border_IO_elt(ordered_key.first, ordered_key.second);
_ordered_map_erase(value, pkey);
remove_border_elt(ordered_key);
}
//---------------------------------------------------------------------
void dequeue_incidence_request(const Vertex_handle& v)
{
if (v->is_incidence_requested())
{
for(Incidence_request_iterator v_it = v->incidence_request_begin();
v_it != v->get_incidence_request_end();
v_it++)
{
IO_edge_type* ptr;
if (is_ordered_border_elt(v_it->second, ptr))
_ordered_border.insert(Radius_ptr_type(v_it->first, ptr));
}
v->erase_incidence_request();
}
}
//---------------------------------------------------------------------
bool
try_to_close_border(IO_edge_type* /*p*/)
{
//=================== Pas une mauvaise idee, MAIS =================
// ATTENTION C'est incompatible avec le post-traitement !!!
// pour l'instant on ferme juste les triangles qui ne sont pas dans
// Delaunay, des que l'on en trouve un...
// Edge_IFacet e_Ifacet = p->first;
// Cell_handle c = e_Ifacet.first.first;
// Vertex_handle
// v1 = c->vertex(e_Ifacet.first.second),
// v2 = c->vertex(e_Ifacet.first.third);
// Edge_like el(v1, v2);
// Border_elt result;
// is_border_elt(el, result);
// Next_border_elt* succ1 = el.second->get_next_on_border(result.second);
// Vertex_handle v_succ1 = (Vertex*) succ1->first;
// Next_border_elt* succ2 = v_succ1->get_next_on_border(result.second);
// Vertex_handle v_succ2 = (Vertex*) succ2->first;
// if (v_succ2 == el.first)
// {
// // dans ce cas on a a faire a un contour a trois cote qui n'a pas ete
// // trouve comme candidat a fermer... certainement pas dans Delaunay...
// remove_border_elt(el);
// force_merge(Edge_like(el.second, v_succ1), succ1->second);
// force_merge(Edge_like(v_succ1, el.first), succ2->second);
// el.first->dec_mark();
// el.second->dec_mark();
// v_succ1->dec_mark();
// // marquer la facette en question pour l'affichage...
// _facet_number++;
// _additional_facets_list.push_back(Facet_like(el.second, v_succ1, el.first));
// return true;
// }
return false;
}
//---------------------------------------------------------------------
void
merge_ear(const Edge_like& ordered_el1, const Border_elt& result1,
const Edge_like& ordered_key,
const Vertex_handle& v1, const Vertex_handle& v2,
const Edge_IFacet& edge_Ifacet_2)
{
remove_border_elt(ordered_key);
force_merge(ordered_el1, result1);
Radius_edge_type e2 = compute_value(edge_Ifacet_2);
IO_edge_type* p2;
if (ordered_el1.first == v1)
p2 = set_border_elt(v2, ordered_el1.second,
Border_elt(e2,result1.second));
else
p2 = set_border_elt(ordered_el1.first, v2,
Border_elt(e2,result1.second));
v1->dec_mark();
// if e2 contain HUGE_VAL there is no candidates to
// continue: compute_value is not valid...
// if (e2.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e2.first, p2));
// else
// try_to_close_border(p2);
//depiler les eventuelles requettes de connections avortees... zones etoilees,
//en effet le bord a change donc on peut peut etre maintenant.
dequeue_incidence_request(v2);
if (ordered_el1.first == v1)
dequeue_incidence_request(ordered_el1.second);
else
dequeue_incidence_request(ordered_el1.first);
}
//---------------------------------------------------------------------
void
border_extend(const Edge_like& ordered_key, const Border_elt& result12,
const Vertex_handle& v1, const Vertex_handle& v2,
const Vertex_handle& v3,
const Radius_edge_type& e1, const Radius_edge_type& e2,
IO_edge_type* &p1, IO_edge_type* &p2)
{
remove_border_elt(ordered_key);
//depiler v3 avant de le mettre a jour... pour reperer s'il est sur un bord
if (v3->is_on_border())
dequeue_incidence_request(v3);
if (ordered_key.first == v1)
{
p1 = set_border_elt(v1, v3, Border_elt(e1,result12.second));
p2 = set_border_elt(v3, v2, Border_elt(e2,result12.second));
}
else
{
p2 = set_border_elt(v2, v3, Border_elt(e2,result12.second));
p1 = set_border_elt(v3, v1, Border_elt(e1,result12.second));
}
v3->inc_mark();
//depiler les eventuelles requettes de connections avortees... zones etoilees,
//en effet le bord a change donc on peut peut etre maintenant.
dequeue_incidence_request(v1);
dequeue_incidence_request(v2);
}
//=====================================================================
Validation_case
validate(const Edge_IFacet& edge_Efacet,
const criteria& value)
{
int i = (6 - edge_Efacet.second
- edge_Efacet.first.second
- edge_Efacet.first.third);
Cell_handle c = edge_Efacet.first.first;
// coord_type candidate_alpha = c->get_smallest_radius(edge_Efacet.second);
// coord_type pre_pliure = edge_Efacet.third;
// if ((c->vertex(i)->not_interior() > 0)&&(value > K*alpha_max))
// return not_valid;
Vertex_handle
v1 = c->vertex(edge_Efacet.first.second),
v2 = c->vertex(edge_Efacet.first.third);
Edge_like ordered_el1(c->vertex(i), v1);
Edge_like ordered_el2(c->vertex(i), v2);
Border_elt result1, result2, result12;
Edge_like ordered_key(v1,v2);
if (!is_border_elt(ordered_key, result12))
std::cerr << "+++probleme coherence bord <validate>" << std::endl;
bool is_border_el1 = is_border_elt(ordered_el1, result1),
is_border_el2 = is_border_elt(ordered_el2, result2);
// bool is_on_same_border (c->vertex(i)->is_on_border(result12.second));
Radius_edge_type e1, e2;
if (c->vertex(i)->not_interior())
{
if ((!is_interior_edge(ordered_el1))&&
(!is_interior_edge(ordered_el2)))
{
//toujours utile meme avec l'essai de try_to_close_border avant
//validate pour la resolution de singularite par oreille qui elle
//doit etre dans Delaunay.
if (is_border_el1&&is_border_el2)
{
remove_border_elt(ordered_key);
force_merge(ordered_el1, result1);
force_merge(ordered_el2, result2);
v1->dec_mark();
v2->dec_mark();
c->vertex(i)->dec_mark();
//Pour une visu correcte
visu_facet(c, edge_Efacet.second);
return final_case;
}
//---------------------------------------------------------------------
//on peut alors marquer v1 et on pourrait essayer de merger
//sans faire de calcul inutile???
if (is_border_el1)
{
// if (test_merge_ear(ordered_el1, result1, v2, candidate_alpha)&&
// (result12.second==result1.second))// force a merger
// {
Edge_IFacet edge_Ifacet_2(Edge(c, i, edge_Efacet.first.third),
edge_Efacet.second);
merge_ear(ordered_el1, result1,
ordered_key, v1, v2, edge_Ifacet_2);
//Pour une visu correcte
visu_facet(c, edge_Efacet.second);
return ear_case;
// }
// return not_valid;
}
//---------------------------------------------------------------------
//idem pour v2
if (is_border_el2)
{
// if (test_merge_ear(ordered_el2, result2, v1, candidate_alpha)&&
// (result12.second==result2.second))// force a merger
// {
Edge_IFacet edge_Ifacet_1(Edge(c, i, edge_Efacet.first.second),
edge_Efacet.second);
merge_ear(ordered_el2, result2,
ordered_key, v2, v1, edge_Ifacet_1);
//Pour une visu correcte
visu_facet(c, edge_Efacet.second);
return ear_case;
// }
// return not_valid;
}
//---------------------------------------------------------------------
if ((!is_border_el1)&&(!is_border_el2))
{
// si on veut s'interdir de spliter un bord (pelure d'orange....)
// seulement c->vertex(i)->is_exterior()
// pour s'autoriser des split de bord surface a bord->sphere ou Moebius...
// alors || is_on_same_border:
// if (c->vertex(i)->is_exterior() || is_on_same_border)
// pour passer au tore (changementde type de topologie)
// recoller deux bord different...
// if (c->vertex(i)->not_interior() deja teste en haut
if(c->vertex(i)->is_exterior())
{
Edge_IFacet edge_Ifacet_1(Edge(c, i, edge_Efacet.first.second),
edge_Efacet.second);
Edge_IFacet edge_Ifacet_2(Edge(c, i, edge_Efacet.first.third),
edge_Efacet.second);
e1 = compute_value(edge_Ifacet_1);
e2 = compute_value(edge_Ifacet_2);
IO_edge_type* p1;
IO_edge_type* p2;
border_extend(ordered_key, result12,
v1, v2, c->vertex(i),
e1, e2, p1, p2);
// if e1 contain HUGE_VAL there is no candidates to
// continue: compute_value is not valid...
// if (e1.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e1.first, p1));
// else
// try_to_close_border(p1);
// if e2 contain HUGE_VAL there is no candidates to
// continue: compute_value is not valid...
// if (e2.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e2.first, p2));
// else
// try_to_close_border(p2);
//Pour une visu correcte
visu_facet(c, edge_Efacet.second);
return exterior_case;
}
else // c->vertex(i) is a border point (and now there's only 1
// border incident to a point... _mark<1 even if th orientation
// may be such as one vh has 2 successorson the same border...
{
// a ce niveau on peut tester si le recollement se fait en
// maintenant la compatibilite d'orientation des bords (pour
// surface orientable...) ou si elle est brisee...
Edge_IFacet edge_Ifacet_1(Edge(c, i, edge_Efacet.first.second),
edge_Efacet.second);
Edge_IFacet edge_Ifacet_2(Edge(c, i, edge_Efacet.first.third),
edge_Efacet.second);
e1 = compute_value(edge_Ifacet_1);
e2 = compute_value(edge_Ifacet_2);
if ((e1.first >= STANDBY_CANDIDATE)&&(e2.first >= STANDBY_CANDIDATE))
return not_valid_connecting_case;
// vu compute value: les candidats oreilles fournis sont sans
// aretes interieures et le sommet oppose n'est pas non plus interieur
Edge_IFacet ear1 = e1.second.second;
Edge_IFacet ear2 = e2.second.second;
int ear1_i = (6 - ear1.second
- ear1.first.second
- ear1.first.third);
Cell_handle ear1_c = ear1.first.first;
Border_elt result_ear1;
int ear2_i = (6 - ear2.second
- ear2.first.second
- ear2.first.third);
Cell_handle ear2_c = ear2.first.first;
Border_elt result_ear2;
Edge_like ear1_e, ear2_e;
// pour maintenir la reconstruction d'une surface orientable :
// on verifie que les bords se recollent dans des sens opposes
if (ordered_key.first==v1)
{
ear1_e = Edge_like(c->vertex(i), ear1_c ->vertex(ear1_i));
ear2_e = Edge_like(ear2_c ->vertex(ear2_i), c->vertex(i));
}
else
{
ear1_e = Edge_like(ear1_c ->vertex(ear1_i), c->vertex(i));
ear2_e = Edge_like(c->vertex(i), ear2_c ->vertex(ear2_i));
}
//maintient la surface orientable
bool is_border_ear1 = is_ordered_border_elt(ear1_e, result_ear1);
bool is_border_ear2 = is_ordered_border_elt(ear2_e, result_ear2);
bool ear1_valid(false), ear2_valid(false);
//version sans controle d'orientabilite
// bool is_border_ear1 = is_border_elt(ear1_e, result_ear1);
// bool is_border_ear2 = is_border_elt(ear2_e, result_ear2);
if (is_border_ear1&&(e1.first < STANDBY_CANDIDATE)&&
(e1.first <= value)&&
(result12.second==result_ear1.second))
{
ear1_valid = test_merge(ear1_e, result_ear1, v1,
get_smallest_radius_delaunay_sphere(ear1_c,
ear1.second));
// si on veut etre plus restrictif
// et exiger au moins une bonne pliure:
// int test_merge_ear1 =
// test_merge(ear1_e, result_ear1, v1,
// ear1_c->get_smallest_radius(ear1.second));
// ear1_valid = (test_merge_ear1&&(e1.first < -1)&&
// ((value < -1)||(test_merge_ear1 == 1)));
}
if (is_border_ear2&&(e2.first < STANDBY_CANDIDATE)&&
(e2.first <= value)&&
(result12.second==result_ear2.second))
{
ear2_valid = test_merge(ear2_e, result_ear2, v2,
get_smallest_radius_delaunay_sphere(ear2_c,
ear2.second));
// si on veut etre plus restrictif
// et exiger au moins une bonne pliure:
// int test_merge_ear2 =
// test_merge(ear2_e, result_ear2, v2,
// ear2_c->get_smallest_radius(ear2.second));
// ear2_valid = (test_merge_ear2&&(e2.first < -1)&&
// ((value < -1)||(test_merge_ear2 == 1)));
}
if ((!ear1_valid)&&(!ear2_valid))
return not_valid_connecting_case;
IO_edge_type* p1;
IO_edge_type* p2;
border_extend(ordered_key, result12,
v1, v2, c->vertex(i),
e1, e2, p1, p2);
if (ear1_valid&&ear2_valid&&(ear1_e==ear2_e))
{
if (e1.first < e2.first)
{
Validation_case res = validate(ear1, e1.first);
if (!((res == ear_case)||(res == final_case)))
std::cerr << "+++probleme de recollement : cas "
<< res << std::endl;
e2 = compute_value(edge_Ifacet_2);
if (ordered_key.first == v1)
p2 = set_again_border_elt(c->vertex(i), v2,
Border_elt(e2, result2.second));
else
p2 = set_again_border_elt(v2, c->vertex(i),
Border_elt(e2, result2.second));
// if (e2.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e2.first, p2));
// else
// try_to_close_border(p2);
}
else
{
Validation_case res = validate(ear2, e2.first);
if (!((res == ear_case)||(res == final_case)))
std::cerr << "+++probleme de recollement : cas "
<< res << std::endl;
e1 = compute_value(edge_Ifacet_1);
if (ordered_key.first == v1)
p1 = set_again_border_elt(v1, c->vertex(i),
Border_elt(e1, result1.second));
else
p1 = set_again_border_elt(c->vertex(i), v1,
Border_elt(e1, result1.second));
// if (e1.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e1.first, p1));
// else
// try_to_close_border(p1);
}
}
else// les deux oreilles ne se recollent pas sur la meme arete...
{
// on resoud la singularite.
if (ear1_valid)
{
Validation_case res = validate(ear1, e1.first);
if (!((res == ear_case)||(res == final_case)))
std::cerr << "+++probleme de recollement : cas "
<< res << std::endl;
}
if (ear2_valid)
{
Validation_case res = validate(ear2, e2.first);
if (!((res == ear_case)||(res == final_case)))
std::cerr << "+++probleme de recollement : cas "
<< res << std::endl;
}
// on met a jour la PQ s'il y a lieu... mais surtout pas
// avant la resolution de la singularite
if (!ear1_valid)
{
// if (e1.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e1.first, p1));
// else
// try_to_close_border(p1);
}
if (!ear2_valid)
{
// if (e2.first < NOT_VALID_CANDIDATE)
_ordered_border.insert(Radius_ptr_type(e2.first, p2));
// else
// try_to_close_border(p2);
}
}
//Pour une visu correcte
visu_facet(c, edge_Efacet.second);
return connecting_case;
}
// if (is_on_same_border)
// {
// _number_of_border++;
// Incident_border_iterator tmp;
// std::cout << "En train de separer deux bords :"
// << result12.second << " et " << _number_of_border
// << std::endl;
// Vertex_handle circ = c->vertex(i), done = circ;
// do
// {
// tmp = circ->get_next_on_border(result12.second);
// (*tmp).second.second = _number_of_border;
// circ = (Vertex*) (*tmp).first;
// }
// while(circ != done);
// }
// else
// {
// //certainement un probleme avec le recollement de bords differents
// if (c->vertex(i)->not_interior() > 1)
// {
// std::cout << "En train de recoller des bords au bord :"
// << result12.second << std::endl;
// Incident_border_iterator tmp;
// for(Incident_border_iterator it =
// c->vertex(i)->first_incident();
// it != c->vertex(i)->not_incident();
// it++)
// {
// int current_index = (*it).second.second;
// if (current_index != result12.second)
// {
// Vertex_handle circ = c->vertex(i), done = circ;
// do
// {
// tmp = circ->get_next_on_border(current_index);
// (*tmp).second.second = result12.second;
// circ = (Vertex*) (*tmp).first;
// }
// while(circ != done);
// }
// }
// }
// }
}
}
}
return not_valid;
}
//=====================================================================
void re_compute_values()
{
if(!_ordered_border.empty())
{
Ordered_border_type _ordered_border_tmp;
do
{
Ordered_border_iterator e_it = _ordered_border.begin();
Edge_IFacet mem_Ifacet = e_it->second->first;
Cell_handle c_tmp = mem_Ifacet.first.first;
_ordered_border.erase(e_it);
Vertex_handle v1 = c_tmp->vertex(mem_Ifacet.first.second);
Vertex_handle v2 = c_tmp->vertex(mem_Ifacet.first.third);
Radius_edge_type new_candidate;
new_candidate = compute_value(mem_Ifacet);
// if (new_candidate.first < NOT_VALID_CANDIDATE)
{
if (new_candidate.first == STANDBY_CANDIDATE)
{
// a garder pour un K un peu plus grand...
new_candidate.first = STANDBY_CANDIDATE_BIS;
}
Border_elt result;
Edge_like key_tmp(v1,v2);
is_border_elt(key_tmp, result);
IO_edge_type* pnew =
set_again_border_elt(key_tmp.first, key_tmp.second,
Border_elt (new_candidate, result.second));
_ordered_border_tmp.insert(Radius_ptr_type(new_candidate.first, pnew));
}
}
while(!_ordered_border.empty());
_ordered_border.swap(_ordered_border_tmp);
}
}
//---------------------------------------------------------------------
void
extend(const coord_type& K_init, const coord_type& K_step, const coord_type& K_max)
{
// initilisation de la variable globale K: qualite d'echantillonnage requise
K = K_init; // valeur d'initialisation de K pour commencer prudemment...
//-------------------------------------------------------------------
// modif
//int _facet_number_test = _last_component_facet_number+3;
//bool close_result(false);
// modif
Vertex_handle v1, v2;
t1.start();
if (_ordered_border.empty()) return;
do
{
min_K = HUGE_VAL; // pour retenir le prochain K necessaire pour progresser...
do
{
Ordered_border_iterator e_it = _ordered_border.begin();
criteria value = e_it->first;
if (value >= STANDBY_CANDIDATE)
re_compute_values();
else
{
Edge_IFacet candidate = e_it->second->second;
Cell_handle c_ext = candidate.first.first;
int i1, i2 , i3;
i1 = candidate.first.second;
i2 = candidate.first.third;
i3 = (6 - i1- i2 - candidate.second);
Edge_IFacet mem_Ifacet = e_it->second->first;
Cell_handle c_tmp = mem_Ifacet.first.first;
v1 = c_tmp->vertex(mem_Ifacet.first.second);
v2 = c_tmp->vertex(mem_Ifacet.first.third);
Radius_edge_type mem_e_it(e_it->first, *e_it->second);
// Radius_ptr_type mem_first_it(*e_it);
_ordered_border.erase(e_it);
// modif: Pour boucher les trous triangulaires avant de faire des conneries???
//if (_facet_number > _facet_number_test)
//close_result = try_to_close_border(e_it->second);
//if (!close_result)
//{
// fin de la modif...
Validation_case validate_result = validate(candidate, value);
// Cell_handle ccc = candidate.first.first;
if ((validate_result == not_valid)||
(validate_result == not_valid_connecting_case))
{
Radius_edge_type new_candidate;
Border_elt result;
Edge_like key_tmp(v1,v2);
is_border_elt(key_tmp, result);
if (validate_result == not_valid_connecting_case)
set_incidence_request(c_ext->vertex(i3), value, key_tmp);
if (validate_result == not_valid)
{
new_candidate = compute_value(mem_Ifacet);
if ((new_candidate != mem_e_it))
// &&(new_candidate.first < NOT_VALID_CANDIDATE))
{
IO_edge_type* pnew =
set_again_border_elt(key_tmp.first, key_tmp.second,
Border_elt (new_candidate, result.second));
_ordered_border.insert(Radius_ptr_type(new_candidate.first,
pnew));
}
// else
// try_to_close_border(e_it->second);
}
}
else // valid candidate...
{
// alpha_max = std::max(alpha_max, value);
// if (validate_result != final_case)
// {
// Radius_edge_type v1_candidate, v2_candidate, v3_candidate;
// if (v1->not_interior())
// if (v1->is_incidence_requested())//le bord ayant change autant essayer
// v1_candidate = v1->get_best_incidence_request();
// if (v2->not_interior())
// if (v2->is_incidence_requested())
// v2_candidate = v2->get_best_incidence_request();
// if (validate_result != exterior_case)
// if (c_ext->vertex(i3)->is_incidence_requested())
// v3_candidate =
// c_ext->vertex(i3)->get_best_incidence_request();
// }
}
// modif
//}
// modif
}
}
while((!_ordered_border.empty())&&
(_ordered_border.begin()->first < STANDBY_CANDIDATE_BIS));
K += std::max(K_step, min_K-K+eps);
// on augmente progressivement le K mais on a deja rempli sans
// faire des betises auparavant...
}
while((!_ordered_border.empty())&&(K <= K_max)&&(min_K != HUGE_VAL));
t1.stop();
#ifdef VERBOSE
if ((min_K < HUGE_VAL)&&(!_ordered_border.empty())) {
std::cout << " [ next K required = " << min_K << " ]" << std::endl;
}
#endif // VERBOSE
}
//---------------------------------------------------------------------
// En principe, si l'allocateur de cellules etait bien fait on aurait pas besoin
// de mettre a jour les valeurs rajoutees pour les cellules a la main...
void re_init_for_free_cells_cache(const Vertex_handle& vh)
{
std::list<Cell_handle> ch_set;
T.incident_cells(vh, std::back_inserter(ch_set));
for (typename std::list<Cell_handle>::iterator c_it = ch_set.begin();
c_it != ch_set.end();
c_it++)
(*c_it)->clear();
}
//---------------------------------------------------------------------
void swap_selected_facets_on_conflict_boundary(const Vertex_handle& vh)
{
std::list<Cell_handle> ch_set;
T.incident_cells(vh, std::back_inserter(ch_set));
for (typename std::list<Cell_handle>::iterator c_it = ch_set.begin();
c_it != ch_set.end(); c_it++)
{
Cell_handle c = *c_it;
int index = c->index(vh);
Cell_handle neigh = c->neighbor(index);
int n_ind = neigh->index(c);
neigh->set_smallest_radius(n_ind, -1); // pour obliger le recalcul
// si c est selectionnee c'est qu'elle est aussi le mem_IFacet renvoye par
// compute_value... donc a swapper aussi
if (c->is_selected_facet(index))
{
int fn = c->facet_number(index);
c->unselect_facet(index);
neigh->select_facet(n_ind);
neigh->set_facet_number(n_ind, fn);
int i1 = (n_ind+1) & 3;
int i2 = (n_ind+2) & 3;
int i3 = (n_ind+3) & 3;
Edge_like key(neigh->vertex(i1), neigh->vertex(i2));
if (is_border_elt(key))
{
Edge_IFacet ei_facet(Edge(neigh, i1, i2),
n_ind);
*get_border_IO_elt(key.first, key.second) =
IO_edge_type(ei_facet, ei_facet);
}
key = Edge_like(neigh->vertex(i1), neigh->vertex(i3));
if (is_border_elt(key))
{
Edge_IFacet ei_facet(Edge(neigh, i1, i3),
n_ind);
*get_border_IO_elt(key.first, key.second) =
IO_edge_type(ei_facet, ei_facet);
}
key = Edge_like(neigh->vertex(i3), neigh->vertex(i2));
if (is_border_elt(key))
{
Edge_IFacet ei_facet(Edge(neigh, i3, i2),
n_ind);
*get_border_IO_elt(key.first, key.second) =
IO_edge_type(ei_facet, ei_facet);
}
}
}
}
//---------------------------------------------------------------------
Facet get_next_selected_facet_around_edge(const Edge_IFacet& start)
{
Edge_IFacet circ = inc_facet_circ(start);
Cell_handle c = start.first.first;
do
{
Cell_handle ch = circ.first.first;
int ind = circ.second;
Cell_handle neigh = ch->neighbor(ind);
int n_ind = neigh->index(ch);
if (ch->is_selected_facet(ind))
return Facet(ch, ind);
if (neigh->is_selected_facet(n_ind))
return Facet(neigh, n_ind);
circ = inc_facet_circ(circ);
}
while(circ.first.first != c);
// si on passe par la, alors y a eu un probleme....
std::cerr << "+++probleme dans la MAJ avant remove..." << std::endl;
return Facet(c, start.second);
}
//---------------------------------------------------------------------
void retract_border_for_incident_facets(const Vertex_handle& vh)
{
Next_border_elt border_elt = *(vh->first_incident());
int border_index = border_elt.second.second;
Vertex_handle vh_succ = border_elt.first;
IO_edge_type io_edge = border_elt.second.first.second;
Edge_IFacet i_facet = io_edge.first;
Cell_handle c = i_facet.first.first;
int i1 = c->index(vh);
int i2 = c->index(vh_succ);
int index = i_facet.second;
int i3 = 6 - index - i1 - i2;
Vertex_handle vh_int = c->vertex(i3);
_ordered_map_erase(border_elt.second.first.first,
get_border_IO_elt(vh, vh_succ));
vh->remove_border_edge(vh_succ);
// 1- a virer au cas ou car vh va etre detruit
vh_succ->remove_interior_edge(vh);
bool while_cond(true);
do
{
_facet_number--;
assert(c->is_selected_facet(index));
c->unselect_facet(index);
// if (!vh_succ->is_on_border())
// {
// vh_succ->re_init();
// }
Facet f32 =
get_next_selected_facet_around_edge(Edge_IFacet(Edge(c, i3, i2),
index));
if (!vh_int->is_on_border())
{
vh_int->re_init();
vh_int->inc_mark();
// std::list<Vertex_handle> vh_set;
// T.incident_vertices(vh_int, std::back_inserter(vh_set));
// for (std::list<Vertex_handle>::iterator v_it = vh_set.begin();
// v_it != vh_set.end(); v_it++)
// if((*v_it)->is_on_border())
// {
// // pour retrouver cette info, on a besoin de savoir si l'arete
// // [vh_hint, *v_it] est une arete de la reconstruction...
// vh_int->set_interior_edge(*v_it);
// }
}
Edge_IFacet e32(Edge(f32.first,
f32.first->index(vh_int),
f32.first->index(vh_succ)), f32.second);
Radius_edge_type rad_elt_32(STANDBY_CANDIDATE, IO_edge_type(e32, e32));
Border_elt result;
if (is_ordered_border_elt(Edge_like(vh_int, vh), result))
{
_ordered_map_erase(result.first.first, get_border_IO_elt(vh_int, vh));
vh_int->remove_border_edge(vh);
// 1- a virer au cas ou car vh va etre detruit
vh_int->remove_interior_edge(vh);
while_cond = false;
}
// a titre preventif... on essaye de s'assurer de marquer les aretes
// interieures au sens large...
// 2- a virer a tout pris pour que maintenir le sens de interior edge
vh_int->remove_interior_edge(vh_succ);
vh_succ->remove_interior_edge(vh_int);
IO_edge_type* p32 = set_border_elt(vh_int, vh_succ,
Border_elt(rad_elt_32, border_index));
_ordered_border.insert(Radius_ptr_type (STANDBY_CANDIDATE, p32));
// incrementation...
if (while_cond)
{
Facet f31 =
get_next_selected_facet_around_edge(Edge_IFacet(Edge(c, i3, i1),
index));
c = f31.first;
index = f31.second;
i1 = c->index(vh);
vh_succ = vh_int;
i2 = c->index(vh_int);
i3 = 6 - index - i1 - i2;
vh_int = c->vertex(i3);
}
}
while(while_cond);
}
//---------------------------------------------------------------------
bool create_singularity(const Vertex_handle& vh)
{
// Pour reperer le cas de triangle isole
if (vh->is_on_border())
{
// vh sommet 0
Next_border_elt border_elt = *(vh->first_incident());
Vertex_handle vh_1 = border_elt.first;// sommet 1
border_elt = *(vh_1->first_incident());
Vertex_handle vh_2 = border_elt.first;// sommet 2
border_elt = *(vh_2->first_incident());
Vertex_handle vh_3 = border_elt.first;// sommet 0 ???
Cell_handle c;
int i, j, k;
if ((vh_3 == vh)&&(T.is_facet(vh, vh_1, vh_2, c, i ,j ,k)))
{
int l = 6-i-j-k;
Cell_handle neigh = c->neighbor(l);
if
(c->is_selected_facet(l)||neigh->is_selected_facet(neigh->index(c)))
return true;
}
}
// Reperer le cas d'aretes interieures...
std::list<Vertex_handle> vh_list;
T.incident_vertices(vh, std::back_inserter(vh_list));
for (typename std::list<Vertex_handle>::iterator v_it = vh_list.begin();
v_it != vh_list.end(); v_it++)
if ((*v_it)->is_on_border() && is_interior_edge(Edge_like(vh, *v_it)))
return true;
return false;
}
//---------------------------------------------------------------------
void
store_outlier(const Point& p){
outliers.push_back(p);
}
void dec_vh_number()
{
_vh_number--;
}
struct Remove : public std::unary_function<Vertex_handle, bool>
{
Extract& E;
Triangulation_3& T;
Remove(Extract& E_, Triangulation_3& T_) : E(E_), T(T_) {}
bool operator()(Vertex_handle vh) {
if (vh->is_exterior())
{
E.swap_selected_facets_on_conflict_boundary(vh);
E.re_init_for_free_cells_cache(vh);
const Point& p = vh->point();
if (!T.remove(vh)) {
std::cerr << "+++Delaunay_triangulation_3.remove(Vertex_handle) failed." <<
p << std::endl;
} else {
E.store_outlier(p);
}
return true;
}
else if (vh->is_on_border()&&(!E.create_singularity(vh)))
{
E.swap_selected_facets_on_conflict_boundary(vh);
E.retract_border_for_incident_facets(vh);
E.re_init_for_free_cells_cache(vh);
E.dec_vh_number();
const Point& p = vh->point();
if (!T.remove(vh)){
std::cerr << "+++Delaunay_triangulation_3.remove(Vertex_handle) failed." <<
p << std::endl;
} else {
E.store_outlier(p);
}
return true;
}
else
{ }
return false;
}
};
//---------------------------------------------------------------------
bool postprocessing(const int& NB_BORDER_MAX)
{
_postprocessing_counter++;
std::list<Vertex_handle> L_v;
// Pour prendre en compte tous sommets exterieurs ou sur le bord
// for(Finite_vertices_iterator v_it = T.finite_vertices_begin();
// v_it != T.finite_vertices_end(); v_it++)
// {
// if (v_it->number_of_incident_border() != 0)
// {
// L_v.push_back(v_it->handle());
// v_it->erase_incidence_request();
// }
// }
// Pour controler les sommets choisis sur le bord...
// nombre d'aretes a partir duquel on considere que c'est irrecuperable NB_BORDER_MAX
int vh_on_border_inserted(0);
for(Finite_vertices_iterator v_it = T.finite_vertices_begin();
v_it != T.finite_vertices_end();
v_it++)
{
v_it->erase_incidence_request();
if ((v_it->is_on_border())&&
(!v_it->is_post_marked(_postprocessing_counter)))
{
std::list<Vertex_handle> L_v_tmp;
Vertex_handle vprev_it(v_it), done(vprev_it), vh_it;
// Vertex_handle vsucc_it;
int v_count(0);
// collect all vertices on the border
do
{
vh_it = vprev_it->first_incident()->first;
// vsucc_it = (Vertex*) vh_it->first_incident()->first;
// D_Point p1 = convert()(vprev_it->point());
// D_Point p = convert()(vh_it->point());
// D_Point p2 = convert()(vsucc_it->point());
// pour imposer une condition sur l'angle d'aretes...
// if ((p1-p)*(p2-p) > 0)
L_v_tmp.push_back(vh_it);
vh_it->set_post_mark(_postprocessing_counter);
vprev_it = vh_it;
v_count++;
}
while((vprev_it != done)&&(v_count < NB_BORDER_MAX));
// we stopped either because we did a complete tour, or because
// the border was so long that we consider it as too big to close
// e.g., if it is a terrain with only one real border at the exterior
if (v_count < NB_BORDER_MAX)
{
L_v.insert(L_v.begin(), L_v_tmp.begin(), L_v_tmp.end());
vh_on_border_inserted += v_count;
}
}
if (v_it->is_exterior())
L_v.push_back(v_it);
}
unsigned int itmp, L_v_size_mem;
L_v_size_mem = L_v.size();
if ((vh_on_border_inserted != 0)&& // pour ne post-traiter que les bords
(L_v.size() < .1 * _size_before_postprocessing))
{
{
do
{
itmp = L_v.size();
typename std::list<Vertex_handle>::iterator new_end =
std::remove_if(L_v.begin(), L_v.end(), Remove(*this,T));
L_v.erase(new_end, L_v.end());
}
while (!L_v.empty() && (L_v.size() < itmp));
}
#ifdef VERBOSE
if(L_v.size() > 0){
std::cout << " " << L_v.size() << " non regular points." << std::endl;
}
#endif // VERBOSE
re_compute_values();
}
else{
return false;
}
// we stop if we removed more than 10% of points or after 20 rounds
if ((L_v_size_mem == L_v.size())||
((_size_before_postprocessing - T.number_of_vertices()) >
.1 * _size_before_postprocessing)||
(_postprocessing_counter > 20)){
return false;
}
min_K = HUGE_VAL;
// fin--
// if (_postprocessing_counter < 5)
// return true;
return true;
}
}; // class Extract_surface
#endif // NUAGE_EXTRACT_SURFACE_H