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
60 DecimaterPlugin::DecimaterPlugin() :
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()) {
73 tool_ = new DecimaterToolbarWidget();
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
153 void DecimaterPlugin::pluginsInitialized() {
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
182 void DecimaterPlugin::slotUpdateRoundness(int _value)
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
205 void DecimaterPlugin::slotUpdateRoundness(double _value)
206 {
207 tool_->roundnessSlider->setValue( (int) (_value * 100) );
208 tool_->cbRoundness->setChecked (true);
209 }
210
211 //-----------------------------------------------------------------------------
212
213
218 void DecimaterPlugin::slotUpdateAspectRatio(int _value)
219 {
220 tool_->aspectRatio->setValue( (double) _value / 100.0 );
221 tool_->cbAspectRatio->setChecked (true);
222 }
223
224
225 //-----------------------------------------------------------------------------
226
231 void DecimaterPlugin::slotUpdateAspectRatio(double _value)
232 {
233 tool_->aspectRatioSlider->setValue( (int) (_value * 100) );
234 tool_->cbAspectRatio->setChecked (true);
235 }
236 //-----------------------------------------------------------------------------
237
238
242 void DecimaterPlugin::slot_initialize()
243 {
244
245 if ( ! OpenFlipper::Options::gui())
246 return;
247
248 decimater_objects_.clear();
249
250 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DATA_TRIANGLE_MESH) ;
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
261 TriMeshObject* object = PluginFunctions::triMeshObject(obj);
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 //-----------------------------------------------------------------------------
417 void DecimaterPlugin::slot_decimate()
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
893 void DecimaterPlugin::slotUpdateNumVertices()
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
911 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
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
945 void DecimaterPlugin::slotUpdateNumTriangles() {
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
953 for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS, DataType(DATA_TRIANGLE_MESH));
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 {
982 slotUpdateNumVertices ();
983 slotUpdateNumTriangles ();
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) ) {
1015 slotUpdateNumVertices ();
1016 slotUpdateNumTriangles ();
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
1055 void DecimaterPlugin::slotUpdateDistance()
1056 {
1057 tool_->cbDistance->setChecked (true);
1058 }
1059
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
LOGWARN
Definition: LoggingInterface.hh:95
UpdateType
Update type class.
Definition: UpdateType.hh:60
DecimaterPlugin::DecimaterPlugin
DecimaterPlugin()
Default constructor.
Definition: DecimaterPlugin.cc:60
DecimaterPlugin::DecimaterInit
Definition: DecimaterPlugin.hh:195
WhatsThisGenerator::generateLink
QString generateLink(const QString &_ref="", const QString &_site="index.html") const
generates a clickable link to the documentation for whatsThis Messages
Definition: WhatsThisGenerator.cc:65
BaseObject::id
int id() const
Definition: BaseObject.cc:190
DecimateThread
Definition: DecimateThread.hh:57
DecimaterPlugin::decimate
void decimate(int _objID, QVariantMap _constraints)
decimate an object
Definition: DecimaterPlugin.cc:559
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
DecimaterPlugin::canceledJob
void canceledJob(QString _job)
A job has been canceled.
Definition: DecimaterPlugin.cc:484
PluginFunctions::triMeshObject
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
Definition: PluginFunctionsTriangleMesh.cc:156
DecimaterPlugin::slotUpdateNumTriangles
void slotUpdateNumTriangles()
gets and sets the current maximum number of triangles
Definition: DecimaterPlugin.cc:945
DecimaterPlugin::slotUpdateAspectRatio
void slotUpdateAspectRatio(int _value)
sync between values of aspect ratio slider and spinbox in the toolbox
Definition: DecimaterPlugin.cc:218
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:134
LOGERR
Definition: LoggingInterface.hh:96
DecimaterToolbarWidget
Definition: DecimaterToolbarWidget.hh:48
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
TriMeshObject
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
DecimaterPlugin::slot_decimate
void slot_decimate()
decimating called from button in toolbox
Definition: DecimaterPlugin.cc:417
DecimaterInfo
Definition: DecimaterInfo.hh:47
UpdateType::contains
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:104
DecimateThread::Params
Definition: DecimateThread.hh:66
DecimaterPlugin::tool_
DecimaterToolbarWidget * tool_
Widget for Toolbox.
Definition: DecimaterPlugin.hh:192
BaseObject::setObjectData
void setObjectData(QString _dataName, PerObjectData *_data)
Definition: BaseObject.cc:781
OpenFlipperThread::startProcessing
void startProcessing()
start processing
Definition: OpenFlipperThread.cc:112
DecimaterPlugin::slotUpdateRoundness
void slotUpdateRoundness(int _value)
roundness slider - spinbox sync
Definition: DecimaterPlugin.cc:182
DecimaterPlugin::slotUpdateNumVertices
void slotUpdateNumVertices()
update number of vertices information
Definition: DecimaterPlugin.cc:893
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
DecimaterPlugin::pluginsInitialized
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
Definition: DecimaterPlugin.cc:153
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:441
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:177
WhatsThisGenerator
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
Definition: WhatsThisGenerator.hh:65
DecimaterPlugin::slotUpdateDistance
void slotUpdateDistance()
slider / spinbox updates
Definition: DecimaterPlugin.cc:1055
UPDATE_TOPOLOGY
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
DecimaterPlugin::slot_initialize
void slot_initialize()
init called from button in toolbox
Definition: DecimaterPlugin.cc:242
BaseObject::objectData
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:803
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
BaseObjectData
Definition: BaseObjectData.hh:102