OpenMesh
PropertyManager.hh
1/* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2025, 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
45#include <OpenMesh/Core/System/config.h>
46#include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
47#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
48#include <sstream>
49#include <stdexcept>
50#include <string>
51
52namespace OpenMesh {
53
75template<typename PROPTYPE, typename MeshT = int>
77
78 public:
79 using Value = typename PROPTYPE::Value;
80 using value_type = typename PROPTYPE::value_type;
81 using Handle = typename PROPTYPE::Handle;
83 using Reference = typename PROPTYPE::reference;
84 using ConstReference = typename PROPTYPE::const_reference;
85
86 private:
87 // Mesh properties (MPropHandleT<...>) are stored differently than the other properties.
88 // This class implements different behavior when initializing a property or when
89 // copying or swapping data from one property manager to a another one.
90 template <typename PropertyManager2, typename PropHandleT>
91 struct StorageT;
92
93 // specialization for Mesh Properties
94 template <typename PropertyManager2>
95 struct StorageT<PropertyManager2, MPropHandleT<Value>> {
96 static void initialize(PropertyManager<PROPTYPE, MeshT>& pm, const Value& initial_value ) {
97 pm() = initial_value;
98 }
99 static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
100 *to = *from;
101 }
102 static void swap(PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
103 std::swap(*to, *from);
104 }
105 static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) {
106 return mesh.property(prop_handle);
107 }
108 static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle&) {
109 return mesh.property(prop_handle);
110 }
111 };
112
113 // definition for other Mesh Properties
114 template <typename PropertyManager2, typename PropHandleT>
115 struct StorageT {
116 static void initialize(PropertyManager<PROPTYPE, MeshT>& pm, const Value& initial_value ) {
117 pm.set_range(pm.mesh_.template all_elements<Handle>(), initial_value);
118 }
119 static void copy(const PropertyManager& from, PropertyManager2& to) {
120 from.copy_to(from.mesh_.template all_elements<Handle>(), to, to.mesh_.template all_elements<Handle>());
121 }
122 static void swap(PropertyManager& lhs, PropertyManager2& rhs) {
123 std::swap(lhs.mesh().property(lhs.prop_).data_vector(), rhs.mesh().property(rhs.prop_).data_vector());
124 // resize the property to the correct size
125 lhs.mesh().property(lhs.prop_).resize(lhs.mesh().template n_elements<Handle>());
126 rhs.mesh().property(rhs.prop_).resize(rhs.mesh().template n_elements<Handle>());
127 }
128 static ConstReference access_property_const(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) {
129 return mesh.property(prop_handle, handle);
130 }
131 static Reference access_property(PolyConnectivity& mesh, const PROPTYPE& prop_handle, const Handle& handle) {
132 return mesh.property(prop_handle, handle);
133 }
134 };
135
136 using Storage = StorageT<Self, PROPTYPE>;
137
138 public:
139
159 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
160 PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) {
161 if (existing) {
162 if (!PropertyManager::mesh().get_property_handle(prop_, propname)) {
163 std::ostringstream oss;
164 oss << "Requested property handle \"" << propname << "\" does not exist.";
165 throw std::runtime_error(oss.str());
166 }
167 } else {
168 PropertyManager::mesh().add_property(prop_, propname);
169 }
170 }
171
180 PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) {
181 if (!PropertyManager::mesh().get_property_handle(prop_, propname)) {
182 PropertyManager::mesh().add_property(prop_, propname);
183 }
184 }
185
196 PropertyManager(const Value& initial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) {
197 if (!mesh_.get_property_handle(prop_, propname)) {
198 PropertyManager::mesh().add_property(prop_, propname);
199 Storage::initialize(*this, initial_value);
200 }
201 }
202
210 explicit PropertyManager(const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
211 PropertyManager::mesh().add_property(prop_, name_);
212 }
213
222 PropertyManager(const Value& initial_value, const PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") {
223 PropertyManager::mesh().add_property(prop_, name_);
224 Storage::initialize(*this, initial_value);
225 }
226
235 PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() {
236 }
237
238 PropertyManager() = delete;
239
241 :
242 mesh_(rhs.mesh_),
243 prop_(),
244 retain_(rhs.retain_),
245 name_(rhs.name_)
246 {
247 if (rhs.retain_) // named property -> create a property manager referring to the same
248 {
249 prop_ = rhs.prop_;
250 }
251 else // unnamed property -> create a property manager refering to a new property and copy the contents
252 {
253 PropertyManager::mesh().add_property(prop_, name_);
254 Storage::copy(rhs, *this);
255 }
256 }
257
258
265 {
266 PropertyManager result(this->mesh());
267 Storage::copy(*this, result);
268 return result;
269 }
270
271 PropertyManager& operator=(const PropertyManager& rhs)
272 {
273 if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_)
274 ; // nothing to do
275 else
276 Storage::copy(rhs, *this);
277 return *this;
278 }
279
280 ~PropertyManager() {
281 deleteProperty();
282 }
283
284 void swap(PropertyManager &rhs) {
285 // swap the data stored in the properties
286 Storage::swap(rhs, *this);
287 }
288
289 static bool propertyExists(const PolyConnectivity &mesh, const char *propname) {
290 PROPTYPE dummy;
291 return mesh.get_property_handle(dummy, propname);
292 }
293
294 bool isValid() const { return prop_.is_valid(); }
295 operator bool() const { return isValid(); }
296
297 const PROPTYPE &getRawProperty() const { return prop_; }
298
299 const std::string &getName() const { return name_; }
300
314 template <typename MeshType >
315 const MeshType& getMesh() const { return dynamic_cast<const MeshType&>(mesh_); }
316
317 const MeshT& getMesh() const { return dynamic_cast<const MeshT&>(mesh_); }
318
319
325 OM_DEPRECATED("retain no longer has any effect. Instead, named properties are always retained, while unnamed ones are not.")
326 void retain(bool = true) {}
327
331 PropertyManager(PropertyManager &&rhs)
332 :
333 mesh_(rhs.mesh_),
334 prop_(rhs.prop_),
335 retain_(rhs.retain_),
336 name_(rhs.name_)
337 {
338 if (!rhs.retain_)
339 rhs.prop_.invalidate(); // only invalidate unnamed properties
340 }
341
345 PropertyManager& operator=(PropertyManager&& rhs)
346 {
347 if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_))
348 {
349 if (rhs.retain_)
350 {
351 // retained properties cannot be invalidated. Copy instead
352 Storage::copy(rhs, *this);
353 }
354 else
355 {
356 // swap the data stored in the properties
357 Storage::swap(rhs, *this);
358 // remove the property from rhs
359 rhs.mesh().remove_property(rhs.prop_);
360 // invalidate prop_
361 rhs.prop_.invalidate();
362 }
363 }
364 return *this;
365 }
366
374 static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
375 return PropertyManager(mesh, propname);
376 }
377
387 template<typename PROP_VALUE, typename ITERATOR_TYPE>
388 static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
389 const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
390 const PROP_VALUE &init_value) {
391 const bool exists = propertyExists(mesh, propname);
392 PropertyManager pm(mesh, propname, exists);
393 pm.retain();
394 if (!exists)
395 pm.set_range(begin, end, init_value);
396 return std::move(pm);
397 }
398
408 template<typename PROP_VALUE, typename ITERATOR_RANGE>
409 static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname,
410 const ITERATOR_RANGE &range, const PROP_VALUE &init_value) {
411 return createIfNotExists(
412 mesh, propname, range.begin(), range.end(), init_value);
413 }
414
415
428 typename PROPTYPE::reference& operator*() {
429 return mesh().mproperty(prop_)[0];
430 }
431
444 typename PROPTYPE::const_reference& operator*() const {
445 return mesh().mproperty(prop_)[0];
446 }
447
455 inline typename PROPTYPE::reference operator[] (Handle handle) {
456 return mesh().property(prop_, handle);
457 }
458
466 inline typename PROPTYPE::const_reference operator[] (const Handle& handle) const {
467 return mesh().property(prop_, handle);
468 }
469
477 inline typename PROPTYPE::reference operator() (const Handle& handle = Handle()) {
478// return mesh().property(prop_, handle);
479 return Storage::access_property(mesh(), prop_, handle);
480 }
481
489 inline typename PROPTYPE::const_reference operator() (const Handle& handle = Handle()) const {
490// return mesh().property(prop_, handle);
491 return Storage::access_property_const(mesh(), prop_, handle);
492 }
493
518 template<typename HandleTypeIterator, typename PROP_VALUE>
519 void set_range(HandleTypeIterator begin, HandleTypeIterator end,
520 const PROP_VALUE &value) {
521 for (; begin != end; ++begin)
522 (*this)[*begin] = value;
523 }
524
525#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
526 template<typename HandleTypeIteratorRange, typename PROP_VALUE>
527 void set_range(const HandleTypeIteratorRange &range,
528 const PROP_VALUE &value) {
529 set_range(range.begin(), range.end(), value);
530 }
531#endif
532
547 template<typename HandleTypeIterator, typename PropertyManager2,
548 typename HandleTypeIterator2>
549 void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
550 PropertyManager2 &dst_propmanager,
551 HandleTypeIterator2 dst_begin, HandleTypeIterator2 dst_end) const {
552
553 for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
554 dst_propmanager[*dst_begin] = (*this)[*begin];
555 }
556 }
557
558 template<typename RangeType, typename PropertyManager2,
559 typename RangeType2>
560 void copy_to(const RangeType &range,
561 PropertyManager2 &dst_propmanager,
562 const RangeType2 &dst_range) const {
563 copy_to(range.begin(), range.end(), dst_propmanager,
564 dst_range.begin(), dst_range.end());
565 }
566
567
582 template<typename RangeType, typename RangeType2>
583 static void copy(const char *prop_name,
584 PolyConnectivity &src_mesh, const RangeType &src_range,
585 PolyConnectivity &dst_mesh, const RangeType2 &dst_range) {
586
588 DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name));
589
591 SrcPM src(src_mesh, prop_name, true);
592
593 src.copy_to(src_range, dst, dst_range);
594 }
595
602 void set_persistent(bool _persistence = true)
603 {
604 mesh().property(getRawProperty()).set_persistent(_persistence);
605 }
606
607 private:
608 void deleteProperty() {
609 if (!retain_ && prop_.is_valid())
610 mesh().remove_property(prop_);
611 }
612
613 PolyConnectivity& mesh() const
614 {
615 return const_cast<PolyConnectivity&>(mesh_);
616 }
617
618 private:
619 const PolyConnectivity& mesh_;
620 PROPTYPE prop_;
621 bool retain_;
622 std::string name_;
623};
624
625template <typename PropertyT>
627{
628public:
629 using Value = typename PropertyT::Value;
630 using value_type = typename PropertyT::value_type;
631 using Handle = typename PropertyT::Handle;
632
633 ConstPropertyViewer(const PolyConnectivity& mesh, const PropertyT& property_handle)
634 :
635 mesh_(mesh),
636 prop_(property_handle)
637 {}
638
639 inline const typename PropertyT::const_reference operator() (const Handle& handle)
640 {
641 return mesh_.property(prop_, handle);
642 }
643
644 inline const typename PropertyT::const_reference operator[] (const Handle& handle)
645 {
646 return mesh_.property(prop_, handle);
647 }
648
649private:
650 const PolyConnectivity& mesh_;
651 PropertyT prop_;
652};
653
681template<typename ElementT, typename T>
683OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name")
684makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) {
686}
687
712template<typename ElementT, typename T>
716}
717
718
740template<typename ElementT, typename T>
741bool
742hasProperty(const PolyConnectivity &mesh, const char *propname) {
744 return mesh.get_property_handle(ph, propname);
745}
746
774template<typename ElementT, typename T>
776getProperty(PolyConnectivity &mesh, const char *propname) {
777 if (!hasProperty<ElementT, T>(mesh, propname))
778 {
779 std::ostringstream oss;
780 oss << "Requested property handle \"" << propname << "\" does not exist.";
781 throw std::runtime_error(oss.str());
782 }
784}
785
815template<typename ElementT, typename T>
817getOrMakeProperty(PolyConnectivity &mesh, const char *propname) {
818 return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>::createIfNotExists(mesh, propname);
819}
820
830template<typename PROPTYPE>
831OM_DEPRECATED("Use makeTemporaryProperty instead.")
832PropertyManager<PROPTYPE> makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname)
833{
834 return PropertyManager<PROPTYPE>(mesh, propname, false);
835}
836
849template<typename PROPTYPE, typename MeshT = int>
850OM_DEPRECATED("Use getProperty instead.")
851PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname)
852{
853 return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true);
854}
855
864template<typename PROPTYPE, typename MeshT = int>
865OM_DEPRECATED("Use getOrMakeProperty instead.")
866PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname)
867{
869}
870
882template<typename PROPTYPE,
883 typename ITERATOR_TYPE, typename PROP_VALUE>
884OM_DEPRECATED("Use getOrMakeProperty instead.")
885PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
886 PolyConnectivity &mesh, const char *propname,
887 const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
888 const PROP_VALUE &init_value) {
890 mesh, propname, begin, end, init_value);
891}
892
904template<typename PROPTYPE,
905 typename ITERATOR_RANGE, typename PROP_VALUE>
906OM_DEPRECATED("Use getOrMakeProperty instead.")
907PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
908 PolyConnectivity &mesh, const char *propname,
909 const ITERATOR_RANGE &range,
910 const PROP_VALUE &init_value) {
911 return makePropertyManagerFromExistingOrNew<PROPTYPE>(
912 mesh, propname, range.begin(), range.end(), init_value);
913}
914
915
919template<typename MeshT>
921getPointsProperty(MeshT &mesh) {
922 return PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>(mesh, mesh.points_property_handle());
923}
924
928template<typename MeshT>
930getPointsProperty(const MeshT &mesh) {
932 return ConstPropertyViewer<PropType>(mesh, mesh.points_property_handle());
933}
934
935template <typename HandleT, typename T>
937
938template <typename T>
940
941template <typename T>
943
944template <typename T>
946
947template <typename T>
949
950template <typename T>
952
953
954} /* namespace OpenMesh */
955#endif /* PROPERTYMANAGER_HH_ */
Contains all the mesh ingredients like the polygonal mesh, the triangle mesh, different mesh kernels ...
Definition: MeshItems.hh:59
void remove_property(VPropHandleT< T > &_ph)
You should not use this function directly.
Definition: BaseKernel.hh:194
PropertyT< T > & property(VPropHandleT< T > _ph)
In most cases you should use the convenient PropertyManager wrapper and use of this function should n...
Definition: BaseKernel.hh:310
bool get_property_handle(VPropHandleT< T > &_ph, const std::string &_name) const
You should not use this function directly.
Definition: BaseKernel.hh:254
Connectivity Class for polygonal meshes.
Definition: PolyConnectivity.hh:115
Definition: HandleToPropHandle.hh:10
Default property class for any type T.
Definition: Property.hh:93
Handle representing a vertex property.
Definition: Property.hh:417
Handle representing a mesh property.
Definition: Property.hh:477
This class is intended to manage the lifecycle of properties.
Definition: PropertyManager.hh:76
static void copy(const char *prop_name, PolyConnectivity &src_mesh, const RangeType &src_range, PolyConnectivity &dst_mesh, const RangeType2 &dst_range)
Copy the values of a property from a source range to a target range.
Definition: PropertyManager.hh:583
void set_range(HandleTypeIterator begin, HandleTypeIterator end, const PROP_VALUE &value)
Conveniently set the property for an entire range of values.
Definition: PropertyManager.hh:519
PropertyManager(const Value &initial_value, PolyConnectivity &mesh, const char *propname)
Constructor.
Definition: PropertyManager.hh:196
ConstPropertyViewer< OpenMesh::VPropHandleT< typename MeshT::Point > > getPointsProperty(const MeshT &mesh)
Returns a convenience wrapper around the points property of a mesh that only allows const access.
Definition: PropertyManager.hh:930
PropertyManager(PolyConnectivity &mesh, const char *propname, bool existing)
Definition: PropertyManager.hh:160
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > makeTemporaryProperty(PolyConnectivity &mesh)
Creates a new property whose lifetime is limited to the current scope.
Definition: PropertyManager.hh:714
PROPTYPE::reference operator[](Handle handle)
Enables convenient access to the encapsulated property.
Definition: PropertyManager.hh:455
bool hasProperty(const PolyConnectivity &mesh, const char *propname)
Tests whether a property with the given element type, value type, and name is present on the given me...
Definition: PropertyManager.hh:742
void copy_to(HandleTypeIterator begin, HandleTypeIterator end, PropertyManager2 &dst_propmanager, HandleTypeIterator2 dst_begin, HandleTypeIterator2 dst_end) const
Conveniently transfer the values managed by one property manager onto the values managed by a differe...
Definition: PropertyManager.hh:549
PROPTYPE::reference & operator*()
Get the mesh corresponding to the property.
Definition: PropertyManager.hh:428
PropertyManager< OpenMesh::VPropHandleT< typename MeshT::Point > > getPointsProperty(MeshT &mesh)
Returns a convenience wrapper around the points property of a mesh.
Definition: PropertyManager.hh:921
void set_persistent(bool _persistence=true)
Mark whether this property should be stored when mesh is written to a file.
Definition: PropertyManager.hh:602
PropertyManager(const PolyConnectivity &mesh)
Constructor.
Definition: PropertyManager.hh:210
PropertyManager(const Value &initial_value, const PolyConnectivity &mesh)
Constructor.
Definition: PropertyManager.hh:222
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > getProperty(PolyConnectivity &mesh, const char *propname)
Obtains a handle to a named property.
Definition: PropertyManager.hh:776
PropertyManager clone()
Create property manager referring to a copy of the current property.
Definition: PropertyManager.hh:264
PropertyManager(PolyConnectivity &mesh, PROPTYPE property_handle)
Constructor.
Definition: PropertyManager.hh:235
PROPTYPE::reference operator()(const Handle &handle=Handle())
Enables convenient access to the encapsulated property.
Definition: PropertyManager.hh:477
PropertyManager< typename HandleToPropHandle< ElementT, T >::type > getOrMakeProperty(PolyConnectivity &mesh, const char *propname)
Obtains a handle to a named property if it exists or creates a new one otherwise.
Definition: PropertyManager.hh:817
PROPTYPE::const_reference & operator*() const
Access the value of the encapsulated mesh property.
Definition: PropertyManager.hh:444
PropertyManager(PolyConnectivity &mesh, const char *propname)
Constructor.
Definition: PropertyManager.hh:180
Definition: PropertyManager.hh:627

Project OpenMesh, ©  Visual Computing Institute, RWTH Aachen. Documentation generated using doxygen .