Developer Documentation

IsotropicRemesherPlugin.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 #include "IsotropicRemesherPlugin.hh"
45 #include "IsotropicRemesherT.hh"
46
47 IsotropicRemesherPlugin::IsotropicRemesherPlugin() :
48 tool_(0),
49 toolIcon_(0),
50 edgeLength_(0),
51 thread_(0)
52 {
53 }
54
56 void IsotropicRemesherPlugin::initializePlugin() {
57 if ( OpenFlipper::Options::gui() ) {
58 tool_ = new IsotropicRemesherToolBox();
59
60 QSize size(300, 300);
61 tool_->resize(size);
62
63 connect(tool_->remeshButton, SIGNAL(clicked()), this, SLOT(slotRemeshButtonClicked()) );
64
65 connect(tool_->minEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMinLength()) );
66 connect(tool_->maxEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMaxLength()) );
67 connect(tool_->meanEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMeanLength()) );
68
69 toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"remesher.png");
70 emit addToolbox( tr("Isotropic Remesher") , tool_, toolIcon_ );
71 }
72 }
73
74 void IsotropicRemesherPlugin::slotRemeshButtonClicked() {
75 edgeLength_ = tool_->targetEdgeLength->value();
76
77 if ( thread_ == 0){
78 thread_ = new OpenFlipperThread(name() + "IsotropicRemesh"); // Create your thread containing a unique id \n
79 connect(thread_,SIGNAL( finished(QString)), this,SIGNAL(finishJob(QString))); // connect your threads finish info to the global one ( you can do the same for a local one ) \n
80 connect(thread_,SIGNAL( function() ), this,SLOT(slotRemesh()),Qt::DirectConnection); // You can directly give a slot of your app that gets called \n
81 connect(this,SIGNAL( finishJob(QString)), this, SLOT(threadFinished(QString)), Qt::QueuedConnection);
82 }
83
84 emit startJob( name() + "IsotropicRemesh", "Isotropic remeshing" , 0 , 100 , true); // As long as meshes cannot be locked, this thread has to be blocking. Otherwise, during operation the mesh could be deleted. We don't want that!
85
86 thread_->start(); // start thread
87 thread_->startProcessing(); // start processing
88 }
89
90
91 void IsotropicRemesherPlugin::slotRemesh(){
92
93 //read one target objects
94 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
95 o_it != PluginFunctions::objectsEnd(); ++o_it) {
96
97 //check dataType
98 if ( o_it->dataType(DATA_TRIANGLE_MESH) ) {
99 TriMesh* mesh = PluginFunctions::triMesh(o_it);
100
101 ProgressEmitter prgEmt(name() + "IsotropicRemesh");
102 connect (&prgEmt, SIGNAL(changeDescription(QString,QString)), this, SIGNAL(setJobDescription(QString,QString)) );
103 connect (&prgEmt, SIGNAL(signalJobState(QString,int)), this, SIGNAL(setJobState(QString,int)) );
104 IsotropicRemesher< TriMesh > remesher(&prgEmt);
105
106 remesher.remesh(*mesh, edgeLength_);
107
108 mesh->update_normals();
109
110 }else{
111 emit log("Remeshing currently only implemented for triangle Meshes");
112 }
113 }
114 }
115
116 void IsotropicRemesherPlugin::threadFinished(QString /*_jobId*/) {
117
118 std::cerr << "threadFinished() called" << std::endl;
119
120 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
121 o_it != PluginFunctions::objectsEnd(); ++o_it) {
122
123 emit updatedObject( o_it->id(), UPDATE_ALL );
124
125 emit createBackup(o_it->id(),"Isotropic Remeshing");
126
127 emit updateView();
128
129 }
130 }
131
132 void IsotropicRemesherPlugin::slotSetMinLength()
133 {
134 double current = 0.0;
135 bool first = true;
136
137 bool ok;
138 emit functionExists( "infomeshobject" , "minEdgeLength(int)", ok ) ;
139 if (!ok)
140 return;
141
142 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
143 o_it != PluginFunctions::objectsEnd(); ++o_it) {
144
145 if (first)
146 {
147 current = RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() );
148 first = false;
149 }
150 else
151 current = qMin (current, RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() ));
152
153 }
154
155 if (!first)
156 tool_->targetEdgeLength->setValue (current);
157 }
158
159 void IsotropicRemesherPlugin::slotSetMaxLength()
160 {
161 double current = 0.0;
162 bool first = true;
163
164 bool ok;
165 emit functionExists( "infomeshobject" , "maxEdgeLength(int)", ok ) ;
166 if (!ok)
167 return;
168
169 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
170 o_it != PluginFunctions::objectsEnd(); ++o_it) {
171
172 if (first)
173 {
174 current = RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() );
175 first = false;
176 }
177 else
178 current = qMax (current, RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() ));
179
180 }
181
182 if (!first)
183 tool_->targetEdgeLength->setValue (current);
184 }
185
186 void IsotropicRemesherPlugin::slotSetMeanLength()
187 {
188 double current = 0.0;
189 int div = 0;
190
191 bool ok;
192 emit functionExists( "infomeshobject" , "edgeCount(int)", ok ) ;
193 if (!ok)
194 return;
195
196 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH)) ;
197 o_it != PluginFunctions::objectsEnd(); ++o_it) {
198
199
200 current += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id()) *
201 RPC::callFunctionValue<double>("infomeshobject" , "meanEdgeLength",o_it->id() );
202 div += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id() );
203 }
204
205 if (div > 0)
206 tool_->targetEdgeLength->setValue (current / div);
207 }
208
209
211 void IsotropicRemesherPlugin::pluginsInitialized(){
212
213 emit setSlotDescription("isotropicRemesh(int,double)", "Isotropic Remeshing",
214 QString("object_id,targetEdgeLength").split(","),
215 QString("id of an object, target edge length").split(","));
216 }
217
218
219 void IsotropicRemesherPlugin::isotropicRemesh(int _objectID, double _targetEdgeLength ){
220 BaseObjectData* object = 0;
221
222
223 if ( PluginFunctions::getObject(_objectID, object) ){
224
225 //check dataType
226 if ( object->dataType(DATA_TRIANGLE_MESH)) {
227
228 TriMesh* mesh = PluginFunctions::triMesh(object);
229
230 IsotropicRemesher< TriMesh > remesher;
231
232 remesher.remesh(*mesh, _targetEdgeLength);
233
234 mesh->update_normals();
235
236 emit updatedObject( object->id(), UPDATE_ALL );
237
238 emit scriptInfo("isotropicRemesh(" + QString::number(_objectID) + ", " + QString::number(_targetEdgeLength) + ")");
239
240 emit updateView();
241
242 return;
243
244 }else{
245 emit log("Remeshing currently only implemented for triangle Meshes");
246 return;
247 }
248 }else{
249 emit log("Unable to get object");
250 }
251 }
252
253
254
255
IsotropicRemesherPlugin::pluginsInitialized
void pluginsInitialized()
Initialize the plugin.
Definition: IsotropicRemesherPlugin.cc:211
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
IsotropicRemesher::remesh
void remesh(MeshT &_mesh, const double _targetEdgeLength)
do the remeshing
Definition: IsotropicRemesherT_impl.hh:56
IsotropicRemesherPlugin::initializePlugin
void initializePlugin()
init the Toolbox
Definition: IsotropicRemesherPlugin.cc:56
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
ProgressEmitter
Definition: ProgressEmitter.hh:46
BaseInterface::updateView
virtual void updateView()
Update current view in Main Application.
Definition: BaseInterface.hh:122
BaseInterface::setSlotDescription
virtual void setSlotDescription(QString _slotName, QString _slotDescription, QStringList _parameters, QStringList _descriptions)
Set a description for a public slot.
Definition: BaseInterface.hh:305
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:296
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:134
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
BaseObject::id
int id() const
Definition: BaseObject.cc:190
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:177
IsotropicRemesherToolBox
Definition: IsotropicRemesherToolbox.hh:48
IsotropicRemesher
Definition: IsotropicRemesherT.hh:50
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:441
ScriptInterface::scriptInfo
virtual void scriptInfo(QString _functionWithParameters)
Emit this signal if a scriptable function is executed.
Definition: ScriptInterface.hh:131
BaseObjectData
Definition: BaseObjectData.hh:102
OpenMesh::PolyMeshT::update_normals
void update_normals()
Compute normals for all primitives.
Definition: PolyMeshT_impl.hh:317
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
BaseInterface::updatedObject
virtual void updatedObject(int _objectId)
An object has been changed or added by this plugin.
Definition: BaseInterface.hh:146
OpenFlipperThread
Thread handling class for OpenFlipper.
Definition: OpenFlipperThread.hh:77