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 // CLASS SmootherPlugin - IMPLEMENTATION
53 //
54 //=============================================================================
55 
56 
57 //== INCLUDES =================================================================
58 
59 
60 #include "SmootherPlugin.hh"
61 
62 #include "SmootherObject.hh"
63 
64 #if QT_VERSION >= 0x050000
65 #else
66 #include <QtGui>
67 #endif
68 
69 #define SMOOTHER "SmootherData"
70 
71 //== IMPLEMENTATION ==========================================================
72 
73 SmootherPlugin::SmootherPlugin() :
74  tool_(0),
75  toolIcon_(0)
76 {
77 }
78 
79 //-----------------------------------------------------------------------------
80 
81 void
82 SmootherPlugin::
83 initializePlugin()
84 {
85  if ( OpenFlipper::Options::gui() ) {
87  QSize size(100, 100);
88  tool_->resize(size);
89 
90  // connect signals->slots
91  connect(tool_->pB_smooth,SIGNAL(clicked() ),this,SLOT(slot_smooth()));
92 
93  toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"smoother2.png");
94  emit addToolbox( tr("Smoother") , tool_, toolIcon_ );
95  }
96 }
97 
98 //-----------------------------------------------------------------------------
99 
103 void
105 
106  emit setSlotDescription("smooth(int,int,QString,QString,double,bool)", "Smooth an object",
107  QString("object_id,iterations,direction,continuity,maxDistance,respectFeatures").split(","),
108  QString("id of an object, number of smoothing iterations, Smoothing direction. (tangential;normal;tangential+normal), Continuity. (C1 or C2), max distance the smoothed mesh is allowed to differ from the original,Keep features intact").split(","));
109 
110  emit setSlotDescription("smooth(int,int,QString,QString,double)", "Smooth an object",
111  QString("object_id,iterations,direction,continuity,maxDistance").split(","),
112  QString("id of an object, number of smoothing iterations, Smoothing direction. (tangential;normal;tangential+normal), Continuity. (C1 or C2), max distance the smoothed mesh is allowed to differ from the original").split(","));
113 
114  emit setSlotDescription("smooth(int,int,QString,QString)", "Smooth an object",
115  QString("object_id,iterations,direction,continuity").split(","),
116  QString("id of an object, number of smoothing iterations, Smoothing direction. (tangential;normal;tangential+normal), Continuity. (C1 or C2)").split(","));
117 
118 }
119 
120 
121 //-----------------------------------------------------------------------------
122 
128 void
131 {
132  bool found = false;
133 
135  o_it != PluginFunctions::objectsEnd(); ++o_it) {
136 
137  QString jobDescription = "Smoothed (";
138 
140 
141  if ( object == 0 ) {
142  emit log(LOGWARN , "Unable to get object ( Only Triangle Meshes supported)");
143  continue;
144  }
145 
146  found = true;
147 
148  SmootherObject* data = dynamic_cast< SmootherObject* > ( o_it->objectData(SMOOTHER) );
149 
150  // Get triangle mesh
151  TriMesh* mesh = PluginFunctions::triMesh(*o_it);
152 
153  if ( mesh == NULL ) {
154  emit log(LOGERR, "Unable to get mesh from object( Only Triangle Meshes supported)");
155  return;
156  }
157 
158  if (data == 0){
159  data = new SmootherObject();
160  o_it->setObjectData(SMOOTHER, data);
161  }
162 
163  // Create smoother
164  SmootherType smoother(*mesh);
165 
167  if( tool_->rbTangential_and_Normal->isChecked() ) {
169  jobDescription += "tangential and normal,";
170  } else if( tool_->rbNormal->isChecked() ) {
172  jobDescription += "normal,";
173  } else if( tool_->rbTangential->isChecked() ) {
175  jobDescription += "tangential,";
176  }
177 
178  // Set perObjectData
179  data->component(component);
180 
181  OpenMesh::Smoother::SmootherT< TriMesh >::Continuity continuity = OpenMesh::Smoother::SmootherT< TriMesh >::C0;
182  if( tool_->rB_c0->isChecked() ) {
184  jobDescription += "C0";
185  } else if( tool_->rB_c1->isChecked() ) {
187  jobDescription += "C1";
188  }
189 
190  // Set perObjectData
191  data->continuity(continuity);
192 
193  // Read maximum distance Error from lineEdit
194  if ( tool_->cbDistance->isChecked() ) {
195  QString value;
196  value = tool_->distance->text();
197  bool ok = false;
198 
199  double absoluteError = value.toDouble(&ok);
200 
201  if ( ok ) {
202  data->distance(absoluteError);
203  smoother.set_absolute_local_error( absoluteError );
204  } else {
205  emit log(LOGWARN , "Unable to read distance error from LineEdit");
206  }
207 
208  jobDescription += ",max_error: " + QString::number(absoluteError);
209  }
210 
211  // Set perObjectData
212  data->features(tool_->respectFeatures->isChecked());
213  data->iterations(tool_->sB_iter->value());
214 
215  // Initialize smoother
216 
217  if(tool_->cbReinitialize->isChecked() || !data->initialized())
218  {
219  smoother.initialize(component,continuity );
220  data->initialized(true);
221  }
222 
223  smoother.skip_features(data->features());
224 
225  smoother.smooth( data->iterations() );
226 
227  jobDescription += ") " + QString::number(tool_->sB_iter->value()) + " iterations";
228 
229  mesh->update_normals();
230 
231  emit updatedObject( o_it->id(), UPDATE_GEOMETRY );
232  emit createBackup(o_it->id(), "Smoothing", UPDATE_GEOMETRY );
233  }
234 
235  if ( !found )
236  emit log(LOGERR , tr("Unable to smooth. No triangle mesh selected as target!") );
237 
238 }
239 
240 
241 //-----------------------------------------------------------------------------
242 
243 void SmootherPlugin::smooth(int _objectId , int _iterations , QString _direction , QString _continuity, double _maxDistance, bool _respectFeatures ) {
244 
245  BaseObjectData* baseObjectData;
246  if ( ! PluginFunctions::getObject(_objectId,baseObjectData) ) {
247  emit log(LOGERR,"Unable to get Object");
248  return;
249  }
250 
251  if ( baseObjectData->dataType() == DATA_TRIANGLE_MESH ) {
252  TriMeshObject* object = PluginFunctions::triMeshObject(baseObjectData);
253 
254  QString jobDescription = "Smoothed (";
255 
256  if ( object == 0 ) {
257  emit log(LOGWARN , "Unable to get object ( Only Triangle Meshes supported)");
258  return;
259  }
260 
261  SmootherObject* data = dynamic_cast< SmootherObject* > ( object->objectData(SMOOTHER) );
262 
263  // Get triangle mesh
264  TriMesh* mesh = PluginFunctions::triMesh(object);
265 
266  if ( mesh == NULL ) {
267  emit log(LOGERR, "Unable to get mesh from object( Only Triangle Meshes supported)");
268  return;
269  }
270 
271  if (data == 0){
272  data = new SmootherObject();
273  object->setObjectData(SMOOTHER, data);
274  }
275 
276  SmootherType smoother(*mesh);
277 
279  bool tangential = _direction.contains("tangential");
280  bool normal = _direction.contains("normal");
281 
282  if ( tangential && normal ) {
284  jobDescription += "tangential and normal,";
285  } else if ( tangential ) {
287  jobDescription += "normal,";
288  } else {
290  jobDescription += "tangential,";
291  }
292 
293  // Set perObjectData
294  data->component(component);
295 
296  OpenMesh::Smoother::SmootherT< TriMesh >::Continuity continuity = OpenMesh::Smoother::SmootherT< TriMesh >::C0;
297  bool c0 = _continuity.contains("C0");
298  bool c1 = _continuity.contains("C1");
299 
300  if ( c0 && c1 )
301  std::cerr << "Continuity C0 + C1 ? Using C1" << std::endl;
302  if( c1 ) {
304  jobDescription += "C1";
305  } else if( c0 ) {
307  jobDescription += "C0";
308  }
309 
310  // Set perObjectData
311  data->continuity(continuity);
312 
313  if ( _maxDistance > 0.0) {
314  // Set perObjectData
315  data->distance(_maxDistance);
316  smoother.set_absolute_local_error( _maxDistance );
317  jobDescription += ",max_error: " + QString::number(_maxDistance);
318  } else {
319  // Set perObjectData
320  data->distance( FLT_MAX );
321  smoother.set_absolute_local_error( FLT_MAX );
322  }
323 
324  // Keep features?
325  data->features(_respectFeatures);
326  smoother.skip_features(_respectFeatures);
327 
328  smoother.initialize(component,continuity);
329 
330  smoother.smooth( _iterations );
331 
332  jobDescription += ") " + QString::number(_iterations) + " iterations";
333 
334  mesh->update_normals();
335 
336  emit updatedObject( object->id(), UPDATE_GEOMETRY );
337 
338  // Create backup
339  emit createBackup(object->id(),"Smoothing", UPDATE_GEOMETRY );
340 
341  emit scriptInfo(tr("smooth(%1, %2, %3, %4, %5)").arg(QString::number(_objectId), QString::number(_iterations),
342  _direction, _continuity, QString::number(_maxDistance)));
343 
344  } else {
345  emit log(LOGERR,"Unsupported object type for smoother");
346  return;
347  }
348 
349 }
350 
351 //-----------------------------------------------------------------------------
352 
353 #if QT_VERSION < 0x050000
354  Q_EXPORT_PLUGIN2( SmootherPlugin , SmootherPlugin );
355 #endif
356 
void slot_smooth()
Slot connected to the smooth button in the toolbox.
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
void update_normals()
Compute normals for all primitives.
Definition: PolyMeshT.cc:241
void set_absolute_local_error(Scalar _err)
Set local error as an absolute value.
Definition: SmootherT.cc:283
bool getObject(int _identifier, BSplineCurveObject *&_object)
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void pluginsInitialized()
Set the scripting slot descriptions.
int id() const
Definition: BaseObject.cc:201
void smooth(unsigned int _n)
Do _n smoothing iterations.
void skip_features(bool _state)
enable or disable feature handling
Definition: SmootherT.hh:172
const UpdateType UPDATE_GEOMETRY(UpdateTypeSet(1)<< 2)
Geometry updated.
TriMeshObject * triMeshObject(BaseObjectData *_object)
Cast an BaseObject to a TriMeshObject if possible.
SmootherToolbarWidget * tool_
Widget for Toolbox.
void smooth(int _objectId, int _iterations, QString _direction, QString _continuity, double _maxDistance=-1.0, bool _respectFeatures=true)
smooth an object
#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.