Developer Documentation
PropertyManager.hh
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
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 #ifndef PROPERTYMANAGER_HH_
43 #define PROPERTYMANAGER_HH_
44 
46 #include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
47 #include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
48 #include <sstream>
49 #include <stdexcept>
50 #include <string>
51 
52 namespace OpenMesh {
53 
79 template<typename PROPTYPE, typename MeshT = int>
81 
82  public:
83  using Value = typename PROPTYPE::Value;
84  using value_type = typename PROPTYPE::value_type;
85  using Handle = typename PROPTYPE::Handle;
87  using Reference = typename PROPTYPE::reference;
88  using ConstReference = typename PROPTYPE::const_reference;
89 
90  private:
91  // Mesh properties (MPropHandleT<...>) are stored differently than the other properties.
92  // This class implements different behavior when copying or swapping data from one
93  // property manager to a another one.
94  template <typename PropertyManager2, typename PropHandleT>
95  struct StorageT;
96 
97  // specialization for Mesh Properties
98  template <typename PropertyManager2>
99  struct StorageT<PropertyManager2, MPropHandleT<Value>> {
100  static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
101  *to = *from;
102  }
103  static void swap(PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
104  std::swap(*to, *from);
105  }
106  static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) {
107  return mesh.property(prop_handle);
108  }
109  static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) {
110  return mesh.property(prop_handle);
111  }
112  };
113 
114  // definition for other Mesh Properties
115  template <typename PropertyManager2, typename PropHandleT>
116  struct StorageT {
117  static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
118  from.copy_to(from.mesh_.template all_elements<Handle>(), to, to.mesh_.template all_elements<Handle>());
119  }
120  static void swap(PropertyManager<PROPTYPE, MeshT>& lhs, PropertyManager2& rhs) {
121  std::swap(lhs.mesh().property(lhs.prop_).data_vector(), rhs.mesh().property(rhs.prop_).data_vector());
122  // resize the property to the correct size
123  lhs.mesh().property(lhs.prop_).resize(lhs.mesh().template n_elements<Handle>());
124  rhs.mesh().property(rhs.prop_).resize(rhs.mesh().template n_elements<Handle>());
125  }
126  static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) {
127  return mesh.property(prop_handle, handle);
128  }
129  static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) {
130  return mesh.property(prop_handle, handle);
131  }
132  };
133 
135 
136  public:
137 
157  OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") // As long as this overload exists, initial value must be first parameter due to ambiguity for properties of type bool
158  PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) {
159  if (existing) {
160  if (!PropertyManager::mesh().get_property_handle(prop_, propname)) {
161  std::ostringstream oss;
162  oss << "Requested property handle \"" << propname << "\" does not exist.";
163  throw std::runtime_error(oss.str());
164  }
165  } else {
166  PropertyManager::mesh().add_property(prop_, propname);
167  }
168  }
169 
178  PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) {
179  if (!PropertyManager::mesh().get_property_handle(prop_, propname)) {
180  PropertyManager::mesh().add_property(prop_, propname);
181  }
182  }
183 
194  PropertyManager(const Value& initial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) {
195  if (!mesh_.get_property_handle(prop_, propname)) {
196  PropertyManager::mesh().add_property(prop_, propname);
197  set_range(mesh_.all_elements<Handle>(), initial_value);
198  }
199  }
200 
208  PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
209  PropertyManager::mesh().add_property(prop_, name_);
210  }
211 
220  PropertyManager(const Value& initial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
221  PropertyManager::mesh().add_property(prop_, name_);
222  set_range(mesh_.all_elements<Handle>(), initial_value);
223  }
224 
233  PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() {
234  }
235 
236  PropertyManager() = delete;
237 
238  PropertyManager(const PropertyManager& rhs)
239  :
240  mesh_(rhs.mesh_),
241  prop_(),
242  retain_(rhs.retain_),
243  name_(rhs.name_)
244  {
245  if (rhs.retain_) // named property -> create a property manager referring to the same
246  {
247  prop_ = rhs.prop_;
248  }
249  else // unnamed property -> create a property manager refering to a new property and copy the contents
250  {
251  PropertyManager::mesh().add_property(prop_, name_);
252  Storage::copy(rhs, *this);
253  }
254  }
255 
256  PropertyManager& operator=(const PropertyManager& rhs)
257  {
258  if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_)
259  ; // nothing to do
260  else
261  Storage::copy(rhs, *this);
262  return *this;
263  }
264 
265  ~PropertyManager() {
266  deleteProperty();
267  }
268 
269  void swap(PropertyManager &rhs) {
270  // swap the data stored in the properties
271  Storage::swap(rhs, *this);
272  }
273 
274  static bool propertyExists(PolyConnectivity &mesh, const char *propname) {
275  PROPTYPE dummy;
276  return mesh.get_property_handle(dummy, propname);
277  }
278 
279  bool isValid() const { return prop_.is_valid(); }
280  operator bool() const { return isValid(); }
281 
282  const PROPTYPE &getRawProperty() const { return prop_; }
283 
284  const std::string &getName() const { return name_; }
285 
299  template <typename MeshType >
300  const MeshType& getMesh() const { return dynamic_cast<const MeshType&>(mesh_); }
301 
302  const MeshT& getMesh() const { return dynamic_cast<const MeshT&>(mesh_); }
303 
304 
310  OM_DEPRECATED("retain no longer has any effect. Instead, named properties are always retained, while unnamed ones are not.")
311  void retain(bool = true) {}
312 
317  :
318  mesh_(rhs.mesh_),
319  prop_(rhs.prop_),
320  retain_(rhs.retain_),
321  name_(rhs.name_)
322  {
323  if (!rhs.retain_)
324  rhs.prop_.invalidate(); // only invalidate unnamed properties
325  }
326 
330  PropertyManager& operator=(PropertyManager&& rhs)
331  {
332  if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_))
333  {
334  if (rhs.retain_)
335  {
336  // retained properties cannot be invalidated. Copy instead
337  Storage::copy(rhs, *this);
338  }
339  else
340  {
341  // swap the data stored in the properties
342  Storage::swap(rhs, *this);
343  // remove the property from rhs
344  rhs.mesh().remove_property(rhs.prop_);
345  // invalidate prop_
346  rhs.prop_.invalidate();
347  }
348  }
349  return *this;
350  }
351 
359  static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
360  return PropertyManager(mesh, propname);
361  }
362 
372  template<typename PROP_VALUE, typename ITERATOR_TYPE>
373  static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
374  const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
375  const PROP_VALUE &init_value) {
376  const bool exists = propertyExists(mesh, propname);
377  PropertyManager pm(mesh, propname, exists);
378  pm.retain();
379  if (!exists)
380  pm.set_range(begin, end, init_value);
381  return std::move(pm);
382  }
383 
393  template<typename PROP_VALUE, typename ITERATOR_RANGE>
394  static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
395  const ITERATOR_RANGE &range, const PROP_VALUE &init_value) {
396  return createIfNotExists(
397  mesh, propname, range.begin(), range.end(), init_value);
398  }
399 
400 
413  typename PROPTYPE::reference& operator*() {
414  return mesh().mproperty(prop_)[0];
415  }
416 
429  typename PROPTYPE::const_reference& operator*() const {
430  return mesh().mproperty(prop_)[0];
431  }
432 
440  inline typename PROPTYPE::reference operator[] (Handle handle) {
441  return mesh().property(prop_, handle);
442  }
443 
451  inline typename PROPTYPE::const_reference operator[] (const Handle& handle) const {
452  return mesh().property(prop_, handle);
453  }
454 
462  inline typename PROPTYPE::reference operator() (const Handle& handle = Handle()) {
463 // return mesh().property(prop_, handle);
464  return Storage::access_property(mesh(), prop_, handle);
465  }
466 
474  inline typename PROPTYPE::const_reference operator() (const Handle& handle = Handle()) const {
475 // return mesh().property(prop_, handle);
476  return Storage::access_property_const(mesh(), prop_, handle);
477  }
478 
503  template<typename HandleTypeIterator, typename PROP_VALUE>
504  void set_range(HandleTypeIterator begin, HandleTypeIterator end,
505  const PROP_VALUE &value) {
506  for (; begin != end; ++begin)
507  (*this)[*begin] = value;
508  }
509 
510 #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
511  template<typename HandleTypeIteratorRange, typename PROP_VALUE>
512  void set_range(const HandleTypeIteratorRange &range,
513  const PROP_VALUE &value) {
514  set_range(range.begin(), range.end(), value);
515  }
516 #endif
517 
532  template<typename HandleTypeIterator, typename PROPTYPE_2,
533  typename HandleTypeIterator_2>
534  void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
535  PropertyManager<PROPTYPE_2> &dst_propmanager,
536  HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {
537 
538  for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
539  dst_propmanager[*dst_begin] = (*this)[*begin];
540  }
541  }
542 
543  template<typename RangeType, typename PROPTYPE_2,
544  typename RangeType_2>
545  void copy_to(const RangeType &range,
546  PropertyManager<PROPTYPE_2> &dst_propmanager,
547  const RangeType_2 &dst_range) const {
548  copy_to(range.begin(), range.end(), dst_propmanager,
549  dst_range.begin(), dst_range.end());
550  }
551 
552 
567  template<typename RangeType, typename RangeType_2>
568  static void copy(const char *prop_name,
569  PolyConnectivity &src_mesh, const RangeType &src_range,
570  PolyConnectivity &dst_mesh, const RangeType_2 &dst_range) {
571 
573  DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name));
574 
576  SrcPM src(src_mesh, prop_name, true);
577 
578  src.copy_to(src_range, dst, dst_range);
579  }
580 
581  private:
582  void deleteProperty() {
583  if (!retain_ && prop_.is_valid())
584  mesh().remove_property(prop_);
585  }
586 
587  PolyConnectivity& mesh() const
588  {
589  return const_cast<PolyConnectivity&>(mesh_);
590  }
591 
592  private:
593  const PolyConnectivity& mesh_;
594  PROPTYPE prop_;
595  bool retain_;
596  std::string name_;
597 };
598 
599 template <typename PropertyT>
601 {
602 public:
603  using Value = typename PropertyT::Value;
604  using value_type = typename PropertyT::value_type;
605  using Handle = typename PropertyT::Handle;
606 
607  ConstPropertyViewer(const PolyConnectivity& mesh, PropertyT property_handle)
608  :
609  mesh_(mesh),
610  prop_(property_handle)
611  {}
612 
613  inline const typename PropertyT::const_reference operator() (const Handle& handle)
614  {
615  return mesh_.property(prop_, handle);
616  }
617 
618  inline const typename PropertyT::const_reference operator[] (const Handle& handle)
619  {
620  return mesh_.property(prop_, handle);
621  }
622 
623 private:
624  const PolyConnectivity& mesh_;
625  PropertyT prop_;
626 };
627 
655 template<typename ElementT, typename T>
657 OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name")
658 makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) {
660 }
661 
686 template<typename ElementT, typename T>
690 }
691 
692 
714 template<typename ElementT, typename T>
715 bool
716 hasProperty(const PolyConnectivity &mesh, const char *propname) {
718  return mesh.get_property_handle(ph, propname);
719 }
720 
748 template<typename ElementT, typename T>
750 getProperty(PolyConnectivity &mesh, const char *propname) {
751  if (!hasProperty<ElementT, T>(mesh, propname))
752  {
753  std::ostringstream oss;
754  oss << "Requested property handle \"" << propname << "\" does not exist.";
755  throw std::runtime_error(oss.str());
756  }
758 }
759 
789 template<typename ElementT, typename T>
791 getOrMakeProperty(PolyConnectivity &mesh, const char *propname) {
792  return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>::createIfNotExists(mesh, propname);
793 }
794 
804 template<typename PROPTYPE>
805 OM_DEPRECATED("Use makeTemporaryProperty instead.")
806 PropertyManager<PROPTYPE> makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname)
807 {
808  return PropertyManager<PROPTYPE>(mesh, propname, false);
809 }
810 
823 template<typename PROPTYPE, typename MeshT = int>
824 OM_DEPRECATED("Use getProperty instead.")
825 PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname)
826 {
827  return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true);
828 }
829 
838 template<typename PROPTYPE, typename MeshT = int>
839 OM_DEPRECATED("Use getOrMakeProperty instead.")
840 PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname)
841 {
843 }
844 
856 template<typename PROPTYPE,
857  typename ITERATOR_TYPE, typename PROP_VALUE>
858 OM_DEPRECATED("Use getOrMakeProperty instead.")
860  PolyConnectivity &mesh, const char *propname,
861  const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
862  const PROP_VALUE &init_value) {
864  mesh, propname, begin, end, init_value);
865 }
866 
878 template<typename PROPTYPE,
879  typename ITERATOR_RANGE, typename PROP_VALUE>
880 OM_DEPRECATED("Use getOrMakeProperty instead.")
882  PolyConnectivity &mesh, const char *propname,
883  const ITERATOR_RANGE &range,
884  const PROP_VALUE &init_value) {
885  return makePropertyManagerFromExistingOrNew<PROPTYPE>(
886  mesh, propname, range.begin(), range.end(), init_value);
887 }
888 
889 
893 template<typename MeshT>
895 getPointsProperty(MeshT &mesh) {
896  return PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>(mesh, mesh.points_property_handle());
897 }
898 
902 template<typename MeshT>
904 getPointsProperty(const MeshT &mesh) {
906  return ConstPropertyViewer<PropType>(mesh, mesh.points_property_handle());
907 }
908 
909 template <typename HandleT, typename T>
911 
912 template <typename T>
914 
915 template <typename T>
917 
918 template <typename T>
920 
921 template <typename T>
923 
924 template <typename T>
926 
927 
928 } /* namespace OpenMesh */
929 #endif /* PROPERTYMANAGER_HH_ */
PROPTYPE::const_reference & operator*() const
PropertyManager< PROPTYPE, MeshT > makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname)
void set_range(HandleTypeIterator begin, HandleTypeIterator end, const PROP_VALUE &value)
bool hasProperty(const PolyConnectivity &mesh, const char *propname)
PROPTYPE::reference operator[](Handle handle)
PropertyManager(const PolyConnectivity &mesh)
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > getOrMakeProperty(PolyConnectivity &mesh, const char *propname)
bool get_property_handle(VPropHandleT< T > &_ph, const std::string &_name) const
Definition: BaseKernel.hh:254
static void copy(const char *prop_name, PolyConnectivity &src_mesh, const RangeType &src_range, PolyConnectivity &dst_mesh, const RangeType_2 &dst_range)
void remove_property(VPropHandleT< T > &_ph)
Definition: BaseKernel.hh:194
OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") PropertyManager(PolyConnectivity &mesh
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > getProperty(PolyConnectivity &mesh, const char *propname)
Default property class for any type T.
Definition: Property.hh:89
PropertyT< T > & mproperty(MPropHandleT< T > _ph)
Definition: BaseKernel.hh:346
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > makeTemporaryProperty(PolyConnectivity &mesh)
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > makeTemporaryProperty(PolyConnectivity &mesh, const char *propname)
PropertyManager(PolyConnectivity &mesh, PROPTYPE property_handle)
PropertyManager(PolyConnectivity &mesh, const char *propname)
PropertyManager< OpenMesh::VPropHandleT< typename MeshT::Point > > getPointsProperty(MeshT &mesh)
PropertyManager< PROPTYPE, MeshT > makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname)
ConstPropertyViewer< OpenMesh::VPropHandleT< typename MeshT::Point > > getPointsProperty(const MeshT &mesh)
PropertyT< T > & property(VPropHandleT< T > _ph)
Definition: BaseKernel.hh:310
PROPTYPE::reference operator()(const Handle &handle=Handle())
PropertyManager< PROPTYPE > makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname)
PROPTYPE::reference & operator*()
Connectivity Class for polygonal meshes.
PropertyManager(const Value &initial_value, const PolyConnectivity &mesh)
PropertyManager(const Value &initial_value, PolyConnectivity &mesh, const char *propname)
void copy_to(HandleTypeIterator begin, HandleTypeIterator end, PropertyManager< PROPTYPE_2 > &dst_propmanager, HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const