add property creator that can create properties from strings

This commit is contained in:
Max Lyon
2020-11-30 20:53:18 +01:00
parent fcb7680610
commit bc6f7b75d9
3 changed files with 317 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
/* ========================================================================= *
* *
* 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. *
* *
* ========================================================================= */
#include "PropertyCreator.hh"
namespace OpenMesh {
PropertyCreationManager& PropertyCreationManager::instance()
{
static PropertyCreationManager manager;
return manager;
}
bool PropertyCreator::can_you_create(const std::string& _type_name)
{
return _type_name == type_string();
}
} /* namespace OpenMesh */

View 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");