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
45 #include "OpenFlipper/BasePlugin/PluginFunctions.hh"
46 #include <OpenFlipper/BasePlugin/RPCWrappers.hh>
47
48 #include <ObjectTypes/PolyMesh/PolyMesh.hh>
49 #include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
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
72 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)) ;
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 {
80 for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,_type) ;
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
169 void MergePlugin::initializePlugin() {
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;
205 PluginFunctions::getObject(i,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
278 void MergePlugin::mergeObjects()
279 {
280 getTargets(objects);
281 mergeObjects(objects,tool_->mergedName->text(),tool_->deleteObjects->isChecked());
282 }
283
284
285
RPCWrappers.hh
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
TriangleMesh.hh
DATA_POLY_MESH
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
BaseObject::id
int id() const
Definition: BaseObject.cc:190
MergePlugin::initializePlugin
void initializePlugin()
init the Toolbox
Definition: MergePlugin.cc:169
PluginFunctions.hh
MergePlugin::mergeMeshes
void mergeMeshes(const std::vector< MeshT * > &_meshes)
merges Meshes into the first mesh
Definition: MergePlugintemplate.cc:51
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
MergePlugin::slotCleanup
void slotCleanup(DataType _type, bool _deleteSeparateObjects)
slotCleanup is called when the cleanup event is processed at the end of mergeObjects.
Definition: MergePlugin.cc:96
MergePlugin::mergeObjects
void mergeObjects()
merge two objects with target flag
Definition: MergePlugin.cc:278
PluginFunctions::getMesh
bool getMesh(int _identifier, PolyMesh *&_mesh)
Get the Poly Mesh which has the given identifier.
Definition: PluginFunctionsPolyMesh.cc:101
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:294
IdList
std::vector< int > IdList
Standard Type for id Lists used for scripting.
Definition: DataTypes.hh:179
MergeToolBox
Definition: MergeToolbox.hh:46
PluginFunctions::baseObjectData
BaseObjectData * baseObjectData(BaseObject *_object)
Cast an BaseObject to a BaseObjectData if possible.
Definition: PluginFunctions.cc:1089
PluginFunctions::getAllMeshes
bool getAllMeshes(std::vector< int > &_identifiers)
Get identifiers of all meshes.
Definition: PluginFunctions.cc:349
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:441
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:177
BaseObject
Definition: BaseObject.hh:82
BaseObject::setName
virtual void setName(QString _name)
path to the file from which the object is loaded ( defaults to "." )
Definition: BaseObject.cc:723
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
PolyMesh.hh
dataTypeName
DLLEXPORT QString dataTypeName(DataType _id)
Get DataType Human readable name ( this name might change. Use the typeName instead! ) ...
Definition: Types.cc:252