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  o_it != PluginFunctions::objectsEnd(); ++o_it) {
252 
253  initialize_object(*o_it);
254 
255  }
256  tool_->pbDecimate->setEnabled(true);
257 }
258 
259 void DecimaterPlugin::initialize_object(BaseObjectData *obj) {
260  //initialize
262 
263  if ( object == 0 )
264  emit log(LOGWARN , tr("Unable to get object"));
265 
266  DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( obj->objectData(DECIMATER) );
267 
268  TriMesh* mesh = PluginFunctions::triMesh(obj);
269 
270  if (decimater == 0){
271  decimater = new DecimaterInfo();
272  obj->setObjectData(DECIMATER, decimater);
273  }
274 
275  // constraint handles for decimation
276  ModAspectRatioH hModAspectRatio;
277  ModEdgeLengthH hModEdgeLength;
278  ModHausdorffH hModHausdorff;
279  ModIndependentH hModIndependent;
280  ModNormalDeviationH hModNormalDeviation;
281  ModNormalFlippingH hModNormalFlipping;
282  ModQuadricH hModQuadric;
283  ModRoundnessH hModRoundness;
284 
285  // Create decimater
286  ptr::shared_ptr<BaseDecimaterType> decimater_object;
287  if (tool_->rbUseDecimater->isChecked())
288  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
289  else if(tool_->rbUseMC->isChecked())
290  decimater_object = ptr::shared_ptr<McDecimaterType>(new McDecimaterType(*mesh));
291  else if(tool_->rbUseMixed->isChecked())
292  decimater_object = ptr::shared_ptr<MixedDecimaterType>(new MixedDecimaterType(*mesh));
293 
294 
295  // Remove old constraints
296  if(decimater->distance()) {
297  decimater->removeDistanceConstraint();
298  decimater_object->remove(hModHausdorff);
299  }
300  if(decimater->normalDeviation()) {
301  decimater->removeNormalDeviationConstraint();
302  decimater_object->remove(hModNormalDeviation);
303  }
304  if(decimater->normalFlipping()) {
305  decimater->removeNormalFlippingConstraint();
306  decimater_object->remove(hModNormalFlipping);
307  }
308  if(decimater->roundness()) {
309  decimater->removeRoundnessConstraint();
310  decimater_object->remove(hModRoundness);
311  }
312  if(decimater->aspectRatio()) {
313  decimater->removeAspectRatioConstraint();
314  decimater_object->remove(hModAspectRatio);
315  }
316  if(decimater->edgeLength()) {
317  decimater->removeEdgeLengthConstraint();
318  decimater_object->remove(hModEdgeLength);
319  }
320  if(decimater->independentSets()) {
321  decimater->removeIndependentSetsConstraint();
322  decimater_object->remove(hModIndependent);
323  }
324 
325  // set priority module: quadric, normal deviation or edge length
326  if (tool_->rbByDistance->isChecked()) {
327  decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
328  decimater_object->add( hModQuadric );
329  decimater_object->module( hModQuadric ).unset_max_err();
330  } else if (tool_->rbByNormalDeviation->isChecked()) {
331  decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
332  decimater_object->add(hModNormalDeviation);
333  decimater_object->module(hModNormalDeviation).set_binary(false);
334  } else if (tool_->rbByEdgeLength->isChecked()) {
335  decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
336  decimater_object->add(hModEdgeLength);
337  decimater_object->module(hModEdgeLength).set_binary(false);
338  }
339 
340  // and set new constraints
341  ptr::shared_ptr<DecimaterInit> decInit (new DecimaterInit);
342  if ( tool_->cbDistance->isChecked() ) {
343  if ( decimater_object->add( decInit->hModHausdorff ) || tool_->rbConstraintsOnly->isChecked() ) {
344  decimater->setDistanceConstraint( tool_->distance->value() );
345  decimater_object->module( decInit->hModHausdorff ).set_tolerance( decimater->distanceValue() );
346  }
347  }
348 
349  if ( tool_->cbNormalDev->isChecked() ) {
350  if ( decimater_object->add( decInit->hModNormalDeviation ) || tool_->rbConstraintsOnly->isChecked() ) {
351  decimater->setNormalDeviationConstraint( tool_->normalDeviation->value() );
352  decimater_object->module( decInit->hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
353  }
354  } else {
355  if ( decimater_object->add( decInit->hModNormalFlipping ) || tool_->rbConstraintsOnly->isChecked() ) {
356  decimater->setNormalFlippingConstraint();
357  }
358  }
359 
360  if ( tool_->cbRoundness->isChecked() ) {
361  if ( decimater_object->add( decInit->hModRoundness ) || tool_->rbConstraintsOnly->isChecked() ) {
362  decimater->setRoundnessConstraint( tool_->roundness->value() );
363  decimater_object->module( decInit->hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
364  }
365  }
366 
367  if ( tool_->cbAspectRatio->isChecked() ) {
368  if ( decimater_object->add( decInit->hModAspectRatio ) || tool_->rbConstraintsOnly->isChecked() ) {
369  decimater->setAspectRatioConstraint( tool_->aspectRatio->value() );
370  decimater_object->module( decInit->hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
371  }
372  }
373 
374  if ( tool_->cbEdgeLength->isChecked() ) {
375  if ( decimater_object->add( decInit->hModEdgeLength ) || tool_->rbConstraintsOnly->isChecked() ) {
376  decimater->setEdgeLengthConstraint( tool_->edgeLength->value() );
377  decimater_object->module( decInit->hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
378  }
379  }
380 
381  if ( tool_->cbIndependentSets->isChecked() ) {
382  if ( decimater_object->add( decInit->hModIndependent ) || tool_->rbConstraintsOnly->isChecked() ) {
383  decimater->setIndependentSetsConstraint();
384  }
385  }
386 
387 
388  // Initialize the decimater
389  if( ! decimater_object->initialize() ){
390  emit log(LOGWARN, tr("Decimater could not be initialized"));
391  return;
392  }
393 
394  decInit->decimater = decimater_object;
395  decInit->objId = obj->id();
396 
397  decimater_objects_.push_back(decInit);
398 }
399 
400 void DecimaterPlugin::slot_initialize_object(int obj_id, bool clear) {
401  if (clear)
402  decimater_objects_.clear();
403 
404  BaseObjectData *obj = 0;
405  PluginFunctions::getObject(obj_id, obj);
406  if (!obj) return;
407 
408  initialize_object(obj);
409 
410  tool_->pbDecimate->setEnabled(true);
411 }
412 
413 //-----------------------------------------------------------------------------
418 {
419 
420  if ( ! OpenFlipper::Options::gui())
421  return;
422 
423  //decimate
424  runningJobs_ = decimater_objects_.size();
425  for (std::vector< ptr::shared_ptr<DecimaterInit> >::iterator decIter = decimater_objects_.begin();
426  decIter != decimater_objects_.end(); ++decIter)
427  {
428  ptr::shared_ptr<DecimaterInit> decInit = *decIter;
429  ptr::shared_ptr<BaseDecimaterType> decimater = decInit->decimater;
430 
431  // set values for constraints
432  if ( tool_->cbDistance->isChecked() ) {
433  decimater->module( decInit->hModHausdorff ).set_tolerance( tool_->distance->value() );
434  }
435 
436  if ( tool_->cbNormalDev->isChecked() ) {
437  decimater->module( decInit->hModNormalDeviation ).set_normal_deviation( tool_->normalDeviation->value() );
438  }
439 
440  if ( tool_->cbRoundness->isChecked() ) {
441  decimater->module( decInit->hModRoundness ).set_min_roundness( tool_->roundness->value(), true );
442  }
443 
444  if ( tool_->cbAspectRatio->isChecked() ) {
445  decimater->module( decInit->hModAspectRatio ).set_aspect_ratio( tool_->aspectRatio->value() );
446  }
447 
448  if ( tool_->cbEdgeLength->isChecked() ) {
449  decimater->module( decInit->hModEdgeLength ).set_edge_length( tool_->edgeLength->value() );
450  }
451 
452  // fill data for the decimate thread
453  DecimateThread::Params params;
454  params.dec = (tool_->rbUseDecimater->isChecked()) ? dynamic_cast<DecimaterType*>(decimater.get()) : NULL;
455  params.mcDec = (tool_->rbUseMC->isChecked()) ? dynamic_cast<McDecimaterType*>(decimater.get()) : NULL;
456  params.mixedDec = (tool_->rbUseMixed->isChecked()) ? dynamic_cast<MixedDecimaterType*>(decimater.get()) : NULL;
457 
458  params.facesCount = (tool_->rbTriangles->isChecked()) ? tool_->trianglesCount->value() : -1;
459  params.verticesCount = (tool_->rbVertices->isChecked() ) ? tool_->verticesCount->value() : -1;
460  params.samples = tool_->randomSamplesCounter->value();
461  params.mc_factor = 1.0 - (tool_->mixedFactorCounter->value()*0.01);
462 
463  // create and start decimate thread
464  QString jobId = QString("Decimate_Object_%1").arg(decInit->objId);
465  DecimateThread* th = new DecimateThread(params, jobId, decInit->objId);
466  connect(th, SIGNAL(finished(QString)), this,SIGNAL(finishJob(QString)));
467  connect(th, SIGNAL(finished(QString)), this, SLOT(slot_decimate_finished(QString)));
468  connect(th, SIGNAL(state(QString, int)), this, SIGNAL(setJobState(QString, int)));
469  connect(this, SIGNAL(jobCanceled(QString)), th, SLOT(slotCancel(QString)));
470 
471  tool_->pbDecimate->setEnabled(false);
472  tool_->pbInitialize->setEnabled(false);
473 
474  emit startJob(jobId , QString("Decimate Object with Id %1").arg(decInit->objId) , 0, 100, false);
475 
476  th->start();
477  th->startProcessing();
478 
479  }
480 
481 
482 }
483 
484 void DecimaterPlugin::canceledJob (QString _job )
485 {
486  emit jobCanceled(_job);
487 }
488 
489 void DecimaterPlugin::slot_decimate_finished(QString _jobId)
490 {
491  //This function is executed by the main thread! but the sender is the finished thread
492  DecimateThread* thread = dynamic_cast<DecimateThread*>(sender());
493 
494  if (!thread)
495  return;
496  if (!thread->baseDecimater())
497  return;
498 
499  //update mesh
500  thread->baseDecimater()->mesh().garbage_collection();
501  thread->baseDecimater()->mesh().update_normals();
502 
503  emit updatedObject( thread->objectId() , UPDATE_TOPOLOGY );
504  emit createBackup( thread->objectId(), "Decimation");
505 
506  //cleanup when all threads are done
507  --runningJobs_;//running in main thread, so no race condition
508  if (runningJobs_ == 0)
509  {
510  tool_->pbDecimate->setEnabled(true);
511  tool_->pbInitialize->setEnabled(true);
512  emit updateView();
513  }
514 }
515 
516 
517 //-----------------------------------------------------------------------------
518 
519 void DecimaterPlugin::decimate(int _objID, QString _constraints) {
520  QStringList constraintList = _constraints.split(";");
521 
522  QVariantMap map;
523 
524  for ( auto i = 0 ; i < constraintList.size() ; ++i) {
525  const auto& currentConstraint = constraintList[i];
526 
527  int pos = currentConstraint.indexOf("=" );
528 
529  if ( pos == -1 ) {
530  emit log(LOGERR,"Wrong parameter format for decimater: " + currentConstraint);
531  return;
532  }
533 
534  QString constraintName = currentConstraint.left(pos);
535  QString constraintValue = currentConstraint.right(currentConstraint.size() - pos -1 );
536 
537  bool ok = false;
538 
539  double value = constraintValue.toDouble(&ok);
540 
541  if ( !ok) {
542  emit log(LOGERR,"Wrong parameter format for decimater. Conversion failed!");
543  emit log(LOGERR,"Got Name : " + constraintName );
544  emit log(LOGERR,"Got Value: " + constraintValue);
545  return;
546  }
547 // decimater.decimate(5,"random_samples=2;decimater_type=2;distance=0.0001")
548 
549  map[constraintName] = value;
550  }
551 
552  decimate(_objID,map);
553 
554 
555 }
556 
557 //-----------------------------------------------------------------------------
558 
559 void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
560 
561  BaseObjectData* baseObjectData;
562  if ( ! PluginFunctions::getObject(_objID,baseObjectData) ) {
563  emit log(LOGERR,tr("Unable to get Object"));
564  return;
565  }
566 
567  if ( baseObjectData->dataType() == DATA_TRIANGLE_MESH ) {
568  TriMeshObject* object = PluginFunctions::triMeshObject(baseObjectData);
569 
570  if ( object == 0 ) {
571  emit log(LOGWARN , tr("Unable to get object ( Only Triangle Meshes supported)"));
572  return;
573  }
574 
575  DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( object->objectData(DECIMATER) );
576 
577  TriMesh* mesh = PluginFunctions::triMesh(baseObjectData);
578 
579  if (decimater == 0){
580  decimater = new DecimaterInfo();
581  object->setObjectData(DECIMATER, decimater);
582  }
583 
584  // constraint handles for decimation
585  ModAspectRatioH hModAspectRatio;
586  ModEdgeLengthH hModEdgeLength;
587  ModHausdorffH hModHausdorff;
588  ModIndependentH hModIndependent;
589  ModNormalDeviationH hModNormalDeviation;
590  ModNormalFlippingH hModNormalFlipping;
591  ModQuadricH hModQuadric;
592  ModRoundnessH hModRoundness;
593 
594  // Create decimater
595  ptr::shared_ptr<BaseDecimaterType> decimater_object;
596  if (_constraints.contains("decimater_type"))
597  {
598  bool ok;
599  int value = _constraints["decimater_type"].toInt(&ok);
600  if (ok)
601  {
602  if (value == 0)
603  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
604  else if (value == 1)
605  decimater_object = ptr::shared_ptr<McDecimaterType>(new McDecimaterType(*mesh));
606  else if (value == 2)
607  decimater_object = ptr::shared_ptr<MixedDecimaterType>(new MixedDecimaterType(*mesh));
608  }
609 
610  }
611 
612  if (!decimater_object)
613  decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
614 
615  // Remove old constraints
616  if(decimater->distance()) {
617  decimater->removeDistanceConstraint();
618  decimater_object->remove(hModHausdorff);
619  }
620  if(decimater->normalDeviation()) {
621  decimater->removeNormalDeviationConstraint();
622  decimater_object->remove(hModNormalDeviation);
623  }
624  if(decimater->normalFlipping()) {
625  decimater->removeNormalFlippingConstraint();
626  decimater_object->remove(hModNormalFlipping);
627  }
628  if(decimater->roundness()) {
629  decimater->removeRoundnessConstraint();
630  decimater_object->remove(hModRoundness);
631  }
632  if(decimater->aspectRatio()) {
633  decimater->removeAspectRatioConstraint();
634  decimater_object->remove(hModAspectRatio);
635  }
636  if(decimater->edgeLength()) {
637  decimater->removeEdgeLengthConstraint();
638  decimater_object->remove(hModEdgeLength);
639  }
640  if(decimater->independentSets()) {
641  decimater->removeIndependentSetsConstraint();
642  decimater_object->remove(hModIndependent);
643  }
644 
645  // set priority module: quadric, normal deviation or edge length
646  if ( _constraints.contains("decimation_order") ){
647  bool ok;
648 
649  int value = _constraints["decimation_order"].toInt(&ok);
650 
651  if (ok) {
652  switch (value) {
653  case 0:
654  decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
655  decimater_object->add( hModQuadric );
656  decimater_object->module( hModQuadric ).unset_max_err();
657  break;
658  case 1:
659  decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
660  decimater_object->add(hModNormalDeviation);
661  decimater_object->module(hModNormalDeviation).set_binary(false);
662  break;
663  case 2:
664  decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
665  decimater_object->add(hModEdgeLength);
666  decimater_object->module(hModEdgeLength).set_binary(false);
667  break;
668  default:
669  emit log(LOGERR,tr("Invalid Decimation Order"));
670  return;
671  }
672  }
673  } else {
674  emit log(LOGERR,tr("No Decimation Order set"));
675  return;
676  }
677 
678  // stock options (triangle and vertices count) constraint
679  bool verticesCount = false;
680  bool trianglesCount = false;
681  int vertices = 0;
682  int triangles = 0;
683 
684  if ( _constraints.contains("vertices") ){
685 
686  bool ok;
687 
688  int value = _constraints["vertices"].toInt(&ok);
689 
690  if (ok){
691  verticesCount = true;
692  vertices = value;
693  }
694  } else if ( _constraints.contains("triangles") ){
695 
696  bool ok;
697 
698  int value = _constraints["triangles"].toInt(&ok);
699 
700  if (ok){
701  trianglesCount = true;
702  triangles = value;
703  }
704  }
705 
706  //distance constraint
707  if ( _constraints.contains("distance") ){
708 
709  bool ok;
710 
711  double value = _constraints["distance"].toDouble(&ok);
712 
713  if (ok) {
714  if ( decimater_object->add( hModHausdorff ) || (!verticesCount && !trianglesCount) ) {
715  decimater->setDistanceConstraint( value );
716  decimater_object->module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
717  }
718  }
719  }
720 
721  //normal deviation constraint
722  if ( _constraints.contains("normal_deviation") ){
723 
724  bool ok;
725 
726  int value = _constraints["normal_deviation"].toInt(&ok);
727 
728  if (ok) {
729  if ( decimater_object->add( hModNormalDeviation ) || (!verticesCount && !trianglesCount) ) {
730  decimater->setNormalDeviationConstraint( value );
731  decimater_object->module( hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
732  }
733  }
734  } else { // flipping constraint
735  if ( decimater_object->add( hModNormalFlipping ) || (!verticesCount && !trianglesCount) ) {
736  decimater->setNormalFlippingConstraint();
737  // decimater_object->module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() ); ?
738  }
739  }
740 
741  //roundness constraint
742  if ( _constraints.contains("roundness") ){
743 
744  bool ok;
745 
746  double value = _constraints["roundness"].toDouble(&ok);
747 
748  if (ok) {
749  if ( decimater_object->add( hModRoundness ) || (!verticesCount && !trianglesCount) ) {
750  decimater->setRoundnessConstraint( value );
751  decimater_object->module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
752  }
753  }
754  }
755 
756  //aspect ratio constraint
757  if ( _constraints.contains("aspect_ratio") ){
758 
759  bool ok;
760 
761  double value = _constraints["aspect_ratio"].toDouble(&ok);
762 
763  if (ok) {
764  if ( decimater_object->add( hModAspectRatio ) || (!verticesCount && !trianglesCount) ) {
765  decimater->setAspectRatioConstraint( value );
766  decimater_object->module( hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
767  }
768  }
769  }
770 
771  //edge length constraint
772  if ( _constraints.contains("edge_length") ){
773 
774  bool ok;
775 
776  double value = _constraints["edge_length"].toDouble(&ok);
777 
778  if (ok) {
779  if ( decimater_object->add( hModEdgeLength ) || (!verticesCount && !trianglesCount) ) {
780  decimater->setEdgeLengthConstraint( value );
781  decimater_object->module( hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
782  }
783  }
784  }
785 
786  //independent sets constraint
787  if ( _constraints.contains("independent_sets") ){
788 
789  bool value = _constraints["independent_sets"].toBool();
790 
791  if (value) {
792  if ( decimater_object->add( hModIndependent ) || (!verticesCount && !trianglesCount) ) {
793  decimater->setIndependentSetsConstraint();
794  }
795  }
796  }
797 
798  //init the decimater
799  if( ! decimater_object->initialize() ){
800  emit log(LOGWARN, tr("Decimater could not be initialized"));
801  return;
802  }
803 
804  float mc_factor = 0.5;
805  size_t randomSamples = 8;
806 
807  if (_constraints.contains("random_samples"))
808  {
809  bool ok;
810  unsigned value =_constraints["random_samples"].toUInt(&ok);
811  if (ok)
812  randomSamples = value;
813  }
814 
815  if (_constraints.contains("incremental_percentage"))
816  {
817  bool ok;
818  unsigned value =_constraints["incremental_percentage"].toUInt(&ok);
819  if (ok)
820  mc_factor = 1.f - (value*0.01f);
821  }
822 
823  //decimate
824  DecimaterType* dec = dynamic_cast<DecimaterType*>(decimater_object.get());
825  McDecimaterType* mcDec = dynamic_cast<McDecimaterType*>(decimater_object.get());
826  MixedDecimaterType* mixedDec = dynamic_cast<MixedDecimaterType*>(decimater_object.get());
827 
828  if(dec && !mixedDec)
829  {
830  if ( verticesCount )
831  dec->decimate_to(vertices);
832  else if (trianglesCount )
833  dec->decimate_to_faces(0, triangles);
834  else // constraints only
835  dec->decimate_to_faces(0, 1);
836  }
837  else if (mcDec && !mixedDec)
838  {
839  mcDec->set_samples(randomSamples);
840  if ( verticesCount )
841  mcDec->decimate_to(vertices);
842  else if (trianglesCount)
843  mcDec->decimate_to_faces(0, triangles);
844  else // constraints only
845  mcDec->decimate_to_faces(0, 1);
846  }
847  else if (mixedDec)
848  {
849  mixedDec->set_samples(randomSamples);
850  if ( verticesCount )
851  mixedDec->decimate_to(vertices,mc_factor);
852  else if (trianglesCount)
853  mixedDec->decimate_to_faces(0, triangles,mc_factor);
854  else // constraints only
855  mixedDec->decimate_to_faces(0, 1,mc_factor);
856  }else
857  {
858  emit log(LOGERR,tr("Could not find Decimater Type"));
859  }
860 
861  object->mesh()->garbage_collection();
862  object->mesh()->update_normals();
863 
864  emit updatedObject( baseObjectData->id() , UPDATE_TOPOLOGY);
865 
866  // Create backup
867  emit createBackup(_objID, "Decimation");
868 
869  // Create QVariantMap parameter string
870  QString param = "(" + (_constraints.contains("decimation_order") ? tr("decimation_order = %1").arg(_constraints["decimation_order"].toString()) : "") +
871  ", " + (_constraints.contains("distance") ? tr("distance = %1").arg(_constraints["distance"].toString()) : "") +
872  ", " + (_constraints.contains("normal_deviation") ? tr("normal_deviation = %1").arg(_constraints["normal_deviation"].toString()) : "") +
873  ", " + (_constraints.contains("edge_length") ? tr("edge_length = %1").arg(_constraints["edge_length"].toString()) : "") +
874  ", " + (_constraints.contains("roundness") ? tr("roundness = %1").arg(_constraints["roundness"].toString()) : "") +
875  ", " + (_constraints.contains("aspect_ratio") ? tr("aspect_ratio = %1").arg(_constraints["aspect_ratio"].toString()) : "") +
876  ", " + (_constraints.contains("independent_sets") ? tr("independent_sets = %1").arg(_constraints["independent_sets"].toString()) : "") +
877  ", " + (_constraints.contains("triangles") ? tr("triangles = %1").arg(_constraints["triangles"].toString()) : "") +
878  ", " + (_constraints.contains("vertices") ? tr("vertices = %1").arg(_constraints["vertices"].toString()) : "") + ")";
879 
880  emit scriptInfo( "decimate(" + QString::number(_objID) + ", " + param + ")" );
881 
882 
883  } else {
884  emit log(LOGERR,tr("Unsupported object type for decimater"));
885  return;
886  }
887 
888  emit updateView();
889 }
890 
891 //-----------------------------------------------------------------------------
892 
894 {
895  // Only update if tool is visible
896  if ( !OpenFlipper::Options::gui() || !tool_->isVisible() ) {
897  return;
898  }
899 
900  int max = 0;
901  int div = 0;
902 
903  bool ok;
904  emit functionExists( "infomeshobject" , "vertexCount(int)", ok ) ;
905  if (!ok)
906  {
907  tool_->currentNumVertices->setText ("<not available>");
908  return;
909  }
910 
912  o_it != PluginFunctions::objectsEnd(); ++o_it) {
913 
914 
915  max = std::max( RPC::callFunctionValue<int> ("infomeshobject" , "vertexCount",o_it->id()) , max );
916  div++;
917  }
918 
919  if (div <= 0)
920  tool_->currentNumVertices->setText ("<not available>");
921  else {
922  tool_->verticesCount->blockSignals(true);
923  tool_->verticesCountSlider->blockSignals(true);
924 
925  tool_->currentNumVertices->setText (QString::number(max));
926  tool_->verticesCount->setMaximum(max);
927  tool_->verticesCountSlider->setMaximum(max);
928 
929  if ( tool_->verticesCount->value() < 2 )
930  {
931  tool_->verticesCount->setValue( max / 2 );
932  tool_->verticesCountSlider->setValue( max / 2);
933  }
934 
935  tool_->verticesCount->blockSignals(false);
936  tool_->verticesCountSlider->blockSignals(false);
937  }
938 }
939 
940 //-----------------------------------------------------------------------------
941 
946  // only update if the tool is visible
947  if (!OpenFlipper::Options::gui() || !tool_->isVisible())
948  return;
949 
950  size_t max = 0;
951  int meshN = 0;
952 
954  o_it != PluginFunctions::objectsEnd(); ++o_it) {
955  TriMesh* mesh = PluginFunctions::triMesh(o_it->id());
956  max = std::max(mesh->n_faces(), max);
957  meshN++;
958  }
959 
960  tool_->trianglesCount->blockSignals(true);
961  tool_->trianglesCountSlider->blockSignals(true);
962 
963  tool_->trianglesCount->setMinimum(1);
964  tool_->trianglesCount->setMaximum(max);
965  tool_->trianglesCountSlider->setMinimum(1);
966  tool_->trianglesCountSlider->setMaximum(max);
967 
968  if (tool_->trianglesCount->value() < 2)
969  {
970  tool_->trianglesCount->setValue (max / 2 );
971  tool_->trianglesCountSlider->setValue( max / 2);
972  }
973 
974  tool_->trianglesCount->blockSignals(false);
975  tool_->trianglesCountSlider->blockSignals(false);
976 }
977 
978 //-----------------------------------------------------------------------------
979 
980 void DecimaterPlugin::slotObjectSelectionChanged(int /*_identifier*/)
981 {
984 }
985 //-----------------------------------------------------------------------------
986 
987 void DecimaterPlugin::objectDeleted(int _id)
988 {
989  slotDisableDecimation();
990 }
991 
992 //-----------------------------------------------------------------------------
993 
994 void DecimaterPlugin::slotAboutToRestore(int _id)
995 {
996  slotDisableDecimation();
997 }
998 
999 //-----------------------------------------------------------------------------
1000 
1001 void DecimaterPlugin::slotDisableDecimation()
1002 {
1003  if ( ! OpenFlipper::Options::gui())
1004  return;
1005 
1006  decimater_objects_.clear();
1007  tool_->pbDecimate->setEnabled(false);
1008 }
1009 
1010 //-----------------------------------------------------------------------------
1011 
1012 void DecimaterPlugin::slotObjectUpdated(int /*_identifier*/ , const UpdateType& _type )
1013 {
1014  if ( _type.contains(UPDATE_TOPOLOGY) ) {
1017  }
1018 }
1019 
1020 //-----------------------------------------------------------------------------
1021 
1022 // activate checkbox if value has changed
1023 void DecimaterPlugin::slotUpdateVertices()
1024 {
1025  tool_->rbVertices->setChecked (true);
1026 }
1027 
1028 //-----------------------------------------------------------------------------
1029 
1030 // activate checkbox if value has changed
1031 void DecimaterPlugin::slotUpdateTriangles()
1032 {
1033  tool_->rbTriangles->setChecked (true);
1034 }
1035 
1036 //-----------------------------------------------------------------------------
1037 
1038 // activate checkbox if value has changed
1039 void DecimaterPlugin::slotUpdateNormalDev()
1040 {
1041  tool_->cbNormalDev->setChecked (true);
1042 }
1043 
1044 //-----------------------------------------------------------------------------
1045 
1046 // activate checkbox if value has changed
1047 void DecimaterPlugin::slotUpdateEdgeLength()
1048 {
1049  tool_->cbEdgeLength->setChecked (true);
1050 }
1051 
1052 //-----------------------------------------------------------------------------
1053 
1054 // activate checkbox if value has changed
1056 {
1057  tool_->cbDistance->setChecked (true);
1058 }
1059 
Update type class.
Definition: UpdateType.hh:60
DecimaterPlugin()
Default constructor.
QString generateLink(const QString &_ref="", const QString &_site="index.html") const
generates a clickable link to the documentation for whatsThis Messages
int id() const
Definition: BaseObject.cc:190
void decimate(int _objID, QVariantMap _constraints)
decimate an object
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void canceledJob(QString _job)
A job has been canceled.
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
void slotUpdateNumTriangles()
gets and sets the current maximum number of triangles
void slotUpdateAspectRatio(int _value)
sync between values of aspect ratio slider and spinbox in the toolbox
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
void slot_decimate()
decimating called from button in toolbox
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:104
DecimaterToolbarWidget * tool_
Widget for Toolbox.
void setObjectData(QString _dataName, PerObjectData *_data)
Definition: BaseObject.cc:781
void startProcessing()
start processing
void slotUpdateRoundness(int _value)
roundness slider - spinbox sync
void slotUpdateNumVertices()
update number of vertices information
Predefined datatypes.
Definition: DataTypes.hh:83
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
void slotUpdateDistance()
slider / spinbox updates
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
void slot_initialize()
init called from button in toolbox
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:803
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60