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