Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 #include "IsotropicRemesherPlugin.hh"
51 #include "IsotropicRemesherT.hh"
52 
53 IsotropicRemesherPlugin::IsotropicRemesherPlugin() :
54 tool_(0),
55 toolIcon_(0),
56 edgeLength_(0),
57 thread_(0)
58 {
59 }
60 
63  if ( OpenFlipper::Options::gui() ) {
64  tool_ = new IsotropicRemesherToolBox();
65 
66  QSize size(300, 300);
67  tool_->resize(size);
68 
69  connect(tool_->remeshButton, SIGNAL(clicked()), this, SLOT(slotRemeshButtonClicked()) );
70 
71  connect(tool_->minEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMinLength()) );
72  connect(tool_->maxEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMaxLength()) );
73  connect(tool_->meanEdgeLength, SIGNAL(clicked()), this, SLOT(slotSetMeanLength()) );
74 
75  toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"remesher.png");
76  emit addToolbox( tr("Isotropic Remesher") , tool_, toolIcon_ );
77  }
78 }
79 
80 void IsotropicRemesherPlugin::slotRemeshButtonClicked() {
81  edgeLength_ = tool_->targetEdgeLength->value();
82 
83  if ( thread_ == 0){
84  thread_ = new OpenFlipperThread(name() + "IsotropicRemesh"); // Create your thread containing a unique id \n
85  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
86  connect(thread_,SIGNAL( function() ), this,SLOT(slotRemesh()),Qt::DirectConnection); // You can directly give a slot of your app that gets called \n
87  connect(this,SIGNAL( finishJob(QString)), this, SLOT(threadFinished(QString)), Qt::QueuedConnection);
88  }
89 
90  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!
91 
92  thread_->start(); // start thread
93  thread_->startProcessing(); // start processing
94 }
95 
96 
97 void IsotropicRemesherPlugin::slotRemesh(){
98 
99  //read one target objects
101  o_it != PluginFunctions::objectsEnd(); ++o_it) {
102 
103  //check dataType
104  if ( o_it->dataType(DATA_TRIANGLE_MESH) ) {
105  TriMesh* mesh = PluginFunctions::triMesh(o_it);
106 
107  ProgressEmitter prgEmt(name() + "IsotropicRemesh");
108  connect (&prgEmt, SIGNAL(changeDescription(QString,QString)), this, SIGNAL(setJobDescription(QString,QString)) );
109  connect (&prgEmt, SIGNAL(signalJobState(QString,int)), this, SIGNAL(setJobState(QString,int)) );
110  IsotropicRemesher< TriMesh > remesher(&prgEmt);
111 
112  remesher.remesh(*mesh, edgeLength_);
113 
114  mesh->update_normals();
115 
116  }else{
117  emit log("Remeshing currently only implemented for triangle Meshes");
118  }
119  }
120 }
121 
122 void IsotropicRemesherPlugin::threadFinished(QString /*_jobId*/) {
123 
124  std::cerr << "threadFinished() called" << std::endl;
125 
127  o_it != PluginFunctions::objectsEnd(); ++o_it) {
128 
129  emit updatedObject( o_it->id(), UPDATE_ALL );
130 
131  emit createBackup(o_it->id(),"Isotropic Remeshing");
132 
133  emit updateView();
134 
135  }
136 }
137 
138 void IsotropicRemesherPlugin::slotSetMinLength()
139 {
140  double current = 0.0;
141  bool first = true;
142 
143  bool ok;
144  emit functionExists( "infomeshobject" , "minEdgeLength(int)", ok ) ;
145  if (!ok)
146  return;
147 
149  o_it != PluginFunctions::objectsEnd(); ++o_it) {
150 
151  if (first)
152  {
153  current = RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() );
154  first = false;
155  }
156  else
157  current = qMin (current, RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() ));
158 
159  }
160 
161  if (!first)
162  tool_->targetEdgeLength->setValue (current);
163 }
164 
165 void IsotropicRemesherPlugin::slotSetMaxLength()
166 {
167  double current = 0.0;
168  bool first = true;
169 
170  bool ok;
171  emit functionExists( "infomeshobject" , "maxEdgeLength(int)", ok ) ;
172  if (!ok)
173  return;
174 
176  o_it != PluginFunctions::objectsEnd(); ++o_it) {
177 
178  if (first)
179  {
180  current = RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() );
181  first = false;
182  }
183  else
184  current = qMax (current, RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() ));
185 
186  }
187 
188  if (!first)
189  tool_->targetEdgeLength->setValue (current);
190 }
191 
192 void IsotropicRemesherPlugin::slotSetMeanLength()
193 {
194  double current = 0.0;
195  int div = 0;
196 
197  bool ok;
198  emit functionExists( "infomeshobject" , "edgeCount(int)", ok ) ;
199  if (!ok)
200  return;
201 
203  o_it != PluginFunctions::objectsEnd(); ++o_it) {
204 
205 
206  current += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id()) *
207  RPC::callFunctionValue<double>("infomeshobject" , "meanEdgeLength",o_it->id() );
208  div += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id() );
209  }
210 
211  if (div > 0)
212  tool_->targetEdgeLength->setValue (current / div);
213 }
214 
215 
218 
219  emit setSlotDescription("isotropicRemesh(int,double)", "Isotropic Remeshing",
220  QString("object_id,targetEdgeLength").split(","),
221  QString("id of an object, target edge length").split(","));
222 }
223 
224 
225 void IsotropicRemesherPlugin::isotropicRemesh(int _objectID, double _targetEdgeLength ){
226  BaseObjectData* object = 0;
227 
228 
229  if ( PluginFunctions::getObject(_objectID, object) ){
230 
231  //check dataType
232  if ( object->dataType(DATA_TRIANGLE_MESH)) {
233 
234  TriMesh* mesh = PluginFunctions::triMesh(object);
235 
237 
238  remesher.remesh(*mesh, _targetEdgeLength);
239 
240  mesh->update_normals();
241 
242  emit updatedObject( object->id(), UPDATE_ALL );
243 
244  emit scriptInfo("isotropicRemesh(" + QString::number(_objectID) + ", " + QString::number(_targetEdgeLength) + ")");
245 
246  emit updateView();
247 
248  return;
249 
250  }else{
251  emit log("Remeshing currently only implemented for triangle Meshes");
252  return;
253  }
254  }else{
255  emit log("Unable to get object");
256  }
257 }
258 
259 #if QT_VERSION < 0x050000
260  Q_EXPORT_PLUGIN2( isotropicRemesherPlugin , IsotropicRemesherPlugin );
261 #endif
262 
263 
264 
QString name()
Return a name for the plugin.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool getObject(int _identifier, BSplineCurveObject *&_object)
void initializePlugin()
init the Toolbox
const QStringList TARGET_OBJECTS("target")
Iterable object range.
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
void remesh(MeshT &_mesh, const double _targetEdgeLength)
do the remeshing
Thread handling class for OpenFlipper.
Predefined datatypes.
Definition: DataTypes.hh:96
void startProcessing()
start processing
void pluginsInitialized()
Initialize the plugin.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
int id() const
Definition: BaseObject.cc:201