SmootherPlugin.cc 10.8 KB
Newer Older
1
/*===========================================================================*\
Jan Möbius's avatar
Jan Möbius committed
2 3
*                                                                            *
*                              OpenFlipper                                   *
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 37 38
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39
*                                                                            *
40 41
\*===========================================================================*/

42 43 44

#include "SmootherPlugin.hh"

45 46 47

#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
48

49 50 51 52
#include <QGridLayout>
#include <QPushButton>
#include <QLabel>

Jan Möbius's avatar
Jan Möbius committed
53 54 55 56 57 58 59 60 61 62 63
SmootherPlugin::SmootherPlugin() :
        iterationsSpinbox_(0)
{

}

SmootherPlugin::~SmootherPlugin()
{

}

Jan Möbius's avatar
Jan Möbius committed
64
void SmootherPlugin::initializePlugin()
65 66
{
   // Create the Toolbox Widget
67 68
   QWidget* toolBox = new QWidget();
   QGridLayout* layout = new QGridLayout(toolBox);
69

70
   QPushButton* smoothButton = new QPushButton("&Smooth",toolBox);
71 72 73 74
   smoothButton->setToolTip(tr("Smooths an Object using Laplacian Smoothing."));
   smoothButton->setWhatsThis(tr("Smooths an Object using Laplacian Smoothing. Use the Smooth Plugin for more options."));


75

76
   iterationsSpinbox_ =  new QSpinBox(toolBox) ;
77 78 79
   iterationsSpinbox_->setMinimum(1);
   iterationsSpinbox_->setMaximum(1000);
   iterationsSpinbox_->setSingleStep(1);
80 81
   iterationsSpinbox_->setToolTip(tr("The number of the smooting operations."));
   iterationsSpinbox_->setWhatsThis(tr("Give the number, how often the Laplacian Smoothing should modify the object."));
82

83 84 85 86 87
   QLabel* label = new QLabel("Iterations:");

   layout->addWidget( label             , 0, 0);
   layout->addWidget( smoothButton      , 1, 1);
   layout->addWidget( iterationsSpinbox_, 0, 1);
88

89
   layout->addItem(new QSpacerItem(10,10,QSizePolicy::Expanding,QSizePolicy::Expanding),2,0,1,2);
90

91
   connect( smoothButton, SIGNAL(clicked()), this, SLOT(simpleLaplace()) );
92

Dirk Wilden's avatar
Dirk Wilden committed
93 94
   QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"smoother1.png");
   emit addToolbox( tr("Simple Smoother") , toolBox, toolIcon );
95 96
}

97 98 99 100 101 102 103 104
void SmootherPlugin::pluginsInitialized() {
    
    // Emit slot description
    emit setSlotDescription(tr("simpleLaplace(int)"),   tr("Smooth mesh using the Laplace operator with uniform weights."),
                            QStringList(tr("iterations")), QStringList(tr("Number of iterations")));
}

/** \brief simpleLaplace
105
 *
106 107
 *  Smooth mesh using the Laplace operator
 *  with uniform weights.
108
 */
109
void SmootherPlugin::simpleLaplace() {
110

111 112 113 114 115 116 117 118
    int iterations = 1;
    
    if(!OpenFlipper::Options::nogui()) {
        iterations = iterationsSpinbox_->value();
    }
    
    simpleLaplace(iterations);
}
119

120 121 122 123 124
/** \brief simpleLaplace
 *
 * Smooth mesh using the Laplace operator
 * with uniform weights.
 *
125
 * @param _iterations Number of iterations
126 127 128 129
 */
void SmootherPlugin::simpleLaplace(int _iterations) {
    
    for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
130

131 132
    bool selectionExists = false;

133
    if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
134

135
        // Get the mesh to work on
136
      TriMesh* mesh = PluginFunctions::triMesh(*o_it);
137

138 139
      // Property for the active mesh to store original point positions
      OpenMesh::VPropHandleT< TriMesh::Point > origPositions;
140

141
      // Add a property to the mesh to store original vertex positions
142
      mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
143

144
      for ( int i = 0 ; i < _iterations ; ++i ) {
145

146 147 148
          // Copy original positions to backup ( in Vertex property )
          TriMesh::VertexIter v_it, v_end=mesh->vertices_end();
          for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
Matthias Möller's avatar
Matthias Möller committed
149
            mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
150
            // See if at least one vertex has been selected
Matthias Möller's avatar
Matthias Möller committed
151
            selectionExists |= mesh->status(*v_it).selected();
152
          }
153

154 155
          // Do one smoothing step (For each point of the mesh ... )
          for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
156

Matthias Möller's avatar
Matthias Möller committed
157
            if(selectionExists && mesh->status(*v_it).selected() == false) {
158 159 160
              continue;
            }

161
            TriMesh::Point point = TriMesh::Point(0.0,0.0,0.0);
162

163 164
            // Flag, to skip boundary vertices
            bool skip = false;
165

166
            // ( .. for each Outoing halfedge .. )
Matthias Möller's avatar
Matthias Möller committed
167 168
            TriMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
            for ( ; voh_it.is_valid(); ++voh_it ) {
169
                // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
Matthias Möller's avatar
Matthias Möller committed
170
                point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
171

172 173
                // Check if the current Halfedge is a boundary halfedge
                // If it is, abort and keep the current vertex position
Matthias Möller's avatar
Matthias Möller committed
174
                if ( mesh->is_boundary( *voh_it ) ) {
175
                  skip = true;
176
                  break;
177
                }
178

179
            }
180

181
            // Devide by the valence of the current vertex
Matthias Möller's avatar
Matthias Möller committed
182
            point /= mesh->valence( *v_it );
183

184
            if ( ! skip ) {
185
                // Set new position for the mesh if its not on the boundary
Matthias Möller's avatar
Matthias Möller committed
186
                mesh->point(*v_it) = point;
187
            }
188
          }
189

190
      }// Iterations end
191

192
      // Remove the property
193
      mesh->remove_property( origPositions );
194

195
      mesh->update_normals();
196

197
      emit updatedObject( o_it->id(), UPDATE_GEOMETRY );
198 199
      
      // Create backup
Dirk Wilden's avatar
Dirk Wilden committed
200
      emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY );
201

202
   } else if ( o_it->dataType( DATA_POLY_MESH ) ) {
203

204
       // Get the mesh to work on
205
      PolyMesh* mesh = PluginFunctions::polyMesh(*o_it);
206

207 208 209
      // Property for the active mesh to store original point positions
      OpenMesh::VPropHandleT< TriMesh::Point > origPositions;

210
      // Add a property to the mesh to store original vertex positions
211
      mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
212

213
      for ( int i = 0 ; i < _iterations ; ++i ) {
214

215 216 217
         // Copy original positions to backup ( in Vertex property )
         PolyMesh::VertexIter v_it, v_end=mesh->vertices_end();
         for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
Matthias Möller's avatar
Matthias Möller committed
218
            mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
219
            // See if at least one vertex has been selected
Matthias Möller's avatar
Matthias Möller committed
220
            selectionExists |= mesh->status(*v_it).selected();
221
         }
222

223 224
         // Do one smoothing step (For each point of the mesh ... )
         for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
225

Matthias Möller's avatar
Matthias Möller committed
226
            if(selectionExists && mesh->status(*v_it).selected() == false) {
227 228 229
              continue;
            }

230
            PolyMesh::Point point = PolyMesh::Point(0.0,0.0,0.0);
231

232 233
            // Flag, to skip boundary vertices
            bool skip = false;
234

235
            // ( .. for each Outoing halfedge .. )
Matthias Möller's avatar
Matthias Möller committed
236 237
            PolyMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
            for ( ; voh_it.is_valid(); ++voh_it ) {
238
               // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
Matthias Möller's avatar
Matthias Möller committed
239
               point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
240

241 242
               // Check if the current Halfedge is a boundary halfedge
               // If it is, abort and keep the current vertex position
Matthias Möller's avatar
Matthias Möller committed
243
               if ( mesh->is_boundary( *voh_it ) ) {
244
                  skip = true;
245
                  break;
246
               }
247

248
            }
249

250
            // Devide by the valence of the current vertex
Matthias Möller's avatar
Matthias Möller committed
251
            point /= mesh->valence( *v_it );
252

253 254
            if ( ! skip ) {
               // Set new position for the mesh if its not on the boundary
Matthias Möller's avatar
Matthias Möller committed
255
               mesh->point(*v_it) = point;
256 257
            }
         }
258

259
      }// Iterations end
260

261
      // Remove the property
262
      mesh->remove_property( origPositions );
263

264
      mesh->update_normals();
265

266
      emit updatedObject( o_it->id() , UPDATE_GEOMETRY);
267 268
      
      // Create backup
Dirk Wilden's avatar
Dirk Wilden committed
269
      emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY);
270

271
    } else {
272

273 274
      emit log(LOGERR, "DataType not supported.");
    }
275
  }
276 277
  
  // Show script logging
278 279 280
  emit scriptInfo("simpleLaplace(" + QString::number(_iterations) + ")");
  
  emit updateView();
281 282 283
}


284 285


286