Developer Documentation
SubdividerPlugin.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 
45 #include "SubdividerPlugin.hh"
46 
52 
54 
55 
56 
57 SubdividerPlugin::SubdividerPlugin() :
58  tool_(0),
59  toolIcon_(0)
60 {
61 
62 }
63 
64 
65 void SubdividerPlugin::initializePlugin()
66 {
67  if ( OpenFlipper::Options::gui() ) {
68  tool_ = new subdividerToolbarWidget();
69  QSize size(300, 300);
70  tool_->resize(size);
71 
72  connect(tool_->subdivide_uniform_toolButton, SIGNAL( clicked() ), this, SLOT( slotSubdivideUniformButton() ) );
73  connect(tool_->simpleButton, SIGNAL( clicked() ), this, SLOT( slotSimpleSubdivideButton() ) );
74 
75 
76 
77  toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"subdivider.png");
78  emit addToolbox( tr("Subdivider") , tool_, toolIcon_ );
79  }
80 }
81 
82 void SubdividerPlugin::pluginsInitialized()
83 {
84  emit setSlotDescription("subdivide(int,QString,int,bool)", "Subdivide a triangular or polygonal mesh. For polygonal meshes use catmullClark, the other algorithms are for triangular meshes.",
85  QString("object_id,algorithm,iterations,update_points").split(","),
86  QString(" id of an object, algorithm to use ( loop | sqrt3 | interpolating_sqrt3 | modifiedButterfly | catmullClark ), number of iterations, update original points").split(","));
87 
88  emit setSlotDescription("subdivide(int,QString,int)", "Subdivide a triangular or polygonal mesh. For polygonal meshes use catmullClark, the other algorithms are for triangular meshes. This function will modify the original point locations.",
89  QString("object_id,algorithm,iterations").split(","),
90  QString(" id of an object, algorithm to use ( loop | sqrt3 | interpolating_sqrt3 | modifiedButterfly | catmullClark ), number of iterations").split(","));
91 
92  emit setSlotDescription("simpleSubdivide(int,QString,int,double,bool)", "Subdivide a triangular mesh.",
93  QString("object_id,algorithm,iterations,parameter,update_points").split(","),
94  QString(" id of an object, algorithm to use ( longest ), number of iterations, additional parameter(e.g. maximal edge length for longest), update original points").split(","));
95 
96  emit setSlotDescription("simpleSubdivide(int,QString,int,double)", "Subdivide a triangular mesh. This function will modify the original point locations.",
97  QString("object_id,algorithm,iterations,parameter").split(","),
98  QString(" id of an object, algorithm to use ( longest ), number of iterations, additional parameter(e.g. maximal edge length for longest)").split(","));
99 }
100 
101 //-----------------------------------------------------------------------------
102 
103 void SubdividerPlugin::slotSubdivideUniformButton()
104 {
105  std::vector< int > ids;
107  {
108 
109  for (unsigned int i = 0; i < ids.size(); ++i)
110  {
111  if(tool_->loop_radioButton->isChecked())
112  {
113  subdivide(ids[i],"loop",tool_->subdivision_steps_spinBox->value(), tool_->updatePoints->isChecked());
114  }
115  else if ( tool_->sqrt3_radioButton->isChecked() )
116  {
117  subdivide(ids[i],"sqrt3",tool_->subdivision_steps_spinBox->value(), tool_->updatePoints->isChecked());
118  }
119  else if ( tool_->LabsikGreiner_radioButton->isChecked() )
120  {
121  subdivide(ids[i],"interpolating_sqrt3",tool_->subdivision_steps_spinBox->value(), tool_->updatePoints->isChecked());
122  }
123  else if ( tool_->modifiedButterfly_radioButton->isChecked() )
124  {
125  subdivide(ids[i],"modifiedButterfly",tool_->subdivision_steps_spinBox->value(), tool_->updatePoints->isChecked());
126  }
127  else if ( tool_->catmullClark_radioButton->isChecked() )
128  {
129  subdivide(ids[i],"catmullClark",tool_->subdivision_steps_spinBox->value(), tool_->updatePoints->isChecked());
130  }
131 
132  // Create backup
133  emit createBackup(ids[i], "Subdivider", UPDATE_TOPOLOGY);
134  }
135 
136  }
137  emit updateView();
138 }
139 
140 //-----------------------------------------------------------------------------
141 
142 void SubdividerPlugin::slotSimpleSubdivideButton()
143 {
144  std::vector< int > ids;
146  {
147  for (unsigned int i = 0; i < ids.size(); ++i)
148  {
149  if(tool_->longestEdgeSplit->isChecked())
150  {
151  simpleSubdivide(ids[i],"longest",tool_->subdivision_steps_spinBox->value(),
152  tool_->maximalEdgeLength->value(), tool_->updatePoints->isChecked());
153 
154  // Create backup
155  emit createBackup(ids[i], "Subdivider", UPDATE_TOPOLOGY);
156  }
157  }
158  }
159  emit updateView();
160 }
161 
162 //-----------------------------------------------------------------------------
163 
164 void SubdividerPlugin::simpleSubdivide(int _objectId, QString _algorithm , int _steps, double _parameter, bool _update_points) {
165 
166  BaseObjectData* object;
167  if (!test_trimesh_object(_objectId, object)) {
168  emit log(LOGERR,"The simple subdivision algorithms only work on triangular meshes.");
169  return;
170  }
171 
172  TriMesh* mesh = PluginFunctions::triMesh(object);
173 
174  if (_algorithm.contains("longest", Qt::CaseInsensitive)) {
176 
177  subdivider.attach(*mesh);
178  subdivider.set_max_edge_length(_parameter);
179  subdivider(*mesh, _steps, _update_points);
180  subdivider.detach();
181  } else {
182  emit log(LOGERR,"Unsupported algorithm in simpleSubdivide: " + _algorithm);
183  return;
184  }
185 
186  mesh->garbage_collection();
187 
188  mesh->update_face_normals();
189  mesh->update_vertex_normals();
190 
191  // Geometry and topology changed!
192  emit updatedObject(object->id(), UPDATE_TOPOLOGY);
193 }
194 
195 //-----------------------------------------------------------------------------
196 
197 void SubdividerPlugin::subdivide(int _objectId, QString _algorithm , int _steps, bool _update_points) {
198 
199  BaseObjectData* object;
200  PluginFunctions::getObject(_objectId,object);
201 
202  if(!object) {
203  emit log(LOGERR,"Unable to get Object in SubdividerPlugin::subdivide");
204  return;
205  }
206 
207 
208  // Catmull clark:
209  if ( _algorithm.contains("catmullClark",Qt::CaseInsensitive) ) {
210 
211  PolyMesh* polyMesh = PluginFunctions::polyMesh(object);
212  if ( ! polyMesh ) {
213  emit log(LOGERR,"Error: Catmull Clark only works on Poly Meshes!");
214  return;
215  }
216 
218 
219  subdivider.attach(*polyMesh);
220  subdivider(_steps,_update_points);
221  subdivider.detach();
222 
223  polyMesh->garbage_collection();
224 
225  polyMesh->update_face_normals();
226  polyMesh->update_vertex_normals();
227 
228  // Geometry and topology changed!
229  emit updatedObject(object->id(), UPDATE_TOPOLOGY);
230 
231  } else {
232 
233  //=======================================================
234  // All other algorithms work on triangular meshes here
235  //=======================================================
236 
237  TriMesh* mesh = PluginFunctions::triMesh(object);
238 
239  if ( ! mesh ) {
240  emit log(LOGERR,"Error: Unable to get trisngular mesh in subdivider!");
241  return;
242  }
243 
244  if(_algorithm.contains("loop",Qt::CaseInsensitive))
245  {
247 
248  subdivider.attach(*mesh);
249  subdivider(*mesh,_steps,_update_points);
250  subdivider.detach();
251  }
252  else if ( _algorithm.contains("sqrt3",Qt::CaseInsensitive) )
253  {
255 
256  subdivider.attach(*mesh);
257  subdivider(_steps,_update_points);
258  subdivider.detach();
259  }
260  else if ( _algorithm.contains("interpolating_sqrt(3)",Qt::CaseInsensitive) )
261  {
263 
264  subdivider.attach(*mesh);
265  subdivider(_steps,_update_points);
266  subdivider.detach();
267  }
268  else if ( _algorithm.contains("modifiedButterfly",Qt::CaseInsensitive) )
269  {
271 
272  subdivider.attach(*mesh);
273  subdivider(_steps,_update_points);
274  subdivider.detach();
275  } else {
276  emit log(LOGERR,"Unsupported or unknown subdivider for triangular meshes: " + _algorithm);
277  }
278 
279  mesh->garbage_collection();
280 
281  mesh->update_face_normals();
282  mesh->update_vertex_normals();
283 
284  // Geometry and topology changed!
285  emit updatedObject(object->id(), UPDATE_TOPOLOGY);
286 
287  }
288 
289 
290 }
291 
292 
293 //-----------------------------------------------------------------------------
294 
295 
296 bool SubdividerPlugin::test_trimesh_object(int _identifier, BaseObjectData*& _object)
297 {
298  if ( _identifier == -1)
299  return false;
300 
301  if (! PluginFunctions::getObject(_identifier,_object) )
302  return false;
303 
304  if (!_object->dataType(DATA_TRIANGLE_MESH) )
305  return false;
306  return true;
307 }
308 
309 
310 
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
virtual void updateView()
Update current view in Main Application.
virtual void setSlotDescription(QString _slotName, QString _slotDescription, QStringList _parameters, QStringList _descriptions)
Set a description for a public slot.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
void simpleSubdivide(int _objectId, QString _algorithm, int _steps, double _parameter, bool _update_points=true)
Scripting slot for the simple subdivision algorithms.
void update_vertex_normals()
Update normal vectors for all vertices.
void update_face_normals()
Update normal vectors for all faces.
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
bool getTargetIdentifiers(std::vector< int > &_identifiers)
Get the identifiers of all objects marked as a target object.
void subdivide(int _objectId, QString _algorithm, int _steps, bool _update_points=true)
Scripting slot for subdivision.