Developer Documentation
DecimaterPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 //=============================================================================
44 //
45 // CLASS DecimaterPlugin - IMPLEMENTATION
46 //
47 //=============================================================================
48 
49 
50 //== INCLUDES =================================================================
51 
52 #include "DecimaterPlugin.hh"
53 
54 #include <OpenFlipper/BasePlugin/WhatsThisGenerator.hh>
55 
56 #define DECIMATER "DecimaterData"
57 
58 //== IMPLEMENTATION ==========================================================
59 
61  tool_(0),
62  decimater_objects_(),
63  toolIcon_(0),
64  runningJobs_(0)
65 {
66 
67 }
68 
69 void DecimaterPlugin::initializePlugin()
70 {
71 
72  if ( OpenFlipper::Options::gui()) {
74  QSize size(100, 100);
75  tool_->resize(size);
76 
77  // connect signals->slots
78  connect(tool_->pbDecimate,SIGNAL(clicked() ),this,SLOT(slot_decimate()));
79  connect(tool_->pbInitialize,SIGNAL(clicked() ), this, SLOT(slot_initialize()));
80 
81  connect(tool_->roundness,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateRoundness(double)) );
82  connect(tool_->roundnessSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateRoundness(int)) );
83  connect(tool_->aspectRatio,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateAspectRatio(double)) );
84  connect(tool_->aspectRatioSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateAspectRatio(int)) );
85  connect(tool_->distance,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateDistance()) );
86  connect(tool_->edgeLength,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateEdgeLength()) );
87  connect(tool_->normalDeviation,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateNormalDev()) );
88  connect(tool_->normalDeviationSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateNormalDev()) );
89  connect(tool_->verticesCount,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateVertices()) );
90  connect(tool_->verticesCountSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateVertices()) );
91  connect(tool_->trianglesCount,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateTriangles()) );
92  connect(tool_->trianglesCountSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateTriangles()) );
93 
94  // Force update if the Toolbox gets visible
95  connect(tool_, SIGNAL(showing()), this, SLOT( slotUpdateNumVertices() ) );
96  connect(tool_, SIGNAL(showing()), this, SLOT( slotUpdateNumTriangles() ) );
97  connect(tool_->mixedFactorCounter, SIGNAL(valueChanged(double)), this, SLOT(slotMixedCounterValueChanged(double)) );
98  connect(tool_->mixedFactorSlider, SIGNAL(valueChanged(int)), this, SLOT(slotMixedSliderValueChanged(int)) );
99  connect(tool_->cbDistance, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
100  connect(tool_->cbNormalDev, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
101  connect(tool_->cbEdgeLength, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
102  connect(tool_->cbIndependentSets, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
103  connect(tool_->cbRoundness, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
104  connect(tool_->cbAspectRatio, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
105  connect(tool_->rbByDistance, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
106  connect(tool_->rbByEdgeLength, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
107  connect(tool_->rbByNormalDeviation, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
108  connect(tool_->rbConstraintsOnly, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
109  connect(tool_->rbTriangles, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
110  connect(tool_->rbUseDecimater, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
111  connect(tool_->rbUseMC, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
112  connect(tool_->rbUseMixed, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
113  connect(tool_->rbVertices, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
114 
115  toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"decimater.png");
116  emit addToolbox( tr("Decimater") , tool_, toolIcon_ );
117 
118  WhatsThisGenerator generator("Decimater");
119 
120  tool_->pbDecimate->setWhatsThis(tool_->pbDecimate->whatsThis()+generator.generateLink("quick_tutorial"));
121  tool_->pbInitialize->setWhatsThis(tool_->pbInitialize->whatsThis()+generator.generateLink("quick_tutorial"));
122  tool_->rbUseDecimater->setWhatsThis(tool_->rbUseDecimater->whatsThis()+generator.generateLink("incremental"));
123  tool_->rbUseMC->setWhatsThis(tool_->rbUseMC->whatsThis()+generator.generateLink("multiple_choice"));
124  tool_->rbUseMixed->setWhatsThis(tool_->rbUseMixed->whatsThis()+generator.generateLink("mixed"));
125  tool_->cbDistance->setWhatsThis(tool_->cbDistance->whatsThis()+generator.generateLink());
126  tool_->cbNormalDev->setWhatsThis(tool_->cbNormalDev->whatsThis()+generator.generateLink());
127  tool_->cbEdgeLength->setWhatsThis(tool_->cbEdgeLength->whatsThis()+generator.generateLink());
128  tool_->cbIndependentSets->setWhatsThis(tool_->cbIndependentSets->whatsThis()+generator.generateLink());
129  tool_->cbRoundness->setWhatsThis(tool_->cbRoundness->whatsThis()+generator.generateLink());
130  tool_->cbAspectRatio->setWhatsThis(tool_->cbAspectRatio->whatsThis()+generator.generateLink());
131  tool_->rbByDistance->setWhatsThis(tool_->rbByDistance->whatsThis()+generator.generateLink());
132  tool_->rbByEdgeLength->setWhatsThis(tool_->rbByEdgeLength->whatsThis()+generator.generateLink());
133  tool_->rbByNormalDeviation->setWhatsThis(tool_->rbByNormalDeviation->whatsThis()+generator.generateLink());
134  tool_->rbConstraintsOnly->setWhatsThis(tool_->rbConstraintsOnly->whatsThis()+generator.generateLink());
135  tool_->rbTriangles->setWhatsThis(tool_->rbTriangles->whatsThis()+generator.generateLink());
136  tool_->rbVertices->setWhatsThis(tool_->rbVertices->whatsThis()+generator.generateLink());
137 
138 
139  tool_->randomSamplesCounter->setWhatsThis(tool_->randomSamplesCounter->whatsThis()+generator.generateLink("multiple_choice"));
140  tool_->mixedFactorCounter->setWhatsThis(tool_->mixedFactorCounter->whatsThis()+generator.generateLink("mixed"));
141  tool_->roundness->setWhatsThis(tool_->roundness->whatsThis()+generator.generateLink());
142  tool_->aspectRatio->setWhatsThis(tool_->aspectRatio->whatsThis()+generator.generateLink());
143  tool_->distance->setWhatsThis(tool_->distance->whatsThis()+generator.generateLink());
144  tool_->edgeLength->setWhatsThis(tool_->edgeLength->whatsThis()+generator.generateLink());
145  tool_->normalDeviation->setWhatsThis(tool_->normalDeviation->whatsThis()+generator.generateLink());
146  }
147 
148 }
149 
154 
155  emit setSlotDescription("decimate(int,QVariantMap)",tr("Decimate a given object"),
156  QString(tr("objectId,constraints")).split(","),
157  QString(tr("ID of an object; Object that can has one or more constraint properties ("
158  "decimater_type [0 (Incremental), 1 (MC), 2 (Mixed)], "
159  "random_samples [For MC/Mixed], "
160  "incremental_percentage [For Mixed], "
161  "decimation_order [0 (by distance), 1 (by normal deviation), 2 (by edge length)], "
162  "distance, "
163  "edge_length, "
164  "normal_deviation, "
165  "roundness, "
166  "aspect_ratio,independent_sets, "
167  "vertices, "
168  "triangles)")).split(";"));
169 
170  if ( OpenFlipper::Options::gui()) {
171  tool_->decTypeOps->setVisible(false);
172  }
173 }
174 
175 
176 //-----------------------------------------------------------------------------
177 
183 {
184  tool_->roundness->setValue( (double) _value / 100.0 );
185  tool_->cbRoundness->setChecked (true);
186 }
187 
188 void DecimaterPlugin::slotMixedCounterValueChanged(double _value)
189 {
190  tool_->mixedFactorLabel->setText(QString::number(100-_value)+QString("%"));
191  tool_->mixedFactorSlider->setValue(100-_value);
192 }
193 void DecimaterPlugin::slotMixedSliderValueChanged(int _value)
194 {
195  tool_->mixedFactorLabel->setText(QString::number(_value)+QString("%"));
196  tool_->mixedFactorCounter->setValue(100.0-_value);
197 }
198 
199 //-----------------------------------------------------------------------------
200 
206 {
207  tool_->roundnessSlider->setValue( (int) (_value * 100) );
208  tool_->cbRoundness->setChecked (true);
209 }
210 
211 //-----------------------------------------------------------------------------
212 
213 
219 {
220  tool_->aspectRatio->setValue( (double) _value / 100.0 );
221  tool_->cbAspectRatio->setChecked (true);
222 }
223 
224 
225 //-----------------------------------------------------------------------------
226 
232 {
233  tool_->aspectRatioSlider->setValue( (int) (_value * 100) );
234  tool_->cbAspectRatio->setChecked (true);
235 }
236 //-----------------------------------------------------------------------------
237 
238 
243 {
244 
245  if ( ! OpenFlipper::Options::gui())
246  return;
247 
248  decimater_objects_.clear();
249 
251  initialize_object(o_it);
252  }
253  tool_->pbDecimate->setEnabled(true);
254 }
255 
256 void DecimaterPlugin::initialize_object(BaseObjectData *obj) {
257  //initialize
259 
260  if ( object == 0 )
261  emit log(LOGWARN , tr("Unable to get object"));
262 
263  DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( obj->objectData(DECIMATER) );
264 
265  TriMesh* mesh = PluginFunctions::triMesh(obj);
266 
267  if (decimater == 0){
268  decimater = new DecimaterInfo();
269  obj->setObjectData(DECIMATER, decimater);
270  }
271 
272  // constraint handles for decimation
273  ModAspectRatioH hModAspectRatio;
274  ModEdgeLengthH hModEdgeLength;
275  ModHausdorffH hModHausdorff;
276  ModIndependentH hModIndependent;
277  ModNormalDeviationH hModNormalDeviation;
278  ModNormalFlippingH hModNormalFlipping;
279  ModQuadricH hModQuadric;
280  ModRoundnessH hModRoundness;
281 
282  // Create decimater
283  ptr::shared_ptr<BaseDecimaterType> decimater_object;
284  if (tool_->rbUseDecimater->isChecked())
285  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
286  else if(tool_->rbUseMC->isChecked())
287  decimater_object = ptr::shared_ptr<McDecimaterType>(new McDecimaterType(*mesh));
288  else if(tool_->rbUseMixed->isChecked())
289  decimater_object = ptr::shared_ptr<MixedDecimaterType>(new MixedDecimaterType(*mesh));
290 
291 
292  // Remove old constraints
293  if(decimater->distance()) {
294  decimater->removeDistanceConstraint();
295  decimater_object->remove(hModHausdorff);
296  }
297  if(decimater->normalDeviation()) {
298  decimater->removeNormalDeviationConstraint();
299  decimater_object->remove(hModNormalDeviation);
300  }
301  if(decimater->normalFlipping()) {
302  decimater->removeNormalFlippingConstraint();
303  decimater_object->remove(hModNormalFlipping);
304  }
305  if(decimater->roundness()) {
306  decimater->removeRoundnessConstraint();
307  decimater_object->remove(hModRoundness);
308  }
309  if(decimater->aspectRatio()) {
310  decimater->removeAspectRatioConstraint();
311  decimater_object->remove(hModAspectRatio);
312  }
313  if(decimater->edgeLength()) {
314  decimater->removeEdgeLengthConstraint();
315  decimater_object->remove(hModEdgeLength);
316  }
317  if(decimater->independentSets()) {
318  decimater->removeIndependentSetsConstraint();
319  decimater_object->remove(hModIndependent);
320  }
321 
322  // set priority module: quadric, normal deviation or edge length
323  if (tool_->rbByDistance->isChecked()) {
324  decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
325  decimater_object->add( hModQuadric );
326  decimater_object->module( hModQuadric ).unset_max_err();
327  } else if (tool_->rbByNormalDeviation->isChecked()) {
328  decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
329  decimater_object->add(hModNormalDeviation);
330  decimater_object->module(hModNormalDeviation).set_binary(false);
331  } else if (tool_->rbByEdgeLength->isChecked()) {
332  decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
333  decimater_object->add(hModEdgeLength);
334  decimater_object->module(hModEdgeLength).set_binary(false);
335  }
336 
337  // and set new constraints
338  ptr::shared_ptr<DecimaterInit> decInit (new DecimaterInit);
339  if ( tool_->cbDistance->isChecked() ) {
340  if ( decimater_object->add( decInit->hModHausdorff ) || tool_->rbConstraintsOnly->isChecked() ) {
341  decimater->setDistanceConstraint( tool_->distance->value() );
342  decimater_object->module( decInit->hModHausdorff ).set_tolerance( decimater->distanceValue() );
343  }
344  }
345 
346  if ( tool_->cbNormalDev->isChecked() ) {
347  if ( decimater_object->add( decInit->hModNormalDeviation ) || tool_->rbConstraintsOnly->isChecked() ) {
348  decimater->setNormalDeviationConstraint( tool_->normalDeviation->value() );
349  decimater_object->module( decInit->hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
350  }
351  } else {
352  if ( decimater_object->add( decInit->hModNormalFlipping ) || tool_->rbConstraintsOnly->isChecked() ) {
353  decimater->setNormalFlippingConstraint();
354  }
355  }
356 
357  if ( tool_->cbRoundness->isChecked() ) {
358  if ( decimater_object->add( decInit->hModRoundness ) || tool_->rbConstraintsOnly->isChecked() ) {
359  decimater->setRoundnessConstraint( tool_->roundness->value() );
360  decimater_object->module( decInit->hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
361  }
362  }
363 
364  if ( tool_->cbAspectRatio->isChecked() ) {
365  if ( decimater_object->add( decInit->hModAspectRatio ) || tool_->rbConstraintsOnly->isChecked() ) {
366  decimater->setAspectRatioConstraint( tool_->aspectRatio->value() );
367  decimater_object->module( decInit->hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
368  }
369  }
370 
371  if ( tool_->cbEdgeLength->isChecked() ) {
372  if ( decimater_object->add( decInit->hModEdgeLength ) || tool_->rbConstraintsOnly->isChecked() ) {
373  decimater->setEdgeLengthConstraint( tool_->edgeLength->value() );
374  decimater_object->module( decInit->hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
375  }
376  }
377 
378  if ( tool_->cbIndependentSets->isChecked() ) {
379  if ( decimater_object->add( decInit->hModIndependent ) || tool_->rbConstraintsOnly->isChecked() ) {
380  decimater->setIndependentSetsConstraint();
381  }
382  }
383 
384 
385  // Initialize the decimater
386  if( ! decimater_object->initialize() ){
387  emit log(LOGWARN, tr("Decimater could not be initialized"));
388  return;
389  }
390 
391  decInit->decimater = decimater_object;
392  decInit->objId = obj->id();
393 
394  decimater_objects_.push_back(decInit);
395 }
396 
397 void DecimaterPlugin::slot_initialize_object(int obj_id, bool clear) {
398  if (clear)
399  decimater_objects_.clear();
400 
401  BaseObjectData *obj = 0;
402  PluginFunctions::getObject(obj_id, obj);
403  if (!obj) return;
404 
405  initialize_object(obj);
406 
407  tool_->pbDecimate->setEnabled(true);
408 }
409 
410 //-----------------------------------------------------------------------------
415 {
416 
417  if ( ! OpenFlipper::Options::gui())
418  return;
419 
420  //decimate
421  runningJobs_ = decimater_objects_.size();
422  for (std::vector< ptr::shared_ptr<DecimaterInit> >::iterator decIter = decimater_objects_.begin();
423  decIter != decimater_objects_.end(); ++decIter)
424  {
425  ptr::shared_ptr<DecimaterInit> decInit = *decIter;
426  ptr::shared_ptr<BaseDecimaterType> decimater = decInit->decimater;
427 
428  // set values for constraints
429  if ( tool_->cbDistance->isChecked() ) {
430  decimater->module( decInit->hModHausdorff ).set_tolerance( tool_->distance->value() );
431  }
432 
433  if ( tool_->cbNormalDev->isChecked() ) {
434  decimater->module( decInit->hModNormalDeviation ).set_normal_deviation( tool_->normalDeviation->value() );
435  }
436 
437  if ( tool_->cbRoundness->isChecked() ) {
438  decimater->module( decInit->hModRoundness ).set_min_roundness( tool_->roundness->value(), true );
439  }
440 
441  if ( tool_->cbAspectRatio->isChecked() ) {
442  decimater->module( decInit->hModAspectRatio ).set_aspect_ratio( tool_->aspectRatio->value() );
443  }
444 
445  if ( tool_->cbEdgeLength->isChecked() ) {
446  decimater->module( decInit->hModEdgeLength ).set_edge_length( tool_->edgeLength->value() );
447  }
448 
449  // fill data for the decimate thread
450  DecimateThread::Params params;
451  params.dec = (tool_->rbUseDecimater->isChecked()) ? dynamic_cast<DecimaterType*>(decimater.get()) : NULL;
452  params.mcDec = (tool_->rbUseMC->isChecked()) ? dynamic_cast<McDecimaterType*>(decimater.get()) : NULL;
453  params.mixedDec = (tool_->rbUseMixed->isChecked()) ? dynamic_cast<MixedDecimaterType*>(decimater.get()) : NULL;
454 
455  params.facesCount = (tool_->rbTriangles->isChecked()) ? tool_->trianglesCount->value() : -1;
456  params.verticesCount = (tool_->rbVertices->isChecked() ) ? tool_->verticesCount->value() : -1;
457  params.samples = tool_->randomSamplesCounter->value();
458  params.mc_factor = 1.0 - (tool_->mixedFactorCounter->value()*0.01);
459  params.selectionOnly = tool_->selectionOnly->isChecked();
460 
461  // create and start decimate thread
462  QString jobId = QString("Decimate_Object_%1").arg(decInit->objId);
463  DecimateThread* th = new DecimateThread(params, jobId, decInit->objId);
464  connect(th, SIGNAL(finished(QString)), this,SIGNAL(finishJob(QString)));
465  connect(th, SIGNAL(finished(QString)), this, SLOT(slot_decimate_finished(QString)));
466  connect(th, SIGNAL(state(QString, int)), this, SIGNAL(setJobState(QString, int)));
467  connect(this, SIGNAL(jobCanceled(QString)), th, SLOT(slotCancel(QString)));
468 
469  tool_->pbDecimate->setEnabled(false);
470  tool_->pbInitialize->setEnabled(false);
471 
472  emit startJob(jobId , QString("Decimate Object with Id %1").arg(decInit->objId) , 0, 100, false);
473 
474  th->start();
475  th->startProcessing();
476 
477  }
478 
479 
480 }
481 
482 void DecimaterPlugin::canceledJob (QString _job )
483 {
484  emit jobCanceled(_job);
485 }
486 
487 void DecimaterPlugin::slot_decimate_finished(QString _jobId)
488 {
489  //This function is executed by the main thread! but the sender is the finished thread
490  DecimateThread* thread = dynamic_cast<DecimateThread*>(sender());
491 
492  if (!thread)
493  return;
494  if (!thread->baseDecimater())
495  return;
496 
497  //update mesh
498  thread->baseDecimater()->mesh().garbage_collection();
499  thread->baseDecimater()->mesh().update_normals();
500 
501  emit updatedObject( thread->objectId() , UPDATE_TOPOLOGY );
502  emit createBackup( thread->objectId(), "Decimation");
503 
504  //cleanup when all threads are done
505  --runningJobs_;//running in main thread, so no race condition
506  if (runningJobs_ == 0)
507  {
508  tool_->pbDecimate->setEnabled(true);
509  tool_->pbInitialize->setEnabled(true);
510  emit updateView();
511  }
512 }
513 
514 
515 //-----------------------------------------------------------------------------
516 
517 void DecimaterPlugin::decimate(int _objID, QString _constraints) {
518  QStringList constraintList = _constraints.split(";");
519 
520  QVariantMap map;
521 
522  for ( auto i = 0 ; i < constraintList.size() ; ++i) {
523  const auto& currentConstraint = constraintList[i];
524 
525  int pos = currentConstraint.indexOf("=" );
526 
527  if ( pos == -1 ) {
528  emit log(LOGERR,"Wrong parameter format for decimater: " + currentConstraint);
529  return;
530  }
531 
532  QString constraintName = currentConstraint.left(pos);
533  QString constraintValue = currentConstraint.right(currentConstraint.size() - pos -1 );
534 
535  bool ok = false;
536 
537  double value = constraintValue.toDouble(&ok);
538 
539  if ( !ok) {
540  emit log(LOGERR,"Wrong parameter format for decimater. Conversion failed!");
541  emit log(LOGERR,"Got Name : " + constraintName );
542  emit log(LOGERR,"Got Value: " + constraintValue);
543  return;
544  }
545 // decimater.decimate(5,"random_samples=2;decimater_type=2;distance=0.0001")
546 
547  map[constraintName] = value;
548  }
549 
550  decimate(_objID,map);
551 
552 
553 }
554 
555 //-----------------------------------------------------------------------------
556 
557 void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
558 
559  BaseObjectData* baseObjectData;
560  if ( ! PluginFunctions::getObject(_objID,baseObjectData) ) {
561  emit log(LOGERR,tr("Unable to get Object"));
562  return;
563  }
564 
565  if ( baseObjectData->dataType() == DATA_TRIANGLE_MESH ) {
566  TriMeshObject* object = PluginFunctions::triMeshObject(baseObjectData);
567 
568  if ( object == 0 ) {
569  emit log(LOGWARN , tr("Unable to get object ( Only Triangle Meshes supported)"));
570  return;
571  }
572 
573  DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( object->objectData(DECIMATER) );
574 
575  TriMesh* mesh = PluginFunctions::triMesh(baseObjectData);
576 
577  if (decimater == 0){
578  decimater = new DecimaterInfo();
579  object->setObjectData(DECIMATER, decimater);
580  }
581 
582  // constraint handles for decimation
583  ModAspectRatioH hModAspectRatio;
584  ModEdgeLengthH hModEdgeLength;
585  ModHausdorffH hModHausdorff;
586  ModIndependentH hModIndependent;
587  ModNormalDeviationH hModNormalDeviation;
588  ModNormalFlippingH hModNormalFlipping;
589  ModQuadricH hModQuadric;
590  ModRoundnessH hModRoundness;
591 
592  // Create decimater
593  ptr::shared_ptr<BaseDecimaterType> decimater_object;
594  if (_constraints.contains("decimater_type"))
595  {
596  bool ok;
597  int value = _constraints["decimater_type"].toInt(&ok);
598  if (ok)
599  {
600  if (value == 0)
601  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
602  else if (value == 1)
603  decimater_object = ptr::shared_ptr<McDecimaterType>(new McDecimaterType(*mesh));
604  else if (value == 2)
605  decimater_object = ptr::shared_ptr<MixedDecimaterType>(new MixedDecimaterType(*mesh));
606  }
607 
608  }
609 
610  if (!decimater_object)
611  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
612 
613  // Remove old constraints
614  if(decimater->distance()) {
615  decimater->removeDistanceConstraint();
616  decimater_object->remove(hModHausdorff);
617  }
618  if(decimater->normalDeviation()) {
619  decimater->removeNormalDeviationConstraint();
620  decimater_object->remove(hModNormalDeviation);
621  }
622  if(decimater->normalFlipping()) {
623  decimater->removeNormalFlippingConstraint();
624  decimater_object->remove(hModNormalFlipping);
625  }
626  if(decimater->roundness()) {
627  decimater->removeRoundnessConstraint();
628  decimater_object->remove(hModRoundness);
629  }
630  if(decimater->aspectRatio()) {
631  decimater->removeAspectRatioConstraint();
632  decimater_object->remove(hModAspectRatio);
633  }
634  if(decimater->edgeLength()) {
635  decimater->removeEdgeLengthConstraint();
636  decimater_object->remove(hModEdgeLength);
637  }
638  if(decimater->independentSets()) {
639  decimater->removeIndependentSetsConstraint();
640  decimater_object->remove(hModIndependent);
641  }
642 
643  // set priority module: quadric, normal deviation or edge length
644  if ( _constraints.contains("decimation_order") ){
645  bool ok;
646 
647  int value = _constraints["decimation_order"].toInt(&ok);
648 
649  if (ok) {
650  switch (value) {
651  case 0:
652  decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
653  decimater_object->add( hModQuadric );
654  decimater_object->module( hModQuadric ).unset_max_err();
655  break;
656  case 1:
657  decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
658  decimater_object->add(hModNormalDeviation);
659  decimater_object->module(hModNormalDeviation).set_binary(false);
660  break;
661  case 2:
662  decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
663  decimater_object->add(hModEdgeLength);
664  decimater_object->module(hModEdgeLength).set_binary(false);
665  break;
666  default:
667  emit log(LOGERR,tr("Invalid Decimation Order"));
668  return;
669  }
670  }
671  } else {
672  emit log(LOGERR,tr("No Decimation Order set"));
673  return;
674  }
675 
676  // stock options (triangle and vertices count) constraint
677  bool verticesCount = false;
678  bool trianglesCount = false;
679  int vertices = 0;
680  int triangles = 0;
681 
682  if ( _constraints.contains("vertices") ){
683 
684  bool ok;
685 
686  int value = _constraints["vertices"].toInt(&ok);
687 
688  if (ok){
689  verticesCount = true;
690  vertices = value;
691  }
692  } else if ( _constraints.contains("triangles") ){
693 
694  bool ok;
695 
696  int value = _constraints["triangles"].toInt(&ok);
697 
698  if (ok){
699  trianglesCount = true;
700  triangles = value;
701  }
702  }
703 
704  //distance constraint
705  if ( _constraints.contains("distance") ){
706 
707  bool ok;
708 
709  double value = _constraints["distance"].toDouble(&ok);
710 
711  if (ok) {
712  if ( decimater_object->add( hModHausdorff ) || (!verticesCount && !trianglesCount) ) {
713  decimater->setDistanceConstraint( value );
714  decimater_object->module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
715  }
716  }
717  }
718 
719  //normal deviation constraint
720  if ( _constraints.contains("normal_deviation") ){
721 
722  bool ok;
723 
724  int value = _constraints["normal_deviation"].toInt(&ok);
725 
726  if (ok) {
727  if ( decimater_object->add( hModNormalDeviation ) || (!verticesCount && !trianglesCount) ) {
728  decimater->setNormalDeviationConstraint( value );
729  decimater_object->module( hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
730  }
731  }
732  } else { // flipping constraint
733  if ( decimater_object->add( hModNormalFlipping ) || (!verticesCount && !trianglesCount) ) {
734  decimater->setNormalFlippingConstraint();
735  // decimater_object->module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() ); ?
736  }
737  }
738 
739  //roundness constraint
740  if ( _constraints.contains("roundness") ){
741 
742  bool ok;
743 
744  double value = _constraints["roundness"].toDouble(&ok);
745 
746  if (ok) {
747  if ( decimater_object->add( hModRoundness ) || (!verticesCount && !trianglesCount) ) {
748  decimater->setRoundnessConstraint( value );
749  decimater_object->module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
750  }
751  }
752  }
753 
754  //aspect ratio constraint
755  if ( _constraints.contains("aspect_ratio") ){
756 
757  bool ok;
758 
759  double value = _constraints["aspect_ratio"].toDouble(&ok);
760 
761  if (ok) {
762  if ( decimater_object->add( hModAspectRatio ) || (!verticesCount && !trianglesCount) ) {
763  decimater->setAspectRatioConstraint( value );
764  decimater_object->module( hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
765  }
766  }
767  }
768 
769  //edge length constraint
770  if ( _constraints.contains("edge_length") ){
771 
772  bool ok;
773 
774  double value = _constraints["edge_length"].toDouble(&ok);
775 
776  if (ok) {
777  if ( decimater_object->add( hModEdgeLength ) || (!verticesCount && !trianglesCount) ) {
778  decimater->setEdgeLengthConstraint( value );
779  decimater_object->module( hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
780  }
781  }
782  }
783 
784  //independent sets constraint
785  if ( _constraints.contains("independent_sets") ){
786 
787  bool value = _constraints["independent_sets"].toBool();
788 
789  if (value) {
790  if ( decimater_object->add( hModIndependent ) || (!verticesCount && !trianglesCount) ) {
791  decimater->setIndependentSetsConstraint();
792  }
793  }
794  }
795 
796  //independent sets constraint
797  bool selection_only = false;
798  if ( _constraints.contains("selection_only") ){
799 
800  selection_only = _constraints["selection_only"].toBool();
801 
802  }
803 
804  //init the decimater
805  if( ! decimater_object->initialize() ){
806  emit log(LOGWARN, tr("Decimater could not be initialized"));
807  return;
808  }
809 
810  float mc_factor = 0.5;
811  size_t randomSamples = 8;
812 
813  if (_constraints.contains("random_samples"))
814  {
815  bool ok;
816  unsigned value =_constraints["random_samples"].toUInt(&ok);
817  if (ok)
818  randomSamples = value;
819  }
820 
821  if (_constraints.contains("incremental_percentage"))
822  {
823  bool ok;
824  unsigned value =_constraints["incremental_percentage"].toUInt(&ok);
825  if (ok)
826  mc_factor = 1.f - (value*0.01f);
827  }
828 
829  //decimate
830  DecimaterType* dec = dynamic_cast<DecimaterType*>(decimater_object.get());
831  McDecimaterType* mcDec = dynamic_cast<McDecimaterType*>(decimater_object.get());
832  MixedDecimaterType* mixedDec = dynamic_cast<MixedDecimaterType*>(decimater_object.get());
833 
834  if(dec && !mixedDec)
835  {
836  if ( verticesCount )
837  dec->decimate_to(vertices,selection_only);
838  else if (trianglesCount )
839  dec->decimate_to_faces(0, triangles,selection_only);
840  else // constraints only
841  dec->decimate_to_faces(0, 1,selection_only);
842  }
843  else if (mcDec && !mixedDec)
844  {
845  mcDec->set_samples(randomSamples);
846  if ( verticesCount )
847  mcDec->decimate_to(vertices,selection_only);
848  else if (trianglesCount)
849  mcDec->decimate_to_faces(0, triangles,selection_only);
850  else // constraints only
851  mcDec->decimate_to_faces(0, 1,selection_only);
852  }
853  else if (mixedDec)
854  {
855  mixedDec->set_samples(randomSamples);
856  if ( verticesCount )
857  mixedDec->decimate_to(vertices,mc_factor,selection_only);
858  else if (trianglesCount)
859  mixedDec->decimate_to_faces(0, triangles,mc_factor,selection_only);
860  else // constraints only
861  mixedDec->decimate_to_faces(0, 1,mc_factor,selection_only);
862  }else
863  {
864  emit log(LOGERR,tr("Could not find Decimater Type"));
865  }
866 
867  object->mesh()->garbage_collection();
868  object->mesh()->update_normals();
869 
870  emit updatedObject( baseObjectData->id() , UPDATE_TOPOLOGY);
871 
872  // Create backup
873  emit createBackup(_objID, "Decimation");
874 
875  // Create QVariantMap parameter string
876  QString param = "(" + (_constraints.contains("decimation_order") ? tr("decimation_order = %1").arg(_constraints["decimation_order"].toString()) : "") +
877  ", " + (_constraints.contains("distance") ? tr("distance = %1").arg(_constraints["distance"].toString()) : "") +
878  ", " + (_constraints.contains("normal_deviation") ? tr("normal_deviation = %1").arg(_constraints["normal_deviation"].toString()) : "") +
879  ", " + (_constraints.contains("edge_length") ? tr("edge_length = %1").arg(_constraints["edge_length"].toString()) : "") +
880  ", " + (_constraints.contains("roundness") ? tr("roundness = %1").arg(_constraints["roundness"].toString()) : "") +
881  ", " + (_constraints.contains("aspect_ratio") ? tr("aspect_ratio = %1").arg(_constraints["aspect_ratio"].toString()) : "") +
882  ", " + (_constraints.contains("independent_sets") ? tr("independent_sets = %1").arg(_constraints["independent_sets"].toString()) : "") +
883  ", " + (_constraints.contains("triangles") ? tr("triangles = %1").arg(_constraints["triangles"].toString()) : "") +
884  ", " + (_constraints.contains("vertices") ? tr("vertices = %1").arg(_constraints["vertices"].toString()) : "") + ")";
885 
886  emit scriptInfo( "decimate(" + QString::number(_objID) + ", " + param + ")" );
887 
888 
889  } else {
890  emit log(LOGERR,tr("Unsupported object type for decimater"));
891  return;
892  }
893 
894  emit updateView();
895 }
896 
897 //-----------------------------------------------------------------------------
898 
900 {
901  // Only update if tool is visible
902  if ( !OpenFlipper::Options::gui() || !tool_->isVisible() ) {
903  return;
904  }
905 
906  int max = 0;
907  int div = 0;
908 
909  bool ok;
910  emit functionExists( "infomeshobject" , "vertexCount(int)", ok ) ;
911  if (!ok)
912  {
913  tool_->currentNumVertices->setText ("<not available>");
914  return;
915  }
916 
918  max = std::max( RPC::callFunctionValue<int> ("infomeshobject" , "vertexCount",o_it->id()) , max );
919  div++;
920  }
921 
922  if (div <= 0)
923  tool_->currentNumVertices->setText ("<not available>");
924  else {
925  tool_->verticesCount->blockSignals(true);
926  tool_->verticesCountSlider->blockSignals(true);
927 
928  tool_->currentNumVertices->setText (QString::number(max));
929  tool_->verticesCount->setMaximum(max);
930  tool_->verticesCountSlider->setMaximum(max);
931 
932  if ( tool_->verticesCount->value() < 2 )
933  {
934  tool_->verticesCount->setValue( max / 2 );
935  tool_->verticesCountSlider->setValue( max / 2);
936  }
937 
938  tool_->verticesCount->blockSignals(false);
939  tool_->verticesCountSlider->blockSignals(false);
940  }
941 }
942 
943 //-----------------------------------------------------------------------------
944 
949  // only update if the tool is visible
950  if (!OpenFlipper::Options::gui() || !tool_->isVisible())
951  return;
952 
953  size_t max = 0;
954  int meshN = 0;
955 
957  TriMesh* mesh = PluginFunctions::triMesh(o_it->id());
958  max = std::max(mesh->n_faces(), max);
959  meshN++;
960  }
961 
962  tool_->trianglesCount->blockSignals(true);
963  tool_->trianglesCountSlider->blockSignals(true);
964 
965  tool_->trianglesCount->setMinimum(1);
966  tool_->trianglesCount->setMaximum(max);
967  tool_->trianglesCountSlider->setMinimum(1);
968  tool_->trianglesCountSlider->setMaximum(max);
969 
970  if (tool_->trianglesCount->value() < 2)
971  {
972  tool_->trianglesCount->setValue (max / 2 );
973  tool_->trianglesCountSlider->setValue( max / 2);
974  }
975 
976  tool_->trianglesCount->blockSignals(false);
977  tool_->trianglesCountSlider->blockSignals(false);
978 }
979 
980 //-----------------------------------------------------------------------------
981 
982 void DecimaterPlugin::slotObjectSelectionChanged(int /*_identifier*/)
983 {
986 }
987 //-----------------------------------------------------------------------------
988 
989 void DecimaterPlugin::objectDeleted(int _id)
990 {
991  slotDisableDecimation();
992 }
993 
994 //-----------------------------------------------------------------------------
995 
996 void DecimaterPlugin::slotAboutToRestore(int _id)
997 {
998  slotDisableDecimation();
999 }
1000 
1001 //-----------------------------------------------------------------------------
1002 
1003 void DecimaterPlugin::slotDisableDecimation()
1004 {
1005  if ( ! OpenFlipper::Options::gui())
1006  return;
1007 
1008  decimater_objects_.clear();
1009  tool_->pbDecimate->setEnabled(false);
1010 }
1011 
1012 //-----------------------------------------------------------------------------
1013 
1014 void DecimaterPlugin::slotObjectUpdated(int /*_identifier*/ , const UpdateType& _type )
1015 {
1016  if ( _type.contains(UPDATE_TOPOLOGY) ) {
1019  }
1020 }
1021 
1022 //-----------------------------------------------------------------------------
1023 
1024 // activate checkbox if value has changed
1025 void DecimaterPlugin::slotUpdateVertices()
1026 {
1027  tool_->rbVertices->setChecked (true);
1028 }
1029 
1030 //-----------------------------------------------------------------------------
1031 
1032 // activate checkbox if value has changed
1033 void DecimaterPlugin::slotUpdateTriangles()
1034 {
1035  tool_->rbTriangles->setChecked (true);
1036 }
1037 
1038 //-----------------------------------------------------------------------------
1039 
1040 // activate checkbox if value has changed
1041 void DecimaterPlugin::slotUpdateNormalDev()
1042 {
1043  tool_->cbNormalDev->setChecked (true);
1044 }
1045 
1046 //-----------------------------------------------------------------------------
1047 
1048 // activate checkbox if value has changed
1049 void DecimaterPlugin::slotUpdateEdgeLength()
1050 {
1051  tool_->cbEdgeLength->setChecked (true);
1052 }
1053 
1054 //-----------------------------------------------------------------------------
1055 
1056 // activate checkbox if value has changed
1058 {
1059  tool_->cbDistance->setChecked (true);
1060 }
1061 
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(8))
Topology updated.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
void setObjectData(QString _dataName, PerObjectData *_data)
Definition: BaseObject.cc:781
void canceledJob(QString _job)
A job has been canceled.
void slotUpdateRoundness(int _value)
roundness slider - spinbox sync
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void slot_decimate()
decimating called from button in toolbox
void startProcessing()
start processing
Predefined datatypes.
Definition: DataTypes.hh:83
void slotUpdateNumVertices()
update number of vertices information
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
void slotUpdateAspectRatio(int _value)
sync between values of aspect ratio slider and spinbox in the toolbox
void decimate(int _objID, QVariantMap _constraints)
decimate an object
DecimaterToolbarWidget * tool_
Widget for Toolbox.
void slotUpdateDistance()
slider / spinbox updates
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:59
void slot_initialize()
init called from button in toolbox
const QStringList TARGET_OBJECTS("target")
Iterable object range.
ObjectRange objects(IteratorRestriction _restriction, DataType _dataType)
Iterable object range.
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:99
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:803
QString generateLink(const QString &_ref="", const QString &_site="index.html") const
generates a clickable link to the documentation for whatsThis Messages
void slotUpdateNumTriangles()
gets and sets the current maximum number of triangles
DecimaterPlugin()
Default constructor.