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
47 #include <OpenMesh/Tools/Subdivider/Uniform/LoopT.hh>
48 #include <OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh>
49 #include <OpenMesh/Tools/Subdivider/Uniform/Sqrt3InterpolatingSubdividerLabsikGreinerT.hh>
50 #include <OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.hh>
51 #include <OpenMesh/Tools/Subdivider/Uniform/LongestEdgeT.hh>
52
53 #include <OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.hh>
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;
106 if ( PluginFunctions::getTargetIdentifiers( 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;
145 if ( PluginFunctions::getTargetIdentifiers( 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)) {
175 OpenMesh::Subdivider::Uniform::LongestEdgeT<TriMesh, double> subdivider;
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
217 OpenMesh::Subdivider::Uniform::CatmullClarkT<PolyMesh> subdivider;
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 {
246 OpenMesh::Subdivider::Uniform::LoopT<TriMesh,double> subdivider;
247
248 subdivider.attach(*mesh);
249 subdivider(*mesh,_steps,_update_points);
250 subdivider.detach();
251 }
252 else if ( _algorithm.contains("sqrt3",Qt::CaseInsensitive) )
253 {
254 OpenMesh::Subdivider::Uniform::Sqrt3T<TriMesh,double> subdivider;
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 {
262 OpenMesh::Subdivider::Uniform::InterpolatingSqrt3LGT<TriMesh,double> subdivider;
263
264 subdivider.attach(*mesh);
265 subdivider(_steps,_update_points);
266 subdivider.detach();
267 }
268 else if ( _algorithm.contains("modifiedButterfly",Qt::CaseInsensitive) )
269 {
270 OpenMesh::Subdivider::Uniform::ModifiedButterflyT<TriMesh,double> subdivider;
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
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
ModifiedButterFlyT.hh
BaseObject::id
int id() const
Definition: BaseObject.cc:190
SubdividerPlugin::subdivide
void subdivide(int _objectId, QString _algorithm, int _steps, bool _update_points=true)
Scripting slot for subdivision.
Definition: SubdividerPlugin.cc:197
PluginFunctions::getTargetIdentifiers
bool getTargetIdentifiers(std::vector< int > &_identifiers)
Get the identifiers of all objects marked as a target object.
Definition: PluginFunctions.cc:280
Sqrt3InterpolatingSubdividerLabsikGreinerT.hh
SubdividerPlugin::simpleSubdivide
void simpleSubdivide(int _objectId, QString _algorithm, int _steps, double _parameter, bool _update_points=true)
Scripting slot for the simple subdivision algorithms.
Definition: SubdividerPlugin.cc:164
LongestEdgeT.hh
CatmullClarkT.hh
Sqrt3T.hh
LoopT.hh
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
OpenMesh::PolyMeshT::update_vertex_normals
void update_vertex_normals()
Update normal vectors for all vertices.
Definition: PolyMeshT_impl.hh:466
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:134
LOGERR
Definition: LoggingInterface.hh:96
OpenMesh::Subdivider::Uniform::SubdividerT::attach
bool attach(MeshType &_m)
Definition: SubdividerT.hh:132
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
OpenMesh::Subdivider::Uniform::ModifiedButterflyT
Definition: ModifiedButterFlyT.hh:92
OpenMesh::Subdivider::Uniform::SubdividerT::detach
void detach(void)
Definition: SubdividerT.hh:155
OpenMesh::Subdivider::Uniform::LoopT
Definition: LoopT.hh:91
subdividerToolbarWidget
Definition: subdividerToolbar.hh:46
OpenMesh::PolyMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:94
OpenMesh::Subdivider::Uniform::Sqrt3T
Definition: Sqrt3T.hh:98
OpenMesh::Subdivider::Uniform::CatmullClarkT
Definition: CatmullClarkT.hh:85
BaseInterface::updateView
virtual void updateView()
Update current view in Main Application.
Definition: BaseInterface.hh:122
OpenMesh::PolyMeshT::update_face_normals
void update_face_normals()
Update normal vectors for all faces.
Definition: PolyMeshT_impl.hh:277
PluginFunctions::polyMesh
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Definition: PluginFunctionsPolyMesh.cc:128
UPDATE_TOPOLOGY
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
OpenMesh::Subdivider::Uniform::LongestEdgeT
Definition: LongestEdgeT.hh:99
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
BaseObjectData
Definition: BaseObjectData.hh:102
OpenMesh::Subdivider::Uniform::InterpolatingSqrt3LGT
Definition: Sqrt3InterpolatingSubdividerLabsikGreinerT.hh:106
BaseInterface::setSlotDescription
virtual void setSlotDescription(QString _slotName, QString _slotDescription, QStringList _parameters, QStringList _descriptions)
Set a description for a public slot.
Definition: BaseInterface.hh:305