1
// Copyright (C) 2012 Johannes Ring
3
// This file is part of DOLFIN.
5
// DOLFIN is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU Lesser General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
10
// DOLFIN is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU Lesser General Public License for more details.
15
// You should have received a copy of the GNU Lesser General Public License
16
// along with DOLFIN. If not, see <http://www.gnu.org/licenses/>.
18
// Modified by Joachim B Haga 2012
19
// Modified by Benjamin Kehlet 2012
21
// First added: 2012-05-10
22
// Last changed: 2012-11-14
27
#include <dolfin/common/constants.h>
28
#include <dolfin/math/basic.h>
29
#include <dolfin/mesh/Mesh.h>
30
#include <dolfin/mesh/MeshEditor.h>
32
#include "CSGCGALMeshGenerator2D.h"
33
#include "CSGGeometry.h"
34
#include "CSGOperators.h"
35
#include "CSGPrimitives2D.h"
38
#include "CGALMeshBuilder.h"
40
#include <CGAL/basic.h>
41
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
42
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
44
#include <CGAL/Gmpq.h>
45
#include <CGAL/Lazy_exact_nt.h>
46
#include <CGAL/Simple_cartesian.h>
47
#include <CGAL/Bounded_kernel.h>
48
#include <CGAL/Nef_polyhedron_2.h>
49
#include <CGAL/Polygon_2.h>
50
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
51
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
52
#include <CGAL/Triangulation_face_base_with_info_2.h>
53
#include <CGAL/Delaunay_mesher_2.h>
54
#include <CGAL/Delaunay_mesh_face_base_2.h>
55
#include <CGAL/Delaunay_mesh_size_criteria_2.h>
57
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_Kernel;
58
typedef CGAL::Exact_predicates_inexact_constructions_kernel Inexact_Kernel;
60
typedef CGAL::Lazy_exact_nt<CGAL::Gmpq> FT;
61
typedef CGAL::Simple_cartesian<FT> EKernel;
62
typedef CGAL::Bounded_kernel<EKernel> Extended_kernel;
63
typedef CGAL::Nef_polyhedron_2<Extended_kernel> Nef_polyhedron_2;
64
typedef Nef_polyhedron_2::Point Nef_point_2;
66
typedef Nef_polyhedron_2::Explorer Explorer;
67
typedef Explorer::Face_const_iterator Face_const_iterator;
68
typedef Explorer::Hole_const_iterator Hole_const_iterator;
69
typedef Explorer::Halfedge_around_face_const_circulator Halfedge_around_face_const_circulator;
70
typedef Explorer::Vertex_const_handle Vertex_const_handle;
71
typedef Explorer::Halfedge_const_handle Halfedge_const_handle;
73
typedef CGAL::Triangulation_vertex_base_2<Inexact_Kernel> Vertex_base;
74
typedef CGAL::Constrained_triangulation_face_base_2<Inexact_Kernel> Face_base;
78
class Enriched_face_base_2 : public Fb {
80
typedef Gt Geom_traits;
81
typedef typename Fb::Vertex_handle Vertex_handle;
82
typedef typename Fb::Face_handle Face_handle;
84
template < typename TDS2 >
86
typedef typename Fb::template Rebind_TDS<TDS2>::Other Fb2;
87
typedef Enriched_face_base_2<Gt,Fb2> Other;
94
Enriched_face_base_2(): Fb(), status(-1) {};
96
Enriched_face_base_2(Vertex_handle v0,
99
: Fb(v0,v1,v2), status(-1) {};
101
Enriched_face_base_2(Vertex_handle v0,
107
: Fb(v0,v1,v2,n0,n1,n2), status(-1) {};
110
bool is_in_domain() const { return (status%2 == 1); };
113
void set_in_domain(const bool b) { status = (b ? 1 : 0); };
116
void set_counter(int i) { status = i; };
119
int counter() const { return status; };
122
int& counter() { return status; };
123
}; // end class Enriched_face_base_2
125
typedef CGAL::Triangulation_vertex_base_2<Inexact_Kernel> Vb;
126
typedef CGAL::Triangulation_vertex_base_with_info_2<std::size_t, Inexact_Kernel, Vb> Vbb;
127
typedef Enriched_face_base_2<Inexact_Kernel, Face_base> Fb;
128
typedef CGAL::Triangulation_data_structure_2<Vbb, Fb> TDS;
129
typedef CGAL::Exact_predicates_tag Itag;
130
typedef CGAL::Constrained_Delaunay_triangulation_2<Inexact_Kernel, TDS, Itag> CDT;
131
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT> Mesh_criteria_2;
132
typedef CGAL::Delaunay_mesher_2<CDT, Mesh_criteria_2> CGAL_Mesher_2;
134
typedef CDT::Vertex_handle Vertex_handle;
135
typedef CDT::Face_handle Face_handle;
136
typedef CDT::All_faces_iterator All_faces_iterator;
138
typedef CGAL::Polygon_2<Inexact_Kernel> Polygon_2;
139
typedef Inexact_Kernel::Point_2 Point_2;
141
using namespace dolfin;
143
//-----------------------------------------------------------------------------
144
CSGCGALMeshGenerator2D::CSGCGALMeshGenerator2D(const CSGGeometry& geometry)
147
parameters = default_parameters();
149
//-----------------------------------------------------------------------------
150
CSGCGALMeshGenerator2D::~CSGCGALMeshGenerator2D() {}
151
//-----------------------------------------------------------------------------
152
Nef_polyhedron_2 make_circle(const Circle* c)
154
std::vector<Nef_point_2> pts;
156
for (std::size_t i = 0; i < c->fragments(); i++)
158
const double phi = (2*DOLFIN_PI*i) / c->fragments();
159
const double x = c->center().x() + c->radius()*cos(phi);
160
const double y = c->center().y() + c->radius()*sin(phi);
161
pts.push_back(Nef_point_2(x, y));
164
return Nef_polyhedron_2(pts.begin(), pts.end(), Nef_polyhedron_2::INCLUDED);
166
//-----------------------------------------------------------------------------
167
Nef_polyhedron_2 make_ellipse(const Ellipse* e)
169
std::vector<Nef_point_2> pts;
171
for (std::size_t i = 0; i < e->fragments(); i++)
173
const double phi = (2*DOLFIN_PI*i) / e->fragments();
174
const double x = e->center().x() + e->a()*cos(phi);
175
const double y = e->center().y() + e->b()*sin(phi);
176
pts.push_back(Nef_point_2(x, y));
179
return Nef_polyhedron_2(pts.begin(), pts.end(), Nef_polyhedron_2::INCLUDED);
181
//-----------------------------------------------------------------------------
182
Nef_polyhedron_2 make_rectangle(const Rectangle* r)
184
const double x0 = std::min(r->first_corner().x(), r->first_corner().y());
185
const double y0 = std::max(r->first_corner().x(), r->first_corner().y());
187
const double x1 = std::min(r->second_corner().x(), r->second_corner().y());
188
const double y1 = std::max(r->second_corner().x(), r->second_corner().y());
190
std::vector<Nef_point_2> pts;
191
pts.push_back(Nef_point_2(x0, x1));
192
pts.push_back(Nef_point_2(y0, x1));
193
pts.push_back(Nef_point_2(y0, y1));
194
pts.push_back(Nef_point_2(x0, y1));
196
return Nef_polyhedron_2(pts.begin(), pts.end(), Nef_polyhedron_2::INCLUDED);
198
//-----------------------------------------------------------------------------
199
Nef_polyhedron_2 make_polygon(const Polygon* p)
201
std::vector<Nef_point_2> pts;
202
std::vector<Point>::const_iterator v;
203
for (v = p->vertices().begin(); v != p->vertices().end(); ++v)
204
pts.push_back(Nef_point_2(v->x(), v->y()));
206
return Nef_polyhedron_2(pts.begin(), pts.end(), Nef_polyhedron_2::INCLUDED);
208
//-----------------------------------------------------------------------------
209
static Nef_polyhedron_2 convertSubTree(const CSGGeometry *geometry)
211
switch (geometry->getType()) {
212
case CSGGeometry::Union:
214
const CSGUnion* u = dynamic_cast<const CSGUnion*>(geometry);
216
return convertSubTree(u->_g0.get()) + convertSubTree(u->_g1.get());
219
case CSGGeometry::Intersection:
221
const CSGIntersection* u = dynamic_cast<const CSGIntersection*>(geometry);
223
return convertSubTree(u->_g0.get()) * convertSubTree(u->_g1.get());
226
case CSGGeometry::Difference:
228
const CSGDifference* u = dynamic_cast<const CSGDifference*>(geometry);
230
return convertSubTree(u->_g0.get()) - convertSubTree(u->_g1.get());
233
case CSGGeometry::Circle:
235
const Circle* c = dynamic_cast<const Circle*>(geometry);
237
return make_circle(c);
240
case CSGGeometry::Ellipse:
242
const Ellipse* c = dynamic_cast<const Ellipse*>(geometry);
244
return make_ellipse(c);
247
case CSGGeometry::Rectangle:
249
const Rectangle* r = dynamic_cast<const Rectangle*>(geometry);
251
return make_rectangle(r);
254
case CSGGeometry::Polygon:
256
const Polygon* p = dynamic_cast<const Polygon*>(geometry);
258
return make_polygon(p);
262
dolfin_error("CSGCGALMeshGenerator2D.cpp",
263
"converting geometry to cgal polyhedron",
264
"Unhandled primitive type");
266
return Nef_polyhedron_2();
268
//-----------------------------------------------------------------------------
269
// Taken from examples/Triangulation_2/polygon_triangulation.cpp in the
272
// Explore set of facets connected with non constrained edges,
273
// and attribute to each such set a counter.
274
// We start from facets incident to the infinite vertex, with a counter
275
// set to 0. Then we recursively consider the non-explored facets incident
276
// to constrained edges bounding the former set and increase thecounter by 1.
277
// Facets in the domain are those with an odd nesting level.
278
void mark_domains(CDT& ct,
279
CDT::Face_handle start,
281
std::list<CDT::Edge>& border)
283
if (start->counter() != -1)
286
std::list<CDT::Face_handle> queue;
287
queue.push_back(start);
289
while (!queue.empty())
291
CDT::Face_handle fh = queue.front();
293
if (fh->counter() == -1)
295
fh->counter() = index;
296
fh->set_in_domain(index%2 == 1);
297
for (int i = 0; i < 3; i++)
300
CDT::Face_handle n = fh->neighbor(i);
301
if (n->counter() == -1)
303
if (ct.is_constrained(e))
312
//-----------------------------------------------------------------------------
313
void mark_domains(CDT& cdt)
315
for (CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it)
319
std::list<CDT::Edge> border;
320
mark_domains(cdt, cdt.infinite_face(), index++, border);
321
while (!border.empty())
323
CDT::Edge e = border.front();
325
CDT::Face_handle n = e.first->neighbor(e.second);
326
if (n->counter() == -1)
327
mark_domains(cdt, n, e.first->counter()+1, border);
330
//-----------------------------------------------------------------------------
331
void CSGCGALMeshGenerator2D::generate(Mesh& mesh)
333
Nef_polyhedron_2 cgal_geometry = convertSubTree(&geometry);
335
// Create empty CGAL triangulation
338
// Explore the Nef polyhedron and insert constraints in the triangulation
339
Explorer explorer = cgal_geometry.explorer();
340
Face_const_iterator fit = explorer.faces_begin();
341
for (; fit != explorer.faces_end(); fit++)
343
// Skip face if it is not part of polygon
344
if (!explorer.mark(fit))
347
Halfedge_around_face_const_circulator hafc = explorer.face_cycle(fit), done(hafc);
349
Vertex_handle va = cdt.insert(Point_2(to_double(hafc->vertex()->point().x()),
350
to_double(hafc->vertex()->point().y())));
351
Vertex_handle vb = cdt.insert(Point_2(to_double(hafc->next()->vertex()->point().x()),
352
to_double(hafc->next()->vertex()->point().y())));
353
cdt.insert_constraint(va, vb);
355
} while (hafc != done);
357
Hole_const_iterator hit = explorer.holes_begin(fit);
358
for (; hit != explorer.holes_end(fit); hit++)
360
Halfedge_around_face_const_circulator hafc(hit), done(hit);
362
Vertex_handle va = cdt.insert(Point_2(to_double(hafc->vertex()->point().x()),
363
to_double(hafc->vertex()->point().y())));
364
Vertex_handle vb = cdt.insert(Point_2(to_double(hafc->next()->vertex()->point().x()),
365
to_double(hafc->next()->vertex()->point().y())));
366
cdt.insert_constraint(va, vb);
368
} while (hafc != done);
372
// Mark parts that are inside and outside the domain
376
CGAL_Mesher_2 mesher(cdt);
378
// Add seeds for all faces in the domain
379
std::list<Point_2> list_of_seeds;
380
for(CDT::Finite_faces_iterator fit = cdt.finite_faces_begin();
381
fit != cdt.finite_faces_end(); ++fit)
383
if (fit->is_in_domain())
385
// Calculate center of triangle and add to list of seeds
386
Point_2 p0 = fit->vertex(0)->point();
387
Point_2 p1 = fit->vertex(1)->point();
388
Point_2 p2 = fit->vertex(2)->point();
389
const double x = (p0[0] + p1[0] + p2[0]) / 3;
390
const double y = (p0[1] + p1[1] + p2[1]) / 3;
391
list_of_seeds.push_back(Point_2(x, y));
394
mesher.set_seeds(list_of_seeds.begin(), list_of_seeds.end(), true);
396
// Set shape and size criteria
397
Mesh_criteria_2 criteria(parameters["triangle_shape_bound"],
398
parameters["cell_size"]);
399
mesher.set_criteria(criteria);
401
// Refine CGAL mesh/triangulation
402
mesher.refine_mesh();
404
// Make sure triangulation is valid
405
dolfin_assert(cdt.is_valid());
410
// Get various dimensions
411
const std::size_t gdim = cdt.finite_vertices_begin()->point().dimension();
412
const std::size_t tdim = cdt.dimension();
413
const std::size_t num_vertices = cdt.number_of_vertices();
416
std::size_t num_cells = 0;
417
CDT::Finite_faces_iterator cgal_cell;
418
for (cgal_cell = cdt.finite_faces_begin(); cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
420
// Add cell if it is in the domain
421
if (cgal_cell->is_in_domain())
427
// Create a MeshEditor and open
428
dolfin::MeshEditor mesh_editor;
429
mesh_editor.open(mesh, tdim, gdim);
430
mesh_editor.init_vertices(num_vertices);
431
mesh_editor.init_cells(num_cells);
433
// Add vertices to mesh
434
std::size_t vertex_index = 0;
435
CDT::Finite_vertices_iterator cgal_vertex;
436
for (cgal_vertex = cdt.finite_vertices_begin();
437
cgal_vertex != cdt.finite_vertices_end(); ++cgal_vertex)
439
// Get vertex coordinates and add vertex to the mesh
441
p[0] = cgal_vertex->point()[0];
442
p[1] = cgal_vertex->point()[1];
444
p[2] = cgal_vertex->point()[2];
447
mesh_editor.add_vertex(vertex_index, p);
449
// Attach index to vertex and increment
450
cgal_vertex->info() = vertex_index++;
452
dolfin_assert(vertex_index == num_vertices);
455
std::size_t cell_index = 0;
456
for (cgal_cell = cdt.finite_faces_begin(); cgal_cell != cdt.finite_faces_end(); ++cgal_cell)
458
// Add cell if it is in the domain
459
if (cgal_cell->is_in_domain())
461
mesh_editor.add_cell(cell_index++,
462
cgal_cell->vertex(0)->info(),
463
cgal_cell->vertex(1)->info(),
464
cgal_cell->vertex(2)->info());
467
dolfin_assert(cell_index == num_cells);
472
// Build DOLFIN mesh from CGAL triangulation
473
// FIXME: Why does this not work correctly?
474
//CGALMeshBuilder::build(mesh, cdt);
480
CSGCGALMeshGenerator2D::CSGCGALMeshGenerator2D(const CSGGeometry& geometry)
483
dolfin_error("CSGCGALMeshGenerator2D.cpp",
484
"Create mesh generator",
485
"Dolfin must be compiled with CGAL to use this feature.");
487
//-----------------------------------------------------------------------------
488
CSGCGALMeshGenerator2D::~CSGCGALMeshGenerator2D(){}
489
//-----------------------------------------------------------------------------
490
void CSGCGALMeshGenerator2D::generate(Mesh& mesh) {}
495
//-----------------------------------------------------------------------------