Developer Documentation
Loading...
Searching...
No Matches
FileManagerT_impl.hh
1/*===========================================================================*\
2 * *
3 * OpenVolumeMesh *
4 * Copyright (C) 2011 by Computer Graphics Group, RWTH Aachen *
5 * www.openvolumemesh.org *
6 * *
7 *---------------------------------------------------------------------------*
8 * This file is part of OpenVolumeMesh. *
9 * *
10 * OpenVolumeMesh is free software: you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License as *
12 * published by the Free Software Foundation, either version 3 of *
13 * the License, or (at your option) any later version with the *
14 * following exceptions: *
15 * *
16 * If other files instantiate templates or use macros *
17 * or inline functions from this file, or you compile this file and *
18 * link it with other files to produce an executable, this file does *
19 * not by itself cause the resulting executable to be covered by the *
20 * GNU Lesser General Public License. This exception does not however *
21 * invalidate any other reasons why the executable file might be *
22 * covered by the GNU Lesser General Public License. *
23 * *
24 * OpenVolumeMesh is distributed in the hope that it will be useful, *
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
27 * GNU Lesser General Public License for more details. *
28 * *
29 * You should have received a copy of the GNU LesserGeneral Public *
30 * License along with OpenVolumeMesh. If not, *
31 * see <http://www.gnu.org/licenses/>. *
32 * *
33\*===========================================================================*/
34
35
36#define FILEMANAGERT_CC
37
38#include <vector>
39#include <iostream>
40#include <sstream>
41#include <algorithm>
42#include <cctype>
43#include <typeinfo>
44#include <stdint.h>
45#include <memory>
46#include <array>
47
48#include <OpenVolumeMesh/Geometry/VectorT.hh>
49#include <OpenVolumeMesh/Mesh/PolyhedralMesh.hh>
50
51#include <OpenVolumeMesh/FileManager/FileManager.hh>
52
53namespace OpenVolumeMesh {
54
55namespace IO {
56
57using namespace OpenVolumeMesh::Geometry;
58
59//==================================================
60
61template<class MeshT>
62bool FileManager::readStream(std::istream &_istream, MeshT &_mesh,
63 bool _topologyCheck, bool _computeBottomUpIncidences) const
64{
65 std::stringstream sstr;
66 std::string line;
67 std::string s_tmp;
68 typedef typename MeshT::PointT Point;
69 Point v = Point(0.0, 0.0, 0.0);
70
71 _istream.imbue(std::locale::classic());
72
73 _mesh.clear(false);
74 // Temporarily disable bottom-up incidences
75 // since it's way faster to first add all the
76 // geometry and compute them in one pass afterwards
77 _mesh.enable_bottom_up_incidences(false);
78
79 /*
80 * Header
81 */
82
83 bool header_found = true;
84
85 // Get first line
86 getCleanLine(_istream, line);
87 sstr.str(line);
88
89 // Check header
90 sstr >> s_tmp;
91 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
92 if(s_tmp != "OVM") {
93 //_istream.close();
94 header_found = false;
95 if (verbosity_level_ >= 1) {
96 std::cerr << "The specified file might not be in OpenVolumeMesh format!" << std::endl;
97 }
98 //return false;
99 }
100
101 // Get ASCII/BINARY string
102 sstr >> s_tmp;
103 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
104 if(s_tmp == "BINARY") {
105 if (verbosity_level_ >= 1) {
106 std::cerr << "Binary files are not supported at the moment!" << std::endl;
107 }
108 return false;
109 }
110
111 /*
112 * Vertices
113 */
114 if(!header_found) {
115 sstr.clear();
116 sstr.str(line);
117 } else {
118 getCleanLine(_istream, line);
119 sstr.clear();
120 sstr.str(line);
121 }
122
123 size_t n_vertices = 0;
124 sstr >> s_tmp;
125 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
126 if(s_tmp != "VERTICES") {
127 if (verbosity_level_ >= 1) {
128 std::cerr << "No vertex section defined!" << std::endl;
129 }
130 return false;
131 } else {
132
133 // Read in number of vertices
134 getCleanLine(_istream, line);
135 sstr.clear();
136 sstr.str(line);
137 sstr >> n_vertices;
138
139 _mesh.reserve_vertices(static_cast<size_t>(n_vertices));
140
141 // Read in vertices
142 for(uint64_t i = 0u; i < n_vertices; ++i) {
143
144 getCleanLine(_istream, line);
145 sstr.clear();
146 sstr.str(line);
147 sstr >> v[0];
148 sstr >> v[1];
149 sstr >> v[2];
150 _mesh.add_vertex(v);
151 }
152 }
153
154 /*
155 * Edges
156 */
157 size_t n_edges = 0;
158 getCleanLine(_istream, line);
159 sstr.clear();
160 sstr.str(line);
161 sstr >> s_tmp;
162 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
163 if(s_tmp != "EDGES") {
164 if (verbosity_level_ >= 2) {
165 std::cerr << "No edge section defined!" << std::endl;
166 }
167 return false;
168 } else {
169
170 // Read in number of edges
171 getCleanLine(_istream, line);
172 sstr.clear();
173 sstr.str(line);
174 sstr >> n_edges;
175
176 _mesh.reserve_edges(static_cast<size_t>(n_edges));
177
178 // Read in edges
179 for(uint64_t i = 0u; i < n_edges; ++i) {
180
181 unsigned int v1 = 0;
182 unsigned int v2 = 0;
183 getCleanLine(_istream, line);
184 sstr.clear();
185 sstr.str(line);
186 sstr >> v1;
187 sstr >> v2;
188 if (v1 >= n_vertices || v2 >= n_vertices) {
189 std::cerr << "OVM file loading error: invalid vertex for edge #" << i
190 << " = (" << v1 << ", " << v2 << ") - there are only" << n_vertices << " vertices." << std::endl;
191 return false;
192 }
193 // TODO: check index validity
194 _mesh.add_edge(VertexHandle(v1), VertexHandle(v2), true);
195 }
196 }
197
198 size_t n_halfedges = 2 * n_edges;
199 /*
200 * Faces
201 */
202 size_t n_faces = 0;
203 getCleanLine(_istream, line);
204 sstr.clear();
205 sstr.str(line);
206 sstr >> s_tmp;
207 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
208 if(s_tmp != "FACES") {
209 if (verbosity_level_ >= 2) {
210 std::cerr << "No face section defined!" << std::endl;
211 }
212 return false;
213 } else {
214
215 // Read in number of faces
216 getCleanLine(_istream, line);
217 sstr.clear();
218 sstr.str(line);
219 sstr >> n_faces;
220
221 _mesh.reserve_faces(static_cast<size_t>(n_faces));
222
223 std::vector<HalfEdgeHandle> hes;
224
225 // Read in faces
226 for(uint64_t i = 0u; i < n_faces; ++i) {
227
228 getCleanLine(_istream, line);
229 sstr.clear();
230 sstr.str(line);
231
232
233 // Get face valence
234 uint64_t val = 0u;
235 sstr >> val;
236
237 hes.clear();
238 hes.reserve(static_cast<size_t>(val));
239 // Read half-edge indices
240 for(unsigned int e = 0; e < val; ++e) {
241
242 unsigned int v1 = 0;
243 sstr >> v1;
244 if (v1 >= n_halfedges) {
245 std::cerr << "OVM File loading error: invalid halfedge #" << v1 << " in face #" << i
246 << " - there are only" << n_halfedges << " halfedges." << std::endl;
247 return false;
248
249 }
250 // TODO: check index validity
251 hes.emplace_back(v1);
252 }
253
254 _mesh.add_face(hes, _topologyCheck);
255 }
256 }
257 size_t n_halffaces = 2 * n_faces;
258
259 /*
260 * Cells
261 */
262 size_t n_cells;
263 getCleanLine(_istream, line);
264 sstr.clear();
265 sstr.str(line);
266 sstr >> s_tmp;
267 std::transform(s_tmp.begin(), s_tmp.end(), s_tmp.begin(), ::toupper);
268 if(s_tmp != "POLYHEDRA") {
269 if (verbosity_level_ >= 2) {
270 std::cerr << "No polyhedra section defined!" << std::endl;
271 }
272 return false;
273 } else {
274
275 // Read in number of cells
276 getCleanLine(_istream, line);
277 sstr.clear();
278 sstr.str(line);
279 sstr >> n_cells;
280
281 _mesh.reserve_cells(static_cast<size_t>(n_cells));
282
283 std::vector<HalfFaceHandle> hfs;
284 // Read in cells
285 for(uint64_t i = 0u; i < n_cells; ++i) {
286
287 getCleanLine(_istream, line);
288 sstr.clear();
289 sstr.str(line);
290
291
292 // Get cell valence
293 uint64_t val = 0u;
294 sstr >> val;
295
296 hfs.clear();
297 hfs.reserve(static_cast<size_t>(val));
298
299 // Read half-face indices
300 for(unsigned int f = 0; f < val; ++f) {
301
302 unsigned int v1 = 0;
303 sstr >> v1;
304 if (v1 >= n_halffaces) {
305 std::cerr << "OVM File loading error: invalid halfface #" << v1 << " in cell #" << i
306 << " - there are only" << n_halffaces << " halffaces." << std::endl;
307 return false;
308
309 }
310 // TODO: check index validity
311 hfs.emplace_back(v1);
312 }
313
314 _mesh.add_cell(hfs, _topologyCheck);
315 }
316 }
317
318 while(!_istream.eof()) {
319 // "End of file reached while searching for input!"
320 // is thrown here. \TODO Fix it!
321
322 // Read property
323 readProperty(_istream, _mesh);
324 }
325
326 if(_computeBottomUpIncidences) {
327 // Compute bottom-up incidences
328 _mesh.enable_bottom_up_incidences(true);
329 }
330
331 if (verbosity_level_ >= 2) {
332 std::cerr << "######## openvolumemesh info #########" << std::endl;
333 std::cerr << "#vertices: " << _mesh.n_vertices() << std::endl;
334 std::cerr << "#edges: " << _mesh.n_edges() << std::endl;
335 std::cerr << "#faces: " << _mesh.n_faces() << std::endl;
336 std::cerr << "#cells: " << _mesh.n_cells() << std::endl;
337 std::cerr << "######################################" << std::endl;
338 }
339
340 return true;
341}
342
343template <class MeshT>
344bool FileManager::readFile(const std::string& _filename, MeshT& _mesh,
345 bool _topologyCheck, bool _computeBottomUpIncidences) const {
346
347 std::ifstream iff(_filename.c_str(), std::ios::in);
348
349 auto read_buf = std::make_unique<std::array<char, 0x10000>>();
350 iff.rdbuf()->pubsetbuf(read_buf->data(), read_buf->size());
351
352 if(!iff.good()) {
353 if (verbosity_level_ >= 1) {
354 std::cerr << "Error: Could not open file " << _filename << " for reading!" << std::endl;
355 }
356 iff.close();
357 return false;
358 }
359 return readStream(iff, _mesh, _topologyCheck,_computeBottomUpIncidences);
360}
361
362//==================================================
363
364template <class MeshT>
365void FileManager::readProperty(std::istream& _iff, MeshT& _mesh) const {
366
367 std::string line, entity_t, prop_t, name;
368 std::stringstream sstr;
369
370 getCleanLine(_iff, line);
371
372 if(line.empty()) return;
373
374 sstr.clear();
375 sstr.str(line);
376 sstr >> entity_t;
377 std::transform(entity_t.begin(), entity_t.end(), entity_t.begin(), ::tolower);
378 sstr >> prop_t;
379 std::transform(prop_t.begin(), prop_t.end(), prop_t.begin(), ::tolower);
380 name = line;
381 extractQuotedText(name);
382
383 if (verbosity_level_ >= 2) {
384 std::cerr << "OVM read property " << name << " of type " << prop_t << std::endl;
385 }
386
387 if(prop_t == typeName<int>()) generateGenericProperty<int, MeshT>(entity_t, name, _iff, _mesh);
388 else if(prop_t == typeName<unsigned int>()) generateGenericProperty<unsigned int, MeshT>(entity_t, name, _iff, _mesh);
389 else if(prop_t == typeName<short>()) generateGenericProperty<short, MeshT>(entity_t, name, _iff, _mesh);
390 else if(prop_t == typeName<long>()) generateGenericProperty<long, MeshT>(entity_t, name, _iff, _mesh);
391 else if(prop_t == typeName<unsigned long>()) generateGenericProperty<unsigned long, MeshT>(entity_t, name, _iff, _mesh);
392 else if(prop_t == typeName<char>()) generateGenericProperty<char, MeshT>(entity_t, name, _iff, _mesh);
393 else if(prop_t == typeName<unsigned char>()) generateGenericProperty<unsigned char, MeshT>(entity_t, name, _iff, _mesh);
394 else if(prop_t == typeName<bool>()) generateGenericProperty<bool, MeshT>(entity_t, name, _iff, _mesh);
395 else if(prop_t == typeName<float>()) generateGenericProperty<float, MeshT>(entity_t, name, _iff, _mesh);
396 else if(prop_t == typeName<double>()) generateGenericProperty<double, MeshT>(entity_t, name, _iff, _mesh);
397 else if(prop_t == typeName<std::string>()) generateGenericProperty<std::string, MeshT>(entity_t, name, _iff, _mesh);
398 else if(prop_t == typeName<std::map<HalfEdgeHandle, int> >()) generateGenericProperty<std::map<HalfEdgeHandle, int>, MeshT>(entity_t, name, _iff, _mesh);
399 else if(prop_t == typeName<std::vector<double> >()) generateGenericProperty<std::vector<double> , MeshT>(entity_t, name, _iff, _mesh);
400 else if(prop_t == typeName<std::vector<VertexHandle> >()) generateGenericProperty<std::vector<VertexHandle> , MeshT>(entity_t, name, _iff, _mesh);
401 else if(prop_t == typeName<std::vector<HalfFaceHandle> >()) generateGenericProperty<std::vector<HalfFaceHandle> , MeshT>(entity_t, name, _iff, _mesh);
402 else if(prop_t == typeName<std::vector<std::vector<HalfFaceHandle> > >()) generateGenericProperty<std::vector<std::vector<HalfFaceHandle> > , MeshT>(entity_t, name, _iff, _mesh);
403
404 else if(prop_t == typeName<Vec2f>()) generateGenericProperty<Vec2f, MeshT>(entity_t, name, _iff, _mesh);
405 else if(prop_t == typeName<Vec2d>()) generateGenericProperty<Vec2d, MeshT>(entity_t, name, _iff, _mesh);
406 else if(prop_t == typeName<Vec2i>()) generateGenericProperty<Vec2i, MeshT>(entity_t, name, _iff, _mesh);
407 else if(prop_t == typeName<Vec2ui>()) generateGenericProperty<Vec2ui, MeshT>(entity_t, name, _iff, _mesh);
408
409 else if(prop_t == typeName<Vec3f>()) generateGenericProperty<Vec3f, MeshT>(entity_t, name, _iff, _mesh);
410 else if(prop_t == typeName<Vec3d>()) generateGenericProperty<Vec3d, MeshT>(entity_t, name, _iff, _mesh);
411 else if(prop_t == typeName<Vec3i>()) generateGenericProperty<Vec3i, MeshT>(entity_t, name, _iff, _mesh);
412 else if(prop_t == typeName<Vec3ui>()) generateGenericProperty<Vec3ui, MeshT>(entity_t, name, _iff, _mesh);
413
414 else if(prop_t == typeName<Vec4f>()) generateGenericProperty<Vec4f, MeshT>(entity_t, name, _iff, _mesh);
415 else if(prop_t == typeName<Vec4d>()) generateGenericProperty<Vec4d, MeshT>(entity_t, name, _iff, _mesh);
416 else if(prop_t == typeName<Vec4i>()) generateGenericProperty<Vec4i, MeshT>(entity_t, name, _iff, _mesh);
417 else if(prop_t == typeName<Vec4ui>()) generateGenericProperty<Vec4ui, MeshT>(entity_t, name, _iff, _mesh);
418
419
420
421}
422
423//==================================================
424
425template <class PropT, class MeshT>
426void FileManager::generateGenericProperty(const std::string& _entity_t, const std::string& _name,
427 std::istream& _iff, MeshT& _mesh) const {
428
429 if(_entity_t == "vprop") {
430 VertexPropertyT<PropT> prop = _mesh.template request_vertex_property<PropT>(_name);
431 prop.deserialize(_iff);
432 _mesh.set_persistent(prop);
433 } else if(_entity_t == "eprop") {
434 EdgePropertyT<PropT> prop = _mesh.template request_edge_property<PropT>(_name);
435 prop.deserialize(_iff);
436 _mesh.set_persistent(prop);
437 } else if(_entity_t == "heprop") {
438 HalfEdgePropertyT<PropT> prop = _mesh.template request_halfedge_property<PropT>(_name);
439 prop.deserialize(_iff);
440 _mesh.set_persistent(prop);
441 } else if(_entity_t == "fprop") {
442 FacePropertyT<PropT> prop = _mesh.template request_face_property<PropT>(_name);
443 prop.deserialize(_iff);
444 _mesh.set_persistent(prop);
445 } else if(_entity_t == "hfprop") {
446 HalfFacePropertyT<PropT> prop = _mesh.template request_halfface_property<PropT>(_name);
447 prop.deserialize(_iff);
448 _mesh.set_persistent(prop);
449 } else if(_entity_t == "cprop") {
450 CellPropertyT<PropT> prop = _mesh.template request_cell_property<PropT>(_name);
451 prop.deserialize(_iff);
452 _mesh.set_persistent(prop);
453 } else if(_entity_t == "mprop") {
454 MeshPropertyT<PropT> prop = _mesh.template request_mesh_property<PropT>(_name);
455 prop.deserialize(_iff);
456 _mesh.set_persistent(prop);
457 }
458}
459
460//==================================================
461
462
463template<class MeshT>
464void FileManager::writeStream(std::ostream &_ostream, const MeshT &_mesh) const
465{
466 _ostream.imbue(std::locale::classic());
467 // Write header
468 _ostream << "OVM ASCII" << std::endl;
469
470 uint64_t n_vertices(_mesh.n_vertices());
471 _ostream << "Vertices" << std::endl;
472 _ostream << n_vertices << std::endl;
473
474 typedef typename MeshT::PointT Point;
475
476 // write vertices
477 for(VertexIter v_it = _mesh.v_iter(); v_it; ++v_it) {
478
479 Point v = _mesh.vertex(*v_it);
480 _ostream << v[0] << " " << v[1] << " " << v[2] << std::endl;
481 }
482
483 uint64_t n_edges(_mesh.n_edges());
484 _ostream << "Edges" << std::endl;
485 _ostream << n_edges << std::endl;
486
487 // write edges
488 for(EdgeIter e_it = _mesh.e_iter(); e_it; ++e_it) {
489
490 VertexHandle from_vertex = _mesh.edge(*e_it).from_vertex();
491 VertexHandle to_vertex = _mesh.edge(*e_it).to_vertex();
492 _ostream << from_vertex << " " << to_vertex << std::endl;
493 }
494
495 uint64_t n_faces(_mesh.n_faces());
496 _ostream << "Faces" << std::endl;
497 _ostream << n_faces << std::endl;
498
499 // write faces
500 for(FaceIter f_it = _mesh.f_iter(); f_it; ++f_it) {
501
502 _ostream << static_cast<uint64_t>(_mesh.face(*f_it).halfedges().size()) << " ";
503
504 std::vector<HalfEdgeHandle> halfedges = _mesh.face(*f_it).halfedges();
505
506 for(typename std::vector<HalfEdgeHandle>::const_iterator it = halfedges.begin(); it
507 != halfedges.end(); ++it) {
508
509 _ostream << it->idx();
510
511 if((it + 1) != halfedges.end())
512 _ostream << " ";
513 }
514
515 _ostream << std::endl;
516 }
517
518 uint64_t n_cells(_mesh.n_cells());
519 _ostream << "Polyhedra" << std::endl;
520 _ostream << n_cells << std::endl;
521
522 for(CellIter c_it = _mesh.c_iter(); c_it; ++c_it) {
523
524 _ostream << static_cast<uint64_t>(_mesh.cell(*c_it).halffaces().size()) << " ";
525
526 std::vector<HalfFaceHandle> halffaces = _mesh.cell(*c_it).halffaces();
527
528 for(typename std::vector<HalfFaceHandle>::const_iterator it = halffaces.begin(); it
529 != halffaces.end(); ++it) {
530
531 _ostream << it->idx();
532
533 if((it + 1) != halffaces.end())
534 _ostream << " ";
535 }
536
537 _ostream << std::endl;
538 }
539
540 writeProps<Entity::Vertex> (_ostream, _mesh);
541 writeProps<Entity::Edge> (_ostream, _mesh);
542 writeProps<Entity::HalfEdge>(_ostream, _mesh);
543 writeProps<Entity::Face> (_ostream, _mesh);
544 writeProps<Entity::HalfFace>(_ostream, _mesh);
545 writeProps<Entity::Cell> (_ostream, _mesh);
546 writeProps<Entity::Mesh> (_ostream, _mesh);
547}
548
549template<class MeshT>
550bool FileManager::writeFile(const std::string& _filename, const MeshT& _mesh) const {
551
552 std::ofstream off(_filename.c_str(), std::ios::out);
553
554 if(!off.good()) {
555 if (verbosity_level_ >= 1) {
556 std::cerr << "Error: Could not open file " << _filename << " for writing!" << std::endl;
557 }
558 return false;
559 }
560 writeStream(off, _mesh);
561 return off.good();
562}
563
564//==================================================
565template<typename EntityTag, class MeshT>
566void FileManager::writeProps(std::ostream &_ostream, const MeshT& _mesh) const {
567 writeProps(_ostream,
568 _mesh.template persistent_props_begin<EntityTag>(),
569 _mesh.template persistent_props_end<EntityTag>(),
570 entityTypeName<EntityTag>()
571 );
572}
573
574
575template<class IteratorT>
576void FileManager::writeProps(
577 std::ostream& _ostr,
578 const IteratorT& _begin, const IteratorT& _end,
579 std::string const &_entityType
580 ) const {
581
582 // write props
583 for(IteratorT p_it = _begin; p_it != _end; ++p_it) {
584 auto prop = *p_it;
585 if(!prop->persistent()) continue;
586 if(prop->anonymous()) {
587 if (verbosity_level_ >= 2) {
588 std::cerr << "Serialization of anonymous properties is not supported!" << std::endl;
589 }
590 continue;
591 }
592
593 std::string type_name;
594 try {
595 type_name = prop->typeNameWrapper();
596 } catch (std::runtime_error &e) { // type not serializable
597 if (verbosity_level_ >= 1) {
598 std::cerr << "Failed to save property " << prop->name() << " , skipping: " << e.what() << std::endl;
599 }
600 continue;
601 }
602 _ostr << _entityType << " ";
603 _ostr << type_name << " ";
604 _ostr << "\"" << prop->name() << "\"" << std::endl;
605
606 prop->serialize(_ostr);
607 }
608}
609
610//==================================================
611
612} // Namespace IO
613
614} // Namespace FileManager
VertexHandle add_vertex(const VecT &_p)
Add a geometric point to the mesh.
const VecT & vertex(VertexHandle _vh) const
Get point _vh's coordinates.
void writeStream(std::ostream &_ostream, const MeshT &_mesh) const
Write a mesh to an std::ostream.
bool readFile(const std::string &_filename, MeshT &_mesh, bool _topologyCheck=true, bool _computeBottomUpIncidences=true) const
Read a mesh from a file.
bool writeFile(const std::string &_filename, const MeshT &_mesh) const
Write a mesh to a file.
bool readStream(std::istream &_istream, MeshT &_mesh, bool _topologyCheck=true, bool _computeBottomUpIncidences=true) const
Read a mesh from an std::istream.
const Cell & cell(CellHandle _cellHandle) const
Get cell with handle _cellHandle.
size_t n_vertices() const override
Get number of vertices in mesh.
virtual FaceHandle add_face(std::vector< HalfEdgeHandle > _halfedges, bool _topologyCheck=false)
Add face via incident edges.
size_t n_faces() const override
Get number of faces in mesh.
virtual CellHandle add_cell(std::vector< HalfFaceHandle > _halffaces, bool _topologyCheck=false)
Add cell via incident halffaces.
size_t n_cells() const override
Get number of cells in mesh.
virtual void clear(bool _clearProps=true)
Clear whole mesh.
size_t n_edges() const override
Get number of edges in mesh.
const Edge & edge(EdgeHandle _edgeHandle) const
Get edge with handle _edgeHandle.
virtual EdgeHandle add_edge(VertexHandle _fromVertex, VertexHandle _toHandle, bool _allowDuplicates=false)
Add edge.
const Face & face(FaceHandle _faceHandle) const
Get face with handle _faceHandle.