/* ========================================================================= * * * * OpenMesh * * Copyright (c) 2001-2023, 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 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 OPENMESHDLLEXPORT 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(); } template void create_prop(BaseKernel& _mesh, const std::string& _property_name) { using PHandle = typename PropHandle::template type; PHandle prop; if (!_mesh.get_property_handle(prop, _property_name)) _mesh.add_property(prop, _property_name); } void create_vertex_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name); } void create_halfedge_property(BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} void create_edge_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} void create_face_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _property_name);} void create_mesh_property (BaseKernel& _mesh, const std::string& _property_name) override { create_prop(_mesh, _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 provide a string for type recognition #define OM_REGISTER_PROPERTY_TYPE(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::IO::binary::type_identifier(); } \ \ 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 OPENMESHDLLEXPORT PropertyCreationManager { public: static PropertyCreationManager& instance(); template void create_property(BaseKernel& _mesh, const std::string& _type_name, const std::string& _property_name) { auto can_create = [_type_name](OpenMesh::PropertyCreator* pc){ return pc->can_you_create(_type_name); }; std::vector::iterator pc_iter = std::find_if(property_creators_.begin(), property_creators_.end(), can_create); if (pc_iter != property_creators_.end()) { const auto& pc = *pc_iter; 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) and declare the struct binary.\ See documentation for more details." << 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()) { 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; } 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 */