DecimaterPlugin.cc 35 KB
Newer Older
1 2 3
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
Jan Möbius's avatar
Jan Möbius committed
4
*      Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen       *
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
*                           www.openflipper.org                              *
*                                                                            *
*--------------------------------------------------------------------------- *
*  This file is part of OpenFlipper.                                         *
*                                                                            *
*  OpenFlipper is free software: you can redistribute it and/or modify       *
*  it under the terms of the GNU Lesser General Public License as            *
*  published by the Free Software Foundation, either version 3 of            *
*  the License, or (at your option) any later version with the               *
*  following exceptions:                                                     *
*                                                                            *
*  If other files instantiate templates or use macros                        *
*  or inline functions from this file, or you compile this file and          *
*  link it with other files to produce an executable, this file does         *
*  not by itself cause the resulting executable to be covered by the         *
*  GNU Lesser General Public License. This exception does not however        *
*  invalidate any other reasons why the executable file might be             *
*  covered by the GNU Lesser General Public License.                         *
*                                                                            *
*  OpenFlipper is distributed in the hope that it will be useful,            *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*  GNU Lesser General Public License for more details.                       *
*                                                                            *
*  You should have received a copy of the GNU LesserGeneral Public           *
*  License along with OpenFlipper. If not,                                   *
*  see <http://www.gnu.org/licenses/>.                                       *
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
Jan Möbius's avatar
Jan Möbius committed
37 38 39
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
40 41 42 43
*                                                                            *
\*===========================================================================*/


44 45 46 47 48
//=============================================================================
//
//  CLASS DecimaterPlugin - IMPLEMENTATION
//
//=============================================================================
49 50


51
//== INCLUDES =================================================================
52

Matthias Möller's avatar
Matthias Möller committed
53 54 55 56 57 58 59

#if QT_VERSION >= 0x050000 
  #include <QtWidgets>
#else
  #include <QtGui>
#endif

60
#include <memory>
61

62
#include "DecimaterPlugin.hh"
63

64 65 66 67
#include <iostream>
#include <ACG/GL/GLState.hh>
#include <QStringList>
#include <ACG/Scenegraph/ManipulatorNode.hh>
68

69
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
70

71
#define DECIMATER "DecimaterData"
72

73
//== IMPLEMENTATION ==========================================================
74

75 76 77 78 79 80 81
DecimaterPlugin::DecimaterPlugin() :
        tool_(0),
        toolIcon_(0)
{

}

82 83
void DecimaterPlugin::initializePlugin()
{
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

  if ( OpenFlipper::Options::gui()) {
    tool_ = new DecimaterToolbarWidget();
    QSize size(100, 100);
    tool_->resize(size);

    // connect signals->slots
    connect(tool_->pbDecimate,SIGNAL(clicked() ),this,SLOT(slot_decimate()));
    connect(tool_->pbInitialize,SIGNAL(clicked() ), this, SLOT(slot_initialize()));

    connect(tool_->roundness,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateRoundness(double)) );
    connect(tool_->roundnessSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateRoundness(int)) );
    connect(tool_->aspectRatio,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateAspectRatio(double)) );
    connect(tool_->aspectRatioSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateAspectRatio(int)) );
    connect(tool_->distance,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateDistance()) );
    connect(tool_->edgeLength,SIGNAL(valueChanged(double) ),this,SLOT(slotUpdateEdgeLength()) );
    connect(tool_->normalDeviation,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateNormalDev()) );
    connect(tool_->normalDeviationSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateNormalDev()) );
    connect(tool_->verticesCount,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateVertices()) );
    connect(tool_->verticesCountSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateVertices()) );
    connect(tool_->trianglesCount,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateTriangles()) );
    connect(tool_->trianglesCountSlider,SIGNAL(valueChanged(int) ),this,SLOT(slotUpdateTriangles()) );

    // Force update if the Toolbox gets visible
    connect(tool_, SIGNAL(showing()), this, SLOT( slotUpdateNumVertices() ) );
    connect(tool_, SIGNAL(showing()), this, SLOT( slotUpdateNumTriangles() ) );
    connect(tool_->mixedFactorCounter, SIGNAL(valueChanged(double)), this, SLOT(slotMixedCounterValueChanged(double)) );
    connect(tool_->mixedFactorSlider, SIGNAL(valueChanged(int)), this, SLOT(slotMixedSliderValueChanged(int)) );
    connect(tool_->cbDistance, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->cbNormalDev, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->cbEdgeLength, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->cbIndependentSets, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->cbRoundness, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->cbAspectRatio, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbByDistance, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbByEdgeLength, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbByNormalDeviation, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbConstraintsOnly, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbTriangles, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbUseDecimater, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbUseMC, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbUseMixed, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));
    connect(tool_->rbVertices, SIGNAL(toggled(bool)), this, SLOT(slotDisableDecimation()));

    toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"decimater.png");
    emit addToolbox( tr("Decimater") , tool_, toolIcon_ );

    WhatsThisGenerator generator("Decimater");

    tool_->pbDecimate->setWhatsThis(tool_->pbDecimate->whatsThis()+generator.generateLink("quick_tutorial"));
    tool_->pbInitialize->setWhatsThis(tool_->pbInitialize->whatsThis()+generator.generateLink("quick_tutorial"));
    tool_->rbUseDecimater->setWhatsThis(tool_->rbUseDecimater->whatsThis()+generator.generateLink("incremental"));
    tool_->rbUseMC->setWhatsThis(tool_->rbUseMC->whatsThis()+generator.generateLink("multiple_choice"));
    tool_->rbUseMixed->setWhatsThis(tool_->rbUseMixed->whatsThis()+generator.generateLink("mixed"));
    tool_->cbDistance->setWhatsThis(tool_->cbDistance->whatsThis()+generator.generateLink());
    tool_->cbNormalDev->setWhatsThis(tool_->cbNormalDev->whatsThis()+generator.generateLink());
    tool_->cbEdgeLength->setWhatsThis(tool_->cbEdgeLength->whatsThis()+generator.generateLink());
    tool_->cbIndependentSets->setWhatsThis(tool_->cbIndependentSets->whatsThis()+generator.generateLink());
    tool_->cbRoundness->setWhatsThis(tool_->cbRoundness->whatsThis()+generator.generateLink());
    tool_->cbAspectRatio->setWhatsThis(tool_->cbAspectRatio->whatsThis()+generator.generateLink());
    tool_->rbByDistance->setWhatsThis(tool_->rbByDistance->whatsThis()+generator.generateLink());
    tool_->rbByEdgeLength->setWhatsThis(tool_->rbByEdgeLength->whatsThis()+generator.generateLink());
    tool_->rbByNormalDeviation->setWhatsThis(tool_->rbByNormalDeviation->whatsThis()+generator.generateLink());
    tool_->rbConstraintsOnly->setWhatsThis(tool_->rbConstraintsOnly->whatsThis()+generator.generateLink());
    tool_->rbTriangles->setWhatsThis(tool_->rbTriangles->whatsThis()+generator.generateLink());
    tool_->rbVertices->setWhatsThis(tool_->rbVertices->whatsThis()+generator.generateLink());


    tool_->randomSamplesCounter->setWhatsThis(tool_->randomSamplesCounter->whatsThis()+generator.generateLink("multiple_choice"));
    tool_->mixedFactorCounter->setWhatsThis(tool_->mixedFactorCounter->whatsThis()+generator.generateLink("mixed"));
    tool_->roundness->setWhatsThis(tool_->roundness->whatsThis()+generator.generateLink());
    tool_->aspectRatio->setWhatsThis(tool_->aspectRatio->whatsThis()+generator.generateLink());
    tool_->distance->setWhatsThis(tool_->distance->whatsThis()+generator.generateLink());
    tool_->edgeLength->setWhatsThis(tool_->edgeLength->whatsThis()+generator.generateLink());
    tool_->normalDeviation->setWhatsThis(tool_->normalDeviation->whatsThis()+generator.generateLink());
  }
Matthias Möller's avatar
doc  
Matthias Möller committed
160

161 162
}

163
/** \brief Initialization of the plugin when it is loaded by the core
164
 *
165
 */
166
void DecimaterPlugin::pluginsInitialized() {
167

168 169
  emit setSlotDescription("decimate(int,QVariantMap)",tr("Decimate a given object"),
                          QString(tr("objectId,constraints")).split(","),
170
                          QString(tr("ID of an object; Object that can has one or more constraint properties (decimation_order,distance,edge_length,normal_deviation,roundness,aspect_ratio,independent_sets,vertices,triangles)")).split(";"));
171

172 173 174
  if ( OpenFlipper::Options::gui()) {
    tool_->decTypeOps->setVisible(false);
  }
175 176 177 178 179
}


//-----------------------------------------------------------------------------

180
/** \brief sync between values of roundness slider and spinbox in the toolbox
181
 *
182
 * @param _value new roundness value
183
 */
184
void DecimaterPlugin::slotUpdateRoundness(int _value)
185 186 187
{
  tool_->roundness->setValue( (double) _value / 100.0 );
  tool_->cbRoundness->setChecked (true);
188 189
}

190 191 192 193 194 195 196 197 198 199
void DecimaterPlugin::slotMixedCounterValueChanged(double _value)
{
  tool_->mixedFactorLabel->setText(QString::number(100-_value)+QString("%"));
  tool_->mixedFactorSlider->setValue(100-_value);
}
void DecimaterPlugin::slotMixedSliderValueChanged(int _value)
{
  tool_->mixedFactorLabel->setText(QString::number(_value)+QString("%"));
  tool_->mixedFactorCounter->setValue(100.0-_value);
}
200 201 202

//-----------------------------------------------------------------------------

203
/** \brief sync between values of roundness slider and spinbox in the toolbox
204
 *
205
 * @param _value new roundness value
206
 */
207
void DecimaterPlugin::slotUpdateRoundness(double _value)
208 209 210
{
  tool_->roundnessSlider->setValue( (int) (_value * 100) );
  tool_->cbRoundness->setChecked (true);
211 212 213 214
}

//-----------------------------------------------------------------------------

215 216 217 218 219

/** \brief sync between values of aspect ratio slider and spinbox in the toolbox
 *
 * @param _value new aspect ratio value
 */
220
void DecimaterPlugin::slotUpdateAspectRatio(int _value)
221 222 223 224 225 226 227 228 229 230 231 232
{
  tool_->aspectRatio->setValue( (double) _value / 100.0 );
  tool_->cbAspectRatio->setChecked (true);
}


//-----------------------------------------------------------------------------

/** \brief sync between values of aspect ratio slider and spinbox in the toolbox
 *
 * @param _value new aspect ratio value
 */
233
void DecimaterPlugin::slotUpdateAspectRatio(double _value)
234 235 236 237 238
{
  tool_->aspectRatioSlider->setValue( (int) (_value * 100) );
  tool_->cbAspectRatio->setChecked (true);
}
//-----------------------------------------------------------------------------
239
/** \brief Init called by toolbox
240 241
 *
 */
242
void DecimaterPlugin::slot_initialize()
243
{
244

245 246 247
  if ( ! OpenFlipper::Options::gui())
    return;

248 249
  decimater_objects_.clear();

250
  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DATA_TRIANGLE_MESH) ;
251
      o_it != PluginFunctions::objectsEnd(); ++o_it)  {
252

253 254
    //initialize
    TriMeshObject* object = PluginFunctions::triMeshObject(*o_it);
255

256 257
    if ( object == 0 )
      emit log(LOGWARN , tr("Unable to get object"));
258

259
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( o_it->objectData(DECIMATER) );
260

261
    TriMesh* mesh = PluginFunctions::triMesh(*o_it);
262

263 264 265 266
    if (decimater == 0){
      decimater = new DecimaterInfo();
      o_it->setObjectData(DECIMATER, decimater);
    }
267

268 269 270 271 272 273 274 275 276
    // constraint handles for decimation
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
    ModNormalDeviationH hModNormalDeviation;
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
277

278
    // Create decimater
279 280 281 282 283 284 285 286
    ptr::shared_ptr<BaseDecimaterType> decimater_object;
    if (tool_->rbUseDecimater->isChecked())
      decimater_object = ptr::shared_ptr<DecimaterType>(new DecimaterType(*mesh));
    else if(tool_->rbUseMC->isChecked())
      decimater_object = ptr::shared_ptr<McDecimaterType>(new McDecimaterType(*mesh));
    else if(tool_->rbUseMixed->isChecked())
      decimater_object = ptr::shared_ptr<MixedDecimaterType>(new MixedDecimaterType(*mesh));

287

288 289
    // Remove old constraints
    if(decimater->distance()) {
290 291
      decimater->removeDistanceConstraint();
      decimater_object->remove(hModHausdorff);
292 293
    }
    if(decimater->normalDeviation()) {
294 295
      decimater->removeNormalDeviationConstraint();
      decimater_object->remove(hModNormalDeviation);
296 297
    }
    if(decimater->normalFlipping()) {
298 299
      decimater->removeNormalFlippingConstraint();
      decimater_object->remove(hModNormalFlipping);
300 301
    }
    if(decimater->roundness()) {
302 303
      decimater->removeRoundnessConstraint();
      decimater_object->remove(hModRoundness);
304
    }
305 306
    if(decimater->aspectRatio()) {
      decimater->removeAspectRatioConstraint();
307
      decimater_object->remove(hModAspectRatio);
308 309 310
    }
    if(decimater->edgeLength()) {
      decimater->removeEdgeLengthConstraint();
311
      decimater_object->remove(hModEdgeLength);
312 313 314
    }
    if(decimater->independentSets()) {
      decimater->removeIndependentSetsConstraint();
315
      decimater_object->remove(hModIndependent);
316 317 318 319 320
    }

    // set priority module: quadric, normal deviation or edge length
    if (tool_->rbByDistance->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
321 322
      decimater_object->add( hModQuadric );
      decimater_object->module( hModQuadric ).unset_max_err();
323 324
    } else if (tool_->rbByNormalDeviation->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
325 326
      decimater_object->add(hModNormalDeviation);
      decimater_object->module(hModNormalDeviation).set_binary(false);
327 328
    } else if (tool_->rbByEdgeLength->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
329 330
      decimater_object->add(hModEdgeLength);
      decimater_object->module(hModEdgeLength).set_binary(false);
331
    }
332

333
    // and set new constraints
Matthias Möller's avatar
Matthias Möller committed
334
    ptr::shared_ptr<DecimaterInit> decInit (new DecimaterInit);
335
    if ( tool_->cbDistance->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
336
      if (  decimater_object->add( decInit->hModHausdorff ) || tool_->rbConstraintsOnly->isChecked() ) {
337
        decimater->setDistanceConstraint( tool_->distance->value() );
Matthias Möller's avatar
Matthias Möller committed
338
        decimater_object->module( decInit->hModHausdorff ).set_tolerance( decimater->distanceValue() );
339 340
      }
    }
341

342
    if ( tool_->cbNormalDev->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
343
      if (  decimater_object->add( decInit->hModNormalDeviation ) || tool_->rbConstraintsOnly->isChecked() ) {
344
        decimater->setNormalDeviationConstraint( tool_->normalDeviation->value() );
Matthias Möller's avatar
Matthias Möller committed
345
        decimater_object->module( decInit->hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
346 347
      }
    } else {
Matthias Möller's avatar
Matthias Möller committed
348
      if ( decimater_object->add( decInit->hModNormalFlipping ) || tool_->rbConstraintsOnly->isChecked() ) {
349
        decimater->setNormalFlippingConstraint();
350 351
      }
    }
352

353
    if ( tool_->cbRoundness->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
354
      if (  decimater_object->add( decInit->hModRoundness ) || tool_->rbConstraintsOnly->isChecked() ) {
355
        decimater->setRoundnessConstraint( tool_->roundness->value() );
Matthias Möller's avatar
Matthias Möller committed
356
        decimater_object->module( decInit->hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
357 358
      }
    }
359

360
    if ( tool_->cbAspectRatio->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
361
      if ( decimater_object->add( decInit->hModAspectRatio ) || tool_->rbConstraintsOnly->isChecked() ) {
362
        decimater->setAspectRatioConstraint( tool_->aspectRatio->value() );
Matthias Möller's avatar
Matthias Möller committed
363
        decimater_object->module( decInit->hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
364 365 366 367
      }
    }

    if ( tool_->cbEdgeLength->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
368
      if ( decimater_object->add( decInit->hModEdgeLength ) || tool_->rbConstraintsOnly->isChecked() ) {
369
        decimater->setEdgeLengthConstraint( tool_->edgeLength->value() );
Matthias Möller's avatar
Matthias Möller committed
370
        decimater_object->module( decInit->hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
371 372 373 374
      }
    }

    if ( tool_->cbIndependentSets->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
375
      if ( decimater_object->add( decInit->hModIndependent ) || tool_->rbConstraintsOnly->isChecked() ) {
376
        decimater->setIndependentSetsConstraint();
377 378 379
      }
    }

380

381 382 383 384 385
    // Initialize the decimater
    if( ! decimater_object->initialize() ){
      emit log(LOGWARN, tr("Decimater could not be initialized"));
      continue;
    }
Matthias Möller's avatar
Matthias Möller committed
386 387 388 389 390

    decInit->decimater = decimater_object;
    decInit->objId = o_it->id();

    decimater_objects_.push_back(decInit);
391 392 393 394 395 396 397 398 399
  }
  tool_->pbDecimate->setEnabled(true);
}
//-----------------------------------------------------------------------------
/** \brief Decimation called by toolbox
 *
 */
void DecimaterPlugin::slot_decimate()
{
Matthias Möller's avatar
Matthias Möller committed
400

401 402 403
  if ( ! OpenFlipper::Options::gui())
    return;

404
  //decimate
Matthias Möller's avatar
Matthias Möller committed
405
  for (std::vector< ptr::shared_ptr<DecimaterInit> >::iterator decIter = decimater_objects_.begin();
406 407
      decIter != decimater_objects_.end(); ++decIter)
  {
Matthias Möller's avatar
Matthias Möller committed
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
    ptr::shared_ptr<DecimaterInit> decInit = *decIter;
    ptr::shared_ptr<BaseDecimaterType> decimater = decInit->decimater;

    // set values for constraints
    if ( tool_->cbDistance->isChecked() ) {
        decimater->module( decInit->hModHausdorff ).set_tolerance( tool_->distance->value() );
    }

    if ( tool_->cbNormalDev->isChecked() ) {
      decimater->module( decInit->hModNormalDeviation ).set_normal_deviation( tool_->normalDeviation->value() );
    }

    if ( tool_->cbRoundness->isChecked() ) {
      decimater->module( decInit->hModRoundness ).set_min_roundness( tool_->roundness->value(), true );
    }

    if ( tool_->cbAspectRatio->isChecked() ) {
      decimater->module( decInit->hModAspectRatio ).set_aspect_ratio( tool_->aspectRatio->value() );
    }

    if ( tool_->cbEdgeLength->isChecked() ) {
      decimater->module( decInit->hModEdgeLength ).set_edge_length( tool_->edgeLength->value() );
    }

    DecimaterType* dec = dynamic_cast<DecimaterType*>(decimater.get());
    McDecimaterType* mcDec = dynamic_cast<McDecimaterType*>(decimater.get());
    MixedDecimaterType* mixedDec = dynamic_cast<MixedDecimaterType*>(decimater.get());
435

436
    if(dec && tool_->rbUseDecimater->isChecked())
437
    {
438 439 440 441 442
      if ( tool_->rbVertices->isChecked() )
        dec->decimate_to(tool_->verticesCount->value());
      else if (tool_->rbTriangles->isChecked() )
        dec->decimate_to_faces(0, tool_->trianglesCount->value());
      else // constraints only
Matthias Möller's avatar
Matthias Möller committed
443
      dec->decimate_to_faces(0, 1);
444
    }
445
    else if (mcDec && tool_->rbUseMC->isChecked())
446 447 448 449 450 451 452 453 454
    {
      mcDec->set_samples(tool_->randomSamplesCounter->value());
      if ( tool_->rbVertices->isChecked() )
        mcDec->decimate_to(tool_->verticesCount->value());
      else if (tool_->rbTriangles->isChecked() )
        mcDec->decimate_to_faces(0, tool_->trianglesCount->value());
      else // constraints only
        mcDec->decimate_to_faces(0, 1);
    }
455
    else if (mixedDec && tool_->rbUseMixed->isChecked())
456 457 458
    {
      float mc_factor = 1.0 - (tool_->mixedFactorCounter->value()*0.01);
      mixedDec->set_samples(tool_->randomSamplesCounter->value());
459

460 461 462 463 464 465
      if ( tool_->rbVertices->isChecked() )
        mixedDec->decimate_to(tool_->verticesCount->value(),mc_factor);
      else if (tool_->rbTriangles->isChecked() )
        mixedDec->decimate_to_faces(0, tool_->trianglesCount->value(),mc_factor);
      else // constraints only
        mixedDec->decimate_to_faces(0, 1,mc_factor);
Matthias Möller's avatar
Matthias Möller committed
466 467 468
    }else
    {
      emit log(LOGERR,tr("Could not find Decimater Type"));
469
    }
470

Matthias Möller's avatar
Matthias Möller committed
471
    TriMeshObject* object = PluginFunctions::triMeshObject(decInit->objId);
472

Matthias Möller's avatar
Matthias Möller committed
473 474
    decInit->decimater->mesh().garbage_collection();
    decInit->decimater->mesh().update_normals();
475
    object->update();
476

477
    // Create backup
Matthias Möller's avatar
Matthias Möller committed
478 479
    emit createBackup(decInit->objId, "Decimation");
    emit updatedObject( decInit->objId , UPDATE_TOPOLOGY );
480
  }
481

482
  emit updateView();
483 484
}

Jan Möbius's avatar
Jan Möbius committed
485 486 487

//-----------------------------------------------------------------------------

488
void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
489

490 491 492 493 494 495 496 497
  BaseObjectData* baseObjectData;
  if ( ! PluginFunctions::getObject(_objID,baseObjectData) ) {
    emit log(LOGERR,tr("Unable to get Object"));
    return;
  }

  if ( baseObjectData->dataType() == DATA_TRIANGLE_MESH ) {
    TriMeshObject* object = PluginFunctions::triMeshObject(baseObjectData);
498

499 500 501 502
    if ( object == 0 ) {
      emit log(LOGWARN , tr("Unable to get object ( Only Triangle Meshes supported)"));
      return;
    }
503

504
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( object->objectData(DECIMATER) );
505

506
    TriMesh* mesh = PluginFunctions::triMesh(baseObjectData);
507

508 509 510 511
    if (decimater == 0){
      decimater = new DecimaterInfo();
      object->setObjectData(DECIMATER, decimater);
    }
512

513
    // constraint handles for decimation
Jan Möbius's avatar
Jan Möbius committed
514 515 516 517
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
518
    ModNormalDeviationH hModNormalDeviation;
Jan Möbius's avatar
Jan Möbius committed
519 520 521
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
522

523 524 525 526 527
    // Create decimater
    DecimaterType decimater_object( *mesh );

    // Remove old constraints
    if(decimater->distance()) {
528 529
      decimater->removeDistanceConstraint();
      decimater_object.remove(hModHausdorff);
530 531
    }
    if(decimater->normalDeviation()) {
532 533 534 535 536 537
      decimater->removeNormalDeviationConstraint();
      decimater_object.remove(hModNormalDeviation);
    }
    if(decimater->normalFlipping()) {
      decimater->removeNormalFlippingConstraint();
      decimater_object.remove(hModNormalFlipping);
538 539
    }
    if(decimater->roundness()) {
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
      decimater->removeRoundnessConstraint();
      decimater_object.remove(hModRoundness);
    }
    if(decimater->aspectRatio()) {
      decimater->removeAspectRatioConstraint();
      decimater_object.remove(hModAspectRatio);
    }
    if(decimater->edgeLength()) {
      decimater->removeEdgeLengthConstraint();
      decimater_object.remove(hModEdgeLength);
    }
    if(decimater->independentSets()) {
      decimater->removeIndependentSetsConstraint();
      decimater_object.remove(hModIndependent);
    }

    // set priority module: quadric, normal deviation or edge length
    if ( _constraints.contains("decimation_order") ){
      bool ok;

      int value = _constraints["decimation_order"].toInt(&ok);

      if (ok) {
        switch (value) {
        case 0:
          decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
          decimater_object.add( hModQuadric );
567
          decimater_object.module( hModQuadric ).unset_max_err();
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
          break;
        case 1:
          decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
          decimater_object.add(hModNormalDeviation);
          decimater_object.module(hModNormalDeviation).set_binary(false);
          break;
        case 2:
          decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
          decimater_object.add(hModEdgeLength);
          decimater_object.module(hModEdgeLength).set_binary(false);
          break;
        default:
          emit log(LOGERR,tr("Invalid Decimation Order"));
          return;
        }
      }
    } else {
      emit log(LOGERR,tr("No Decimation Order set"));
      return;
    }

    // stock options (triangle and vertices count) constraint
    bool verticesCount = false;
    bool trianglesCount = false;
    int vertices = 0;
    int triangles = 0;

    if ( _constraints.contains("vertices") ){

      bool ok;

      int value = _constraints["vertices"].toInt(&ok);

      if (ok){
        verticesCount = true;
        vertices = value;
      }
    } else if ( _constraints.contains("triangles") ){

      bool ok;

      int value = _constraints["triangles"].toInt(&ok);

      if (ok){
        trianglesCount = true;
        triangles = value;
      }
615
    }
Jan Möbius's avatar
Jan Möbius committed
616

617 618
    //distance constraint
    if ( _constraints.contains("distance") ){
619

620 621 622 623 624
      bool ok;

      double value = _constraints["distance"].toDouble(&ok);

      if (ok) {
625
        if (  decimater_object.add( hModHausdorff ) || (!verticesCount && !trianglesCount)  ) {
626 627 628 629
            decimater->setDistanceConstraint( value );
            decimater_object.module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
        }
      }
630 631
    }

632 633
    //normal deviation constraint
    if ( _constraints.contains("normal_deviation") ){
634

635
      bool ok;
636

637
      int value = _constraints["normal_deviation"].toInt(&ok);
638

639
      if (ok) {
640
        if (  decimater_object.add( hModNormalDeviation ) || (!verticesCount && !trianglesCount)  ) {
641
            decimater->setNormalDeviationConstraint( value );
642
            decimater_object.module( hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
643 644
        }
      }
645 646 647 648 649
    } else { // flipping constraint
      if (  decimater_object.add( hModNormalFlipping ) || (!verticesCount && !trianglesCount)  ) {
        decimater->setNormalFlippingConstraint();
        // decimater_object.module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() ); ?
      }
650 651
    }

652 653 654 655 656 657 658 659
    //roundness constraint
    if ( _constraints.contains("roundness") ){

      bool ok;

      double value = _constraints["roundness"].toDouble(&ok);

      if (ok) {
660
        if (  decimater_object.add( hModRoundness ) || (!verticesCount && !trianglesCount)  ) {
661 662 663
            decimater->setRoundnessConstraint( value );
            decimater_object.module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
        }
664 665 666
      }
    }

667 668
    //aspect ratio constraint
    if ( _constraints.contains("aspect_ratio") ){
669

670 671 672 673 674 675 676 677 678 679 680 681 682 683
      bool ok;

      double value = _constraints["aspect_ratio"].toDouble(&ok);

      if (ok) {
        if (  decimater_object.add( hModAspectRatio ) || (!verticesCount && !trianglesCount)  ) {
            decimater->setAspectRatioConstraint( value );
            decimater_object.module( hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
        }
      }
    }

    //edge length constraint
    if ( _constraints.contains("edge_length") ){
684

685
      bool ok;
686

687
      double value = _constraints["edge_length"].toDouble(&ok);
688

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
      if (ok) {
        if (  decimater_object.add( hModEdgeLength ) || (!verticesCount && !trianglesCount)  ) {
            decimater->setEdgeLengthConstraint( value );
            decimater_object.module( hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
        }
      }
    }

    //independent sets constraint
    if ( _constraints.contains("independent_sets") ){

      bool value = _constraints["independent_sets"].toBool();

      if (value) {
        if (  decimater_object.add( hModIndependent ) || (!verticesCount && !trianglesCount)  ) {
            decimater->setIndependentSetsConstraint();
        }
706 707 708 709 710 711 712 713 714 715
      }
    }

    //init the decimater
    if( ! decimater_object.initialize() ){
      emit log(LOGWARN, tr("Decimater could not be initialized"));
      return;
    }

    //decimate
716 717 718 719
    if ( verticesCount )
      decimater_object.decimate_to( vertices ); // do decimation (vertices)
    else if (trianglesCount )
      decimater_object.decimate_to_faces(0, triangles); // do decimation (triangles)
720
    else
721
      decimater_object.decimate_to_faces(0, 1); // do decimation
722 723 724 725 726 727 728

    object->mesh()->garbage_collection();
    object->mesh()->update_normals();
    object->update();

    // Create backup
    emit createBackup(_objID, "Decimation");
729

730
    // Create QVariantMap parameter string
731 732
    QString param = "("  + (_constraints.contains("decimation_order") ? tr("decimation_order =  %1").arg(_constraints["decimation_order"].toString()) : "") +
                    ", " + (_constraints.contains("distance") ? tr("distance = %1").arg(_constraints["distance"].toString()) : "") +
733
                    ", " + (_constraints.contains("normal_deviation") ? tr("normal_deviation = %1").arg(_constraints["normal_deviation"].toString()) : "") +
734
                    ", " + (_constraints.contains("edge_length") ? tr("edge_length = %1").arg(_constraints["edge_length"].toString()) : "") +
735
                    ", " + (_constraints.contains("roundness") ? tr("roundness = %1").arg(_constraints["roundness"].toString()) : "") +
736 737 738
                    ", " + (_constraints.contains("aspect_ratio") ? tr("aspect_ratio = %1").arg(_constraints["aspect_ratio"].toString()) : "") +
                    ", " + (_constraints.contains("independent_sets") ? tr("independent_sets = %1").arg(_constraints["independent_sets"].toString()) : "") +
                    ", " + (_constraints.contains("triangles") ? tr("triangles = %1").arg(_constraints["triangles"].toString()) : "") +
739
                    ", " + (_constraints.contains("vertices") ? tr("vertices = %1").arg(_constraints["vertices"].toString()) : "") + ")";
740

741
    emit scriptInfo( "decimate(" + QString::number(_objID) + ", " + param + ")" );
742

743 744 745 746 747
    emit updatedObject( baseObjectData->id() , UPDATE_TOPOLOGY);

  } else {
    emit log(LOGERR,tr("Unsupported object type for decimater"));
    return;
748 749 750 751 752 753 754
  }

  emit updateView();
}

//-----------------------------------------------------------------------------

755 756 757
void DecimaterPlugin::slotUpdateNumVertices()
{
  // Only update if tool is visible
758
  if ( !OpenFlipper::Options::gui() || !tool_->isVisible() ) {
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
    return;
  }

  int max = 0;
  int div = 0;

  bool ok;
  emit functionExists( "infomeshobject" , "vertexCount(int)", ok  ) ;
  if (!ok)
  {
    tool_->currentNumVertices->setText ("<not available>");
    return;
  }

  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
                                        o_it != PluginFunctions::objectsEnd(); ++o_it)  {


    max = std::max( RPC::callFunctionValue<int>   ("infomeshobject" , "vertexCount",o_it->id()) , max );
    div++;
  }

  if (div <= 0)
    tool_->currentNumVertices->setText ("<not available>");
  else {
784 785 786
    tool_->verticesCount->blockSignals(true);
    tool_->verticesCountSlider->blockSignals(true);

787 788 789
    tool_->currentNumVertices->setText (QString::number(max));
    tool_->verticesCount->setMaximum(max);
    tool_->verticesCountSlider->setMaximum(max);
790

791
    if ( tool_->verticesCount->value() < 2 )
792
    {
793
      tool_->verticesCount->setValue( max / 2 );
794 795
      tool_->verticesCountSlider->setValue( max / 2);
    }
796 797 798

    tool_->verticesCount->blockSignals(false);
    tool_->verticesCountSlider->blockSignals(false);
799 800 801 802 803
  }
}

//-----------------------------------------------------------------------------

804 805 806 807 808
/** \brief gets and sets the current maximum number of triangles
 *
 */
void DecimaterPlugin::slotUpdateNumTriangles() {
  // only update if the tool is visible
809
  if (!OpenFlipper::Options::gui() || !tool_->isVisible())
810 811
    return;

812
  size_t max = 0;
813 814 815 816 817 818 819 820 821
  int meshN = 0;

  for (PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS, DataType(DATA_TRIANGLE_MESH));
                                       o_it != PluginFunctions::objectsEnd(); ++o_it) {
    TriMesh* mesh = PluginFunctions::triMesh(o_it->id());
    max = std::max(mesh->n_faces(), max);
    meshN++;
  }

822 823 824
  tool_->trianglesCount->blockSignals(true);
  tool_->trianglesCountSlider->blockSignals(true);

825 826 827 828 829 830
  tool_->trianglesCount->setMinimum(1);
  tool_->trianglesCount->setMaximum(max);
  tool_->trianglesCountSlider->setMinimum(1);
  tool_->trianglesCountSlider->setMaximum(max);

  if (tool_->trianglesCount->value() < 2)
831 832 833 834
  {
    tool_->trianglesCount->setValue (max / 2 );
    tool_->trianglesCountSlider->setValue( max / 2);
  }
835 836 837

  tool_->trianglesCount->blockSignals(false);
  tool_->trianglesCountSlider->blockSignals(false);
838 839 840 841
}

//-----------------------------------------------------------------------------

842 843 844
void DecimaterPlugin::slotObjectSelectionChanged(int /*_identifier*/)
{
  slotUpdateNumVertices ();
845
  slotUpdateNumTriangles ();
846
}
847 848 849 850
//-----------------------------------------------------------------------------

void DecimaterPlugin::objectDeleted(int _id)
{
Matthias Möller's avatar
Matthias Möller committed
851
  slotDisableDecimation();
852
}
853 854 855

//-----------------------------------------------------------------------------

856
void DecimaterPlugin::slotAboutToRestore(int _id)
Matthias Möller's avatar
Matthias Möller committed
857 858 859 860 861 862 863
{
  slotDisableDecimation();
}

//-----------------------------------------------------------------------------

void DecimaterPlugin::slotDisableDecimation()
864
{
865 866 867
  if ( ! OpenFlipper::Options::gui())
    return;

868
  decimater_objects_.clear();
Matthias Möller's avatar
Matthias Möller committed
869
  tool_->pbDecimate->setEnabled(false);
870 871 872 873
}

//-----------------------------------------------------------------------------

874
void DecimaterPlugin::slotObjectUpdated(int /*_identifier*/ , const UpdateType& _type )
875
{
876
  if ( _type.contains(UPDATE_TOPOLOGY) ) {
877
    slotUpdateNumVertices ();
878 879
    slotUpdateNumTriangles ();
  }
880 881 882 883 884
}

//-----------------------------------------------------------------------------

// activate checkbox if value has changed
885
void DecimaterPlugin::slotUpdateVertices()
886
{
887 888 889 890 891 892
  tool_->rbVertices->setChecked (true);
}

//-----------------------------------------------------------------------------

// activate checkbox if value has changed
893
void DecimaterPlugin::slotUpdateTriangles()
894 895
{
  tool_->rbTriangles->setChecked (true);
896 897 898 899 900
}

//-----------------------------------------------------------------------------

// activate checkbox if value has changed
901
void DecimaterPlugin::slotUpdateNormalDev()
902 903 904 905 906 907
{
  tool_->cbNormalDev->setChecked (true);
}

//-----------------------------------------------------------------------------

908
// activate checkbox if value has changed
909
void DecimaterPlugin::slotUpdateEdgeLength()
910 911 912 913 914 915
{
  tool_->cbEdgeLength->setChecked (true);
}

//-----------------------------------------------------------------------------

916
// activate checkbox if value has changed
917
void DecimaterPlugin::slotUpdateDistance()
918 919 920 921
{
  tool_->cbDistance->setChecked (true);
}

Matthias Möller's avatar
Matthias Möller committed
922 923 924
#if QT_VERSION < 0x050000
  Q_EXPORT_PLUGIN2(DecimaterPlugin , DecimaterPlugin );
#endif