deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
surface_mesh.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2022 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/config.h>
14
16
17#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
18#include <CGAL/Simple_cartesian.h>
19#include <CGAL/Surface_mesh/Surface_mesh.h>
20
21
23
24namespace
25{
26 template <typename dealiiFace, typename CGAL_Mesh>
27 void
28 add_facet(
29 const dealiiFace &face,
30 const std::map<unsigned int, typename CGAL_Mesh::Vertex_index> &deal2cgal,
31 CGAL_Mesh &mesh,
32 const bool clockwise_ordering = true)
33 {
34 const auto reference_cell_type = face->reference_cell();
35 std::vector<typename CGAL_Mesh::Vertex_index> indices;
36
37 if (reference_cell_type == ReferenceCells::Line)
38 {
39 mesh.add_edge(deal2cgal.at(face->vertex_index(0)),
40 deal2cgal.at(face->vertex_index(1)));
41
42 if (clockwise_ordering)
43 std::reverse(indices.begin(), indices.end());
44 }
45 else if (reference_cell_type == ReferenceCells::Triangle)
46 {
47 indices = {deal2cgal.at(face->vertex_index(0)),
48 deal2cgal.at(face->vertex_index(1)),
49 deal2cgal.at(face->vertex_index(2))};
50
51 if (clockwise_ordering)
52 std::reverse(indices.begin(), indices.end());
53 }
54
55 else if (reference_cell_type == ReferenceCells::Quadrilateral)
56 {
57 if (clockwise_ordering)
58 {
59 indices = {deal2cgal.at(face->vertex_index(0)),
60 deal2cgal.at(face->vertex_index(2)),
61 deal2cgal.at(face->vertex_index(3)),
62 deal2cgal.at(face->vertex_index(1))};
63 }
64 else
65 {
66 indices = {deal2cgal.at(face->vertex_index(0)),
67 deal2cgal.at(face->vertex_index(1)),
68 deal2cgal.at(face->vertex_index(3)),
69 deal2cgal.at(face->vertex_index(2))};
70 }
71 }
72 else
74
75 const auto new_face = mesh.add_face(indices);
76 Assert(new_face != mesh.null_face(),
77 ExcInternalError("While trying to build a CGAL facet, "
78 "CGAL encountered a orientation problem that it "
79 "was not able to solve."));
80 }
81
82
83
84 template <typename dealiiFace, typename CGAL_Mesh>
85 void
86 map_vertices(
87 const dealiiFace &cell,
88 std::map<unsigned int, typename CGAL_Mesh::Vertex_index> &deal2cgal,
89 CGAL_Mesh &mesh)
90 {
91 for (const auto i : cell->vertex_indices())
92 {
93 if (deal2cgal.find(cell->vertex_index(i)) == deal2cgal.end())
94 {
95 deal2cgal[cell->vertex_index(i)] =
96 mesh.add_vertex(CGALWrappers::dealii_point_to_cgal_point<
97 typename CGAL_Mesh::Point>(cell->vertex(i)));
98 }
99 }
100 }
101} // namespace
102
103
104
105#ifndef DOXYGEN
106// Template implementations
107namespace CGALWrappers
108{
109 template <typename CGALPointType, int dim, int spacedim>
110 void
113 const Mapping<dim, spacedim> &mapping,
114 CGAL::Surface_mesh<CGALPointType> &mesh)
115 {
116 Assert(dim > 1, ExcImpossibleInDim(dim));
117 using Mesh = CGAL::Surface_mesh<CGALPointType>;
118 const auto &vertices = mapping.get_vertices(cell);
119 std::map<unsigned int, typename Mesh::Vertex_index> deal2cgal;
120
121 // Add all vertices to the mesh
122 // Store CGAL ordering
123 for (const auto &i : cell->vertex_indices())
124 deal2cgal[cell->vertex_index(i)] = mesh.add_vertex(
125 CGALWrappers::dealii_point_to_cgal_point<CGALPointType>(vertices[i]));
126
127 // Add faces
128 if (dim < 3)
129 // simplices and quads are allowable faces for CGAL
130 add_facet(cell, deal2cgal, mesh);
131 else
132 // in 3d, we build a surface mesh containing all the faces of the 3d cell.
133 // Simplices, Tetrahedrons, and Pyramids have their faces numbered in the
134 // same way as CGAL does (all faces of a bounding polyhedron are numbered
135 // counter-clockwise, so that their normal points outwards). Hexahedrons
136 // in deal.II have their faces numbered lexicographically, and one cannot
137 // deduce the direction of the normals by just looking at the vertices.
138 //
139 // In order for CGAL to be able to produce the right orientation, we need
140 // to reverse the order of the vertices for faces with even index.
141 // However, in order to allow for all kinds of meshes in 3d, including
142 // Moebius-loops, a deal.II face might even be rotated looking from one
143 // cell, whereas it is according to the standard when looking at it from
144 // the neighboring cell sharing that particular face. Therefore, when
145 // building a cgal face we must also take into account the fact that a
146 // face may have a non-standard orientation.
147 for (const auto &f : cell->face_indices())
148 {
149 // Check for standard orientation of faces
150 bool face_is_clockwise_oriented =
152 (f % 2 == 0);
153 // Make sure that we revert the orientation if required
154 if (cell->face_orientation(f) == false)
155 face_is_clockwise_oriented = !face_is_clockwise_oriented;
156 add_facet(cell->face(f), deal2cgal, mesh, face_is_clockwise_oriented);
157 }
158 }
159
160
161
162 template <typename CGALPointType, int dim, int spacedim>
163 void
165 const ::Triangulation<dim, spacedim> &tria,
166 CGAL::Surface_mesh<CGALPointType> &mesh)
167 {
168 Assert(tria.n_cells() > 0,
170 "Triangulation cannot be empty upon calling this function."));
171 Assert(mesh.is_empty(),
173 "The surface mesh must be empty upon calling this function."));
174
175 Assert(dim > 1, ExcImpossibleInDim(dim));
176 using Mesh = CGAL::Surface_mesh<CGALPointType>;
177 using Vertex_index = typename Mesh::Vertex_index;
178
179 std::map<unsigned int, Vertex_index> deal2cgal;
180 if constexpr (dim == 2)
181 {
182 for (const auto &cell : tria.active_cell_iterators())
183 {
184 map_vertices(cell, deal2cgal, mesh);
185 add_facet(cell, deal2cgal, mesh);
186 }
187 }
188 else if constexpr (dim == 3 && spacedim == 3)
189 {
190 for (const auto &cell : tria.active_cell_iterators())
191 {
192 for (const auto &f : cell->face_indices())
193 {
194 if (cell->face(f)->at_boundary())
195 {
196 map_vertices(cell->face(f), deal2cgal, mesh);
197 add_facet(cell->face(f),
198 deal2cgal,
199 mesh,
200 (f % 2 == 0 || cell->n_vertices() != 8));
201 }
202 }
203 }
204 }
205 else
206 {
207 Assert(false, ExcImpossibleInDimSpacedim(dim, spacedim));
208 }
209 }
210
211// Explicit instantiations.
212//
213// We don't build the instantiations.inst file if deal.II isn't
214// configured with CGAL, but doxygen doesn't know that and tries to
215// find that file anyway for parsing -- which then of course it fails
216// on. So exclude the following from doxygen consideration.
217# ifndef DOXYGEN
218# include "cgal/surface_mesh.inst"
219# endif
220
221} // namespace CGALWrappers
222#endif
223
224
TriaIterator< TriaAccessor< dim - 1, dim, spacedim > > face(const unsigned int i) const
virtual boost::container::small_vector< Point< spacedim >, ReferenceCells::max_n_vertices< dim >() > get_vertices(const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices() const
unsigned int n_vertices() const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices() const
unsigned int vertex_index(const unsigned int i) const
ReferenceCell< structdim > reference_cell() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_ASSERT_UNREACHABLE()
static ::ExceptionBase & ExcImpossibleInDimSpacedim(int arg1, int arg2)
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
Definition tria.h:1624
bool face_orientation(const unsigned int face) const
MappingQ< dim, spacedim > StaticMappingQ1< dim, spacedim >::mapping
Definition mapping_q1.h:101
void dealii_tria_to_cgal_surface_mesh(const ::Triangulation< dim, spacedim > &triangulation, CGAL::Surface_mesh< CGALPointType > &mesh)
void dealii_cell_to_cgal_surface_mesh(const typename ::Triangulation< dim, spacedim >::cell_iterator &cell, const ::Mapping< dim, spacedim > &mapping, CGAL::Surface_mesh< CGALPointType > &mesh)
constexpr ReferenceCell< 3 > Hexahedron
constexpr ReferenceCell< 2 > Quadrilateral
constexpr ReferenceCell< 1 > Line
constexpr ReferenceCell< 2 > Triangle