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