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 
96  //check dataType
97  if ( o_it->dataType(DATA_TRIANGLE_MESH) ) {
98  TriMesh* mesh = PluginFunctions::triMesh(o_it);
99 
100  ProgressEmitter prgEmt(name() + "IsotropicRemesh");
101  connect (&prgEmt, SIGNAL(changeDescription(QString,QString)), this, SIGNAL(setJobDescription(QString,QString)) );
102  connect (&prgEmt, SIGNAL(signalJobState(QString,int)), this, SIGNAL(setJobState(QString,int)) );
103  IsotropicRemesher< TriMesh > remesher(&prgEmt);
104 
105  remesher.remesh(*mesh, edgeLength_);
106 
107  mesh->update_normals();
108 
109  }else{
110  emit log("Remeshing currently only implemented for triangle Meshes");
111  }
112  }
113 }
114 
115 void IsotropicRemesherPlugin::threadFinished(QString /*_jobId*/) {
116 
117  std::cerr << "threadFinished() called" << std::endl;
118 
120 
121  emit updatedObject( o_it->id(), UPDATE_ALL );
122 
123  emit createBackup(o_it->id(),"Isotropic Remeshing");
124 
125  emit updateView();
126 
127  }
128 }
129 
130 void IsotropicRemesherPlugin::slotSetMinLength()
131 {
132  double current = 0.0;
133  bool first = true;
134 
135  bool ok;
136  emit functionExists( "infomeshobject" , "minEdgeLength(int)", ok ) ;
137  if (!ok)
138  return;
139 
141 
142  if (first)
143  {
144  current = RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() );
145  first = false;
146  }
147  else
148  current = qMin (current, RPC::callFunctionValue<double>("infomeshobject" , "minEdgeLength",o_it->id() ));
149 
150  }
151 
152  if (!first)
153  tool_->targetEdgeLength->setValue (current);
154 }
155 
156 void IsotropicRemesherPlugin::slotSetMaxLength()
157 {
158  double current = 0.0;
159  bool first = true;
160 
161  bool ok;
162  emit functionExists( "infomeshobject" , "maxEdgeLength(int)", ok ) ;
163  if (!ok)
164  return;
165 
167 
168  if (first)
169  {
170  current = RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() );
171  first = false;
172  }
173  else
174  current = qMax (current, RPC::callFunctionValue<double>("infomeshobject" , "maxEdgeLength",o_it->id() ));
175 
176  }
177 
178  if (!first)
179  tool_->targetEdgeLength->setValue (current);
180 }
181 
182 void IsotropicRemesherPlugin::slotSetMeanLength()
183 {
184  double current = 0.0;
185  int div = 0;
186 
187  bool ok;
188  emit functionExists( "infomeshobject" , "edgeCount(int)", ok ) ;
189  if (!ok)
190  return;
191 
193  current += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id()) *
194  RPC::callFunctionValue<double>("infomeshobject" , "meanEdgeLength",o_it->id() );
195  div += RPC::callFunctionValue<int> ("infomeshobject" , "edgeCount",o_it->id() );
196  }
197 
198  if (div > 0)
199  tool_->targetEdgeLength->setValue (current / div);
200 }
201 
202 
205 
206  emit setSlotDescription("isotropicRemesh(int,double)", "Isotropic Remeshing",
207  QString("object_id,targetEdgeLength").split(","),
208  QString("id of an object, target edge length").split(","));
209 }
210 
211 
212 void IsotropicRemesherPlugin::isotropicRemesh(int _objectID, double _targetEdgeLength ){
213  BaseObjectData* object = 0;
214 
215 
216  if ( PluginFunctions::getObject(_objectID, object) ){
217 
218  //check dataType
219  if ( object->dataType(DATA_TRIANGLE_MESH)) {
220 
221  TriMesh* mesh = PluginFunctions::triMesh(object);
222 
224 
225  remesher.remesh(*mesh, _targetEdgeLength);
226 
227  mesh->update_normals();
228 
229  emit updatedObject( object->id(), UPDATE_ALL );
230 
231  emit scriptInfo("isotropicRemesh(" + QString::number(_objectID) + ", " + QString::number(_targetEdgeLength) + ")");
232 
233  emit updateView();
234 
235  return;
236 
237  }else{
238  emit log("Remeshing currently only implemented for triangle Meshes");
239  return;
240  }
241  }else{
242  emit log("Unable to get object");
243  }
244 }
245 
246 
247 
248 
void pluginsInitialized()
Initialize the plugin.
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
void remesh(MeshT &_mesh, const double _targetEdgeLength)
do the remeshing
void initializePlugin()
init the Toolbox
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
virtual void updateView()
Update current view in Main Application.
virtual void setSlotDescription(QString _slotName, QString _slotDescription, QStringList _parameters, QStringList _descriptions)
Set a description for a public slot.
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.
Predefined datatypes.
Definition: DataTypes.hh:83
int id() const
Definition: BaseObject.cc:190
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
virtual void scriptInfo(QString _functionWithParameters)
Emit this signal if a scriptable function is executed.
void update_normals()
Compute normals for all primitives.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
ObjectRange objects(IteratorRestriction _restriction, DataType _dataType)
Iterable object range.
virtual void updatedObject(int _objectId)
An object has been changed or added by this plugin.
Thread handling class for OpenFlipper.