Developer Documentation
HoleFillerPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 #include "HoleFillerPlugin.hh"
43 #include "holefillerToolbar.hh"
44 
46 #include "HoleInfoT.hh"
47 
48 #include <QProgressDialog>
49 
50 #define HOLEINFO "HoleInfoData"
51 
54  tool_(0)
55 {
56 
57 }
58 
61 {
62  if ( OpenFlipper::Options::gui()) {
64  QSize size(300, 300);
65  tool_->resize(size);
66 
67  connect(tool_->tableWidget,SIGNAL(itemSelectionChanged()),this,SLOT(slotItemSelectionChanged()));
68 
69  connect(tool_->tableWidget,SIGNAL(cellDoubleClicked(int,int)),this,SLOT(slotCellDoubleClicked(int,int)));
70 
71  connect(tool_->detect,SIGNAL(clicked()),this,SLOT(detectButton()));
72  connect(tool_->fillButton, SIGNAL(clicked()), this, SLOT(slotFillSelection()) );
73 
74  QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"holefilling.png");
75 
76  emit addToolbox( tr("Hole Filler") , tool_ , toolIcon);
77  }
78 }
79 
82 {
83  if ( OpenFlipper::Options::gui()) {
84  emit addPickMode("Separator");
85  emit addPickMode("Hole Filler");
86 
87  //build the tableWidget with headers
88  update_menu();
89  }
90 
91  emit setSlotDescription("fillAllHoles(int)", tr("Fill all holes from a given Mesh"),
92  QString("objectId").split(","), QString("Id of the mesh").split(","));
93 
94  emit setSlotDescription("fillHole(int,int)", tr("Fill a holes from a given Mesh where edgeHandle is on the boundary"),
95  QString("objectId,edgeHandle").split(","), QString("Id of the mesh,Handle of one boundary edge of the hole").split(","));
96 
97 }
98 
99 void HoleFillerPlugin::getSelectedHoles(std::vector<int>& _holeIds, std::vector<int>& _objIds)
100 {
101  QModelIndexList indices = tool_->tableWidget->selectionModel()->selectedRows();
102 
103  //get a map from objectID to (selected) holeIDs
104  for (int i=0; i < indices.size(); i++){
105  int objID = holeMapping_[ indices[i].row() ].first;
106  int holeID = holeMapping_[ indices[i].row() ].second;
107 
108  _holeIds.push_back ( holeID );
109  _objIds.push_back( objID );
110  }
111 }
112 
115 
116  //get a map from objectID to (selected) holeIDs
117  std::vector< int > holes;
118  std::vector< int > objects;
119  getSelectedHoles(holes,objects);
120 
121  //init progressDialog
122  QProgressDialog progress(tr("Filling holes..."), tr("Abort"), 0, holes.size(), 0);
123  progress.setWindowModality(Qt::ApplicationModal);
124  progress.setValue(0);
125 
126  int counter = 0;
127 
128  //iterate over all objects with holes that should be filled
130 
131  // TYPE is TRIMESH
132  if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
133 
134  TriMesh* mesh = PluginFunctions::triMesh(o_it);
135 
136  //get perObjectData
137  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( o_it->objectData(HOLEINFO) );
138 
139  if (holeInfo == 0){
140  holeInfo = new HoleInfo< TriMesh >( mesh );
141  o_it->setObjectData(HOLEINFO, holeInfo);
142  }
143 
144  //fill the holes
145  for (uint i = 0; i < objects.size(); i++)
146  if ( objects[i] == o_it->id() ){
147  holeInfo->fillHole( holes[i]);
148 
149  if (progress.wasCanceled())
150  break;
151  else
152  progress.setValue(++counter);
153  }
154 
155  //update the object
156  emit updatedObject(o_it->id(),UPDATE_ALL);
157 
158  holeInfo->getHoles();
159 
160  update_menu();
161  emit createBackup( o_it->id(), "Hole Filling", UPDATE_GEOMETRY | UPDATE_TOPOLOGY | UPDATE_SELECTION);
162  }
163  // DATATYPE is POLYMESH
164  else if ( o_it->dataType( DATA_POLY_MESH ) ) {
165  emit log(LOGWARN, tr("HoleFilling unsupported for poly meshes") );
166  continue;
167  }
168 
169  //abort if user wants to
170  if (progress.wasCanceled())
171  break;
172  }
173 
174  progress.close();
175 
176  emit updateView();
177 }
178 
181 
182  std::vector< int > holes;
183  std::vector< int > objects;
184  getSelectedHoles(holes,objects);
185 
186  //iterate over all objects with holes that should be displayed
188 
189  // TYPE is TRIMESH
190  if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
191 
193  TriMesh* mesh = PluginFunctions::triMesh(o_it);
194 
195  //get perObjectData
196  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( o_it->objectData(HOLEINFO) );
197 
198  if (holeInfo == 0){
199  holeInfo = new HoleInfo< TriMesh >( mesh );
200  o_it->setObjectData(HOLEINFO, holeInfo);
201  }
202 
203  //clear the edge selection
204  MeshSelection::clearEdgeSelection(mesh);
205 
206  //select the holes
207  for (uint i = 0; i < objects.size(); i++)
208  if ( objects[i] == o_it->id() )
209  holeInfo->selectHole( holes[i] );
210 
211  // We only fly if we have exacly one object and one hole
212  if ( (objects.size() == 1) && (holes.size() == 1) && ( objects[0] == o_it->id() ) ){
213 
214  TriMesh::Point center;
215  TriMesh::Normal normal;
216  holeInfo->getHolePostitionInfo(holes[0], normal, center);
217 
218  // Get bounding box to get a scaling for the movement
219  TriMesh::Point _bbMin;
220  TriMesh::Point _bbMax;
221 
222  object->boundingBox(_bbMin, _bbMax);
223 
224  PluginFunctions::flyTo(center + normal * (_bbMax-_bbMin).length() , center, 10.0);
225  }
226 
227  //update the object
228  emit updatedObject(o_it->id(),UPDATE_SELECTION);
229  }
230  // DATATYPE is POLYMESH
231  else if ( o_it->dataType( DATA_POLY_MESH ) ) {
232 
234  PolyMesh* mesh = PluginFunctions::polyMesh(o_it);
235 
236  //get perObjectData
237  HoleInfo< PolyMesh >* holeInfo = dynamic_cast< HoleInfo< PolyMesh >* > ( o_it->objectData(HOLEINFO) );
238 
239  if (holeInfo == 0){
240  holeInfo = new HoleInfo< PolyMesh >( mesh );
241  o_it->setObjectData(HOLEINFO, holeInfo);
242  }
243 
244  //clear the edge selection
245  MeshSelection::clearEdgeSelection(mesh);
246 
247  //select the holes
248  for (uint i = 0; i < objects.size(); i++)
249  if ( objects[i] == o_it->id() )
250  holeInfo->selectHole( holes[i] );
251 
252  // We only fly if we have exacly one object and one hole
253  if ( (objects.size() == 1) && (holes.size() == 1) && ( objects[0] == o_it->id() ) ){
254 
255  PolyMesh::Point center;
256  PolyMesh::Normal normal;
257  holeInfo->getHolePostitionInfo(holes[0], normal, center);
258 
259  // Get bounding box to get a scaling for the movement
260  PolyMesh::Point _bbMin;
261  PolyMesh::Point _bbMax;
262 
263  object->boundingBox(_bbMin, _bbMax);
264 
265  PluginFunctions::flyTo(center + normal * (_bbMax-_bbMin).length() , center, 10.0);
266  }
267 
268  //update the object
269  emit updatedObject(o_it->id(),UPDATE_SELECTION);
270 
271  }
272  }
273 
274  emit updateView();
275 }
276 
278 void HoleFillerPlugin::slotCellDoubleClicked(int _row , int /*_col*/) {
279 
280  if ( _row > (int)holeMapping_.size() ) {
281  emit log(LOGWARN, tr("Error for holeMapping_ vector size") );
282  return;
283  }
284 
285  BaseObjectData* object;
286  int objID = holeMapping_[_row].first;
287  int holeID = holeMapping_[_row].second;
288 
289  if ( !PluginFunctions::getObject( objID, object ) ) {
290  emit log(LOGWARN, tr("Unable to find object for hole (should not happen!!)") );
291  return;
292  }
293 
294  // TYPE is TRIMESH
295  if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
296 
297  TriMesh* mesh = PluginFunctions::triMesh(object);
298 
299  //get perObjectData
300  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( object->objectData(HOLEINFO) );
301 
302  if (holeInfo == 0){
303  holeInfo = new HoleInfo< TriMesh >( mesh );
304  object->setObjectData(HOLEINFO, holeInfo);
305  }
306 
307  //fill the hole
308  holeInfo->fillHole( holeID );
309 
310  emit updatedObject(object->id(),UPDATE_ALL);
311 
312  holeInfo->getHoles();
313 
314  update_menu();
315 
316  emit updateView();
317  }
318  // DATATYPE is POLYMESH
319  else if ( object->dataType( DATA_POLY_MESH ) ) {
320 
321  emit log(LOGWARN,tr("HoleFilling unsupported for poly meshes"));
322 
323  return;
324  }
325 }
326 
329 {
331 
332  //case TRIMESH
333  if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
334 
335  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( o_it->objectData(HOLEINFO) );
336 
337  if ( holeInfo == 0 ){
338  TriMesh* mesh = PluginFunctions::triMesh(*o_it);
339  holeInfo = new HoleInfo< TriMesh >( mesh );
340  o_it->setObjectData(HOLEINFO, holeInfo);
341  }
342 
343  holeInfo->getHoles();
344  }
345 
346  //case POLYMESH
347  if ( o_it->dataType( DATA_POLY_MESH ) ) {
348 
349  HoleInfo< PolyMesh >* holeInfo = dynamic_cast< HoleInfo< PolyMesh >* > ( o_it->objectData(HOLEINFO) );
350 
351  if (holeInfo == 0){
352  PolyMesh* mesh = PluginFunctions::polyMesh(*o_it);
353  holeInfo = new HoleInfo< PolyMesh >( mesh );
354  o_it->setObjectData(HOLEINFO, holeInfo);
355  }
356 
357  holeInfo->getHoles();
358  }
359  }
360 
361  update_menu();
362 }
363 
365 void HoleFillerPlugin::slotObjectUpdated( int _identifier, const UpdateType& _type ) {
366 
367  BaseObjectData* object;
368 
369  // Check if this is a usable Object
370  if ( !PluginFunctions::getObject(_identifier,object) )
371  return;
372 
373  bool updated = false;
374 
375  if ( _type.contains(UPDATE_TOPOLOGY) ) {
376 
377  // get holes for TRIMESH
378  if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
379 
380  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( object->objectData(HOLEINFO) );
381 
382  if ( holeInfo ) {
383  holeInfo->getHoles();
384  updated = true;
385  }
386  }
387 
388  // get holes for POLYMESH
389  else if ( object->dataType( DATA_POLY_MESH ) ) {
390 
391  HoleInfo< PolyMesh >* holeInfo = dynamic_cast< HoleInfo< PolyMesh >* > ( object->objectData(HOLEINFO) );
392 
393  if ( holeInfo ) {
394  holeInfo->getHoles();
395  updated = true;
396  }
397  }
398  }
399 
400  // Only update if something has changed!
401  if ( updated )
402  update_menu();
403 }
404 
407 
408  holeMapping_.clear();
409 
410  tool_->tableWidget->clear();
411 
412  tool_->tableWidget->setRowCount ( 0 );
413  tool_->tableWidget->setColumnCount ( 4 );
414 
415  QStringList headerdata;
416  headerdata << "Object" << "Edges" << "Boundary Length" << "BB Diagonal";
417 
418  tool_->tableWidget->setHorizontalHeaderLabels(headerdata);
419  tool_->updateGeometry();
420 
421  int elements = 0;
422  int count = 0;
423 
424  //iterate over all objects
426 
427  // DATATYPE is TRIMESH
428  if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
429 
430  //get perObjectData
431  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( o_it->objectData(HOLEINFO) );
432 
433  if (holeInfo != 0){
434  elements += holeInfo->holes()->size();
435  tool_->tableWidget->setRowCount ( elements );
436 
437  //add holes to the table
438  for (uint i = 0 ; i < holeInfo->holes()->size() ; ++i ) {
439  // Set Name of the object
440  QTableWidgetItem* name = new QTableWidgetItem( o_it->name() );
441  name->setFlags( 0 );
442  name->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
443  tool_->tableWidget->setItem(count,0,name);
444 
445  size_t egde_count = 0;
446  TriMesh::Scalar bbDiagonal = 0.0;
447  double boundaryLength = 0.0;
448 
449  holeInfo->getHoleInfo(i, egde_count, bbDiagonal, boundaryLength);
450 
451  // Set Number of the edges
452  QTableWidgetItem* size = new QTableWidgetItem( QString::number( egde_count ) );
453  size->setFlags( 0 );
454  size->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
455  tool_->tableWidget->setItem(count,1,size);
456 
457  // Set boundary Length
458  QTableWidgetItem* boundaryLengthWidget = new QTableWidgetItem( QString::number(boundaryLength) );
459  boundaryLengthWidget->setFlags( 0 );
460  boundaryLengthWidget->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
461  tool_->tableWidget->setItem(count,2,boundaryLengthWidget);
462 
463  QTableWidgetItem* bbDiagonalWidget = new QTableWidgetItem( QString::number(bbDiagonal) );
464  bbDiagonalWidget->setFlags( 0 );
465  bbDiagonalWidget->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
466  tool_->tableWidget->setItem(count,3,bbDiagonalWidget);
467 
468  // remember the id for the hole
469  holeMapping_.push_back( std::pair<int , int>( o_it->id() , i ) );
470 
471  ++count;
472  }
473  }
474  }
475  // DATATYPE is POLYMESH
476  else if ( o_it->dataType( DATA_POLY_MESH ) ) {
477 
478  //get perObjectData
479  HoleInfo< PolyMesh >* holeInfo = dynamic_cast< HoleInfo< PolyMesh >* > ( o_it->objectData(HOLEINFO) );
480 
481  if (holeInfo != 0){
482  elements += holeInfo->holes()->size();
483  tool_->tableWidget->setRowCount ( elements );
484 
485  //add holes to the table
486  for (uint i = 0 ; i < holeInfo->holes()->size() ; ++i ) {
487  // Set Name of the object
488  QTableWidgetItem* name = new QTableWidgetItem( o_it->name() );
489  name->setFlags( 0 );
490  name->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
491  tool_->tableWidget->setItem(count,0,name);
492 
493  size_t egde_count = 0;
494  double boundaryLength = 0.0;
495  TriMesh::Scalar bbDiagonal = 0.0;
496 
497  holeInfo->getHoleInfo(i, egde_count, boundaryLength, bbDiagonal);
498 
499  // Set Number of the edges
500  QTableWidgetItem* size = new QTableWidgetItem( QString::number( egde_count ) );
501  size->setFlags( 0 );
502  size->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
503  tool_->tableWidget->setItem(count,1,size);
504 
505  // Set Bounding box diagonal
506  QTableWidgetItem* radius = new QTableWidgetItem( QString::number(boundaryLength) );
507  radius->setFlags( 0 );
508  radius->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
509  tool_->tableWidget->setItem(count,2,radius);
510 
511  // Set Bounding box diagonal
512  QTableWidgetItem* bbDiagonalWidget = new QTableWidgetItem( QString::number(bbDiagonal) );
513  bbDiagonalWidget->setFlags( 0 );
514  bbDiagonalWidget->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled);
515  tool_->tableWidget->setItem(count,3,bbDiagonalWidget);
516 
517  // remember the id for the hole
518  holeMapping_.push_back( std::pair<int , int>( o_it->id() , i ) );
519 
520  ++count;
521  }
522  }
523  }
524  }
525 
526  tool_->tableWidget->resizeColumnToContents ( 1 );
527 }
528 
530 void HoleFillerPlugin::fillAllHoles(int _objectID){
531  BaseObjectData* object = 0;
532  PluginFunctions::getObject( _objectID , object );
533 
534  if (object == 0){
535  emit log(LOGERR, tr("Could not get object from ID.") );
536  return;
537  }
538 
539  emit scriptInfo( "fillAllHoles( ObjectId )" );
540 
541 
542  // TYPE is TRIMESH
543  if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
544 
545  TriMesh* mesh = PluginFunctions::triMesh(object);
546 
547  //get perObjectData
548  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( object->objectData(HOLEINFO) );
549 
550  if (holeInfo == 0){
551  holeInfo = new HoleInfo< TriMesh >( mesh );
552  object->setObjectData(HOLEINFO, holeInfo);
553  }
554 
555  //fill the hole
556  holeInfo->fillAllHoles();
557 
558  //and update everything
559  emit updatedObject(object->id(),UPDATE_ALL);
560 
561  holeInfo->getHoles();
562 
563  update_menu();
564 
565  emit updateView();
566  }
567  // DATATYPE is POLYMESH
568  else if ( object->dataType( DATA_POLY_MESH ) ) {
569  emit log(LOGERR, tr("HoleFilling unsopported for poly meshes.") );
570  return;
571  }
572 }
573 
574 
576 void HoleFillerPlugin::fillHole(int _objectID, int _edgeHandle){
577  BaseObjectData* object = 0;
578  PluginFunctions::getObject( _objectID , object );
579 
580  if (object == 0){
581  emit log(LOGERR, tr("Could not get object from ID.") );
582  return;
583  }
584 
585  emit scriptInfo( "fillHole( ObjectId , EdgeHandle )" );
586 
587 
588  // TYPE is TRIMESH
589  if ( object->dataType( DATA_TRIANGLE_MESH ) ) {
590 
591  TriMesh* mesh = PluginFunctions::triMesh(object);
592 
593  //get perObjectData
594  HoleInfo< TriMesh >* holeInfo = dynamic_cast< HoleInfo< TriMesh >* > ( object->objectData(HOLEINFO) );
595 
596  if (holeInfo == 0){
597  holeInfo = new HoleInfo< TriMesh >( mesh );
598  object->setObjectData(HOLEINFO, holeInfo);
599  }
600 
601  //check edgeHandle
602  TriMesh::EdgeHandle eh(_edgeHandle);
603 
604  if ( !eh.is_valid() || !mesh->is_boundary(eh) ){
605  emit log(LOGERR, tr("Invalid edge handle.") );
606  return;
607  }
608 
609  //fill the hole
610  holeInfo->fillHole( eh );
611 
612  //and update everything
613  emit updatedObject(object->id(),UPDATE_ALL);
614 
615  holeInfo->getHoles();
616 
617  update_menu();
618 
619  emit updateView();
620  }
621  // DATATYPE is POLYMESH
622  else if ( object->dataType( DATA_POLY_MESH ) ) {
623  emit log(LOGERR, tr("HoleFilling unsopported for poly meshes.") );
624  return;
625  }
626 }
627 
628 
void getSelectedHoles(std::vector< int > &_holeIds, std::vector< int > &_objIds)
get a map from objectID to (selected) holeIDs
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
void detectButton()
detect holes on all objects
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void initializePlugin()
Initialize the toolbox widget.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Kernel::Normal Normal
Normal type.
Definition: PolyMeshT.hh:114
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
HoleFillerPlugin()
Constructor.
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
void slotItemSelectionChanged()
slot for displaying selected holes
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void getHoleInfo(const unsigned int _index, size_t &_edges, typename MeshT::Scalar &_diagonal, typename MeshT::Scalar &_boundaryLength) const
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
const QStringList ALL_OBJECTS
Iterable object range.
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
void selectHole(int _index)
select a hole with given index
QString name()
Return a name for the plugin.
void slotObjectUpdated(int _identifier, const UpdateType &_type)
check for holes if an object has changed
std::vector< std::pair< int, int > > holeMapping_
map from the index in the table to (object-id, hole-id)
void fillAllHoles(int _stages=3)
fill all holes
PolyMeshObject * polyMeshObject(BaseObjectData *_object)
Cast an BaseObject to a PolyMeshObject if possible.
Functions for selection on a mesh.
void fillAllHoles(int _objectID)
fill all holes from a given object
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
Update type class.
Definition: UpdateType.hh:60
Kernel::Scalar Scalar
Scalar type.
Definition: PolyMeshT.hh:110
void fillHole(int _index, int _stages=3)
fill hole with given index
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:104
void getHoles()
get all holes and store them internally
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
void getHolePostitionInfo(const int _index, typename MeshT::Normal &_holeNormal, typename MeshT::Point &_holeCenter) const
Collect information to fly to a hole.
std::vector< std::vector< typename MeshT::EdgeHandle > > * holes()
get the holes vector
void fillHole(int _objectID, int _edgeHandle)
fill a hole in given object where _edgeHandle is on the boundary
void pluginsInitialized()
add PickModes after initialization
void slotCellDoubleClicked(int _row, int _col)
Slot for filling holes from double-clicked rows.
void slotFillSelection()
Fill all selected holes.
HoleFillerToolbarWidget * tool_
Widget for Toolbox.
void update_menu()
update the entries in the tableWidget
void flyTo(const ACG::Vec3d &_position, const ACG::Vec3d &_center, double _time)
Fly to point and viewing direction (animated).