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