Chi-Tech
unpartmesh_01d_readfromwavefrontobj.cc
Go to the documentation of this file.
2
3#include "chi_runtime.h"
4#include "chi_log.h"
5
6#include "chi_mpi.h"
7
8#include <algorithm>
9#include <fstream>
10
11// ###################################################################
12/**Reads an unpartitioned mesh from a wavefront .obj file.*/
14{
15 const std::string fname = "chi_mesh::UnpartitionedMesh::ReadFromWavefrontOBJ";
16
17 //======================================================= Opening the file
18 std::ifstream file;
19 file.open(options.file_name);
20 if (!file.is_open())
21 {
22 Chi::log.LogAllError() << "Failed to open file: " << options.file_name
23 << " in call "
24 << "to ImportFromOBJFile \n";
25 Chi::Exit(EXIT_FAILURE);
26 }
27
29 Chi::log.Log() << "Making Unpartitioned mesh from wavefront file "
30 << options.file_name;
31
32 typedef std::pair<uint64_t, uint64_t> Edge;
33 struct BlockData
34 {
35 std::string name;
36 std::vector<LightWeightCell*> cells;
37 std::vector<Edge> edges;
38 };
39
40 std::vector<BlockData> block_data;
41 std::vector<chi_mesh::Vertex> file_vertices;
42
43 //======================================================= Reading every line
44 std::string file_line;
45 std::string delimiter = " ";
46 int material_id = -1;
47 while (std::getline(file, file_line))
48 {
49 //================================================ Get the first word
50 size_t beg_of_word = file_line.find_first_not_of(delimiter);
51 size_t end_of_word = file_line.find(delimiter, beg_of_word - beg_of_word);
52 std::string first_word = file_line.substr(beg_of_word, end_of_word);
53 std::string sub_word;
54
55 if (first_word == "o")
56 {
57 beg_of_word = file_line.find_first_not_of(delimiter, end_of_word);
58 end_of_word = file_line.find(delimiter, beg_of_word);
59 sub_word = file_line.substr(beg_of_word, end_of_word - beg_of_word);
60
61 std::string block_name = sub_word;
62 block_data.push_back({block_name, {}});
63 }
64
65 if (first_word == "usemtl")
66 {
68 << "New material at cell count: " << block_data.back().cells.size();
69 ++material_id;
70 }
71
72 //================================================ Keyword "v" for Vertex
73 if (first_word == "v")
74 {
75 chi_mesh::Vertex newVertex;
76 for (int k = 1; k <= 3; k++)
77 {
78 //================================== Extract sub word
79 beg_of_word = file_line.find_first_not_of(delimiter, end_of_word);
80 end_of_word = file_line.find(delimiter, beg_of_word);
81 sub_word = file_line.substr(beg_of_word, end_of_word - beg_of_word);
82
83 //================================== Convert word to number
84 try
85 {
86 double numValue = std::stod(sub_word);
87
88 if (k == 1) newVertex.x = numValue;
89 else if (k == 2)
90 newVertex.y = numValue;
91 else if (k == 3)
92 newVertex.z = numValue;
93 }
94
95 //================================== Catch conversion error
96 catch (const std::invalid_argument& ia)
97 {
99 << "Failed to convert vertex in line " << file_line << std::endl;
100 }
101
102 //================================== Stop word extraction on line end
103 if (end_of_word == std::string::npos) { break; }
104 }
105 file_vertices.push_back(newVertex);
106 } // if (first_word == "v")
107
108 //===================================================== Keyword "f" for face
109 if (first_word == "f")
110 {
111 size_t number_of_verts =
112 std::count(file_line.begin(), file_line.end(), '/') / 2;
113
114 CellType sub_type = CellType::POLYGON;
115 if (number_of_verts == 3) sub_type = CellType::TRIANGLE;
116 else if (number_of_verts == 4)
117 sub_type = CellType::QUADRILATERAL;
118
119 auto cell = new LightWeightCell(CellType::POLYGON, sub_type);
120 cell->material_id = material_id;
121
122 // Populate vertex-ids
123 for (size_t k = 1; k <= number_of_verts; k++)
124 {
125 //================================== Extract sub word
126 beg_of_word = file_line.find_first_not_of(delimiter, end_of_word);
127 end_of_word = file_line.find(delimiter, beg_of_word);
128 sub_word = file_line.substr(beg_of_word, end_of_word - beg_of_word);
129
130 //============================= Extract locations of hiphens
131 size_t first_dash = sub_word.find('/');
132 size_t last_dash = sub_word.find_last_of('/');
133
134 //============================= Extract the words ass. vertex and normal
135 std::string vert_word = sub_word.substr(0, first_dash - 0);
136 std::string norm_word =
137 sub_word.substr(last_dash + 1, sub_word.length() - last_dash - 1);
138
139 //============================= Convert word to number (Vertex)
140 try
141 {
142 int numValue = std::stoi(vert_word);
143 cell->vertex_ids.push_back(numValue - 1);
144 }
145 catch (const std::invalid_argument& ia)
146 {
147 Chi::log.Log0Warning() << "Failed converting work to number in line "
148 << file_line << std::endl;
149 }
150
151 //============================= Stop word extraction on line end
152 if (end_of_word == std::string::npos) { break; }
153 }
154
155 // Build faces
156 const size_t num_verts = cell->vertex_ids.size();
157 for (uint64_t v = 0; v < num_verts; ++v)
158 {
159 LightWeightFace face;
160
161 face.vertex_ids.resize(2);
162 face.vertex_ids[0] = cell->vertex_ids[v];
163 face.vertex_ids[1] =
164 (v < (num_verts - 1)) ? cell->vertex_ids[v + 1] : cell->vertex_ids[0];
165
166 cell->faces.push_back(std::move(face));
167 } // for v
168
169 if (block_data.empty())
170 throw std::logic_error(
171 fname + ": Could not add cell to block-data. "
172 "This normally indicates that the file does not have the "
173 "\"o Object Name\" entry.");
174
175 block_data.back().cells.push_back(cell);
176 } // if (first_word == "f")
177
178 //===================================================== Keyword "l" for edge
179 if (first_word == "l")
180 {
181 Edge edge;
182 for (int k = 1; k <= 2; ++k)
183 {
184 //================================== Extract sub word
185 beg_of_word = file_line.find_first_not_of(delimiter, end_of_word);
186 end_of_word = file_line.find(delimiter, beg_of_word);
187 sub_word = file_line.substr(beg_of_word, end_of_word - beg_of_word);
188
189 //================================== Convert word to number
190 try
191 {
192 int vertex_id = std::stoi(sub_word);
193 if (k == 1) edge.first = vertex_id - 1;
194 if (k == 2) edge.second = vertex_id - 1;
195 }
196
197 //================================== Catch conversion error
198 catch (const std::invalid_argument& ia)
199 {
201 << "Failed to text to integer in line " << file_line << std::endl;
202 }
203 } // for k
204
205 if (block_data.empty())
206 throw std::logic_error(
207 fname + ": Could not add edge to block-data. "
208 "This normally indicates that the file does not have the "
209 "\"o Object Name\" entry.");
210
211 block_data.back().edges.push_back(edge);
212 } // if (first_word == "l")
213 }
214 file.close();
215 Chi::log.Log0Verbose0() << "Max material id: " << material_id;
216
217 //======================================================= Error checks
218 for (const auto& block : block_data)
219 for (const auto& cell : block.cells)
220 for (const auto vid : cell->vertex_ids)
221 {
222 ChiLogicalErrorIf(vid >= file_vertices.size(),
223 "Cell vertex id " + std::to_string(vid) +
224 " not in list of vertices read (size=" +
225 std::to_string(file_vertices.size()) + ").");
226 }
227
228 //======================================================= Filter blocks
229 std::vector<size_t> bndry_block_ids;
230 size_t num_cell_blocks = 0;
231 size_t main_block_id = 0;
232 for (size_t block_id = 0; block_id < block_data.size(); ++block_id)
233 {
234 if (not block_data[block_id].edges.empty())
235 bndry_block_ids.push_back(block_id);
236 if (not block_data[block_id].cells.empty())
237 {
238 ++num_cell_blocks;
239 main_block_id = block_id;
240 }
241 } // for block_id
242
243 if (num_cell_blocks != 1)
244 throw std::logic_error(
245 fname +
246 ": More than one cell-block has been read "
247 "from the file. Only a single face-containing object is supported. "
248 "If you exported this mesh from blender, be sure to export "
249 "\"selection only\"");
250
251 //======================================================= Process blocks
252 std::vector<chi_mesh::Vertex> cell_vertices;
253 {
254 // Initial map is straight
255 std::vector<size_t> vertex_map;
256 vertex_map.reserve(file_vertices.size());
257 for (size_t m = 0; m < file_vertices.size(); ++m)
258 vertex_map.push_back(m);
259
260 // Build set of cell vertices
261 std::set<size_t> cell_vertex_id_set;
262 for (const auto& cell_ptr : block_data.at(main_block_id).cells)
263 for (size_t vid : cell_ptr->vertex_ids)
264 cell_vertex_id_set.insert(vid);
265
266 // Make cell_vertices and edit map
267 {
268 size_t new_id = 0;
269 for (size_t vid : cell_vertex_id_set)
270 {
271 cell_vertices.push_back(file_vertices[vid]);
272 vertex_map[vid] = new_id;
273 ++new_id;
274 }
275 }
276
277 // Build set of bndry vertices
278 std::set<size_t> bndry_vertex_id_set;
279 for (size_t block_id : bndry_block_ids)
280 for (const auto& edge : block_data[block_id].edges)
281 {
282 bndry_vertex_id_set.insert(edge.first);
283 bndry_vertex_id_set.insert(edge.second);
284 }
285
286 // Find a match for each boundary vertex and
287 // place it in the map
288 for (size_t bvid : bndry_vertex_id_set)
289 {
290 const auto& bndry_vertex = file_vertices[bvid];
291
292 bool match_found = false;
293 for (size_t cvid = 0; cvid < cell_vertices.size(); ++cvid)
294 {
295 const auto& cell_vertex = cell_vertices[cvid];
296
297 if ((bndry_vertex - cell_vertex).NormSquare() < 1.0e-12)
298 {
299 vertex_map[bvid] = cvid;
300 match_found = true;
301 break;
302 }
303 } // for cvid
304 if (not match_found)
305 throw std::logic_error(
306 fname +
307 ": Failed to map a boundary vertex to"
308 "any cell vertex. Check that the edges are conformal with the "
309 "object containing the faces.");
310 } // for bvid
311
312 // Change cell and face vertex ids to cell vertex ids
313 // using vertex map
314 for (auto& cell_ptr : block_data.at(main_block_id).cells)
315 {
316 for (uint64_t& vid : cell_ptr->vertex_ids)
317 vid = vertex_map[vid];
318
319 for (auto& face : cell_ptr->faces)
320 for (uint64_t& vid : face.vertex_ids)
321 vid = vertex_map[vid];
322 }
323
324 // Change edge vertex ids to cell vertex ids using
325 // the vertex map
326 for (size_t block_id : bndry_block_ids)
327 for (auto& edge : block_data[block_id].edges)
328 {
329 edge.first = static_cast<int>(vertex_map[edge.first]);
330 edge.second = static_cast<int>(vertex_map[edge.second]);
331 }
332 }
333 this->vertices_ = cell_vertices;
334 this->raw_cells_ = block_data[main_block_id].cells;
335
336 //======================================================= Always do this
338
341
342 //======================================================= Set boundary ids
343 if (bndry_block_ids.empty())
344 {
345 mesh_options_.boundary_id_map[0] = "Default Boundary";
346 }
347 else
348 {
349 std::vector<LightWeightFace*> bndry_faces;
350 for (auto& cell_ptr : raw_cells_)
351 for (auto& face : cell_ptr->faces)
352 if (not face.has_neighbor) bndry_faces.push_back(&face);
353
354 size_t bndry_id = 0;
355 for (size_t bid : bndry_block_ids)
356 {
357 const auto& bndry_edges = block_data[bid].edges;
358
359 size_t num_faces_boundarified = 0;
360 for (const auto& edge : bndry_edges)
361 {
362 std::set<size_t> edge_vert_id_set({edge.first, edge.second});
363
364 for (auto& face_ptr : bndry_faces)
365 {
366 const auto& vert_ids = face_ptr->vertex_ids;
367 std::set<size_t> face_vert_id_set(vert_ids.begin(), vert_ids.end());
368
369 if (face_vert_id_set == edge_vert_id_set)
370 {
371 face_ptr->neighbor = bndry_id;
372 ++num_faces_boundarified;
373 break;
374 }
375 } // for face
376 } // for edge
377
378 Chi::log.Log() << "UnpartitionedMesh: assigned " << num_faces_boundarified
379 << " faces to boundary id " << bndry_id << " with name "
380 << block_data[bid].name;
381
382 mesh_options_.boundary_id_map[bndry_id] = block_data[bid].name;
383
384 ++bndry_id;
385 } // for boundary block
386 }
387}
#define ChiLogicalErrorIf(condition, message)
static void Exit(int error_code)
Definition: chi_runtime.cc:342
static chi::ChiLog & log
Definition: chi_runtime.h:81
static chi::MPI_Info & mpi
Definition: chi_runtime.h:78
LogStream LogAllError()
Definition: chi_log.h:239
LogStream Log0Warning()
Definition: chi_log.h:231
LogStream Log0Verbose0()
Definition: chi_log.h:233
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
LogStream Log0Verbose1()
Definition: chi_log.h:234
void Barrier() const
Definition: mpi_info.cc:38
std::vector< chi_mesh::Vertex > vertices_
void ReadFromWavefrontOBJ(const Options &options)
std::vector< LightWeightCell * > raw_cells_
std::pair< uint64_t, uint64_t > Edge
Definition: meshcutting.h:11
CellType
Definition: cell.h:12
@ UNSTRUCTURED
Definition: chi_mesh.h:77
@ DIMENSION_2
Definition: chi_mesh.h:73
std::map< uint64_t, std::string > boundary_id_map
double x
Element-0.
double y
Element-1.
double z
Element-2.