1 /****************************************************************************/
2 /* This file is part of FreeFEM.                                            */
3 /*                                                                          */
4 /* FreeFEM is free software: you can redistribute it and/or modify          */
5 /* it under the terms of the GNU Lesser General Public License as           */
6 /* published by the Free Software Foundation, either version 3 of           */
7 /* the License, or (at your option) any later version.                      */
8 /*                                                                          */
9 /* FreeFEM is distributed in the hope that it will be useful,               */
10 /* but WITHOUT ANY WARRANTY; without even the implied warranty of           */
11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
12 /* GNU Lesser General Public License for more details.                      */
13 /*                                                                          */
14 /* You should have received a copy of the GNU Lesser General Public License */
15 /* along with FreeFEM. If not, see <http://www.gnu.org/licenses/>.          */
16 /****************************************************************************/
17 // SUMMARY : DelaunayFlip
18 // LICENSE : LGPLv3
19 // ORG     : LJLL Universite Pierre et Marie Curie, Paris, FRANCE
20 // AUTHORS : Jean-Marie Mirebeau
21 // E-MAIL  : jean-marie.mirebeau@math.u-psud.fr
22 
23 #ifndef GEOMETRY
24 #define GEOMETRY
25 
26 #include <iostream>
27 #include "RZ.h"
28 #include "SortedList.h"
29 
30 using namespace std;
31 
32 /**************** Vertex ******************/
33 class Vertex : public R2 {    // heritage is perhaps not totally justified here, but...
34   sym2 m;
35   int gen;
36   // friend int main(int argc, const char * argv[]); //for Debug purposes
37 
38  public:
Vertex()39   Vertex( ) : R2( ), m( ){};
Vertex(R2 u,int Gen,sym2 metric=sym2 ())40   Vertex(R2 u, int Gen, sym2 metric = sym2( )) : R2(u), gen(Gen), m(metric) {}
41 
Vertex(R2 u,int Gen,const Metric2 & metric)42   Vertex(R2 u, int Gen, const Metric2 &metric) : R2(u), gen(Gen), m(metric(u)) {}
43 
getm() const44   const sym2 &getm( ) const { return m; }
45 
getGen() const46   int getGen( ) const { return gen; }
47 
homogeneousDistance() const48   sym3 homogeneousDistance( ) const {
49     const R2 a(*this);
50     const R2 ma = m * a;
51     const double ama = a.scal(ma);
52     return sym3(m.xx, m.yy, ama, m.xy, -ma.y, -ma.x);
53   }
54 
dist2(const R2 & P) const55   double dist2(const R2 &P) const { return m.norm2(*this - P); }
56 };
57 
58 /*inline ostream& operator<<(ostream &f, const Vertex &u){f<<R2(u)<<u.getGen(); return f;}
59  * inline ostream_math operator<<(ostream_math f, const Vertex &u){
60  *  if(f.format==Mathematica) f<<"{"<<R2(u)<<","<<u.getGen()<<"}"; else f.os<<u; return f;}
61  */
operator <<(ostream & f,const Vertex & u)62 inline ostream &operator<<(ostream &f, const Vertex &u) { return f << R2(u); }
63 
operator <<(ostream_math f,const Vertex & u)64 inline ostream_math operator<<(ostream_math f, const Vertex &u) {
65   return f << "{" << R2(u) << "," << u.getGen( ) << "," << u.getm( ) << "}";
66 }
67 
68 /****************** Edge ****************/
69 class Edge {    // edges are oriented. t is on the left.
70                 // bool refinable;
71   Vertex const *u;
72   Vertex const *
73     v;    // Note : routines tend to leave v constant when possible (i.e. except construct and flip)
74   Edge *next, *sister;    // next edge on triangle and reversed edge
prev() const75   Edge *prev( ) const { return next->next; }
76 
77   bool cut(Vertex const *start, Vertex const *end, Edge *oldSister, Tab< Edge > &EdgeAllocator,
78            Tab< Vertex > &VertexAllocator, const Metric2 &metric, vector< Edge * > &aligned);
79   // friend int main(int argc, const char * argv[]); //for Debug purposes
80 #ifdef _FLAGGED_BOUNDARY_
81   int onBoundary_;
82 #endif
83 
84  public:
Edge()85   Edge( ) : u(NULL), v(NULL), next(NULL), sister(NULL){};
86 
87 #ifdef _FLAGGED_BOUNDARY_
Edge(Vertex const * U,Vertex const * V,Edge * S,Edge * N,int OnBoundary_=0)88   Edge(Vertex const *U, Vertex const *V, Edge *S, Edge *N, int OnBoundary_ = 0)
89     : u(U), v(V), sister(S), next(N), onBoundary_(OnBoundary_){};
onBoundary() const90   int onBoundary( ) const {
91     return onBoundary_;
92   }    // {if(sister!=NULL) return 0; if(onBoundary_>0) return onBoundary_; return 10;}
93 
94 #else
Edge(Vertex const * U,Vertex const * V,Edge * S,Edge * N)95   Edge(Vertex const *U, Vertex const *V, Edge *S, Edge *N) : u(U), v(V), next(N), sister(S){};
onBoundary() const96   bool onBoundary( ) const { return sister == NULL; }
97 
98 #endif
99 
100   inline bool flipable( ) const;
101   inline double flipGain( ) const;    // gain brought by a flip in terms of square cosine
102   inline bool flip( );
103   inline bool flip(Edge *affected[4]);
104   inline bool flip_resolve( );
getu() const105   Vertex const *getu( ) const { return u; }
106 
getv() const107   Vertex const *getv( ) const { return v; }
108 
vec() const109   R2 vec( ) const { return *v - *u; }    // R2(v->x - u->x, v->y - u->y)
110 
isRepresentative() const111   bool isRepresentative( ) const {
112     return (sister == NULL) || (u->x < v->x) || (u->x == v->x && u->y < v->y);
113   }
114 
representative()115   Edge *representative( ) { return isRepresentative( ) ? this : sister; }
116 
isRepresentative3() const117   bool isRepresentative3( ) const {
118     R2 v = vec( );
119     return v < next->vec( ) && v < prev( )->vec( );
120   }
121 
isRepresentative3(Vertex const * triangle[3]) const122   bool isRepresentative3(Vertex const *triangle[3]) const {
123     triangle[0] = u;
124     triangle[1] = v;
125     triangle[2] = next->v;
126     return isRepresentative3( );
127   }
128 
129   enum refinement_priority {
130     selected_edge_first,
131     newest_vertex_first,
132     euclidean_longest_edge_first
133   };
134   Edge *which_first(refinement_priority priority);
135   // refine splits the edge and returns a pointer to the other half of the splitted edge //bool
136   // newestVertexFirst=true
137   Edge *refine(Tab< Edge > &EdgeAllocator, Tab< Vertex > &VertexAllocator, const Metric2 &metric,
138                refinement_priority priority);
139   // splits associated triangle if larger than size h/sqrt(smallEigenVal) (metric taken at the worst
140   // point on the triangle). Non recursive.
141   bool hRefine3(double h, Tab< Edge > &EdgeAllocator, Tab< Vertex > &VertexAllocator,
142                 const Metric2 &metric, refinement_priority priority);
143   // splits the edge if its length in the metric (taken at the worst point on the edge) is larger
144   // than h.
145   Edge *hRefine2(double h, Tab< Edge > &EdgeAllocator, Tab< Vertex > &VertexAllocator,
146                  const Metric2 &metric, safe_vector< Edge * > *recursive = NULL,
147                  bool exaggerate = false);
148   bool check( ) const;
149 
getNext() const150   Edge *getNext( ) const { return next; }
151 
getSister() const152   Edge *getSister( ) const { return sister; }
153 
154   bool cut(Vertex const *start, Vertex const *end, Tab< Edge > &EdgeAllocator,
155            Tab< Vertex > &VertexAllocator, const Metric2 &metric, vector< Edge * > &aligned);
156   Vertex *intersect(Vertex const *start, Vertex const *end, Tab< Vertex > &VertexAllocator,
157                     const Metric2 &metric);
158 };
159 
operator <<(ostream & f,const Edge & e)160 inline ostream &operator<<(ostream &f, const Edge &e) {
161   f << R2(*(e.getu( ))) << " " << R2(*(e.getv( )));
162   return f;
163 }
164 
operator <<(ostream_math f,const Edge & e)165 inline ostream_math operator<<(ostream_math f, const Edge &e) {
166   if (f.format == Mathematica) {
167     f << "{" << R2(*(e.getu( ))) << "," << R2(*(e.getv( ))) << "}";
168   } else {
169     f.os << e;
170   }
171 
172   return f;
173 }
174 
check() const175 inline bool Edge::check( ) const {
176   if (u == NULL || v == NULL) {
177     cout << "Edge::check : Invalid extremities";
178   } else if (u == v) {
179     cout << "Edge::check : identical extremities";
180   } else if (next == NULL || next->next == NULL) {
181     cout << "Edge::check : Missing edge connections";
182   } else if (next->next->next != this) {
183     cout << "Edge::check : not a triangle";
184   } else if (next->u != v) {
185     cout << "Edge::check : invalid next edge (next->u!=v)";
186   } else if (sister != NULL && sister->u != v) {
187     cout << "Edge::check : invalid sister edge";
188   }
189   // else if(sister!=NULL && refinable && !sister->refinable) cout<<"Edge::check : flag refinable
190   // inconsistent with sister edge"<<endl;
191   else if (isRepresentative3( ) && det(vec( ), next->vec( )) < 0) {
192     cout << "Edge::check : trigonometric order not respected";
193   }
194 
195 #ifdef _FLAGGED_BOUNDARY_
196   else if (sister == NULL && onBoundary_ == 0) {
197     cout << "Edge::check : Interior edge without sister !" << endl;
198   }
199 #endif
200   else {
201     return true;
202   }
203   coutMath << " " << *this << *next << *next->next << endl;
204   return false;
205 }
206 
flipable() const207 inline bool Edge::flipable( ) const {
208   return !onBoundary( ) && det(sister->prev( )->vec( ), next->vec( )) > 0 &&
209          det(prev( )->vec( ), sister->next->vec( )) > 0;
210 }
211 
flipGain() const212 inline double Edge::flipGain( ) const {    // edge is assumed to be flipable, hence angles are <pi.
213                                            // Result positive <=> flip increases minimum angle.
214   if (!flipable( )) {
215     return 0;
216   }
217 
218   Vertex const *s = next->v;
219   Vertex const *t = sister->next->v;
220   const R2 uv = *v - *u, st = *t - *s, vs = *s - *v, su = *u - *s, ut = *t - *u, tv = *v - *t;
221   const sym2 &mu = u->getm( ), &mv = v->getm( ), ms = s->getm( ), mt = t->getm( );
222   return min(min(min(-ms.cos(st, vs), ms.cos(st, su)), min(mt.cos(st, ut), -mt.cos(st, tv))),
223              min(-mu.cos(su, ut), -mv.cos(tv, vs))) -
224          min(min(min(-mu.cos(uv, su), mu.cos(uv, ut)), min(mv.cos(uv, tv), -mv.cos(uv, vs))),
225              min(-ms.cos(vs, su), -mt.cos(ut, tv)));
226 }
227 
flip()228 inline bool Edge::flip( ) {
229   if (sister == NULL) {
230     return false;    // triangle inversion is unchecked
231   }
232 
233   Edge *e = this, *f = sister;
234   Edge *ep = prev( ), *fp = sister->prev( );
235   Vertex const *u = ep->u;
236   Vertex const *v = fp->u;
237 
238   e->u = u;
239   e->v = v;
240   f->u = v;
241   f->v = u;
242 
243   e->next->next = e;
244   f->next->next = f;
245   ep->next = f->next;
246   fp->next = e->next;
247   e->next = fp;
248   f->next = ep;
249   return true;
250 }
251 
flip(Edge * affected[4])252 inline bool Edge::flip(Edge *affected[4]) {    // representatives of affected edges
253   if (flip( )) {
254     affected[0] = next->representative( );
255     affected[1] = prev( )->representative( );
256     affected[2] = sister->next->representative( );
257     affected[3] = sister->prev( )->representative( );
258     return true;
259   }
260 
261   return false;
262 }
263 
flip_resolve()264 inline bool Edge::flip_resolve( ) {
265   if (flipGain( ) <= 0) {
266     return false;
267   }
268 
269   Edge *affected[4];
270   flip(affected);
271 
272   for (int i = 0; i < 4; i++) {
273     affected[i]->flip_resolve( );
274   }
275 
276   return true;
277 }
278 
279 /****************************************************/
280 
281 class Triangulation {
282   Tab< Vertex > vertices;
283   Tab< Edge > edges;
284   friend int main(int argc, const char *argv[]);    // for Debug purposes
285 
286  public:
287   const Metric2 &metric;
getVertices()288   const Tab< Vertex > &getVertices( ) { return vertices; }
289 
getEdges()290   const Tab< Edge > &getEdges( ) { return edges; }
291 
nv() const292   int nv( ) const { return vertices.card( ); }
293 
ne_oriented() const294   int ne_oriented( ) const { return edges.card( ); }
295 
nt() const296   int nt( ) const { return ne_oriented( ) / 3; }
297 
298   Triangulation(int N, const Metric2 &Metric);    // basic NxN square triangulation
299   // Triangulation(const Tab<Vertex> &Vertices, const Tab<Edge> &Edges, sym2 (*Metric)(const
300   // R2&)=NULL, double Lip=5): vertices(Vertices), edges(Edges), metric(Metric), lip(Lip)
301   // {if(!check()) cout << "Invalid triangulation !" << endl; movie_init();} //pointer mismatch
302 #ifdef FF___HPP_
303   Triangulation(const Fem2D::Mesh &Th, const Metric2 &Metric);
304 #endif
305 
306   void Delaunay_ordered(const vector< bool > &toExclude);
Delaunay_ordered()307   void Delaunay_ordered( ) {
308     vector< bool > toExclude;
309     toExclude.resize(ne_oriented( ));
310     Delaunay_ordered(toExclude);
311   }
312 
Delaunay_unordered()313   void Delaunay_unordered( ) {
314     for (int i = 0; i < ne_oriented( ); ++i) {
315       edges[i].flip_resolve( );
316     }
317   }
318 
Connectivity(Tab<Z2> & connectivity) const319   int Connectivity(Tab< Z2 > &connectivity) const {
320     int counter = 0;
321 
322     for (int i = 0; i < ne_oriented( ); ++i) {
323       if (edges[i].isRepresentative( )) {
324         connectivity[counter++] =
325           Z2(vertices.index(edges[i].getu( )), vertices.index(edges[i].getv( )));
326       }
327     }
328 
329     return nt( );    // number of triangles
330   }
331 
332   // Refines triangles isotropically, based on the small eigenvalue of the metric.
hRefine(double h=1,Edge::refinement_priority priority=Edge::euclidean_longest_edge_first)333   void hRefine(double h = 1,
334                Edge::refinement_priority priority = Edge::euclidean_longest_edge_first) {
335     if (h <= 0) {
336       return;
337     }
338 
339     for (int i = 0; i < ne_oriented( ); ++i) {
340       if (edges[i].hRefine3(h, edges, vertices, metric, priority)) {
341         movie_frame( );
342       }
343     }
344   }
345 
346   void hRefineQA(double h = 1, unsigned int flag = 0,
347                  Edge::refinement_priority priority = Edge::euclidean_longest_edge_first);
348   enum hRefineQA_opt { hRQA_finalRefine = 1, hRQA_exportIntermediateData = 2, hRQA_noIsoRef = 4 };
349 
350   // Affects only the position, not the metric
moveMesh(R2 (* vec)(const R2 &),double amplification=1)351   void moveMesh(R2 (*vec)(const R2 &), double amplification = 1) {
352     for (int i = 0; i < nv( ); i++) {
353       vertices[i] += vec(vertices[i]) * amplification;
354     }
355   }
356 
check() const357   bool check( ) const {
358     bool passed = true;
359 
360     for (int i = 0; i < edges.card( ); i++) {
361       passed = passed && edges[i].check( );
362     }
363 
364     return passed;
365   }
366 
367   void export_to_FreeFem(const char *filename) const;
368   Fem2D::Mesh *export_to_Mesh( ) const;
export_to_Mathematica(const char * filename) const369   void export_to_Mathematica(const char *filename) const {
370     ofstream data_out;
371     data_out.open(filename);
372     data_out << Mathematica << edges;
373     data_out.close( );
374   }
375 
export_to_Mathematica_Metric(const char * filename) const376   void export_to_Mathematica_Metric(const char *filename) const {
377     ofstream data_out;
378     data_out.open(filename);
379     data_out << Mathematica << vertices;
380     data_out.close( );
381   }
382 
export_to(Format_Math format,const char * filename) const383   void export_to(Format_Math format, const char *filename) const {
384     if (format == Mathematica) {
385       export_to_Mathematica(filename);
386     } else {
387       export_to_FreeFem(filename);
388     }
389   }
390 
391   // movie functionality
392   string movie_name;
393   Format_Math movie_format;
394   mutable int movie_frame_number;
movie_frame() const395   void movie_frame( ) const {
396     if (movie_name.size( ) == 0) {
397       return;
398     }
399 
400     export_to(movie_format, movie_frame_name( ).c_str( ));
401   }
402 
403  private:
movie_init()404   void movie_init( ) {
405     movie_name = "";
406     movie_frame_number = 0;
407     movie_format = Mathematica;
408   }
409 
410   string movie_frame_name( ) const;
411 };
412 
413 #endif
414