Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
72 DecimaterPlugin::DecimaterPlugin() :
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()) {
85 tool_ = new DecimaterToolbarWidget();
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
165 void DecimaterPlugin::pluginsInitialized() {
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
194 void DecimaterPlugin::slotUpdateRoundness(int _value)
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
217 void DecimaterPlugin::slotUpdateRoundness(double _value)
218 {
219 tool_->roundnessSlider->setValue( (int) (_value * 100) );
220 tool_->cbRoundness->setChecked (true);
221 }
222
223 //-----------------------------------------------------------------------------
224
225
230 void DecimaterPlugin::slotUpdateAspectRatio(int _value)
231 {
232 tool_->aspectRatio->setValue( (double) _value / 100.0 );
233 tool_->cbAspectRatio->setChecked (true);
234 }
235
236
237 //-----------------------------------------------------------------------------
238
243 void DecimaterPlugin::slotUpdateAspectRatio(double _value)
244 {
245 tool_->aspectRatioSlider->setValue( (int) (_value * 100) );
246 tool_->cbAspectRatio->setChecked (true);
247 }
248 //-----------------------------------------------------------------------------
249
250
254 void DecimaterPlugin::slot_initialize()
255 {
256
257 if ( ! OpenFlipper::Options::gui())
258 return;
259
260 decimater_objects_.clear();
261
262 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DATA_TRIANGLE_MESH) ;
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
273 TriMeshObject* object = PluginFunctions::triMeshObject(obj);
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 //-----------------------------------------------------------------------------
429 void DecimaterPlugin::slot_decimate()
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
865 void DecimaterPlugin::slotUpdateNumVertices()
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
883 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
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
917 void DecimaterPlugin::slotUpdateNumTriangles() {
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
925 for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS, DataType(DATA_TRIANGLE_MESH));
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 {
954 slotUpdateNumVertices ();
955 slotUpdateNumTriangles ();
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) ) {
987 slotUpdateNumVertices ();
988 slotUpdateNumTriangles ();
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
1027 void DecimaterPlugin::slotUpdateDistance()
1028 {
1029 tool_->cbDistance->setChecked (true);
1030 }
1031
1032 #if QT_VERSION < 0x050000
1033 Q_EXPORT_PLUGIN2(DecimaterPlugin , DecimaterPlugin );
1034 #endif
BaseObject::objectData
PerObjectData * objectData(QString _dataName)
Returns the object data pointer.
Definition: BaseObject.cc:814
DecimaterPlugin::slotUpdateRoundness
void slotUpdateRoundness(int _value)
roundness slider - spinbox sync
Definition: DecimaterPlugin.cc:194
LOGERR
Definition: LoggingInterface.hh:107
BaseObjectData
Definition: BaseObjectData.hh:105
DecimaterPlugin::slot_decimate
void slot_decimate()
decimating called from button in toolbox
Definition: DecimaterPlugin.cc:429
UpdateType::contains
bool contains(const UpdateType &_type) const
Check if this update contains the given UpdateType.
Definition: UpdateType.cc:111
UpdateType
Update type class.
Definition: UpdateType.hh:70
TriMeshObject
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
DecimateThread::Params
Definition: DecimateThread.hh:72
PluginFunctions::getObject
bool getObject(int _identifier, BSplineCurveObject *&_object)
Definition: PluginFunctionsBSplineCurve.cc:75
DecimaterPlugin::decimate
void decimate(int _objID, QVariantMap _constraints)
decimate an object
Definition: DecimaterPlugin.cc:531
DecimaterInfo
Definition: DecimaterInfo.hh:53
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
LOGWARN
Definition: LoggingInterface.hh:106
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:140
BaseObject::setObjectData
void setObjectData(QString _dataName, PerObjectData *_data)
Definition: BaseObject.cc:792
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:452
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:187
DecimaterToolbarWidget
Definition: DecimaterToolbarWidget.hh:62
DecimaterPlugin
Definition: DecimaterPlugin.hh:100
DecimaterPlugin::slotUpdateAspectRatio
void slotUpdateAspectRatio(int _value)
sync between values of aspect ratio slider and spinbox in the toolbox
Definition: DecimaterPlugin.cc:230
DecimaterPlugin::slot_initialize
void slot_initialize()
init called from button in toolbox
Definition: DecimaterPlugin.cc:254
DecimaterPlugin::slotUpdateNumVertices
void slotUpdateNumVertices()
update number of vertices information
Definition: DecimaterPlugin.cc:865
PluginFunctions::triMeshObject
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
Definition: PluginFunctionsTriangleMesh.cc:162
UPDATE_TOPOLOGY
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
WhatsThisGenerator
a class which provides an link generator for WhatsThisMessages linking to the user doc If you have an...
Definition: WhatsThisGenerator.hh:74
DecimaterPlugin::tool_
DecimaterToolbarWidget * tool_
Widget for Toolbox.
Definition: DecimaterPlugin.hh:200
DecimaterPlugin::DecimaterPlugin
DecimaterPlugin()
Default constructor.
Definition: DecimaterPlugin.cc:72
DecimaterPlugin::slotUpdateDistance
void slotUpdateDistance()
slider / spinbox updates
Definition: DecimaterPlugin.cc:1027
DataType
Predefined datatypes.
Definition: DataTypes.hh:96
DecimaterPlugin::canceledJob
void canceledJob(QString _job)
A job has been canceled.
Definition: DecimaterPlugin.cc:496
OpenFlipperThread::startProcessing
void startProcessing()
start processing
Definition: OpenFlipperThread.cc:118
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
DecimaterPlugin::pluginsInitialized
void pluginsInitialized()
Initialization of the plugin when it is loaded by the core.
Definition: DecimaterPlugin.cc:165
DecimateThread
Definition: DecimateThread.hh:63
BaseObject::id
int id() const
Definition: BaseObject.cc:201
DecimaterPlugin::slotUpdateNumTriangles
void slotUpdateNumTriangles()
gets and sets the current maximum number of triangles
Definition: DecimaterPlugin.cc:917