DecimaterPlugin.cc 16.5 KB
Newer Older
Jan Möbius's avatar
 
Jan Möbius committed
1 2 3 4 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
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
*      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen       *
*                           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/>.                                       *
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
37 38 39
*   $Revision: 11950 $                                                       *
*   $LastChangedBy: moebius $                                                *
*   $Date: 2011-07-07 10:01:14 +0200 (Do, 07 Jul 2011) $                     *
Jan Möbius's avatar
 
Jan Möbius committed
40 41 42 43
*                                                                            *
\*===========================================================================*/


44 45 46 47 48
//=============================================================================
//
//  CLASS DecimaterPlugin - IMPLEMENTATION
//
//=============================================================================
Jan Möbius's avatar
 
Jan Möbius committed
49 50


51
//== INCLUDES =================================================================
Jan Möbius's avatar
 
Jan Möbius committed
52

53
#include <QtGui>
Jan Möbius's avatar
 
Jan Möbius committed
54

55
#include "DecimaterPlugin.hh"
Jan Möbius's avatar
 
Jan Möbius committed
56

57 58 59 60
#include <iostream>
#include <ACG/GL/GLState.hh>
#include <QStringList>
#include <ACG/Scenegraph/ManipulatorNode.hh>
Jan Möbius's avatar
 
Jan Möbius committed
61

62
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
Jan Möbius's avatar
 
Jan Möbius committed
63

64
#define DECIMATER "DecimaterData"
Jan Möbius's avatar
 
Jan Möbius committed
65

66
//== IMPLEMENTATION ==========================================================
Jan Möbius's avatar
 
Jan Möbius committed
67

68 69 70 71 72
void DecimaterPlugin::initializePlugin()
{
  tool_ = new DecimaterToolbarWidget();
  QSize size(100, 100);
  tool_->resize(size);
Jan Möbius's avatar
 
Jan Möbius committed
73

74 75
  // connect signals->slots
  connect(tool_->pbDecimate,SIGNAL(clicked() ),this,SLOT(slot_decimate()));
Jan Möbius's avatar
 
Jan Möbius committed
76

77 78 79 80 81 82 83
  connect(tool_->roundness,SIGNAL(valueChanged(double) ),this,SLOT(updateRoundness(double)) );
  connect(tool_->roundnessSlider,SIGNAL(valueChanged(int) ),this,SLOT(updateRoundness(int)) );
  connect(tool_->distance,SIGNAL(valueChanged(double) ),this,SLOT(updateDistance()) );
  connect(tool_->normalDeviation,SIGNAL(valueChanged(int) ),this,SLOT(updateNormalDev()) );
  connect(tool_->normalDeviationSlider,SIGNAL(valueChanged(int) ),this,SLOT(updateNormalDev()) );
  connect(tool_->verticesCount,SIGNAL(valueChanged(int) ),this,SLOT(updateVertices()) );
  connect(tool_->verticesCountSlider,SIGNAL(valueChanged(int) ),this,SLOT(updateVertices()) );
Jan Möbius's avatar
 
Jan Möbius committed
84

85 86
  // Force update if the Toolbox gets visible
  connect(tool_, SIGNAL(showing()), this, SLOT( slotUpdateNumVertices() ) );
Jan Möbius's avatar
 
Jan Möbius committed
87

88 89
  toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"decimater.png");
  emit addToolbox( tr("Decimater") , tool_, toolIcon_ );
Jan Möbius's avatar
 
Jan Möbius committed
90 91
}

92 93
/** \brief Initialization of the plugin when it is loaded by the core
 * 
Jan Möbius's avatar
 
Jan Möbius committed
94
 */
95
void DecimaterPlugin::pluginsInitialized() {
Jan Möbius's avatar
 
Jan Möbius committed
96

97 98 99
  emit setSlotDescription("decimate(int,QVariantMap)",tr("Decimate a given object"),
                          QString(tr("objectId,constraints")).split(","),
                          QString(tr("ID of an object; Object that can has one or more constraint properties (distance,normal_deviation,roundness,vertices)")).split(";"));
Jan Möbius's avatar
 
Jan Möbius committed
100 101 102 103 104
}


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

105
/** \brief sync between values of roundness slider and spinbox in the toolbox
Jan Möbius's avatar
 
Jan Möbius committed
106
 *
107
 * @param _value new roundness value
Jan Möbius's avatar
 
Jan Möbius committed
108
 */
109 110 111 112
void DecimaterPlugin::updateRoundness(int _value)
{
  tool_->roundness->setValue( (double) _value / 100.0 );
  tool_->cbRoundness->setChecked (true);
Jan Möbius's avatar
 
Jan Möbius committed
113 114 115 116 117
}


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

118
/** \brief sync between values of roundness slider and spinbox in the toolbox
Jan Möbius's avatar
 
Jan Möbius committed
119
 *
120
 * @param _value new roundness value
Jan Möbius's avatar
 
Jan Möbius committed
121
 */
122 123 124 125
void DecimaterPlugin::updateRoundness(double _value)
{
  tool_->roundnessSlider->setValue( (int) (_value * 100) );
  tool_->cbRoundness->setChecked (true);
Jan Möbius's avatar
 
Jan Möbius committed
126 127 128 129
}

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

130
/** \brief Decimation called by toolbox
Jan Möbius's avatar
 
Jan Möbius committed
131 132
 *
 */
133
void DecimaterPlugin::slot_decimate()
Jan Möbius's avatar
 
Jan Möbius committed
134
{
135 136 137
  
  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DATA_TRIANGLE_MESH) ;
                                        o_it != PluginFunctions::objectsEnd(); ++o_it)  {
Jan Möbius's avatar
 
Jan Möbius committed
138

139 140
    //initialize
    TriMeshObject* object = PluginFunctions::triMeshObject(*o_it);
Jan Möbius's avatar
 
Jan Möbius committed
141

142 143
    if ( object == 0 )
      emit log(LOGWARN , tr("Unable to get object"));
Jan Möbius's avatar
 
Jan Möbius committed
144

145
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( o_it->objectData(DECIMATER) );
Jan Möbius's avatar
 
Jan Möbius committed
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    TriMesh* mesh = PluginFunctions::triMesh(*o_it);
  
    if (decimater == 0){
      decimater = new DecimaterInfo();
      o_it->setObjectData(DECIMATER, decimater);
    }
    
    // constraint handles for decimation
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
    ModNormalDeviationH hModNormalDeviation;
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
    
    // Create decimater
    DecimaterType decimater_object( *mesh );
    decimater_object.add( hModQuadric );
    decimater_object.module( hModQuadric ).unset_max_err();
    
    // Remove old constraints
    if(decimater->distance()) {
        decimater->removeDistanceConstraint();
        decimater_object.remove(hModHausdorff);
    }
    if(decimater->normalDeviation()) {
        decimater->removeNormalDeviationConstraint();
        decimater_object.remove(hModNormalFlipping);
    }
    if(decimater->roundness()) {
        decimater->removeRoundnessConstraint();
        decimater_object.remove(hModRoundness);
    }
Jan Möbius's avatar
 
Jan Möbius committed
182

183 184 185 186 187 188 189
    //and set new constraints
    if ( tool_->cbDistance->isChecked() ) {
      if (  decimater_object.add( hModHausdorff ) ) {
          decimater->setDistanceConstraint( tool_->distance->value() );
          decimater_object.module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
      }
    }
Jan Möbius's avatar
 
Jan Möbius committed
190

191 192 193 194 195 196
    if ( tool_->cbNormalDev->isChecked() ) {
      if (  decimater_object.add( hModNormalFlipping ) ) {
          decimater->setNormalDeviationConstraint( tool_->normalDeviation->value() );
          decimater_object.module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() );
      }
    }
Jan Möbius's avatar
 
Jan Möbius committed
197

198 199 200 201 202 203
    if ( tool_->cbRoundness->isChecked() ) {      
      if (  decimater_object.add( hModRoundness ) ) {
          decimater->setRoundnessConstraint( tool_->roundness->value() );
          decimater_object.module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
      }
    }
Jan Möbius's avatar
 
Jan Möbius committed
204

205 206 207 208 209
    // Initialize the decimater
    if( ! decimater_object.initialize() ){
      emit log(LOGWARN, tr("Decimater could not be initialized"));
      continue;
    }
Jan Möbius's avatar
 
Jan Möbius committed
210

211 212 213 214 215 216 217 218 219 220 221 222 223 224
    //decimate
    if ( tool_->cbVertices->isChecked() )
        decimater_object.decimate_to(tool_->verticesCount->value());
    else
        decimater_object.decimate();

    object->mesh()->garbage_collection();
    object->mesh()->update_normals();
    object->update();
    
    // Create backup
    emit createBackup(o_it->id(), "Decimation");
    emit updatedObject( o_it->id() , UPDATE_TOPOLOGY );
  }
Jan Möbius's avatar
 
Jan Möbius committed
225

226
  emit updateView();
Jan Möbius's avatar
 
Jan Möbius committed
227 228
}

Jan Möbius's avatar
Jan Möbius committed
229 230 231

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

232
/** \brief Decimation called by Scripting
Jan Möbius's avatar
 
Jan Möbius committed
233
 *
234 235 236
 * @param _objID id of an object
 * @param _constraints A string containing a comma separated list of constraints (distance,normal_deviation,roundness,triangles)
 * @param _values a string containing a comma separated list of constraint values suited to the _constraints parameter
Jan Möbius's avatar
 
Jan Möbius committed
237
 */
238
void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
Jan Möbius's avatar
 
Jan Möbius committed
239 240


241 242 243 244 245 246 247 248
  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);
Jan Möbius's avatar
 
Jan Möbius committed
249

250 251 252 253
    if ( object == 0 ) {
      emit log(LOGWARN , tr("Unable to get object ( Only Triangle Meshes supported)"));
      return;
    }
Jan Möbius's avatar
 
Jan Möbius committed
254

255
    DecimaterInfo* decimater = dynamic_cast< DecimaterInfo* > ( object->objectData(DECIMATER) );
Jan Möbius's avatar
 
Jan Möbius committed
256

257 258 259 260 261 262 263
    TriMesh* mesh = PluginFunctions::triMesh(baseObjectData);
    
    if (decimater == 0){
      decimater = new DecimaterInfo();
      object->setObjectData(DECIMATER, decimater);
    }
    
Jan Möbius's avatar
 
Jan Möbius committed
264
    // constraint handles for decimation
Jan Möbius's avatar
Jan Möbius committed
265 266 267 268
    ModAspectRatioH     hModAspectRatio;
    ModEdgeLengthH      hModEdgeLength;
    ModHausdorffH       hModHausdorff;
    ModIndependentH     hModIndependent;
Jan Möbius's avatar
 
Jan Möbius committed
269
    ModNormalDeviationH hModNormalDeviation;
Jan Möbius's avatar
Jan Möbius committed
270 271 272
    ModNormalFlippingH  hModNormalFlipping;
    ModQuadricH         hModQuadric;
    ModRoundnessH       hModRoundness;
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    
    // Create decimater
    DecimaterType decimater_object( *mesh );
    decimater_object.add( hModQuadric );
    decimater_object.module( hModQuadric ).unset_max_err();

    // Remove old constraints
    if(decimater->distance()) {
        decimater->removeDistanceConstraint();
        decimater_object.remove(hModHausdorff);
    }
    if(decimater->normalDeviation()) {
        decimater->removeNormalDeviationConstraint();
        decimater_object.remove(hModNormalFlipping);
    }
    if(decimater->roundness()) {
        decimater->removeRoundnessConstraint();
        decimater_object.remove(hModRoundness);
    }
Jan Möbius's avatar
Jan Möbius committed
292

293 294
    //distance constraint
    if ( _constraints.contains("distance") ){
Jan Möbius's avatar
 
Jan Möbius committed
295

296 297 298 299 300 301 302 303 304 305
      bool ok;

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

      if (ok) {
        if (  decimater_object.add( hModHausdorff ) ) {
            decimater->setDistanceConstraint( value );
            decimater_object.module( hModHausdorff ).set_tolerance( decimater->distanceValue() );
        }
      }
Jan Möbius's avatar
 
Jan Möbius committed
306 307
    }

308 309
    //normal deviation constraint
    if ( _constraints.contains("normal_deviation") ){
Jan Möbius's avatar
 
Jan Möbius committed
310

311
      bool ok;
Jan Möbius's avatar
 
Jan Möbius committed
312

313
      int value = _constraints["normal_deviation"].toInt(&ok);
Jan Möbius's avatar
 
Jan Möbius committed
314

315 316 317 318 319 320
      if (ok) {
        if (  decimater_object.add( hModNormalFlipping ) ) {
            decimater->setNormalDeviationConstraint( value );
            decimater_object.module( hModNormalFlipping ).set_max_normal_deviation( decimater->normalDeviationValue() );
        }
      }
Jan Möbius's avatar
 
Jan Möbius committed
321 322
    }

323 324 325 326 327 328 329 330 331 332 333 334
    //roundness constraint
    if ( _constraints.contains("roundness") ){

      bool ok;

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

      if (ok) {
        if (  decimater_object.add( hModRoundness ) ) {
            decimater->setRoundnessConstraint( value );
            decimater_object.module( hModRoundness ).set_min_roundness( decimater->roundnessValue(), true );
        }
Jan Möbius's avatar
 
Jan Möbius committed
335 336 337
      }
    }

338 339 340
    //triangleCount constraint
    bool triangleCount = false;
    int triangles = 0;
Jan Möbius's avatar
 
Jan Möbius committed
341

342
    if ( _constraints.contains("vertices") ){
Jan Möbius's avatar
 
Jan Möbius committed
343

344
      bool ok;
Jan Möbius's avatar
 
Jan Möbius committed
345

346
      int value = _constraints["vertices"].toInt(&ok);
Jan Möbius's avatar
 
Jan Möbius committed
347

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
      if (ok){
        triangleCount = true;
        triangles = value;
      }
    }

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

    //decimate
    if ( triangleCount )
      decimater_object.decimate_to( triangles ); // do decimation
    else
      decimater_object.decimate(); // do decimation

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

    // Create backup
    emit createBackup(_objID, "Decimation");
    
    // Create QVariantMap parameter string
    QString param = "("  + (_constraints.contains("distance") ? tr("distance = %1").arg(_constraints["distance"].toString()) : "") +
                    ", " + (_constraints.contains("normal_deviation") ? tr("normal_deviation = %1").arg(_constraints["normal_deviation"].toString()) : "") +
                    ", " + (_constraints.contains("roundness") ? tr("roundness = %1").arg(_constraints["roundness"].toString()) : "") +
                    ", " + (_constraints.contains("vertices") ? tr("vertices = %1").arg(_constraints["vertices"].toString()) : "") + ")";
    
    emit scriptInfo( "decimate(" + QString::number(_objID) + ", " + param + ")" );
    
    emit updatedObject( baseObjectData->id() , UPDATE_TOPOLOGY);

  } else {
    emit log(LOGERR,tr("Unsupported object type for decimater"));
    return;
Jan Möbius's avatar
 
Jan Möbius committed
386 387 388 389 390 391 392
  }

  emit updateView();
}

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

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 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 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
void DecimaterPlugin::slotUpdateNumVertices()
{
  // Only update if tool is visible
  if ( !tool_->isVisible() ) {
    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 {
    tool_->currentNumVertices->setText (QString::number(max));
    tool_->verticesCount->setMaximum(max);
    tool_->verticesCountSlider->setMaximum(max);
    
    if ( tool_->verticesCount->value() < 2 )
      tool_->verticesCount->setValue( max / 2 );
  }
}

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

void DecimaterPlugin::slotObjectSelectionChanged(int /*_identifier*/)
{
  slotUpdateNumVertices ();
}

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

void DecimaterPlugin::slotObjectUpdated(int /*_identifier*/ , const UpdateType _type )
{
  if ( _type.contains(UPDATE_TOPOLOGY) )
    slotUpdateNumVertices ();
}

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

// activate checkbox if value has changed
void DecimaterPlugin::updateVertices()
{
  tool_->cbVertices->setChecked (true);
}

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

// activate checkbox if value has changed
void DecimaterPlugin::updateNormalDev()
{
  tool_->cbNormalDev->setChecked (true);
}

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

// activate checkbox if value has changed
void DecimaterPlugin::updateDistance()
{
  tool_->cbDistance->setChecked (true);
}

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

Q_EXPORT_PLUGIN2(DecimaterPlugin , DecimaterPlugin );