mirror of https://github.com/CGAL/cgal
1136 lines
28 KiB
C++
1136 lines
28 KiB
C++
#ifndef CGAL_MESH_H
|
|
#define CGAL_MESH_H
|
|
#include <list>
|
|
#include <map>
|
|
#include <cmath>
|
|
#include <iostream.h>
|
|
#include <fstream.h>
|
|
#include <qwidget.h>
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Constrained_triangulation_2.h>
|
|
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
|
|
#include <CGAL/predicate_classes_2.h>
|
|
#include <CGAL/Triangulation_circulators_2.h>
|
|
|
|
//CGAL_BEGIN_NAMESPACE
|
|
using namespace CGAL;
|
|
|
|
#define INVALID_EDGE Edge(NULL, -1);
|
|
|
|
#define UPDATE {viewer->repaint(); qApp->processEvents(); float ff; for(float f=0.0; f<1.2e6; f++) ff += sin(f);}
|
|
//#define UPDATE
|
|
|
|
template <class Gt, class Tds> class Triangulation_finite_vertex_circulator :
|
|
public Triangulation_vertex_circulator_2<Gt, Tds>
|
|
{
|
|
|
|
};
|
|
|
|
template <class Gt, class Tds, class Mtraits = void>
|
|
class Mesh:
|
|
public Constrained_Delaunay_triangulation_2 <Gt, Tds>
|
|
{
|
|
|
|
public:
|
|
QWidget *viewer;
|
|
|
|
typedef Gt Triangulation_geom_traits;
|
|
typedef Tds Triangulation_data_structure;
|
|
typedef typename Gt::FT FT;
|
|
typedef FT Length;
|
|
typedef FT Square_length;
|
|
|
|
typedef CGAL::Triangulation_2<Gt, Tds> Tr;
|
|
typedef CGAL::Constrained_triangulation_2<Gt, Tds> Ct;
|
|
typedef CGAL::Constrained_Delaunay_triangulation_2<Gt, Tds> CDt;
|
|
// typedef typename CDt::Constraint Constraint;
|
|
typedef typename CDt::Vertex Vertex;
|
|
typedef typename CDt::Edge Edge;
|
|
typedef typename CDt::Face_handle Face_handle;
|
|
typedef typename CDt::Vertex_handle Vertex_handle;
|
|
typedef typename CDt::Finite_faces_iterator Finite_faces_iterator;
|
|
|
|
typedef std::pair<Vertex_handle,Vertex_handle> Constrained_edge;
|
|
|
|
typedef typename Gt::Point_2 Point;
|
|
typedef std::pair<Point,Point> Constraint;
|
|
typedef std::list<Constraint> List_constraints;
|
|
|
|
typedef Mtraits Mesh_traits;
|
|
|
|
enum Cluster_status {REDUCED,NON_REDUCED};
|
|
struct Cluster {
|
|
Cluster_status status;
|
|
Length length;
|
|
FT alpha_min;
|
|
std::map<Vertex_handle, Length> vertices;
|
|
};
|
|
|
|
void write(ostream &f);
|
|
void read(istream &f);
|
|
void reset() {
|
|
cluster_map.clear();
|
|
clear();
|
|
}
|
|
|
|
private:
|
|
int current_time;
|
|
std::multimap<FT, Face_handle> Bad_faces;
|
|
std::list<Constrained_edge> c_edge_queue;
|
|
std::map<Vertex_handle, int> insertion_time;
|
|
std::map<Vertex_handle, FT> insertion_radius_map;
|
|
std::multimap<Vertex_handle, Cluster> cluster_map;
|
|
|
|
public:
|
|
//INSERTION-REMOVAL
|
|
void refine_mesh(QWidget *v);
|
|
void bounds(FT &xmin, FT &ymin,
|
|
FT &xmax, FT &ymax,
|
|
FT &xcenter, FT &ycenter);
|
|
void bounding_box();
|
|
|
|
|
|
|
|
Mesh(const Geom_traits& gt=Geom_traits()):CDt(gt){};
|
|
|
|
Mesh(List_constraints& lc, const Geom_traits& gt=Geom_traits()):CDt(gt)
|
|
{
|
|
typename List_constraints::iterator lcit=lc.begin();
|
|
for( ; lcit != lc.end(); ++lcit)
|
|
{
|
|
insert( (*lcit).first, (*lcit).second);
|
|
}
|
|
CGAL_triangulation_postcondition(is_valid());
|
|
}
|
|
|
|
template <class InputIterator>
|
|
Mesh(InputIterator first, InputIterator last, const Geom_traits&
|
|
gt=Gt()):CDt(gt)
|
|
{
|
|
while(first != last){
|
|
insert((*first).first, (*first).second);
|
|
++first;
|
|
}
|
|
CGAL_triangulation_postcondition(is_valid());
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
void refine_face(Face_handle f);
|
|
void refine_edge(Vertex_handle va, Vertex_handle vb);
|
|
void create_clusters();
|
|
void create_clusters_of_vertex(Vertex_handle v);
|
|
void show_clusters();
|
|
Vertex_handle insert_middle(Vertex_handle va, Vertex_handle vb);
|
|
void cut_cluster(Vertex_handle va, Vertex_handle vb);
|
|
void cut_reduced_cluster(Vertex_handle va, Vertex_handle vb);
|
|
void cut_cluster_edge(Vertex_handle va, Vertex_handle vb);
|
|
Vertex_handle insert_in_c_edge(Vertex_handle va, Vertex_handle vb, Point p);
|
|
void fill_edge_queue();
|
|
void fill_facette_map();
|
|
void process_edge_queue();
|
|
void process_facette_map();
|
|
void update_c_edge_queue(Vertex_handle va,
|
|
Vertex_handle vb,
|
|
Vertex_handle vm);
|
|
void update_facette_map(Vertex_handle v);
|
|
void update_cluster(Vertex_handle va, Vertex_handle vb, Vertex_handle vm);
|
|
inline Edge edge_between(Vertex_handle va, Vertex_handle vb);
|
|
|
|
|
|
|
|
//CHECK
|
|
bool is_encroached(Vertex_handle va, Vertex_handle vb, Point p);
|
|
bool is_encroached(Vertex_handle va, Vertex_handle vb);
|
|
bool min_insertion_radius(Vertex_handle v, Cluster &c);
|
|
bool is_bad(Face_handle f);
|
|
bool is_small_angle(Vertex_handle vleft,
|
|
Vertex_handle vmiddle,
|
|
Vertex_handle vright);
|
|
bool is_cluster_reduced(const Cluster&); //look cluster status
|
|
bool is_cluster(Vertex_handle va, Vertex_handle vb);
|
|
|
|
FT shortest_edge_of_cluster(Vertex_handle v, Cluster &cluster);
|
|
void check_cluster_status( Cluster&);
|
|
|
|
|
|
|
|
// HELPING functions
|
|
Square_length shortest_edge(Face_handle f);
|
|
FT angle(Vertex_handle vleft, Vertex_handle vmiddle, Vertex_handle vright);
|
|
FT circumradius_to_shortest_edge_ratio(Face_handle f);
|
|
FT insertion_radius(Vertex_handle v);
|
|
Vertex_handle nearest_incident_vertex(Vertex_handle v);
|
|
bool find_cluster(Vertex_handle va, Vertex_handle vb, Cluster &c);
|
|
inline Vertex_circulator incr(Vertex_circulator &c) {
|
|
c++;
|
|
if(Vertex_handle(c) == infinite_vertex()) {
|
|
c++;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
inline Vertex_circulator incr_constraint(Vertex_handle v, Vertex_circulator &c)
|
|
{
|
|
Vertex_circulator cbegin = c;
|
|
incr(c);
|
|
while(!edge_between(v, c).first->is_constrained(edge_between(v, c).second)
|
|
&& c != cbegin ) {
|
|
incr(c);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
inline Vertex_circulator succ(Vertex_circulator c) { return incr(c); }
|
|
inline Vertex_circulator succ_constraint(Vertex_handle v,
|
|
Vertex_circulator c)
|
|
{
|
|
return incr_constraint(v, c);
|
|
}
|
|
inline bool get_conflicting_edges(const Point &p,
|
|
list<Constrained_edge> &cel)
|
|
{ //cel = constrained edges list
|
|
Face_handle start;
|
|
int li;
|
|
Locate_type lt;
|
|
Face_handle fh = locate(p,lt,li, start);
|
|
switch(lt) {
|
|
case OUTSIDE_AFFINE_HULL:
|
|
case VERTEX:
|
|
return false;
|
|
case FACE:
|
|
case EDGE:
|
|
case OUTSIDE_CONVEX_HULL:
|
|
propagate_conflicting_edges(p,fh,0,cel);
|
|
propagate_conflicting_edges(p,fh,1,cel);
|
|
propagate_conflicting_edges(p,fh,2,cel);
|
|
return true;
|
|
}
|
|
CGAL_triangulation_assertion(false);
|
|
return false;
|
|
}
|
|
//private:
|
|
|
|
|
|
inline void propagate_conflicting_edges (const Point &p,
|
|
Face_handle fh,
|
|
int i,
|
|
list<Constrained_edge> &cel)
|
|
{
|
|
if(is_infinite(make_pair(fh,i))) return;
|
|
Face_handle fn = fh->neighbor(i);
|
|
Edge e(fh,i);
|
|
if(!is_encroached(e.first->vertex(cw(e.second)),
|
|
e.first->vertex(ccw(e.second)), p)) {
|
|
return;
|
|
}
|
|
if ( fh->is_constrained(i)) {// || ! test_conflict(p,fn)) {
|
|
cel.push_back(Constrained_edge(e.first->vertex(cw(e.second)),
|
|
e.first->vertex(ccw(e.second))));//Edge(fn, fn->index(fh));
|
|
return;
|
|
}
|
|
|
|
int j = fn->index(fh);
|
|
propagate_conflicting_edges(p,fn,ccw(j),cel);
|
|
propagate_conflicting_edges(p,fn,cw(j),cel);
|
|
return;
|
|
}
|
|
|
|
bool is_infinite(Face_handle fh) {
|
|
Vertex_handle va, vb, vc;
|
|
va=fh->vertex(0);
|
|
vb=fh->vertex(1);
|
|
vc=fh->vertex(2);
|
|
if(va==infinite_vertex() || vb==infinite_vertex() ||
|
|
vc==infinite_vertex()) return true;
|
|
//check whether the face still exists...
|
|
if(!is_face(va, vb, vc)) return true;
|
|
return false;
|
|
}
|
|
|
|
bool is_infinite(Edge e) {
|
|
Vertex_handle va, vb;
|
|
va=e.first->vertex(cw(e.second));
|
|
vb=e.first->vertex(ccw(e.second));
|
|
if(va==infinite_vertex() || vb==infinite_vertex()) return true;
|
|
//check whether the face still exists...
|
|
if(!is_edge(va, vb)) return true;
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
find_cluster(Vertex_handle va, Vertex_handle vb, Cluster &c)
|
|
{
|
|
// check if vb is in any cluster of va
|
|
pair<multimap<Vertex_handle, Cluster>::iterator,
|
|
multimap<Vertex_handle, Cluster>::iterator> range =
|
|
cluster_map.equal_range(va);
|
|
for(multimap<Vertex_handle, Cluster>::iterator it = range.first;
|
|
it != range.second; it++)
|
|
{
|
|
Cluster &cl = it->second;
|
|
if(cl.vertices.find(vb)!=cl.vertices.end()) {
|
|
c = it->second;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//the function that writes a file
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
write(ostream &f)
|
|
{
|
|
int nedges = 0;
|
|
Edge_iterator eit = edges_begin();
|
|
while(eit != edges_end()) {
|
|
if((*eit).first->is_constrained((*eit).second))
|
|
nedges++;
|
|
eit++;
|
|
}
|
|
f<<nedges<<endl;
|
|
eit=edges_begin();
|
|
while(eit!=edges_end()) {
|
|
if((*eit).first->is_constrained((*eit).second)) {
|
|
f<<(*eit).first->vertex(cw((*eit).second))->point().x()<<" ";
|
|
f<<(*eit).first->vertex(cw((*eit).second))->point().y()<<" ";
|
|
f<<(*eit).first->vertex(ccw((*eit).second))->point().x()<<" ";
|
|
f<<(*eit).first->vertex(ccw((*eit).second))->point().y()<<endl;
|
|
}
|
|
eit++;
|
|
}
|
|
}
|
|
|
|
|
|
//the function that reads a file
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
read(istream &f)
|
|
{
|
|
int nedges = 0;
|
|
clear();
|
|
f>>nedges;
|
|
for(int n=0; n<nedges; n++) {
|
|
FT x1, y1, x2, y2;
|
|
f>>x1>>y1>>x2>>y2;
|
|
insert(Point(x1, y1), Point(x2, y2));
|
|
}
|
|
}
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
fill_edge_queue()
|
|
{
|
|
Edge_iterator ei = edges_begin();
|
|
while(ei != edges_end()) {
|
|
Vertex_handle va = (*ei).first->vertex(cw((*ei).second));
|
|
Vertex_handle vb = (*ei).first->vertex(ccw((*ei).second));
|
|
if((*ei).first->is_constrained((*ei).second) &&
|
|
is_encroached(va, vb)&&
|
|
va!=infinite_vertex()&&
|
|
vb!=infinite_vertex()) {
|
|
c_edge_queue.push_back(make_pair(va, vb));
|
|
}
|
|
ei++;
|
|
}
|
|
}
|
|
|
|
//it is necessarry for process_facette_map
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
fill_facette_map()
|
|
{
|
|
Face_iterator fit = faces_begin();
|
|
while(fit != faces_end())
|
|
{
|
|
if(!is_infinite(fit)) {
|
|
if( is_bad(fit))
|
|
{
|
|
Bad_faces.insert(make_pair(
|
|
circumradius_to_shortest_edge_ratio(fit), fit));
|
|
}
|
|
}
|
|
fit++;
|
|
}
|
|
}
|
|
|
|
|
|
//is used by process_edge_queue
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
process_edge_queue()
|
|
{
|
|
while(! c_edge_queue.empty() )
|
|
{
|
|
Constrained_edge ce;
|
|
ce=c_edge_queue.front();
|
|
c_edge_queue.pop_front();
|
|
// if ce is not an edge, choose another. should be more robust
|
|
while(!is_edge(ce.first, ce.second) && !c_edge_queue.empty()) {
|
|
ce=c_edge_queue.front();
|
|
c_edge_queue.pop_front();
|
|
}
|
|
Face_handle fh;
|
|
int i;
|
|
if ( is_edge( ce.first, ce.second, fh,i))
|
|
{
|
|
if(fh->is_constrained(i) &&
|
|
is_encroached(ce.first, ce.second))
|
|
{
|
|
//Vertex_handle va = ce.first;
|
|
//Vertex_handle vb = ce.second;
|
|
refine_edge(ce.first, ce.second);
|
|
//c_edge_queue.pop_front();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
process_facette_map()
|
|
{
|
|
if(Bad_faces.empty())
|
|
{
|
|
}
|
|
while( !Bad_faces.empty())
|
|
{
|
|
Face_handle Bf = (*(Bad_faces.begin())).second;
|
|
while(is_infinite(Bf)) {
|
|
Bad_faces.erase(Bad_faces.begin());
|
|
if(Bad_faces.empty()) return;
|
|
Bf = (*(Bad_faces.begin())).second;
|
|
}
|
|
Bad_faces.erase(Bad_faces.begin());
|
|
Vertex_handle va, vb, vc;
|
|
va = Bf->vertex(0);
|
|
vb = Bf->vertex(1);
|
|
vc = Bf->vertex(2);
|
|
if( is_face(va,vb,vc )&&is_bad(Bf))
|
|
{
|
|
refine_face(Bf);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//this function split all the segments that are encroached
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
refine_edge(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
UPDATE;
|
|
Face_handle f;
|
|
int i;
|
|
is_edge(va, vb, f, i);
|
|
if( !is_cluster(va,vb) &&
|
|
!is_cluster(vb,va) &&
|
|
f->is_constrained(i)) {
|
|
Vertex_handle vm = insert_middle(va,vb);
|
|
update_c_edge_queue(va, vb, vm);
|
|
update_facette_map(vm);
|
|
return;
|
|
}
|
|
else if (is_cluster(va,vb) && is_cluster(vb,va)) {
|
|
Vertex_handle vm = insert_middle(va,vb);
|
|
update_c_edge_queue(va, vb, vm);
|
|
update_facette_map(vm);
|
|
if(vm.is_null()) {
|
|
exit(-1);
|
|
}
|
|
update_cluster(va,vb,vm);
|
|
update_cluster(vb,va,vm);
|
|
return;
|
|
}
|
|
Vertex_handle vaa = is_cluster(va,vb) ? va : vb;
|
|
Vertex_handle vbb = is_cluster(va,vb) ? vb : va;
|
|
cut_cluster_edge(vaa,vbb);
|
|
}
|
|
|
|
//split all the bad faces
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
refine_face(Face_handle f)
|
|
{
|
|
Point pc;
|
|
Vertex_handle v;
|
|
//check if the face still exists
|
|
pc = circumcenter(f);
|
|
list<Constrained_edge> conflicts;
|
|
list<Constrained_edge>::iterator out_conflicts=c_edge_queue.begin();
|
|
if(get_conflicting_edges(pc, c_edge_queue))
|
|
{
|
|
if(!c_edge_queue.empty()){
|
|
while(! c_edge_queue.empty() )
|
|
{
|
|
Constrained_edge ce;
|
|
ce=c_edge_queue.front();
|
|
c_edge_queue.pop_front();
|
|
while(!is_edge(ce.first, ce.second) && !c_edge_queue.empty()) {
|
|
ce=c_edge_queue.front();
|
|
c_edge_queue.pop_front();
|
|
}
|
|
Face_handle fh;
|
|
int i;
|
|
if ( is_edge( ce.first, ce.second, fh,i))
|
|
{
|
|
if( fh->is_constrained(i) &&
|
|
is_encroached(ce.first, ce.second))
|
|
{
|
|
Vertex_handle va = ce.first;
|
|
Vertex_handle vb = ce.second;
|
|
Square_length rg = shortest_edge(f);
|
|
Cluster cluster;
|
|
Vertex_handle vaa = is_cluster(va,vb) ? va : vb;
|
|
Vertex_handle vbb = is_cluster(va,vb) ? vb : va;
|
|
find_cluster(vaa, vbb, cluster);
|
|
Length rmin = shortest_edge_of_cluster(vaa, cluster);
|
|
if(rmin >rg) {
|
|
refine_edge(ce.first, ce.second);
|
|
} else {
|
|
exit(-1);
|
|
}
|
|
//c_edge_queue.pop_front();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Face_handle start;
|
|
int li;
|
|
Locate_type lt;
|
|
Face_handle fh = locate(pc,lt,li, start);
|
|
if(lt!=OUTSIDE_CONVEX_HULL) {
|
|
v = insert(pc);
|
|
update_facette_map(v);
|
|
}
|
|
}
|
|
}
|
|
UPDATE;
|
|
current_time++;
|
|
insertion_time[v] = current_time;
|
|
//flip_around(v);
|
|
}
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
create_clusters()
|
|
{
|
|
Vertex_iterator vit = vertices_begin();
|
|
while(vit != vertices_end()) {
|
|
create_clusters_of_vertex(vit);
|
|
vit++;
|
|
}
|
|
}
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
create_clusters_of_vertex(Vertex_handle v)
|
|
{
|
|
// prerequisite: at least too vertices must exist in the triangulation
|
|
Vertex_circulator vcirc = incident_vertices(v);
|
|
|
|
incr_constraint(v, vcirc);
|
|
Vertex_circulator vbegin = vcirc;
|
|
incr_constraint(v, vcirc);
|
|
do {
|
|
if(!is_small_angle(vcirc, v, succ_constraint(v, vcirc))) {
|
|
break;
|
|
}
|
|
incr_constraint(v, vcirc);
|
|
} while(vcirc!=vbegin);
|
|
// now vcirc points to:
|
|
// * either the point JUST BEFORE the first large angle
|
|
// * or vbegin if such an angle has not been encountered
|
|
|
|
// begin with the second case: a single cluster exists
|
|
if(vcirc==vbegin) {
|
|
FT min_angle = 1000.0; // a BIG value for an angle
|
|
Cluster cl;
|
|
|
|
do{
|
|
if(is_small_angle(vcirc, v, succ_constraint(v, vcirc))) {
|
|
cl.vertices.insert(make_pair(vcirc, squared_distance(v->point(),
|
|
vcirc->point())));
|
|
min_angle = min(min_angle, angle(vcirc, v, succ_constraint(v, vcirc)));
|
|
}
|
|
incr_constraint(v, vcirc);
|
|
}while(vcirc!=vbegin);
|
|
|
|
cl.alpha_min = min_angle;
|
|
cluster_map.insert(make_pair(v, cl));
|
|
} else {
|
|
// the first case
|
|
vbegin = vcirc;
|
|
do{
|
|
Cluster cl;
|
|
cl.alpha_min = 1000;
|
|
do {
|
|
cl.vertices.insert(make_pair(vcirc, squared_distance(v->point(),
|
|
vcirc->point())));
|
|
cl.alpha_min = min(cl.alpha_min, angle(vcirc, v,
|
|
succ_constraint(v, vcirc)));
|
|
incr_constraint(v, vcirc);
|
|
} while(is_small_angle(vcirc, v, succ_constraint(v, vcirc)));
|
|
cluster_map.insert(make_pair(v, cl));
|
|
} while(vcirc != vbegin);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
show_clusters()
|
|
{
|
|
multimap<Vertex_handle, Cluster>::iterator cmit = cluster_map.begin();
|
|
while(cmit != cluster_map.end()) {
|
|
Vertex_handle v = (*cmit).first;
|
|
map<Vertex_handle, Length>::iterator cit = (*cmit).second.vertices.begin();
|
|
while(cit != (*cmit).second.vertices.end()) {
|
|
Vertex_handle v1 = (*cit).first;
|
|
cit++;
|
|
}
|
|
cmit++;
|
|
}
|
|
}
|
|
|
|
//refine the cluster
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
cut_cluster(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
Cluster c;
|
|
find_cluster(va, vb, c);
|
|
check_cluster_status(c);
|
|
if( !is_cluster_reduced(c))
|
|
{
|
|
cut_cluster_edge(va, vb);
|
|
}
|
|
else
|
|
{
|
|
cut_reduced_cluster(va, vb);
|
|
}
|
|
}
|
|
|
|
|
|
//refine the reduced_cluster
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
cut_reduced_cluster(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
Cluster c;
|
|
find_cluster(va, vb, c);
|
|
Vertex_handle vm;
|
|
if(is_cluster_reduced(c))
|
|
{
|
|
// vm = insert_in_c_edge(va, vb, va->point() + (vb->point() - va->point())/2.0);
|
|
}
|
|
update_c_edge_queue(va, vb, vm);
|
|
update_facette_map(vm);
|
|
}
|
|
|
|
|
|
//refine the cluster edges
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
cut_cluster_edge(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
//seulement les constraints
|
|
Cluster c;
|
|
find_cluster(va, vb, c);
|
|
Square_length l2 = 2.0; //shortest_edge_of_cluster(va, c)/1.001;
|
|
Square_length L2 = squared_distance(va->point(), vb->point());
|
|
if(L2 > l2)
|
|
{
|
|
FT rapport = pow(2.0, rint(0.5*log(L2/l2)/log(2.0)))*::sqrt(l2/(L2*4));
|
|
Point pc=va->point()+(vb->point()-va->point())*rapport;
|
|
Vertex_handle vc = insert_in_c_edge(va,vb,pc);
|
|
flip_around(vc);
|
|
update_c_edge_queue(va, vb, vc);
|
|
update_facette_map(vc);
|
|
update_cluster(va, vb, vc);
|
|
}
|
|
}
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
Mesh<Gt, Tds, Mtraits>::Vertex_handle Mesh<Gt, Tds, Mtraits>::
|
|
insert_middle(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
Point midpoint;
|
|
midpoint = va->point() + (vb->point() - va->point())/2.0 ;
|
|
return insert_in_c_edge(va,vb, midpoint);
|
|
}
|
|
|
|
|
|
//insert in constraint edge the middle
|
|
template <class Gt, class Tds, class Mtraits>
|
|
Mesh<Gt, Tds, Mtraits>::Vertex_handle Mesh<Gt, Tds, Mtraits>::
|
|
insert_in_c_edge(Vertex_handle va, Vertex_handle vb, Point p)
|
|
{
|
|
Face_handle f;
|
|
int i;
|
|
is_edge(va, vb, f, i);
|
|
Vertex_handle v = Ct::special_insert_in_edge(p, f, i);
|
|
flip_around(v) ;
|
|
update_c_edge_queue(va, vb, v);
|
|
return v;
|
|
}
|
|
|
|
|
|
|
|
|
|
//update the encroached segments list
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
update_c_edge_queue(Vertex_handle va, Vertex_handle vb, Vertex_handle vm)
|
|
{
|
|
//c_edge_queue.pop_back();
|
|
Face_circulator fc = incident_faces(vm);
|
|
Face_circulator fcbegin = fc;
|
|
if(fc.is_empty()) return;
|
|
do {
|
|
int i;
|
|
for(i=0; i<3; i++) {
|
|
Edge e=Edge(fc, i);
|
|
Vertex_handle v1=e.first->vertex(cw(i));
|
|
Vertex_handle v2=e.first->vertex(ccw(i));
|
|
if(is_encroached(v1, v2)&&
|
|
e.first->is_constrained(i)&&
|
|
v1!=infinite_vertex()&&v2!=infinite_vertex())
|
|
{
|
|
c_edge_queue.push_back(Constrained_edge(v1, v2));
|
|
}
|
|
}
|
|
fc++;
|
|
} while(fc != fcbegin);
|
|
if(is_encroached(va, vm)) {
|
|
c_edge_queue.push_back(Constrained_edge(va, vm));
|
|
}
|
|
|
|
if(is_encroached(vb, vm)) {
|
|
c_edge_queue.push_back(Constrained_edge(vb, vm));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
update_facette_map(Vertex_handle v)
|
|
{
|
|
Face_circulator fc = v->incident_faces();
|
|
Face_circulator fcbegin = fc;
|
|
do {
|
|
if(!is_infinite(fc)) {
|
|
if(is_bad(fc)) {
|
|
Bad_faces.insert(make_pair(
|
|
circumradius_to_shortest_edge_ratio(fc), fc));
|
|
}
|
|
}
|
|
fc++;
|
|
} while(fc!=fcbegin);
|
|
}
|
|
|
|
|
|
//ok
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
update_cluster(Vertex_handle va, Vertex_handle vb, Vertex_handle vm)
|
|
{
|
|
multimap<Vertex_handle, Cluster>::iterator it_va_cluster =
|
|
cluster_map.find(va);
|
|
int n_va_cluster = cluster_map.count(va);
|
|
for(int i=0; i<n_va_cluster; i++)
|
|
{
|
|
map<Vertex_handle, Length> &vertices = (*it_va_cluster).second.vertices;
|
|
map<Vertex_handle, Length>::iterator it_vertices = vertices.find(vb);
|
|
if(it_vertices != vertices.end())
|
|
{
|
|
vertices.erase(vb);
|
|
if(va.is_null()) {}
|
|
if(vm.is_null()) {}
|
|
|
|
vertices[vm] = (squared_distance(va->point(), vm->point()));
|
|
break;
|
|
}
|
|
it_va_cluster++;
|
|
}
|
|
|
|
multimap<Vertex_handle, Cluster>::iterator it_vb_cluster =
|
|
cluster_map.find(vb);
|
|
int n_vb_cluster = cluster_map.count(vb);
|
|
for(int i=0; i<n_vb_cluster; i++)
|
|
{
|
|
map<Vertex_handle, Length> &vertices = (*it_vb_cluster).second.vertices;
|
|
map<Vertex_handle, Length>::iterator it_vertices = vertices.find(va);
|
|
if(it_vertices != vertices.end())
|
|
{
|
|
vertices.erase(va);
|
|
vertices[vm] = (squared_distance(vb->point(), vm->point()));
|
|
break;
|
|
}
|
|
it_vb_cluster++;
|
|
}
|
|
}
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
inline Mesh<Gt, Tds, Mtraits>::Edge
|
|
Mesh<Gt, Tds, Mtraits>::edge_between(Vertex_handle va, Vertex_handle vb) {
|
|
Edge_circulator ec = va->incident_edges();
|
|
Edge_circulator ecbegin = ec;
|
|
do {
|
|
Edge e = (*ec);
|
|
Face_handle f = e.first;
|
|
int iedge = e.second;
|
|
Vertex_handle v1 = f->vertex(cw(iedge));
|
|
Vertex_handle v2 = f->vertex(ccw(iedge));
|
|
if((v1 == va && v2 == vb) || (v2 == va && v1 == vb)) {
|
|
return e;
|
|
}
|
|
ec++;
|
|
} while(ec != ecbegin);
|
|
cerr<<"invalid edge"<<endl;
|
|
return INVALID_EDGE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//CHECK
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_encroached(Vertex_handle va, Vertex_handle vb, Point p)
|
|
{
|
|
Point pm=midpoint(va->point(), vb->point());
|
|
if(2.0*::sqrt(squared_distance(pm, p)) < ::sqrt(squared_distance(va->point(), vb->point())))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_encroached(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
Vertex_iterator vi=vertices_begin();
|
|
while(vi!=vertices_end())
|
|
{
|
|
if(is_encroached(va, vb, vi->point())&&
|
|
va!=Vertex_handle(vi)&&
|
|
vb!=Vertex_handle(vi))
|
|
{
|
|
return true;
|
|
}
|
|
vi++;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
min_insertion_radius(Vertex_handle v, Cluster &c)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//the measure of faces quality
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_bad(Face_handle f)
|
|
{
|
|
FT quality = circumradius_to_shortest_edge_ratio(f);
|
|
if((quality >1) || (quality < 0.5))
|
|
//set_a:(>1.0 || <0.4)
|
|
//set_b:(>1.0 || <0.5)
|
|
//set_c:(>1.1 || <0.5)
|
|
//set_d:(>1.1 || <0.4)
|
|
//set_e:(>0.9 || <0.5)
|
|
//set_f:(>0.9 || <0.4)//~NOK
|
|
//set_g:(>0.8 || <0.4)//NOK
|
|
//set_h:(>0.8 || <0.5)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
// }
|
|
}
|
|
|
|
|
|
//
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_small_angle(Vertex_handle vleft,
|
|
Vertex_handle vmiddle,
|
|
Vertex_handle vright)
|
|
{
|
|
FT cos_alpha;
|
|
cos_alpha = angle(vleft, vmiddle, vright);
|
|
if(cos_alpha > 1/2)
|
|
{
|
|
return TRUE; //the same cluster
|
|
}
|
|
else
|
|
{
|
|
return FALSE; //another cluster
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_cluster_reduced(const Cluster& c)
|
|
{
|
|
return c.status == REDUCED;
|
|
}
|
|
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
bool Mesh<Gt, Tds, Mtraits>::
|
|
is_cluster(Vertex_handle va, Vertex_handle vb)
|
|
{
|
|
// check if vb is in any cluster of va
|
|
pair<multimap<Vertex_handle, Cluster>::iterator,
|
|
multimap<Vertex_handle, Cluster>::iterator> range =
|
|
cluster_map.equal_range(va);
|
|
for(multimap<Vertex_handle, Cluster>::iterator it = range.first;
|
|
it != range.second; it++)
|
|
{
|
|
Cluster &cl = it->second;
|
|
if(cl.vertices.find(vb)!=cl.vertices.end()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
typename Gt::FT Mesh<Gt, Tds, Mtraits>::
|
|
shortest_edge_of_cluster(Vertex_handle v, Cluster &cluster)
|
|
{
|
|
map<Vertex_handle, Length>::iterator vit = cluster.vertices.begin();
|
|
FT min_edge = squared_distance(((*vit).first)->point(), (*v).point());
|
|
vit++;
|
|
while(vit != cluster.vertices.end())
|
|
{
|
|
FT temp = squared_distance(((*vit).first)->point(), (*v).point());
|
|
if(temp < min_edge)
|
|
{
|
|
min_edge = temp;
|
|
}
|
|
vit++;
|
|
}
|
|
return min_edge;
|
|
}
|
|
|
|
// look if all edges have the same lenght
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
check_cluster_status( Cluster& cluster)
|
|
{
|
|
Length initl;
|
|
map<Vertex_handle, Length>::iterator vi = cluster.vertices.begin();
|
|
initl = (*(cluster.vertices.find((*vi).first))).second;
|
|
vi++;
|
|
for(;vi != cluster.vertices.end(); vi++)
|
|
{
|
|
if(( (*(cluster.vertices.find((*vi).first))).second) != initl)
|
|
{
|
|
cluster.status = NON_REDUCED;
|
|
|
|
return;
|
|
}
|
|
vi++;
|
|
}
|
|
cluster.status = REDUCED;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
bounds(FT &xmin, FT &ymin,
|
|
FT &xmax, FT &ymax,
|
|
FT &xcenter, FT &ycenter)
|
|
{
|
|
Vertex_iterator vi=vertices_begin();
|
|
xmin=xmax=xcenter=vi->point().x();
|
|
ymin=ymax=ycenter=vi->point().y();
|
|
vi++;
|
|
while(vi != vertices_end())
|
|
{
|
|
xcenter+=vi->point().x();
|
|
ycenter+=vi->point().y();
|
|
if(vi->point().x() < xmin) xmin=vi->point().x();
|
|
if(vi->point().x() > xmax) xmax=vi->point().x();
|
|
if(vi->point().y() < ymin) ymin=vi->point().y();
|
|
if(vi->point().y() > ymax) ymax=vi->point().y();
|
|
vi++;
|
|
}
|
|
xcenter /= number_of_vertices();
|
|
ycenter /= number_of_vertices();
|
|
}
|
|
|
|
|
|
//bounding box
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
bounding_box()
|
|
{
|
|
|
|
FT span;
|
|
FT xmin, xmax, ymin, ymax, xcenter, ycenter;
|
|
bounds(xmin, ymin, xmax, ymax, xcenter, ycenter);
|
|
span = max((xmax-xmin), (ymax-ymin));
|
|
Point bb1(xcenter - 1.5*span, ycenter - 1.5*span);
|
|
Point bb2(xcenter + 1.5*span, ycenter - 1.5*span);
|
|
Point bb3(xcenter + 1.5*span, ycenter + 1.5*span);
|
|
Point bb4(xcenter - 1.5*span, ycenter + 1.5*span);
|
|
insert(bb1);
|
|
insert(bb2);
|
|
insert(bb3);
|
|
insert(bb4);
|
|
insert(bb1, bb2);
|
|
insert(bb2, bb3);
|
|
insert(bb3, bb4);
|
|
insert(bb4, bb1);
|
|
|
|
}
|
|
|
|
|
|
//the angle that are between 2 edges from the triangulation
|
|
template <class Gt, class Tds, class Mtraits>
|
|
typename Gt::FT Mesh<Gt, Tds, Mtraits>::
|
|
angle(Vertex_handle vleft, Vertex_handle vmiddle, Vertex_handle vright)
|
|
{
|
|
Point
|
|
pa = vleft->point(),
|
|
pb = vmiddle->point(),
|
|
pc = vright->point();
|
|
FT a, b, c;
|
|
a = ::sqrt(squared_distance(pb, pc));
|
|
b = ::sqrt(squared_distance(pc, pa));
|
|
c = ::sqrt(squared_distance(pa, pb));
|
|
FT cos_alpha = ((a*a+c*c-b*b)/(2*a*c));
|
|
return cos_alpha;
|
|
}
|
|
|
|
|
|
//the shortest edge that are in a triangle
|
|
template <class Gt, class Tds, class Mtraits>
|
|
typename Gt::FT Mesh<Gt, Tds, Mtraits>::
|
|
shortest_edge(Face_handle f)
|
|
{
|
|
Point
|
|
pa = (f->vertex(0))->point(),
|
|
pb = (f->vertex(1))->point(),
|
|
pc = (f->vertex(2))->point();
|
|
FT a, b, c;
|
|
a =(squared_distance(pb, pc));
|
|
b =(squared_distance(pc, pa));
|
|
c =(squared_distance(pa, pb));
|
|
return (min(a, min(b, c))); // regarder la documentation du CGAL sur
|
|
// MIN (Developer Manual)
|
|
}
|
|
|
|
|
|
//the triangle quality is represented by the
|
|
//circumradius_to_shortest_edge_ratio value
|
|
template <class Gt, class Tds, class Mtraits>
|
|
typename Gt::FT Mesh<Gt, Tds, Mtraits>::
|
|
circumradius_to_shortest_edge_ratio(Face_handle f)
|
|
{
|
|
Point p;
|
|
p = circumcenter(f);
|
|
Point A = (f->vertex(0))->point();
|
|
FT radius =::sqrt(squared_distance(p, A));
|
|
FT sh_edge =::sqrt(shortest_edge(f));
|
|
return (radius/sh_edge);
|
|
}
|
|
|
|
|
|
//insertion radius: the definition
|
|
template <class Gt, class Tds, class Mtraits>
|
|
typename Gt::FT Mesh<Gt, Tds, Mtraits>::
|
|
insertion_radius(Vertex_handle v)
|
|
{
|
|
Vertex_handle v1 = nearest_incident_vertex(v);
|
|
return (squared_distance(v->point(), v1->point()));
|
|
}
|
|
|
|
|
|
//this function must compute the vertex that are so close to our vertex.
|
|
template <class Gt, class Tds, class Mtraits>
|
|
Mesh<Gt, Tds, Mtraits>::Vertex_handle Mesh<Gt, Tds, Mtraits>::
|
|
nearest_incident_vertex(Vertex_handle v)
|
|
{
|
|
Vertex_handle vbegin, vcurrent, vnearest;
|
|
Vertex_circulator circ = v->incident_vertices();
|
|
vbegin = circ;
|
|
vnearest = vbegin;
|
|
circ++;
|
|
FT dist = (squared_distance(v->point(), vbegin->point()));
|
|
while((vcurrent = circ) != vbegin) {
|
|
FT d1 = (squared_distance(v->point(), vcurrent->point()));
|
|
if(d1 < dist) {
|
|
vnearest = vcurrent;
|
|
}
|
|
circ++;
|
|
}
|
|
return vnearest;
|
|
}
|
|
|
|
|
|
//the mesh refine function
|
|
template <class Gt, class Tds, class Mtraits>
|
|
void Mesh<Gt, Tds, Mtraits>::
|
|
refine_mesh( QWidget *w)
|
|
{
|
|
viewer = w;
|
|
// bounding_box();
|
|
create_clusters();
|
|
show_clusters();
|
|
|
|
fill_edge_queue();
|
|
fill_facette_map();
|
|
process_edge_queue();
|
|
process_facette_map();
|
|
|
|
}
|
|
|
|
//CGAL_END_NAMESPACE
|
|
|
|
|
|
#endif
|
|
|