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