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 
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
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 
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 
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 
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 
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 
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 
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 
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
int id() const
Definition: BaseObject.cc:190
virtual void scriptInfo(QString _functionWithParameters)
Emit this signal if a scriptable function is executed.
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
const QStringList TARGET_OBJECTS("target")
Iterable object range.
virtual void updatedObject(int _objectId)
An object has been changed or added by this plugin.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void remesh(MeshT &_mesh, const double _targetEdgeLength)
do the remeshing
void initializePlugin()
init the Toolbox
Predefined datatypes.
Definition: DataTypes.hh:83
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
virtual void updateView()
Update current view in Main Application.
Thread handling class for OpenFlipper.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
void pluginsInitialized()
Initialize the plugin.
void update_normals()
Compute normals for all primitives.
virtual void setSlotDescription(QString _slotName, QString _slotDescription, QStringList _parameters, QStringList _descriptions)
Set a description for a public slot.