Developer Documentation
MergePlugin.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 #include "MergePlugin.hh"
44 
47 
50 #include <QInputDialog>
51 
55 namespace
56 {
57  template< class MeshT >
58  void getAllMeshes(std::vector< MeshT* > & meshes, const std::vector< BaseObjectData* > & objects)
59  {
60  for (uint i=0; i < objects.size(); i++)
61  {
62  MeshT* t;
63  if(PluginFunctions::getMesh(objects[i]->id(),t))
64  meshes.push_back( t );
65  }
66  }
67 
68  void getTargets(std::vector< BaseObjectData* > & _objects)
69  {
70  _objects.clear();
71  //read all target objects
73  o_it != PluginFunctions::objectsEnd(); ++o_it)
74  _objects.push_back( *o_it );
75  }
76 
77  template< class MeshT >
78  void convertMeshes(const DataType & _type, std::vector< int >& convertedIds, std::vector< MeshT* >& _meshes)
79  {
81  o_it != PluginFunctions::objectsEnd(); ++o_it)
82  {
83  //convert polyMesh to triMesh or vice versa
84  convertedIds.push_back(RPC::callFunctionValue<int>("meshconvert","convert",(*o_it)->id(), _type != DATA_TRIANGLE_MESH));
85  MeshT* ptr;
86  PluginFunctions::getMesh(convertedIds.back(),ptr);
87  _meshes.push_back(ptr);
88  }
89  }
90 }
91 
96 void MergePlugin::slotCleanup( DataType _type, bool _deleteSeparateObjects )
97 {
98  //clean up conversion objects
99  for(int i : convertedIds)
100  emit deleteObject( i );
101 
102  convertedIds.clear();
103 
104  if(_deleteSeparateObjects)
105  {
106  //clean up separated objects
107  for (size_t i=0; i < objects.size(); i++)
108  emit deleteObject( (objects[i])->id() );
109 
110  objects.clear();
111  }
112  //clean up unused merge target
113  if(_type == DATA_TRIANGLE_MESH)
114  emit deleteObject( polyMergeID );
115  else
116  emit deleteObject( triMergeID );
117 }
118 
119 DataType MergePlugin::checkType(const std::vector< BaseObjectData* > & objects )
120 {
121  DataType type = (objects[0])->dataType();
122  bool askForType = false;
123  for (uint i=1; i < objects.size(); i++)
124  if ( type != (objects[i])->dataType() ){
125  askForType = true;
126  break;
127  }
128 
129  if(askForType)
130  {
131  QStringList types;
132  types.append(dataTypeName(DATA_TRIANGLE_MESH));
133  types.append(dataTypeName(DATA_POLY_MESH));
134  bool ok;
135  QString result = QInputDialog::getItem(nullptr,
136  tr("Select Mesh Type"),
137  tr("Convert meshes to:"),
138  types,
139  1,
140  false,
141  &ok);
142  if(ok)
143  {
144  if( result == dataTypeName(DATA_POLY_MESH))
145  {
146  type = DATA_POLY_MESH;
147  }
148  else
149  {
150  type = DATA_TRIANGLE_MESH;
151  }
152  }
153  else
154  return DataType();
155  }
156  return type;
157 }
158 
159 
160 MergePlugin::MergePlugin() :
161  tool_(nullptr),
162  polyMergeID(0),
163  triMergeID(0)
164 {
165 
166 }
167 
170  if ( ! OpenFlipper::Options::gui())
171  return;
172  tool_ = new MergeToolBox();
173 
174  QSize size(300, 300);
175  tool_->resize(size);
176 
177  connect(tool_->mergeButton, SIGNAL( clicked() ), this, SLOT( mergeObjects() ) );
178  tool_->mergeButton->setStatusTip("Merge all target objects into one without changing geometry");
179  tool_->mergeButton->setToolTip( tool_->mergeButton->statusTip() );
180  QIcon* toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"merge.png");
181 
182  connect(this,SIGNAL(cleanup(DataType, bool)),this,SLOT(slotCleanup(DataType, bool)),Qt::QueuedConnection);
183 
184  emit addToolbox( tr("Merge") , tool_, toolIcon_ );
185 }
186 
187 void MergePlugin::pluginsInitialized()
188 {
189  //populate scripting function
190  emit setSlotDescription("mergeObjects(const std::vector< BaseObjectData* >,QString,bool,DataType)", "Merges multiple meshes into one mesh. returns the ID of the new mesh or -1 in case of error.",
191  QString("objects,mergedName,deleteSeparateObjects").split(","),
192  QString(" vector of BaseObjectData* containing Poly or TriMeshes to be merged, name for the merged object, flag to remove separated objects default is true, DataType for the new mesh if used in nogui mode").split(","));
193 
194  emit setSlotDescription("mergeObjects(IdList,QString,bool,DataType)", "Merges multiple meshes into one mesh. returns the ID of the new mesh or -1 in case of error.",
195  QString("objects,mergedName,deleteSeparateObjects").split(","),
196  QString(" vector of Object Ids of Poly or TriMeshes to be merged, name for the merged object, flag to remove separated objects default is true, DataType for the new mesh if used in nogui mode").split(","));
197 }
198 
199 int MergePlugin::mergeObjects(IdList _objects, QString _name, bool _deleteSeparateObjects, DataType _type)
200 {
201  std::vector< BaseObjectData* > objects;
202  for(int i : _objects)
203  {
204  BaseObject* obj;
206  objects.push_back(PluginFunctions::baseObjectData(obj));
207  }
208  return mergeObjects(objects, _name, _deleteSeparateObjects, _type);
209 }
210 
211 int MergePlugin::mergeObjects(const std::vector< BaseObjectData* > & _objects, QString _name, bool _deleteSeparateObjects, DataType _type)
212 {
213  int result = -1;
214  if (_objects.size() < 2)
215  return -1; //nothing to do
216 
217  objects = _objects;
218 
219  DataType type;
220  if ( OpenFlipper::Options::gui())
221  type = checkType(objects);
222  else
223  type = _type;
224 
225  //user pushed the cancel button
226  if(type != DATA_TRIANGLE_MESH && type != DATA_POLY_MESH)
227  return -1;
228 
229  convertedIds.clear();
230  std::vector< TriMesh* > triMeshes;
231  std::vector< PolyMesh* > polyMeshes;
232  TriMesh* triMergePtr;
233  PolyMesh* polyMergePtr;
234 
235  emit addEmptyObject(DATA_POLY_MESH, polyMergeID);
236  PluginFunctions::getMesh(polyMergeID, polyMergePtr);
237  polyMeshes.push_back(polyMergePtr);
238  emit addEmptyObject(DATA_TRIANGLE_MESH, triMergeID);
239  PluginFunctions::getMesh(triMergeID,triMergePtr);
240  triMeshes.push_back(triMergePtr);
241 
242  getAllMeshes(triMeshes,objects);
243  getAllMeshes(polyMeshes,objects);
244 
245  if ( type == DATA_TRIANGLE_MESH ) {
246  // Convert PolyMeshes to TriMeshes
247  convertMeshes(DATA_POLY_MESH,convertedIds,triMeshes);
248 
249  *triMergePtr = *triMeshes[1];
250  mergeMeshes(triMeshes);
251  (triMeshes[0])->update_normals();
252  BaseObject* bo;
253  PluginFunctions::getObject(triMergeID,bo);
254  bo->setName(_name);
255  result = bo->id();
256  } else {
257  // Convert TriMeshes to PolyMeshes
258  convertMeshes(DATA_TRIANGLE_MESH,convertedIds,polyMeshes);
259 
260  *polyMergePtr = *polyMeshes[1];
261  mergeMeshes(polyMeshes);
262  (polyMeshes[0])->update_normals();
263  BaseObject* bo;
264  PluginFunctions::getObject(polyMergeID,bo);
265  bo->setName(_name);
266  result = bo->id();
267  }
268 
269  emit updatedObject(triMergeID,UPDATE_ALL);
270  emit updatedObject(polyMergeID,UPDATE_ALL);
271 
272  //clean up after merging (removes OF objects)
273  emit cleanup( type, _deleteSeparateObjects );
274  return result;
275 }
276 
279 {
280  getTargets(objects);
281  mergeObjects(objects,tool_->mergedName->text(),tool_->deleteObjects->isChecked());
282 }
283 
284 
285 
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
int id() const
Definition: BaseObject.cc:190
void initializePlugin()
init the Toolbox
Definition: MergePlugin.cc:169
void mergeMeshes(const std::vector< MeshT * > &_meshes)
merges Meshes into the first mesh
const QStringList TARGET_OBJECTS("target")
Iterable object range.
void slotCleanup(DataType _type, bool _deleteSeparateObjects)
slotCleanup is called when the cleanup event is processed at the end of mergeObjects.
Definition: MergePlugin.cc:96
void mergeObjects()
merge two objects with target flag
Definition: MergePlugin.cc:278
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
BaseObjectData * baseObjectData(BaseObject *_object)
Cast an BaseObject to a BaseObjectData if possible.
bool getAllMeshes(std::vector< int > &_identifiers)
Get identifiers of all meshes.
Predefined datatypes.
Definition: DataTypes.hh:83
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
virtual void setName(QString _name)
path to the file from which the object is loaded ( defaults to "." )
Definition: BaseObject.cc:723
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
DLLEXPORT QString dataTypeName(DataType _id)
Get DataType Human readable name ( this name might change. Use the typeName instead! ) ...
Definition: Types.cc:252