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 #include "SmootherPlugin.hh"
44
45
46 #include <ObjectTypes/PolyMesh/PolyMesh.hh>
47 #include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
48
49 #include <QGridLayout>
50 #include <QPushButton>
51 #include <QLabel>
52
53 SmootherPlugin::SmootherPlugin() :
54 iterationsSpinbox_(0)
55 {
56
57 }
58
59 SmootherPlugin::~SmootherPlugin()
60 {
61
62 }
63
64 void SmootherPlugin::initializePlugin()
65 {
66 // Create the Toolbox Widget
67 QWidget* toolBox = new QWidget();
68 QGridLayout* layout = new QGridLayout(toolBox);
69
70 QPushButton* smoothButton = new QPushButton("&Smooth",toolBox);
71 smoothButton->setToolTip(tr("Smooths an Object using Laplacian Smoothing."));
72 smoothButton->setWhatsThis(tr("Smooths an Object using Laplacian Smoothing. Use the Smooth Plugin for more options."));
73
74
75
76 iterationsSpinbox_ = new QSpinBox(toolBox) ;
77 iterationsSpinbox_->setMinimum(1);
78 iterationsSpinbox_->setMaximum(1000);
79 iterationsSpinbox_->setSingleStep(1);
80 iterationsSpinbox_->setToolTip(tr("The number of the smooting operations."));
81 iterationsSpinbox_->setWhatsThis(tr("Give the number, how often the Laplacian Smoothing should modify the object."));
82
83 QLabel* label = new QLabel("Iterations:");
84
85 layout->addWidget( label , 0, 0);
86 layout->addWidget( smoothButton , 1, 1);
87 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
93 QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"smoother1.png");
94 emit addToolbox( tr("Simple Smoother") , toolBox, toolIcon );
95 }
96
97 void SmootherPlugin::pluginsInitialized() {
98
99 // Emit slot description
100 emit setSlotDescription(tr("simpleLaplace(int)"), tr("Smooth mesh using the Laplace operator with uniform weights."),
101 QStringList(tr("iterations")), QStringList(tr("Number of iterations")));
102 }
103
109 void SmootherPlugin::simpleLaplace() {
110
111 int iterations = 1;
112
113 if(!OpenFlipper::Options::nogui()) {
114 iterations = iterationsSpinbox_->value();
115 }
116
117 simpleLaplace(iterations);
118 }
119
127 void SmootherPlugin::simpleLaplace(int _iterations) {
128
129 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {
130
131 bool selectionExists = false;
132
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 // Property for the active mesh to store original point positions
139 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 // Copy original positions to backup ( in Vertex property )
147 TriMesh::VertexIter v_it, v_end=mesh->vertices_end();
148 for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
149 mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
150 // See if at least one vertex has been selected
151 selectionExists |= mesh->status(*v_it).selected();
152 }
153
154 // Do one smoothing step (For each point of the mesh ... )
155 for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
156
157 if(selectionExists && mesh->status(*v_it).selected() == false) {
158 continue;
159 }
160
161 TriMesh::Point point = TriMesh::Point(0.0,0.0,0.0);
162
163 // Flag, to skip boundary vertices
164 bool skip = false;
165
166 // ( .. for each Outoing halfedge .. )
167 TriMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
168 for ( ; voh_it.is_valid(); ++voh_it ) {
169 // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
170 point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
171
172 // Check if the current Halfedge is a boundary halfedge
173 // If it is, abort and keep the current vertex position
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
182 point /= mesh->valence( *v_it );
183
184 if ( ! skip ) {
185 // Set new position for the mesh if its not on the boundary
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
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 // Property for the active mesh to store original point positions
208 OpenMesh::VPropHandleT< TriMesh::Point > origPositions;
209
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 // Copy original positions to backup ( in Vertex property )
216 PolyMesh::VertexIter v_it, v_end=mesh->vertices_end();
217 for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
218 mesh->property( origPositions, *v_it ) = mesh->point(*v_it);
219 // See if at least one vertex has been selected
220 selectionExists |= mesh->status(*v_it).selected();
221 }
222
223 // Do one smoothing step (For each point of the mesh ... )
224 for (v_it=mesh->vertices_begin(); v_it!=v_end; ++v_it) {
225
226 if(selectionExists && mesh->status(*v_it).selected() == false) {
227 continue;
228 }
229
230 PolyMesh::Point point = PolyMesh::Point(0.0,0.0,0.0);
231
232 // Flag, to skip boundary vertices
233 bool skip = false;
234
235 // ( .. for each Outoing halfedge .. )
236 PolyMesh::VertexOHalfedgeIter voh_it(*mesh,*v_it);
237 for ( ; voh_it.is_valid(); ++voh_it ) {
238 // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
239 point += mesh->property( origPositions, mesh->to_vertex_handle(*voh_it) );
240
241 // Check if the current Halfedge is a boundary halfedge
242 // If it is, abort and keep the current vertex position
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
251 point /= mesh->valence( *v_it );
252
253 if ( ! skip ) {
254 // Set new position for the mesh if its not on the boundary
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
269 emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY);
270
271 } else {
272
273 emit log(LOGERR, "DataType not supported.");
274 }
275 }
276
277 // Show script logging
278 emit scriptInfo("simpleLaplace(" + QString::number(_iterations) + ")");
279
280 emit updateView();
281 }
282
283
284
285
286
TriangleMesh.hh
DATA_POLY_MESH
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
SmootherPlugin::pluginsInitialized
void pluginsInitialized()
Set the scripting slot descriptions.
Definition: SmootherPlugin.cc:97
SmootherPlugin::iterationsSpinbox_
QSpinBox * iterationsSpinbox_
SpinBox for Number of iterations.
Definition: SmootherPlugin.hh:34
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:134
LOGERR
Definition: LoggingInterface.hh:96
UPDATE_GEOMETRY
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:441
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:177
PluginFunctions::polyMesh
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Definition: PluginFunctionsPolyMesh.cc:128
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
PolyMesh.hh
SmootherPlugin::simpleLaplace
void simpleLaplace()
simpleLaplace
Definition: SmootherPlugin.cc:75
OpenMesh::VPropHandleT
Definition: Property.hh:482