DecimaterPlugin.cc 35.4 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

53 54 55 56
#include "DecimaterPlugin.hh"
#include <ACG/GL/GLState.hh>
#include <ACG/Scenegraph/ManipulatorNode.hh>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
Matthias Möller's avatar
Matthias Möller committed
57 58 59 60 61 62 63

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

64
#include <memory>
65
#include <iostream>
66

67
#include <QStringList>
68 69


70
#define DECIMATER "DecimaterData"
71

72
//== IMPLEMENTATION ==========================================================
73

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

}

81 82
void DecimaterPlugin::initializePlugin()
{
83 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

  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
159

160 161
}

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

167 168
  emit setSlotDescription("decimate(int,QVariantMap)",tr("Decimate a given object"),
                          QString(tr("objectId,constraints")).split(","),
169
                          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(";"));
170

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


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

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

189 190 191 192 193 194 195 196 197 198
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);
}
199 200 201

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

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

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

214 215 216 217 218

/** \brief sync between values of aspect ratio slider and spinbox in the toolbox
 *
 * @param _value new aspect ratio value
 */
219
void DecimaterPlugin::slotUpdateAspectRatio(int _value)
220 221 222 223 224 225 226 227 228 229 230 231
{
  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
 */
232
void DecimaterPlugin::slotUpdateAspectRatio(double _value)
233 234 235 236 237
{
  tool_->aspectRatioSlider->setValue( (int) (_value * 100) );
  tool_->cbAspectRatio->setChecked (true);
}
//-----------------------------------------------------------------------------
238 239


240
/** \brief Init called by toolbox
241 242
 *
 */
243
void DecimaterPlugin::slot_initialize()
244
{
245

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

249 250
  decimater_objects_.clear();

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

254 255 256 257 258 259 260
	  initialize_object(*o_it);

  }
  tool_->pbDecimate->setEnabled(true);
}

void DecimaterPlugin::initialize_object(BaseObjectData *obj) {
261
    //initialize
262
    TriMeshObject* object = PluginFunctions::triMeshObject(obj);
263

264 265
    if ( object == 0 )
      emit log(LOGWARN , tr("Unable to get object"));
266

267
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( obj->objectData(DECIMATER) );
268

269
    TriMesh* mesh = PluginFunctions::triMesh(obj);
270

271 272
    if (decimater == 0){
      decimater = new DecimaterInfo();
273
      obj->setObjectData(DECIMATER, decimater);
274
    }
275

276 277 278 279 280 281 282 283 284
    // constraint handles for decimation
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
    ModNormalDeviationH hModNormalDeviation;
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
285

286
    // Create decimater
287 288 289 290 291 292 293 294
    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));

295

296 297
    // Remove old constraints
    if(decimater->distance()) {
298 299
      decimater->removeDistanceConstraint();
      decimater_object->remove(hModHausdorff);
300 301
    }
    if(decimater->normalDeviation()) {
302 303
      decimater->removeNormalDeviationConstraint();
      decimater_object->remove(hModNormalDeviation);
304 305
    }
    if(decimater->normalFlipping()) {
306 307
      decimater->removeNormalFlippingConstraint();
      decimater_object->remove(hModNormalFlipping);
308 309
    }
    if(decimater->roundness()) {
310 311
      decimater->removeRoundnessConstraint();
      decimater_object->remove(hModRoundness);
312
    }
313 314
    if(decimater->aspectRatio()) {
      decimater->removeAspectRatioConstraint();
315
      decimater_object->remove(hModAspectRatio);
316 317 318
    }
    if(decimater->edgeLength()) {
      decimater->removeEdgeLengthConstraint();
319
      decimater_object->remove(hModEdgeLength);
320 321 322
    }
    if(decimater->independentSets()) {
      decimater->removeIndependentSetsConstraint();
323
      decimater_object->remove(hModIndependent);
324 325 326 327 328
    }

    // set priority module: quadric, normal deviation or edge length
    if (tool_->rbByDistance->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::DISTANCE);
329 330
      decimater_object->add( hModQuadric );
      decimater_object->module( hModQuadric ).unset_max_err();
331 332
    } else if (tool_->rbByNormalDeviation->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::NORMALDEV);
333 334
      decimater_object->add(hModNormalDeviation);
      decimater_object->module(hModNormalDeviation).set_binary(false);
335 336
    } else if (tool_->rbByEdgeLength->isChecked()) {
      decimater->setDecimationOrder(DecimaterInfo::EDGELENGTH);
337 338
      decimater_object->add(hModEdgeLength);
      decimater_object->module(hModEdgeLength).set_binary(false);
339
    }
340

341
    // and set new constraints
Matthias Möller's avatar
Matthias Möller committed
342
    ptr::shared_ptr<DecimaterInit> decInit (new DecimaterInit);
343
    if ( tool_->cbDistance->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
344
      if (  decimater_object->add( decInit->hModHausdorff ) || tool_->rbConstraintsOnly->isChecked() ) {
345
        decimater->setDistanceConstraint( tool_->distance->value() );
Matthias Möller's avatar
Matthias Möller committed
346
        decimater_object->module( decInit->hModHausdorff ).set_tolerance( decimater->distanceValue() );
347 348
      }
    }
349

350
    if ( tool_->cbNormalDev->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
351
      if (  decimater_object->add( decInit->hModNormalDeviation ) || tool_->rbConstraintsOnly->isChecked() ) {
352
        decimater->setNormalDeviationConstraint( tool_->normalDeviation->value() );
Matthias Möller's avatar
Matthias Möller committed
353
        decimater_object->module( decInit->hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
354 355
      }
    } else {
Matthias Möller's avatar
Matthias Möller committed
356
      if ( decimater_object->add( decInit->hModNormalFlipping ) || tool_->rbConstraintsOnly->isChecked() ) {
357
        decimater->setNormalFlippingConstraint();
358 359
      }
    }
360

361
    if ( tool_->cbRoundness->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
362
      if (  decimater_object->add( decInit->hModRoundness ) || tool_->rbConstraintsOnly->isChecked() ) {
363
        decimater->setRoundnessConstraint( tool_->roundness->value() );
Matthias Möller's avatar
Matthias Möller committed
364
        decimater_object->module( decInit->hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
365 366
      }
    }
367

368
    if ( tool_->cbAspectRatio->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
369
      if ( decimater_object->add( decInit->hModAspectRatio ) || tool_->rbConstraintsOnly->isChecked() ) {
370
        decimater->setAspectRatioConstraint( tool_->aspectRatio->value() );
Matthias Möller's avatar
Matthias Möller committed
371
        decimater_object->module( decInit->hModAspectRatio ).set_aspect_ratio( decimater->aspectRatioValue() );
372 373 374 375
      }
    }

    if ( tool_->cbEdgeLength->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
376
      if ( decimater_object->add( decInit->hModEdgeLength ) || tool_->rbConstraintsOnly->isChecked() ) {
377
        decimater->setEdgeLengthConstraint( tool_->edgeLength->value() );
Matthias Möller's avatar
Matthias Möller committed
378
        decimater_object->module( decInit->hModEdgeLength ).set_edge_length( decimater->edgeLengthValue() );
379 380 381 382
      }
    }

    if ( tool_->cbIndependentSets->isChecked() ) {
Matthias Möller's avatar
Matthias Möller committed
383
      if ( decimater_object->add( decInit->hModIndependent ) || tool_->rbConstraintsOnly->isChecked() ) {
384
        decimater->setIndependentSetsConstraint();
385 386 387
      }
    }

388

389 390 391
    // Initialize the decimater
    if( ! decimater_object->initialize() ){
      emit log(LOGWARN, tr("Decimater could not be initialized"));
392
      return;
393
    }
Matthias Möller's avatar
Matthias Möller committed
394 395

    decInit->decimater = decimater_object;
396
    decInit->objId = obj->id();
Matthias Möller's avatar
Matthias Möller committed
397 398

    decimater_objects_.push_back(decInit);
399
}
400 401 402 403 404 405 406 407 408 409 410 411 412 413

void DecimaterPlugin::slot_initialize_object(int obj_id, bool clear) {
	if (clear)
		decimater_objects_.clear();

	BaseObjectData *obj = 0;
	PluginFunctions::getObject(obj_id, obj);
	if (!obj) return;

	initialize_object(obj);

	tool_->pbDecimate->setEnabled(true);
}

414 415 416 417 418 419
//-----------------------------------------------------------------------------
/** \brief Decimation called by toolbox
 *
 */
void DecimaterPlugin::slot_decimate()
{
Matthias Möller's avatar
Matthias Möller committed
420

421 422 423
  if ( ! OpenFlipper::Options::gui())
    return;

424
  //decimate
Matthias Möller's avatar
Matthias Möller committed
425
  for (std::vector< ptr::shared_ptr<DecimaterInit> >::iterator decIter = decimater_objects_.begin();
426 427
      decIter != decimater_objects_.end(); ++decIter)
  {
Matthias Möller's avatar
Matthias Möller committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
    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());
455

456
    if(dec && tool_->rbUseDecimater->isChecked())
457
    {
458 459 460 461 462
      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
463
      dec->decimate_to_faces(0, 1);
464
    }
465
    else if (mcDec && tool_->rbUseMC->isChecked())
466 467 468 469 470 471 472 473 474
    {
      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);
    }
475
    else if (mixedDec && tool_->rbUseMixed->isChecked())
476 477 478
    {
      float mc_factor = 1.0 - (tool_->mixedFactorCounter->value()*0.01);
      mixedDec->set_samples(tool_->randomSamplesCounter->value());
479

480 481 482 483 484 485
      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
486 487 488
    }else
    {
      emit log(LOGERR,tr("Could not find Decimater Type"));
489
    }
490

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

Matthias Möller's avatar
Matthias Möller committed
493 494
    decInit->decimater->mesh().garbage_collection();
    decInit->decimater->mesh().update_normals();
495
    object->update();
496

497
    // Create backup
Matthias Möller's avatar
Matthias Möller committed
498 499
    emit createBackup(decInit->objId, "Decimation");
    emit updatedObject( decInit->objId , UPDATE_TOPOLOGY );
500
  }
501

502
  emit updateView();
503 504
}

Jan Möbius's avatar
Jan Möbius committed
505 506 507

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

508
void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
509

510 511 512 513 514 515 516 517
  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);
518

519 520 521 522
    if ( object == 0 ) {
      emit log(LOGWARN , tr("Unable to get object ( Only Triangle Meshes supported)"));
      return;
    }
523

524
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( object->objectData(DECIMATER) );
525

526
    TriMesh* mesh = PluginFunctions::triMesh(baseObjectData);
527

528 529 530 531
    if (decimater == 0){
      decimater = new DecimaterInfo();
      object->setObjectData(DECIMATER, decimater);
    }
532

533
    // constraint handles for decimation
Jan Möbius's avatar
Jan Möbius committed
534 535 536 537
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
538
    ModNormalDeviationH hModNormalDeviation;
Jan Möbius's avatar
Jan Möbius committed
539 540 541
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
542

543 544 545 546 547
    // Create decimater
    DecimaterType decimater_object( *mesh );

    // Remove old constraints
    if(decimater->distance()) {
548 549
      decimater->removeDistanceConstraint();
      decimater_object.remove(hModHausdorff);
550 551
    }
    if(decimater->normalDeviation()) {
552 553 554 555 556 557
      decimater->removeNormalDeviationConstraint();
      decimater_object.remove(hModNormalDeviation);
    }
    if(decimater->normalFlipping()) {
      decimater->removeNormalFlippingConstraint();
      decimater_object.remove(hModNormalFlipping);
558 559
    }
    if(decimater->roundness()) {
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
      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 );
587
          decimater_object.module( hModQuadric ).unset_max_err();
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 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
          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;
      }
635
    }
Jan Möbius's avatar
Jan Möbius committed
636

637 638
    //distance constraint
    if ( _constraints.contains("distance") ){
639

640 641 642 643 644
      bool ok;

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

      if (ok) {
645
        if (  decimater_object.add( hModHausdorff ) || (!verticesCount && !trianglesCount)  ) {
646 647 648 649
            decimater->setDistanceConstraint( value );
            decimater_object.module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
        }
      }
650 651
    }

652 653
    //normal deviation constraint
    if ( _constraints.contains("normal_deviation") ){
654

655
      bool ok;
656

657
      int value = _constraints["normal_deviation"].toInt(&ok);
658

659
      if (ok) {
660
        if (  decimater_object.add( hModNormalDeviation ) || (!verticesCount && !trianglesCount)  ) {
661
            decimater->setNormalDeviationConstraint( value );
662
            decimater_object.module( hModNormalDeviation ).set_normal_deviation( decimater->normalDeviationValue() );
663 664
        }
      }
665 666 667 668 669
    } else { // flipping constraint
      if (  decimater_object.add( hModNormalFlipping ) || (!verticesCount && !trianglesCount)  ) {
        decimater->setNormalFlippingConstraint();
        // decimater_object.module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() ); ?
      }
670 671
    }

672 673 674 675 676 677 678 679
    //roundness constraint
    if ( _constraints.contains("roundness") ){

      bool ok;

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

      if (ok) {
680
        if (  decimater_object.add( hModRoundness ) || (!verticesCount && !trianglesCount)  ) {
681 682 683
            decimater->setRoundnessConstraint( value );
            decimater_object.module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
        }
684 685 686
      }
    }

687 688
    //aspect ratio constraint
    if ( _constraints.contains("aspect_ratio") ){
689

690 691 692 693 694 695 696 697 698 699 700 701 702 703
      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") ){
704

705
      bool ok;
706

707
      double value = _constraints["edge_length"].toDouble(&ok);
708

709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
      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();
        }
726 727 728 729 730 731 732 733 734 735
      }
    }

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

    //decimate
736 737 738 739
    if ( verticesCount )
      decimater_object.decimate_to( vertices ); // do decimation (vertices)
    else if (trianglesCount )
      decimater_object.decimate_to_faces(0, triangles); // do decimation (triangles)
740
    else
741
      decimater_object.decimate_to_faces(0, 1); // do decimation
742 743 744 745 746 747 748

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

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

750
    // Create QVariantMap parameter string
751 752
    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()) : "") +
753
                    ", " + (_constraints.contains("normal_deviation") ? tr("normal_deviation = %1").arg(_constraints["normal_deviation"].toString()) : "") +
754
                    ", " + (_constraints.contains("edge_length") ? tr("edge_length = %1").arg(_constraints["edge_length"].toString()) : "") +
755
                    ", " + (_constraints.contains("roundness") ? tr("roundness = %1").arg(_constraints["roundness"].toString()) : "") +
756 757 758
                    ", " + (_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()) : "") +
759
                    ", " + (_constraints.contains("vertices") ? tr("vertices = %1").arg(_constraints["vertices"].toString()) : "") + ")";
760

761
    emit scriptInfo( "decimate(" + QString::number(_objID) + ", " + param + ")" );
762

763 764 765 766 767
    emit updatedObject( baseObjectData->id() , UPDATE_TOPOLOGY);

  } else {
    emit log(LOGERR,tr("Unsupported object type for decimater"));
    return;
768 769 770 771 772 773 774
  }

  emit updateView();
}

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

775 776 777
void DecimaterPlugin::slotUpdateNumVertices()
{
  // Only update if tool is visible
778
  if ( !OpenFlipper::Options::gui() || !tool_->isVisible() ) {
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
    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 {
804 805 806
    tool_->verticesCount->blockSignals(true);
    tool_->verticesCountSlider->blockSignals(true);

807 808 809
    tool_->currentNumVertices->setText (QString::number(max));
    tool_->verticesCount->setMaximum(max);
    tool_->verticesCountSlider->setMaximum(max);
810

811
    if ( tool_->verticesCount->value() < 2 )
812
    {
813
      tool_->verticesCount->setValue( max / 2 );
814 815
      tool_->verticesCountSlider->setValue( max / 2);
    }
816 817 818

    tool_->verticesCount->blockSignals(false);
    tool_->verticesCountSlider->blockSignals(false);
819 820 821 822 823
  }
}

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

824 825 826 827 828
/** \brief gets and sets the current maximum number of triangles
 *
 */
void DecimaterPlugin::slotUpdateNumTriangles() {
  // only update if the tool is visible
829
  if (!OpenFlipper::Options::gui() || !tool_->isVisible())
830 831
    return;

832
  size_t max = 0;
833 834 835 836 837 838 839 840 841
  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++;
  }

842 843 844
  tool_->trianglesCount->blockSignals(true);
  tool_->trianglesCountSlider->blockSignals(true);

845 846 847 848 849 850
  tool_->trianglesCount->setMinimum(1);
  tool_->trianglesCount->setMaximum(max);
  tool_->trianglesCountSlider->setMinimum(1);
  tool_->trianglesCountSlider->setMaximum(max);

  if (tool_->trianglesCount->value() < 2)
851 852 853 854
  {
    tool_->trianglesCount->setValue (max / 2 );
    tool_->trianglesCountSlider->setValue( max / 2);
  }
855 856 857

  tool_->trianglesCount->blockSignals(false);
  tool_->trianglesCountSlider->blockSignals(false);
858 859 860 861
}

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

862 863 864
void DecimaterPlugin::slotObjectSelectionChanged(int /*_identifier*/)
{
  slotUpdateNumVertices ();
865
  slotUpdateNumTriangles ();
866
}
867 868 869 870
//-----------------------------------------------------------------------------

void DecimaterPlugin::objectDeleted(int _id)
{
Matthias Möller's avatar
Matthias Möller committed
871
  slotDisableDecimation();
872
}
873 874 875

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

876
void DecimaterPlugin::slotAboutToRestore(int _id)
Matthias Möller's avatar
Matthias Möller committed
877 878 879 880 881 882 883
{
  slotDisableDecimation();
}

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

void DecimaterPlugin::slotDisableDecimation()
884
{
885 886 887
  if ( ! OpenFlipper::Options::gui())
    return;

888
  decimater_objects_.clear();
Matthias Möller's avatar
Matthias Möller committed
889
  tool_->pbDecimate->setEnabled(false);
890 891 892 893
}

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

894
void DecimaterPlugin::slotObjectUpdated(int /*_identifier*/ , const UpdateType& _type )
895
{
896
  if ( _type.contains(UPDATE_TOPOLOGY) ) {
897
    slotUpdateNumVertices ();
898 899
    slotUpdateNumTriangles ();
  }
900 901 902 903 904
}

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

// activate checkbox if value has changed
905
void DecimaterPlugin::slotUpdateVertices()
906
{
907 908 909 910 911 912
  tool_->rbVertices->setChecked (true);
}

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

// activate checkbox if value has changed
913
void DecimaterPlugin::slotUpdateTriangles()
914 915
{
  tool_->rbTriangles->setChecked (true);
916 917 918 919 920
}

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

// activate checkbox if value has changed
921
void DecimaterPlugin::slotUpdateNormalDev()
922 923 924 925 926 927
{
  tool_->cbNormalDev->setChecked (true);
}

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

928
// activate checkbox if value has changed
929
void DecimaterPlugin::slotUpdateEdgeLength()
930 931 932 933 934 935
{
  tool_->cbEdgeLength->setChecked (true);
}

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

936
// activate checkbox if value has changed
937
void DecimaterPlugin::slotUpdateDistance()
938 939 940 941
{
  tool_->cbDistance->setChecked (true);
}

Matthias Möller's avatar
Matthias Möller committed
942 943 944
#if QT_VERSION < 0x050000
  Q_EXPORT_PLUGIN2(DecimaterPlugin , DecimaterPlugin );
#endif