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
55namespace
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
94void 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
117DataType 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
158MergePlugin::MergePlugin() :
159 tool_(nullptr),
160 toolIcon_(nullptr),
161 polyMergeID(0),
162 triMergeID(0)
163{
164
165}
166
167MergePlugin::~MergePlugin() {
168 delete toolIcon_;
169}
170
173 if ( ! OpenFlipper::Options::gui())
174 return;
175 tool_ = new MergeToolBox();
176
177 QSize size(300, 300);
178 tool_->resize(size);
179
180 connect(tool_->mergeButton, SIGNAL( clicked() ), this, SLOT( mergeObjects() ) );
181 tool_->mergeButton->setStatusTip("Merge all target objects into one without changing geometry");
182 tool_->mergeButton->setToolTip( tool_->mergeButton->statusTip() );
183 toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"merge.png");
184
185 connect(this,SIGNAL(cleanup(DataType, bool)),this,SLOT(slotCleanup(DataType, bool)),Qt::QueuedConnection);
186
187 emit addToolbox( tr("Merge") , tool_, toolIcon_ );
188}
189
190void MergePlugin::pluginsInitialized()
191{
192 //populate scripting function
193 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.",
194 QString("objects,mergedName,deleteSeparateObjects").split(","),
195 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(","));
196
197 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.",
198 QString("objects,mergedName,deleteSeparateObjects").split(","),
199 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(","));
200}
201
202int MergePlugin::mergeObjects(IdList _objects, QString _name, bool _deleteSeparateObjects, DataType _type)
203{
204 std::vector< BaseObjectData* > objects;
205 for(int i : _objects)
206 {
207 BaseObject* obj;
209 objects.push_back(PluginFunctions::baseObjectData(obj));
210 }
211 return mergeObjects(objects, _name, _deleteSeparateObjects, _type);
212}
213
214int MergePlugin::mergeObjects(const std::vector< BaseObjectData* > & _objects, QString _name, bool _deleteSeparateObjects, DataType _type)
215{
216 int result = -1;
217 if (_objects.size() < 2)
218 return -1; //nothing to do
219
220 objects = _objects;
221
222 DataType type;
223 if ( OpenFlipper::Options::gui())
224 type = checkType(objects);
225 else
226 type = _type;
227
228 //user pushed the cancel button
229 if(type != DATA_TRIANGLE_MESH && type != DATA_POLY_MESH)
230 return -1;
231
232 convertedIds.clear();
233 std::vector< TriMesh* > triMeshes;
234 std::vector< PolyMesh* > polyMeshes;
235 TriMesh* triMergePtr;
236 PolyMesh* polyMergePtr;
237
238 emit addEmptyObject(DATA_POLY_MESH, polyMergeID);
239 PluginFunctions::getMesh(polyMergeID, polyMergePtr);
240 polyMeshes.push_back(polyMergePtr);
241 emit addEmptyObject(DATA_TRIANGLE_MESH, triMergeID);
242 PluginFunctions::getMesh(triMergeID,triMergePtr);
243 triMeshes.push_back(triMergePtr);
244
245 getAllMeshes(triMeshes,objects);
246 getAllMeshes(polyMeshes,objects);
247
248 if ( type == DATA_TRIANGLE_MESH ) {
249 // Convert PolyMeshes to TriMeshes
250 convertMeshes(DATA_POLY_MESH,convertedIds,triMeshes);
251
252 mergeMeshes(triMeshes);
253 (triMeshes[0])->update_normals();
254 BaseObject* bo;
255 PluginFunctions::getObject(triMergeID,bo);
256 bo->setName(_name);
257 result = bo->id();
258 } else {
259 // Convert TriMeshes to PolyMeshes
260 convertMeshes(DATA_TRIANGLE_MESH,convertedIds,polyMeshes);
261
262 mergeMeshes(polyMeshes);
263 (polyMeshes[0])->update_normals();
264 BaseObject* bo;
265 PluginFunctions::getObject(polyMergeID,bo);
266 bo->setName(_name);
267 result = bo->id();
268 }
269
270 emit updatedObject(triMergeID,UPDATE_ALL);
271 emit updatedObject(polyMergeID,UPDATE_ALL);
272
273 //clean up after merging (removes OF objects)
274 emit cleanup( type, _deleteSeparateObjects );
275 return result;
276}
277
280{
281 getTargets(objects);
282 mergeObjects(objects,tool_->mergedName->text(),tool_->deleteObjects->isChecked());
283}
284
285
286
DLLEXPORT QString dataTypeName(DataType _id)
Get DataType Human readable name ( this name might change. Use the typeName instead!...
Definition: Types.cc:252
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:181
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
virtual void setName(QString _name)
path to the file from which the object is loaded ( defaults to "." )
Definition: BaseObject.cc:721
int id() const
Definition: BaseObject.cc:188
Predefined datatypes.
Definition: DataTypes.hh:83
void mergeMeshes(const std::vector< MeshT * > &_meshes)
merges Meshes into the first mesh
void slotCleanup(DataType _type, bool _deleteSeparateObjects)
slotCleanup is called when the cleanup event is processed at the end of mergeObjects.
Definition: MergePlugin.cc:94
void initializePlugin()
init the Toolbox
Definition: MergePlugin.cc:172
void mergeObjects()
merge two objects with target flag
Definition: MergePlugin.cc:279
virtual void clear(bool _clearProps=true)
Clear whole mesh.
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
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.
bool getAllMeshes(std::vector< int > &_identifiers)
Get identifiers of all meshes.
const QStringList TARGET_OBJECTS("target")
Iterable object range.
ObjectRange objects(IteratorRestriction _restriction, DataType _dataType)
Iterable object range.
BaseObjectData * baseObjectData(BaseObject *_object)
Cast an BaseObject to a BaseObjectData if possible.