PropertyManager.hh 14 KB
Newer Older
1
2
3
/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
4
 *      Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen      *
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh is free software: you can redistribute it and/or modify         *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh is distributed in the hope that it will be useful,              *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                              *
 *   $Date$                                                                  *
 *                                                                           *
\*===========================================================================*/

#ifndef PROPERTYMANAGER_HH_
#define PROPERTYMANAGER_HH_

#include <sstream>
46
#include <stdexcept>
47
#include <string>
48
49
50
51
52
53
54
55
56
57
58
59

namespace OpenMesh {

/**
 * This class is intended to manage the lifecycle of properties.
 * It also defines convenience operators to access the encapsulated
 * property's value.
 *
 * Usage example:
 *
 * \code
 * TriMesh mesh;
60
 * PropertyManager<VPropHandleT<bool>, TriMesh> visited(mesh, "visited.plugin-example.i8.informatik.rwth-aachen.de");
61
62
63
64
65
66
67
68
69
70
71
 *
 * for (TriMesh::VertexIter vh_it = mesh.begin(); ... ; ...) {
 *     if (!visited[*vh_it]) {
 *         visitComponent(mesh, *vh_it, visited);
 *     }
 * }
 * \endcode
 *
 */
template<typename PROPTYPE, typename MeshT>
class PropertyManager {
72
73
74
75
76
#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
    public:
        PropertyManager(const PropertyManager&) = delete;
        PropertyManager& operator=(const PropertyManager&) = delete;
#else
77
78
    private:
        /**
79
         * Noncopyable because there aren't no straightforward copy semantics.
80
81
82
83
         */
        PropertyManager(const PropertyManager&);

        /**
84
         * Noncopyable because there aren't no straightforward copy semantics.
85
         */
86
87
        PropertyManager& operator=(const PropertyManager&);
#endif
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

    public:
        /**
         * Constructor.
         *
         * Throws an \p std::runtime_error if \p existing is true and
         * no property named \p propname of the appropriate property type
         * exists.
         *
         * @param mesh The mesh on which to create the property.
         * @param propname The name of the property.
         * @param existing If false, a new property is created and its lifecycle is managed (i.e.
         * the property is deleted upon destruction of the PropertyManager instance). If true,
         * the instance merely acts as a convenience wrapper around an existing property with no
         * lifecycle management whatsoever.
         */
104
        PropertyManager(MeshT &mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) {
105
106
107
108
109
110
111
112
113
114
115
            if (existing) {
                if (!mesh_->get_property_handle(prop_, propname)) {
                    std::ostringstream oss;
                    oss << "Requested property handle \"" << propname << "\" does not exist.";
                    throw std::runtime_error(oss.str());
                }
            } else {
                mesh_->add_property(prop_, propname);
            }
        }

116
117
118
        PropertyManager() : mesh_(0), retain_(false) {
        }

119
120
121
122
        ~PropertyManager() {
            deleteProperty();
        }

123
124
125
126
        void swap(PropertyManager &rhs) {
            std::swap(mesh_, rhs.mesh_);
            std::swap(prop_, rhs.prop_);
            std::swap(retain_, rhs.retain_);
127
            std::swap(name_, rhs.name_);
128
129
        }

130
131
132
133
134
        static bool propertyExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy;
            return mesh.get_property_handle(dummy, propname);
        }

135
136
137
138
139
        bool isValid() const { return mesh_ != 0; }
        operator bool() const { return isValid(); }

        const PROPTYPE &getRawProperty() const { return prop_; }

140
141
        const std::string &getName() const { return name_; }

142
143
        MeshT &getMesh() const { return *mesh_; }

144
145
146
147
#if __cplusplus > 199711L or __GXX_EXPERIMENTAL_CXX0X__
        /**
         * Move constructor. Transfers ownership (delete responsibility).
         */
148
        PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) {
149
150
151
152
153
154
155
156
157
158
159
160
161
            rhs.retain_ = true;
        }

        /**
         * Move assignment. Transfers ownership (delete responsibility).
         */
        PropertyManager &operator=(PropertyManager &&rhs) {

            deleteProperty();

            mesh_ = rhs.mesh_;
            prop_ = rhs.prop_;
            retain_ = rhs.retain_;
162
            name_ = rhs.name_;
163
164
165
166
            rhs.retain_ = true;

            return *this;
        }
167
168
169
170
171
172
173
174
175
176
177
178

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return std::move(pm);
        }
179

180
181
182
183
184
185
186

        PropertyManager duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return std::move(pm);
        }

187
188
189
190
191
192
193
        /**
         * Included for backwards compatibility with non-C++11 version.
         */
        PropertyManager move() {
            return std::move(*this);
        }

194
195
196
#else
        class Proxy {
            private:
197
198
                Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) :
                    mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {}
199
200
201
                MeshT *mesh_;
                PROPTYPE prop_;
                bool retain_;
202
                std::string name_;
203
204
205
206
207

                friend class PropertyManager;
        };

        operator Proxy() {
208
            Proxy p(mesh_, prop_, retain_, name_);
209
210
211
212
213
            mesh_ = 0;
            retain_ = true;
            return p;
        }

214
215
216
217
        Proxy move() {
            return (Proxy)*this;
        }

218
        PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {}
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

        PropertyManager &operator=(Proxy p) {
            PropertyManager(p).swap(*this);
            return *this;
        }

        /**
         * Create a property manager for the supplied property and mesh.
         * If the property doesn't exist, it is created. In any case,
         * lifecycle management is disabled.
         */
        static Proxy createIfNotExists(MeshT &mesh, const char *propname) {
            PROPTYPE dummy_prop;
            PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
            pm.retain();
            return (Proxy)pm;
        }
236
237
238
239
240
241

        Proxy duplicate(const char *clone_name) {
            PropertyManager pm(*mesh_, clone_name, false);
            pm.mesh_->property(pm.prop_) = mesh_->property(prop_);
            return (Proxy)pm;
        }
242
243
244
245
246
247
248
249
#endif

        /**
         * \brief Disable lifecycle management for this property.
         *
         * If this method is called, the encapsulated property will not be deleted
         * upon destruction of the PropertyManager instance.
         */
250
251
        inline void retain(bool doRetain = true) {
            retain_ = doRetain;
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        }

        /**
         * Access the encapsulated property.
         */
        inline PROPTYPE &operator* () {
            return prop_;
        }

        /**
         * Access the encapsulated property.
         */
        inline const PROPTYPE &operator* () const {
            return prop_;
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
            return mesh_->property(prop_, handle);
        }

        /**
         * Enables convenient access to the encapsulated property.
         *
         * For a usage example see this class' documentation.
         *
         * @param handle A handle of the appropriate handle type. (I.e. \p VertexHandle for \p VPropHandleT, etc.)
         */
        template<typename HandleType>
        inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
            return mesh_->property(prop_, handle);
        }

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
        /**
         * Conveniently set the property for an entire range of values.
         *
         * Examples:
         * \code
         * MeshT mesh;
         * PropertyManager<VPropHandleT<double>, MeshT> distance(
         *     mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de");
         * distance.set_range(
         *     mesh.vertices_begin(), mesh.vertices_end(),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         * or
         * \code
         * MeshT::VertexHandle vh;
         * distance.set_range(
         *     mesh.vv_begin(vh), mesh.vv_end(vh),
         *     std::numeric_limits<double>::infinity());
         * \endcode
         *
         * @param begin Start iterator. Needs to dereference to HandleType.
         * @param end End iterator. (Exclusive.)
         * @param value The value the range will be set to.
         */
        template<typename HandleTypeIterator>
        void set_range(HandleTypeIterator begin, HandleTypeIterator end,
                typename PROPTYPE::const_reference value) {
            for (; begin != end; ++begin)
                (*this)[*begin] = value;
        }

323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
        /**
         * Conveniently transfer the values managed by one property manager
         * onto the values managed by a different property manager.
         *
         * @param begin Start iterator. Needs to dereference to HandleType. Will
         * be used with this property manager.
         * @param end End iterator. (Exclusive.) Will be used with this property
         * manager.
         * @param dst_propmanager The destination property manager.
         * @param dst_begin Start iterator. Needs to dereference to the
         * HandleType of dst_propmanager. Will be used with dst_propmanager.
         * @param dst_end End iterator. (Exclusive.)
         * Will be used with dst_propmanager. Used to double check the bounds.
         */
        template<typename HandleTypeIterator, typename PROPTYPE_2,
                 typename MeshT_2, typename HandleTypeIterator_2>
        void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {

            for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
                dst_propmanager[dst_begin] = (*this)[*begin];
            }
        }

        template<typename RangeType, typename PROPTYPE_2,
                 typename MeshT_2, typename RangeType_2>
        void copy_to(RangeType range,
                PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager,
                RangeType_2 dst_range) const {
            copy_to(range.begin(), range.end(), dst_propmanager,
                    dst_range.begin(), dst_range.end());
        }

357
358
359
360
361
362
363
364
365
366
    private:
        void deleteProperty() {
            if (!retain_)
                mesh_->remove_property(prop_);
        }

    private:
        MeshT *mesh_;
        PROPTYPE prop_;
        bool retain_;
367
        std::string name_;
368
369
370
371
};

} /* namespace OpenMesh */
#endif /* PROPERTYMANAGER_HH_ */