/* openDCM, dimensional constraint manager Copyright (C) 2012 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_PART_H #define GCM_MODULE_PART_H #include "opendcm/core.hpp" #include "opendcm/core/traits.hpp" #include "opendcm/core/clustergraph.hpp" #include "opendcm/core/property.hpp" #include "opendcm/module3d.hpp" #include #include namespace mpl = boost::mpl; namespace dcm { enum { clusterPart = 110}; enum CoordinateFrame {Local, Global}; template struct ModulePart { template struct type { struct Part; struct PrepareCluster; struct EvaljuateCluster; typedef boost::shared_ptr Partptr; typedef mpl::map2< mpl::pair >, mpl::pair > > PartSignal; typedef ID Identifier; class Part_base : public Object { protected: #ifdef USE_LOGGING src::logger log; #endif //check if we have module3d in this system typedef typename system_traits::template getModule::type module3d; BOOST_MPL_ASSERT((mpl::not_ >)); //define what we need typedef typename module3d::Geometry3D Geometry3D; typedef boost::shared_ptr Geom; typedef typename boost::make_variant_over< Typelist >::type Variant; typedef Object base; typedef typename Sys::Kernel Kernel; typedef typename Sys::Cluster Cluster; typedef typename Kernel::number_type Scalar; typedef typename Kernel::Transform3D Transform; struct cloner : boost::static_visitor { 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(Transform& t) : m_transform(t) {}; template void operator()(T& t) const { (typename geometry_traits::modell()).template inject::accessor >(t, m_transform); } Transform& m_transform; }; //collect all clustergraph upstream cluster transforms void transform_traverse(Transform& t, boost::shared_ptr c); public: using Object::m_system; template Part_base(const T& geometry, Sys& system, boost::shared_ptr cluster); template typename Visitor::result_type apply(Visitor& vis); template Geom addGeometry3D(const T& geom, CoordinateFrame frame = Global); template void set(const T& geometry); template T& get(); template T getGlobal(); virtual boost::shared_ptr clone(Sys& newSys); public: Variant m_geometry; Transform m_transform; boost::shared_ptr m_cluster; void finishCalculation(); void fix(bool fix_value); public: //we hold a transform and need therefore a aligned new operator EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; struct Part_id : public Part_base { template Part_id(const T& geometry, Sys& system, boost::shared_ptr cluster); template typename Part_base::Geom addGeometry3D(const T& geom, Identifier id, CoordinateFrame frame = Global); template void set(const T& geometry, Identifier id); bool hasGeometry3D(Identifier id); typename Part_base::Geom getGeometry3D(Identifier id); Identifier& getIdentifier(); void setIdentifier(Identifier id); }; struct Part : public mpl::if_, Part_base, Part_id>::type { typedef typename mpl::if_, Part_base, Part_id>::type base; template Part(const T& geometry, Sys& system, boost::shared_ptr cluster); friend struct PrepareCluster; friend struct EvaljuateCluster; public: //we hold a transform and need therefore a aligned new operator EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; struct inheriter_base { inheriter_base(); template Partptr createPart(const T& geometry); void removePart(Partptr p); template void setTransformation(const T& geom) { typedef typename system_traits::template getModule::type module3d; details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getProperty(); (typename geometry_traits::modell()).template extract::accessor >(geom, cm.getTransform()); }; template T getTransformation() { T geom; getTransformation(geom); return geom; }; template void getTransformation(T& geom) { typedef typename system_traits::template getModule::type module3d; details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getProperty(); (typename geometry_traits::modell()).template inject::accessor >(geom, cm.getTransform()); }; protected: Sys* m_this; //function object to emit remove signal too al geometry which is deleted by part deletion struct remover { typedef typename Sys::Cluster Cluster; typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; typedef boost::shared_ptr Geom; typedef typename module3d::Constraint3D Constraint3D; typedef boost::shared_ptr Cons; Sys& system; remover(Sys& s); //see if we have a geometry or a constraint and emit the remove signal void operator()(GlobalVertex v); //we delete all global edges connecting to this part void operator()(GlobalEdge e); void operator()(boost::shared_ptr g) {}; }; }; struct inheriter_id : public inheriter_base { template Partptr createPart(const T& geometry, Identifier id); bool hasPart(Identifier id); Partptr getPart(Identifier id); }; struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; typedef mpl::vector0<> properties; typedef mpl::vector1 objects; typedef mpl::vector0<> geometries; struct PrepareCluster : public Job { typedef typename Sys::Cluster Cluster; typedef typename Sys::Kernel Kernel; typedef typename system_traits::template getModule::type module3d; PrepareCluster(); virtual void execute(Sys& sys); }; struct EvaljuateCluster : public Job { typedef typename Sys::Cluster Cluster; typedef typename Sys::Kernel Kernel; typedef typename system_traits::template getModule::type module3d; EvaljuateCluster(); virtual void execute(Sys& sys); }; static void system_init(Sys& sys) { sys.m_sheduler.addPreprocessJob(new PrepareCluster()); sys.m_sheduler.addPostprocessJob(new EvaljuateCluster()); }; static void system_copy(const Sys& from, Sys& into) {}; }; }; template template template ModulePart::type::Part_base::Part_base(const T& geometry, Sys& system, boost::shared_ptr cluster) : Object(system), m_geometry(geometry), m_cluster(cluster) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Part3D")); #endif (typename geometry_traits::modell()).template extract::accessor >(geometry, m_transform); cluster->template setProperty(false); //the the clustermath transform m_cluster->template getProperty().getTransform() = m_transform; #ifdef USE_LOGGING BOOST_LOG(log) << "Init: "< template template typename Visitor::result_type ModulePart::type::Part_base::apply(Visitor& vis) { return boost::apply_visitor(vis, m_geometry); }; template template template typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_base::addGeometry3D(const T& geom, CoordinateFrame frame) { Geom g(new Geometry3D(geom, *m_system)); if(frame == Local) { //we need to collect all transforms up to this part! Transform t;//(m_transform); transform_traverse(t, m_cluster); g->transform(t); } fusion::vector res = m_cluster->addVertex(); m_cluster->template setObject (fusion::at_c<0> (res), g); g->template setProperty(fusion::at_c<1>(res)); m_system->template objectVector().push_back(g); return g; }; template template void ModulePart::type::Part_base::transform_traverse(ModulePart::type::Part_base::Transform& t, boost::shared_ptr::type::Part_base::Cluster> c) { t *= c->template getProperty().m_transform; if(c->isRoot()) return; transform_traverse(t, c->parent()); } template template template void ModulePart::type::Part_base::set(const T& geometry) { Part_base::m_geometry = geometry; (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); //set the clustermath transform m_cluster->template getClusterProperty().getTransform() = m_transform; }; template template template T& ModulePart::type::Part_base::get() { return get(this); }; template template template T ModulePart::type::Part_base::getGlobal() { //get the successive transform Transform t; transform_traverse(t, m_cluster); //put it into the user type T ut; (typename geometry_traits::modell()).template inject::accessor >(ut, t); return ut; }; template template boost::shared_ptr::template type::Part> ModulePart::type::Part_base::clone(Sys& newSys) { //we need to reset the cluster pointer to the new system cluster LocalVertex lv = Object::m_system->m_cluster->getClusterVertex(m_cluster); GlobalVertex gv = Object::m_system->m_cluster->getGlobalVertex(lv); boost::shared_ptr np = Object::clone(newSys); //there may be pointer inside the variant cloner clone_fnc(np->m_geometry); boost::apply_visitor(clone_fnc, m_geometry); fusion::vector, bool> res = newSys.m_cluster->getLocalVertexGraph(gv); if(!fusion::at_c<2>(res)) { //todo: throw return np; } np->m_cluster = fusion::at_c<1>(res)->getVertexCluster(fusion::at_c<0>(res)); return np; }; template template void ModulePart::type::Part_base::finishCalculation() { m_transform.normalize(); apply_visitor vis(m_transform); apply(vis); #ifdef USE_LOGGING BOOST_LOG(log) << "New Value: "<(((Part*)this)->shared_from_this()); }; template template void ModulePart::type::Part_base::fix(bool fix_value) { m_cluster->template setProperty(fix_value); }; template template template ModulePart::type::Part_id::Part_id(const T& geometry, Sys& system, boost::shared_ptr cluster) : Part_base(geometry, system, cluster) { }; template template template typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_id::addGeometry3D(const T& geom, Identifier id, CoordinateFrame frame) { typename Part_base::Geom g = Part_base::addGeometry3D(geom, frame); g->setIdentifier(id); return g; }; template template template void ModulePart::type::Part_id::set(const T& geometry, Identifier id) { Part_base::set(geometry); setIdentifier(id); }; template template bool ModulePart::type::Part_id::hasGeometry3D(Identifier id) { typename Part_base::Geom g = Part_base::m_system->getGeometry3D(id); if(!g) return false; //get the global vertex and check if it is a child of the part cluster GlobalVertex v = g->template getProperty(); return Part_base::m_cluster->getLocalVertex(v).second; }; template template typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_id::getGeometry3D(Identifier id) { return Part_base::m_system->getGeometry3D(id); }; template template typename ModulePart::template type::Identifier& ModulePart::type::Part_id::getIdentifier() { return this->template getProperty >(); }; template template void ModulePart::type::Part_id::setIdentifier(Identifier id) { this->template setProperty >(id); }; template template template ModulePart::type::Part::Part(const T& geometry, Sys& system, boost::shared_ptr cluster) : mpl::if_, Part_base, Part_id>::type(geometry, system, cluster) { }; template template ModulePart::type::inheriter_base::inheriter_base() { m_this = ((Sys*) this); }; template template template typename ModulePart::template type::Partptr ModulePart::type::inheriter_base::createPart(const T& geometry) { typedef typename Sys::Cluster Cluster; std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); Partptr p(new Part(geometry, * ((Sys*) this), res.first)); m_this->m_cluster->template setObject (res.second, p); m_this->push_back(p); res.first->template setProperty(clusterPart); return p; }; template template void ModulePart::type::inheriter_base::removePart(Partptr p) { remover r(*m_this); m_this->m_cluster->removeCluster(p->m_cluster, r); p->template emitSignal(p); m_this->erase(p); }; template template ModulePart::type::inheriter_base::remover::remover(Sys& s) : system(s) { }; template template void ModulePart::type::inheriter_base::remover::operator()(GlobalVertex v) { Geom g = system.m_cluster->template getObject(v); if(g) { g->template emitSignal(g); system.erase(g); } Cons c = system.m_cluster->template getObject(v); if(c) { c->template emitSignal(c); system.erase(c); } }; template template void ModulePart::type::inheriter_base::remover::operator()(GlobalEdge e) { Cons c = system.m_cluster->template getObject(e); if(c) { c->template emitSignal(c); system.erase(c); } }; template template template typename ModulePart::template type::Partptr ModulePart::type::inheriter_id::createPart(const T& geometry, Identifier id) { Partptr p = inheriter_base::createPart(geometry); p->setIdentifier(id); return p; }; template template bool ModulePart::type::inheriter_id::hasPart(Identifier id) { if(getPart(id)) return true; return false; }; template template typename ModulePart::template type::Partptr ModulePart::type::inheriter_id::getPart(Identifier id) { std::vector< Partptr >& vec = inheriter_base::m_this->template objectVector(); typedef typename std::vector::iterator iter; for(iter it=vec.begin(); it!=vec.end(); it++) { if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; }; return Partptr(); }; template template ModulePart::type::PrepareCluster::PrepareCluster() { Job::priority = 1000; }; template template void ModulePart::type::PrepareCluster::execute(Sys& sys) { //get all parts and set their values to the cluster's typedef typename std::vector::iterator iter; for(iter it = sys.template begin(); it != sys.template end(); it++) { details::ClusterMath& cm = (*it)->m_cluster->template getProperty(); cm.getTransform() = (*it)->m_transform; }; }; template template ModulePart::type::EvaljuateCluster::EvaljuateCluster() { Job::priority = 1000; }; template template void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { //get all parts and set their values to the cluster's typedef typename std::vector::iterator iter; for(iter it = sys.template begin(); it != sys.template end(); it++) { details::ClusterMath& cm = (*it)->m_cluster->template getProperty(); (*it)->m_transform = cm.getTransform(); (*it)->finishCalculation(); }; }; } #endif //GCM_MODULEPART_H