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