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