Chi-Tech
cutmesh_2D_cutcell.cc
Go to the documentation of this file.
1#include "meshcutting.h"
2
4
5#include <algorithm>
6#include <functional>
7
8//###################################################################
9/**Cuts a polygon.*/
11 CutPolygon(const std::vector<ECI> &cut_edges,
12 const std::set<uint64_t> &cut_vertices,
13 const Vector3 &plane_point,
14 const Vector3 &plane_normal,
15 MeshContinuum &mesh,
16 chi_mesh::Cell& cell)
17{
18 const auto& p = plane_point;
19 const auto& n = plane_normal;
20
21 /**Utility lambda to check if a vertex is in "cut_vertices" list.*/
22 auto VertexIsCut = [&cut_vertices](uint64_t vid)
23 {
24 auto result = cut_vertices.find(vid);
25
26 if (result != cut_vertices.end())
27 return true;
28
29 return false;
30 };
31
32 /**Utility function to check if an edge is in the "cut_edges" list.*/
33 auto EdgeIsCut = [&cut_edges](const Edge& edge)
34 {
35 Edge edge_set(std::min(edge.first,edge.second),
36 std::max(edge.first,edge.second));
37
38 constexpr auto Arg1 = std::placeholders::_1;
39 constexpr auto Comparator = &ECI::Comparator;
40
41 auto result = std::find_if(cut_edges.begin(),
42 cut_edges.end(),
43 std::bind(Comparator,Arg1,edge_set));
44
45 if (result != cut_edges.end())
46 return std::make_pair(true,*result);
47
48 return std::make_pair(false,*result);
49 };
50
51 //============================================= Create and set vertex and edge
52 // cut flags for the current cell.
53 // Also populate edge_cut_info
54 size_t num_verts = cell.vertex_ids_.size();
55 size_t num_edges = num_verts;
56
57 std::vector<bool> vertex_cut_flags(num_verts,false);
58 std::vector<bool> edge_cut_flags(num_edges,false);
59 std::vector<ECI> edge_cut_info(num_edges);
60
61 for (size_t e=0; e<num_edges; ++e)
62 {
63 vertex_cut_flags[e] = VertexIsCut(cell.vertex_ids_[e]);
64
65 auto edge = MakeEdgeFromPolygonEdgeIndex(cell.vertex_ids_, e);
66 auto cut_nature = EdgeIsCut(edge);
67 edge_cut_flags[e] = cut_nature.first;
68 if (cut_nature.first) edge_cut_info[e] = cut_nature.second;
69
70 edge_cut_info[e].vertex_ids = edge;
71 }//populate flags
72
73 //============================================= Lamda for edge loop
74 enum class CurVertex
75 {
76 AT_FIRST,
77 AT_CUT_POINT,
78 AT_SECOND,
79 NONE
80 };
81
82 struct CurCutInfo
83 {
84 int which_edge=0;
85 CurVertex which_vertex=CurVertex::AT_FIRST;
86
87 CurCutInfo() = default;
88
89 CurCutInfo(int in_which_edge, CurVertex in_which_vertex) :
90 which_edge(in_which_edge),
91 which_vertex(in_which_vertex) {}
92 };
93
94 /**This lamda function starts from a current cut-edge, which is either
95 * an edge where the first vertex is cut or an edge that is cut
96 * somewhere along its length, and then follows the edges in a ccw fashion
97 * until it finds another cut. This last cut is just as either an edge
98 * cut along its length or cut at the second vertex. This then completes
99 * an edge loop that can be used to define another polygon.*/
100 auto GetVerticesTillNextCut =
101 [&cell,&edge_cut_flags,&edge_cut_info,&VertexIsCut](
102 CurCutInfo start_cut_info)
103 {
104 size_t num_verts = cell.vertex_ids_.size();
105 std::vector<uint64_t> vertex_ids;
106 vertex_ids.reserve(num_verts); //Ought to be more than enough
107
108 int e = start_cut_info.which_edge;
109 auto end_type = CurVertex::NONE;
110
111 switch (start_cut_info.which_vertex)
112 {
113 case CurVertex::AT_FIRST:
114 {
115 vertex_ids.push_back(edge_cut_info[e].vertex_ids.first);
116 vertex_ids.push_back(edge_cut_info[e].vertex_ids.second);
117
118 if (VertexIsCut(edge_cut_info[e].vertex_ids.second))
119 {
120 end_type = CurVertex::AT_SECOND;
121 goto skip_to_return_portion;
122 }
123
124 break;
125 }
126 case CurVertex::AT_CUT_POINT:
127 {
128 vertex_ids.push_back(edge_cut_info[e].cut_point_id);
129 vertex_ids.push_back(edge_cut_info[e].vertex_ids.second);
130
131 if (VertexIsCut(edge_cut_info[e].vertex_ids.second))
132 {
133 end_type = CurVertex::AT_SECOND;
134 goto skip_to_return_portion;
135 }
136
137 break;
138 }
139 case CurVertex::AT_SECOND:
140 case CurVertex::NONE:
141 default:
142 break;
143 }//switch type of starting cut
144
145 //Look at downstream ccw edges and check for
146 //edges cut or end-point cuts
147 for (int eref=0; eref<num_verts; ++eref)
148 {
149 e = (e<(num_verts-1))? e+1 : 0;
150
151 if (e == start_cut_info.which_edge) break;
152
153 if (edge_cut_flags[e])
154 {
155 vertex_ids.push_back(edge_cut_info[e].cut_point_id);
156 end_type = CurVertex::AT_CUT_POINT;
157 break;
158 }
159 else if (VertexIsCut(edge_cut_info[e].vertex_ids.second))
160 {
161 vertex_ids.push_back(edge_cut_info[e].vertex_ids.second);
162 end_type = CurVertex::AT_SECOND;
163 break;
164 }
165 else
166 vertex_ids.push_back(edge_cut_info[e].vertex_ids.second);
167 }//for eref
168
169 skip_to_return_portion:
170 CurCutInfo end_cut_info(e, end_type);
171
172 return std::make_pair(vertex_ids,end_cut_info);
173 };
174
175 typedef std::pair<std::vector<uint64_t>,CurCutInfo> LoopInfo;
176
177 //============================================= Process all edges and create
178 // edge loops with associated
179 // cells
180 std::vector<std::vector<uint64_t>> loops_to_add_to_mesh;
181 std::vector<CurCutInfo> cut_history;
182 for (size_t e=0; e<num_edges; ++e)
183 {
184 LoopInfo loop_info;
185
186 if (vertex_cut_flags[e])
187 loop_info = GetVerticesTillNextCut(CurCutInfo(e,CurVertex::AT_FIRST));
188 else if (edge_cut_flags[e])
189 loop_info = GetVerticesTillNextCut(CurCutInfo(e,CurVertex::AT_CUT_POINT));
190 else continue;
191
192 std::vector<uint64_t> verts_to_next_cut = loop_info.first;
193 int end_edge = loop_info.second.which_edge;
194 CurVertex end_type = loop_info.second.which_vertex;
195
196 //Notes:
197 // - If the end_edge == e then this means trouble as a polygon cannot
198 // be cut like that.
199 // - If end_edge < e then the end-edge is definitely the edge right before
200 // the first cut edge. We should still process this edge-loop, but stop
201 // searching.
202
203 if (end_edge < e) //if looped past num_edges
204 e = int(num_edges)-1; //stop search
205 else if (end_type == CurVertex::AT_SECOND)
206 e = end_edge; //resume search after end_e
207 else
208 e = end_edge - 1; //resume search at end_e. e will get ++ to end_edge
209
210 loops_to_add_to_mesh.push_back(verts_to_next_cut);
211 }//for e
212
213 //================================================== Add derivative cells to
214 // mesh
215
216 // Take the back cell and paste onto
217 // the current cell reference
218 if (not loops_to_add_to_mesh.empty())
219 {
220 auto& back_loop = loops_to_add_to_mesh.back();
221 PopulatePolygonFromVertices(mesh, back_loop, cell);
222
223 loops_to_add_to_mesh.pop_back();
224 }//if there are cells to add
225
226 // Now push-up new cells from the remainder
227 for (auto& loop : loops_to_add_to_mesh)
228 {
229 auto new_cell = std::make_unique<chi_mesh::Cell>(CellType::POLYGON,
230 CellType::TRIANGLE);
231 PopulatePolygonFromVertices(mesh, loop, *new_cell);
232 mesh.cells.push_back(std::move(new_cell));
233 }
234}
235
std::vector< uint64_t > vertex_ids_
Definition: cell.h:81
void push_back(std::unique_ptr< chi_mesh::Cell > new_cell)
GlobalCellHandler cells
void PopulatePolygonFromVertices(const MeshContinuum &mesh, const std::vector< uint64_t > &vertex_ids, chi_mesh::Cell &cell)
void CutPolygon(const std::vector< ECI > &cut_edges, const std::set< uint64_t > &cut_vertices, const Vector3 &plane_point, const Vector3 &plane_normal, MeshContinuum &mesh, chi_mesh::Cell &cell)
Edge MakeEdgeFromPolygonEdgeIndex(const std::vector< uint64_t > &vertex_ids, size_t edge_index)
std::pair< uint64_t, uint64_t > Edge
Definition: meshcutting.h:11
@ NONE
Definition: chi_mesh.h:71