Developer Documentation
Loading...
Searching...
No Matches
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
48
49#include <QGridLayout>
50#include <QPushButton>
51#include <QLabel>
52
53SmootherPlugin::SmootherPlugin() :
54 iterationsSpinbox_(nullptr),
55 toolIcon_(nullptr)
56{
57
58}
59
60SmootherPlugin::~SmootherPlugin()
61{
62 delete toolIcon_;
63}
64
65void SmootherPlugin::initializePlugin()
66{
67 // Create the Toolbox Widget
68 QWidget* toolBox = new QWidget();
69 QGridLayout* layout = new QGridLayout(toolBox);
70
71 QPushButton* smoothButton = new QPushButton("&Smooth",toolBox);
72 smoothButton->setToolTip(tr("Smooths an Object using Laplacian Smoothing."));
73 smoothButton->setWhatsThis(tr("Smooths an Object using Laplacian Smoothing. Use the Smooth Plugin for more options."));
74
75
76
77 iterationsSpinbox_ = new QSpinBox(toolBox) ;
78 iterationsSpinbox_->setMinimum(1);
79 iterationsSpinbox_->setMaximum(1000);
80 iterationsSpinbox_->setSingleStep(1);
81 iterationsSpinbox_->setToolTip(tr("The number of the smooting operations."));
82 iterationsSpinbox_->setWhatsThis(tr("Give the number, how often the Laplacian Smoothing should modify the object."));
83
84 QLabel* label = new QLabel("Iterations:");
85
86 layout->addWidget( label , 0, 0);
87 layout->addWidget( smoothButton , 1, 1);
88 layout->addWidget( iterationsSpinbox_, 0, 1);
89
90 layout->addItem(new QSpacerItem(10,10,QSizePolicy::Expanding,QSizePolicy::Expanding),2,0,1,2);
91
92 connect( smoothButton, SIGNAL(clicked()), this, SLOT(simpleLaplace()) );
93
94 toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"smoother1.png");
95 emit addToolbox( tr("Simple Smoother") , toolBox, toolIcon_ );
96}
97
99
100 // Emit slot description
101 emit setSlotDescription(tr("simpleLaplace(int)"), tr("Smooth mesh using the Laplace operator with uniform weights."),
102 QStringList(tr("iterations")), QStringList(tr("Number of iterations")));
103}
104
111
112 int iterations = 1;
113
114 if(!OpenFlipper::Options::nogui()) {
115 iterations = iterationsSpinbox_->value();
116 }
117
118 simpleLaplace(iterations);
119}
120
128void SmootherPlugin::simpleLaplace(int _iterations) {
129
131
132 bool selectionExists = false;
133
134 if ( o_it->dataType( DATA_TRIANGLE_MESH ) ) {
135
136 // Get the mesh to work on
137 TriMesh* mesh = PluginFunctions::triMesh(*o_it);
138
139 // Property for the active mesh to store original point positions
141
142 // Add a property to the mesh to store original vertex positions
143 mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
144
145 for ( int i = 0 ; i < _iterations ; ++i ) {
146
147 // Copy original positions to backup ( in Vertex property )
148 for (auto v_it : mesh->vertices()) {
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 (auto v_it : mesh->vertices()) {
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 for (auto voh_it : v_it.outgoing_halfedges()) {
168 // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
169 point += mesh->property( origPositions, mesh->to_vertex_handle(voh_it) );
170
171 // Check if the current Halfedge is a boundary halfedge
172 // If it is, abort and keep the current vertex position
173 if ( mesh->is_boundary( voh_it ) ) {
174 skip = true;
175 break;
176 }
177
178 }
179
180 // Devide by the valence of the current vertex
181 point /= mesh->valence( v_it );
182
183 if ( ! skip ) {
184 // Set new position for the mesh if its not on the boundary
185 mesh->point(v_it) = point;
186 }
187 }
188
189 }// Iterations end
190
191 // Remove the property
192 mesh->remove_property( origPositions );
193
194 mesh->update_normals();
195
196 emit updatedObject( o_it->id(), UPDATE_GEOMETRY );
197
198 // Create backup
199 emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY );
200
201 } else if ( o_it->dataType( DATA_POLY_MESH ) ) {
202
203 // Get the mesh to work on
204 PolyMesh* mesh = PluginFunctions::polyMesh(*o_it);
205
206 // Property for the active mesh to store original point positions
208
209 // Add a property to the mesh to store original vertex positions
210 mesh->add_property( origPositions, "SmootherPlugin_Original_Positions" );
211
212 for ( int i = 0 ; i < _iterations ; ++i ) {
213
214 // Copy original positions to backup ( in Vertex property )
215 for (auto v_it : mesh->vertices()) {
216 mesh->property( origPositions, v_it ) = mesh->point(v_it);
217 // See if at least one vertex has been selected
218 selectionExists |= mesh->status(v_it).selected();
219 }
220
221 // Do one smoothing step (For each point of the mesh ... )
222 for (auto v_it : mesh->vertices()) {
223
224 if(selectionExists && mesh->status(v_it).selected() == false) {
225 continue;
226 }
227
228 PolyMesh::Point point = PolyMesh::Point(0.0,0.0,0.0);
229
230 // Flag, to skip boundary vertices
231 bool skip = false;
232
233 // ( .. for each Outoing halfedge .. )
234 for (auto voh_it : v_it.outgoing_halfedges()) {
235 // .. add the (original) position of the Neighbour ( end of the outgoing halfedge )
236 point += mesh->property( origPositions, mesh->to_vertex_handle(voh_it) );
237
238 // Check if the current Halfedge is a boundary halfedge
239 // If it is, abort and keep the current vertex position
240 if ( mesh->is_boundary( voh_it ) ) {
241 skip = true;
242 break;
243 }
244
245 }
246
247 // Devide by the valence of the current vertex
248 point /= mesh->valence( v_it );
249
250 if ( ! skip ) {
251 // Set new position for the mesh if its not on the boundary
252 mesh->point(v_it) = point;
253 }
254 }
255
256 }// Iterations end
257
258 // Remove the property
259 mesh->remove_property( origPositions );
260
261 mesh->update_normals();
262
263 emit updatedObject( o_it->id() , UPDATE_GEOMETRY);
264
265 // Create backup
266 emit createBackup(o_it->id(), "Simple Smoothing", UPDATE_GEOMETRY);
267
268 } else {
269
270 emit log(LOGERR, "DataType not supported.");
271 }
272 }
273
274 // Show script logging
275 emit scriptInfo("simpleLaplace(" + QString::number(_iterations) + ")");
276
277 emit updateView();
278}
279
280
281
282
@ LOGERR
#define DATA_POLY_MESH
Definition PolyMesh.hh:59
#define DATA_TRIANGLE_MESH
void update_normals()
Compute normals for all primitives.
Kernel::Point Point
Coordinate type.
Definition PolyMeshT.hh:112
QIcon * toolIcon_
Icon of the toolbox.
void pluginsInitialized()
Set the scripting slot descriptions.
void simpleLaplace()
simpleLaplace
QSpinBox * iterationsSpinbox_
SpinBox for Number of iterations.
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(4))
Geometry updated.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
const QStringList TARGET_OBJECTS("target")
Iterable object range.