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