58 throw std::runtime_error(
"A polyhedral vertex requires one mesh vertex");
60 cell->position = positions.at(simplices.front().front());
64 using Key = std::vector<size_t>;
65 std::map<Key, size_t> counts;
67 for (
auto simplex : simplices)
69 std::sort(simplex.begin(), simplex.end());
70 if (simplex.size() !=
order + 1 ||
71 std::adjacent_find(simplex.begin(), simplex.end()) != simplex.end() ||
72 !unique.insert(simplex).second)
74 throw std::runtime_error(
"Invalid or duplicate boundary simplex");
76 for (
const auto id : simplex)
83 child.erase(child.begin() +
k);
87 for (
const auto &entry : counts)
91 throw std::runtime_error(
"Non-manifold boundary simplex");
93 if (entry.second == 1)
95 const auto child = std::get<
order - 1>(factories).get(entry.first);
96 cell->children.emplace(child->key, child);
97 child->parents.emplace(
cell->key, cell);
98 buildBoundary<
order - 1>(child, {entry.first}, positions);
101 if constexpr (
order == 1)
103 if (
cell->children.size() != 2)
105 throw std::runtime_error(
"A polyhedral edge requires two endpoints");
108 std::map<size_t, std::set<size_t>>
adjacency;
109 for (
const auto &simplex : simplices)
114 std::set<size_t> visited;
115 std::vector<size_t> pending{simplices.front().front()};
116 while (!pending.empty())
118 const auto id = pending.back();
120 if (visited.insert(
id).second)
124 throw std::runtime_error(
"Branched polyhedral edge");
134 throw std::runtime_error(
"Disconnected polyhedral edge");
137 if constexpr (
order == 2)
139 buildPerimeter(cell);
144 template <
int dim>
void PolyhedralMesh<dim>::buildPerimeter(
const std::shared_ptr<
Polyhedron<dim, 2>> &cell)
147 if (
cell->perimeter.empty())
149 std::map<Key, std::vector<std::shared_ptr<Polyhedron<dim, 1>>>>
adjacency;
150 for (
const auto &entry :
cell->children)
152 for (
const auto &
vertex : entry.second->children)
157 for (
const auto &entry : adjacency)
159 if (entry.second.size() != 2)
161 throw std::runtime_error(
"Open or branched polygon perimeter");
164 if (
cell->children.size() < 3)
166 throw std::runtime_error(
"Polygon requires at least three edges");
168 const auto first =
cell->children.begin()->second;
172 std::set<PolyhedronKey<dim, 1>> visited;
175 if (!visited.insert(edge->key).second)
177 throw std::runtime_error(
"Polygon perimeter repeats an edge");
179 cell->perimeter.push_back(
180 {
cell, edge,
cell->perimeter.size(),
vertex != edge->children.begin()->second});
181 edge->faceIncidences.emplace(
cell->key,
cell->perimeter.size() - 1);
184 edge = neighbors[0] == edge ? neighbors[1] : neighbors[0];
185 }
while (edge !=
first);
186 if (
vertex != start || visited.size() !=
cell->children.size())
188 throw std::runtime_error(
"Polygon requires one closed perimeter");
190 if constexpr (
dim == 2)
194 for (
const auto &incidence :
cell->perimeter)
196 const Vector
a = incidence.source()->position -
origin;
197 const Vector
b = incidence.sink()->position -
origin;
202 std::reverse(
cell->perimeter.begin(),
cell->perimeter.end());
203 for (
auto &incidence :
cell->perimeter)
205 incidence.reversed = !incidence.reversed;
208 for (
size_t k = 0;
k <
cell->perimeter.size(); ++
k)
210 cell->perimeter[
k].index =
k;
211 cell->perimeter[
k].edge->faceIncidences.at(
cell->key) =
k;
216 template <
int dim>
void PolyhedralMesh<dim>::orientMeshFaces()
225 std::set<size_t> ids;
226 for (
const auto &input : faces)
228 if (!ids.insert(input.id).second || input.regions.empty() || input.regions.size() > 2 ||
229 (input.regions.size() == 2 && input.regions[0] == input.regions[1]) || input.simplices.empty())
231 throw std::runtime_error(
"Invalid polyhedral face input");
233 const auto face = std::get<dim - 1>(factories).get({input.id});
234 std::vector<std::vector<size_t>> simplices;
235 for (
const auto &simplex : input.simplices)
237 simplices.emplace_back(simplex.begin(), simplex.end());
239 buildBoundary<dim - 1>(
face, simplices, positions);
240 for (
const auto id : input.regions)
242 const auto region = std::get<dim>(factories).get({
id});
247 if constexpr (dim == 2)
251 buildPerimeter(
region.second);
254 validateLevel<dim>();
261 const size_t id = identifier.sID;
262 const auto face = std::get<dim - 1>(factories).get(
id);
263 face->initialize(simplex);
264 for (
const auto regionID : simplex->regionIDs())
272 template <
int dim>
template <
int order>
void PolyhedralMesh<dim>::attachSimplex(
const Simplex<dim, order> *simplex)
274 if constexpr (
order < dim - 1)
276 const std::vector<size_t>
key(simplex->xID.begin(), simplex->xID.end());
277 const auto found = std::get<order>(factories).find(
key);
278 if (found != std::get<order>(factories).
end())
280 found->second->simplices().insert(simplex);
283 if constexpr (
order > 0)
285 for (
const auto &child :
simplex->children())
287 attachSimplex<
order - 1>(child.get());
295 const auto &
face = entry.second;
296 std::map<size_t, Vector> positions;
297 std::vector<std::vector<size_t>> simplices;
298 for (
const auto *simplex :
face->simplices())
300 simplices.emplace_back(simplex->xID.begin(), simplex->xID.end());
301 for (
const auto *
vertex : simplex->vertices())
306 buildBoundary<dim - 1>(
face, simplices, positions);
307 for (
const auto *simplex :
face->simplices())
309 attachSimplex<dim - 1>(simplex);
312 if constexpr (dim == 2)
316 buildPerimeter(
region.second);