Developer Documentation
SmootherPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 
51 
52 #include "SmootherPlugin.hh"
53 
54 
57 
58 SmootherPlugin::SmootherPlugin() :
59  iterationsSpinbox_(0)
60 {
61 
62 }
63 
64 SmootherPlugin::~SmootherPlugin()
65 {
66 
67 }
68 
69 void SmootherPlugin::initializePlugin()
70 {
71  // Create the Toolbox Widget
72  QWidget* toolBox = new QWidget();
73  QGridLayout* layout = new QGridLayout(toolBox);
74 
75  QPushButton* smoothButton = new QPushButton("&Smooth",toolBox);
76  smoothButton->setToolTip(tr("Smooths an Object using Laplacian Smoothing."));
77  smoothButton->setWhatsThis(tr("Smooths an Object using Laplacian Smoothing. Use the Smooth Plugin for more options."));
78 
79 
80 
81  iterationsSpinbox_ = new QSpinBox(toolBox) ;
82  iterationsSpinbox_->setMinimum(1);
83  iterationsSpinbox_->setMaximum(1000);
84  iterationsSpinbox_->setSingleStep(1);
85  iterationsSpinbox_->setToolTip(tr("The number of the smooting operations."));
86  iterationsSpinbox_->setWhatsThis(tr("Give the number, how often the Laplacian Smoothing should modify the object."));
87 
88  QLabel* label = new QLabel("Iterations:");
89 
90  layout->addWidget( label , 0, 0);
91  layout->addWidget( smoothButton , 1, 1);
92  layout->addWidget( iterationsSpinbox_, 0, 1);
93 
94  layout->addItem(new QSpacerItem(10,10,QSizePolicy::Expanding,QSizePolicy::Expanding),2,0,1,2);
95 
96  connect( smoothButton, SIGNAL(clicked()), this, SLOT(simpleLaplace()) );
97 
98  QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"smoother1.png");
99  emit addToolbox( tr("Simple Smoother") , toolBox, toolIcon );
100 }
101 
103 
104  // Emit slot description
105  emit setSlotDescription(tr("simpleLaplace(int)"), tr("Smooth mesh using the Laplace operator with uniform weights."),
106  QStringList(tr("iterations")), QStringList(tr("Number of iterations")));
107 }
108 
115 
116  int iterations = 1;
117 
118  if(!OpenFlipper::Options::nogui()) {
119  iterations = iterationsSpinbox_->value();
120  }
121 
122  simpleLaplace(iterations);
123 }
124 
132 void SmootherPlugin::simpleLaplace(int _iterations) {
133 
135 
136  bool selectionExists = false;
137 
138  if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
139 
140  // Get the mesh to work on
141  TriMesh* mesh = PluginFunctions::triMesh(*o_it);
142 
143  // Property for the active mesh to store original point positions
145 
146  // Add a property to the mesh to store original vertex positions
147  mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
148 
149  for ( int i = 0 ; i < _iterations ; ++i ) {
150 
151  // Copy original positions to backup ( in Vertex property )
152  TriMesh::VertexIter v_it, v_end=mesh->vertices_end();
153  for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
154  mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
155  // See if at least one vertex has been selected
156  selectionExists |= mesh->status(*v_it).selected();
157  }
158 
159  // Do one smoothing step (For each point of the mesh ... )
160  for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
161 
162  if(selectionExists && mesh->status(*v_it).selected() == false) {
163  continue;
164  }
165 
166  TriMesh::Point point = TriMesh::Point(0.0,0.0,0.0);
167 
168  // Flag, to skip boundary vertices
169  bool skip = false;
170 
171  // ( .. for each Outoing halfedge .. )
172  TriMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
173  for ( ; voh_it.is_valid(); ++voh_it ) {
174  // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
175  point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
176 
177  // Check if the current Halfedge is a boundary halfedge
178  // If it is, abort and keep the current vertex position
179  if ( mesh->is_boundary( *voh_it ) ) {
180  skip = true;
181  break;
182  }
183 
184  }
185 
186  // Devide by the valence of the current vertex
187  point /= mesh->valence( *v_it );
188 
189  if ( ! skip ) {
190  // Set new position for the mesh if its not on the boundary
191  mesh->point(*v_it) = point;
192  }
193  }
194 
195  }// Iterations end
196 
197  // Remove the property
198  mesh->remove_property( origPositions );
199 
200  mesh->update_normals();
201 
202  emit updatedObject( o_it->id(), UPDATE_GEOMETRY );
203 
204  // Create backup
205  emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY );
206 
207  } else if ( o_it->dataType( DATA_POLY_MESH ) ) {
208 
209  // Get the mesh to work on
210  PolyMesh* mesh = PluginFunctions::polyMesh(*o_it);
211 
212  // Property for the active mesh to store original point positions
214 
215  // Add a property to the mesh to store original vertex positions
216  mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
217 
218  for ( int i = 0 ; i < _iterations ; ++i ) {
219 
220  // Copy original positions to backup ( in Vertex property )
221  PolyMesh::VertexIter v_it, v_end=mesh->vertices_end();
222  for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
223  mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
224  // See if at least one vertex has been selected
225  selectionExists |= mesh->status(*v_it).selected();
226  }
227 
228  // Do one smoothing step (For each point of the mesh ... )
229  for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
230 
231  if(selectionExists && mesh->status(*v_it).selected() == false) {
232  continue;
233  }
234 
235  PolyMesh::Point point = PolyMesh::Point(0.0,0.0,0.0);
236 
237  // Flag, to skip boundary vertices
238  bool skip = false;
239 
240  // ( .. for each Outoing halfedge .. )
241  PolyMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
242  for ( ; voh_it.is_valid(); ++voh_it ) {
243  // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
244  point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
245 
246  // Check if the current Halfedge is a boundary halfedge
247  // If it is, abort and keep the current vertex position
248  if ( mesh->is_boundary( *voh_it ) ) {
249  skip = true;
250  break;
251  }
252 
253  }
254 
255  // Devide by the valence of the current vertex
256  point /= mesh->valence( *v_it );
257 
258  if ( ! skip ) {
259  // Set new position for the mesh if its not on the boundary
260  mesh->point(*v_it) = point;
261  }
262  }
263 
264  }// Iterations end
265 
266  // Remove the property
267  mesh->remove_property( origPositions );
268 
269  mesh->update_normals();
270 
271  emit updatedObject( o_it->id() , UPDATE_GEOMETRY);
272 
273  // Create backup
274  emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY);
275 
276  } else {
277 
278  emit log(LOGERR, "DataType not supported.");
279  }
280  }
281 
282  // Show script logging
283  emit scriptInfo("simpleLaplace(" + QString::number(_iterations) + ")");
284 
285  emit updateView();
286 }
287 
288 
289 #if QT_VERSION < 0x050000
290  Q_EXPORT_PLUGIN2( smootherplugin , SmootherPlugin );
291 #endif
292 
293 
294 
void update_normals()
Compute normals for all primitives.
Definition: PolyMeshT.cc:241
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void pluginsInitialized()
Set the scripting slot descriptions.
QSpinBox * iterationsSpinbox_
SpinBox for Number of iterations.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
Kernel::VertexOHalfedgeIter VertexOHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:166
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:115
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
void simpleLaplace()
simpleLaplace