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/>.                                       *
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
Jan Möbius's avatar
Jan Möbius committed
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
*                                                                            *
\*===========================================================================*/


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


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

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

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

Jan Möbius's avatar
Jan Möbius committed
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

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

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

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

Jan Möbius's avatar
Jan Möbius committed
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

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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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
}

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

Jan Möbius's avatar
Jan Möbius committed
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
}


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

Jan Möbius's avatar
Jan Möbius committed
105
/** \brief sync between values of roundness slider and spinbox in the toolbox
Jan Möbius's avatar
 
Jan Möbius committed
106
 *
Jan Möbius's avatar
Jan Möbius committed
107
 * @param _value new roundness value
Jan Möbius's avatar
 
Jan Möbius committed
108
 */
Jan Möbius's avatar
Jan Möbius committed
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
}


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

Jan Möbius's avatar
Jan Möbius committed
118
/** \brief sync between values of roundness slider and spinbox in the toolbox
Jan Möbius's avatar
 
Jan Möbius committed
119
 *
Jan Möbius's avatar
Jan Möbius committed
120
 * @param _value new roundness value
Jan Möbius's avatar
 
Jan Möbius committed
121
 */
Jan Möbius's avatar
Jan Möbius committed
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
}

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

Jan Möbius's avatar
Jan Möbius committed
130
/** \brief Decimation called by toolbox
Jan Möbius's avatar
 
Jan Möbius committed
131 132
 *
 */
Jan Möbius's avatar
Jan Möbius committed
133
void DecimaterPlugin::slot_decimate()
Jan Möbius's avatar
 
Jan Möbius committed
134
{
Jan Möbius's avatar
Jan Möbius committed
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

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

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

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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

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

Jan Möbius's avatar
Jan Möbius committed
232
/** \brief Decimation called by Scripting
Jan Möbius's avatar
 
Jan Möbius committed
233
 *
Jan Möbius's avatar
Jan Möbius committed
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
 */
Jan Möbius's avatar
Jan Möbius committed
238
void DecimaterPlugin::decimate(int _objID, QVariantMap _constraints) {
Jan Möbius's avatar
 
Jan Möbius committed
239 240


Jan Möbius's avatar
Jan Möbius committed
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

Jan Möbius's avatar
Jan Möbius committed
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

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

Jan Möbius's avatar
Jan Möbius committed
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;
Jan Möbius's avatar
Jan Möbius committed
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

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

Jan Möbius's avatar
Jan Möbius committed
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
    }

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

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

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

Jan Möbius's avatar
Jan Möbius committed
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
    }

Jan Möbius's avatar
Jan Möbius committed
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
      }
    }

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

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

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

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

Jan Möbius's avatar
Jan Möbius committed
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();
}

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

Jan Möbius's avatar
Jan Möbius committed
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 );