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