Developer Documentation
Loading...
Searching...
No Matches
MultiObjectPropertyModel.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 "MultiObjectPropertyModel.hh"
44
45#include "PropertyModelFactory.hh"
46#include "OpenMesh/OMPropertyModel.hh"
47
48#ifdef ENABLE_OPENVOLUMEMESH
49#include "OpenVolumeMesh/OVMPropertyModelT.hh"
50#endif
51
53
54MultiObjectPropertyModel::MultiObjectPropertyModel(const QStringList& res, QObject *parent) :
55 PropertyModel(parent), restriction(res), datatypes(supportedDataTypes()), widget(0)
56{
57 QVBoxLayout* layout = new QVBoxLayout();
58 widget = new QWidget();
59 widget->setLayout(layout);
60}
61
62MultiObjectPropertyModel::~MultiObjectPropertyModel()
63{
64 for (size_t i = 0; i < propWidgets.size(); ++i)
65 {
66 delete propWidgets[i];
67 }
68 delete widget;
69}
70
71QVariant MultiObjectPropertyModel::data(const QModelIndex & index, int role) const
72{
73 switch (role) {
74 case Qt::DisplayRole:
75 return QVariant(propNames[index.row()]);
76 default:
77 return QVariant{};
78 }
79}
80
81int MultiObjectPropertyModel::rowCount(const QModelIndex & parent) const
82{
83 return propNames.size();
84}
85
86QVariant MultiObjectPropertyModel::headerData(int section, Qt::Orientation orientation, int role) const
87{
88 return QVariant{};
89}
90
91QModelIndex MultiObjectPropertyModel::index(int row, int column, const QModelIndex &parent) const
92{
93 (void)parent;
94 return createIndex(row, column);
95}
96
98{
99 using namespace PluginFunctions;
100
101 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
102 {
103 // get the property model and call objectUpdated
104 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
105 if (model == 0) continue;
106 model->objectUpdated();
107 }
108}
109
110void MultiObjectPropertyModel::visualize(QModelIndexList selectedIndices, QWidgetList widgets)
111{
112 using namespace PluginFunctions;
113
114 // return if nothing is selected
115 if (selectedIndices.size() < 1) return;
116
117 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
118 {
119 // get the property model and update it
120 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
121 if (model == 0) continue;
122 model->gatherProperties();
123
124 QModelIndexList indexList;
125 QWidgetList widgetList;
126
127 for (int i = 0; i < selectedIndices.size(); ++i)
128 {
129 const QString name = selectedIndices[i].data().toString();
130
131 // skip this property if it does not exist
132 const QModelIndex idx = model->indexFromFancyPropName(name);
133 if (!idx.isValid()) continue;
134
135 // insert items into lists
136 indexList.append(idx);
137 widgetList.append(propWidgets[selectedIndices[i].row()]);
138 }
139
140 // visualize the property
141 model->visualize(indexList, widgetList);
142 }
143}
144
145void MultiObjectPropertyModel::removeProperty(QModelIndexList selectedIndices)
146{
147 using namespace PluginFunctions;
148
149 // return if nothing is selected
150 if (selectedIndices.size() < 1) return;
151
152 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
153 {
154 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
155 if (model == 0) continue;
156
157 QModelIndexList indexList;
158
159 for (int i = 0; i < selectedIndices.size(); ++i)
160 {
161 const QString name = selectedIndices[i].data().toString();
162
163 // skip this property if it does not exist
164 const QModelIndex idx = model->indexFromFancyPropName(name);
165 if (!idx.isValid()) continue;
166
167 // insert item into list
168 indexList.append(idx);
169 }
170
171 model->removeProperty(indexList);
172 }
173
174 // update this model
176}
177
178void MultiObjectPropertyModel::duplicateProperty(QModelIndexList selectedIndices)
179{
180 using namespace PluginFunctions;
181
182 // return if nothing is selected
183 if (selectedIndices.size() < 1) return;
184
185 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
186 {
187 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
188 if (model == 0) continue;
189
190 QModelIndexList indexList;
191
192 for (int i = 0; i < selectedIndices.size(); ++i)
193 {
194 const QString name = selectedIndices[i].data().toString();
195
196 // skip this property if it does not exist
197 const QModelIndex idx = model->indexFromFancyPropName(name);
198 if (!idx.isValid()) continue;
199
200 // insert item into list
201 indexList.append(idx);
202 }
203
204 model->duplicateProperty(indexList);
205 }
206
207 // update this model
209}
210
212{
213 using namespace PluginFunctions;
214
215 beginResetModel();
216 propNames.clear();
217 propInfos.clear();
218 for (size_t i = 0; i < propWidgets.size(); ++i)
219 {
220 delete propWidgets[i];
221 }
222 propWidgets.clear();
223 endResetModel();
224
225 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
226 {
227 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
228 if (model == 0) continue;
229 model->gatherProperties();
230
231 for (int i = 0; i < model->rowCount(); ++i)
232 {
233 const QModelIndex idx = model->index(i, 0);
234 const QString name = idx.data().toString();
235
236 // add property
237 if (std::find(propNames.begin(), propNames.end(), name) == propNames.end())
238 {
239 PropertyInfo info = model->getPropertyInfo(idx);
240 QWidget* widget = createWidgetForType(info.typeinfo());
241 setRange(info, widget);
242
243 propNames.push_back(name);
244 propInfos.push_back(info);
245 propWidgets.push_back(widget);
246 }
247 }
248 }
249}
250
251void MultiObjectPropertyModel::clear(QModelIndexList selectedIndices)
252{
253 using namespace PluginFunctions;
254
255 // return if nothing is selected
256 if (selectedIndices.size() < 1) return;
257
258 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
259 {
260 PropertyModel* model = PropertyModelFactory::Instance().getModel(o_it->id());
261 if (model == 0) continue;
262
263 QModelIndexList indexList;
264
265 for (int i = 0; i < selectedIndices.size(); ++i)
266 {
267 const QString name = selectedIndices[i].data().toString();
268
269 // skip this property if it does not exist
270 const QModelIndex idx = model->indexFromFancyPropName(name);
271 if (!idx.isValid()) continue;
272
273 // insert item into list
274 indexList.append(idx);
275 }
276
277 model->clear(indexList);
278 }
279}
280
282{
283 widget->hide();
284}
285
287{
288 return widget;
289}
290
291void MultiObjectPropertyModel::updateWidget(const QModelIndexList& selectedIndices)
292{
293 QLayout* layout = widget->layout();
294
295 for (unsigned int i = 0; i < propWidgets.size(); ++i)
296 {
297 propWidgets[i]->hide();
298 }
299
300 for (int i = 0; i < selectedIndices.size(); ++i)
301 {
302 const int row = selectedIndices[i].row();
303 QWidget* w = propWidgets[row];
304 layout->addWidget(w);
305 w->show();
306 }
307
308 widget->setLayout(layout);
309}
310
315
317{
318 return propInfos[index.row()];
319}
320
321QWidget* MultiObjectPropertyModel::createWidgetForType(const TypeInfoWrapper& info) const
322{
323 // OpenMesh
324 // ----------------------------------------
325
327 return new BooleanWidget();
329 return new IntegerWidget();
331 return new IntegerWidget();
333 return new DoubleWidget();
335 return new VectorWidget;
337 return new VectorWidget;
339 return new VectorWidget;
341 return new VectorWidget;
342
343 #ifdef ENABLE_SKELETON_SUPPORT
345 return new SkinWeightsWidget;
346 #endif
347
348
349 // OpenVolumeMesh
350 // ----------------------------------------
351
352 #if defined(ENABLE_HEXAHEDRALMESH_SUPPORT)
354 return new BooleanWidget();
356 return new IntegerWidget();
358 return new IntegerWidget();
360 return new DoubleWidget();
362 return new VectorWidget();
364 return new VectorWidget();
365 #endif
366
367
368 // Other
369 // ----------------------------------------
370
371 return new QWidget();
372}
373
374template <typename ItemHandle, typename PropHandle, typename T>
375void range3_om(const OpenMesh::BaseKernel* mesh, unsigned int n, const std::string& name, T& min, T& max)
376{
377 PropHandle ph;
378 mesh->get_property_handle(ph, name);
379 if (!ph.is_valid()) return;
380
381 for (unsigned int i = 0; i < n; ++i)
382 {
383 const ItemHandle ih(i);
384 min = std::min(min, mesh->property(ph, ih));
385 max = std::max(max, mesh->property(ph, ih));
386 }
387}
388
389template <typename ItemHandle, typename Property, typename T>
390void range3_ovm(Property& prop, unsigned int n, T& min, T& max)
391{
392 for (unsigned int i = 0; i < n; ++i)
393 {
394 const ItemHandle ih(i);
395 min = std::min(min, prop[ih]);
396 max = std::max(max, prop[ih]);
397 }
398}
399
400template <typename Mesh, typename T>
401void range2_om(const Mesh* mesh, const PropertyInfo& info, T& min, T&max)
402{
403 if (mesh == 0) return;
404
405 if (info.isVertexProp())
406 range3_om<OpenMesh::VertexHandle, OpenMesh::VPropHandleT<T>, T>
407 (mesh, mesh->n_vertices(), info.propName(), min, max);
408 if (info.isHalfedgeProp())
410 (mesh, mesh->n_halfedges(), info.propName(), min, max);
411 if (info.isEdgeProp())
413 (mesh, mesh->n_edges(), info.propName(), min, max);
414 if (info.isFaceProp())
416 (mesh, mesh->n_faces(), info.propName(), min, max);
417}
418
419#if defined(ENABLE_HEXAHEDRALMESH_SUPPORT) || defined(ENABLE_POLYHEDRALMESH_SUPPORT) || defined(ENABLE_TETRAHEDRALMESH_SUPPORT)
420template <typename Mesh, typename T>
421void range2_ovm(Mesh* mesh, const PropertyInfo& info, T& min, T&max)
422{
423 if (mesh == 0) return;
424
425 if (info.isCellProp() && mesh->template cell_property_exists<T>(info.propName())) {
426 OpenVolumeMesh::CellPropertyT<T> prop = mesh->template request_cell_property<T>(info.propName());
427 range3_ovm<OpenVolumeMesh::CellHandle, OpenVolumeMesh::CellPropertyT<T>, T>
428 (prop, mesh->n_cells(), min, max);
429 }
430 if (info.isEdgeProp() && mesh->template edge_property_exists<T>(info.propName())) {
431 OpenVolumeMesh::EdgePropertyT<T> prop = mesh->template request_edge_property<T>(info.propName());
432 range3_ovm<OpenVolumeMesh::EdgeHandle, OpenVolumeMesh::EdgePropertyT<T>, T>
433 (prop, mesh->n_edges(), min, max);
434 }
435 if (info.isFaceProp() && mesh->template face_property_exists<T>(info.propName())) {
436 OpenVolumeMesh::FacePropertyT<T> prop = mesh->template request_face_property<T>(info.propName());
437 range3_ovm<OpenVolumeMesh::FaceHandle, OpenVolumeMesh::FacePropertyT<T>, T>
438 (prop, mesh->n_faces(), min, max);
439 }
440 if (info.isHalfedgeProp() && mesh->template halfedge_property_exists<T>(info.propName())) {
441 OpenVolumeMesh::HalfEdgePropertyT<T> prop = mesh->template request_halfedge_property<T>(info.propName());
442 range3_ovm<OpenVolumeMesh::HalfEdgeHandle, OpenVolumeMesh::HalfEdgePropertyT<T>, T>
443 (prop, mesh->n_halfedges(), min, max);
444 }
445 if (info.isHalffaceProp() && mesh->template halfface_property_exists<T>(info.propName())) {
446 OpenVolumeMesh::HalfFacePropertyT<T> prop = mesh->template request_halfface_property<T>(info.propName());
447 range3_ovm<OpenVolumeMesh::HalfFaceHandle, OpenVolumeMesh::HalfFacePropertyT<T>, T>
448 (prop, mesh->n_halffaces(), min, max);
449 }
450 if (info.isVertexProp() && mesh->template vertex_property_exists<T>(info.propName())) {
451 OpenVolumeMesh::VertexPropertyT<T> prop = mesh->template request_vertex_property<T>(info.propName());
452 range3_ovm<OpenVolumeMesh::VertexHandle, OpenVolumeMesh::VertexPropertyT<T>, T>
453 (prop, mesh->n_vertices(), min, max);
454 }
455}
456#endif
457
458template <typename T>
459void range1(const BaseObject* obj, const PropertyInfo& info, T& min, T& max)
460{
461 using namespace PluginFunctions;
462
464 range2_om(triMesh(obj->id()), info, min, max);
465 if (obj->dataType(DATA_POLY_MESH))
466 range2_om(polyMesh(obj->id()), info, min, max);
467
468 #ifdef ENABLE_POLYHEDRALMESH_SUPPORT
470 range2_ovm(polyhedralMesh(obj->id()), info, min, max);
471 #endif
472
473 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
475 range2_ovm(hexahedralMesh(obj->id()), info, min, max);
476 #endif
477}
478
479void MultiObjectPropertyModel::setRange(const PropertyInfo& info, QWidget* widget) const
480{
481 using namespace PluginFunctions;
482
483 bool isDoubleType = info.typeinfo() == OMPropertyModel<TriMesh>::proptype_double;
484
485 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
486 isDoubleType |= OVMPropertyModel<HexahedralMesh>::isDoubleType(info.typeinfo());
487 #endif
488
489 bool isIntType = info.typeinfo() == OMPropertyModel<TriMesh>::proptype_int;
490
491 #ifdef ENABLE_HEXAHEDRALMESH_SUPPORT
492 isIntType |= OVMPropertyModel<HexahedralMesh>::isIntType(info.typeinfo());
493 #endif
494
495 if (isDoubleType)
496 {
497 double min = +DBL_MAX;
498 double max = -DBL_MAX;
499
500 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
501 {
502 range1<double>(*o_it, info, min, max);
503 }
504
505 DoubleWidget* w = static_cast<DoubleWidget*>(widget);
506 w->doubleFixedRange->toggle();
507 w->doubleFixedRangeMin->setValue(min);
508 w->doubleFixedRangeMax->setValue(max);
509 }
510
511 if (isIntType)
512 {
513 int min = +INT_MAX;
514 int max = -INT_MAX;
515
516 for (ObjectIterator o_it(restriction, datatypes); o_it != objectsEnd(); ++o_it)
517 {
518 range1<int>(*o_it, info, min, max);
519 }
520
521 IntegerWidget* w = static_cast<IntegerWidget*>(widget);
522 w->intFixedRange->toggle();
523 w->intFixedRangeMin->setValue(min);
524 w->intFixedRangeMax->setValue(max);
525 }
526}
#define DATA_HEXAHEDRAL_MESH
#define DATA_POLYHEDRAL_MESH
#define DATA_POLY_MESH
Definition PolyMesh.hh:59
#define DATA_TRIANGLE_MESH
bool dataType(DataType _type) const
int id() const
virtual QWidget * getWidget() override
Returns the widget.
virtual void duplicateProperty(QModelIndexList selectedIndices) override
Duplicates the selected properties.
virtual void objectUpdated() override
Revisualizes visualized properties.
virtual void removeProperty(QModelIndexList selectedIndices) override
Removes the selected properties.
virtual PropertyInfo getPropertyInfo(const QModelIndex index) const override
Returns the property info for the property with the given index.
virtual void clear(QModelIndexList selectedIndices) override
Clears the selected property visualization.
virtual void updateWidget(const QModelIndexList &selectedIndices) override
Updates the widget.
virtual void connectLogs(PropertyVisualizer *propViz) override
Connects the PropertyVisualizer log signals with the log slot.
virtual void gatherProperties() override
Searches for properties and creates PropertyVisualizers.
virtual void visualize(QModelIndexList selectedIndices, QWidgetList widgets=QWidgetList()) override
Visualizes the selected properties.
virtual void hideWidget() override
Hides the widget.
static T & Instance()
Definition SingletonT.hh:86
Cellection of information about a property.
Definition Utils.hh:109
virtual PropertyInfo getPropertyInfo(const QModelIndex index) const =0
Returns the property info for the property with the given index.
virtual void objectUpdated()=0
Revisualizes visualized properties.
virtual void visualize(QModelIndexList selectedIndices, QWidgetList widgets=QWidgetList())=0
Visualizes the selected properties.
virtual void removeProperty(QModelIndexList selectedIndices)=0
Removes the selected properties.
virtual void gatherProperties()=0
Searches for properties and creates PropertyVisualizers.
QModelIndex indexFromFancyPropName(const QString &propName) const
Returns the index of the property with the given name.
virtual void clear(QModelIndexList selectedIndices)=0
Clears the selected property visualization.
virtual void duplicateProperty(QModelIndexList selectedIndices)=0
Duplicates the selected properties.
This class vizualizes a property.
Wraps the information of a type.
Definition Utils.hh:73
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
PolyhedralMesh * polyhedralMesh(BaseObjectData *_object)
Get an PolyhedralMesh from an object.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
HexahedralMesh * hexahedralMesh(BaseObjectData *_object)
Get an HexahedralMesh from an object.
Handle for a edge entity.
Definition Handles.hh:135
Handle for a face entity.
Definition Handles.hh:142
Handle for a halfedge entity.
Definition Handles.hh:128