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 v_it = _mesh.vertices_begin(); v_it != _mesh.vertices_end(); ++v_it) {
1113  typename OpenMesh::Vec3d n = vertexNormals[*v_it];
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 
1226 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1227  QStringList header = line.split(" ",QString::SkipEmptyParts);
1228 #else
1229  QStringList header = line.split(" ",Qt::SkipEmptyParts);
1230 #endif
1231 
1232  if ( header.size() != 5 ) {
1233  return BMT_None;
1234  }
1235 
1236  QString version = header[4];
1237 
1238  header.removeLast();
1239 
1240  QString magic = header.join(" ");
1241 
1242  if ( magic != "# vtk DataFile Version" ) {
1243  return BMT_None;
1244  }
1245 
1246  QString description = in.readLine();
1247 
1248  QString fileTypeStr = in.readLine();
1249 
1250  fileTypeStr = fileTypeStr.simplified();
1251 
1252  if ( fileTypeStr.toLower() == "binary" ) {
1253  binary_ = true;
1254  } else if ( fileTypeStr.toLower() == "ascii" ) {
1255  binary_ = false;
1256  } else {
1257  return BMT_None;
1258  }
1259 
1260  line = "";
1261 
1262  while ( line.simplified() == "" )
1263  line = in.readLine();
1264 
1265 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1266  QStringList datasetList = line.split(" ",QString::SkipEmptyParts);
1267 #else
1268  QStringList datasetList = line.split(" ",Qt::SkipEmptyParts);
1269 #endif
1270 
1271 
1272 
1273  if ( datasetList.size() != 2 ) {
1274  return BMT_None;
1275  }
1276 
1277  Dataset dataset;
1278 
1279  datasetList[1] = datasetList[1].simplified();
1280 
1281  if ( datasetList[1] == "STRUCTURED_POINTS" )
1282  dataset = STRUCTURED_POINTS;
1283  else if ( datasetList[1] == "STRUCTURED_GRID" )
1284  dataset = STRUCTURED_GRID;
1285  else if ( datasetList[1] == "RECTILINEAR_GRID" )
1286  dataset = RECTILINEAR_GRID;
1287  else if ( datasetList[1] == "POLYDATA" )
1288  dataset = POLYDATA;
1289  else if ( datasetList[1] == "UNSTRUCTURED_GRID" )
1290  dataset = UNSTRUCTURED_GRID;
1291  else {
1292  return BMT_None;
1293  }
1294 
1295 
1296  if ((dataset == STRUCTURED_POINTS) || (dataset == STRUCTURED_GRID) || (dataset == RECTILINEAR_GRID) )
1297  {
1298  // Just points so every type is ok. Just use TriMesh. (Apperently these aren't even supported.)
1299  return BMT_TriMesh;
1300  }
1301  else if (dataset == POLYDATA)
1302  {
1303  // The file could contain vertices, lines, polygons, or triangle strips.
1304  // So we will use either TriMesh or PolyMesh.
1305  //
1306  // Test if all polygons are triangles
1307 
1308  line = in.readLine();
1309 
1310  // Search for line "POLYGONS n size"
1311  while ( !line.contains("POLYGONS") ) {
1312 
1313  // stop at end of file!
1314  if ( in.atEnd() ) {
1315  // we didn't find polygons -> all primitives are either vertices, lines or trianglestrips
1316  return BMT_TriMesh;
1317  }
1318 
1319  line = in.readLine();
1320  }
1321 
1322 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1323  QStringList polygonsLine = line.split(" ",QString::SkipEmptyParts);
1324 #else
1325  QStringList polygonsLine = line.split(" ",Qt::SkipEmptyParts);
1326 #endif
1327 
1328 
1329  // 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 )
1330  if ( polygonsLine.size() != 3 ) {
1331  emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(polygonsLine.size()));
1332  return BMT_None;
1333  }
1334 
1335  bool ok = true;
1336 
1337  // Number of polygons to read
1338  quint32 polygoncount = polygonsLine[1].toUInt(&ok);
1339 
1340  if ( ! ok) {
1341  emit log(LOGERR,tr("Expected to get number of points and entries, but read %1 !").arg(polygonsLine.join(" ")));
1342  return BMT_None;
1343  }
1344 
1345  quint32 read = 0;
1346  while ( read < polygoncount) {
1347 
1348  // Read first integer describing number of indices
1349  quint32 valence;
1350  if ( !binary_ )
1351  in >> valence;
1352  else
1353  in.device()->read((char*)&valence,sizeof(quint32));
1354 
1355  if (valence != 3)
1356  {
1357  // Polygone with more than 3 vertices found -> TriMesh not possible
1358  return BMT_PolyMesh;
1359  }
1360 
1361  // read rest
1362  quint32 index;
1363 
1364  for ( unsigned int i = 0 ; i < valence; ++i ) {
1365 
1366  // Read one index
1367  if ( !binary_ )
1368  in >> index;
1369  else
1370  in.device()->read((char*)&valence,sizeof(quint32));
1371  }
1372  ++read;
1373  }
1374 
1375  // if we reach this point, all polygons were triangles
1376  return BMT_TriMesh;
1377 
1378  }
1379  else /*if (dataset == UNSTRUCTURED_GRID)*/
1380  {
1381  // The file could contain all different kind of primitives.
1382  // We need to check if all of them are triangles.
1383  // If OpenVolumeMesh is supported we additionally check whether there are
1384  // Cell primitives, and if so, whether all of them are hexaherdral.
1385 
1386  line = in.readLine();
1387 
1388  // Search for line "CELL_TYPES n"
1389  while ( !line.contains("CELL_TYPES") ) {
1390 
1391  // stop at end of file!
1392  if ( in.atEnd() ) {
1393  // we didn't find the line "CELL_TYPES n" -> bad file
1394  return BMT_None;
1395  }
1396 
1397  line = in.readLine();
1398  }
1399 
1400  // Split the header line into components
1401 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1402  QStringList cellLine = line.split(" ",QString::SkipEmptyParts);
1403 #else
1404  QStringList cellLine = line.split(" ",Qt::SkipEmptyParts);
1405 #endif
1406 
1407 
1408  // It has to contain the Keyword CELL_TYPES , the number of cells to read
1409  if ( cellLine.size() != 2 ) {
1410  emit log(LOGERR,tr("Expected to get CELL_TYPES line with exactly 2 entries, but %1 found!").arg(cellLine.size()));
1411  return BMT_None;
1412  }
1413 
1414  bool ok = true;
1415 
1416  // Number of cells to read
1417  quint32 cellCountTypes = cellLine[1].toUInt(&ok);
1418 
1419  if ( ! ok) {
1420  emit log(LOGERR,tr("Expected to get number of cell types, but read %1 !").arg(cellLine[1]));
1421  return BMT_None;
1422  }
1423 
1424  bool triMeshPossible = true;
1425  bool polyMeshPossible = true;
1426 
1427 #ifndef ENABLE_HEXAHEDRALMESH_SUPPORT
1428  bool hexahedralMeshPossible = false;
1429 #else
1430  bool hexahedralMeshPossible = true;
1431 #endif
1432 #ifndef ENABLE_POLYHEDRALMESH_SUPPORT
1433  bool polyhedralMeshPossible = false;
1434 #else
1435  bool polyhedralMeshPossible = true;
1436 #endif
1437 #ifndef ENABLE_TETRAHEDRALMESH_SUPPORT
1438  bool tetrahedralMeshPossible = false;
1439 #else
1440  bool tetrahedralMeshPossible = true;
1441 #endif
1442 
1443  quint32 read = 0;
1444  while ( read < cellCountTypes) {
1445 
1446  // Read first integer describing number of indizes
1447  quint32 type;
1448  if ( !binary_ )
1449  in >> type;
1450  else
1451  in.device()->read((char*)&type,sizeof(quint32));
1452 
1453 
1454  if (( 1 <= type ) && (type <= 6 ))
1455  {
1456  // vertex, poly vertex, line, poly line, triangle, triangle strip
1457  // all mesh types possible except hexahedral mesh and tetrahedral mesh
1458  hexahedralMeshPossible = false;
1459  tetrahedralMeshPossible = false;
1460  }
1461  else if (( 7 <= type ) && (type <= 9 ))
1462  {
1463  // polygone, pixel (axis alligned quad), quad -> triMesh not possible
1464  // while polygon could be a triangle as well, we assume that it's not because
1465  // we hope the file author would have chosen type == 5 in that case
1466  triMeshPossible = false;
1467  hexahedralMeshPossible = false;
1468  tetrahedralMeshPossible = false;
1469  }
1470  // TODO: ignore if no OpenVolumeMesh support
1471  else if ( 10 == type )
1472  {
1473  // tetra
1474  triMeshPossible = false;
1475  polyMeshPossible = false;
1476  hexahedralMeshPossible = false;
1477  }
1478  else if (( 13 == type ) || (type == 14 ))
1479  {
1480  // wedge, pyramid
1481  // cannot be represented by anything other than polyhedral mesh
1482  triMeshPossible = false;
1483  polyMeshPossible = false;
1484  hexahedralMeshPossible = false;
1485  tetrahedralMeshPossible = false;
1486 
1487  }
1488  else if (( 11 == type ) || ( 12 == type ))
1489  {
1490  // voxel, hexahedron
1491  // cannot be represented by open mesh
1492  triMeshPossible = false;
1493  polyMeshPossible = false;
1494  }
1495 
1496 
1497  if ( in.status() != QTextStream::Ok ) {
1498  emit log(LOGERR,tr("Read corrupted cell type data!"));
1499  return BMT_None;
1500  }
1501  ++read;
1502  }
1503 
1504  if (triMeshPossible)
1505  return BMT_TriMesh;
1506  else if (polyMeshPossible)
1507  return BMT_PolyMesh;
1508  else if (hexahedralMeshPossible)
1509  return BMT_HexahedralMesh;
1510  else if (tetrahedralMeshPossible)
1511  return BMT_TetrahedralMesh;
1512  else if (polyhedralMeshPossible)
1513  return BMT_PolyhedralMesh;
1514  else
1515  return BMT_None;
1516 
1517  }
1518 
1519 
1520 
1521 }
1522 
1523 int FileVTKPlugin::loadObject(QString _filename) {
1524  std::cerr << "Loading vtk file" << std::endl;
1525 
1526  BestMeshType bestType = findBestObjectType(_filename);
1527 
1528  QFile file(_filename);
1529 
1530  if ( !file.open(QIODevice::ReadOnly) ) {
1531  emit log(LOGERR,"Unable to open vtk file!");
1532  return -1;
1533  }
1534 
1535  QTextStream in(&file);
1536 
1537  std::cerr << "File is open!" << std::endl;
1538 
1539  QString line = in.readLine();
1540 
1541  std::cerr << "Got line: " << std::endl;
1542  std::cerr << line.toStdString() << std::endl;
1543 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1544  QStringList header = line.split(" ",QString::SkipEmptyParts);
1545 #else
1546  QStringList header = line.split(" ",Qt::SkipEmptyParts);
1547 #endif
1548 
1549 
1550  if ( header.size() != 5 ) {
1551  emit log(LOGERR,tr("Bad VTK header? ") + line);
1552  return -1;
1553  }
1554 
1555  QString version = header[4];
1556 
1557  header.removeLast();
1558 
1559  QString magic = header.join(" ");
1560 
1561  if ( magic != "# vtk DataFile Version" ) {
1562  emit log(LOGERR,tr("Bad VTK header magic? ") + magic);
1563  return -1;
1564  }
1565 
1566  QString description = in.readLine();
1567 
1568  QString fileTypeStr = in.readLine();
1569 
1570  fileTypeStr = fileTypeStr.simplified();
1571 
1572  if ( fileTypeStr.toLower() == "binary" ) {
1573  binary_ = true;
1574  emit log(LOGINFO,tr("Loading VTK binary file of version %1.").arg(version));
1575  emit log(LOGERR,tr("Not yet implemented!"));
1576  } else if ( fileTypeStr.toLower() == "ascii" ) {
1577  binary_ = false;
1578  emit log(LOGINFO,tr("Loading VTK ascii file of version %1.").arg(version));
1579  } else {
1580  emit log(LOGERR,tr("Bad VTK type? ") + fileTypeStr);
1581  return -1;
1582  }
1583 
1584  emit log(LOGINFO,description);
1585 
1586  line = "";
1587 
1588  while ( line.simplified() == "" )
1589  line = in.readLine();
1590 
1591 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1592  QStringList datasetList = line.split(" ",QString::SkipEmptyParts);
1593 #else
1594  QStringList datasetList = line.split(" ",Qt::SkipEmptyParts);
1595 #endif
1596  if ( datasetList.size() != 2 ) {
1597  emit log(LOGERR,tr("Bad dataset specification!"));
1598  return -1;
1599  }
1600 
1601  Dataset dataset;
1602 
1603  datasetList[1] = datasetList[1].simplified();
1604 
1605  if ( datasetList[1] == "STRUCTURED_POINTS" )
1606  dataset = STRUCTURED_POINTS;
1607  else if ( datasetList[1] == "STRUCTURED_GRID" )
1608  dataset = STRUCTURED_GRID;
1609  else if ( datasetList[1] == "RECTILINEAR_GRID" )
1610  dataset = RECTILINEAR_GRID;
1611  else if ( datasetList[1] == "POLYDATA" )
1612  dataset = POLYDATA;
1613  else if ( datasetList[1] == "UNSTRUCTURED_GRID" )
1614  dataset = UNSTRUCTURED_GRID;
1615  else {
1616  emit log(LOGERR,tr("Unknown dataset specification! %1").arg(datasetList[1]));
1617  return -1;
1618  }
1619 
1620  BaseObjectData* baseObj = 0;
1621  bool is_OpenVolumeMesh = false;
1622 
1623  if ( (forceTriangleMesh_) || (bestType == BMT_TriMesh) ){
1624 
1625  // add a triangle mesh
1626  int id = -1;
1627  emit addEmptyObject(DATA_TRIANGLE_MESH, id);
1628 
1629  TriMeshObject* object(0);
1630 
1631  if(PluginFunctions::getObject( id, object)){
1632 
1633  TriMesh* _mesh;
1634  PluginFunctions::getMesh(id,_mesh);
1635 
1636  if ( _mesh != 0 ) {
1637  if ( !loadMesh(in,_mesh,dataset) ) {
1638  emit log(LOGERR,"Unable to load mesh!");
1639  return -1;
1640  }
1641  } else {
1642  emit log(LOGERR,"Unable to add empty triangle mesh!");
1643  return -1;
1644  }
1645 
1646  baseObj = object;
1647  }
1648 
1649  }
1650  // If no type can represent the object in the file just use PolyMesh
1651  // and load as much as possible
1652  else if ((bestType == BMT_PolyMesh) || (bestType == BMT_None))
1653  {
1654 
1655  int id = -1;
1656  emit addEmptyObject(DATA_POLY_MESH, id);
1657 
1658 
1659  PolyMeshObject* object(0);
1660 
1661  if(PluginFunctions::getObject( id, object)){
1662 
1663  PolyMesh* _mesh(0);
1664  PluginFunctions::getMesh(id, _mesh);
1665 
1666  if ( _mesh != 0 ) {
1667  if ( !loadMesh(in,_mesh,dataset) ) {
1668  emit log(LOGERR,"Unable to load mesh!");
1669  return -1;
1670  }
1671  } else {
1672  emit log(LOGERR,"Unable to add empty poly mesh!");
1673  return -1;
1674  }
1675 
1676  baseObj = object;
1677 
1678  }
1679 
1680 
1681  }
1682 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
1683  else if (bestType == BMT_PolyhedralMesh)
1684  {
1685  // add a Polyhedral mesh
1686  is_OpenVolumeMesh = true;
1687  int id = -1;
1688  emit addEmptyObject(DATA_POLYHEDRAL_MESH, id);
1689 
1690  PolyhedralMeshObject* object(0);
1691 
1692  if(PluginFunctions::getObject( id, object)){
1693 
1694  PolyhedralMesh* _mesh;
1695  _mesh = PluginFunctions::polyhedralMesh(object);
1696 
1697  if ( _mesh != 0 ) {
1698  if ( !loadMesh(in,_mesh,dataset) ) {
1699  emit log(LOGERR,"Unable to load mesh!");
1700  return -1;
1701  }
1702  } else {
1703  emit log(LOGERR,"Unable to add empty polyhedral mesh!");
1704  return -1;
1705  }
1706 
1707  baseObj = object;
1708  }
1709 
1710  }
1711 #endif //ENABLE_POLYHEDRALMESH_SUPPORT
1712 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
1713  else if (bestType == BMT_HexahedralMesh)
1714  {
1715  // add a hexahedral mesh
1716  is_OpenVolumeMesh = true;
1717  int id = -1;
1718  emit addEmptyObject(DATA_HEXAHEDRAL_MESH, id);
1719 
1720  HexahedralMeshObject* object(0);
1721 
1722  if(PluginFunctions::getObject( id, object)){
1723 
1724  HexahedralMesh* _mesh;
1725  _mesh = PluginFunctions::hexahedralMesh(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 hexahedral mesh!");
1734  return -1;
1735  }
1736  baseObj = object;
1737  }
1738 
1739  }
1740 #endif //ENABLE_HEXAHEDRALMESH_SUPPORT
1741 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
1742  else if (bestType == BMT_TetrahedralMesh)
1743  {
1744  // add a tetrahedral mesh
1745  is_OpenVolumeMesh = true;
1746  int id = -1;
1747  emit addEmptyObject(DATA_TETRAHEDRAL_MESH, id);
1748 
1749  TetrahedralMeshObject* object(0);
1750 
1751  if(PluginFunctions::getObject( id, object)){
1752 
1753  TetrahedralMesh* _mesh;
1754  _mesh = PluginFunctions::tetrahedralMesh(object);
1755 
1756  if ( _mesh != 0 ) {
1757  if ( !loadMesh(in,_mesh,dataset) ) {
1758  emit log(LOGERR,"Unable to load mesh!");
1759  return -1;
1760  }
1761  } else {
1762  emit log(LOGERR,"Unable to add empty tetrahedral mesh!");
1763  return -1;
1764  }
1765  baseObj = object;
1766  }
1767 
1768  }
1769 #endif //ENABLE_TETRAHEDRALMESH_SUPPORT
1770 
1771  if (baseObj)
1772  {
1773  baseObj->setFromFileName(_filename);
1774  baseObj->setName(baseObj->filename());
1775 
1776  if (is_OpenVolumeMesh)
1777  {
1778  // Go into solid flat shaded mode
1779  baseObj->setObjectDrawMode(ACG::SceneGraph::DrawModes::getDrawMode("Cells (flat shaded)"));
1780  }
1781 
1782  emit updatedObject(baseObj->id(), UPDATE_ALL);
1783 
1784  //general stuff
1785  emit openedFile( baseObj->id() );
1786 
1787  return baseObj->id();
1788  }
1789 
1790  emit log(LOGERR,tr("Error in load mesh!"));
1791 
1792  return -1;
1793 
1794 
1795 }
1796 
1797 template <typename MeshT>
1798 bool FileVTKPlugin::loadMeshPoints(QString _spec, QTextStream& _in,MeshT*& _mesh){
1799 
1800  std::cerr << "loadMeshPoints" << std::endl;
1801 
1802  bool ok = true;
1803 
1804  // Split the header line into components
1805 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1806  QStringList pointsLine = _spec.split(" ",QString::SkipEmptyParts);
1807 #else
1808  QStringList pointsLine = _spec.split(" ",Qt::SkipEmptyParts);
1809 #endif
1810 
1811 
1812  // It has to contain the Keyword POINTS , the number of points to read and the datatype of the points
1813  if ( pointsLine.size() != 3 ) {
1814  emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(pointsLine.size()));
1815  return false;
1816  }
1817 
1818  // Get the number of points to read
1819  quint32 points = pointsLine[1].toUInt(&ok);
1820 
1821  if ( ! ok) {
1822  emit log(LOGERR,tr("Expected to get number of points, but read %1 !").arg(pointsLine[1]));
1823  return false;
1824  }
1825 
1826  // In OpenMesh we use doubles for the point representation
1827  OpenMesh::Vec3d vec;
1828 
1829  quint32 read = 0;
1830  while ( read < points ) {
1831 
1832 
1833  if ( binary_ ) {
1834 
1835  // Read binary float values
1836  if ( pointsLine[2] == "float" ) {
1837  // Read floats
1838  OpenMesh::Vec3f vecf;
1839  _in.device()->read((char*)&vecf[0],sizeof(float));
1840  _in.device()->read((char*)&vecf[1],sizeof(float));
1841  _in.device()->read((char*)&vecf[2],sizeof(float));
1842 
1843  // convert
1844  vec = vecf;
1845  } else {
1846  emit log(LOGERR,tr("Not implemented data type %1 !").arg(pointsLine[2]));
1847  return false;
1848  }
1849 
1850  } else {
1851  // Don't care about original type, as we read text and convert it anyway.
1852  _in >> vec[0] >> vec[1] >> vec[2];
1853  }
1854 
1855  // Next point to read
1856  ++read;
1857 
1858  // Check if the stream is still ok
1859  if ( _in.status() == QTextStream::Ok ) {
1860  _mesh->add_vertex(vec);
1861  } else {
1862  emit log(LOGERR,tr("Read corrupted point data!"));
1863  return false;
1864  }
1865 
1866  }
1867 
1868  if (binary_) {
1869  if ( pointsLine[2] == "float" ) {
1870  // Reposition text stream. We read points * 3 * sizeof(float)
1871  // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
1872  _in.seek(_in.pos() + read * 3 * sizeof(float) / sizeof(char) );
1873  }
1874  }
1875 
1876  return true;
1877 
1878 }
1879 
1880 template <typename MeshT>
1881 bool FileVTKPlugin::loadMeshLines(QString _spec,QTextStream& _in,MeshT*& _mesh) {
1882  std::cerr << "loadMeshLines" << std::endl;
1883 
1884  bool ok = true;
1885 
1886  // Split the header line into components
1887 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1888  QStringList linesLine = _spec.split(" ",QString::SkipEmptyParts);
1889 #else
1890  QStringList linesLine = _spec.split(" ",Qt::SkipEmptyParts);
1891 #endif
1892 
1893 
1894  // 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 )
1895  if ( linesLine.size() != 3 ) {
1896  emit log(LOGERR,tr("Expected to get LINES line with exactly 3 entries, but %1 found!").arg(linesLine.size()));
1897  return false;
1898  }
1899 
1900  // umber of lines to read
1901  quint32 linecount = linesLine[1].toUInt(&ok);
1902 
1903  // number of ints in the whole line description!
1904  quint32 entrycount = linesLine[2].toUInt(&ok);
1905 
1906  if ( ! ok) {
1907  emit log(LOGERR,tr("Expected to get number of lines and entries, but read %1 !").arg(linesLine.join(" ")));
1908  return false;
1909  }
1910 
1911  quint32 read = 0;
1912 
1913  while ( read < linecount) {
1914 
1915  // Read first integer describing number of indizes in the current line
1916  quint32 valence;
1917 
1918  if ( !binary_ )
1919  _in >> valence;
1920  else
1921  _in.device()->read((char*)&valence,sizeof(quint32));
1922 
1923 
1924  quint32 index;
1925 
1926  if ( _in.status() == QTextStream::Ok ) {
1927 
1928  if ( !binary_ ) {
1929  for ( unsigned int i = 0 ; i < valence; ++i )
1930  _in >> index;
1931  } else {
1932  for ( unsigned int i = 0 ; i < valence; ++i )
1933  _in.device()->read((char*)&valence,sizeof(quint32));
1934  }
1935 
1936  if ( _in.status() == QTextStream::Ok ) {
1937  // TODO : Generate lines here!
1938 
1939  //_mesh->add_edge(handles);
1940  } else {
1941  emit log(LOGERR,tr("Read corrupted face data!"));
1942  return false;
1943  }
1944 
1945  } else {
1946  emit log(LOGERR,tr("Read corrupted POLYGONS data!"));
1947  return false;
1948  }
1949 
1950  ++read;
1951  }
1952 
1953  if ( binary_ ) {
1954  // Reposition text stream. We read entrycount * sizeof(quint32) .
1955  // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
1956  _in.seek(_in.pos() + entrycount * sizeof(quint32) / sizeof(char) );
1957  }
1958 
1959  emit log(LOGWARN,tr("Lines not supported yet ... skipped!"));
1960 
1961  return true;
1962 }
1963 
1964 template <typename MeshT>
1965 bool FileVTKPlugin::loadMeshPolygons(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
1966  std::cerr << "loadMeshPolygons" << std::endl;
1967 
1968  bool ok = true;
1969 
1970  // Split the header line into components
1971 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1972  QStringList polygonsLine = _spec.split(" ",QString::SkipEmptyParts);
1973 #else
1974  QStringList polygonsLine = _spec.split(" ",Qt::SkipEmptyParts);
1975 #endif
1976 
1977 
1978  // 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 )
1979  if ( polygonsLine.size() != 3 ) {
1980  emit log(LOGERR,tr("Expected to get Points line with exactly 3 entries, but %1 found!").arg(polygonsLine.size()));
1981  return false;
1982  }
1983 
1984  // Number of polygons to read
1985  quint32 polygoncount = polygonsLine[1].toUInt(&ok);
1986 
1987  // number of ints in the whole polygon description
1988  quint32 entrycount = polygonsLine[2].toUInt(&ok);
1989 
1990  if ( ! ok) {
1991  emit log(LOGERR,tr("Expected to get number of points and entries, but read %1 !").arg(polygonsLine.join(" ")));
1992  return false;
1993  }
1994 
1995  // Disable OpenMesh error logging
1996  bool errorEnabled = omerr().is_enabled();
1997  omerr().disable();
1998 
1999  quint32 read = 0;
2000  while ( read < polygoncount) {
2001 
2002  // Read first integer describing number of indices
2003  quint32 valence;
2004  if ( !binary_ )
2005  _in >> valence;
2006  else
2007  _in.device()->read((char*)&valence,sizeof(quint32));
2008 
2009 
2010  quint32 index;
2011  std::vector< quint32 > indices;
2012 
2013  for ( unsigned int i = 0 ; i < valence; ++i ) {
2014 
2015  // Read one index
2016  if ( !binary_ )
2017  _in >> index;
2018  else
2019  _in.device()->read((char*)&valence,sizeof(quint32));
2020 
2021  // Remember it
2022  indices.push_back( index );
2023  }
2024 
2025  if ( _in.status() == QTextStream::Ok ) {
2026 
2027  //check, if there exists duplicate vertices inside of the face
2028  remove_duplicated_vertices(indices);
2029 
2030  if (indices.size() >= 3)
2031  {
2032  CellType cell;
2033  cell.type = 7; // VTK_POLYGON
2034  cell.indices = indices;
2035  cell.index = addFace(_mesh, indices);
2036  _cells.push_back(cell);
2037  }
2038  } else {
2039  emit log(LOGERR,tr("Read corrupted face data!"));
2040 
2041  // Restore error logging state before returning
2042  if ( errorEnabled )
2043  omerr().enable();
2044 
2045  return false;
2046  }
2047  ++read;
2048  }
2049 
2050  // Restore error logging state.
2051  if ( errorEnabled )
2052  omerr().enable();
2053 
2054  if (binary_) {
2055  // Reposition text stream. We read entrycount * sizeof(qint32)
2056  // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
2057  _in.seek(_in.pos() + entrycount * sizeof(qint32) / sizeof(char) );
2058  }
2059 
2060  return true;
2061 }
2062 
2063 template <typename MeshT>
2064 int FileVTKPlugin::add_non_manifold_face(MeshT*& _mesh, std::vector< OpenMesh::VertexHandle >& _vhandles) {
2065 
2066  // Duplicate vertices of non-manifold faces
2067  // and add them as new isolated face
2068  if (_vhandles.empty()) return -1;
2069 
2071  if (! _mesh->get_property_handle(originalVertexIdx,"FileVTKPlugin_originalVertexIdx")) {
2072  _mesh->add_property( originalVertexIdx, "FileVTKPlugin_originalVertexIdx" );
2073 
2074  //mark all vertices
2075  typename MeshT::VertexIter vit = _mesh->vertices_begin();
2076  typename MeshT::VertexIter vend = _mesh->vertices_end();
2077  for(; vit != vend; ++vit) {
2078  _mesh->property (originalVertexIdx, *vit) = OpenMesh::VertexHandle(-1);
2079  }
2080  }
2081 
2082  // double vertices
2083  for (unsigned int j = 0; j < _vhandles.size(); ++j)
2084  {
2085  typename MeshT::Point p = _mesh->point(_vhandles[j]);
2086  OpenMesh::VertexHandle original_handle = _vhandles[j];
2087  _vhandles[j] = _mesh->add_vertex(p);
2088  // DO STORE p, reference may not work since vertex array
2089  // may be relocated after adding a new vertex !
2090 
2091  // Mark vertices of failed face as non-manifold
2092  if (_mesh->has_vertex_status()) {
2093  _mesh->status(_vhandles[j]).set_fixed_nonmanifold(true);
2094  }
2095  // To assign other properties to this vertex later, save its "original" in property
2096  _mesh->property (originalVertexIdx, _vhandles[j]) = original_handle;
2097  }
2098 
2099  // add face
2100  OpenMesh::FaceHandle fh = _mesh->add_face(_vhandles);
2101 
2102  // Mark failed face as non-manifold
2103  if (_mesh->has_face_status())
2104  _mesh->status(fh).set_fixed_nonmanifold(true);
2105 
2106  // Mark edges of failed face as non-two-manifold
2107  if (_mesh->has_edge_status()) {
2108  typename MeshT::FaceEdgeIter fe_it = _mesh->fe_iter(fh);
2109  for (; fe_it.is_valid(); ++fe_it) {
2110  _mesh->status(*fe_it).set_fixed_nonmanifold(true);
2111  }
2112  }
2113 
2114  return fh.idx();
2115 }
2116 
2117 
2118 template <typename MeshT>
2119 bool FileVTKPlugin::loadMeshTriangleStrips(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
2120  std::cerr << "loadMeshTriangleStrips" << std::endl;
2121 
2122  bool ok = true;
2123 
2124  // Split the header line into components
2125 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2126  QStringList triStripsLine = _spec.split(" ",QString::SkipEmptyParts);
2127 #else
2128  QStringList triStripsLine = _spec.split(" ",Qt::SkipEmptyParts);
2129 #endif
2130 
2131 
2132  // 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 )
2133  if ( triStripsLine.size() != 3 ) {
2134  emit log(LOGERR,tr("Expected to get TRIANGLE_STRIPS line with exactly 3 entries, but %1 found!").arg(triStripsLine.size()));
2135  return false;
2136  }
2137 
2138  // Number of polygons to read
2139  quint32 stripcount = triStripsLine[1].toUInt(&ok);
2140 
2141  // number of ints in the whole polygon description
2142  quint32 entrycount = triStripsLine[2].toUInt(&ok);
2143 
2144  if ( ! ok) {
2145  emit log(LOGERR,tr("Expected to get number of strips and entries, but read %1 !").arg(triStripsLine.join(" ")));
2146  return false;
2147  }
2148 
2149  quint32 read = 0;
2150  while ( read < stripcount) {
2151 
2152  // Read first integer describing number of indizes in the strip
2153  quint32 valence;
2154  if ( !binary_ )
2155  _in >> valence;
2156  else
2157  _in.device()->read((char*)&valence,sizeof(quint32));
2158 
2159 
2160  quint32 index;
2161  QList< quint32 > indices;
2162 
2163  // Read first two of strip:
2164  for ( unsigned int i = 0 ; i < 2; ++i ) {
2165 
2166  // Read one index
2167  if ( !binary_ )
2168  _in >> index;
2169  else
2170  _in.device()->read((char*)&valence,sizeof(quint32));
2171 
2172  // Remember it
2173  indices.push_back( index );
2174  }
2175 
2176  // Read rest of strip while adding faces
2177  for ( unsigned int i = 2 ; i < valence; ++i ) {
2178 
2179  // Read one index
2180  if ( !binary_ )
2181  _in >> index;
2182  else
2183  _in.device()->read((char*)&valence,sizeof(quint32));
2184 
2185  // Remember it
2186  indices.push_back( index );
2187 
2188  if ( _in.status() == QTextStream::Ok ) {
2189  // TODO : handle non manifold cases!
2190  CellType cell;
2191  cell.type = 6; //VTK_TRIANGLE_STRIP
2192  cell.indices.resize(3);
2193  cell.indices[0] = indices[i];
2194  cell.indices[1] = indices[i-1];
2195  cell.indices[2] = indices[i-2];
2196  if ( i % 2 != 0 )
2197  std::swap(cell.indices[1],cell.indices[2]);
2198  cell.index = addFace(_mesh, cell.indices);
2199  _cells.push_back(cell);
2200  } else {
2201  emit log(LOGERR,tr("Read corrupted face data!"));
2202  return false;
2203  }
2204 
2205 
2206  }
2207 
2208  ++read;
2209  }
2210 
2211 
2212  if (binary_) {
2213  // Reposition text stream. We read entrycount * sizeof(qint32)
2214  // For the text stream we calculate the position in charactersso convert it witth 1.0 / sizeof(char)
2215  _in.seek(_in.pos() + entrycount * sizeof(qint32) / sizeof(char) );
2216  }
2217 
2218  return true;
2219 }
2220 
2221 template <typename MeshT>
2222 bool FileVTKPlugin::loadMeshNormals(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells, bool _pointNormal, quint32 _count) {
2223  std::cerr << "loadMeshNormals" << std::endl;
2224 
2225  // Split the header line into components
2226 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2227  QStringList normalsLine = _spec.split(" ",QString::SkipEmptyParts);
2228 #else
2229  QStringList normalsLine = _spec.split(" ",Qt::SkipEmptyParts);
2230 #endif
2231 
2232 
2233 
2234  // It has to contain the Keyword NORMALS , the name of the dataset and the datatype
2235  if ( normalsLine.size() != 3 ) {
2236  emit log(LOGERR,tr("Expected to get NORMALS line with exactly 3 entries, but %1 found!").arg(normalsLine.size()));
2237  return false;
2238  }
2239 
2240  // In OpenMesh we use doubles for the normal representation
2241  OpenMesh::Vec3d normal;
2242 
2243  quint32 read = 0;
2244  while ( read < _count) {
2245 
2246  if ( binary_ ) {
2247 
2248  // Read binary float values
2249  if ( normalsLine[2] == "float" ) {
2250 
2251  // Read floats
2252  OpenMesh::Vec3f vecf;
2253  _in.device()->read((char*)&vecf[0],sizeof(float));
2254  _in.device()->read((char*)&vecf[1],sizeof(float));
2255  _in.device()->read((char*)&vecf[2],sizeof(float));
2256 
2257  // convert
2258  normal = vecf;
2259  } else {
2260  emit log(LOGERR,tr("Not implemented data type %1 !").arg(normalsLine[2]));
2261  return false;
2262  }
2263 
2264  } else {
2265  // Don't care about original type, as we read text and convert it anyway.
2266  _in >> normal[0] >> normal[1] >> normal[2];
2267  }
2268 
2269  // Check if the stream is still ok
2270  if ( _in.status() == QTextStream::Ok ) {
2271 
2272  if ( _pointNormal ) {
2273  addVertexNormal(_mesh, read, normal);
2274 
2275  } else {
2276  addCellNormal(_mesh, _cells[read], normal);
2277  }
2278 
2279  } else {
2280  emit log(LOGERR,tr("Read corrupted point data!"));
2281  return false;
2282  }
2283 
2284  // Next normal to read
2285  ++read;
2286  }
2287 
2288  if (binary_) {
2289  if ( normalsLine[2] == "float" ) {
2290  // Reposition text stream. We read points * 3 * sizeof(float)
2291  // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2292  _in.seek(_in.pos() + read * 3 * sizeof(float) / sizeof(char) );
2293  }
2294  }
2295 
2297 
2298 
2299  return true;
2300 }
2301 
2302 template <typename MeshT>
2303 bool FileVTKPlugin::loadMeshCells(QString _spec,QTextStream& _in,MeshT*& _mesh, std::vector<CellType>& _cells) {
2304 
2305  std::cerr << "loadMeshCells" << std::endl;
2306 
2307  // Split the header line into components
2308 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2309  QStringList cellLine = _spec.split(" ",QString::SkipEmptyParts);
2310 #else
2311  QStringList cellLine = _spec.split(" ",Qt::SkipEmptyParts);
2312 #endif
2313 
2314 
2315  // 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 )
2316  if ( cellLine.size() != 3 ) {
2317  emit log(LOGERR,tr("Expected to get CELLS line with exactly 3 entries, but %1 found!").arg(cellLine.size()));
2318  return false;
2319  }
2320 
2321  bool ok = true;
2322 
2323  // Number of cells to read
2324  quint32 cellCount = cellLine[1].toUInt(&ok);
2325 
2326  // number of ints in the whole cell description
2327  quint32 entryCount = cellLine[2].toUInt(&ok);
2328 
2329 
2330  if ( ! ok) {
2331  emit log(LOGERR,tr("Expected to get number of cells and entries, but read %1 !").arg(cellLine.join(" ")));
2332  return false;
2333  }
2334 
2335  quint32 read = 0;
2336  while ( read < cellCount) {
2337 
2338  CellType currentCell;
2339 
2340  // Read first integer describing number of indizes
2341  quint32 valence;
2342  if ( !binary_ )
2343  _in >> valence;
2344  else
2345  _in.device()->read((char*)&valence,sizeof(quint32));
2346 
2347 
2348  quint32 index;
2349 
2350  for ( unsigned int i = 0 ; i < valence; ++i ) {
2351 
2352  // Read one index
2353  if ( !binary_ )
2354  _in >> index;
2355  else
2356  _in.device()->read((char*)&valence,sizeof(quint32));
2357 
2358  // Remember it
2359  currentCell.indices.push_back( index );
2360  }
2361 
2362  if ( _in.status() == QTextStream::Ok ) {
2363  _cells.push_back(currentCell);
2364  } else {
2365  emit log(LOGERR,tr("Read corrupted face data!"));
2366  return false;
2367  }
2368  ++read;
2369 
2370  }
2371 
2372  if (binary_) {
2373  // Reposition text stream. We read entryCount * sizeof(quint32)
2374  // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2375  _in.seek(_in.pos() + entryCount * sizeof(quint32) / sizeof(char) );
2376  }
2377 
2378 
2379  //=================================================================================
2380  //=================================================================================
2381  // Read the cell types now
2382  //=================================================================================
2383  //=================================================================================
2384  _spec ="";
2385 
2386  // Read lines until we get something usefull
2387  while ( _spec.simplified().size() == 0 ) {
2388 
2389  // stop at end of file!
2390  if ( _in.atEnd() ) {
2391  emit log(LOGERR,tr("File end when reading cell specification!"));
2392  return false;
2393  }
2394 
2395  _spec = _in.readLine();
2396  }
2397 
2398  if ( ! _spec.contains("CELL_TYPES") ) {
2399  emit log(LOGERR,tr("Wrong token! Expected CELL_TYPES but got : %1").arg(_spec));
2400  return false;
2401  }
2402 
2403  // Split the header line into components
2404 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2405  cellLine = _spec.split(" ",QString::SkipEmptyParts);
2406 #else
2407  cellLine = _spec.split(" ",Qt::SkipEmptyParts);
2408 #endif
2409 
2410 
2411  // It has to contain the Keyword CELL_TYPES , the number of cells to read
2412  if ( cellLine.size() != 2 ) {
2413  emit log(LOGERR,tr("Expected to get CELL_TYPES line with exactly 2 entries, but %1 found!").arg(cellLine.size()));
2414  return false;
2415  }
2416 
2417  // Number of cells to read
2418  quint32 cellCountTypes = cellLine[1].toUInt(&ok);
2419 
2420  if ( ! ok) {
2421  emit log(LOGERR,tr("Expected to get number of cell types, but read %1 !").arg(cellLine[1]));
2422  return false;
2423  }
2424 
2425  if (cellCountTypes != cellCount ) {
2426  emit log(LOGERR,tr("cellCountTypes != cellCount !").arg(cellLine.size()));
2427  return false;
2428  }
2429 
2430  read = 0;
2431  while ( read < cellCount) {
2432 
2433  // Read first integer describing number of indizes
2434  quint32 type;
2435  if ( !binary_ )
2436  _in >> type;
2437  else
2438  _in.device()->read((char*)&type,sizeof(quint32));
2439 
2440 
2441  // Remember it
2442  _cells[read].type = type;
2443 
2444  if ( _in.status() != QTextStream::Ok ) {
2445  emit log(LOGERR,tr("Read corrupted cell type data!"));
2446  return false;
2447  }
2448  ++read;
2449  }
2450 
2451  if (binary_) {
2452  // Reposition text stream. We read cells * sizeof(quint32)
2453  // For the text stream we calculate the position in charactersso convert it with 1.0 / sizeof(char)
2454  _in.seek(_in.pos() + read * sizeof(quint32) / sizeof(char) );
2455  }
2456 
2457  //=================================================================================
2458  //=================================================================================
2459  // Now add the cells
2460  //=================================================================================
2461  //=================================================================================
2462  for ( unsigned int i = 0 ; i < _cells.size() ; ++i ) {
2463  if ( _cells[i].type == 1 ) {
2464 
2465  //VERTEX
2466  // Nothing to do for meshes ... already added as vertex
2467 
2468  } else if ( _cells[i].type == 2 ) {
2469 
2470  //POLY_VERTEX
2471  // Nothing to do for meshes ... already added as vertex
2472 
2473  } else if ( _cells[i].type == 3 ) {
2474 
2475  //LINE
2476  emit log(LOGWARN,tr("Unsupported Cell Type LINE") );
2477 
2478  } else if ( _cells[i].type == 4 ) {
2479  //POLY_LINE
2480 
2481  emit log(LOGWARN,tr("Unsupported Cell Type POLY_LINE") );
2482 
2483  } else if ( _cells[i].type == 5 ) {
2484  //TRIANGLE
2485  _cells[i].index = addFace(_mesh, _cells[i].indices);
2486  } else if ( _cells[i].type == 6 ) {
2487  //TRIANGLE_STRIP
2488 
2489  for ( unsigned int j = 2 ; j < _cells[i].indices.size() ; ++j) {
2490  if ( (j % 2) == 0 )
2491  _cells[i].index = addFace(_mesh, _cells[i].indices[j-2],_cells[i].indices[j],_cells[i].indices[j-1]);
2492  else
2493  _cells[i].index = addFace(_mesh, _cells[i].indices[j-2],_cells[i].indices[j-1],_cells[i].indices[j]);
2494  }
2495 
2496  //TODO : handle non manifold cases!
2497 
2498  } else if ( _cells[i].type == 7 ) {
2499  //POLYGON
2500 
2501  _cells[i].index = addFace(_mesh, _cells[i].indices);
2502 
2503  } else if ( _cells[i].type == 8 ) {
2504  //PIXEL
2505 
2506  emit log(LOGWARN,tr("Unsupported Cell Type PIXEL") );
2507 
2508  } else if ( _cells[i].type == 9 ) {
2509  //QUAD
2510 
2511  _cells[i].index = addFace(_mesh, _cells[i].indices);
2512 
2513  } else if ( _cells[i].type == 10 ) {
2514  //Tetra
2515  _cells[i].index = addTetraCell(_mesh, _cells[i].indices);
2516 
2517  } else if ( _cells[i].type == 11 ) {
2518  //VOXEL
2519 
2520  emit log(LOGWARN,tr("Unsupported Cell Type VOXEL") );
2521 
2522  } else if ( _cells[i].type == 12 ) {
2523  //HEXAHEDRON
2524 
2525  _cells[i].index = addHexaCell(_mesh, _cells[i].indices);
2526  } else if ( _cells[i].type == 13 ) {
2527  //WEDGE
2528 
2529  _cells[i].index = addWedgeCell(_mesh, _cells[i].indices);
2530  } else if ( _cells[i].type == 14 ) {
2531  //PYRAMID
2532 
2533  _cells[i].index = addPyramidCell(_mesh, _cells[i].indices);
2534 
2535  } else {
2536  emit log(LOGERR,tr("Unknown cell type").arg(_cells[i].type) );
2537  }
2538  }
2539 
2540  std::cerr << "Read " << read << " Cells " << std::endl;
2541  std::cerr << "Vector has size: " << _cells.size() << std::endl;
2542 
2543 
2544  return true;
2545 }
2546 
2547 template <typename MeshT>
2548 bool FileVTKPlugin::loadMesh(QTextStream& _in,MeshT*& _mesh, Dataset _type){
2549 
2550 
2551  if ( _type != POLYDATA && _type != UNSTRUCTURED_GRID ) {
2552  emit log(LOGERR,"Unsupported DATASET" );
2553  return false;
2554  }
2555 
2556  QString line = "";
2557 
2558  bool ok = true;
2559 
2560  // Flag if normals have been read from files
2561  bool pointNormalsRead = false;
2562  bool faceNormalsRead = false;
2563 
2564  // flag if we are in Point data mode
2565  bool pointData = false;
2566 
2567  // Size of the point data
2568  quint32 pointDataSize = 0;
2569 
2570  // flag if we are in cell data mode
2571  bool cellData = false;
2572 
2573  // Size of the cell data
2574  quint32 cellDataSize = 0;
2575 
2576  std::vector<CellType> cells;
2577 
2578  while (ok) {
2579 
2580  line = _in.readLine();
2581 
2582  // Read lines until we get something usefull
2583  while ( line.simplified().size() == 0 ) {
2584 
2585  // stop at end of file!
2586  if ( _in.atEnd() ) {
2587  ok = false;
2588  std::cerr << "atEnd" << std::endl;
2589  break;
2590  }
2591 
2592  line = _in.readLine();
2593  }
2594 
2595  // Stop if something is wrong or we are at the end of the file
2596  if ( !ok )
2597  break;
2598 
2599  std::cerr << "Line is: " << line.toStdString() << std::endl;
2600 
2601  // if we got a points token:
2602  if ( line.contains("POINTS") ) {
2603 
2604  ok = loadMeshPoints(line,_in,_mesh);
2605  } else if ( line.contains("POINT_DATA") ) {
2606 
2607  // Split the header line into components
2608 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2609  QStringList pointDataLine = line.split(" ",QString::SkipEmptyParts);
2610 #else
2611  QStringList pointDataLine = line.split(" ",Qt::SkipEmptyParts);
2612 #endif
2613 
2614 
2615  // It has to contain the Keyword POINT_DATA , and the number of datasets
2616  if ( pointDataLine.size() != 2 ) {
2617  emit log(LOGERR,tr("Expected to get POINT_DATA line with exactly 2 entries, but %1 found!").arg(line.size()));
2618  return false;
2619  }
2620 
2621  // Number of polygons to read
2622  pointDataSize = pointDataLine[1].toUInt(&ok);
2623 
2624  pointData = true;
2625  cellData = false;
2626 
2627  std::cerr << "Point data mode with " << pointDataSize << "Elements" << std::endl;
2628 
2629  } else if ( line.contains("CELL_DATA") ) {
2630 
2631  // Split the header line into components
2632 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2633  QStringList cellDataLine = line.split(" ",QString::SkipEmptyParts);
2634 #else
2635  QStringList cellDataLine = line.split(" ",Qt::SkipEmptyParts);
2636 #endif
2637 
2638  // It has to contain the Keyword CELL_DATA , and the number of datasets
2639  if ( cellDataLine.size() != 2 ) {
2640  emit log(LOGERR,tr("Expected to get CELL_DATA line with exactly 2 entries, but %1 found!").arg(line.size()));
2641  return false;
2642  }
2643 
2644  // Number of polygons to read
2645  cellDataSize = cellDataLine[1].toUInt(&ok);
2646 
2647  cellData = true;
2648  pointData = false;
2649 
2650  std::cerr << "Cell data mode with " << cellDataSize << "Elements" << std::endl;
2651 
2652  } else if ( line.contains("VERTICES") ) {
2653  std::cerr << "Vertices will be skipped as they are already added!" << std::endl;
2654  } else if ( line.contains("LINES") ) {
2655  ok = loadMeshLines(line,_in,_mesh);
2656  } else if ( line.contains("POLYGONS") ) {
2657  ok = loadMeshPolygons(line,_in,_mesh, cells);
2658  } else if ( line.contains("TRIANGLE_STRIPS") ) {
2659  ok = loadMeshTriangleStrips(line,_in,_mesh, cells);
2660  } else if ( line.contains("CELL") ) {
2661  ok = loadMeshCells(line,_in,_mesh, cells);
2662  } else if ( line.contains("NORMALS") ) {
2663  // load per point normals or per face normals
2664  if ( pointData ) {
2665  ok = loadMeshNormals(line,_in,_mesh,cells,true,pointDataSize);
2666  pointNormalsRead = true;
2667  } else if (cellData) {
2668  ok = loadMeshNormals(line,_in,_mesh,cells,false,cellDataSize);
2669  faceNormalsRead = true;
2670  } else {
2671  emit log(LOGERR,tr("Got normals keyword but we are neither in pointdata nor celldata mode") );
2672  return false;
2673  }
2674 
2675  } else {
2676  std::cerr << "Unrecognized keyword : " << line.toStdString() << std::endl;
2677  }
2678 
2679  }
2680 
2681  if ( !faceNormalsRead )
2682  updateFaceNormals(_mesh);
2683 
2684  if ( !pointNormalsRead )
2685  updateVertexNormals(_mesh);
2686 
2688 
2689  return true;
2690 }
2691 
2692 //-----------------------------------------------------------------------------------------------------
2693 
2695 int FileVTKPlugin::loadObject(QString _filename, DataType _type){
2696 
2697  if ( _type == DATA_TRIANGLE_MESH )
2698  forceTriangleMesh_ = true;
2699  else if ( _type == DATA_POLY_MESH )
2700  forcePolyMesh_ = true;
2701 
2702  return loadObject(_filename);
2703 }
2704 
2705 //-----------------------------------------------------------------------------------------------------
2706 
2707 bool FileVTKPlugin::saveObject(int _id, QString _filename) {
2708 
2709  BaseObjectData* object;
2710  if ( !PluginFunctions::getObject(_id,object) ) {
2711  emit log(LOGERR, tr("saveObject : cannot get object id %1 for save name %2").arg(_id).arg(_filename) );
2712  return false;
2713  }
2714 
2715  std::string filename = std::string( _filename.toUtf8() );
2716 
2717  std::fstream ofs( filename.c_str(), std::ios_base::out );
2718 
2719  if (!ofs) {
2720 
2721  emit log(LOGERR, tr("saveObject : Cannot not open file %1 for writing!").arg(_filename) );
2722  return false;
2723  }
2724 
2725  // Get user specified options
2727 
2728  if ( object->dataType( DATA_POLY_MESH ) ) {
2729 
2730  object->setFromFileName(_filename);
2731  object->setName(object->filename());
2732 
2733  PolyMeshObject* polyObj = dynamic_cast<PolyMeshObject* >( object );
2734 
2735  if (writeMesh(ofs, *polyObj->mesh())){
2736  emit log(LOGINFO, tr("Saved object to ") + _filename );
2737  ofs.close();
2738  return true;
2739  }else{
2740  emit log(LOGERR, tr("Unable to save ") + _filename);
2741  ofs.close();
2742  return false;
2743  }
2744  } else if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
2745 
2746  object->setFromFileName(_filename);
2747  object->setName(object->filename());
2748 
2749  TriMeshObject* triObj = dynamic_cast<TriMeshObject* >( object );
2750 
2751  if (writeMesh(ofs, *triObj->mesh())) {
2752  emit log(LOGINFO, tr("Saved object to ") + _filename );
2753  ofs.close();
2754  return true;
2755  } else {
2756  emit log(LOGERR, tr("Unable to save ") + _filename);
2757  ofs.close();
2758  return false;
2759  }
2760  }
2761 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
2762  else if ( object->dataType( DATA_POLYHEDRAL_MESH ) )
2763  {
2764 
2765  object->setFromFileName(_filename);
2766  object->setName(object->filename());
2767 
2768  PolyhedralMeshObject* polyhedralObj = dynamic_cast<PolyhedralMeshObject* >( object );
2769 
2770  if (writeMesh(ofs, *polyhedralObj->mesh())) {
2771  emit log(LOGINFO, tr("Saved object to ") + _filename );
2772  ofs.close();
2773  return true;
2774  } else {
2775  emit log(LOGERR, tr("Unable to save ") + _filename);
2776  ofs.close();
2777  return false;
2778  }
2779  }
2780 #endif
2781 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
2782  else if ( object->dataType( DATA_HEXAHEDRAL_MESH ) )
2783  {
2784 
2785  object->setFromFileName(_filename);
2786  object->setName(object->filename());
2787 
2788  HexahedralMeshObject* hexahedralObj = dynamic_cast<HexahedralMeshObject* >( object );
2789 
2790  if (writeMesh(ofs, *hexahedralObj->mesh())) {
2791  emit log(LOGINFO, tr("Saved object to ") + _filename );
2792  ofs.close();
2793  return true;
2794  } else {
2795  emit log(LOGERR, tr("Unable to save ") + _filename);
2796  ofs.close();
2797  return false;
2798  }
2799  }
2800 #endif
2801 #ifdef ENABLE_TETRAHEDRALMESH_SUPPORT
2802  else if ( object->dataType( DATA_TETRAHEDRAL_MESH ) )
2803  {
2804 
2805  object->setFromFileName(_filename);
2806  object->setName(object->filename());
2807 
2808  TetrahedralMeshObject* tetrahedralObj = dynamic_cast<TetrahedralMeshObject* >( object );
2809 
2810  if (writeMesh(ofs, *tetrahedralObj->mesh())) {
2811  emit log(LOGINFO, tr("Saved object to ") + _filename );
2812  ofs.close();
2813  return true;
2814  } else {
2815  emit log(LOGERR, tr("Unable to save ") + _filename);
2816  ofs.close();
2817  return false;
2818  }
2819  }
2820 #endif
2821 
2822  else {
2823  emit log(LOGERR, tr("Unable to save (object is not a compatible mesh type)"));
2824  ofs.close();
2825  return false;
2826  }
2827 
2828 }
2829 
2830 //-----------------------------------------------------------------------------------------------------
2831 
2832 template< class MeshT >
2833 bool FileVTKPlugin::writeMesh(std::ostream& _out, MeshT& _mesh ) {
2834 
2835  /*****************
2836  * HEADER
2837  ******************/
2838  //every VTK file has to start with this
2839  _out << "# vtk DataFile Version 2.0\n";
2840  //write header info. Max. 256 characters!
2841  _out << "Mesh saved from OpenFlipper - www.openflipper.org\n";
2842  //only ASCII is supported right now
2843  _out << "ASCII\n";
2844 
2845  /*****************
2846  * DATA
2847  ******************/
2848 
2849  // Call corresponding write routine
2850  return writeASCIIData(_out, _mesh);
2851 }
2852 
2853 //------------------------------------------------------------------------------------------------------
2854 
2855 
2857 
2858  // If the options dialog has not been initialized, keep
2859  // the initial values
2860 
2861  if( OpenFlipper::Options::nogui() )
2862  return;
2863 
2864  // Save options
2865  if(saveBinary_) {
2866  if(saveBinary_->isChecked()) userWriteOptions_ |= BINARY;
2867  else { if(userWriteOptions_ & BINARY) userWriteOptions_ -= BINARY; }
2868  }
2869  if(saveFaceNormals_) {
2870  if(saveFaceNormals_->isChecked()) userWriteOptions_ |= FACENORMALS;
2871  else { if(userWriteOptions_ & FACENORMALS) userWriteOptions_ -= FACENORMALS; }
2872  }
2873  if(saveVertexNormals_) {
2874  if(saveVertexNormals_->isChecked()) userWriteOptions_ |= VERTEXNORMALS;
2875  else { if(userWriteOptions_ & VERTEXNORMALS) userWriteOptions_ -= VERTEXNORMALS; }
2876  }
2877  if(saveVertexTexCoords_) {
2878  if(saveVertexTexCoords_->isChecked()) userWriteOptions_ |= VERTEXTEXCOORDS;
2879  else { if(userWriteOptions_ & VERTEXTEXCOORDS) userWriteOptions_ -= VERTEXTEXCOORDS; }
2880  }
2881 }
2882 
2883 
2884 
2885 
Handle for a face entity.
Definition: Handles.hh:141
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:2833
void slotSaveDefault()
Slot called when user wants to save the given Save options as default.
Definition: FileVTK.cc:186
bool writeASCIIDataOfOpenMesh(std::ostream &_out, MeshT &_mesh)
Writes the data of the VTK file in ASCII format.
Definition: FileVTK.cc:375
#define DATA_POLYHEDRAL_MESH
bool binary_
Reading binary file?
Definition: FileVTK.hh:215
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
bool loadMeshLines(QString _spec, QTextStream &_in, MeshT *&_mesh)
Reads lines from the stream and adds them to the mesh.
Definition: FileVTK.cc:1881
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
void setNormalsOfDuplicatedVerticesOfOpenMesh(MeshT *&_mesh)
Sets normals of duplicated vertices that were created for non-manifold meshes.
Definition: FileVTK.cc:352
virtual void setName(QString _name) override
path to the file from which the object is loaded ( defaults to "." )
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
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:2222
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
void removeTemporaryPropertiesOfOpenMesh(MeshT *&_mesh)
Removed temporary properties that might have been added during file reading.
Definition: FileVTK.cc:282
int addTetraCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a tetra cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:465
void updateVertexNormalsOfOpenMesh(MeshT *&_mesh)
Updates vertex normals.
Definition: FileVTK.cc:276
int idx() const
Get the underlying index of this handle.
Definition: Handles.hh:69
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void addFaceNormal(TriMesh *&_mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a face normal.
Definition: FileVTK.cc:492
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.
#define DATA_TETRAHEDRAL_MESH
bool loadMeshPoints(QString _spec, QTextStream &_in, MeshT *&_mesh)
Reads points from the stream and adds them to the mesh.
Definition: FileVTK.cc:1798
#define DATA_HEXAHEDRAL_MESH
QWidget * saveOptionsWidget(QString)
Definition: FileVTK.cc:137
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:1965
const DataType DATA_GROUP(1)
Items used for Grouping.
Add 2D texture coordinates (vertices, halfedges)
Definition: Attributes.hh:87
Predefined datatypes.
Definition: DataTypes.hh:83
Handle for a vertex entity.
Definition: Handles.hh:120
void updateFaceNormalsOfOpenMesh(MeshT *&_mesh)
Updates face normals.
Definition: FileVTK.cc:266
QString filename() const
return the filename of the object
Definition: BaseObject.cc:706
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:2119
void addCellNormal(MeshT *&_mesh, const CellType &_cell, OpenMesh::Vec3d _normal)
Adds a normal to the cell.
Definition: FileVTK.cc:309
int id() const
Definition: BaseObject.cc:190
int addFaceToOpenMesh(MeshT *&_mesh, std::vector< quint32 > _indices)
Adds a face to the mesh.
Definition: FileVTK.cc:232
MeshT * mesh()
return a pointer to the mesh
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
BestMeshType findBestObjectType(QString _filename)
Reads the file to check for present primitives and returns the object type that fits best...
Definition: FileVTK.cc:1213
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
void addFaceNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a face normal.
Definition: FileVTK.cc:301
QWidget * loadOptionsWidget(QString)
Definition: FileVTK.cc:131
QString description()
Return a description of what the plugin is doing.
Definition: FileVTK.hh:177
int addHexaCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a hexa cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:468
int loadObject(QString _filename)
Loads Object and converts it to a triangle mesh if possible.
Definition: FileVTK.cc:1523
static constexpr size_t size()
returns dimension of the vector
Definition: Vector11T.hh:107
const DrawMode & getDrawMode(const std::string &_name)
Get a custom DrawMode.
Definition: DrawModes.cc:799
void addVertexNormalToOpenMesh(MeshT _mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a vertex normal.
Definition: FileVTK.cc:292
void setObjectDrawMode(const ACG::SceneGraph::DrawModes::DrawMode &_mode, const bool &_force=false)
Set the draw mode for the object.
void updateVertexNormals(TriMesh *&_mesh)
Updates vertex normals.
Definition: FileVTK.cc:483
QString getSaveFilters()
Definition: FileVTK.cc:107
void addVertexNormal(TriMesh *&_mesh, quint32 _index, OpenMesh::Vec3d _normal)
Adds a vertex normal.
Definition: FileVTK.cc:489
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
TetrahedralMesh * tetrahedralMesh(BaseObjectData *_object)
Get an TetrahedralMesh from an object.
FileVTKPlugin()
Constructor.
Definition: FileVTK.cc:69
int addWedgeCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a wedge cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:471
QString getLoadFilters()
Definition: FileVTK.cc:101
void updateUserOptions()
Definition: FileVTK.cc:2856
int addFace(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a face to the mesh.
Definition: FileVTK.cc:477
DataType supportedType()
Return your supported object type( e.g. DATA_TRIANGLE_MESH )
Definition: FileVTK.cc:113
PolyhedralMesh * polyhedralMesh(BaseObjectData *_object)
Get an PolyhedralMesh from an object.
MeshT * mesh()
return a pointer to the mesh
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
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:2064
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void removeTemporaryProperties(TriMesh *&_mesh)
Removed temporary properties that might have been added during file reading.
Definition: FileVTK.cc:486
int addTetraCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a tetra cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:204
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
int addPyramidCell(TriMesh *&_mesh, const std::vector< quint32 > &_indices)
Adds a pyramid cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:474
int addHexaCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a hexa cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:211
void initializePlugin()
Initialize Plugin.
Definition: FileVTK.cc:87
void updateFaceNormals(TriMesh *&_mesh)
Updates face normals.
Definition: FileVTK.cc:271
bool writeASCIIData(std::ostream &_out, TriMesh &_mesh)
Writes the data of the VTK file in ASCII format.
Definition: FileVTK.cc:498
void setNormalsOfDuplicatedVertices(TriMesh *&_mesh)
Sets normals of duplicated vertices that were created for non-manifold meshes.
Definition: FileVTK.cc:495
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:2303
void setFromFileName(const QString &_filename)
Definition: BaseObject.cc:716
int addWedgeCellToOpenMesh(MeshT _mesh, std::vector< quint32 > _indices)
Adds a wedge cell to the mesh. (Does nothing, yet)
Definition: FileVTK.cc:218