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 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
void pluginsInitialized() override
Initialization of the plugin when it is loaded by the core.
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.