add property creator that can create properties from strings
This commit is contained in:
226
src/OpenMesh/Core/Utils/PropertyCreator.hh
Normal file
226
src/OpenMesh/Core/Utils/PropertyCreator.hh
Normal file
@@ -0,0 +1,226 @@
|
||||
/* ========================================================================= *
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (c) 2001-2020, RWTH-Aachen University *
|
||||
* Department of Computer Graphics and Multimedia *
|
||||
* All rights reserved. *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* This file is part of OpenMesh. *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. Neither the name of the copyright holder nor the names of its *
|
||||
* contributors may be used to endorse or promote products derived from *
|
||||
* this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* ========================================================================= */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
|
||||
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
#define OM_CONCAT_IMPL(a, b) a##b
|
||||
#define OM_CONCAT(a, b) OM_CONCAT_IMPL(a, b)
|
||||
|
||||
/** \brief Base class for property creators
|
||||
*
|
||||
* A PropertyCreator can add a named property to a mesh.
|
||||
* The type of the property is specified in the classes derived from this class.
|
||||
*
|
||||
* */
|
||||
class PropertyCreator
|
||||
{
|
||||
public:
|
||||
|
||||
/// The string that corresponds to the type this property creator can create
|
||||
virtual std::string type_string() = 0;
|
||||
|
||||
virtual std::string type_id_string() = 0;
|
||||
|
||||
/// Returns true iff the given _type_name corresponds to the string the derived class can create a property for
|
||||
bool can_you_create(const std::string &_type_name);
|
||||
|
||||
/// Create a vertex property on _mesh with name _property_name
|
||||
virtual void create_vertex_property (PolyConnectivity& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a halfedge property on _mesh with name _property_name
|
||||
virtual void create_halfedge_property(PolyConnectivity& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create an edge property on _mesh with name _property_name
|
||||
virtual void create_edge_property (PolyConnectivity& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a face property on _mesh with name _property_name
|
||||
virtual void create_face_property (PolyConnectivity& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
/// Create a mesh property on _mesh with name _property_name
|
||||
virtual void create_mesh_property (PolyConnectivity& _mesh, const std::string& _property_name) = 0;
|
||||
|
||||
|
||||
/// Create a property for the element of type HandleT on _mesh with name _property_name
|
||||
template <typename HandleT>
|
||||
void create_property(PolyConnectivity& _mesh, const std::string& _property_name);
|
||||
|
||||
virtual ~PropertyCreator() {}
|
||||
|
||||
protected:
|
||||
PropertyCreator() {}
|
||||
|
||||
};
|
||||
|
||||
template <> inline void PropertyCreator::create_property<VertexHandle> (PolyConnectivity& _mesh, const std::string& _property_name) { create_vertex_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<HalfedgeHandle>(PolyConnectivity& _mesh, const std::string& _property_name) { create_halfedge_property(_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<EdgeHandle> (PolyConnectivity& _mesh, const std::string& _property_name) { create_edge_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<FaceHandle> (PolyConnectivity& _mesh, const std::string& _property_name) { create_face_property (_mesh, _property_name); }
|
||||
template <> inline void PropertyCreator::create_property<MeshHandle> (PolyConnectivity& _mesh, const std::string& _property_name) { create_mesh_property (_mesh, _property_name); }
|
||||
|
||||
/// Helper class that contains the implementation of the create_<HandleT>_property methods.
|
||||
/// Implementation is injected into PropertyCreatorT.
|
||||
template <typename PropertyCreatorT>
|
||||
class PropertyCreatorImpl : public PropertyCreator
|
||||
{
|
||||
public:
|
||||
std::string type_id_string() override { return get_type_name<typename PropertyCreatorT::type>(); }
|
||||
void create_vertex_property (PolyConnectivity& _mesh, const std::string& _property_name) override { VProp<typename PropertyCreatorT::type> prop(_mesh, _property_name.c_str()); }
|
||||
void create_halfedge_property(PolyConnectivity& _mesh, const std::string& _property_name) override { HProp<typename PropertyCreatorT::type> prop(_mesh, _property_name.c_str()); }
|
||||
void create_edge_property (PolyConnectivity& _mesh, const std::string& _property_name) override { EProp<typename PropertyCreatorT::type> prop(_mesh, _property_name.c_str()); }
|
||||
void create_face_property (PolyConnectivity& _mesh, const std::string& _property_name) override { FProp<typename PropertyCreatorT::type> prop(_mesh, _property_name.c_str()); }
|
||||
void create_mesh_property (PolyConnectivity& _mesh, const std::string& _property_name) override { MProp<typename PropertyCreatorT::type> prop(_mesh, _property_name.c_str()); }
|
||||
|
||||
~PropertyCreatorImpl() override {}
|
||||
protected:
|
||||
PropertyCreatorImpl() {}
|
||||
};
|
||||
|
||||
/// Actual PropertyCreators specialize this class in order to add properties of type T
|
||||
namespace {
|
||||
template <typename T>
|
||||
class PropertyCreatorT : public PropertyCreatorImpl<PropertyCreatorT<T>>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#define OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) \
|
||||
namespace OpenMesh { \
|
||||
namespace { /* ensure internal linkage of class */ \
|
||||
template <> \
|
||||
class PropertyCreatorT<ClassName> : public PropertyCreatorImpl<PropertyCreatorT<ClassName>> \
|
||||
{ \
|
||||
public: \
|
||||
using type = ClassName; \
|
||||
std::string type_string() override { return TypeString; } \
|
||||
\
|
||||
PropertyCreatorT() \
|
||||
{ \
|
||||
PropertyCreationManager::instance().register_property_creator(this); \
|
||||
} \
|
||||
~PropertyCreatorT() override {} \
|
||||
}; \
|
||||
} \
|
||||
/* static to ensure internal linkage of object */ \
|
||||
static PropertyCreatorT<ClassName> OM_CONCAT(property_creator_registration_object_, __LINE__); \
|
||||
} \
|
||||
|
||||
/** \brief Class for adding properties based on strings
|
||||
*
|
||||
* The PropertyCreationManager holds all PropertyCreators and dispatches the property creation
|
||||
* to them if they are able to create a property for a given string.
|
||||
*
|
||||
* If you want to be able to store your custom properties into a file and automatically load
|
||||
* them without manually adding the property yourself you can register your type by calling the
|
||||
* OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString)
|
||||
* */
|
||||
class PropertyCreationManager
|
||||
{
|
||||
public:
|
||||
|
||||
static PropertyCreationManager& instance();
|
||||
|
||||
template <typename HandleT>
|
||||
void create_property(PolyConnectivity& _mesh, const std::string& _type_name, const std::string& _property_name)
|
||||
{
|
||||
for (const auto& pc : property_creators_)
|
||||
if (pc->can_you_create(_type_name))
|
||||
{
|
||||
pc->create_property<HandleT>(_mesh, _property_name);
|
||||
return;
|
||||
}
|
||||
omerr() << "No property creator registered that can create a property of type " << _type_name << std::endl;
|
||||
omerr() << "You need to register your custom type using OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString)." << std::endl;
|
||||
omerr() << "Adding property failed." << std::endl;
|
||||
}
|
||||
|
||||
void register_property_creator(PropertyCreator* _property_creator)
|
||||
{
|
||||
for (auto pc : property_creators_)
|
||||
if (pc->type_string() == _property_creator->type_string())
|
||||
{
|
||||
omlog() << "Property creator for type " << pc->type_string() << " already exists. Property creator will be ignored." << std::endl;
|
||||
if (pc->type_id_string() != _property_creator->type_id_string())
|
||||
{
|
||||
omerr() << "And it looks like you are trying to add a different type with an already existing string identification." << std::endl;
|
||||
omerr() << "Type id of existing type is " << pc->type_id_string() << " trying to add for " << _property_creator->type_id_string() << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
omlog() << "Adding property creator for type " << _property_creator->type_string() << std::endl;
|
||||
property_creators_.push_back(_property_creator);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PropertyCreationManager() {}
|
||||
~PropertyCreationManager() {}
|
||||
|
||||
std::vector<PropertyCreator*> property_creators_;
|
||||
};
|
||||
|
||||
/** \brief Create a property with type corresponding to _type_name on _mesh with name _property_name
|
||||
*
|
||||
* For user defined types you need to register the type using OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString)
|
||||
* */
|
||||
template <typename HandleT>
|
||||
void create_property_from_string(PolyConnectivity& _mesh, const std::string& _type_name, const std::string& _property_name)
|
||||
{
|
||||
PropertyCreationManager::instance().create_property<HandleT>(_mesh, _type_name, _property_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace OpenMesh */
|
||||
|
||||
OM_REGISTER_PROPERTY_TYPE(int, "int");
|
||||
Reference in New Issue
Block a user