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