Chi-Tech
cutmesh_3D_cutcell.cc
Go to the documentation of this file.
1#include "meshcutting.h"
2
4
5#include "chi_runtime.h"
6#include "chi_log.h"
7
8#include <queue>
9#include <algorithm>
10#include <functional>
11
12//###################################################################
13/***/
15 Cut3DCell(const std::vector<ECI> &global_cut_edges,
16 const std::set<uint64_t> &global_cut_vertices,
17 const Vector3 &plane_point,
18 const Vector3 &plane_normal,
19 double float_compare,
20 MeshContinuum &mesh,
21 chi_mesh::Cell &cell,
22 bool verbose/*=false*/)
23{
24 const auto& p = plane_point;
25 const auto& n = plane_normal;
26 const size_t cell_num_faces = cell.faces_.size();
27
28 /**Utility lambda to check if a vertex is in generic set.*/
29 auto NumberInSet = [](uint64_t number, const std::set<uint64_t>& the_set)
30 {
31 if (the_set.find(number) != the_set.end()) return true;
32
33 return false;
34 };
35
36 /**Utility function to check if an edge is in the "cut_edges" list.*/
37 auto EdgeIsCut = [](const Edge& edge, const std::vector<ECI>& cut_edges)
38 {
39 Edge edge_set(std::min(edge.first,edge.second),
40 std::max(edge.first,edge.second));
41
42 constexpr auto Arg1 = std::placeholders::_1;
43 constexpr auto Comparator = &ECI::Comparator;
44
45 auto result = std::find_if(cut_edges.begin(),
46 cut_edges.end(),
47 std::bind(Comparator,Arg1,edge_set));
48
49 if (result != cut_edges.end())
50 return std::make_pair(true,*result);
51
52 return std::make_pair(false,*result);
53 };
54
55 /**Utility lambda to check if a vertex is in generic list.*/
56 auto NumberInList = [](uint64_t number, const std::vector<uint64_t>& list)
57 {
58 auto result = std::find(list.begin(), list.end(), number);
59
60 if (result != list.end()) return true;
61
62 return false;
63 };
64 auto NumberInList_t = [](size_t number, const std::vector<size_t>& list)
65 {
66 auto result = std::find(list.begin(), list.end(), number);
67
68 if (result != list.end()) return true;
69
70 return false;
71 };
72
73 /**Utility lambda to flip and edge.*/
74 auto FlipEdge = [](const Edge& in_edge)
75 {
76 return Edge(in_edge.second, in_edge.first);
77 };
78
79 /**Utility lambda to convert a vector of edges to a vertex list.*/
80 auto PopulateFragment = [NumberInList](std::vector<uint64_t>& frag,
81 const std::vector<Edge>& frag_edges)
82 {
83 for (auto edge : frag_edges)
84 {
85 if (not NumberInList(edge.first , frag)) frag.push_back(edge.first );
86 if (not NumberInList(edge.second, frag)) frag.push_back(edge.second);
87 }
88 };
89
90 if (verbose) Chi::log.Log() << "Checkpoint 1";
91
92 //============================================= Determine cut-edges relevant
93 // to this cell
94 std::vector<ECI> local_cut_edges;
95 const std::set<uint64_t> local_vertex_id_set(cell.vertex_ids_.begin(),
96 cell.vertex_ids_.end());
97
98 for (auto& eci : global_cut_edges)
99 if (NumberInSet(eci.vertex_ids.first , local_vertex_id_set) and
100 NumberInSet(eci.vertex_ids.second, local_vertex_id_set))
101 local_cut_edges.push_back(eci);
102
103 if (verbose)
104 {
105 std::stringstream outstr;
106 outstr << "Local cut edges:\n";
107 for (const auto& eci : local_cut_edges)
108 outstr << eci.vertex_ids.first << "->"
109 << eci.vertex_ids.second << " "
110 << "cut at vertex " << eci.cut_point_id << " "
111 << mesh.vertices[eci.cut_point_id].PrintStr()
112 << "\n";
113 Chi::log.Log() << outstr.str();
114 }
115
116 //============================================= Determine cut- and uncut-faces
117 // A face is cut if its vertices have a
118 // differing sense wrt to the plane.
119 std::vector<size_t> cut_faces_indices;
120 std::vector<size_t> uncut_faces_indices_A;
121 std::vector<size_t> uncut_faces_indices_B;
122 cut_faces_indices.reserve(cell_num_faces);
123 {
124 size_t face_index=0;
125 for (const auto& face : cell.faces_)
126 {
127 size_t num_neg_senses = 0;
128 size_t num_pos_senses = 0;
129 for (auto vid : face.vertex_ids_)
130 {
131 const auto& x = mesh.vertices[vid];
132 double new_sense = n.Dot(x-p);
133
134 if (new_sense < (0.0-float_compare)) ++num_neg_senses;
135 if (new_sense > (0.0+float_compare)) ++num_pos_senses;
136
137 if (num_neg_senses>0 && num_pos_senses>0)
138 { cut_faces_indices.push_back(face_index); break; }
139 }//for vid
140
141 if (num_neg_senses > 0 and num_pos_senses == 0)
142 uncut_faces_indices_A.push_back(face_index);
143 if (num_neg_senses == 0 and num_pos_senses > 0)
144 uncut_faces_indices_B.push_back(face_index);
145 ++face_index;
146 }//for cell face
147 }
148
149 if (verbose)
150 {
151 Chi::log.Log() << "Checkpoint 2";
152 std::stringstream outstr;
153 outstr << "Cut faces:\n";
154 for (const auto& f : cut_faces_indices)
155 outstr << f << " ";
156 outstr << "\n";
157
158 outstr << "Uncut faces A:\n";
159 for (const auto& f : uncut_faces_indices_A)
160 outstr << f << " ";
161 outstr << "\n";
162 outstr << "Uncut faces B:\n";
163 for (const auto& f : uncut_faces_indices_B)
164 outstr << f << " ";
165 outstr << "\n";
166
167 Chi::log.Log() << outstr.str();
168 }
169
170 //============================================= Split cut-faces into fragments
171 // We create a map here for each cut-face.
172 // We map the cut-face-index to a fragment sense-wise.
173 std::map<size_t, std::vector<uint64_t>> cut_faces_fragments_A;
174 std::map<size_t, std::vector<uint64_t>> cut_faces_fragments_B;
175
176 for (const auto& cut_face_id : cut_faces_indices)
177 {
178 const auto& cut_face = cell.faces_[cut_face_id];
179
180 if (verbose) Chi::log.Log() << "cut face " << cut_face_id;
181
182 // First extract the edges that form the fragments
183 std::vector<Edge> fragment_edges_A;
184 std::vector<Edge> fragment_edges_B;
185 const size_t face_num_verts = cut_face.vertex_ids_.size();
186 for (size_t e=0; e<face_num_verts; ++e)
187 {
188 auto edge = MakeEdgeFromPolygonEdgeIndex(cut_face.vertex_ids_, e);
189
190 auto edge_cut_state = EdgeIsCut(edge, local_cut_edges);
191 bool edge_is_cut = edge_cut_state.first;
192 ECI& edge_cut_info = edge_cut_state.second;
193
194 // Extract edges according to if they are cut
195 std::vector<Edge> extracted_edges;
196 extracted_edges.reserve(2);
197 if (edge_is_cut)
198 {
199 extracted_edges.push_back(
200 std::make_pair(edge.first, edge_cut_info.cut_point_id));
201 extracted_edges.push_back(
202 std::make_pair(edge_cut_info.cut_point_id, edge.second));
203 }
204 else
205 extracted_edges.push_back(edge);
206
207 if (verbose)
208 {
209 std::stringstream outstr;
210 for (const auto& eedge : extracted_edges)
211 outstr << eedge.first << "->" << eedge.second << " ";
212 Chi::log.Log() << "edge " << e << " "
213 << edge.first << "->" << edge.second
214 << " cut? " << ((edge_is_cut)? "yes" : "no")
215 << " " << outstr.str();
216 }
217
218 // Enlist the edges to the corrected fragment
219 for (const auto& extracted_edge : extracted_edges)
220 {
221 if (n.Dot(GetEdgeCentroid(extracted_edge, mesh) - p) < 0.0 - float_compare)
222 fragment_edges_A.push_back(extracted_edge);
223 else
224 fragment_edges_B.push_back(extracted_edge);
225 }//for extracted edge
226 }// for edge e of face
227
228 // Now convert the fragment edges to vertex-id list
229 std::vector<uint64_t> fragment_A;
230 std::vector<uint64_t> fragment_B;
231
232 fragment_A.reserve(fragment_edges_A.size() + 1);
233 fragment_B.reserve(fragment_edges_B.size() + 1);
234
235 PopulateFragment(fragment_A, fragment_edges_A);
236 PopulateFragment(fragment_B, fragment_edges_B);
237
238 // Finally map the fragments
239 cut_faces_fragments_A[cut_face_id] = fragment_A;
240 cut_faces_fragments_B[cut_face_id] = fragment_B;
241 }//for cut-face
242
243 if (verbose)
244 {
245 Chi::log.Log() << "Checkpoint 3";
246 std::stringstream outstr;
247 outstr << "Cut faces fragments A:\n";
248 for (const auto& f_fragment : cut_faces_fragments_A)
249 {
250 outstr << " face " << f_fragment.first << ": ";
251 for (uint64_t vid : f_fragment.second)
252 outstr << vid << " ";
253 outstr << "\n";
254 }
255
256 outstr << "Cut faces fragments B:\n";
257 for (const auto& f_fragment : cut_faces_fragments_B)
258 {
259 outstr << " face " << f_fragment.first << ": ";
260 for (uint64_t vid : f_fragment.second)
261 outstr << vid << " ";
262 outstr << "\n";
263 }
264
265 Chi::log.Log() << outstr.str();
266 }
267
268 //============================================= Make proxy-faces from data
269 /**This lambda can be applied to uncut faces and cut-face fragments
270 * to give a collection of proxy faces.*/
271 auto MakeProxyFaces = [NumberInList_t, cut_faces_indices, FlipEdge,
272 PopulateFragment]
273 (const chi_mesh::Cell& parent_cell,
274 const std::vector<size_t>& uncut_faces_indices,
275 const std::map<size_t, std::vector<uint64_t>>& cut_face_fragments)
276 {
277 //================================= Build proxy faces based on uncut-faces
278 // and cut faces
279 std::vector<std::vector<uint64_t>> proxy_faces;
280 proxy_faces.reserve(parent_cell.faces_.size());
281
282 size_t f=0;
283 for (const auto& face : parent_cell.faces_)
284 {
285 if (NumberInList_t(f, uncut_faces_indices))
286 proxy_faces.push_back(face.vertex_ids_);
287 else if (NumberInList_t(f, cut_faces_indices))
288 proxy_faces.push_back(cut_face_fragments.at(f));
289 ++f;
290 }//for face f
291
292 //================================= Now build the interface proxy-face
293 // Find non-manifold edges
294 auto non_manifold_edges = FindNonManifoldEdges(proxy_faces);
295
296 // Flip the non-manifold edges
297 for (auto& edge : non_manifold_edges)
298 edge = FlipEdge(edge);
299
300 // Stitch the edges end-to-end
301 auto stitched_nm_edges = StitchEdgesEndToEnd(non_manifold_edges);
302
303 std::vector<uint64_t> interface_proxy_face;
304 PopulateFragment(interface_proxy_face, stitched_nm_edges);
305
306 proxy_faces.push_back(std::move(interface_proxy_face));
307
308 return proxy_faces;
309 };
310
311 auto proxies_A =
312 MakeProxyFaces(cell, uncut_faces_indices_A, cut_faces_fragments_A);
313 auto proxies_B =
314 MakeProxyFaces(cell, uncut_faces_indices_B, cut_faces_fragments_B);
315
316 chi_mesh::Cell cell_A(CellType::POLYHEDRON, CellType::POLYHEDRON);
317 auto cell_A_ptr = &cell_A;
318 auto cell_B_ptr = std::make_unique<chi_mesh::Cell>(CellType::POLYHEDRON,
319 CellType::POLYHEDRON);
320
321 PopulatePolyhedronFromFaces(mesh, proxies_A, *cell_A_ptr);
322 PopulatePolyhedronFromFaces(mesh, proxies_B, *cell_B_ptr);
323
324 cell_A_ptr->local_id_ = cell.local_id_;
325 cell_A_ptr->global_id_ = cell.global_id_;
326
327 cell_B_ptr->global_id_ = mesh.local_cells.size();
328
329 cell_A_ptr->material_id_ = cell.material_id_;
330 cell_B_ptr->material_id_ = cell.material_id_;
331
332 if (verbose)
333 {
334 std::set<uint64_t> verts;
335 for (uint64_t vid : cell_A_ptr->vertex_ids_)
336 verts.insert(vid);
337 for (uint64_t vid : cell_B_ptr->vertex_ids_)
338 verts.insert(vid);
339 for (uint64_t vid : cell.vertex_ids_)
340 verts.insert(vid);
341 for (uint64_t vid : verts)
342 Chi::log.Log() << vid << " " << mesh.vertices[vid].PrintStr();
343 Chi::log.Log() << "Checkpoint 4:\n"
344 << cell.ToString()
345 << cell_A_ptr->ToString()
346 << cell_B_ptr->ToString();
347 }
348
349 cell = cell_A;
350 mesh.cells.push_back(std::move(cell_B_ptr));
351
352
353}
static chi::ChiLog & log
Definition: chi_runtime.h:81
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
std::vector< CellFace > faces_
Definition: cell.h:82
std::string ToString() const
Definition: cell.cc:364
uint64_t local_id_
Definition: cell.h:76
int material_id_
Definition: cell.h:79
uint64_t global_id_
Definition: cell.h:75
std::vector< uint64_t > vertex_ids_
Definition: cell.h:81
void push_back(std::unique_ptr< chi_mesh::Cell > new_cell)
LocalCellHandler local_cells
GlobalCellHandler cells
Edge MakeEdgeFromPolygonEdgeIndex(const std::vector< uint64_t > &vertex_ids, size_t edge_index)
std::vector< Edge > FindNonManifoldEdges(const std::vector< std::vector< uint64_t > > &proxy_faces)
void Cut3DCell(const std::vector< ECI > &global_cut_edges, const std::set< uint64_t > &number, const Vector3 &plane_point, const Vector3 &plane_normal, double float_compare, MeshContinuum &mesh, chi_mesh::Cell &cell, bool verbose=false)
void PopulatePolyhedronFromFaces(const MeshContinuum &mesh, const std::vector< std::vector< uint64_t > > &raw_faces, chi_mesh::Cell &cell)
std::vector< Edge > StitchEdgesEndToEnd(const std::vector< Edge > &edges)
chi_mesh::Vector3 GetEdgeCentroid(const Edge &edge, const chi_mesh::MeshContinuum &grid)
std::pair< uint64_t, uint64_t > Edge
Definition: meshcutting.h:11