/* openDCM, dimensional constraint manager Copyright (C) 2013 Stefan Troeger This library 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 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef GCM_MODULE_SHAPE3D_H #define GCM_MODULE_SHAPE3D_H #include #include #include #include "defines.hpp" #include "geometry.hpp" #include "generator.hpp" #include #include #include #include #include #include #include #include #include #include #include #define APPEND_SINGLE(z, n, data) \ typedef typename Sys::Identifier Identifier; \ typedef typename system_traits::template getModule::type::geometry_types gtypes; \ typedef typename system_traits::template getModule::type::geometry_types stypes; \ g_ptr = details::converter_g::template apply(BOOST_PP_CAT(arg,n), m_this); \ if(!g_ptr) { \ hlg_ptr = details::converter_hlg::template apply(BOOST_PP_CAT(arg,n), data, m_this); \ if(!hlg_ptr) \ throw creation_error() << boost::errinfo_errno(216) << error_message("could not handle input"); \ else \ data->append(hlg_ptr);\ } \ else { \ data->append(g_ptr); \ } \ #define CREATE_DEF(z, n, data) \ template < \ typename Generator \ BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ > \ std::shared_ptr createShape3D( \ BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ ); #define CREATE_DEC(z, n, data) \ template \ template \ template <\ typename Generator \ BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg)\ > \ std::shared_ptr::template type::Shape3D> \ ModuleShape3D::type::inheriter_base::createShape3D( \ BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ ) \ { \ typedef typename system_traits::template getModule::type module3d; \ typedef typename module3d::Geometry3D Geometry3D; \ std::shared_ptr g_ptr; \ std::shared_ptr hlg_ptr; \ std::shared_ptr ptr = std::shared_ptr(new Shape3D(*m_this)); \ BOOST_PP_REPEAT(n, APPEND_SINGLE, ptr) \ ptr->template initShape();\ m_this->push_back(ptr);\ return ptr;\ }; namespace mpl = boost::mpl; namespace dcm { namespace details { //return always a geometry3d pointer struct, no matter what's the supplied type template struct converter_g { //check if the type T is usable from within module3d, as it could also be a shape type template static typename boost::enable_if< mpl::and_< mpl::not_< boost::is_same::type,typename mpl::end::type> >, mpl::not_ > >, std::shared_ptr >::type apply(T const& t, Sys* sys) { return sys->createGeometry3D(t); }; //seems to be a shape type, return an empty geometry template static typename boost::enable_if< mpl::and_< boost::is_same::type, typename mpl::end::type>, mpl::not_ > >, std::shared_ptr >::type apply(T const& t, Sys* sys) { return std::shared_ptr(); }; //seems to be an identifier type, lets check if we have such a geometry template static typename boost::enable_if< boost::is_same, std::shared_ptr >::type apply(T const& t, Sys* sys) { return sys->getGeometry3D(t); }; }; template struct converter_g< std::shared_ptr, R> { template static std::shared_ptr apply(std::shared_ptr t, Sys* sys) { return t; }; }; template struct converter_hlg { template static typename boost::enable_if< mpl::and_< boost::is_same::type, typename mpl::end::type>, mpl::not_ > >, std::shared_ptr >::type apply(T const& t, std::shared_ptr self, Sys* sys) { return std::shared_ptr(); }; template static typename boost::enable_if< mpl::not_< boost::is_same::type, typename mpl::end::type> >, std::shared_ptr >::type apply(T const& t, std::shared_ptr self, Sys* sys) { //shape can only be set one time, throw an error otherwise if(self->holdsType()) throw creation_error() << boost::errinfo_errno(410) << error_message("Shape can only be set with one geometry"); self->set(t); return self; }; //seems to be an identifier type, lets check if we have such a geometry template static typename boost::enable_if< boost::is_same, std::shared_ptr >::type apply(T const& t, std::shared_ptr self, Sys* sys) { return sys->getShape3D(t); }; }; template struct converter_hlg, R> { template static std::shared_ptr apply(std::shared_ptr t, std::shared_ptr self, Sys* sys) { return t; }; }; }//details template struct ModuleShape3D { template struct type : details::mshape3d { typedef TypeList geometry_types; //forward declare struct inheriter_base; struct Shape3D; typedef mpl::map2< mpl::pair) > >, mpl::pair) > > > ShapeSig; template struct Shape3D_base : public details::Geometry, public Object { typedef typename Sys::Kernel Kernel; typedef typename Kernel::number_type Scalar; //traits are only accessible in subclass scope BOOST_MPL_ASSERT((typename system_traits::template getModule::has_module)); typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; typedef typename module3d::Constraint3D Constraint3D; Shape3D_base(Sys& system); template Shape3D_base(const T& geometry, Sys& system); template void set(const T& geometry); bool holdsType() { return m_geometry.which()!=0; }; int whichType() { return m_geometry.which()-1; }; template typename Visitor::result_type apply(Visitor& vis) { return boost::apply_visitor(vis, m_geometry); }; template T convertTo() { T t; (typename geometry_traits::modell()).template inject::accessor >(t, Base::m_global); return t; }; virtual std::shared_ptr clone(Sys& newSys); /*shape access functions and extractors to mimic vector<> iterators*/ typedef std::vector, Connection> > GeometryVector; typedef std::vector, Connection> > ShapeVector; typedef std::vector, Connection> > ConstraintVector; struct geom_extractor { typedef std::shared_ptr result_type; template result_type operator()(T& pair) const { return fusion::at_c<0>(pair); }; }; struct shape_extractor { typedef std::shared_ptr result_type; template result_type operator()(T& pair) const { return fusion::at_c<0>(pair); }; }; struct cons_extractor { typedef std::shared_ptr result_type; template result_type operator()(T& pair) const { return fusion::at_c<0>(pair); }; }; typedef boost::transform_iterator geometry3d_iterator; typedef boost::transform_iterator shape3d_iterator; typedef boost::transform_iterator constraint3d_iterator; shape3d_iterator beginShape3D() { return boost::make_transform_iterator(m_shapes.begin(), shape_extractor()); }; shape3d_iterator endShape3D() { return boost::make_transform_iterator(m_shapes.end(), shape_extractor()); }; geometry3d_iterator beginGeometry3D() { return boost::make_transform_iterator(m_geometries.begin(), geom_extractor()); }; geometry3d_iterator endGeometry3D() { return boost::make_transform_iterator(m_geometries.end(), geom_extractor()); }; constraint3d_iterator beginConstraint3D() { return boost::make_transform_iterator(m_constraints.begin(), cons_extractor()); }; constraint3d_iterator endConstraint3D() { return boost::make_transform_iterator(m_constraints.end(), cons_extractor()); }; std::shared_ptr geometry(purpose f); template std::shared_ptr subshape(); //callbacks void recalc(std::shared_ptr g); void remove(std::shared_ptr g); void remove(std::shared_ptr g); void remove(std::shared_ptr g); private: //we store all geometries, shapes and constraint which belong to this shape. //Furthermore we store the remove connections, as we need to disconnect them later GeometryVector m_geometries; ShapeVector m_shapes; ConstraintVector m_constraints; protected: #ifdef USE_LOGGING src::logger log; #endif typedef details::Geometry Base; typedef Object ObjBase; typedef typename mpl::push_front::type ExtTypeList; typedef typename boost::make_variant_over< ExtTypeList >::type Variant; struct cloner : boost::static_visitor { typedef typename boost::make_variant_over< ExtTypeList >::type Variant; Variant variant; cloner(Variant& v) : variant(v) {}; template void operator()(T& t) { variant = geometry_clone_traits()(t); }; }; //visitor to write the calculated value into the variant struct apply_visitor : public boost::static_visitor { apply_visitor(typename Kernel::Vector& v) : value(v) {}; template void operator()(T& t) const { (typename geometry_traits::modell()).template inject::accessor >(t, value); } typename Kernel::Vector& value; }; Variant m_geometry; //Variant holding the real geometry type std::shared_ptr< details::ShapeGeneratorBase > m_generator; using Object::m_system; template void initShape() { m_generator = std::shared_ptr >(new typename generator::template type(m_system)); m_generator->set(ObjBase::shared_from_this(), &m_geometries, &m_shapes, &m_constraints); if(!m_generator->check()) throw creation_error() << boost::errinfo_errno(210) << error_message("not all needd geometry for shape present"); m_generator->init(); }; //disconnect all remove signals of stored geometry/shapes/constraints void disconnectAll(); //the storage is private, all things need to be added by this methods. //this is used to ensure the proper event connections std::shared_ptr append(std::shared_ptr g); std::shared_ptr append(std::shared_ptr g); std::shared_ptr append(std::shared_ptr g); //override protected event functions to emit signals void reset() {}; void recalculated() {}; void removed() {}; friend struct inheriter_base; friend struct Object >; }; template class Shape3D_id : public Shape3D_base { typedef Shape3D_base Base; #ifdef USE_LOGGING attrs::mutable_constant< std::string > log_id; #endif public: Shape3D_id(Sys& system); template Shape3D_id(const T& geometry, Sys& system); template void set(const T& geometry, ID id); //somehow the base class set function is not found template void set(const T& geometry); ID& getIdentifier(); void setIdentifier(ID id); }; struct Shape3D : public mpl::if_, Shape3D_base, Shape3D_id >::type { Shape3D(Sys& system); template Shape3D(const T& geometry, Sys& system); //allow accessing the internals by module3d classes but not by users friend struct details::ClusterMath; friend struct details::ClusterMath::map_downstream; friend struct details::SystemSolver; friend struct details::SystemSolver::Rescaler; friend struct inheriter_base; friend struct details::ShapeGeneratorBase; public: //the geometry class itself does not hold an aligned eigen object, but maybe the variant EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; //inheriter for own functions struct inheriter_base { inheriter_base() { m_this = (Sys*)this; }; void system_sub(std::shared_ptr subsys) {}; protected: Sys* m_this; public: //with no vararg templates before c++11 we need preprocessor to create the overloads of create we need BOOST_PP_REPEAT(5, CREATE_DEF, ~) void removeShape3D(std::shared_ptr g); }; struct inheriter_id : public inheriter_base { //we don't have a createshape3d method with identifier, as identifiers can be used to //specifie creation geometries or shapes. Therefore a call would always be ambiguous. void removeShape3D(ID id); bool hasShape3D(ID id); std::shared_ptr getShape3D(ID id); using inheriter_base::removeShape3D; protected: using inheriter_base::m_this; }; struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; //add properties to geometry and constraint to evaluate their shape partipance struct shape_purpose_prop { typedef purpose type; typedef typename system_traits::template getModule::type::Geometry3D kind; }; struct shape_geometry_prop { typedef bool type; typedef typename system_traits::template getModule::type::Geometry3D kind; }; struct shape_constraint_prop { typedef bool type; typedef typename system_traits::template getModule::type::Constraint3D kind; }; //needed typedefs typedef ID Identifier; typedef mpl::vector3 properties; typedef mpl::vector1 objects; typedef mpl::vector1 geometries; typedef mpl::map0<> signals; //needed static functions static void system_init(Sys& sys) {}; static void system_copy(const Sys& from, Sys& into) {}; }; }; /*****************************************************************************************************************/ /*****************************************************************************************************************/ /*****************************************************************************************************************/ /*****************************************************************************************************************/ BOOST_PP_REPEAT(5, CREATE_DEC, ~) template template template ModuleShape3D::type::Shape3D_base::Shape3D_base(Sys& system) : Object(system) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); #endif }; template template template template ModuleShape3D::type::Shape3D_base::Shape3D_base(const T& geometry, Sys& system) : Object(system) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); #endif m_geometry = geometry; //first init, so that the geometry internal vector has the right size Base::template init< typename geometry_traits::tag >(); //now write the value; (typename geometry_traits::modell()).template extract::accessor >(geometry, Base::getValue()); }; template template template template void ModuleShape3D::type::Shape3D_base::set(const T& geometry) { m_geometry = geometry; //first init, so that the geometry internal vector has the right size this->template init< typename geometry_traits::tag >(); //now write the value; (typename geometry_traits::modell()).template extract::accessor >(geometry, this->getValue()); reset(); }; template template template std::shared_ptr ModuleShape3D::type::Shape3D_base::clone(Sys& newSys) { //copy the standard stuff std::shared_ptr np = std::shared_ptr(new Derived(*static_cast(this))); np->m_system = &newSys; //it's possible that the variant contains pointers, so we need to clone them cloner clone_fnc(np->m_geometry); boost::apply_visitor(clone_fnc, m_geometry); return np; }; template template template std::shared_ptr::template getModule::type::Geometry3D> ModuleShape3D::type::Shape3D_base::geometry(purpose f) { for(geometry3d_iterator it = beginGeometry3D(); it != endGeometry3D(); it++) { if((*it)->template getProperty() == f) return *it; }; return std::shared_ptr(); }; template template template std::shared_ptr ModuleShape3D::type::Shape3D_base::append(std::shared_ptr g) { g->template setProperty(true); Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); m_geometries.push_back(fusion::make_vector(g,c)); return ObjBase::shared_from_this(); }; template template template std::shared_ptr ModuleShape3D::type::Shape3D_base::append(std::shared_ptr g) { Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); m_shapes.push_back(fusion::make_vector(g,c)); return ObjBase::shared_from_this(); }; template template template std::shared_ptr ModuleShape3D::type::Shape3D_base::append(std::shared_ptr g) { Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); m_constraints.push_back(fusion::make_vector(g,c)); return ObjBase::shared_from_this(); }; template template template void ModuleShape3D::type::Shape3D_base::disconnectAll() { typename GeometryVector::iterator git; for(git = m_geometries.begin(); git!=m_geometries.end(); git++) fusion::at_c<0>(*git)->template disconnectSignal(fusion::at_c<1>(*git)); typename ShapeVector::iterator sit; for(sit = m_shapes.begin(); sit!=m_shapes.end(); sit++) fusion::at_c<0>(*sit)->template disconnectSignal(fusion::at_c<1>(*sit)); typename ConstraintVector::iterator cit; for(cit = m_constraints.begin(); cit!=m_constraints.end(); cit++) fusion::at_c<0>(*cit)->template disconnectSignal(fusion::at_c<1>(*cit)); }; template template template void ModuleShape3D::type::Shape3D_base::recalc(std::shared_ptr g) { //we recalculated thebase line, that means we have our new value. use it. Base::finishCalculation(); }; template template template void ModuleShape3D::type::Shape3D_base::remove(std::shared_ptr g) { //before we delete this shape by calling the system remove function, we need to remove //this geometry as this would be deleted again by the system call and we would go into infinite recursion //get the vector object where the geometry is part of typename GeometryVector::const_iterator it; for(it=m_geometries.begin(); it!=m_geometries.end(); it++) { if(fusion::at_c<0>(*it)==g) break; }; m_geometries.erase(std::remove(m_geometries.begin(), m_geometries.end(), *it), m_geometries.end()); ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); }; template template template void ModuleShape3D::type::Shape3D_base::remove(std::shared_ptr g) { //before we delete this shape by calling the system remove function, we need to remove //this geometry as this would be deleted again by the system call and we would go into infinite recursion //get the vector object where the geometry is part of typename ShapeVector::const_iterator it; for(it=m_shapes.begin(); it!=m_shapes.end(); it++) { if(fusion::at_c<0>(*it)==g) break; }; m_shapes.erase(std::remove(m_shapes.begin(), m_shapes.end(), *it), m_shapes.end()); ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); }; template template template void ModuleShape3D::type::Shape3D_base::remove(std::shared_ptr g) { //before we delete this shape by calling the system remove function, we need to remove //this geometry as this would be deleted again by the system call and we would go into infinite recursion //get the vector object where the geometry is part of typename ConstraintVector::const_iterator it; for(it=m_constraints.begin(); it!=m_constraints.end(); it++) { if(fusion::at_c<0>(*it)==g) break; }; m_constraints.erase(std::remove(m_constraints.begin(), m_constraints.end(), *it), m_constraints.end()); ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); }; template template template ModuleShape3D::type::Shape3D_id::Shape3D_id(Sys& system) : ModuleShape3D::template type::template Shape3D_base(system) #ifdef USE_LOGGING , log_id("No ID") #endif { #ifdef USE_LOGGING Base::log.add_attribute("ID", log_id); #endif }; template template template template ModuleShape3D::type::Shape3D_id::Shape3D_id(const T& geometry, Sys& system) : ModuleShape3D::template type::template Shape3D_base(geometry, system) #ifdef USE_LOGGING , log_id("No ID") #endif { #ifdef USE_LOGGING Base::log.add_attribute("ID", log_id); #endif }; template template template template void ModuleShape3D::type::Shape3D_id::set(const T& geometry, Identifier id) { this->template setProperty >(id); Base::set(geometry); }; template template template template void ModuleShape3D::type::Shape3D_id::set(const T& geometry) { Base::set(geometry); }; template template template typename ModuleShape3D::template type::Identifier& ModuleShape3D::type::Shape3D_id::getIdentifier() { return this->template getProperty >(); }; template template template void ModuleShape3D::type::Shape3D_id::setIdentifier(Identifier id) { this->template setProperty >(id); #ifdef USE_LOGGING std::stringstream str; str<template getProperty >(); log_id.set(str.str()); BOOST_LOG(Base::log)<<"Identifyer set: "< template ModuleShape3D::type::Shape3D::Shape3D(Sys& system) : mpl::if_, Shape3D_base, Shape3D_id >::type(system) { }; template template template ModuleShape3D::type::Shape3D::Shape3D(const T& geometry, Sys& system) : mpl::if_, Shape3D_base, Shape3D_id >::type(geometry, system) { }; template template void ModuleShape3D::type::inheriter_base::removeShape3D(std::shared_ptr g) { //disconnect all shapes, geometries and constraints, as otherwise we would go into infinite //recursion g->disconnectAll(); //remove all constraints is unnecessary as they get removed together with the geometries //remove all geometries typedef typename Shape3D::geometry3d_iterator git; for(git it=g->beginGeometry3D(); it!=g->endGeometry3D(); it++) m_this->removeGeometry3D(*it); /* TODO: find out why it iterates over a empty vector and crashes... //remove all subshapes typedef typename Shape3D::shape3d_iterator sit; for(sit it=g->beginShape3D(); it!=g->endShape3D(); it++) { m_this->removeShape3D(*it); };*/ //emit remove shape signal before actually deleting it g->template emitSignal(g); m_this->erase(g); }; template template bool ModuleShape3D::type::inheriter_id::hasShape3D(Identifier id) { if(getShape3D(id)) return true; return false; }; template template std::shared_ptr::template type::Shape3D> ModuleShape3D::type::inheriter_id::getShape3D(Identifier id) { std::vector< std::shared_ptr >& vec = inheriter_base::m_this->template objectVector(); typedef typename std::vector< std::shared_ptr >::iterator iter; for(iter it=vec.begin(); it!=vec.end(); it++) { if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; }; return std::shared_ptr(); }; template template void ModuleShape3D::type::inheriter_id::removeShape3D(Identifier id) { std::shared_ptr s = getShape3D(id); if(s) removeShape3D(s); }; }//dcm #endif //GCM_MODULE_SHAPE3D_H