/* ========================================================================= * * * * 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 #include #include #include #include #include #include #include #include #include #include #include #include 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 (BaseKernel& _mesh, const std::string& _property_name) = 0; /// Create a halfedge property on _mesh with name _property_name virtual void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) = 0; /// Create an edge property on _mesh with name _property_name virtual void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) = 0; /// Create a face property on _mesh with name _property_name virtual void create_face_property (BaseKernel& _mesh, const std::string& _property_name) = 0; /// Create a mesh property on _mesh with name _property_name virtual void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) = 0; /// Create a property for the element of type HandleT on _mesh with name _property_name template void create_property(BaseKernel& _mesh, const std::string& _property_name); virtual ~PropertyCreator() {} protected: PropertyCreator() {} }; template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_vertex_property (_mesh, _property_name); } template <> inline void PropertyCreator::create_property(BaseKernel& _mesh, const std::string& _property_name) { create_halfedge_property(_mesh, _property_name); } template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_edge_property (_mesh, _property_name); } template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_face_property (_mesh, _property_name); } template <> inline void PropertyCreator::create_property (BaseKernel& _mesh, const std::string& _property_name) { create_mesh_property (_mesh, _property_name); } /// Helper class that contains the implementation of the create__property methods. /// Implementation is injected into PropertyCreatorT. template class PropertyCreatorImpl : public PropertyCreator { public: std::string type_id_string() override { return get_type_name(); } void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) override { VPropHandleT prop; _mesh.add_property(prop, _property_name); } void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) override { HPropHandleT prop; _mesh.add_property(prop, _property_name); } void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) override { EPropHandleT prop; _mesh.add_property(prop, _property_name); } void create_face_property (BaseKernel& _mesh, const std::string& _property_name) override { FPropHandleT prop; _mesh.add_property(prop, _property_name); } void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) override { MPropHandleT prop; _mesh.add_property(prop, _property_name); } ~PropertyCreatorImpl() override {} protected: PropertyCreatorImpl() {} }; /// Actual PropertyCreators specialize this class in order to add properties of type T namespace { template class PropertyCreatorT : public PropertyCreatorImpl> { }; } ///used to register custom type, where typename.hh does NOT provide a string for type recognition #define OM_REGISTER_PROPERTY_TYPE(ClassName, TypeString) \ namespace OpenMesh { \ inline std::string get_string_for_type(ClassName){ return TypeString;} \ \ namespace { /* ensure internal linkage of class */ \ template <> \ class PropertyCreatorT : public PropertyCreatorImpl> \ { \ 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 OM_CONCAT(property_creator_registration_object_, __LINE__); \ } \ ///used to register custom type, where typename.hh does provide a string for type recognition /// #define OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(ClassName) \ namespace OpenMesh { \ namespace { /* ensure internal linkage of class */ \ template <> \ class PropertyCreatorT : public PropertyCreatorImpl> \ { \ public: \ using type = ClassName; \ std::string type_string() override { return OpenMesh::get_string_for_type(type()); } \ \ PropertyCreatorT() \ { \ PropertyCreationManager::instance().register_property_creator(this); \ } \ ~PropertyCreatorT() override {} \ }; \ } \ /* static to ensure internal linkage of object */ \ static PropertyCreatorT 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 void create_property(BaseKernel& _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(_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 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 void create_property_from_string(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) { PropertyCreationManager::instance().create_property(_mesh, _type_name, _property_name); } } /* namespace OpenMesh */ OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(OpenMesh::FaceHandle) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(OpenMesh::EdgeHandle) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(OpenMesh::HalfedgeHandle) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(OpenMesh::VertexHandle) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(bool) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(char) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(signed char) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(double) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(float) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(int) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(short) OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(unsigned char); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(unsigned int); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(unsigned short); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(unsigned long); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec1d); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec2d); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec3d); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec4d); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec5d); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6c); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6uc); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6s); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6us); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6i); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6ui); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6f); OM_REGISTER_PROPERTY_TYPE_USING_DEFAULT_STRING(Vec6d);