Developer Documentation

FileVTK.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44 #include "FileVTK.hh"
45
46 #include <QVBoxLayout>
47 #include <QPushButton>
48
49 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
50 #endif
51 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
52 #endif
53
54
55
56 //-----------------------------------------------------------------------------------------------------
57 void remove_duplicated_vertices(std::vector<quint32>& _indices)
58 {
59 std::vector<quint32>::iterator endIter = _indices.end();
60 for (std::vector<quint32>::iterator iter = _indices.begin(); iter != endIter; ++iter)
61 endIter = std::remove(iter+1, endIter, *(iter));
62
63 _indices.erase(endIter,_indices.end());
64 }
65
66 //-----------------------------------------------------------------------------------------------------
67
69 FileVTKPlugin::FileVTKPlugin():
70 forceTriangleMesh_(false),
71 forcePolyMesh_(false),
72 saveOptions_(0),
73 saveBinary_(0),
74 saveFaceNormals_(0),
75 saveVertexNormals_(0),
76 saveVertexTexCoords_(0),
77 savePrecisionLabel_(0),
78 savePrecision_(0),
79 saveDefaultButton_(),
80 binary_(false),
81 userWriteOptions_(0)
82 {
83 }
84
85 //-----------------------------------------------------------------------------------------------------
86
87 void FileVTKPlugin::initializePlugin() {
88
89 if(OpenFlipperSettings().value("FileVtk/Save/Binary",false).toBool())
90 userWriteOptions_ |= BINARY; //currently unsupported
91 if(OpenFlipperSettings().value("FileVtk/Save/FaceNormals",true).toBool())
92 userWriteOptions_ |= FACENORMALS;
93 if(OpenFlipperSettings().value("FileVtk/Save/VertexNormals",true).toBool())
94 userWriteOptions_ |= VERTEXNORMALS;
95 if(OpenFlipperSettings().value("FileVtk/Save/VertexTexCoords",true).toBool())
96 userWriteOptions_ |= VERTEXTEXCOORDS;
97 }
98
99 //-----------------------------------------------------------------------------------------------------
100
101 QString FileVTKPlugin::getLoadFilters() {
102 return QString( tr("Visualization Toolkit ASCII ( *.vtk )") );
103 }
104
105 //-----------------------------------------------------------------------------------------------------
106
107 QString FileVTKPlugin::getSaveFilters() {
108 return QString( tr("Visualization Toolkit ASCII ( *.vtk )") );
109 }
110
111 //-----------------------------------------------------------------------------------------------------
112
113 DataType FileVTKPlugin::supportedType() {
114 DataType type = DATA_POLY_MESH | DATA_TRIANGLE_MESH | DATA_GROUP;
115
116 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
117 type |= DATA_POLYHEDRAL_MESH;
118 #endif
119 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
120 type |= DATA_HEXAHEDRAL_MESH;
121 #endif
122 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
123 type |= DATA_TETRAHEDRAL_MESH;
124 #endif
125
126 return type;
127 }
128
129 //-----------------------------------------------------------------------------------------------------
130
131 QWidget* FileVTKPlugin::loadOptionsWidget(QString /*_currentFilter*/) {
132 return 0;
133 }
134
135 //-----------------------------------------------------------------------------------------------------
136
137 QWidget* FileVTKPlugin::saveOptionsWidget(QString /*_currentFilter*/) {
138
139 if (saveOptions_ == 0){
140 //generate widget
141 saveOptions_ = new QWidget();
142 QVBoxLayout* layout = new QVBoxLayout();
143 layout->setAlignment(Qt::AlignTop);
144
145 saveBinary_ = new QCheckBox("Save Binary");
146 layout->addWidget(saveBinary_);
147 saveBinary_->setCheckable(false);
148
149 saveFaceNormals_ = new QCheckBox("Save Face Normals");
150 layout->addWidget(saveFaceNormals_);
151
152 saveVertexNormals_ = new QCheckBox("Save Vertex Normals");
153 layout->addWidget(saveVertexNormals_);
154
155 saveVertexTexCoords_ = new QCheckBox("Save Vertex TexCoords");
156 layout->addWidget(saveVertexTexCoords_);
157
158 savePrecisionLabel_ = new QLabel("Writer Precision");
159 layout->addWidget(savePrecisionLabel_);
160
161 savePrecision_ = new QSpinBox();
162 savePrecision_->setMinimum(1);
163 savePrecision_->setMaximum(12);
164 savePrecision_->setValue(6);
165 layout->addWidget(savePrecision_);
166
167 saveDefaultButton_ = new QPushButton("Make Default");
168 layout->addWidget(saveDefaultButton_);
169
170 saveOptions_->setLayout(layout);
171
172 connect(saveBinary_, SIGNAL(clicked(bool)), savePrecision_, SLOT(setDisabled(bool)));
173 connect(saveDefaultButton_, SIGNAL(clicked()), this, SLOT(slotSaveDefault()));
174
175 saveBinary_->setChecked( OpenFlipperSettings().value("FileVtk/Save/Binary",false).toBool() );
176 saveFaceNormals_->setChecked( OpenFlipperSettings().value("FileVtk/Save/FaceNormals",true).toBool() );
177 saveVertexNormals_->setChecked( OpenFlipperSettings().value("FileVtk/Save/VertexNormals",true).toBool() );
178 saveVertexTexCoords_->setChecked( OpenFlipperSettings().value("FileVtk/Save/VertexTexCoords",true).toBool() );
179 }
180
181 return saveOptions_;
182 }
183
184 //-----------------------------------------------------------------------------------------------------
185
186 void FileVTKPlugin::slotSaveDefault() {
187 OpenFlipperSettings().setValue( "FileVtk/Save/Binary", saveBinary_->isChecked() );
188 OpenFlipperSettings().setValue( "FileVtk/Save/FaceNormals", saveFaceNormals_->isChecked() );
189 OpenFlipperSettings().setValue( "FileVtk/Save/VertexNormals", saveVertexNormals_->isChecked() );
190 OpenFlipperSettings().setValue( "FileVtk/Save/VertexTexCoords", saveVertexTexCoords_->isChecked() );
191 }
192
193 //-----------------------------------------------------------------------------------------------------
194
195
196 //-----------------------------------------------------------------------------------------------------
197 //-----------------------------------------------------------------------------------------------------
198 //-------------------------------------- cool helper function -----------------------------------------
199 //-----------------------------------------------------------------------------------------------------
200 //-----------------------------------------------------------------------------------------------------
201
202
203 template <typename MeshT>
204 int FileVTKPlugin::addTetraCellToOpenMesh(MeshT /*_mesh*/, std::vector<quint32> /*_indices*/)
205 {
206 emit log(LOGWARN,tr("Unsupported Cell Type TETRA") );
207 return -1;
208 }
209
210 template <typename MeshT>
211 int FileVTKPlugin::addHexaCellToOpenMesh(MeshT /*_mesh*/, std::vector<quint32> /*_indices*/)
212 {
213 emit log(LOGWARN,tr("Unsupported Cell Type HEXAHEDRON") );
214 return -1;
215 }
216
217 template <typename MeshT>
218 int FileVTKPlugin::addWedgeCellToOpenMesh(MeshT /*_mesh*/, std::vector<quint32> /*_indices*/)
219 {
220 emit log(LOGWARN,tr("Unsupported Cell Type WEDGE") );
221 return -1;
222 }
223
224 template <typename MeshT>
225 int FileVTKPlugin::addPyramidCellToOpenMesh(MeshT /*_mesh*/, std::vector<quint32> /*_indices*/)
226 {
227 emit log(LOGWARN,tr("Unsupported Cell Type PYRAMID") );
228 return -1;
229 }
230
231 template <typename MeshT>
232 int FileVTKPlugin::addFaceToOpenMesh(MeshT*& _mesh, std::vector<quint32> _indices)
233 {
234 std::vector<OpenMesh::VertexHandle> handles;
235 for (std::vector<quint32>::const_iterator it = _indices.begin(); it != _indices.end(); ++it)
236 handles.push_back(_mesh->vertex_handle(*it));
237
238 OpenMesh::FaceHandle fh = _mesh->add_face(handles);
239
240 // Try the other direction
241 if ( ! fh.is_valid() ) {
242
243 std::vector< OpenMesh::VertexHandle > inverseHandles;
244 for ( int i = handles.size()-1 ; i >= 0 ; --i)
245 inverseHandles.push_back(handles[i]);
246
247 fh = _mesh->add_face(inverseHandles);
248
249 if ( !fh.is_valid() ) {
250 return add_non_manifold_face(_mesh, handles);
251 }
252 }
253 return fh.idx();
254 }
255
256 template <typename MeshT>
257 int FileVTKPlugin::addFaceToOpenMesh(MeshT*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3)
258 {
259 OpenMesh::VertexHandle v1 = _mesh->vertex_handle(_index1);
260 OpenMesh::VertexHandle v2 = _mesh->vertex_handle(_index2);
261 OpenMesh::VertexHandle v3 = _mesh->vertex_handle(_index3);
262 return _mesh->add_face(v1,v2,v3).idx();
263 }
264
265 template <typename MeshT>
266 void FileVTKPlugin::updateFaceNormalsOfOpenMesh(MeshT*& _mesh)
267 {
268 _mesh->update_face_normals();
269 }
270
271 void FileVTKPlugin::updateFaceNormals(TriMesh*& _mesh) { updateFaceNormalsOfOpenMesh(_mesh); }
272 void FileVTKPlugin::updateFaceNormals(PolyMesh*& _mesh) { updateFaceNormalsOfOpenMesh(_mesh); }
273
274
275 template <typename MeshT>
276 void FileVTKPlugin::updateVertexNormalsOfOpenMesh(MeshT*& _mesh)
277 {
278 _mesh->update_vertex_normals();
279 }
280
281 template <typename MeshT>
282 void FileVTKPlugin::removeTemporaryPropertiesOfOpenMesh(MeshT*& _mesh)
283 {
284 //if we added this property temporarily, we need to remove it now
285 OpenMesh::VPropHandleT< OpenMesh::VertexHandle > originalVertexIdx;
286 if (! _mesh->get_property_handle(originalVertexIdx,"FileVTKPlugin_originalVertexIdx")) {
287 _mesh->remove_property( originalVertexIdx );
288 }
289 }
290
291 template <typename MeshT>
292 void FileVTKPlugin::addVertexNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
293 {
294 OpenMesh::VertexHandle vh = _mesh->vertex_handle(_index);
295 if ( vh.is_valid() )
296 _mesh->set_normal( vh , _normal );
297 }
298
299
300 template <typename MeshT>
301 void FileVTKPlugin::addFaceNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
302 {
303 OpenMesh::FaceHandle fh = _mesh->face_handle(_index);
304 if ( fh.is_valid() )
305 _mesh->set_normal( fh, _normal );
306 }
307
308 template <typename MeshT>
309 void FileVTKPlugin::addCellNormal(MeshT*& _mesh,const CellType& _cell, OpenMesh::Vec3d _normal)
310 {
311 if ((_cell.type <= 4) || (_cell.type >= 10))
312 {
313 // vertex, poly vertex, line, poly line, tetra, voxel, hexahedron, wedge, pyramid, and quadratic stuff
314 emit log(LOGWARN,tr("Normals not supported for type %1").arg(_cell.type) );
315 }
316 else if (_cell.type == 5)
317 {
318 // Triangle
319 addFaceNormal(_mesh, _cell.index, _normal);
320 }
321 else if (_cell.type == 6)
322 {
323 // Triangle strip
324 int numberOfTriangles = _cell.indices.size() - 2;
325 // we assume here that the triangles have contigous indices as they were freshly created while loading the file
326 for (int i = 0; i < numberOfTriangles; i++)
327 addFaceNormal(_mesh, _cell.index + i, _normal);
328 }
329 else if ((_cell.type >= 7) && (_cell.type <= 9))
330 {
331 // polygon, pixel, quad
332 if (forceTriangleMesh_)
333 {
334 // _mesh is a TriMesh even if cell represents a polygon with more than 3 vertices
335 // for more than 3 vertices the polygon will be split into triangles
336 // we have to set the normal for all these triangles
337 // we assume again that the triangles have contigous indices as they were freshly created while loading the file
338 int numberOfTriangles = _cell.indices.size() - 2;
339 for (int i = 0; i < numberOfTriangles; i++)
340 addFaceNormal(_mesh, _cell.index + i, _normal);
341 }
342 else
343 {
344 // Here _mesh might also be a TriMesh. But this is only the case if all polygons are triangles
345 // so we only need to set a single normal
346 addFaceNormal(_mesh, _cell.index , _normal);
347 }
348 }
349 }
350
351 template <typename MeshT>
352 void FileVTKPlugin::setNormalsOfDuplicatedVerticesOfOpenMesh(MeshT*& _mesh)
353 {
354 //iterate over all contained vertices and set the normals
355 OpenMesh::VPropHandleT< OpenMesh::VertexHandle > originalVertexIdx;
356 if (! _mesh->get_property_handle(originalVertexIdx,"FileVTKPlugin_originalVertexIdx")) {
357 //TODO: check if this is correct;
358 //if the property was not found, there are no copied vertices and we can leave
359 return;
360 //old and maybe unnecessary: _mesh->add_property( originalVertexIdx, "FileVTKPlugin_originalVertexIdx" );
361 }
362
363 typename MeshT::VertexIter vit = _mesh->vertices_begin();
364 typename MeshT::VertexIter vend = _mesh->vertices_end();
365
366 for(; vit != vend; ++vit) {
367 if ( _mesh->property(originalVertexIdx, *vit).is_valid() ) {
368 //copied vertex found
369 _mesh->set_normal( *vit, _mesh->normal(_mesh->property (originalVertexIdx, *vit) ) );
370 }
371 }
372 }
373
374 template< class MeshT >
375 bool FileVTKPlugin::writeASCIIDataOfOpenMesh(std::ostream& _out, MeshT& _mesh ) {
376
377 if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0)
378 _out.precision(savePrecision_->value());
379
380 _out << "DATASET POLYDATA\n";
381
382 typename MeshT::Point p;
383 typename MeshT::Normal n;
384 typename OpenMesh::Vec4f c;
385 typename MeshT::TexCoord2D t;
386
387 typename MeshT::VertexIter vit = _mesh.vertices_begin();
388 typename MeshT::VertexIter end_vit = _mesh.vertices_end();
389 typename MeshT::FaceIter fit = _mesh.faces_begin();
390 typename MeshT::FaceIter end_fit = _mesh.faces_end();
391 typename MeshT::FaceVertexIter fvit;
392
393 int total_face_vertices = _mesh.n_faces();
394 for (; fit != end_fit; ++fit) {
395 total_face_vertices += _mesh.valence(*fit);
396 }
397 // Write vertex data
398 _out << "POINTS " << _mesh.n_vertices() << " float\n";
399 for (; vit != end_vit; ++vit) {
400 // Write vertex p[0] p[1] p[2]
401 p = _mesh.point(*vit);
402 _out << p[0] << " " << p[1] << " " << p[2];
403 _out << "\n";
404 }
405
406 // Write face connectivity
407 _out << "POLYGONS "<< _mesh.n_faces() << " " << total_face_vertices << "\n";
408 for (fit = _mesh.faces_begin(); fit != end_fit; ++fit) {
409 // Write face valence
410 _out << _mesh.valence(*fit);
411
412 // Get face-vertex iterator
413 fvit = _mesh.fv_iter(*fit);
414
415 // Write vertex indices
416 for (;fvit.is_valid(); ++fvit) {
417 _out << " " << fvit->idx();
418 }
419 _out << "\n";
420 }
421
422 //*************//
423 //OPTIONAL DATA//
424 //*************//
425
426 /*** Write face attributes ***/
427 _out << "CELL_DATA "<< _mesh.n_faces() << "\n";
428
429 //Write face normals
430 if (_mesh.has_face_normals() && (userWriteOptions_ & FileVTKPlugin::FACENORMALS)) {
431 _out << "NORMALS faceNormals float\n";
432 for (fit = _mesh.faces_begin(); fit != end_fit; ++fit) {
433 n = _mesh.normal(*fit);
434 _out << n[0] << " " << n[1] << " " << n[2];
435 _out << "\n";
436 }
437 }
438
439 /*** Write vertex attributes ***/
440 _out << "POINT_DATA "<< _mesh.n_vertices() << "\n";
441
442 //Write vertex normals
443 if (_mesh.has_vertex_normals() && (userWriteOptions_ & FileVTKPlugin::VERTEXNORMALS)) {
444 _out << "NORMALS vertexNormals float\n";
445 for (vit = _mesh.vertices_begin(); vit != end_vit; ++vit) {
446 n = _mesh.normal(*vit);
447 _out << n[0] << " " << n[1] << " " << n[2];
448 _out << "\n";
449 }
450 }
451
452 // Write vertex texcoords (only 2D for now)
453 if (_mesh.has_vertex_texcoords2D() && (userWriteOptions_ & FileVTKPlugin::VERTEXTEXCOORDS)) {
454 _out << "TEXTURE_COORDINATES vertexTexcoords 2 float\n";
455 for (vit = _mesh.vertices_begin(); vit != end_vit; ++vit) {
456 t = _mesh.texcoord2D(*vit);
457 _out << t[0] << " " << t[1];
458 _out << "\n";
459 }
460 }
461
462 return true;
463 }
464
465 int FileVTKPlugin::addTetraCell(TriMesh*& _mesh, const std::vector<quint32>& _indices) { return addTetraCellToOpenMesh(_mesh, _indices); }
466 int FileVTKPlugin::addTetraCell(PolyMesh*& _mesh, const std::vector<quint32>& _indices) { return addTetraCellToOpenMesh(_mesh, _indices); }
467
468 int FileVTKPlugin::addHexaCell(TriMesh*& _mesh, const std::vector<quint32>& _indices) { return addHexaCellToOpenMesh(_mesh, _indices); }
469 int FileVTKPlugin::addHexaCell(PolyMesh*& _mesh, const std::vector<quint32>& _indices) { return addHexaCellToOpenMesh(_mesh, _indices); }
470
471 int FileVTKPlugin::addWedgeCell(TriMesh*& _mesh, const std::vector<quint32>& _indices) { return addWedgeCellToOpenMesh(_mesh, _indices); }
472 int FileVTKPlugin::addWedgeCell(PolyMesh*& _mesh, const std::vector<quint32>& _indices) { return addWedgeCellToOpenMesh(_mesh, _indices); }
473
474 int FileVTKPlugin::addPyramidCell(TriMesh*& _mesh, const std::vector<quint32>& _indices) { return addPyramidCellToOpenMesh(_mesh, _indices); }
475 int FileVTKPlugin::addPyramidCell(PolyMesh*& _mesh, const std::vector<quint32>& _indices) { return addPyramidCellToOpenMesh(_mesh, _indices); }
476
477 int FileVTKPlugin::addFace(TriMesh*& _mesh, const std::vector<quint32>& _indices) { return addFaceToOpenMesh(_mesh, _indices); }
478 int FileVTKPlugin::addFace(PolyMesh*& _mesh, const std::vector<quint32>& _indices) { return addFaceToOpenMesh(_mesh, _indices); }
479
480 int FileVTKPlugin::addFace(TriMesh*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3) { return addFaceToOpenMesh(_mesh, _index1, _index2, _index3); }
481 int FileVTKPlugin::addFace(PolyMesh*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3) { return addFaceToOpenMesh(_mesh, _index1, _index2, _index3); }
482
483 void FileVTKPlugin::updateVertexNormals(TriMesh*& _mesh) { updateVertexNormalsOfOpenMesh(_mesh); }
484 void FileVTKPlugin::updateVertexNormals(PolyMesh*& _mesh) { updateVertexNormalsOfOpenMesh(_mesh); }
485
486 void FileVTKPlugin::removeTemporaryProperties(TriMesh*& _mesh) { removeTemporaryPropertiesOfOpenMesh(_mesh); }
487 void FileVTKPlugin::removeTemporaryProperties(PolyMesh*& _mesh) { removeTemporaryPropertiesOfOpenMesh(_mesh); }
488
489 void FileVTKPlugin::addVertexNormal(TriMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addVertexNormalToOpenMesh(_mesh, _index, _normal); }
490 void FileVTKPlugin::addVertexNormal(PolyMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addVertexNormalToOpenMesh(_mesh, _index, _normal); }
491
492 void FileVTKPlugin::addFaceNormal(TriMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addFaceNormalToOpenMesh(_mesh, _index, _normal); }
493 void FileVTKPlugin::addFaceNormal(PolyMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addFaceNormalToOpenMesh(_mesh, _index, _normal); }
494
495 void FileVTKPlugin::setNormalsOfDuplicatedVertices(TriMesh*& _mesh) { setNormalsOfDuplicatedVerticesOfOpenMesh(_mesh); }
496 void FileVTKPlugin::setNormalsOfDuplicatedVertices(PolyMesh*& _mesh) { setNormalsOfDuplicatedVerticesOfOpenMesh(_mesh); }
497
498 bool FileVTKPlugin::writeASCIIData(std::ostream &_out, TriMesh &_mesh) { return writeASCIIDataOfOpenMesh(_out, _mesh); }
499 bool FileVTKPlugin::writeASCIIData(std::ostream &_out, PolyMesh &_mesh) { return writeASCIIDataOfOpenMesh(_out, _mesh); }
500
501
502 #if defined(ENABLE_HEXAHEDRALMESH_SUPPORT) || defined(ENABLE_POLYHEDRALMESH_SUPPORT) || defined(ENABLE_TETRAHEDRALMESH_SUPPORT)
503
504 template <typename MeshT>
505 int FileVTKPlugin::addTetraCellToOpenVolumeMesh(MeshT _mesh, std::vector<quint32> _indices)
506 {
507 if (_indices.size() != 4)
508 { /*emit log(LOGWARN,tr("Unsupported Cell Type Tetra") );*/ }
509
510 std::vector< std::vector<OpenVolumeMesh::VertexHandle> > faces;
511 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
512 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
513 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
514 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
515 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
516 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
517 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
518 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
519 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
520 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
521 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
522 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
523 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
524 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
525 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
526 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
527
528 std::vector<OpenVolumeMesh::HalfFaceHandle> halffacehandles;
529 for (unsigned int i = 0; i < faces.size(); i++)
530 halffacehandles.push_back(_mesh->halfface(faces[i]));
531
532 for (unsigned int i = 0; i < halffacehandles.size(); i++)
533 if (halffacehandles[i] == OpenVolumeMesh::HalfFaceHandle(-1))
534 {
535 // face didn't exist
536 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(faces[i]);
537 halffacehandles[i] = _mesh->halfface_handle(fh, 0);
538 }
539
540 return _mesh->add_cell(halffacehandles).idx();
541
542 }
543
544 template <typename MeshT>
545 int FileVTKPlugin::addHexaCellToOpenVolumeMesh(MeshT _mesh, std::vector<quint32> _indices)
546 {
547 if (_indices.size() != 8)
548 { emit log(LOGWARN,tr("Expected 8 indices to add Hexahedron but got %1").arg(_indices.size()) ); }
549
550 std::vector< std::vector<OpenVolumeMesh::VertexHandle> > faces;
551 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
552 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
553 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
554 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
555 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
556 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
557 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
558 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
559 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
560 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
561 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
562 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
563 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
564 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[7]));
565 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
566 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
567 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
568 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
569 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[6]));
570 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
571 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
572 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
573 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[6]));
574 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[7]));
575 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
576 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
577 faces[5].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
578 faces[5].push_back(OpenVolumeMesh::VertexHandle(_indices[7]));
579 faces[5].push_back(OpenVolumeMesh::VertexHandle(_indices[6]));
580 faces[5].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
581
582 std::vector<OpenVolumeMesh::HalfFaceHandle> halffacehandles;
583 for (unsigned int i = 0; i < faces.size(); i++)
584 halffacehandles.push_back(_mesh->halfface(faces[i]));
585
586 for (unsigned int i = 0; i < halffacehandles.size(); i++)
587 if (halffacehandles[i] == OpenVolumeMesh::HalfFaceHandle(-1))
588 {
589 // face didn't exist
590 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(faces[i]);
591 halffacehandles[i] = _mesh->halfface_handle(fh, 0);
592 }
593
594 return _mesh->add_cell(halffacehandles).idx();
595 }
596
597 template <typename MeshT>
598 int FileVTKPlugin::addWedgeCellToOpenVolumeMesh(MeshT _mesh, std::vector<quint32> _indices)
599 {
600 if (_indices.size() != 6)
601 { emit log(LOGWARN,tr("Expected 6 indices to add Hexahedron but got %1").arg(_indices.size()) ); }
602
603 std::vector< std::vector<OpenVolumeMesh::VertexHandle> > faces;
604 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
605 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
606 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
607 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
608 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
609 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
610 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
611 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
612 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
613 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
614 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
615 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
616 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
617 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
618 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
619 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
620 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
621 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
622 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
623 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
624 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
625 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[5]));
626 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
627
628 std::vector<OpenVolumeMesh::HalfFaceHandle> halffacehandles;
629 for (unsigned int i = 0; i < faces.size(); i++)
630 halffacehandles.push_back(_mesh->halfface(faces[i]));
631
632 for (unsigned int i = 0; i < halffacehandles.size(); i++)
633 if (halffacehandles[i] == OpenVolumeMesh::HalfFaceHandle(-1))
634 {
635 // face didn't exist
636 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(faces[i]);
637 halffacehandles[i] = _mesh->halfface_handle(fh, 0);
638 }
639
640 return _mesh->add_cell(halffacehandles).idx();
641 }
642
643 template <typename MeshT>
644 int FileVTKPlugin::addPyramidCellToOpenVolumeMesh(MeshT _mesh, std::vector<quint32> _indices)
645 {
646 if (_indices.size() != 6)
647 { emit log(LOGWARN,tr("Expected 6 indices to add Hexahedron but got %1").arg(_indices.size()) ); }
648
649 std::vector< std::vector<OpenVolumeMesh::VertexHandle> > faces;
650 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
651 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
652 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
653 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
654 faces[0].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
655 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
656 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
657 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
658 faces[1].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
659 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
660 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[0]));
661 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
662 faces[2].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
663 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
664 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
665 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
666 faces[3].push_back(OpenVolumeMesh::VertexHandle(_indices[3]));
667 faces.push_back(std::vector<OpenVolumeMesh::VertexHandle>());
668 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[1]));
669 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[4]));
670 faces[4].push_back(OpenVolumeMesh::VertexHandle(_indices[2]));
671
672 std::vector<OpenVolumeMesh::HalfFaceHandle> halffacehandles;
673 for (unsigned int i = 0; i < faces.size(); i++)
674 halffacehandles.push_back(_mesh->halfface(faces[i]));
675
676 for (unsigned int i = 0; i < halffacehandles.size(); i++)
677 if (halffacehandles[i] == OpenVolumeMesh::HalfFaceHandle(-1))
678 {
679 // face didn't exist
680 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(faces[i]);
681 halffacehandles[i] = _mesh->halfface_handle(fh, 0);
682 }
683
684 return _mesh->add_cell(halffacehandles).idx();
685 }
686
687 template <typename MeshT>
688 int FileVTKPlugin::addFaceToOpenVolumeMesh(MeshT*& _mesh, std::vector<quint32> _indices)
689 {
690 if (_indices.size() < 3)
691 { emit log(LOGWARN,tr("Expected at least 3 indices to add a face but got %1").arg(_indices.size()) ); }
692
693 std::vector<OpenVolumeMesh::VertexHandle> face;
694 for (unsigned int i = 0; i < _indices.size(); i++)
695 face.push_back(OpenVolumeMesh::VertexHandle(_indices[i]));
696
697
698 OpenVolumeMesh::HalfFaceHandle halffacehandle;
699 halffacehandle = _mesh->halfface(face);
700 if (!halffacehandle.is_valid()) // face didn't exist
701 {
702 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(face);
703 halffacehandle = _mesh->halfface_handle(fh, 0);
704 }
705 return halffacehandle.idx();
706 }
707
708 template <typename MeshT>
709 int FileVTKPlugin::addFaceToOpenVolumeMesh(MeshT*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3)
710 {
711 std::vector<OpenVolumeMesh::VertexHandle> face;
712 face.push_back(OpenVolumeMesh::VertexHandle(_index1));
713 face.push_back(OpenVolumeMesh::VertexHandle(_index2));
714 face.push_back(OpenVolumeMesh::VertexHandle(_index3));
715
716 OpenVolumeMesh::HalfFaceHandle halffacehandle;
717 halffacehandle = _mesh->halfface(face);
718 if (!halffacehandle.is_valid()) // face didn't exist
719 {
720 OpenVolumeMesh::FaceHandle fh = _mesh->add_face(face);
721 halffacehandle = _mesh->halfface_handle(fh, 0);
722 }
723 return halffacehandle.idx();
724 }
725
726 template <typename MeshT>
727 void FileVTKPlugin::addVertexNormalToOpenVolumeMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
728 {
729 OpenVolumeMesh::VertexPropertyT< typename OpenMesh::Vec3d > vertexNormals = _mesh->template request_vertex_property< typename OpenMesh::Vec3d >("vertex_normals");
730 vertexNormals[OpenVolumeMesh::VertexHandle(_index)] = _normal;
731 }
732
733 template <typename MeshT>
734 void FileVTKPlugin::addFaceNormalToOpenVolumeMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
735 {
736 OpenVolumeMesh::FacePropertyT< OpenMesh::Vec3d > faceNormals = _mesh->template request_face_property< OpenMesh::Vec3d >("face_normals");
737
738 OpenVolumeMesh::HalfFaceHandle hfh = OpenVolumeMesh::HalfFaceHandle(_index);
739 OpenVolumeMesh::FaceHandle fh = _mesh->face_handle(hfh);
740 if (hfh == _mesh->halfface_handle(fh, 0))
741 faceNormals[fh] = _normal;
742 else
743 faceNormals[fh] = -_normal;
744
745 }
746
747 template <typename MeshT>
748 int getCellType(MeshT& _mesh, OpenVolumeMesh::CellHandle _cellHandle)
749 {
750 int incidentFaces = _mesh.cell(_cellHandle).halffaces().size();
751 int incidentVertices = 0;
752 for (OpenVolumeMesh::CellVertexIter cvit = OpenVolumeMesh::CellVertexIter(_cellHandle, &_mesh); cvit.valid(); ++cvit)
753 incidentVertices++;
754
755 if ((incidentFaces == 4) && (incidentVertices == 4))
756 return 10; // tetra
757 else if ((incidentFaces == 6) && (incidentVertices == 8))
758 return 12; // hexahedron
759 else if ((incidentFaces == 5) && (incidentVertices == 6))
760 return 13; // wedge
761 else if ((incidentFaces == 5) && (incidentVertices == 5))
762 return 14; // pyramid
763 else
764 return -1;
765 }
766
767 template <typename MeshT>
768 int getCellType(MeshT& _mesh, OpenVolumeMesh::FaceHandle _faceHandle)
769 {
770 std::vector<OpenVolumeMesh::HalfEdgeHandle> halfedges = _mesh.face(_faceHandle).halfedges();
771 if (halfedges.size() == 3)
772 return 5; // triangle;
773 else
774 return 7; // polygon
775 }
776
777 template <typename MeshT>
778 std::vector<int> getCellVertexIndices(MeshT& _mesh, OpenVolumeMesh::CellHandle _cellHandle, int _cellType)
779 {
780 if (_cellType == 10) //tetra
781 {
782 // first three vertices are the three vertices of an arbitrary face
783 // the last vertex is the one that is left
784 OpenVolumeMesh::OpenVolumeMeshCell cell = _mesh.cell(_cellHandle);
785 OpenVolumeMesh::OpenVolumeMeshFace face = _mesh.halfface(cell.halffaces()[0]);
786 std::vector<OpenVolumeMesh::HalfEdgeHandle> halfedges = face.halfedges();
787 std::vector<int> indices;
788 for (unsigned int i = 0; i < halfedges.size(); i++)
789 indices.push_back(_mesh.halfedge(halfedges[i]).from_vertex().idx());
790 for (OpenVolumeMesh::CellVertexIter cvit = OpenVolumeMesh::CellVertexIter(_cellHandle, &_mesh); cvit.valid(); ++cvit)
791 if ((cvit->idx() != indices[0]) && ((*cvit).idx() != indices[1]) && ((*cvit).idx() != indices[2]))
792 indices.push_back(cvit->idx());
793 return indices;
794 }
795 else if (_cellType == 12) // hexahedron
796 {
797 // take an arbitrary face and add its vertices
798 OpenVolumeMesh::OpenVolumeMeshCell cell = _mesh.cell(_cellHandle);
799 OpenVolumeMesh::HalfFaceHandle hfh = cell.halffaces()[0];
800 OpenVolumeMesh::OpenVolumeMeshFace face = _mesh.halfface(hfh);
801 OpenVolumeMesh::HalfEdgeHandle heh = face.halfedges()[0];
802 std::vector<int> indices;
803 for (unsigned int i = 0; i < 4; i++)
804 {
805 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.halfedge(heh);
806 indices.push_back(edge.from_vertex().idx());
807 heh = _mesh.next_halfedge_in_halfface(heh, hfh);
808 }
809 // we now added four vertices and heh is a handle to the edge coming out of the first added vertex
810 // we will now navigate to the oppsite face
811 OpenVolumeMesh::HalfFaceHandle intermediateHalfFaceHandle = _mesh.adjacent_halfface_in_cell(hfh, heh);
812 heh = _mesh.opposite_halfedge_handle(heh);
813 heh = _mesh.next_halfedge_in_halfface(heh, intermediateHalfFaceHandle);
814 heh = _mesh.next_halfedge_in_halfface(heh, intermediateHalfFaceHandle);
815 OpenVolumeMesh::HalfFaceHandle oppositeHalfFaceHandle = _mesh.adjacent_halfface_in_cell(intermediateHalfFaceHandle, heh);
816 heh = _mesh.opposite_halfedge_handle(heh);
817 // heh is now the halfedge pointing to vertex 4 and lies in the opposite half face.
818 // we now have to add the four vertices of that face but in clockwise order
819 for (unsigned int i = 0; i < 4; i++)
820 {
821 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.halfedge(heh);
822 indices.push_back(edge.to_vertex().idx());
823 heh = _mesh.prev_halfedge_in_halfface(heh, oppositeHalfFaceHandle);
824 }
825 return indices;
826 }
827 else if (_cellType == 13) // wedge
828 {
829 // take a face with three vertices and add its vertices in clockwise order
830 OpenVolumeMesh::OpenVolumeMeshCell cell = _mesh.cell(_cellHandle);
831 OpenVolumeMesh::HalfFaceHandle hfh;
832 for (unsigned int i = 0; i < cell.halffaces().size(); i++)
833 if (_mesh.halfface(cell.halffaces()[i]).halfedges().size() == 3)
834 hfh = cell.halffaces()[i];
835 OpenVolumeMesh::OpenVolumeMeshFace face = _mesh.halfface(hfh);
836 OpenVolumeMesh::HalfEdgeHandle heh = face.halfedges()[0];
837 std::vector<int> indices;
838 for (unsigned int i = 0; i < 3; i++)
839 {
840 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.halfedge(heh);
841 indices.push_back(edge.from_vertex().idx());
842 heh = _mesh.prev_halfedge_in_halfface(heh, hfh);
843 }
844 // we now added three vertices and heh is a handle to the edge coming out of the first added vertex
845 // we will now navigate to the oppsite face
846 OpenVolumeMesh::HalfFaceHandle intermediateHalfFaceHandle = _mesh.adjacent_halfface_in_cell(hfh, heh);
847 heh = _mesh.opposite_halfedge_handle(heh);
848 heh = _mesh.next_halfedge_in_halfface(heh, intermediateHalfFaceHandle);
849 heh = _mesh.next_halfedge_in_halfface(heh, intermediateHalfFaceHandle);
850 OpenVolumeMesh::HalfFaceHandle oppositeHalfFaceHandle = _mesh.adjacent_halfface_in_cell(intermediateHalfFaceHandle, heh);
851 heh = _mesh.opposite_halfedge_handle(heh);
852 // heh is now the halfedge pointing to vertex 3 and lies in the opposite half face.
853 // we now have to add the three vertices of that face but in counter clockwise order
854 for (unsigned int i = 0; i < 3; i++)
855 {
856 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.halfedge(heh);
857 indices.push_back(edge.to_vertex().idx());
858 heh = _mesh.next_halfedge_in_halfface(heh, oppositeHalfFaceHandle);
859 }
860 return indices;
861
862 }
863 else if (_cellType == 14) // pyramid
864 {
865 // the first four vertices are the for vertices of the face with for vertices
866 // the other vertex is the one that is left
867 OpenVolumeMesh::OpenVolumeMeshCell cell = _mesh.cell(_cellHandle);
868 std::vector<OpenVolumeMesh::HalfFaceHandle> halffaces = cell.halffaces();
869 OpenVolumeMesh::OpenVolumeMeshFace face = _mesh.halfface(halffaces[0]);
870 for (unsigned int i = 0; i < halffaces.size(); i++)
871 if (_mesh.halfface(halffaces[i]).halfedges().size() == 4)
872 face = _mesh.halfface(halffaces[i]);
873 std::vector<OpenVolumeMesh::HalfEdgeHandle> halfedges = face.halfedges();
874 std::vector<int> indices;
875 for (unsigned int i = 0; i < halfedges.size(); i++)
876 indices.push_back(_mesh.halfedge(halfedges[i]).from_vertex().idx());
877 for (OpenVolumeMesh::CellVertexIter cvit = OpenVolumeMesh::CellVertexIter(_cellHandle, &_mesh); cvit.valid(); ++cvit)
878 if ((cvit->idx() != indices[0]) && ((*cvit).idx() != indices[1]) && ((*cvit).idx() != indices[2]) && ((*cvit).idx() != indices[3]))
879 indices.push_back(cvit->idx());
880 return indices;
881 }
882 else // unsupported type
883 return std::vector<int>();
884 }
885
886 template <typename MeshT>
887 bool FileVTKPlugin::writeASCIIDataOfOpenVolumeMesh(std::ostream& _out, MeshT& _mesh)
888 {
889 if ( !OpenFlipper::Options::savingSettings() && saveOptions_ != 0)
890 _out.precision(savePrecision_->value());
891
892 _out << "DATASET UNSTRUCTURED_GRID\n";
893
894
895 // save all vertices
896
897 OpenVolumeMesh::VertexIter vit = _mesh.vertices_begin();
898 OpenVolumeMesh::VertexIter end_vit = _mesh.vertices_end();
899 _out << "POINTS " << _mesh.n_vertices() << " float\n";
900 for (; vit != end_vit; ++vit) {
901 // Write vertex p[0] p[1] p[2]
902 ACG::Vec3d p = _mesh.vertex(*vit);
903 _out << p[0] << " " << p[1] << " " << p[2];
904 _out << "\n";
905 }
906
907
908
909 // Remember which faces have been added, so we can later save the isolated faces.
910 OpenVolumeMesh::FacePropertyT<bool> fpAlreadyStored = _mesh.template request_face_property<bool>();
911
912 // Remember which edges have been added, so we can later save the isolated edges;
913 OpenVolumeMesh::EdgePropertyT<bool> epAlreadyStored = _mesh.template request_edge_property<bool>();
914
915 int cellCount = 0;
916
917 // count the cell list size (for each cell: 1 + adjacent vertices)
918
919 quint32 listSize = 0;
920 for (OpenVolumeMesh::CellIter cit = _mesh.cells_begin(); cit != _mesh.cells_end(); ++cit)
921 {
922 int cellType = getCellType(_mesh, *cit);
923
924 if (cellType == 10 )
925 listSize += 1 + 4;
926 else if (cellType == 12 )
927 listSize += 1 + 8;
928 else if (cellType == 13 )
929 listSize += 1 + 6;
930 else if (cellType == 14 )
931 listSize += 1 + 5;
932 else // type not supported by vtk file -> ignore
933 continue;
934
935 cellCount++;
936
937 std::vector<OpenVolumeMesh::HalfFaceHandle> halffaces = _mesh.cell(*cit).halffaces();
938 for (unsigned int i = 0; i < halffaces.size(); i++)
939 {
940 OpenVolumeMesh::FaceHandle fh = _mesh.face_handle(halffaces[i]);
941 if (!(fpAlreadyStored[fh]))
942 {
943 // mark this face and its edges as already stored
944 // if the user wants to save face normals we cannot skip adding the faces
945 if (!(userWriteOptions_ & FileVTKPlugin::FACENORMALS))
946 fpAlreadyStored[fh] = true;
947 //mark the edges as already added.
948 OpenVolumeMesh::OpenVolumeMeshFace face = _mesh.halfface(halffaces[i]);
949 for (std::vector<OpenVolumeMesh::HalfEdgeHandle>::const_iterator heit = face.halfedges().begin();
950 heit != face.halfedges().end();
951 ++heit)
952 {
953 epAlreadyStored[_mesh.edge_handle(*heit)] = true;
954 }
955 }
956 }
957 }
958
959 for (OpenVolumeMesh::FaceIter fit = _mesh.faces_begin(); fit != _mesh.faces_end(); ++fit)
960 {
961 if (!(fpAlreadyStored[*fit]))
962 {
963 //mark edges as already stored
964 std::vector<OpenVolumeMesh::HalfEdgeHandle> halfedges = _mesh.face(*fit).halfedges();
965 for (unsigned int i = 0; i < halfedges.size(); i++)
966 epAlreadyStored[_mesh.edge_handle(halfedges[i])] = true;
967
968 // number of incident vertices == number of incident halfedges
969 listSize += 1 + halfedges.size();
970
971 cellCount++;
972 }
973 }
974
975 for (OpenVolumeMesh::EdgeIter eit = _mesh.edges_begin(); eit != _mesh.edges_end(); ++eit)
976 {
977 if (!(epAlreadyStored[*eit]))
978 {
979 listSize += 1 + 2;
980 cellCount++;
981 }
982 }
983
984 _out << "CELLS " << cellCount << " " << listSize << "\n";
985
986
987 // save all cellCells.
988
989 for (OpenVolumeMesh::CellIter cit = _mesh.cells_begin(); cit != _mesh.cells_end(); ++cit)
990 {
991 //std::vector<OpenVolumeMesh::VertexHandle> vertices;
992
993 int cellType = getCellType(_mesh, *cit);
994
995 // TODO:
996 if (cellType == 10 )
997 listSize += 1 + 4;
998 else if (cellType == 12 )
999 listSize += 1 + 8;
1000 else if (cellType == 13 )
1001 listSize += 1 + 6;
1002 else if (cellType == 14 )
1003 listSize += 1 + 5;
1004 else // type not supported by vtk file -> ignore
1005 continue;
1006
1007 if (cellType == -1)// type not supported by vtk file -> ignore
1008 continue;
1009 else
1010 {
1011 std::vector<int> indices = getCellVertexIndices(_mesh, *cit, cellType);
1012 _out << indices.size();
1013 for (unsigned int i = 0; i < indices.size(); i++)
1014 _out << " " << indices[i];
1015 _out << "\n";
1016 }
1017
1018 }
1019
1020 // save isolated faces
1021
1022 for (OpenVolumeMesh::FaceIter fit = _mesh.faces_begin(); fit != _mesh.faces_end(); ++fit)
1023 {
1024 if (!(fpAlreadyStored[*fit]))
1025 {
1026 std::vector<OpenVolumeMesh::HalfEdgeHandle> halfedges = _mesh.face(*fit).halfedges();
1027
1028 _out << halfedges.size();
1029 for (unsigned int i = 0; i < halfedges.size(); i++)
1030 {
1031 OpenVolumeMesh::HalfEdgeHandle heh = halfedges[i];
1032 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.halfedge(heh);
1033 _out << " " << edge.from_vertex().idx();
1034 }
1035 _out << "\n";
1036 }
1037 }
1038
1039
1040 // save isolated edges
1041
1042
1043 for (OpenVolumeMesh::EdgeIter eit = _mesh.edges_begin(); eit != _mesh.edges_end(); ++eit)
1044 {
1045 if (!(epAlreadyStored[*eit]))
1046 {
1047 OpenVolumeMesh::OpenVolumeMeshEdge edge = _mesh.edge(*eit);
1048 _out << "2";
1049 _out << " " << edge.from_vertex().idx();
1050 _out << " " << edge.to_vertex().idx();
1051 _out << "\n";
1052 }
1053 }
1054
1055
1056
1057 // write cell types to file
1058
1059 _out << "CELL_TYPES " << cellCount << "\n";
1060
1061 // cell cellTypes
1062 for (OpenVolumeMesh::CellIter cit = _mesh.cells_begin(); cit != _mesh.cells_end(); ++cit)
1063 {
1064 int cellType = getCellType(_mesh, *cit);
1065 if (cellType == -1) //type not supported by vtk file, so this cell was not added
1066 continue;
1067 else
1068 _out << cellType << "\n";
1069 }
1070
1071 // face cell types
1072
1073 for (OpenVolumeMesh::FaceIter fit = _mesh.faces_begin(); fit != _mesh.faces_end(); ++fit)
1074 {
1075 if (!(fpAlreadyStored[*fit]))
1076 {
1077 int cellType = getCellType(_mesh,*fit);
1078 if (cellType == -1) //type not supported by vtk file, so this cell was not added
1079 continue;
1080 else
1081 _out << cellType << "\n";
1082 }
1083 }
1084
1085
1086 // edge cell type
1087 for (OpenVolumeMesh::EdgeIter eit = _mesh.edges_begin(); eit != _mesh.edges_end(); ++eit)
1088 {
1089 if (!(epAlreadyStored[*eit]))
1090 {
1091 // all edges have type 3
1092 _out << "2\n";
1093 }
1094 }
1095
1096
1097
1098 //*************//
1099 //OPTIONAL DATA//
1100 //*************//
1101
1102 //writing of tex coords also not supported yet.
1103
1104
1105 //Write vertex normals
1106 if ((userWriteOptions_ & FileVTKPlugin::VERTEXNORMALS))
1107 {
1108 _out << "POINT_DATA "<< _mesh.n_vertices() << "\n";
1109
1110 OpenVolumeMesh::VertexPropertyT< typename OpenMesh::Vec3d > vertexNormals = _mesh.template request_vertex_property< typename OpenMesh::Vec3d >("vertex_normals");
1111 _out << "NORMALS vertex_normals float\n";
1112 for (OpenVolumeMesh::VertexIter vit = _mesh.vertices_begin(); vit != _mesh.vertices_end(); ++vit) {
1113 typename OpenMesh::Vec3d n = vertexNormals[*vit];
1114 _out << n[0] << " " << n[1] << " " << n[2];
1115 _out << "\n";
1116 }
1117 }
1118
1119
1120 //Write face normals
1121 if ((userWriteOptions_ & FileVTKPlugin::FACENORMALS))
1122 {
1123 _out << "CELL_DATA "<< cellCount << "\n";
1124 _out << "NORMALS face_normals float\n";
1125 // write dummy normal for cells
1126
1127 for (OpenVolumeMesh::CellIter cit = _mesh.cells_begin(); cit != _mesh.cells_end(); ++cit)
1128 {
1129 int cellType = getCellType(_mesh, *cit);
1130
1131 if (cellType == -1 )// type not supported by vtk file -> ignore
1132 continue;
1133 else
1134 {
1135 _out << 1 << " " << 0 << " " << 0;
1136 _out << "\n";
1137 }
1138 }
1139
1140
1141 // write face normals
1142 OpenVolumeMesh::FacePropertyT< typename OpenMesh::Vec3d > faceNormals = _mesh.template request_face_property< typename OpenMesh::Vec3d >("face_normals");
1143
1144 for (OpenVolumeMesh::FaceIter fit = _mesh.faces_begin(); fit != _mesh.faces_end(); ++fit) {
1145 typename OpenMesh::Vec3d n = faceNormals[*fit];
1146 _out << n[0] << " " << n[1] << " " << n[2];
1147 _out << "\n";
1148 }
1149
1150
1151 // write dummy normals for edges
1152 for (OpenVolumeMesh::EdgeIter eit = _mesh.edges_begin(); eit != _mesh.edges_end(); ++eit)
1153 {
1154 if (!(epAlreadyStored[*eit]))
1155 {
1156 _out << 1 << " " << 0 << " " << 0;
1157 _out << "\n";
1158 }
1159 }
1160
1161
1162 }
1163
1164 return true;
1165 }
1166
1167 #endif //ENABLE_OPENVOLUMEMESH_SUPPORT
1168
1169 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
1170 int FileVTKPlugin::addTetraCell(HexahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addTetraCellToOpenVolumeMesh(_mesh, indices); }
1171 int FileVTKPlugin::addHexaCell(HexahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addHexaCellToOpenVolumeMesh(_mesh, indices); }
1172 int FileVTKPlugin::addWedgeCell(HexahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addWedgeCellToOpenVolumeMesh(_mesh, indices); }
1173 int FileVTKPlugin::addPyramidCell(HexahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addPyramidCellToOpenVolumeMesh(_mesh, indices); }
1174 int FileVTKPlugin::addFace(HexahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addFaceToOpenVolumeMesh(_mesh, indices); }
1175 int FileVTKPlugin::addFace(HexahedralMesh*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3) { return addFaceToOpenVolumeMesh(_mesh, _index1, _index2, _index3); }
1176 void FileVTKPlugin::addVertexNormal(HexahedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addVertexNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1177 void FileVTKPlugin::addFaceNormal(HexahedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addFaceNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1178 bool FileVTKPlugin::writeASCIIData(std::ostream& _out, HexahedralMesh& _mesh) { return writeASCIIDataOfOpenVolumeMesh(_out, _mesh); }
1179 #endif //ENABLE_HEXAHEDRALMESH_SUPPORT
1180
1181
1182 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
1183 int FileVTKPlugin::addTetraCell(PolyhedralMesh*& _mesh, const std::vector<quint32>& indices) { return addTetraCellToOpenVolumeMesh(_mesh, indices); }
1184 int FileVTKPlugin::addHexaCell(PolyhedralMesh*& _mesh, const std::vector<quint32>& indices) { return addHexaCellToOpenVolumeMesh(_mesh, indices); }
1185 int FileVTKPlugin::addWedgeCell(PolyhedralMesh*& _mesh, const std::vector<quint32>& indices) { return addWedgeCellToOpenVolumeMesh(_mesh, indices); }
1186 int FileVTKPlugin::addPyramidCell(PolyhedralMesh*& _mesh, const std::vector<quint32>& indices) { return addPyramidCellToOpenVolumeMesh(_mesh, indices); }
1187 int FileVTKPlugin::addFace(PolyhedralMesh*& _mesh, const std::vector<quint32>& indices) { return addFaceToOpenVolumeMesh(_mesh, indices); }
1188 int FileVTKPlugin::addFace(PolyhedralMesh*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3) { return addFaceToOpenVolumeMesh(_mesh, _index1, _index2, _index3); }
1189 void FileVTKPlugin::addVertexNormal(PolyhedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addVertexNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1190 void FileVTKPlugin::addFaceNormal(PolyhedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addFaceNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1191 bool FileVTKPlugin::writeASCIIData(std::ostream& _out, PolyhedralMesh& _mesh) { return writeASCIIDataOfOpenVolumeMesh(_out, _mesh); }
1192 #endif //ENABLE_POLYHEDRALMESH_SUPPORT
1193
1194
1195 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
1196 int FileVTKPlugin::addTetraCell(TetrahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addTetraCellToOpenVolumeMesh(_mesh, indices); }
1197 int FileVTKPlugin::addHexaCell(TetrahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addHexaCellToOpenVolumeMesh(_mesh, indices); }
1198 int FileVTKPlugin::addWedgeCell(TetrahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addWedgeCellToOpenVolumeMesh(_mesh, indices); }
1199 int FileVTKPlugin::addPyramidCell(TetrahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addPyramidCellToOpenVolumeMesh(_mesh, indices); }
1200 int FileVTKPlugin::addFace(TetrahedralMesh*& _mesh, const std::vector<quint32>& indices) { return addFaceToOpenVolumeMesh(_mesh, indices); }
1201 int FileVTKPlugin::addFace(TetrahedralMesh*& _mesh, quint32 _index1, quint32 _index2, quint32 _index3) { return addFaceToOpenVolumeMesh(_mesh, _index1, _index2, _index3); }
1202 void FileVTKPlugin::addVertexNormal(TetrahedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addVertexNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1203 void FileVTKPlugin::addFaceNormal(TetrahedralMesh*& _mesh, quint32 _index, OpenMesh::Vec3d _normal) { addFaceNormalToOpenVolumeMesh(_mesh, _index, _normal); }
1204 bool FileVTKPlugin::writeASCIIData(std::ostream& _out, TetrahedralMesh& _mesh) { return writeASCIIDataOfOpenVolumeMesh(_out, _mesh); }
1205 #endif //ENABLE_TETRAHEDRALMESH_SUPPORT
1206
1207 //-----------------------------------------------------------------------------------------------------
1208 //-----------------------------------------------------------------------------------------------------
1209 //----------------------------------- end of cool helper function -------------------------------------
1210 //-----------------------------------------------------------------------------------------------------
1211 //-----------------------------------------------------------------------------------------------------
1212
1213 FileVTKPlugin::BestMeshType FileVTKPlugin::findBestObjectType(QString _filename)
1214 {
1215 QFile file(_filename);
1216
1217 if ( !file.open(QIODevice::ReadOnly) ) {
1218 return BMT_None;
1219 }
1220
1221 QTextStream in(&file);
1222
1223 QString line = in.readLine();
1224
1225 QStringList header = line.split(" ",QString::SkipEmptyParts);
1226 if ( header.size() != 5 ) {
1227 return BMT_None;
1228 }
1229
1230 QString version = header[4];
1231
1232 header.removeLast();
1233
1234 QString magic = header.join(" ");
1235
1236 if ( magic != "# vtk DataFile Version" ) {
1237 return BMT_None;
1238 }
1239
1240 QString description = in.readLine();
1241
1242 QString fileTypeStr = in.readLine();
1243
1244 fileTypeStr = fileTypeStr.simplified();
1245
1246 if ( fileTypeStr.toLower() == "binary" ) {
1247 binary_ = true;
1248 } else if ( fileTypeStr.toLower() == "ascii" ) {
1249 binary_ = false;
1250 } else {
1251 return BMT_None;
1252 }
1253
1254 line = "";
1255
1256 while ( line.simplified() == "" )
1257 line = in.readLine();
1258
1259 QStringList datasetList = line.split(" ",QString::SkipEmptyParts);
1260
1261 if ( datasetList.size() != 2 ) {
1262 return BMT_None;
1263 }
1264
1265 Dataset dataset;
1266
1267 datasetList[1] = datasetList[1].simplified();
1268
1269 if ( datasetList[1] == "STRUCTURED_POINTS" )
1270 dataset = STRUCTURED_POINTS;
1271 else if ( datasetList[1] == "STRUCTURED_GRID" )
1272 dataset = STRUCTURED_GRID;
1273 else if ( datasetList[1] == "RECTILINEAR_GRID" )
1274 dataset = RECTILINEAR_GRID;
1275 else if ( datasetList[1] == "POLYDATA" )
1276 dataset = POLYDATA;
1277 else if ( datasetList[1] == "UNSTRUCTURED_GRID" )
1278 dataset = UNSTRUCTURED_GRID;
1279 else {
1280 return BMT_None;
1281 }
1282
1283
1284 if ((dataset == STRUCTURED_POINTS) || (dataset == STRUCTURED_GRID) || (dataset == RECTILINEAR_GRID) )
1285 {
1286 // Just points so every type is ok. Just use TriMesh. (Apperently these aren't even supported.)
1287 return BMT_TriMesh;
1288 }
1289 else if (dataset == POLYDATA)
1290 {
1291 // The file could contain vertices, lines, polygons, or triangle strips.
1292 // So we will use either TriMesh or PolyMesh.
1293 //
1294 // Test if all polygons are triangles
1295
1296 line = in.readLine();
1297
1298 // Search for line "POLYGONS n size"
1299 while ( !line.contains("POLYGONS") ) {
1300
1301 // stop at end of file!
1302 if ( in.atEnd() ) {
1303 // we didn't find polygons -> all primitives are either vertices, lines or trianglestrips
1304 return BMT_TriMesh;
1305 }
1306
1307 line = in.readLine();
1308 }
1309
1310 QStringList polygonsLine = line.split(" ",QString::SkipEmptyParts);
1311
1312 // It has to contain the Keyword POLYGONS , the number of polygons to read and the total number of values to read ( each polygon: 1 + valence )
1313 if ( polygonsLine.size() != 3 ) {
1314 emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(polygonsLine.size()));
1315 return BMT_None;
1316 }
1317
1318 bool ok = true;
1319
1320 // Number of polygons to read
1321 quint32 polygoncount = polygonsLine[1].toUInt(&ok);
1322
1323 if ( ! ok) {
1324 emit log(LOGERR,tr("Expected to get number of points and entries, but read %1 !").arg(polygonsLine.join(" ")));
1325 return BMT_None;
1326 }
1327
1328 quint32 read = 0;
1329 while ( read < polygoncount) {
1330
1331 // Read first integer describing number of indices
1332 quint32 valence;
1333 if ( !binary_ )
1334 in >> valence;
1335 else
1336 in.device()->read((char*)&valence,sizeof(quint32));
1337
1338 if (valence != 3)
1339 {
1340 // Polygone with more than 3 vertices found -> TriMesh not possible
1341 return BMT_PolyMesh;
1342 }
1343
1344 // read rest
1345 quint32 index;
1346
1347 for ( unsigned int i = 0 ; i < valence; ++i ) {
1348
1349 // Read one index
1350 if ( !binary_ )
1351 in >> index;
1352 else
1353 in.device()->read((char*)&valence,sizeof(quint32));
1354 }
1355 ++read;
1356 }
1357
1358 // if we reach this point, all polygons were triangles
1359 return BMT_TriMesh;
1360
1361 }
1362 else /*if (dataset == UNSTRUCTURED_GRID)*/
1363 {
1364 // The file could contain all different kind of primitives.
1365 // We need to check if all of them are triangles.
1366 // If OpenVolumeMesh is supported we additionally check whether there are
1367 // Cell primitives, and if so, whether all of them are hexaherdral.
1368
1369 line = in.readLine();
1370
1371 // Search for line "CELL_TYPES n"
1372 while ( !line.contains("CELL_TYPES") ) {
1373
1374 // stop at end of file!
1375 if ( in.atEnd() ) {
1376 // we didn't find the line "CELL_TYPES n" -> bad file
1377 return BMT_None;
1378 }
1379
1380 line = in.readLine();
1381 }
1382
1383 // Split the header line into components
1384 QStringList cellLine = line.split(" ",QString::SkipEmptyParts);
1385
1386 // It has to contain the Keyword CELL_TYPES , the number of cells to read
1387 if ( cellLine.size() != 2 ) {
1388 emit log(LOGERR,tr("Expected to get CELL_TYPES line with exactly 2 entries, but %1 found!").arg(cellLine.size()));
1389 return BMT_None;
1390 }
1391
1392 bool ok = true;
1393
1394 // Number of cells to read
1395 quint32 cellCountTypes = cellLine[1].toUInt(&ok);
1396
1397 if ( ! ok) {
1398 emit log(LOGERR,tr("Expected to get number of cell types, but read %1 !").arg(cellLine[1]));
1399 return BMT_None;
1400 }
1401
1402 bool triMeshPossible = true;
1403 bool polyMeshPossible = true;
1404
1405 #ifndef ENABLE_HEXAHEDRALMESH_SUPPORT
1406 bool hexahedralMeshPossible = false;
1407 #else
1408 bool hexahedralMeshPossible = true;
1409 #endif
1410 #ifndef ENABLE_POLYHEDRALMESH_SUPPORT
1411 bool polyhedralMeshPossible = false;
1412 #else
1413 bool polyhedralMeshPossible = true;
1414 #endif
1415 #ifndef ENABLE_TETRAHEDRALMESH_SUPPORT
1416 bool tetrahedralMeshPossible = false;
1417 #else
1418 bool tetrahedralMeshPossible = true;
1419 #endif
1420
1421 quint32 read = 0;
1422 while ( read < cellCountTypes) {
1423
1424 // Read first integer describing number of indizes
1425 quint32 type;
1426 if ( !binary_ )
1427 in >> type;
1428 else
1429 in.device()->read((char*)&type,sizeof(quint32));
1430
1431
1432 if (( 1 <= type ) && (type <= 6 ))
1433 {
1434 // vertex, poly vertex, line, poly line, triangle, triangle strip
1435 // all mesh types possible except hexahedral mesh and tetrahedral mesh
1436 hexahedralMeshPossible = false;
1437 tetrahedralMeshPossible = false;
1438 }
1439 else if (( 7 <= type ) && (type <= 9 ))
1440 {
1441 // polygone, pixel (axis alligned quad), quad -> triMesh not possible
1442 // while polygon could be a triangle as well, we assume that it's not because
1443 // we hope the file author would have chosen type == 5 in that case
1444 triMeshPossible = false;
1445 hexahedralMeshPossible = false;
1446 tetrahedralMeshPossible = false;
1447 }
1448 // TODO: ignore if no OpenVolumeMesh support
1449 else if ( 10 == type )
1450 {
1451 // tetra
1452 triMeshPossible = false;
1453 polyMeshPossible = false;
1454 hexahedralMeshPossible = false;
1455 }
1456 else if (( 13 == type ) || (type == 14 ))
1457 {
1458 // wedge, pyramid
1459 // cannot be represented by anything other than polyhedral mesh
1460 triMeshPossible = false;
1461 polyMeshPossible = false;
1462 hexahedralMeshPossible = false;
1463 tetrahedralMeshPossible = false;
1464
1465 }
1466 else if (( 11 == type ) || ( 12 == type ))
1467 {
1468 // voxel, hexahedron
1469 // cannot be represented by open mesh
1470 triMeshPossible = false;
1471 polyMeshPossible = false;
1472 }
1473
1474
1475 if ( in.status() != QTextStream::Ok ) {
1476 emit log(LOGERR,tr("Read corrupted cell type data!"));
1477 return BMT_None;
1478 }
1479 ++read;
1480 }
1481
1482 if (triMeshPossible)
1483 return BMT_TriMesh;
1484 else if (polyMeshPossible)
1485 return BMT_PolyMesh;
1486 else if (hexahedralMeshPossible)
1487 return BMT_HexahedralMesh;
1488 else if (tetrahedralMeshPossible)
1489 return BMT_TetrahedralMesh;
1490 else if (polyhedralMeshPossible)
1491 return BMT_PolyhedralMesh;
1492 else
1493 return BMT_None;
1494
1495 }
1496
1497
1498
1499 }
1500
1501 int FileVTKPlugin::loadObject(QString _filename) {
1502 std::cerr << "Loading vtk file" << std::endl;
1503
1504 BestMeshType bestType = findBestObjectType(_filename);
1505
1506 QFile file(_filename);
1507
1508 if ( !file.open(QIODevice::ReadOnly) ) {
1509 emit log(LOGERR,"Unable to open vtk file!");
1510 return -1;
1511 }
1512
1513 QTextStream in(&file);
1514
1515 std::cerr << "File is open!" << std::endl;
1516
1517 QString line = in.readLine();
1518
1519 std::cerr << "Got line: " << std::endl;
1520 std::cerr << line.toStdString() << std::endl;
1521
1522 QStringList header = line.split(" ",QString::SkipEmptyParts);
1523
1524 if ( header.size() != 5 ) {
1525 emit log(LOGERR,tr("Bad VTK header? ") + line);
1526 return -1;
1527 }
1528
1529 QString version = header[4];
1530
1531 header.removeLast();
1532
1533 QString magic = header.join(" ");
1534
1535 if ( magic != "# vtk DataFile Version" ) {
1536 emit log(LOGERR,tr("Bad VTK header magic? ") + magic);
1537 return -1;
1538 }
1539
1540 QString description = in.readLine();
1541
1542 QString fileTypeStr = in.readLine();
1543
1544 fileTypeStr = fileTypeStr.simplified();
1545
1546 if ( fileTypeStr.toLower() == "binary" ) {
1547 binary_ = true;
1548 emit log(LOGINFO,tr("Loading VTK binary file of version %1.").arg(version));
1549 emit log(LOGERR,tr("Not yet implemented!"));
1550 } else if ( fileTypeStr.toLower() == "ascii" ) {
1551 binary_ = false;
1552 emit log(LOGINFO,tr("Loading VTK ascii file of version %1.").arg(version));
1553 } else {
1554 emit log(LOGERR,tr("Bad VTK type? ") + fileTypeStr);
1555 return -1;
1556 }
1557
1558 emit log(LOGINFO,description);
1559
1560 line = "";
1561
1562 while ( line.simplified() == "" )
1563 line = in.readLine();
1564
1565 QStringList datasetList = line.split(" ",QString::SkipEmptyParts);
1566
1567 if ( datasetList.size() != 2 ) {
1568 emit log(LOGERR,tr("Bad dataset specification!"));
1569 return -1;
1570 }
1571
1572 Dataset dataset;
1573
1574 datasetList[1] = datasetList[1].simplified();
1575
1576 if ( datasetList[1] == "STRUCTURED_POINTS" )
1577 dataset = STRUCTURED_POINTS;
1578 else if ( datasetList[1] == "STRUCTURED_GRID" )
1579 dataset = STRUCTURED_GRID;
1580 else if ( datasetList[1] == "RECTILINEAR_GRID" )
1581 dataset = RECTILINEAR_GRID;
1582 else if ( datasetList[1] == "POLYDATA" )
1583 dataset = POLYDATA;
1584 else if ( datasetList[1] == "UNSTRUCTURED_GRID" )
1585 dataset = UNSTRUCTURED_GRID;
1586 else {
1587 emit log(LOGERR,tr("Unknown dataset specification! %1").arg(datasetList[1]));
1588 return -1;
1589 }
1590
1591 BaseObjectData* baseObj = 0;
1592 bool is_OpenVolumeMesh = false;
1593
1594 if ( (forceTriangleMesh_) || (bestType == BMT_TriMesh) ){
1595
1596 // add a triangle mesh
1597 int id = -1;
1598 emit addEmptyObject(DATA_TRIANGLE_MESH, id);
1599
1600 TriMeshObject* object(0);
1601
1602 if(PluginFunctions::getObject( id, object)){
1603
1604 TriMesh* _mesh;
1605 PluginFunctions::getMesh(id,_mesh);
1606
1607 if ( _mesh != 0 ) {
1608 if ( !loadMesh(in,_mesh,dataset) ) {
1609 emit log(LOGERR,"Unable to load mesh!");
1610 return -1;
1611 }
1612 } else {
1613 emit log(LOGERR,"Unable to add empty triangle mesh!");
1614 return -1;
1615 }
1616
1617 baseObj = object;
1618 }
1619
1620 }
1621 // If no type can represent the object in the file just use PolyMesh
1622 // and load as much as possible
1623 else if ((bestType == BMT_PolyMesh) || (bestType == BMT_None))
1624 {
1625
1626 int id = -1;
1627 emit addEmptyObject(DATA_POLY_MESH, id);
1628
1629
1630 PolyMeshObject* object(0);
1631
1632 if(PluginFunctions::getObject( id, object)){
1633
1634 PolyMesh* _mesh(0);
1635 PluginFunctions::getMesh(id, _mesh);
1636
1637 if ( _mesh != 0 ) {
1638 if ( !loadMesh(in,_mesh,dataset) ) {
1639 emit log(LOGERR,"Unable to load mesh!");
1640 return -1;
1641 }
1642 } else {
1643 emit log(LOGERR,"Unable to add empty poly mesh!");
1644 return -1;
1645 }
1646
1647 baseObj = object;
1648
1649 }
1650
1651
1652 }
1653 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
1654 else if (bestType == BMT_PolyhedralMesh)
1655 {
1656 // add a Polyhedral mesh
1657 is_OpenVolumeMesh = true;
1658 int id = -1;
1659 emit addEmptyObject(DATA_POLYHEDRAL_MESH, id);
1660
1661 PolyhedralMeshObject* object(0);
1662
1663 if(PluginFunctions::getObject( id, object)){
1664
1665 PolyhedralMesh* _mesh;
1666 _mesh = PluginFunctions::polyhedralMesh(object);
1667
1668 if ( _mesh != 0 ) {
1669 if ( !loadMesh(in,_mesh,dataset) ) {
1670 emit log(LOGERR,"Unable to load mesh!");
1671 return -1;
1672 }
1673 } else {
1674 emit log(LOGERR,"Unable to add empty polyhedral mesh!");
1675 return -1;
1676 }
1677
1678 baseObj = object;
1679 }
1680
1681 }
1682 #endif //ENABLE_POLYHEDRALMESH_SUPPORT
1683 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
1684 else if (bestType == BMT_HexahedralMesh)
1685 {
1686 // add a hexahedral mesh
1687 is_OpenVolumeMesh = true;
1688 int id = -1;
1689 emit addEmptyObject(DATA_HEXAHEDRAL_MESH, id);
1690
1691 HexahedralMeshObject* object(0);
1692
1693 if(PluginFunctions::getObject( id, object)){
1694
1695 HexahedralMesh* _mesh;
1696 _mesh = PluginFunctions::hexahedralMesh(object);
1697
1698 if ( _mesh != 0 ) {
1699 if ( !loadMesh(in,_mesh,dataset) ) {
1700 emit log(LOGERR,"Unable to load mesh!");
1701 return -1;
1702 }
1703 } else {
1704 emit log(LOGERR,"Unable to add empty hexahedral mesh!");
1705 return -1;
1706 }
1707 baseObj = object;
1708 }
1709
1710 }
1711 #endif //ENABLE_HEXAHEDRALMESH_SUPPORT
1712 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
1713 else if (bestType == BMT_TetrahedralMesh)
1714 {
1715 // add a tetrahedral mesh
1716 is_OpenVolumeMesh = true;
1717 int id = -1;
1718 emit addEmptyObject(DATA_TETRAHEDRAL_MESH, id);
1719
1720 TetrahedralMeshObject* object(0);
1721
1722 if(PluginFunctions::getObject( id, object)){
1723
1724 TetrahedralMesh* _mesh;
1725 _mesh = PluginFunctions::tetrahedralMesh(object);
1726
1727 if ( _mesh != 0 ) {
1728 if ( !loadMesh(in,_mesh,dataset) ) {
1729 emit log(LOGERR,"Unable to load mesh!");
1730 return -1;
1731 }
1732 } else {
1733 emit log(LOGERR,"Unable to add empty tetrahedral mesh!");
1734 return -1;
1735 }
1736 baseObj = object;
1737 }
1738
1739 }
1740 #endif //ENABLE_TETRAHEDRALMESH_SUPPORT
1741
1742 if (baseObj)
1743 {
1744 baseObj->setFromFileName(_filename);
1745 baseObj->setName(baseObj->filename());
1746
1747 if (is_OpenVolumeMesh)
1748 {
1749 // Go into solid flat shaded mode
1750 baseObj->setObjectDrawMode(ACG::SceneGraph::DrawModes::getDrawMode("Cells (flat shaded)"));
1751 }
1752
1753 emit updatedObject(baseObj->id(), UPDATE_ALL);
1754
1755 //general stuff
1756 emit openedFile( baseObj->id() );
1757
1758 return baseObj->id();
1759 }
1760
1761 emit log(LOGERR,tr("Error in load mesh!"));
1762
1763 return -1;
1764
1765
1766 }
1767
1768 template <typename MeshT>
1769 bool FileVTKPlugin::loadMeshPoints(QString _spec, QTextStream& _in,MeshT*& _mesh){
1770
1771 std::cerr << "loadMeshPoints" << std::endl;
1772
1773 bool ok = true;
1774
1775 // Split the header line into components
1776 QStringList pointsLine = _spec.split(" ",QString::SkipEmptyParts);
1777
1778 // It has to contain the Keyword POINTS , the number of points to read and the datatype of the points
1779 if ( pointsLine.size() != 3 ) {
1780 emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(pointsLine.size()));
1781 return false;
1782 }
1783
1784 // Get the number of points to read
1785 quint32 points = pointsLine[1].toUInt(&ok);
1786
1787 if ( ! ok) {
1788 emit log(LOGERR,tr("Expected to get number of points, but read %1 !").arg(pointsLine[1]));
1789 return false;
1790 }
1791
1792 // In OpenMesh we use doubles for the point representation
1793 OpenMesh::Vec3d vec;
1794
1795 quint32 read = 0;
1796 while ( read < points ) {
1797
1798
1799 if ( binary_ ) {
1800
1801 // Read binary float values
1802 if ( pointsLine[2] == "float" ) {
1803 // Read floats
1804 OpenMesh::Vec3f vecf;
1805 _in.device()->read((char*)&vecf[0],sizeof(float));
1806 _in.device()->read((char*)&vecf[1],sizeof(float));
1807 _in.device()->read((char*)&vecf[2],sizeof(float));
1808
1809 // convert
1810 vec = vecf;
1811 } else {
1812 emit log(LOGERR,tr("Not implemented data type %1 !").arg(pointsLine[2]));
1813 return false;
1814 }
1815
1816 } else {
1817 // Don't care about original type, as we read text and convert it anyway.
1818 _in >> vec[0] >> vec[1] >> vec[2];
1819 }
1820
1821 // Next point to read
1822 ++read;
1823
1824 // Check if the stream is still ok
1825 if ( _in.status() == QTextStream::Ok ) {
1826 _mesh->add_vertex(vec);
1827 } else {
1828 emit log(LOGERR,tr("Read corrupted point data!"));
1829 return false;
1830 }
1831
1832 }
1833
1834 if (binary_) {
1835 if ( pointsLine[2] == "float" ) {
1836 // Reposition text stream. We read points * 3 * sizeof(float)
1837 // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
1838 _in.seek(_in.pos() + read * 3 * sizeof(float) / sizeof(char) );
1839 }
1840 }
1841
1842 return true;
1843
1844 }
1845
1846 template <typename MeshT>
1847 bool FileVTKPlugin::loadMeshLines(QString _spec,QTextStream& _in,MeshT*& _mesh) {
1848 std::cerr << "loadMeshLines" << std::endl;
1849
1850 bool ok = true;
1851
1852 // Split the header line into components
1853 QStringList linesLine = _spec.split(" ",QString::SkipEmptyParts);
1854
1855 // It has to contain the Keyword LINES , the number of polygons to read and the total number of values to read ( each line: 1 + valence )
1856 if ( linesLine.size() != 3 ) {
1857 emit log(LOGERR,tr("Expected to get LINES line with exactly 3 entries, but %1 found!").arg(linesLine.size()));
1858 return false;
1859 }
1860
1861 // umber of lines to read
1862 quint32 linecount = linesLine[1].toUInt(&ok);
1863
1864 // number of ints in the whole line description!
1865 quint32 entrycount = linesLine[2].toUInt(&ok);
1866
1867 if ( ! ok) {
1868 emit log(LOGERR,tr("Expected to get number of lines and entries, but read %1 !").arg(linesLine.join(" ")));
1869 return false;
1870 }
1871
1872 quint32 read = 0;
1873
1874 while ( read < linecount) {
1875
1876 // Read first integer describing number of indizes in the current line
1877 quint32 valence;
1878
1879 if ( !binary_ )
1880 _in >> valence;
1881 else
1882 _in.device()->read((char*)&valence,sizeof(quint32));
1883
1884
1885 quint32 index;
1886
1887 if ( _in.status() == QTextStream::Ok ) {
1888
1889 if ( !binary_ ) {
1890 for ( unsigned int i = 0 ; i < valence; ++i )
1891 _in >> index;
1892 } else {
1893 for ( unsigned int i = 0 ; i < valence; ++i )
1894 _in.device()->read((char*)&valence,sizeof(quint32));
1895 }
1896
1897 if ( _in.status() == QTextStream::Ok ) {
1898 // TODO : Generate lines here!
1899
1900 //_mesh->add_edge(handles);
1901 } else {
1902 emit log(LOGERR,tr("Read corrupted face data!"));
1903 return false;
1904 }
1905
1906 } else {
1907 emit log(LOGERR,tr("Read corrupted POLYGONS data!"));
1908 return false;
1909 }
1910
1911 ++read;
1912 }
1913
1914 if ( binary_ ) {
1915 // Reposition text stream. We read entrycount * sizeof(quint32) .
1916 // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
1917 _in.seek(_in.pos() + entrycount * sizeof(quint32) / sizeof(char) );
1918 }
1919
1920 emit log(LOGWARN,tr("Lines not supported yet ... skipped!"));
1921
1922 return true;
1923 }
1924
1925 template <typename MeshT>
1926 bool FileVTKPlugin::loadMeshPolygons(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
1927 std::cerr << "loadMeshPolygons" << std::endl;
1928
1929 bool ok = true;
1930
1931 // Split the header line into components
1932 QStringList polygonsLine = _spec.split(" ",QString::SkipEmptyParts);
1933
1934 // It has to contain the Keyword POLYGONS , the number of polygons to read and the total number of values to read ( each polygon: 1 + valence )
1935 if ( polygonsLine.size() != 3 ) {
1936 emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(polygonsLine.size()));
1937 return false;
1938 }
1939
1940 // Number of polygons to read
1941 quint32 polygoncount = polygonsLine[1].toUInt(&ok);
1942
1943 // number of ints in the whole polygon description
1944 quint32 entrycount = polygonsLine[2].toUInt(&ok);
1945
1946 if ( ! ok) {
1947 emit log(LOGERR,tr("Expected to get number of points and entries, but read %1 !").arg(polygonsLine.join(" ")));
1948 return false;
1949 }
1950
1951 // Disable OpenMesh error logging
1952 bool errorEnabled = omerr().is_enabled();
1953 omerr().disable();
1954
1955 quint32 read = 0;
1956 while ( read < polygoncount) {
1957
1958 // Read first integer describing number of indices
1959 quint32 valence;
1960 if ( !binary_ )
1961 _in >> valence;
1962 else
1963 _in.device()->read((char*)&valence,sizeof(quint32));
1964
1965
1966 quint32 index;
1967 std::vector< quint32 > indices;
1968
1969 for ( unsigned int i = 0 ; i < valence; ++i ) {
1970
1971 // Read one index
1972 if ( !binary_ )
1973 _in >> index;
1974 else
1975 _in.device()->read((char*)&valence,sizeof(quint32));
1976
1977 // Remember it
1978 indices.push_back( index );
1979 }
1980
1981 if ( _in.status() == QTextStream::Ok ) {
1982
1983 //check, if there exists duplicate vertices inside of the face
1984 remove_duplicated_vertices(indices);
1985
1986 if (indices.size() >= 3)
1987 {
1988 CellType cell;
1989 cell.type = 7; // VTK_POLYGON
1990 cell.indices = indices;
1991 cell.index = addFace(_mesh, indices);
1992 _cells.push_back(cell);
1993 }
1994 } else {
1995 emit log(LOGERR,tr("Read corrupted face data!"));
1996
1997 // Restore error logging state before returning
1998 if ( errorEnabled )
1999 omerr().enable();
2000
2001 return false;
2002 }
2003 ++read;
2004 }
2005
2006 // Restore error logging state.
2007 if ( errorEnabled )
2008 omerr().enable();
2009
2010 if (binary_) {
2011 // Reposition text stream. We read entrycount * sizeof(qint32)
2012 // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
2013 _in.seek(_in.pos() + entrycount * sizeof(qint32) / sizeof(char) );
2014 }
2015
2016 return true;
2017 }
2018
2019 template <typename MeshT>
2020 int FileVTKPlugin::add_non_manifold_face(MeshT*& _mesh, std::vector< OpenMesh::VertexHandle >& _vhandles) {
2021
2022 // Duplicate vertices of non-manifold faces
2023 // and add them as new isolated face
2024 if (_vhandles.empty()) return -1;
2025
2026 OpenMesh::VPropHandleT< OpenMesh::VertexHandle > originalVertexIdx;
2027 if (! _mesh->get_property_handle(originalVertexIdx,"FileVTKPlugin_originalVertexIdx")) {
2028 _mesh->add_property( originalVertexIdx, "FileVTKPlugin_originalVertexIdx" );
2029
2030 //mark all vertices
2031 typename MeshT::VertexIter vit = _mesh->vertices_begin();
2032 typename MeshT::VertexIter vend = _mesh->vertices_end();
2033 for(; vit != vend; ++vit) {
2034 _mesh->property (originalVertexIdx, *vit) = OpenMesh::VertexHandle(-1);
2035 }
2036 }
2037
2038 // double vertices
2039 for (unsigned int j = 0; j < _vhandles.size(); ++j)
2040 {
2041 typename MeshT::Point p = _mesh->point(_vhandles[j]);
2042 OpenMesh::VertexHandle original_handle = _vhandles[j];
2043 _vhandles[j] = _mesh->add_vertex(p);
2044 // DO STORE p, reference may not work since vertex array
2045 // may be relocated after adding a new vertex !
2046
2047 // Mark vertices of failed face as non-manifold
2048 if (_mesh->has_vertex_status()) {
2049 _mesh->status(_vhandles[j]).set_fixed_nonmanifold(true);
2050 }
2051 // To assign other properties to this vertex later, save its "original" in property
2052 _mesh->property (originalVertexIdx, _vhandles[j]) = original_handle;
2053 }
2054
2055 // add face
2056 OpenMesh::FaceHandle fh = _mesh->add_face(_vhandles);
2057
2058 // Mark failed face as non-manifold
2059 if (_mesh->has_face_status())
2060 _mesh->status(fh).set_fixed_nonmanifold(true);
2061
2062 // Mark edges of failed face as non-two-manifold
2063 if (_mesh->has_edge_status()) {
2064 typename MeshT::FaceEdgeIter fe_it = _mesh->fe_iter(fh);
2065 for (; fe_it.is_valid(); ++fe_it) {
2066 _mesh->status(*fe_it).set_fixed_nonmanifold(true);
2067 }
2068 }
2069
2070 return fh.idx();
2071 }
2072
2073
2074 template <typename MeshT>
2075 bool FileVTKPlugin::loadMeshTriangleStrips(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
2076 std::cerr << "loadMeshTriangleStrips" << std::endl;
2077
2078 bool ok = true;
2079
2080 // Split the header line into components
2081 QStringList triStripsLine = _spec.split(" ",QString::SkipEmptyParts);
2082
2083 // It has to contain the Keyword TRIANGLE_STRIPS , the number of strips to read and the total number of values to read ( each strip: 1 + valence )
2084 if ( triStripsLine.size() != 3 ) {
2085 emit log(LOGERR,tr("Expected to get TRIANGLE_STRIPS line with exactly 3 entries, but %1 found!").arg(triStripsLine.size()));
2086 return false;
2087 }
2088
2089 // Number of polygons to read
2090 quint32 stripcount = triStripsLine[1].toUInt(&ok);
2091
2092 // number of ints in the whole polygon description
2093 quint32 entrycount = triStripsLine[2].toUInt(&ok);
2094
2095 if ( ! ok) {
2096 emit log(LOGERR,tr("Expected to get number of strips and entries, but read %1 !").arg(triStripsLine.join(" ")));
2097 return false;
2098 }
2099
2100 quint32 read = 0;
2101 while ( read < stripcount) {
2102
2103 // Read first integer describing number of indizes in the strip
2104 quint32 valence;
2105 if ( !binary_ )
2106 _in >> valence;
2107 else
2108 _in.device()->read((char*)&valence,sizeof(quint32));
2109
2110
2111 quint32 index;
2112 QList< quint32 > indices;
2113
2114 // Read first two of strip:
2115 for ( unsigned int i = 0 ; i < 2; ++i ) {
2116
2117 // Read one index
2118 if ( !binary_ )
2119 _in >> index;
2120 else
2121 _in.device()->read((char*)&valence,sizeof(quint32));
2122
2123 // Remember it
2124 indices.push_back( index );
2125 }
2126
2127 // Read rest of strip while adding faces
2128 for ( unsigned int i = 2 ; i < valence; ++i ) {
2129
2130 // Read one index
2131 if ( !binary_ )
2132 _in >> index;
2133 else
2134 _in.device()->read((char*)&valence,sizeof(quint32));
2135
2136 // Remember it
2137 indices.push_back( index );
2138
2139 if ( _in.status() == QTextStream::Ok ) {
2140 // TODO : handle non manifold cases!
2141 CellType cell;
2142 cell.type = 6; //VTK_TRIANGLE_STRIP
2143 cell.indices.resize(3);
2144 cell.indices[0] = indices[i];
2145 cell.indices[1] = indices[i-1];
2146 cell.indices[2] = indices[i-2];
2147 if ( i % 2 != 0 )
2148 std::swap(cell.indices[1],cell.indices[2]);
2149 cell.index = addFace(_mesh, cell.indices);
2150 _cells.push_back(cell);
2151 } else {
2152 emit log(LOGERR,tr("Read corrupted face data!"));
2153 return false;
2154 }
2155
2156
2157 }
2158
2159 ++read;
2160 }
2161
2162
2163 if (binary_) {
2164 // Reposition text stream. We read entrycount * sizeof(qint32)
2165 // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
2166 _in.seek(_in.pos() + entrycount * sizeof(qint32) / sizeof(char) );
2167 }
2168
2169 return true;
2170 }
2171
2172 template <typename MeshT>
2173 bool FileVTKPlugin::loadMeshNormals(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells, bool _pointNormal, quint32 _count) {
2174 std::cerr << "loadMeshNormals" << std::endl;
2175
2176 // Split the header line into components
2177 QStringList normalsLine = _spec.split(" ",QString::SkipEmptyParts);
2178
2179 // It has to contain the Keyword NORMALS , the name of the dataset and the datatype
2180 if ( normalsLine.size() != 3 ) {
2181 emit log(LOGERR,tr("Expected to get NORMALS line with exactly 3 entries, but %1 found!").arg(normalsLine.size()));
2182 return false;
2183 }
2184
2185 // In OpenMesh we use doubles for the normal representation
2186 OpenMesh::Vec3d normal;
2187
2188 quint32 read = 0;
2189 while ( read < _count) {
2190
2191 if ( binary_ ) {
2192
2193 // Read binary float values
2194 if ( normalsLine[2] == "float" ) {
2195
2196 // Read floats
2197 OpenMesh::Vec3f vecf;
2198 _in.device()->read((char*)&vecf[0],sizeof(float));
2199 _in.device()->read((char*)&vecf[1],sizeof(float));
2200 _in.device()->read((char*)&vecf[2],sizeof(float));
2201
2202 // convert
2203 normal = vecf;
2204 } else {
2205 emit log(LOGERR,tr("Not implemented data type %1 !").arg(normalsLine[2]));
2206 return false;
2207 }
2208
2209 } else {
2210 // Don't care about original type, as we read text and convert it anyway.
2211 _in >> normal[0] >> normal[1] >> normal[2];
2212 }
2213
2214 // Check if the stream is still ok
2215 if ( _in.status() == QTextStream::Ok ) {
2216
2217 if ( _pointNormal ) {
2218 addVertexNormal(_mesh, read, normal);
2219
2220 } else {
2221 addCellNormal(_mesh, _cells[read], normal);
2222 }
2223
2224 } else {
2225 emit log(LOGERR,tr("Read corrupted point data!"));
2226 return false;
2227 }
2228
2229 // Next normal to read
2230 ++read;
2231 }
2232
2233 if (binary_) {
2234 if ( normalsLine[2] == "float" ) {
2235 // Reposition text stream. We read points * 3 * sizeof(float)
2236 // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2237 _in.seek(_in.pos() + read * 3 * sizeof(float) / sizeof(char) );
2238 }
2239 }
2240
2241 setNormalsOfDuplicatedVertices(_mesh);
2242
2243
2244 return true;
2245 }
2246
2247 template <typename MeshT>
2248 bool FileVTKPlugin::loadMeshCells(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
2249
2250 std::cerr << "loadMeshCells" << std::endl;
2251
2252 // Split the header line into components
2253 QStringList cellLine = _spec.split(" ",QString::SkipEmptyParts);
2254
2255 // It has to contain the Keyword CELLS , the number of cells to read and the total number of values to read ( each cell: 1 + valence )
2256 if ( cellLine.size() != 3 ) {
2257 emit log(LOGERR,tr("Expected to get CELLS line with exactly 3 entries, but %1 found!").arg(cellLine.size()));
2258 return false;
2259 }
2260
2261 bool ok = true;
2262
2263 // Number of cells to read
2264 quint32 cellCount = cellLine[1].toUInt(&ok);
2265
2266 // number of ints in the whole cell description
2267 quint32 entryCount = cellLine[2].toUInt(&ok);
2268
2269
2270 if ( ! ok) {
2271 emit log(LOGERR,tr("Expected to get number of cells and entries, but read %1 !").arg(cellLine.join(" ")));
2272 return false;
2273 }
2274
2275 quint32 read = 0;
2276 while ( read < cellCount) {
2277
2278 CellType currentCell;
2279
2280 // Read first integer describing number of indizes
2281 quint32 valence;
2282 if ( !binary_ )
2283 _in >> valence;
2284 else
2285 _in.device()->read((char*)&valence,sizeof(quint32));
2286
2287
2288 quint32 index;
2289
2290 for ( unsigned int i = 0 ; i < valence; ++i ) {
2291
2292 // Read one index
2293 if ( !binary_ )
2294 _in >> index;
2295 else
2296 _in.device()->read((char*)&valence,sizeof(quint32));
2297
2298 // Remember it
2299 currentCell.indices.push_back( index );
2300 }
2301
2302 if ( _in.status() == QTextStream::Ok ) {
2303 _cells.push_back(currentCell);
2304 } else {
2305 emit log(LOGERR,tr("Read corrupted face data!"));
2306 return false;
2307 }
2308 ++read;
2309
2310 }
2311
2312 if (binary_) {
2313 // Reposition text stream. We read entryCount * sizeof(quint32)
2314 // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2315 _in.seek(_in.pos() + entryCount * sizeof(quint32) / sizeof(char) );
2316 }
2317
2318
2319 //=================================================================================
2320 //=================================================================================
2321 // Read the cell types now
2322 //=================================================================================
2323 //=================================================================================
2324 _spec ="";
2325
2326 // Read lines until we get something usefull
2327 while ( _spec.simplified().size() == 0 ) {
2328
2329 // stop at end of file!
2330 if ( _in.atEnd() ) {
2331 emit log(LOGERR,tr("File end when reading cell specification!"));
2332 return false;
2333 }
2334
2335 _spec = _in.readLine();
2336 }
2337
2338 if ( ! _spec.contains("CELL_TYPES") ) {
2339 emit log(LOGERR,tr("Wrong token! Expected CELL_TYPES but got : %1").arg(_spec));
2340 return false;
2341 }
2342
2343 // Split the header line into components
2344 cellLine = _spec.split(" ",QString::SkipEmptyParts);
2345
2346 // It has to contain the Keyword CELL_TYPES , the number of cells to read
2347 if ( cellLine.size() != 2 ) {
2348 emit log(LOGERR,tr("Expected to get CELL_TYPES line with exactly 2 entries, but %1 found!").arg(cellLine.size()));
2349 return false;
2350 }
2351
2352 // Number of cells to read
2353 quint32 cellCountTypes = cellLine[1].toUInt(&ok);
2354
2355 if ( ! ok) {
2356 emit log(LOGERR,tr("Expected to get number of cell types, but read %1 !").arg(cellLine[1]));
2357 return false;
2358 }
2359
2360 if (cellCountTypes != cellCount ) {
2361 emit log(LOGERR,tr("cellCountTypes != cellCount !").arg(cellLine.size()));
2362 return false;
2363 }
2364
2365 read = 0;
2366 while ( read < cellCount) {
2367
2368 // Read first integer describing number of indizes
2369 quint32 type;
2370 if ( !binary_ )
2371 _in >> type;
2372 else
2373 _in.device()->read((char*)&type,sizeof(quint32));
2374
2375
2376 // Remember it
2377 _cells[read].type = type;
2378
2379 if ( _in.status() != QTextStream::Ok ) {
2380 emit log(LOGERR,tr("Read corrupted cell type data!"));
2381 return false;
2382 }
2383 ++read;
2384 }
2385
2386 if (binary_) {
2387 // Reposition text stream. We read cells * sizeof(quint32)
2388 // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2389 _in.seek(_in.pos() + read * sizeof(quint32) / sizeof(char) );
2390 }
2391
2392 //=================================================================================
2393 //=================================================================================
2394 // Now add the cells
2395 //=================================================================================
2396 //=================================================================================
2397 for ( unsigned int i = 0 ; i < _cells.size() ; ++i ) {
2398 if ( _cells[i].type == 1 ) {
2399
2400 //VERTEX
2401 // Nothing to do for meshes ... already added as vertex
2402
2403 } else if ( _cells[i].type == 2 ) {
2404
2405 //POLY_VERTEX
2406 // Nothing to do for meshes ... already added as vertex
2407
2408 } else if ( _cells[i].type == 3 ) {
2409
2410 //LINE
2411 emit log(LOGWARN,tr("Unsupported Cell Type LINE") );
2412
2413 } else if ( _cells[i].type == 4 ) {
2414 //POLY_LINE
2415
2416 emit log(LOGWARN,tr("Unsupported Cell Type POLY_LINE") );
2417
2418 } else if ( _cells[i].type == 5 ) {
2419 //TRIANGLE
2420 _cells[i].index = addFace(_mesh, _cells[i].indices);
2421 } else if ( _cells[i].type == 6 ) {
2422 //TRIANGLE_STRIP
2423
2424 for ( unsigned int j = 2 ; j < _cells[i].indices.size() ; ++j) {
2425 if ( (j % 2) == 0 )
2426 _cells[i].index = addFace(_mesh, _cells[i].indices[j-2],_cells[i].indices[j],_cells[i].indices[j-1]);
2427 else
2428 _cells[i].index = addFace(_mesh, _cells[i].indices[j-2],_cells[i].indices[j-1],_cells[i].indices[j]);
2429 }
2430
2431 //TODO : handle non manifold cases!
2432
2433 } else if ( _cells[i].type == 7 ) {
2434 //POLYGON
2435
2436 _cells[i].index = addFace(_mesh, _cells[i].indices);
2437
2438 } else if ( _cells[i].type == 8 ) {
2439 //PIXEL
2440
2441 emit log(LOGWARN,tr("Unsupported Cell Type PIXEL") );
2442
2443 } else if ( _cells[i].type == 9 ) {
2444 //QUAD
2445
2446 _cells[i].index = addFace(_mesh, _cells[i].indices);
2447
2448 } else if ( _cells[i].type == 10 ) {
2449 //Tetra
2450 _cells[i].index = addTetraCell(_mesh, _cells[i].indices);
2451
2452 } else if ( _cells[i].type == 11 ) {
2453 //VOXEL
2454
2455 emit log(LOGWARN,tr("Unsupported Cell Type VOXEL") );
2456
2457 } else if ( _cells[i].type == 12 ) {
2458 //HEXAHEDRON
2459
2460 _cells[i].index = addHexaCell(_mesh, _cells[i].indices);
2461 } else if ( _cells[i].type == 13 ) {
2462 //WEDGE
2463
2464 _cells[i].index = addWedgeCell(_mesh, _cells[i].indices);
2465 } else if ( _cells[i].type == 14 ) {
2466 //PYRAMID
2467
2468 _cells[i].index = addPyramidCell(_mesh, _cells[i].indices);
2469
2470 } else {
2471 emit log(LOGERR,tr("Unknown cell type").arg(_cells[i].type) );
2472 }
2473 }
2474
2475 std::cerr << "Read " << read << " Cells " << std::endl;
2476 std::cerr << "Vector has size: " << _cells.size() << std::endl;
2477
2478
2479 return true;
2480 }
2481
2482 template <typename MeshT>
2483 bool FileVTKPlugin::loadMesh(QTextStream& _in,MeshT*& _mesh, Dataset _type){
2484
2485
2486 if ( _type != POLYDATA && _type != UNSTRUCTURED_GRID ) {
2487 emit log(LOGERR,"Unsupported DATASET" );
2488 return false;
2489 }
2490
2491 QString line = "";
2492
2493 bool ok = true;
2494
2495 // Flag if normals have been read from files
2496 bool pointNormalsRead = false;
2497 bool faceNormalsRead = false;
2498
2499 // flag if we are in Point data mode
2500 bool pointData = false;
2501
2502 // Size of the point data
2503 quint32 pointDataSize = 0;
2504
2505 // flag if we are in cell data mode
2506 bool cellData = false;
2507
2508 // Size of the cell data
2509 quint32 cellDataSize = 0;
2510
2511 std::vector<CellType> cells;
2512
2513 while (ok) {
2514
2515 line = _in.readLine();
2516
2517 // Read lines until we get something usefull
2518 while ( line.simplified().size() == 0 ) {
2519
2520 // stop at end of file!
2521 if ( _in.atEnd() ) {
2522 ok = false;
2523 std::cerr << "atEnd" << std::endl;
2524 break;
2525 }
2526
2527 line = _in.readLine();
2528 }
2529
2530 // Stop if something is wrong or we are at the end of the file
2531 if ( !ok )
2532 break;
2533
2534 std::cerr << "Line is: " << line.toStdString() << std::endl;
2535
2536 // if we got a points token:
2537 if ( line.contains("POINTS") ) {
2538
2539 ok = loadMeshPoints(line,_in,_mesh);
2540 } else if ( line.contains("POINT_DATA") ) {
2541
2542 bool ok = true;
2543
2544 // Split the header line into components
2545 QStringList pointDataLine = line.split(" ",QString::SkipEmptyParts);
2546
2547 // It has to contain the Keyword POINT_DATA , and the number of datasets
2548 if ( pointDataLine.size() != 2 ) {
2549 emit log(LOGERR,tr("Expected to get POINT_DATA line with exactly 2 entries, but %1 found!").arg(line.size()));
2550 return false;
2551 }
2552
2553 // Number of polygons to read
2554 pointDataSize = pointDataLine[1].toUInt(&ok);
2555
2556 pointData = true;
2557 cellData = false;
2558
2559 std::cerr << "Point data mode with " << pointDataSize << "Elements" << std::endl;
2560
2561 } else if ( line.contains("CELL_DATA") ) {
2562
2563 bool ok = true;
2564
2565 // Split the header line into components
2566 QStringList cellDataLine = line.split(" ",QString::SkipEmptyParts);
2567
2568 // It has to contain the Keyword CELL_DATA , and the number of datasets
2569 if ( cellDataLine.size() != 2 ) {
2570 emit log(LOGERR,tr("Expected to get CELL_DATA line with exactly 2 entries, but %1 found!").arg(line.size()));
2571 return false;
2572 }
2573
2574 // Number of polygons to read
2575 cellDataSize = cellDataLine[1].toUInt(&ok);
2576
2577 cellData = true;
2578 pointData = false;
2579
2580 std::cerr << "Cell data mode with " << cellDataSize << "Elements" << std::endl;
2581
2582 } else if ( line.contains("VERTICES") ) {
2583 std::cerr << "Vertices will be skipped as they are already added!" << std::endl;
2584 } else if ( line.contains("LINES") ) {
2585 ok = loadMeshLines(line,_in,_mesh);
2586 } else if ( line.contains("POLYGONS") ) {
2587 ok = loadMeshPolygons(line,_in,_mesh, cells);
2588 } else if ( line.contains("TRIANGLE_STRIPS") ) {
2589 ok = loadMeshTriangleStrips(line,_in,_mesh, cells);
2590 } else if ( line.contains("CELL") ) {
2591 ok = loadMeshCells(line,_in,_mesh, cells);
2592 } else if ( line.contains("NORMALS") ) {
2593 // load per point normals or per face normals
2594 if ( pointData ) {
2595 ok = loadMeshNormals(line,_in,_mesh,cells,true,pointDataSize);
2596 pointNormalsRead = true;
2597 } else if (cellData) {
2598 ok = loadMeshNormals(line,_in,_mesh,cells,false,cellDataSize);
2599 faceNormalsRead = true;
2600 } else {
2601 emit log(LOGERR,tr("Got normals keyword but we are neither in pointdata nor celldata mode") );
2602 return false;
2603 }
2604
2605 } else {
2606 std::cerr << "Unrecognized keyword : " << line.toStdString() << std::endl;
2607 }
2608
2609 }
2610
2611 if ( !faceNormalsRead )
2612 updateFaceNormals(_mesh);
2613
2614 if ( !pointNormalsRead )
2615 updateVertexNormals(_mesh);
2616
2617 removeTemporaryProperties(_mesh);
2618
2619 return true;
2620 }
2621
2622 //-----------------------------------------------------------------------------------------------------
2623
2625 int FileVTKPlugin::loadObject(QString _filename, DataType _type){
2626
2627 if ( _type == DATA_TRIANGLE_MESH )
2628 forceTriangleMesh_ = true;
2629 else if ( _type == DATA_POLY_MESH )
2630 forcePolyMesh_ = true;
2631
2632 return loadObject(_filename);
2633 }
2634
2635 //-----------------------------------------------------------------------------------------------------
2636
2637 bool FileVTKPlugin::saveObject(int _id, QString _filename) {
2638
2639 BaseObjectData* object;
2640 if ( !PluginFunctions::getObject(_id,object) ) {
2641 emit log(LOGERR, tr("saveObject : cannot get object id %1 for save name %2").arg(_id).arg(_filename) );
2642 return false;
2643 }
2644
2645 std::string filename = std::string( _filename.toUtf8() );
2646
2647 std::fstream ofs( filename.c_str(), std::ios_base::out );
2648
2649 if (!ofs) {
2650
2651 emit log(LOGERR, tr("saveObject : Cannot not open file %1 for writing!").arg(_filename) );
2652 return false;
2653 }
2654
2655 // Get user specified options
2656 updateUserOptions();
2657
2658 if ( object->dataType( DATA_POLY_MESH ) ) {
2659
2660 object->setFromFileName(_filename);
2661 object->setName(object->filename());
2662
2663 PolyMeshObject* polyObj = dynamic_cast<PolyMeshObject* >( object );
2664
2665 if (writeMesh(ofs, *polyObj->mesh())){
2666 emit log(LOGINFO, tr("Saved object to ") + _filename );
2667 ofs.close();
2668 return true;
2669 }else{
2670 emit log(LOGERR, tr("Unable to save ") + _filename);
2671 ofs.close();
2672 return false;
2673 }
2674 } else if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
2675
2676 object->setFromFileName(_filename);
2677 object->setName(object->filename());
2678
2679 TriMeshObject* triObj = dynamic_cast<TriMeshObject* >( object );
2680
2681 if (writeMesh(ofs, *triObj->mesh())) {
2682 emit log(LOGINFO, tr("Saved object to ") + _filename );
2683 ofs.close();
2684 return true;
2685 } else {
2686 emit log(LOGERR, tr("Unable to save ") + _filename);
2687 ofs.close();
2688 return false;
2689 }
2690 }
2691 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
2692 else if ( object->dataType( DATA_POLYHEDRAL_MESH ) )
2693 {
2694
2695 object->setFromFileName(_filename);
2696 object->setName(object->filename());
2697
2698 PolyhedralMeshObject* polyhedralObj = dynamic_cast<PolyhedralMeshObject* >( object );
2699
2700 if (writeMesh(ofs, *polyhedralObj->mesh())) {
2701 emit log(LOGINFO, tr("Saved object to ") + _filename );
2702 ofs.close();
2703 return true;
2704 } else {
2705 emit log(LOGERR, tr("Unable to save ") + _filename);
2706 ofs.close();
2707 return false;
2708 }
2709 }
2710 #endif
2711 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
2712 else if ( object->dataType( DATA_HEXAHEDRAL_MESH ) )
2713 {
2714
2715 object->setFromFileName(_filename);
2716 object->setName(object->filename());
2717
2718 HexahedralMeshObject* hexahedralObj = dynamic_cast<HexahedralMeshObject* >( object );
2719
2720 if (writeMesh(ofs, *hexahedralObj->mesh())) {
2721 emit log(LOGINFO, tr("Saved object to ") + _filename );
2722 ofs.close();
2723 return true;
2724 } else {
2725 emit log(LOGERR, tr("Unable to save ") + _filename);
2726 ofs.close();
2727 return false;
2728 }
2729 }
2730 #endif
2731 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
2732 else if ( object->dataType( DATA_TETRAHEDRAL_MESH ) )
2733 {
2734
2735 object->setFromFileName(_filename);
2736 object->setName(object->filename());
2737
2738 TetrahedralMeshObject* tetrahedralObj = dynamic_cast<TetrahedralMeshObject* >( object );
2739
2740 if (writeMesh(ofs, *tetrahedralObj->mesh())) {
2741 emit log(LOGINFO, tr("Saved object to ") + _filename );
2742 ofs.close();
2743 return true;
2744 } else {
2745 emit log(LOGERR, tr("Unable to save ") + _filename);
2746 ofs.close();
2747 return false;
2748 }
2749 }
2750 #endif
2751
2752 else {
2753 emit log(LOGERR, tr("Unable to save (object is not a compatible mesh type)"));
2754 ofs.close();
2755 return false;
2756 }
2757
2758 }
2759
2760 //-----------------------------------------------------------------------------------------------------
2761
2762 template< class MeshT >
2763 bool FileVTKPlugin::writeMesh(std::ostream& _out, MeshT& _mesh ) {
2764
2765 /*****************
2766 * HEADER
2767 ******************/
2768 //every VTK file has to start with this
2769 _out << "# vtk DataFile Version 2.0\n";
2770 //write header info. Max. 256 characters!
2771 _out << "Mesh saved from OpenFlipper - www.openflipper.org\n";
2772 //only ASCII is supported right now
2773 _out << "ASCII\n";
2774
2775 /*****************
2776 * DATA
2777 ******************/
2778
2779 // Call corresponding write routine
2780 return writeASCIIData(_out, _mesh);
2781 }
2782
2783 //------------------------------------------------------------------------------------------------------
2784
2785
2786 void FileVTKPlugin::updateUserOptions() {
2787
2788 // If the options dialog has not been initialized, keep
2789 // the initial values
2790
2791 if( OpenFlipper::Options::nogui() )
2792 return;
2793
2794 // Save options
2795 if(saveBinary_) {
2796 if(saveBinary_->isChecked()) userWriteOptions_ |= BINARY;
2797 else { if(userWriteOptions_ & BINARY) userWriteOptions_ -= BINARY; }
2798 }
2799 if(saveFaceNormals_) {
2800 if(saveFaceNormals_->isChecked()) userWriteOptions_ |= FACENORMALS;
2801 else { if(userWriteOptions_ & FACENORMALS) userWriteOptions_ -= FACENORMALS; }
2802 }
2803 if(saveVertexNormals_) {
2804 if(saveVertexNormals_->isChecked()) userWriteOptions_ |= VERTEXNORMALS;
2805 else { if(userWriteOptions_ & VERTEXNORMALS) userWriteOptions_ -= VERTEXNORMALS; }
2806 }
2807 if(saveVertexTexCoords_) {
2808 if(saveVertexTexCoords_->isChecked()) userWriteOptions_ |= VERTEXTEXCOORDS;
2809 else { if(userWriteOptions_ & VERTEXTEXCOORDS) userWriteOptions_ -= VERTEXTEXCOORDS; }
2810 }
2811 }
2812
2813
2814
2815
FileVTKPlugin::CellType
Definition: FileVTK.hh:85
OpenFlipperSettings
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
Definition: GlobalOptions.cc:1038
LOGWARN
Definition: LoggingInterface.hh:95
OpenVolumeMesh::FaceIter
Definition: Iterators.hh:995
FileVTKPlugin::loadMeshLines
bool loadMeshLines(QString _spec, QTextStream &_in, MeshT *&_mesh)
Reads lines from the stream and adds them to the mesh.
Definition: FileVTK.cc:1847
FileVTKPlugin::addFaceToOpenMesh
int addFaceToOpenMesh(MeshT *&_mesh, std::vector< quint32 > _indices)
Adds a face to the mesh.
Definition: FileVTK.cc:232
LOGINFO
Definition: LoggingInterface.hh:94
FileVTKPlugin::getLoadFilters
QString getLoadFilters()
Definition: FileVTK.cc:101
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
FileVTKPlugin::addFaceNormal
void addFaceNormal(TriMesh *&_mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a face normal.
Definition: FileVTK.cc:492
FileVTKPlugin::loadMeshNormals
bool loadMeshNormals(QString _spec, QTextStream &_in, MeshT *&_mesh, std::vector< CellType > &_cells, bool _pointNormal, quint32 _count)
Reads Normals from the stream and adds them to the mesh.
Definition: FileVTK.cc:2173
OpenMesh::VertexHandle
Handle for a vertex entity.
Definition: Handles.hh:120
FileVTKPlugin::setNormalsOfDuplicatedVertices
void setNormalsOfDuplicatedVertices(TriMesh *&_mesh)
Sets normals of duplicated vertices that were created for non-manifold meshes.
Definition: FileVTK.cc:495
DATA_POLY_MESH
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
FileVTKPlugin::supportedType
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Definition: FileVTK.cc:113
FileVTKPlugin::removeTemporaryProperties
void removeTemporaryProperties(TriMesh *&_mesh)
Removed temporary properties that might have been added during file reading.
Definition: FileVTK.cc:486
FileVTKPlugin::loadMeshPoints
bool loadMeshPoints(QString _spec, QTextStream &_in, MeshT *&_mesh)
Reads points from the stream and adds them to the mesh.
Definition: FileVTK.cc:1769
FileVTKPlugin::addTetraCellToOpenMesh
int addTetraCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a tetra cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:204
FileVTKPlugin::binary_
bool binary_
Reading binary file?
Definition: FileVTK.hh:215
FileVTKPlugin::loadMeshPolygons
bool loadMeshPolygons(QString _spec, QTextStream &_in, MeshT *&_mesh, std::vector< CellType > &_cells)
Reads polygons from the stream and adds them to the mesh.
Definition: FileVTK.cc:1926
FileVTKPlugin::saveOptionsWidget
QWidget * saveOptionsWidget(QString)
Definition: FileVTK.cc:137
BaseObject::id
int id() const
Definition: BaseObject.cc:190
FileVTKPlugin::addFace
int addFace(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a face to the mesh.
Definition: FileVTK.cc:477
FileVTKPlugin::updateVertexNormalsOfOpenMesh
void updateVertexNormalsOfOpenMesh(MeshT *&_mesh)
Updates vertex normals.
Definition: FileVTK.cc:276
ACG::SceneGraph::DrawModes::getDrawMode
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:807
FileVTKPlugin::updateUserOptions
void updateUserOptions()
Definition: FileVTK.cc:2786
FileVTKPlugin::writeMesh
bool writeMesh(std::ostream &_out, MeshT &_mesh)
Writes the header of the VTK file, then calls writeASCIIData (binary VTK is currently unsupported) ...
Definition: FileVTK.cc:2763
BaseObject::setFromFileName
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:716
OpenFlipperQSettings::setValue
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
Definition: OpenFlipperQSettings.cc:61
OpenVolumeMesh::OpenVolumeMeshFace
Definition: BaseEntities.hh:90
FileVTKPlugin::addVertexNormalToOpenMesh
void addVertexNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a vertex normal.
Definition: FileVTK.cc:292
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
MeshObject::mesh
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT_impl.hh:350
OpenVolumeMesh::GeometryKernel
Definition: GeometryKernel.hh:55
FileVTKPlugin::addHexaCell
int addHexaCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a hexa cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:468
FileVTKPlugin::writeASCIIDataOfOpenMesh
bool writeASCIIDataOfOpenMesh(std::ostream &_out, MeshT &_mesh)
Writes the data of the VTK file in ASCII format.
Definition: FileVTK.cc:375
FileVTKPlugin::updateVertexNormals
void updateVertexNormals(TriMesh *&_mesh)
Updates vertex normals.
Definition: FileVTK.cc:483
FileVTKPlugin::addWedgeCell
int addWedgeCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a wedge cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:471
FileVTKPlugin::findBestObjectType
BestMeshType findBestObjectType(QString _filename)
Reads the file to check for present primitives and returns the object type that fits best...
Definition: FileVTK.cc:1213
VolumeMeshObject
Definition: VolumeMeshObject.hh:63
LOGERR
Definition: LoggingInterface.hh:96
DATA_TETRAHEDRAL_MESH
#define DATA_TETRAHEDRAL_MESH
Definition: TetrahedralMesh.hh:55
FileVTKPlugin::addVertexNormal
void addVertexNormal(TriMesh *&_mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a vertex normal.
Definition: FileVTK.cc:489
PluginFunctions::getMesh
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
Definition: PluginFunctionsPolyMesh.cc:101
BaseObjectData::setName
virtual void setName(QString _name)
path to the file from which the object is loaded ( defaults to "." )
Definition: BaseObjectData.cc:355
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
TriMeshObject
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
PluginFunctions::polyhedralMesh
PolyhedralMesh * polyhedralMesh(BaseObjectData *_object)
Get an PolyhedralMesh from an object.
Definition: PluginFunctionsPolyhedralMesh.cc:115
FileVTKPlugin::loadObject
int loadObject(QString _filename)
Loads Object and converts it to a triangle mesh if possible.
Definition: FileVTK.cc:1501
OpenVolumeMesh::VertexIter
Definition: Iterators.hh:833
OpenVolumeMesh::HandleT< Entity::Vertex >
FileVTKPlugin::addPyramidCellToOpenMesh
int addPyramidCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a pyramid cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:225
PluginFunctions::hexahedralMesh
HexahedralMesh * hexahedralMesh(BaseObjectData *_object)
Get an HexahedralMesh from an object.
Definition: PluginFunctionsHexahedralMesh.cc:114
FileVTKPlugin::addHexaCellToOpenMesh
int addHexaCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a hexa cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:211
FileVTKPlugin::addCellNormal
void addCellNormal(MeshT *&_mesh, const CellType &_cell, OpenMesh::Vec3d _normal)
Adds a normal to the cell.
Definition: FileVTK.cc:309
BaseObject::filename
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
OpenMesh::FaceHandle
Handle for a face entity.
Definition: Handles.hh:141
OpenVolumeMesh::OpenVolumeMeshEdge
Definition: BaseEntities.hh:52
OpenVolumeMesh::CellIter
Definition: Iterators.hh:1103
FileVTKPlugin::add_non_manifold_face
int add_non_manifold_face(MeshT *&_mesh, std::vector< OpenMesh::VertexHandle > &_vhandles)
Helper function for loadMeshPolygons() that takes care of adding non-manifold faces.
Definition: FileVTK.cc:2020
FileVTKPlugin::loadOptionsWidget
QWidget * loadOptionsWidget(QString)
Definition: FileVTK.cc:131
FileVTKPlugin::updateFaceNormals
void updateFaceNormals(TriMesh *&_mesh)
Updates face normals.
Definition: FileVTK.cc:271
OpenMesh::Attributes::TexCoord2D
Add 2D texture coordinates (vertices, halfedges)
Definition: Attributes.hh:87
DATA_HEXAHEDRAL_MESH
#define DATA_HEXAHEDRAL_MESH
Definition: HexahedralMesh.hh:56
OpenVolumeMesh::PropertyTT
Definition: ForwardDeclarations.hh:18
FileVTKPlugin::getSaveFilters
QString getSaveFilters()
Definition: FileVTK.cc:107
FileVTKPlugin::removeTemporaryPropertiesOfOpenMesh
void removeTemporaryPropertiesOfOpenMesh(MeshT *&_mesh)
Removed temporary properties that might have been added during file reading.
Definition: FileVTK.cc:282
DATA_GROUP
const DataType DATA_GROUP(1)
Items used for Grouping.
FileVTKPlugin::addPyramidCell
int addPyramidCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a pyramid cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:474
OpenVolumeMesh::OpenVolumeMeshCell
Definition: BaseEntities.hh:124
OpenMesh::BaseHandle::idx
int idx() const
Get the underlying index of this handle.
Definition: Handles.hh:69
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
FileVTKPlugin::slotSaveDefault
void slotSaveDefault()
Slot called when user wants to save the given Save options as default.
Definition: FileVTK.cc:186
OpenMesh::VectorT< double, 3 >
DATA_POLYHEDRAL_MESH
#define DATA_POLYHEDRAL_MESH
Definition: PolyhedralMesh.hh:54
FileVTKPlugin::addWedgeCellToOpenMesh
int addWedgeCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a wedge cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:218
BaseObjectData::setObjectDrawMode
void setObjectDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, const bool &_force=false)
Set the draw mode for the object.
Definition: BaseObjectData.cc:298
FileVTKPlugin::loadMeshCells
bool loadMeshCells(QString _spec, QTextStream &_in, MeshT *&_mesh, std::vector< CellType > &_cells)
Reads unstructured grid data from the stream and adds it to the mesh.
Definition: FileVTK.cc:2248
OpenVolumeMesh::CellVertexIter
Definition: Iterators.hh:599
OpenMesh::VectorT::size
static constexpr size_t size()
returns dimension of the vector
Definition: Vector11T.hh:107
OpenMesh::BaseHandle::is_valid
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
FileVTKPlugin::loadMeshTriangleStrips
bool loadMeshTriangleStrips(QString _spec, QTextStream &_in, MeshT *&_mesh, std::vector< CellType > &_cells)
Reads triangle strips from the stream and adds them to the mesh.
Definition: FileVTK.cc:2075
FileVTKPlugin::updateFaceNormalsOfOpenMesh
void updateFaceNormalsOfOpenMesh(MeshT *&_mesh)
Updates face normals.
Definition: FileVTK.cc:266
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
BaseObjectData
Definition: BaseObjectData.hh:102
VolumeMeshObject::mesh
MeshT * mesh()
return a pointer to the mesh
Definition: VolumeMeshObjectT_impl.hh:212
OpenVolumeMesh::EdgeIter
Definition: Iterators.hh:887
FileVTKPlugin::description
QString description()
Return a description of what the plugin is doing.
Definition: FileVTK.hh:177
PolyMeshObject
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
FileVTKPlugin::addTetraCell
int addTetraCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a tetra cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:465
FileVTKPlugin::FileVTKPlugin
FileVTKPlugin()
Constructor.
Definition: FileVTK.cc:69
PluginFunctions::tetrahedralMesh
TetrahedralMesh * tetrahedralMesh(BaseObjectData *_object)
Get an TetrahedralMesh from an object.
Definition: PluginFunctionsTetrahedralMesh.cc:114
FileVTKPlugin::initializePlugin
void initializePlugin()
Initialize Plugin.
Definition: FileVTK.cc:87
FileVTKPlugin::setNormalsOfDuplicatedVerticesOfOpenMesh
void setNormalsOfDuplicatedVerticesOfOpenMesh(MeshT *&_mesh)
Sets normals of duplicated vertices that were created for non-manifold meshes.
Definition: FileVTK.cc:352
FileVTKPlugin::writeASCIIData
bool writeASCIIData(std::ostream &_out, TriMesh &_mesh)
Writes the data of the VTK file in ASCII format.
Definition: FileVTK.cc:498
OpenMesh::VPropHandleT
Definition: Property.hh:482
FileVTKPlugin::addFaceNormalToOpenMesh
void addFaceNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a face normal.
Definition: FileVTK.cc:301