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