From d4fdb92957e747228e28cf1e7a2205bec5a20c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 19 Dec 2013 06:55:41 +0100 Subject: [PATCH] new openDCM version --- src/Mod/Assembly/App/opendcm/core.hpp | 9 + .../App/opendcm/core/clustergraph.hpp | 1090 ++------------- .../Assembly/App/opendcm/core/constraint.hpp | 632 +-------- .../Assembly/App/opendcm/core/equations.hpp | 230 +--- .../Assembly/App/opendcm/core/geometry.hpp | 229 +--- .../App/opendcm/core/imp/clustergraph_imp.hpp | 1220 +++++++++++++++++ .../core/imp/constraint_holder_imp.hpp | 449 ++++++ .../App/opendcm/core/imp/constraint_imp.hpp | 208 +++ .../App/opendcm/core/imp/equations_imp.hpp | 255 ++++ .../App/opendcm/core/imp/geometry_imp.hpp | 266 ++++ .../App/opendcm/core/imp/kernel_imp.hpp | 512 +++++++ .../App/opendcm/core/imp/object_imp.hpp | 115 ++ .../App/opendcm/core/imp/system_imp.hpp | 257 ++++ .../opendcm/core/imp/transformation_imp.hpp | 303 ++++ src/Mod/Assembly/App/opendcm/core/kernel.hpp | 468 ++----- src/Mod/Assembly/App/opendcm/core/object.hpp | 85 +- .../Assembly/App/opendcm/core/property.hpp | 12 +- src/Mod/Assembly/App/opendcm/core/system.hpp | 253 ++-- src/Mod/Assembly/App/opendcm/core/traits.hpp | 37 +- .../App/opendcm/core/transformation.hpp | 222 +-- src/Mod/Assembly/App/opendcm/module3d.hpp | 31 +- .../App/opendcm/module3d/alignment.hpp | 2 +- .../App/opendcm/module3d/clustermath.hpp | 640 +-------- .../App/opendcm/module3d/coincident.hpp | 4 +- .../Assembly/App/opendcm/module3d/defines.hpp | 1 + .../App/opendcm/module3d/distance.hpp | 1 + .../opendcm/module3d/imp/clustermath_imp.hpp | 667 +++++++++ .../module3d/imp/constraint3d_holder_imp.hpp | 87 ++ .../opendcm/module3d/imp/constraint3d_imp.hpp | 119 ++ .../opendcm/module3d/imp/geometry3d_imp.hpp | 256 ++++ .../App/opendcm/module3d/imp/module_imp.hpp | 268 ++++ .../App/opendcm/module3d/imp/solver_imp.hpp | 410 ++++++ .../App/opendcm/module3d/imp/state_imp.hpp | 373 +++++ .../Assembly/App/opendcm/module3d/module.hpp | 541 +------- .../Assembly/App/opendcm/module3d/solver.hpp | 387 +----- .../Assembly/App/opendcm/module3d/state.hpp | 337 +---- .../App/opendcm/modulePart/module.hpp | 34 +- .../App/opendcm/moduleShape3d/module.hpp | 25 +- .../App/opendcm/moduleState/defines.hpp | 33 + .../moduleState/edge_vertex_generator.hpp | 4 +- .../moduleState/edge_vertex_parser.hpp | 7 +- .../App/opendcm/moduleState/extractor.hpp | 36 +- .../App/opendcm/moduleState/generator.hpp | 16 +- .../imp/edge_vertex_generator_imp.hpp | 58 + .../imp/edge_vertex_parser_imp.hpp | 55 + .../opendcm/moduleState/imp/generator_imp.hpp | 73 + .../opendcm/moduleState/imp/module_imp.hpp | 70 + .../moduleState/imp/object_generator_imp.hpp | 58 + .../moduleState/imp/object_parser_imp.hpp | 78 ++ .../opendcm/moduleState/imp/parser_imp.hpp | 77 ++ .../imp/property_generator_imp.hpp | 50 + .../moduleState/imp/property_parser_imp.hpp | 101 ++ .../opendcm/moduleState/imp/traits_impl.hpp | 185 +++ .../App/opendcm/moduleState/indent.hpp | 4 +- .../App/opendcm/moduleState/module.hpp | 44 +- .../opendcm/moduleState/object_generator.hpp | 4 +- .../App/opendcm/moduleState/object_parser.hpp | 25 +- .../App/opendcm/moduleState/parser.hpp | 18 +- .../moduleState/property_generator.hpp | 14 +- .../opendcm/moduleState/property_parser.hpp | 48 +- .../App/opendcm/moduleState/traits.hpp | 4 + src/Mod/Assembly/App/opendcm/modulestate.hpp | 51 + 62 files changed, 7298 insertions(+), 4850 deletions(-) create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/clustergraph_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/transformation_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/clustermath_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/constraint3d_holder_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/constraint3d_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/geometry3d_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/module_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/solver_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/state_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/edge_vertex_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/edge_vertex_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/module_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/object_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/object_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/property_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/property_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/traits_impl.hpp diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index f878620bdf..8808cf6f7d 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -43,5 +43,14 @@ #include "core/kernel.hpp" #include "core/system.hpp" + +#ifdef DCM_EXTERNAL_CORE + +#define DCM_EXTERNAL_CORE_INCLUDE_01 "opendcm/core/imp/system_imp.hpp" +#define DCM_EXTERNAL_CORE_01( Sys )\ + template class dcm::System; \ + +#endif //external + #endif //DCM_CORE_H diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index 44b6ac6bf2..4d4c000124 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -21,9 +21,6 @@ #define CLUSTERGRAPH_HPP #include -#include -#include -#include #include #include @@ -32,25 +29,16 @@ #include #include -#include -#include #include #include #include -#include -#include -#include #include #include #include -#include -#include #include "property.hpp" -#include -#include #include @@ -71,20 +59,6 @@ namespace details { /** @addtogroup Metafunctions * @{*/ -/** - * @brief Appends a mpl sequences to another - * - * Makes two sequence to one by appending all types of the first to the second sequence. The new - * mpl sequence can be accessed by the ::type typedef. - * Usage: @code vector_fold::type @endcode - * - * @tparam state the mpl sequence which will be expanded - * @tparam seq the mpl sequence which will be appended - **/ -template -struct vector_fold : mpl::fold < seq, state, - mpl::push_back > {}; - /** * @brief Creates a fusion::vector of boost shared_ptr's from the given types * @@ -106,8 +80,6 @@ struct sps { //shared_ptr sequence typedef mpl::vector1 bgl_v_props; typedef mpl::vector1 bgl_e_props; - - typedef boost::adjacency_list_traits list_traits; @@ -162,7 +134,7 @@ struct IDgen { /** * @brief Set the current value for incremental creation * - * ID's are created incrementaly and if a specific startingpoint is whised it can be set here by + * ID's are created incrementaly and if a specific startingpoint is wished it can be set here by * supplying the last created ID or the amount of totaly created ID's * * @param id The last created ID @@ -183,19 +155,6 @@ struct cluster_error : virtual boost::exception {}; **/ typedef boost::shared_ptr IDpointer; -/** @ingroup Functors - * @brief Functor to clear vertex or edge objects - * - * All objects are boost::shared_ptr, therefore they can be cleared by calling the reset() method. As - * objects are stored within fusion::sequences a functor is needed to clear all of them. - **/ -struct clear_ptr { - template - void operator()(T& t) const { - t.reset(); - }; -}; - } /** @name Descriptors */ @@ -345,21 +304,18 @@ public: typedef std::map > ClusterMap; -private: + struct global_extractor { typedef GlobalEdge& result_type; template - result_type operator()(T& bundle) const { - return fusion::at_c<1> (bundle); - }; + result_type operator()(T& bundle) const; }; + struct global_vertex_extractor { typedef GlobalVertex result_type; ClusterGraph& graph; - global_vertex_extractor(ClusterGraph& g) : graph(g) {}; - result_type operator()(LocalVertex& v) const { - return graph.getGlobalVertex(v); - }; + global_vertex_extractor(ClusterGraph& g); + result_type operator()(LocalVertex& v) const; }; template @@ -371,54 +327,10 @@ private: typedef typename mpl::distance::type, iterator>::type distance; BOOST_MPL_ASSERT((mpl::not_::type > >)); - result_type operator()(vertex_bundle& bundle) const { - return fusion::at (fusion::at_c<2> (bundle)); - }; - result_type operator()(edge_bundle_single& bundle) const { - return fusion::at (fusion::at_c<0> (bundle)); - }; + result_type operator()(vertex_bundle& bundle) const; + result_type operator()(edge_bundle_single& bundle) const; }; - template - struct property_extractor { - - typedef typename prop::type base_type; - typedef base_type& result_type; - - typedef typename mpl::if_< is_edge_property, edge_properties, vertex_properties >::type sequence; - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - typedef typename mpl::if_< is_edge_property, mpl::int_<0>, mpl::int_<1> >::type pos; - - template< typename seq> - result_type operator()(seq& b) const { - return fusion::at (fusion::at (b)); - }; - }; - - struct edge_copier { - edge_copier(const ClusterGraph& g1, ClusterGraph& g2) - : graph1(g1), graph2(g2) { } - - void operator()(LocalEdge e1, LocalEdge e2) const { - graph2[e2] = graph1[e1]; - } - const ClusterGraph& graph1; - ClusterGraph& graph2; - }; - - struct vertex_copier { - vertex_copier(const ClusterGraph& g1, ClusterGraph& g2) - : graph1(g1), graph2(g2) { } - - void operator()(LocalVertex v1, LocalVertex v2) const { - graph2[v2] = graph1[v1]; - } - const ClusterGraph& graph1; - ClusterGraph& graph2; - }; - -public: //iterators /** * @brief Iterator for global edge descriptors \ref GlobalEdge @@ -490,52 +402,7 @@ public: * copied graph */ template - void copyInto(boost::shared_ptr into, Functor& functor) const { - - //lists does not provide vertex index, so we have to build our own (cant use the internal - //vertex_index_property as we would need to reset the indices and that's not possible in const graph) - typedef std::map IndexMap; - IndexMap mapIndex; - boost::associative_property_map propmapIndex(mapIndex); - - std::pair vit = boost::vertices(*this); - - for(int c = 0; vit.first != vit.second; vit.first++, c++) - put(propmapIndex, *vit.first, c); - - //first copy all vertices and edges, but be aware that the objects in the new graph - //are also copys only and point to the old graph. there is a bug in older boost version - //(<1.5 i belive) that breaks vertex_all propety map for bundled properties, so we - //have to create our own copie functors - into->clear(); - vertex_copier vc(*this, *into); - edge_copier ec(*this, *into); - boost::copy_graph(*this, *into, boost::vertex_index_map(propmapIndex).vertex_copy(vc).edge_copy(ec)); - - //set the IDgen to the same value to avoid duplicate id's in the copied cluster - into->m_id->setCount(m_id->count()); - - //now that we have all vertices we can recreate the subclusters - std::pair it = clusters(); - - for(; it.first != it.second; it.first++) { - //create the new Graph - boost::shared_ptr ng = boost::shared_ptr (new ClusterGraph(into)); - - //we already have the new vertex, however, we need to find it - GlobalVertex gv = getGlobalVertex((*it.first).first); - LocalVertex lv = into->getLocalVertex(gv).first; - - //add the new graph to the subclustermap - into->m_clusters[lv] = ng; - - //copy the subcluster - (*it.first).second->copyInto(ng, functor); - } - - //lets see if the objects need special treatment - into->for_each_object(functor, false); - }; + void copyInto(boost::shared_ptr into, Functor& functor) const; /** * @brief Compare by adress, not by content @@ -543,9 +410,7 @@ public: * @return bool if this is the same cluster in memory **/ template - bool operator== (const T& other) const { - return this == &other; - }; + bool operator== (const T& other) const; /** * @brief Compare by adress, not by content @@ -553,9 +418,7 @@ public: * @return bool if this is the not same cluster in memory **/ template - bool operator!= (const T& other) const { - return !(this == &other); - }; + bool operator!= (const T& other) const; /** * @brief Set diffrent behaviour for changed markers @@ -566,9 +429,7 @@ public: * @param on Turn change markers on or of * @return void **/ - void setCopyMode(bool on) { - copy_mode = on; - }; + void setCopyMode(bool on); //Make sure the compiler finds the base class setters even with equal named functions in this class using PropertyOwner::getProperty; @@ -583,19 +444,14 @@ public: * @param v the local vertex which describes the subcluster **/ template - typename P::type& getSubclusterProperty(LocalVertex v) { - return getVertexCluster(v)->template getProperty

(); - }; + typename P::type& getSubclusterProperty(LocalVertex v); /** * @brief Mark if the cluster was changed * * @return void **/ - void setChanged() { - if(!copy_mode) - PropertyOwner::template setProperty (true); - }; + void setChanged(); /* ******************************************************* @@ -612,12 +468,7 @@ public: * * @return :pair< boost::shared_ptr< ClusterGraph >, LocalVertex > Subcluster and its descriptor **/ - std::pair, LocalVertex> createCluster() { - vertex_bundle vp; - fusion::at_c<0> (vp) = m_id->generate(); - LocalVertex v = boost::add_vertex(vp, *this); - return std::pair, LocalVertex> (m_clusters[v] = boost::shared_ptr (new ClusterGraph(sp_base::shared_from_this())), v); - }; + std::pair, LocalVertex> createCluster(); /** * @brief Returns the parent cluster @@ -627,45 +478,35 @@ public: * * @return :shared_ptr< ClusterGraph > the parent cluster or empty pointer **/ - inline boost::shared_ptr parent() { - return boost::shared_ptr (m_parent); - }; + boost::shared_ptr parent(); /** * @brief const version of \ref parent() * * @return :shared_ptr< ClusterGraph > **/ - inline const boost::shared_ptr parent() const { - return boost::shared_ptr (m_parent); - }; + const boost::shared_ptr parent() const; /** * @brief Is this the toplevel cluster? * * @return bool if it is **/ - bool isRoot() const { - return m_parent.expired(); - }; + bool isRoot() const; /** * @brief Returns the toplevel cluster * * @return :shared_ptr< ClusterGraph > **/ - boost::shared_ptr root() { - return isRoot() ? sp_base::shared_from_this() : parent()->root(); - }; + boost::shared_ptr root(); /** * @brief const equivalent of \ref root() * * @return :shared_ptr< ClusterGraph > **/ - const boost::shared_ptr root() const { - return isRoot() ? sp_base::shared_from_this() : parent()->root(); - }; + const boost::shared_ptr root() const; /** * @brief Iterators for all subclusters @@ -675,27 +516,21 @@ public: * * @return :pair< cluster_iterator, cluster_iterator > **/ - std::pair clusters() { - return std::make_pair(m_clusters.begin(), m_clusters.end()); - } + std::pair clusters(); /** * @brief const equivalent to \ref clusters() * * @return :pair< const_cluster_iterator, const_cluster_iterator > **/ - std::pair clusters() const { - return std::make_pair(m_clusters.begin(), m_clusters.end()); - } + std::pair clusters() const; /** * @brief The amount of all subclusters * * @return :size_t **/ - std::size_t numClusters() const { - return m_clusters.size(); - } + std::size_t numClusters() const; /** * @brief Check if this vertex is a cluster @@ -708,9 +543,7 @@ public: * @param v The vertex to be checked * @return bool is cluster or not **/ - bool isCluster(LocalVertex v) { - return (m_clusters.find(v) != m_clusters.end()); - }; + bool isCluster(const dcm::LocalVertex v) const; /** * @brief Get the cluster corresponding the discriptor @@ -723,13 +556,7 @@ public: * @param v The vertex for which the cluster is wanted * @return boost::shared_ptr the coresponding cluster orempty pointer **/ - boost::shared_ptr getVertexCluster(LocalVertex v) { - if(isCluster(v)) - return m_clusters[v]; - - //TODO:throw if not a cluster - return sp_base::shared_from_this(); - }; + boost::shared_ptr getVertexCluster(LocalVertex v); /** * @brief Get the vertex descrptor which descripes the clusters position in the graph @@ -739,40 +566,24 @@ public: * @param g the graph for which the vertex is searched * @return :LocalVertex **/ - LocalVertex getClusterVertex(boost::shared_ptr g) { - std::pair it = clusters(); - - for(; it.first != it.second; it.first++) { - if((*it.first).second == g) - return (*it.first).first; - } - - throw details::cluster_error() << boost::errinfo_errno(12) << error_message("Cluster is not part of this graph"); - }; + LocalVertex getClusterVertex(boost::shared_ptr g); /** * @brief Convinience function for \ref removeCluster **/ template - void removeCluster(boost::shared_ptr g, Functor& f) { - removeCluster(getClusterVertex(g), f); - }; + void removeCluster(boost::shared_ptr g, Functor& f); /** * @brief Convinience function for \ref removeCluster **/ - void removeCluster(boost::shared_ptr g) { - placehoder p; - removeCluster(getClusterVertex(g), p); - }; + void removeCluster(boost::shared_ptr g); /** * @brief Delete all subcluster * * @return void **/ - void clearClusters() { - m_clusters.clear(); - }; + void clearClusters(); /** * @brief Remove a subcluster and applys the functor to all removed edges and vertices @@ -786,58 +597,12 @@ public: * @param f Functor to apply on all graph elements */ template - void removeCluster(LocalVertex v, Functor& f) { - - typename ClusterMap::iterator it = m_clusters.find(v); - - if(it == m_clusters.end()) - throw details::cluster_error() << boost::errinfo_errno(11) << error_message("Cluster is not part of this graph"); - - std::pair > res = *it; - - //apply functor to all vertices and edges in the subclusters - f(res.second); - res.second->remove_vertices(f, true); - - //remove from map, delete subcluster and remove vertex - m_clusters.erase(v); - boost::clear_vertex(v, *this); //should not be needed, just to ensure it - boost::remove_vertex(v, *this); - }; - void removeCluster(LocalVertex v) { - placehoder p; - removeCluster(v, p); - }; + void removeCluster(LocalVertex v, Functor& f); + void removeCluster(LocalVertex v); protected: template - void remove_vertices(Functor& f, bool recursive = false) { - - std::pair vit = boost::vertices(*this); - - //we iterate forward before deleting to not invalidate our iterator - while(vit.first != vit.second) { - LocalVertex v = * (vit.first); - vit.first++; - - if(!isCluster(v)) { - //let the functor know we remove this vertex - f(getGlobalVertex(v)); - //need to do this to allow the removal of all relevant edges to this vertex, even upstream - removeVertex(v, f); - } - }; - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->remove_vertices(f, recursive); - } - } - }; - + void remove_vertices(Functor& f, bool recursive = false); /* ******************************************************* @@ -850,16 +615,20 @@ public: * * @return fusion::vector the local and global vertex descriptor **/ - fusion::vector addVertex() { - - vertex_bundle vp; - fusion::at_c<0> (vp) = m_id->generate(); - LocalVertex v = boost::add_vertex(vp, *this); - - setChanged(); - return fusion::make_vector(v, m_id->count()); - }; + fusion::vector addVertex(); + /** + * @brief Add a vertex to the local cluster with given global identifier + * + * Sometimes it is needed to add a vertex with given global identifier. As the global vertex can not + * be changed after creation, this method can be used to specify the global vertex by which this + * graph vertex can be identified. The given global vertex is not checked, you need to ensure that + * it is a unique id. The ID generator is changed so that it creates only identifier bigger than v. + * + * @return fusion::vector the local and global vertex descriptor + **/ + fusion::vector addVertex(GlobalVertex v); + /** * @brief Iterators of all global vertices in this cluster * @@ -868,13 +637,7 @@ public: * * @return std::pair< global_vertex_iterator, global_vertex_iterator > global vertex iterators **/ - std::pair globalVertices() { - std::pair res = boost::vertices(*this); - global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); - global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); - - return std::pair (begin, end); - }; + std::pair globalVertices(); /** * @brief Returns the edge between the local vertices @@ -886,9 +649,7 @@ public: * @return std::pair with the local edge descriptor if existing. The bool value shows if the * edge exists or not **/ - std::pair edge(LocalVertex source, LocalVertex target) { - return boost::edge(source, target, *this); - }; + std::pair edge(LocalVertex source, LocalVertex target); /** * @brief Add a edge between two vertices, defined by local descriptors. @@ -903,32 +664,7 @@ public: * @return fusion::vector with the local and global descriptors of the edge and an bool * value indicationg the successful creation. **/ - fusion::vector addEdge(LocalVertex source, LocalVertex target) { - - //manual edge creation with cluster is not allowed - if((source == target) || isCluster(source) || isCluster(target)) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false); - - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(source, target, *this); - - //if done=true the edge alredy existed - if(!done) - boost::tie(e, done) = boost::add_edge(source, target, *this); - - if(!done) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false); - - //init the bundle corecctly for new edge - GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; - edge_bundle_single s; - fusion::at_c<1> (s) = global; - fusion::at_c<1> ((*this) [e]).push_back(s); - - setChanged(); - return fusion::make_vector(e, global, true); - }; + fusion::vector addEdge(LocalVertex source, LocalVertex target); /** * @brief Add a edge between two vertices, defined by global descriptors. @@ -947,48 +683,9 @@ public: * one where it was added. Success indicates if the function was successful and scope shows the validy of the local * descriptor in this cluster (true means the edge is in this cluster). **/ - fusion::vector addEdge(GlobalVertex source, GlobalVertex target) { + fusion::vector addEdge(GlobalVertex source, GlobalVertex target); - LocalVertex v1, v2; - LocalEdge e; - bool d1, d2, d3; - boost::tie(v1, d1) = getContainingVertex(source); - boost::tie(v2, d2) = getContainingVertex(target); - - //if one vertex is not accessible from here this function fails - if(!(d1 && d2)) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); - - //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here - if(v1 == v2 && isCluster(v1)) { - fusion::vector res = getVertexCluster(v1)->addEdge(source, target); - fusion::at_c<3> (res) = false; - return res; - } - - //check if we already have that Local edge - boost::tie(e, d3) = boost::edge(v1, v2, *this); - - if(!d3) - boost::tie(e, d3) = boost::add_edge(v1, v2, *this); - - if(!d3) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); - - //init the bundle corectly for new edge - GlobalEdge global = { source, target, m_id->generate() }; - edge_bundle_single s; - fusion::at_c<1> (s) = global; - fusion::at_c<1> ((*this) [e]).push_back(s); - - setChanged(); - return fusion::make_vector(e, global, true, true); - - }; - - fusion::vector addEdgeGlobal(GlobalVertex source, GlobalVertex target) { - return addEdge(source, target); - }; + fusion::vector addEdgeGlobal(GlobalVertex source, GlobalVertex target); /** * @brief Get an iterator to all the global edges hold by this local edge @@ -1001,15 +698,7 @@ public: * @return std::pair with the global_edge_iterator's pointing to the vector's start * and end **/ - std::pair getGlobalEdges(LocalEdge e) { - - std::vector& vec = fusion::at_c<1> ((*this) [e]); - global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); - global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); - - setChanged(); - return std::pair (begin, end); - }; + std::pair getGlobalEdges(LocalEdge e); /** * @brief Get the count of all global edges @@ -1021,10 +710,7 @@ public: * @return std::pair with the global_edge_iterator's pointing to the vector's start * and end **/ - int getGlobalEdgeCount(LocalEdge e) { - - return fusion::at_c<1> ((*this) [e]).size(); - }; + int getGlobalEdgeCount(LocalEdge e); /** * @brief Get the local edge which holds the specified global edge. @@ -1036,9 +722,7 @@ public: * @param e GlobalEdge for which the containing local one is wanted * @return std:pair< LocalEdge, bool > with the containing LocalEdge and a bool indicator if function was successful. **/ - std::pair getLocalEdge(GlobalEdge e) { - return getContainingEdge(e); - }; + std::pair getLocalEdge(GlobalEdge e); /** * @brief Get the local edge which holds the specified global one and the subcluster in which it is valid. @@ -1049,9 +733,7 @@ public: * @param e GlobalEdge for which the containing local one is wanted * @return fusion::vector with the containing LocalEdge, the cluster which holds it and a bool indicator if function was successful. **/ - fusion::vector getLocalEdgeGraph(GlobalEdge e) { - return getContainingEdgeGraph(e); - }; + fusion::vector getLocalEdgeGraph(GlobalEdge e); /** * @brief Get the GlobalVertex assiociated with this local one. @@ -1059,24 +741,7 @@ public: * @param v LocalVertex * @return GlobalVertex **/ - GlobalVertex getGlobalVertex(LocalVertex v) const { - return fusion::at_c<0> ((*this) [v]); - }; - - /** - * @brief Set the GlobalVertex assiociated with this local one. - * - * Be carefull, LocalVertices get an global value assigned while created, override it only when your - * are sure that it is unique - * - * @param lv LocalVertex which sould get assigned the global one - * @param gv The value which the localVertex should get assigned - * @return GlobalVertex which was assigned - **/ - GlobalVertex setGlobalVertex(LocalVertex lv, GlobalVertex gv) { - fusion::at_c<0> ((*this) [lv]) = gv; - return gv; - }; + GlobalVertex getGlobalVertex(LocalVertex v) const; /** * @brief Get the LocalVertex which corresponds to the golab one @@ -1087,9 +752,7 @@ public: * @param vertex GlobalVertex for which the local one shall be returned * @return std::pair< LocalVertex, bool > The LocalVertex containing the global one and an success indicator **/ - std::pair getLocalVertex(GlobalVertex vertex) { - return getContainingVertex(vertex); - }; + std::pair getLocalVertex(GlobalVertex vertex); /** * @brief Get the local vertex which holds the specified global one and the subcluster in which it is valid. @@ -1100,9 +763,7 @@ public: * @param v GlobalVertex for which the containing local one is wanted * @return fusion::vector with the containing LocalVertex, the cluster which holds it and a bool indicator if function was successful. **/ - fusion::vector, bool> getLocalVertexGraph(GlobalVertex v) { - return getContainingVertexGraph(v); - }; + fusion::vector, bool> getLocalVertexGraph(GlobalVertex v); /* ******************************************************* @@ -1111,76 +772,9 @@ public: private: template - struct apply_remove_prediacte { - Functor& func; - GlobalVertex vert; - GlobalEdge edge; - bool isEdge; + void downstreamRemoveVertex(GlobalVertex v, Functor& f); - apply_remove_prediacte(Functor& f, GlobalVertex v) : func(f), vert(v), isEdge(false) {}; - apply_remove_prediacte(Functor& f, GlobalEdge e) : func(f), edge(e), vert(0), isEdge(true) {}; - bool operator()(edge_bundle_single& e) { - bool res; - - //this predicate can be used to compare the edge itself or the vertives it connects. See - //if we are a relevant edge - if(isEdge) - res = (edge == fusion::at_c<1> (e)); - else - res = (vert == fusion::at_c<1> (e).source) || (vert == fusion::at_c<1> (e).target); - - //we are a hit, invoke the functor. - if(res || vert < 0) - func(fusion::at_c<1> (e)); - - return res || vert < 0; - } - }; - - struct placehoder { - template - void operator()(T t) {}; - }; - - template - void downstreamRemoveVertex(GlobalVertex v, Functor& f) { - - std::pair res = getContainingVertex(v); - - //we don't throw, as this function gets invoked recursivly and it may happen that the - //vertex to remove is only in the top layers, not the button ones - if(!res.second) - return; - - - //iterate over every edge that connects to the global vertex or the cluster in which it is in - std::vector re; //remove edges - std::pair it = boost::out_edges(res.first, *this); - - for(; it.first != it.second; it.first++) { - std::vector& vec = fusion::at_c<1> ((*this) [* (it.first)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (f, v)), vec.end()); - - if(vec.empty()) - re.push_back(* (it.first)); - }; - - std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); - - //if we have the real vertex here and not only a containing cluster we can delete it - if(!isCluster(res.first)) { - boost::clear_vertex(res.first, *this); //just to make sure, should be done already - boost::remove_vertex(res.first, *this); - }; - - //lets go downstream - for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) - ((*it).second)->downstreamRemoveVertex(v, f); - }; - - void simpleRemoveEdge(LocalEdge e) { - boost::remove_edge(e, *this); - }; + void simpleRemoveEdge(LocalEdge e); public: @@ -1196,17 +790,9 @@ public: * @param f functor whose operator(GlobalEdge) is called for every removed edge **/ template - void removeVertex(LocalVertex id, Functor& f) { - //it is important to delete the global vertex, not the only local one as it's possible that - //we are in a subcluster and there are connections to the global vertex in the parent. They - //need to be deleted too. - removeVertex(getGlobalVertex(id), f); - }; + void removeVertex(LocalVertex id, Functor& f); //no default template arguments for template functions allowed before c++0x, so a little workaround - void removeVertex(LocalVertex id) { - placehoder p; - removeVertex(getGlobalVertex(id), p); - }; + void removeVertex(LocalVertex id) ; /** * @brief Removes a vertex from the cluster or it's subclusters and applys functor to removed edges @@ -1219,14 +805,9 @@ public: * @param f functor whose operator(LocalEdge) is called on every removed edge **/ template - void removeVertex(GlobalVertex id, Functor& f) { - root()->downstreamRemoveVertex(id, f); - }; + void removeVertex(GlobalVertex id, Functor& f); //no default template arguments for template functions allowed before c++0x, so a little workaround - void removeVertex(GlobalVertex id) { - placehoder p; - removeVertex(id, p); - }; + void removeVertex(GlobalVertex id); /** * @brief Removes a global Edge from the cluster or it's subclusters @@ -1237,19 +818,7 @@ public: * @param id Global Edge which should be removed from the graph * @return bool indicates if the global id could be removed **/ - void removeEdge(GlobalEdge id) { - fusion::vector res = getContainingEdgeGraph(id); - - if(!fusion::at_c<2> (res)) - return; //TODO:throw - - placehoder p; - std::vector& vec = fusion::at_c<1> ((*fusion::at_c<1> (res)) [fusion::at_c<0> (res)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (p, id)), vec.end()); - - if(vec.empty()) - boost::remove_edge(fusion::at_c<0> (res), *fusion::at_c<1> (res)); - }; + void removeEdge(GlobalEdge id); /** * @brief Removes a local edge from the cluster and calls the functor for all removed global edges @@ -1262,89 +831,12 @@ public: * @return bool indicates if the global id could be removed **/ template - void removeEdge(LocalEdge id, Functor& f) { - - std::vector& vec = fusion::at_c<1> ((*this) [id]); - std::for_each(vec.begin(), vec.end(), boost::bind (boost::ref(apply_remove_prediacte (f, -1)), _1)); - boost::remove_edge(id, *this); - }; + void removeEdge(LocalEdge id, Functor& f); /* ******************************************************* * Object Handling * *******************************************************/ - -protected: - //types needed to distinguish when objects need to be reset - struct get : public boost::false_type {}; - struct set : public boost::true_type {}; - - template - struct obj_helper { - - typedef typename object_extractor::result_type result_type; - - obj_helper(key k) : m_key(k) {}; - - //used with vertex bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - - if(Type::value) - fusion::for_each(fusion::at_c<2> (p), details::clear_ptr()); - - return object_extractor()(p); - } - - //used with edge bundle type and global edge descriptor - template - typename boost::enable_if < mpl::and_ < boost::is_same::type>, - boost::is_same > , result_type >::type operator()(bundle& p) { - - edge_single_iterator e; - //need to search the edge_bundle for the global descriptor - std::vector& ebsv = fusion::at_c<1> (p); - - for(edge_single_iterator it = ebsv.begin(); it != ebsv.end(); it++) { - if(global_extractor()(*it) == m_key) { - if(Type::value) - fusion::for_each(fusion::at_c<0> (*it), details::clear_ptr()); - - e = it; - break; - } - } - - return object_extractor()(*e); - } - - //used with edge bundle type and local edge descriptor - template - typename boost::enable_if < mpl::and_ < boost::is_same::type>, - boost::is_same > , result_type >::type operator()(bundle& p) { - if(Type::value) - fusion::for_each(fusion::at_c<0> (fusion::at_c<1> (p).front()), details::clear_ptr()); - - return object_extractor()(fusion::at_c<1> (p).front()); - } - - key m_key; - }; - - template - struct valid_ptr_apply { - - Functor& func; - valid_ptr_apply(Functor& f) : func(f) {}; - - template - void operator()(Ptr& p) const { - if(p) - func(p); - } - }; - public: /** @@ -1360,9 +852,7 @@ public: * @return shared_ptr< Obj > the pointer to the desired object **/ template - boost::shared_ptr getObject(key k) { - return apply_to_bundle(k, obj_helper (k)); - }; + boost::shared_ptr getObject(key k); /** * @brief Set a object at the specified vertex or edge @@ -1378,11 +868,7 @@ public: * @return void **/ template - void setObject(key k, boost::shared_ptr val) { - apply_to_bundle(k, obj_helper (k)) = val; - - setChanged(); - }; + void setObject(key k, boost::shared_ptr val); /** * @brief Get iterator range for all GlobalEdge objects hold by this local edge @@ -1395,13 +881,7 @@ public: * @return pair< begin, end > the iterator rang from begin (first element) to end (first undefined element) **/ template - std::pair< object_iterator, object_iterator > getObjects(LocalEdge k) { - - std::vector& vec = fusion::at_c<1> ((*this) [k]); - object_iterator begin(vec.begin(), object_extractor()); - object_iterator end(vec.end(), object_extractor()); - return std::pair< object_iterator, object_iterator > (begin, end); - }; + std::pair< object_iterator, object_iterator > getObjects(LocalEdge k); /** * @brief Applys the functor to each occurence of an object @@ -1416,37 +896,7 @@ public: * @param recursive specifies if the subclusters should be searched for objects too **/ template - void for_each(Functor& f, bool recursive = false) { - - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - boost::shared_ptr ptr = getObject (* (it.first)) ; - - if(ptr) - f(ptr); - } - - std::pair eit = boost::edges(*this); - - for(; eit.first != eit.second; eit.first++) { - std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects (* (eit.first)); - - for(; goit.first != goit.second; goit.first++) { - if(*goit.first) - f(*goit.first); - } - } - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->template for_each (f, recursive); - } - } - }; + void for_each(Functor& f, bool recursive = false); /** * @brief Applys the functor to each object @@ -1460,76 +910,12 @@ public: * @param recursive specifies if the subclusters should be searched for objects too **/ template - void for_each_object(Functor& f, bool recursive = false) { - - valid_ptr_apply func(f); - - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - typename details::sps::type& seq = fusion::at_c<2> ((*this) [*it.first]); - fusion::for_each(seq, func); - } - - typedef typename std::vector::iterator iter; - std::pair eit = boost::edges(*this); - - for(; eit.first != eit.second; eit.first++) { - std::vector& vec = fusion::at_c<1> ((*this) [*eit.first]); - - for(iter git = vec.begin(); git != vec.end(); git++) { - typename details::sps::type& seq = fusion::at_c<0> (*git); - fusion::for_each(seq, func); - } - } - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->for_each_object(f, recursive); - } - } - }; + void for_each_object(Functor& f, bool recursive = false); /* ******************************************************* * Property Handling * *******************************************************/ -protected: - - template - struct get_prop_helper { - - get_prop_helper(key k) : m_key(k) {}; - - typedef typename prop::type base_type; - typedef base_type& result_type; - typedef typename mpl::find::type vertex_iterator; - typedef typename mpl::find::type edge_iterator; - typedef typename mpl::if_ < boost::is_same::type >, - edge_iterator, vertex_iterator >::type iterator; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - - //used with vertex bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - return property_extractor()(p); - } - - //used with edge bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - return property_extractor()(p); - } - - key m_key; - }; - -public: /** * @brief Get the desired property at the specified vertex or edge * @@ -1542,9 +928,7 @@ public: * @return property::type& the reference to the desired property **/ template - typename property::type& getProperty(key k) { - return apply_to_bundle(k, get_prop_helper (k)); - }; + typename property::type& getProperty(key k); /** * @brief Set a property at the specified vertex or edge @@ -1559,11 +943,7 @@ public: * @return void **/ template - void setProperty(key k, typename property::type val) { - apply_to_bundle(k, get_prop_helper (k)) = val; - - setChanged(); - }; + void setProperty(key k, typename property::type val); /** * @brief recreate the internal index maps for edges and vertices @@ -1575,19 +955,7 @@ public: * * @return void **/ - void initIndexMaps() { - - //just iterate over all edges and vertices and give them all a unique index - std::pair vit = boost::vertices(*this); - - for(int c = 0; vit.first != vit.second; vit.first++, c++) - setProperty(*vit.first, c); - - std::pair eit = boost::edges(*this); - - for(int c = 0; eit.first != eit.second; eit.first++, c++) - setProperty(*eit.first, c); - }; + void initIndexMaps(); @@ -1605,11 +973,7 @@ public: * @param cg reference to the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, boost::shared_ptr cg) { - - LocalVertex cv = getClusterVertex(cg); - return moveToSubcluster(v, cv, cg); - }; + LocalVertex moveToSubcluster(LocalVertex v, boost::shared_ptr cg); /** * @brief Move a vertex to a subcluster @@ -1621,11 +985,7 @@ public: * @param Cluster the local vertex descriptor representing the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster) { - - boost::shared_ptr cg = getVertexCluster(Cluster); - return moveToSubcluster(v, Cluster, cg); - }; + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster); /** * @brief Move a vertex to a subcluster @@ -1642,88 +1002,7 @@ public: * @param cg reference to the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg) { - - std::pair it = boost::out_edges(v, *this); - - /* add the later removed edges to the coressponding existing edges - * (or create new edges between adjacent vertices of moved vertex and cluster). - * also get the edge between cluster and vertex while iterating */ - for(; it.first != it.second; it.first++) { - - LocalVertex target = boost::target(*it.first, *this); - - if(target != Cluster) { - - //get or create the edge between the old edge target and the cluster - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(target, Cluster, *this); - - if(!done) - boost::tie(e, done) = boost::add_edge(target, Cluster, *this); - - //if(!done) TODO: throw - - std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); - std::vector& nep = fusion::at_c<1> ((*this) [e]); - nep.insert(nep.end(), ep.begin(), ep.end()); - } - } - - /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster - * if a connection existed */ - LocalVertex nv = boost::add_vertex((*this) [v], *cg); - - //resort cluster parentship if needed - if(isCluster(v)) { - - cg->m_clusters[nv] = m_clusters[v]; - cg->m_clusters[nv]->m_parent = cg; - m_clusters.erase(v); - } - - std::pair moveedge = boost::edge(v, Cluster, *this); - - if(moveedge.second) { - std::vector& vec = fusion::at_c<1> ((*this) [moveedge.first]); - - for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { - - //get the global vertex to which the global edge points and find the local vertex holding this - //global one - GlobalEdge global = global_extractor()(*i); - GlobalVertex target; - //bit cumbersome to support moving clusters - target = (cg->getContainingVertex(global.source).first == nv) ? global.target : global.source; - std::pair res = cg->getContainingVertex(target); - //if(!res.second) TODO: throw - - //get or create the edge between the new vertex and the target - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(nv, res.first, *cg); - - if(!done) - boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); - - //if(!done) TODO: throw - - //push the global edge to the local edge - fusion::at_c<1> ((*cg) [e]).push_back(*i); - }; - } - - //all global edges concerning the move vertex are processed and it is moved to the subcluster, - //lets destroy it in the local cluster - boost::clear_vertex(v, *this); - boost::remove_vertex(v, *this); - - setChanged(); - cg->setChanged(); - - return nv; - }; + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg); /** @@ -1739,96 +1018,7 @@ public: * @param v Local vertex which should be moved to the parents cluster * @return LocalVertex the local descriptor of the moved vertex, valid in the parent cluster only. **/ - LocalVertex moveToParent(LocalVertex v) { - - //if(isRoot()) TODO:throw - - //create new vertex - vertex_bundle& vb = (*this) [v]; - LocalVertex nv = boost::add_vertex(vb, *parent()); - - //regrouping if needed - if(isCluster(v)) { - parent()->m_clusters[nv] = m_clusters[v]; - parent()->m_clusters[nv]->m_parent = m_parent; - m_clusters.erase(v); - } - - GlobalVertex gv = fusion::at_c<0> (vb); - - //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) - std::vector edge_vec; - LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); - std::pair it = boost::out_edges(this_v, *parent()); - - for(; it.first != it.second; it.first++) { - //iterate all global edges and find relevant ones - std::vector& vec = fusion::at_c<1> ((*parent()) [*it.first]); - edge_single_iterator i = vec.begin(); - - while(i != vec.end()) { - - GlobalEdge global = global_extractor()(*i); - GlobalVertex target; - - //a bit cumbersome to allow cluster moving - if(parent()->getContainingVertex(global.source).first == nv) - target = global.target; - else if(parent()->getContainingVertex(global.target).first == nv) - target = global.source; - else { - i++; - continue; - } - - std::pair res = parent()->getContainingVertex(target); - - //get or create the edge between the new vertex and the target - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(nv, res.first, *parent()); - - if(!done) - boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); - - //if(!done) TODO: throw - - //push the global edge bundle to the new local edge and erase it in the old - fusion::at_c<1> ((*parent()) [e]).push_back(*i); - i = vec.erase(i); - } - - //see if we should destroy this edge (no global edges remain in local one) - if(vec.empty()) - edge_vec.push_back(*it.first); - } - - //create a edge between new vertex and this cluster and add all global edges from within this cluster - it = boost::out_edges(v, *this); - LocalEdge e; - - if(it.first != it.second) - e = boost::add_edge(nv, this_v, *parent()).first; - - for(; it.first != it.second; it.first++) { - std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); - std::vector& nep = fusion::at_c<1> ((*parent()) [e]); - nep.insert(nep.end(), ep.begin(), ep.end()); - } - - //all global edges concerning the move vertex are processed and it is moved to the parent, - //lets destroy it in the local cluster - boost::clear_vertex(v, *this); - boost::remove_vertex(v, *this); - - //it's possible that some local edges in the parent are empty now, let's destroy them - for(std::vector::iterator it = edge_vec.begin(); it != edge_vec.end(); it++) - boost::remove_edge(*it, *parent()); - - setChanged(); - parent()->setChanged(); - return nv; - }; + LocalVertex moveToParent(LocalVertex v); /******************************************************** @@ -1837,6 +1027,7 @@ public: ClusterMap m_clusters; int test; + protected: boost::weak_ptr m_parent; details::IDpointer m_id; @@ -1849,140 +1040,35 @@ protected: * be seached too, however, if found there the retourned local vertex will be the vertex * representing the toplevel cluster holding the global vertex in the initial graph. * */ - std::pair getContainingVertex(GlobalVertex id, bool recursive = true) { - - //check all vertices if they are the id - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - if(id == fusion::at_c<0> ((*this) [*it.first])) - return std::make_pair(*it.first, true); - } - - //check all clusters if they have the id - if(recursive) { - for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { - std::pair res = ((*it).second)->getContainingVertex(id); - - if(res.second) - return std::make_pair((*it).first, true); - } - } - - return std::make_pair((LocalVertex) NULL, false); - }; + std::pair getContainingVertex(GlobalVertex id, bool recursive = true); /* Searches the local vertex holding the specified global one in this and all it's subclusters. * If found, the holding local vertex and the graph in which it is valid will be returned. * */ - fusion::vector, bool> getContainingVertexGraph(GlobalVertex id) { - - LocalVertex v; - bool done; - boost::tie(v, done) = getContainingVertex(id); - - if(!done) - return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); - - if(isCluster(v) && (getGlobalVertex(v) != id)) - return m_clusters[v]->getContainingVertexGraph(id); - else - return fusion::make_vector(v, sp_base::shared_from_this(), true); - }; + fusion::vector, bool> getContainingVertexGraph(GlobalVertex id); /* Searches the global edge in all local edges of this graph, and returns the local * one which holds the global edge. If not successfull the local edge returned will be * invalid and the bool parameter will be false. * */ - std::pair getContainingEdge(GlobalEdge id) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(id.source, true); - boost::tie(v2, d2) = getContainingVertex(id.target, true); - - if(!((d1 && d2) && (v1 != v2))) - return std::make_pair(LocalEdge(), false); - - return boost::edge(v1, v2, *this); - }; + std::pair getContainingEdge(GlobalEdge id); /* Searches the local edge holding the specified global one in this and all it's subclusters. * If found, the holding local edge and the graph in which it is valid will be returned. * */ - fusion::vector getContainingEdgeGraph(GlobalEdge id) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(id.source, true); - boost::tie(v2, d2) = getContainingVertex(id.target, true); - - if(!(d1 && d2)) - return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); - - if(v1 == v2) - return m_clusters[v1]->getContainingEdgeGraph(id); - - return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); - }; + fusion::vector getContainingEdgeGraph(GlobalEdge id); template - typename functor::result_type apply_to_bundle(LocalVertex k, functor f) { - return f((*this) [k]); - }; + typename functor::result_type apply_to_bundle(LocalVertex k, functor f); template - typename functor::result_type apply_to_bundle(LocalEdge k, functor f) { - return f((*this) [k]); - }; + typename functor::result_type apply_to_bundle(LocalEdge k, functor f); template - typename functor::result_type apply_to_bundle(GlobalVertex k, functor f) { - - //check all vertices if they are the id - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - vertex_bundle& p = (*this) [*it.first]; - - if(k == fusion::at_c<0> (p)) - return f(p); - } - - //check all clusters if they have the object - fusion::vector, bool> res = getContainingVertexGraph(k); - - if(!fusion::at_c<2> (res)) { - //TODO: Throw (propeties return reference, but cant init a reference temporarily) - } - - return fusion::at_c<1> (res)->template apply_to_bundle (k, f); - }; + typename functor::result_type apply_to_bundle(GlobalVertex k, functor f); template - typename functor::result_type apply_to_bundle(GlobalEdge k, functor f) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(k.source); - boost::tie(v2, d2) = getContainingVertex(k.target); - - if(!(d1 && d2)) { - //TODO:Throw - } - - if((v1 == v2) && isCluster(v1)) - return m_clusters[v1]->apply_to_bundle(k, f); - else { - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(v1, v2, *this); - //if(!done) TODO: throw, as there has to be a edge! - return f((*this) [e]); - }; - - - }; + typename functor::result_type apply_to_bundle(GlobalEdge k, functor f); public: //may hold cluster properties which have Eigen3 objects and therefore need alignment @@ -1995,6 +1081,10 @@ public: } //namespace dcm +#ifndef DCM_EXTERNAL_CORE +#include "imp/clustergraph_imp.hpp" +#endif + #endif // CLUSTERGRAPH_HPP diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index b4b857ff9c..a1e5bd9fe3 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -24,9 +24,6 @@ #include #include -#include -#include -#include #include #include @@ -36,13 +33,7 @@ #include #include - #include -#include -#include -#include -#include -#include #include @@ -61,8 +52,8 @@ namespace detail { //metafunction to avoid ot-of-range access of mpl sequences template struct in_range_value { - typedef typename mpl::prior >::type last_id; - typedef typename mpl::min< mpl::int_, last_id>::type type; + typedef typename mpl::prior >::type last_id; + typedef typename mpl::min< mpl::int_, last_id>::type type; }; //type erasure container for constraints @@ -119,22 +110,10 @@ protected: inline void intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_); - int equationCount(); - - template< typename creator_type> - void resetType(creator_type& c); - + int equationCount(); void calculate(Scalar scale, bool rotation_only = false); void treatLGZ(); - void setMaps(MES& mes); - - void geometryReset(geom_ptr g) { - /* placeholder* p = content->resetConstraint(first, second); - delete content; - content = p;*/ - }; - void collectPseudoPoints(Vec& vec1, Vec& vec2); //Equation is the constraint with types, the EquationSet hold all needed Maps for calculation @@ -174,9 +153,13 @@ protected: int value; public: - template< typename ConstraintVector, typename EquationVector> + template< typename ConstraintVector, typename tag1, typename tag2> struct holder : public placeholder { + //transform the constraints into eqautions with the now known types + typedef typename mpl::fold< ConstraintVector, mpl::vector<>, + mpl::push_back > >::type EquationVector; + //create a vector of EquationSets with some mpl trickery typedef typename mpl::fold< EquationVector, mpl::vector<>, mpl::push_back > >::type eq_set_vector; @@ -309,9 +292,7 @@ public: virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); virtual placeholder* clone(); virtual int equationCount(); - virtual void disable() { - fusion::for_each(m_sets, disabler()); - }; + virtual void disable(); virtual std::vector getGenericEquations(); virtual std::vector getGenericConstraints(); @@ -330,599 +311,14 @@ public: geom_ptr first, second; }; - -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ - - -template -Constraint::Constraint(geom_ptr f, geom_ptr s) - : first(f), second(s), content(0) { - - //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); - //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); -}; - -template -Constraint::~Constraint() { - delete content; - //first->template disconnectSignal(cf); - //second->template disconnectSignal(cs); -}; - -template -template -void Constraint::initializeFromTags(ConstraintVector& v) { - - typedef tag_order< tag1, tag2 > order; - - //transform the constraints into eqautions with the now known types - typedef typename mpl::fold< ConstraintVector, mpl::vector<>, - mpl::push_back > >::type EquationVector; - - //and build the placeholder - content = new holder(v); - - //geometry order needs to be the one needed by equations - if(order::swapt::value) - first.swap(second); -}; - -template -template -void Constraint::initialize(ConstraintVector& cv) { - - //use the compile time unrolling to retrieve the geometry tags - initializeFirstGeometry >(cv, mpl::true_()); -}; - -template -int Constraint::equationCount() { - return content->equationCount(); -}; - -template -template< typename creator_type> -void Constraint::resetType(creator_type& c) { - boost::apply_visitor(c, first->m_geometry, second->m_geometry); - content = c.p; - if(c.need_swap) - first.swap(second); -}; - -template -void Constraint::calculate(Scalar scale, bool rotation_only) { - content->calculate(first, second, scale, rotation_only); -}; - -template -void Constraint::treatLGZ() { - content->treatLGZ(first, second); -}; - -template -void Constraint::setMaps(MES& mes) { - content->setMaps(mes, first, second); -}; - -template -void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { - content->collectPseudoPoints(first, second, vec1, vec2); -}; - -template -std::vector Constraint::getGenericEquations() { - return content->getGenericEquations(); -}; - -template -std::vector Constraint::getGenericConstraints() { - return content->getGenericConstraints(); -}; - -template -std::vector Constraint::getEquationTypes() { - return content->getEquationTypes(); -}; - -template -std::vector Constraint::getConstraintTypes() { - return content->getConstraintTypes(); -}; - -template -template -Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; - -template -template -template -typename boost::enable_if::template holder::template has_option::type, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { - - //get the index of the corresbonding equation - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - fusion::copy(fusion::at(objects).values, val.m_eq.values); - val.pure_rotation = fusion::at(objects).pure_rotation; -}; - -template -template -template -typename boost::enable_if::template holder::template has_option::type>, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { - -}; - -template -template -Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) - : first(f), second(s), scale(sc), rot_only(rotation_only) { - -}; - -template -template -template< typename T > -void Constraint::holder::Calculater::operator()(T& val) const { - - //if the equation is disabled we don't have anything mapped so avoid accessing it - if(!val.enabled) - return; - - //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 - if(rot_only && !val.pure_rotation) { - - val.m_residual(0) = 0; - if(first->getClusterMode()) { - if(!first->isClusterFixed()) { - val.m_diff_first_rot.setZero(); - val.m_diff_first.setZero(); - } - } - else - val.m_diff_first.setZero(); - - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - val.m_diff_second_rot.setZero(); - val.m_diff_second.setZero(); - } - } - else - val.m_diff_second.setZero(); - - } - //we need to calculate, so lets go for it! - else { - - val.m_eq.setScale(scale); - - val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); - - //now see which way we should calculate the gradient (may be diffrent for both geometries) - if(first->m_parameterCount) { - if(first->getClusterMode()) { - //when the cluster is fixed no maps are set as no parameters exist. - if(!first->isClusterFixed()) { - - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<3; i++) { - val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, first->m_diffparam.col(i)); - } - //and now with the translations - for(int i=0; i<3; i++) { - val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, first->m_diffparam.col(i+3)); - } - } - } - else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); - } - } - if(second->m_parameterCount) { - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<3; i++) { - val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, second->m_diffparam.col(i)); - } - //and the translation seperated - for(int i=0; i<3; i++) { - val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, second->m_diffparam.col(i+3)); - } - } - } - else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); - } - } - } -}; - -template -template -Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) - : mes(m), first(f), second(s) { - -}; - -template -template -template< typename T > -void Constraint::holder::MapSetter::operator()(T& val) const { - - if(!val.enabled) - return; - - //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat - //for every parameter in the geometry; - int equation = mes.setResidualMap(val.m_residual); - if(first->getClusterMode()) { - if(!first->isClusterFixed()) { - mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot); - mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); - } - } - else - mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); - - - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - mes.setJacobiMap(equation, second->m_offset_rot, 3, val.m_diff_second_rot); - mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); - } - } - else - mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); -}; - -template -template -Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) - : first(f), second(s), points1(vec1), points2(vec2) { - -}; - -template -template -template< typename T > -void Constraint::holder::PseudoCollector::operator()(T& val) const { - - if(!val.enabled) - return; - - if(first->m_isInCluster && second->m_isInCluster) { - val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); - } - else - if(first->m_isInCluster) { - typename Kernel::Vector sec = second->m_parameter; - val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); - } - else - if(second->m_isInCluster) { - typename Kernel::Vector fir = first->m_parameter; - val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); - } -}; - -template -template -Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) - : first(f), second(s) { - -}; - -template -template -template< typename T > -void Constraint::holder::LGZ::operator()(T& val) const { - - typedef typename Sys::Kernel Kernel; - - if(!val.enabled) - return; - - //to treat local gradient zeros we calculate a approximate second derivative of the equations - //only do that if neseccary: residual is not zero - if(!Kernel::isSame(val.m_residual(0),0, 1e-7)) { //TODO: use exact precission and scale value - - //rotations exist only in cluster - if(first->getClusterMode() && !first->isClusterFixed()) { - //LGZ exists for rotations only - for(int i=0; i<3; i++) { - - //only treat if the gradient realy is zero - if(Kernel::isSame(val.m_diff_first_rot(i), 0, 1e-7)) { - - //to get the approximated second derivative we need the slightly moved geometrie - const typename Kernel::Vector p_old = first->m_parameter; - first->m_parameter += first->m_diffparam.col(i)*1e-3; - first->normalize(); - //with this changed geometrie we test if a gradient exist now - typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); - first->m_parameter = p_old; - - //let's see if the initial LGZ was a real one - if(!Kernel::isSame(res, 0, 1e-7)) { - - //is a fake zero, let's correct it - val.m_diff_first_rot(i) = res; - }; - }; - }; - } - //and the same for the second one too - if(second->getClusterMode() && !second->isClusterFixed()) { - - for(int i=0; i<3; i++) { - - //only treat if the gradient realy is zero - if(Kernel::isSame(val.m_diff_second_rot(i), 0, 1e-7)) { - - //to get the approximated second derivative we need the slightly moved geometrie - const typename Kernel::Vector p_old = second->m_parameter; - second->m_parameter += second->m_diffparam.col(i)*1e-3; - second->normalize(); - //with this changed geometrie we test if a gradient exist now - typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); - second->m_parameter = p_old; - - //let's see if the initial LGZ was a real one - if(!Kernel::isSame(res, 0, 1e-7)) { - - //is a fake zero, let's correct it - val.m_diff_second_rot(i) = res; - }; - }; - }; - }; - }; -}; - -template -template -Constraint::holder::GenericEquations::GenericEquations(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::GenericEquations::operator()(T& val) const { - vec.push_back(val.m_eq); -}; - -template -template -Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::GenericConstraints::operator()(T& val) const { - vec.push_back(val); -}; - -template -template -Constraint::holder::Types::Types(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::Types::operator()(T& val) const { - vec.push_back(&typeid(T)); -}; - -template -template -Constraint::holder::holder(Objects& obj) : m_objects(obj) { - //set the initial values in the equations - fusion::for_each(m_sets, OptionSetter(obj)); -}; - -template -template -void Constraint::holder::calculate(geom_ptr first, geom_ptr second, - Scalar scale, bool rotation_only) { - fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); -}; - -template -template -void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { - fusion::for_each(m_sets, LGZ(first, second)); -}; - -template -template -typename Constraint::placeholder* -Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { - //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); - //if(creator.need_swap) first.swap(second); - return NULL; -}; - -template -template -void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { - fusion::for_each(m_sets, MapSetter(mes, first, second)); -}; - -template -template -void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { - fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); -}; - -template -template -typename Constraint::placeholder* -Constraint::holder::clone() { - return new holder(*this); -}; - -template -template -int Constraint::holder::equationCount() { - int count = 0; - EquationCounter counter(count); - fusion::for_each(m_sets, counter); - return count; -}; - -template -template -std::vector -Constraint::holder::getGenericEquations() { - std::vector vec; - fusion::for_each(m_sets, GenericEquations(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getGenericConstraints() { - std::vector vec; - fusion::for_each(m_objects, GenericConstraints(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getEquationTypes() { - std::vector vec; - mpl::for_each< EquationVector >(Types(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getConstraintTypes() { - std::vector vec; - mpl::for_each< ConstraintVector >(Types(vec)); - return vec; -}; - -/****************************************************************/ -/** compiletime unrolled geometry initialising */ -/****************************************************************/ - -template -template -void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { - //this function is only for breaking the compilation loop, it should never be called - BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist -}; - -template -template -void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { - - typedef typename Sys::geometries geometries; - - switch(first->getExactType()) { - -#ifdef BOOST_PP_LOCAL_ITERATE -#define BOOST_PP_LOCAL_MACRO(n) \ - case (WhichType::value + n): \ - return initializeSecondGeometry,\ - typename mpl::at::type >::type,\ - ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ - break; -#define BOOST_PP_LOCAL_LIMITS (0, 10) -#include BOOST_PP_LOCAL_ITERATE() -#endif //BOOST_PP_LOCAL_ITERATE - default: - typedef typename mpl::int_ next_which_t; - return initializeFirstGeometry (cv, - typename mpl::less< next_which_t, typename mpl::size::type >::type()); - } -}; - -template -template -void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { - //this function is only for breaking the compilation loop, it should never be called - BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist -}; - -template -template -void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { - - typedef typename Sys::geometries geometries; - switch(second->getExactType()) { - -#ifdef BOOST_PP_LOCAL_ITERATE -#define BOOST_PP_LOCAL_MACRO(n) \ - case (WhichType::value + n): \ - return intitalizeFinalize::type >::type,\ - ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ - break; -#define BOOST_PP_LOCAL_LIMITS (0, 10) -#include BOOST_PP_LOCAL_ITERATE() -#endif //BOOST_PP_LOCAL_ITERATE - default: - typedef typename mpl::int_ next_which_t; - return initializeSecondGeometry - (cv, typename mpl::less - < next_which_t - , typename mpl::size::type>::type() - ); - } -}; - -template -template -inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_ /*is_unrolled_t*/) { - - initializeFromTags(cv); -}; - -template -template -inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_ /*is_unrolled_t*/) { - //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds - BOOST_ASSERT(false); -} - - - };//detail - };//dcm +#ifndef DCM_EXTERNAL_CORE +#include "imp/constraint_imp.hpp" +#include "imp/constraint_holder_imp.hpp" +#endif + #endif //GCM_CONSTRAINT_H diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index bc34e6d45f..6ef1b8be2c 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -25,21 +25,13 @@ #include #include #include -#include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include +#include #include - #include namespace fusion = boost::fusion; @@ -82,8 +74,8 @@ struct PseudoScale { //type to allow a metaprogramming check for a Equation struct EQ {}; -template -struct pushed_seq; +//template +//struct pushed_seq; //metafunctions to retrieve the options of an equation template @@ -112,66 +104,17 @@ struct constraint_sequence : public seq { std::cout<<"pretty: "<<__PRETTY_FUNCTION__< - typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T& val) { - - typedef typename pushed_seq::type Sequence; - typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::find::S1>::type >::type EndOld; - - - //create the new sequence - Sequence vec; - - //copy the old values into the new sequence - Begin b(vec); - EndOld eo(vec); - - fusion::iterator_range range(b, eo); - fusion::copy(*this, range); - - //insert this object at the end of the sequence - *fusion::find(vec) = val; - - //and return our new extendet sequence - return vec; - }; - - //an sequence gets added to this sequence (happens only if sequenced equations like coincident are used) - template - typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T& val) { - - typedef typename pushed_seq::type Sequence; - typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::find::S1>::type >::type EndF; - - //create the new sequence - Sequence vec; - - Begin b(vec); - EndF ef(vec); - - fusion::iterator_range range(b, ef); - fusion::copy(val, range); - - //to copy the types of the second sequence is not as easy as before. If types were already present in - //the original sequence they are not added again. therefore we need to find all types of the second sequence - //in the new one and assign the objects to this positions. - - //get a index vector for all second-sequence-elements - typedef typename mpl::transform::S2, - fusion::result_of::distance::type, - fusion::result_of::find > >::type position_vector; - - //and copy the types in - fusion::nview view(vec); - fusion::copy(*this, view); - - //and return our new extendet sequence - return vec; - }; + //dont allow expression equation stacking: the compile time impact is huge if we want to allow + //text parsing + /* + //an equation gets added to this sequence + template + typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T& val); + //an sequence gets added to this sequence (happens only if sequenced equations like coincident are used) + template + typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T& val); + */ //we also allow to set values directly into the equation, as this makes it more compftable for multi constraints //as align. Note that this only works if all option types of all equations in this sequence are distinguishable template @@ -182,6 +125,13 @@ struct constraint_sequence : public seq { fusion::front(view) = val; return *this; }; + +}; + +/* +template +struct get_equation_id { + typedef typename T::ID type; }; template @@ -191,12 +141,13 @@ struct pushed_seq { typedef typename mpl::fold< S2, S1, mpl::if_< boost::is_same< mpl::find, mpl::end >, mpl::push_back, mpl::_1> >::type unique_vector; + typedef typename mpl::sort, get_equation_id > >::type sorted_vector; - typedef typename fusion::result_of::as_vector< unique_vector >::type vec; + typedef typename fusion::result_of::as_vector< sorted_vector >::type vec; typedef constraint_sequence type; -}; +};*/ -template +template struct Equation : public EQ { typedef typename mpl::if_, Option, mpl::vector

(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::setChanged() { + if(!copy_mode) + PropertyOwner::template setProperty (true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair >, LocalVertex> ClusterGraph::createCluster() { + vertex_bundle vp; + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); + return std::pair, LocalVertex> (m_clusters[v] = boost::shared_ptr (new ClusterGraph(sp_base::shared_from_this())), v); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +inline boost::shared_ptr< ClusterGraph > +ClusterGraph:: parent() { + return boost::shared_ptr (m_parent); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +inline const boost::shared_ptr< ClusterGraph > +ClusterGraph::parent() const { + return boost::shared_ptr (m_parent); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +bool ClusterGraph::isRoot() const { + return m_parent.expired(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +boost::shared_ptr< ClusterGraph > +ClusterGraph::root() { + return isRoot() ? sp_base::shared_from_this() : parent()->root(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +const boost::shared_ptr< ClusterGraph > +ClusterGraph::root() const { + return isRoot() ? sp_base::shared_from_this() : parent()->root(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::cluster_iterator, typename ClusterGraph::cluster_iterator> +ClusterGraph::clusters() { + return std::make_pair(m_clusters.begin(), m_clusters.end()); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::const_cluster_iterator, typename ClusterGraph::const_cluster_iterator> +ClusterGraph::clusters() const { + return std::make_pair(m_clusters.begin(), m_clusters.end()); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::size_t +ClusterGraph::numClusters() const { + return m_clusters.size(); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +bool ClusterGraph::isCluster(const LocalVertex v) const { + return (m_clusters.find(v) != m_clusters.end()); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +boost::shared_ptr< ClusterGraph > +ClusterGraph::getVertexCluster(LocalVertex v) { + if(isCluster(v)) + return m_clusters[v]; + + //TODO:throw if not a cluster + return sp_base::shared_from_this(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex ClusterGraph::getClusterVertex(boost::shared_ptr g) { + std::pair it = clusters(); + + for(; it.first != it.second; it.first++) { + if((*it.first).second == g) + return (*it.first).first; + } + + throw details::cluster_error() << boost::errinfo_errno(12) << error_message("Cluster is not part of this graph"); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeCluster(boost::shared_ptr g, Functor& f) { + removeCluster(getClusterVertex(g), f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeCluster(boost::shared_ptr g) { + placehoder p; + removeCluster(getClusterVertex(g), p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::clearClusters() { + m_clusters.clear(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeCluster(LocalVertex v, Functor& f) { + + typename ClusterMap::iterator it = m_clusters.find(v); + + if(it == m_clusters.end()) + throw details::cluster_error() << boost::errinfo_errno(11) << error_message("Cluster is not part of this graph"); + + std::pair > res = *it; + + //apply functor to all vertices and edges in the subclusters + f(res.second); + res.second->remove_vertices(f, true); + + //remove from map, delete subcluster and remove vertex + m_clusters.erase(v); + boost::clear_vertex(v, *this); //should not be needed, just to ensure it + boost::remove_vertex(v, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeCluster(LocalVertex v) { + placehoder p; + removeCluster(v, p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::remove_vertices(Functor& f, bool recursive) { + + std::pair vit = boost::vertices(*this); + + //we iterate forward before deleting to not invalidate our iterator + while(vit.first != vit.second) { + LocalVertex v = * (vit.first); + vit.first++; + + if(!isCluster(v)) { + //let the functor know we remove this vertex + f(getGlobalVertex(v)); + //need to do this to allow the removal of all relevant edges to this vertex, even upstream + removeVertex(v, f); + } + }; + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->remove_vertices(f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addVertex() { + + vertex_bundle vp; + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); + + setChanged(); + return fusion::make_vector(v, m_id->count()); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addVertex(GlobalVertex gv) { + + vertex_bundle vp; + fusion::at_c<0> (vp) = gv; + LocalVertex v = boost::add_vertex(vp, *this); + + //ensure that we never create this id, as it is used now + if(gv > m_id->count()) + m_id->setCount(gv); + + setChanged(); + return fusion::make_vector(v, gv); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::global_vertex_iterator, typename ClusterGraph::global_vertex_iterator> +ClusterGraph::globalVertices() { + std::pair res = boost::vertices(*this); + global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); + global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); + + return std::pair (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::edge(LocalVertex source, LocalVertex target) { + return boost::edge(source, target, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdge(LocalVertex source, LocalVertex target) { + + //manual edge creation with cluster is not allowed + if((source == target) || isCluster(source) || isCluster(target)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(source, target, *this); + + //if done=true the edge alredy existed + if(!done) + boost::tie(e, done) = boost::add_edge(source, target, *this); + + if(!done) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + //init the bundle corecctly for new edge + GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdge(GlobalVertex source, GlobalVertex target) { + + LocalVertex v1, v2; + LocalEdge e; + bool d1, d2, d3; + boost::tie(v1, d1) = getContainingVertex(source); + boost::tie(v2, d2) = getContainingVertex(target); + + //if one vertex is not accessible from here this function fails + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here + if(v1 == v2 && isCluster(v1)) { + fusion::vector res = getVertexCluster(v1)->addEdge(source, target); + fusion::at_c<3> (res) = false; + return res; + } + + //check if we already have that Local edge + boost::tie(e, d3) = boost::edge(v1, v2, *this); + + if(!d3) + boost::tie(e, d3) = boost::add_edge(v1, v2, *this); + + if(!d3) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //init the bundle corectly for new edge + GlobalEdge global = { source, target, m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true, true); + +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdgeGlobal(GlobalVertex source, GlobalVertex target) { + return addEdge(source, target); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::global_edge_iterator, typename ClusterGraph::global_edge_iterator> +ClusterGraph::getGlobalEdges(LocalEdge e) { + + std::vector& vec = fusion::at_c<1> ((*this) [e]); + global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); + global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); + + setChanged(); + return std::pair (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +int ClusterGraph::getGlobalEdgeCount(LocalEdge e) { + + return fusion::at_c<1> ((*this) [e]).size(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getLocalEdge(GlobalEdge e) { + return getContainingEdge(e); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector*, bool> +ClusterGraph::getLocalEdgeGraph(GlobalEdge e) { + return getContainingEdgeGraph(e); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +GlobalVertex +ClusterGraph::getGlobalVertex(LocalVertex v) const { + return fusion::at_c<0> ((*this) [v]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getLocalVertex(GlobalVertex vertex) { + return getContainingVertex(vertex); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector >, bool> +ClusterGraph::getLocalVertexGraph(GlobalVertex v) { + return getContainingVertexGraph(v); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::downstreamRemoveVertex(GlobalVertex v, Functor& f) { + + std::pair res = getContainingVertex(v); + + //we don't throw, as this function gets invoked recursivly and it may happen that the + //vertex to remove is only in the top layers, not the button ones + if(!res.second) + return; + + + //iterate over every edge that connects to the global vertex or the cluster in which it is in + std::vector re; //remove edges + std::pair it = boost::out_edges(res.first, *this); + + for(; it.first != it.second; it.first++) { + std::vector& vec = fusion::at_c<1> ((*this) [* (it.first)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (f, v)), vec.end()); + + if(vec.empty()) + re.push_back(* (it.first)); + }; + + std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); + + //if we have the real vertex here and not only a containing cluster we can delete it + if(!isCluster(res.first)) { + boost::clear_vertex(res.first, *this); //just to make sure, should be done already + boost::remove_vertex(res.first, *this); + }; + + //lets go downstream + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) + ((*it).second)->downstreamRemoveVertex(v, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::simpleRemoveEdge(LocalEdge e) { + boost::remove_edge(e, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeVertex(LocalVertex id, Functor& f) { + //it is important to delete the global vertex, not the only local one as it's possible that + //we are in a subcluster and there are connections to the global vertex in the parent. They + //need to be deleted too. + removeVertex(getGlobalVertex(id), f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeVertex(LocalVertex id) { + placehoder p; + removeVertex(getGlobalVertex(id), p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeVertex(GlobalVertex id, Functor& f) { + root()->downstreamRemoveVertex(id, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeVertex(GlobalVertex id) { + placehoder p; + removeVertex(id, p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeEdge(GlobalEdge id) { + fusion::vector res = getContainingEdgeGraph(id); + + if(!fusion::at_c<2> (res)) + return; //TODO:throw + + placehoder p; + std::vector& vec = fusion::at_c<1> ((*fusion::at_c<1> (res)) [fusion::at_c<0> (res)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (p, id)), vec.end()); + + if(vec.empty()) + boost::remove_edge(fusion::at_c<0> (res), *fusion::at_c<1> (res)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeEdge(LocalEdge id, Functor& f) { + + std::vector& vec = fusion::at_c<1> ((*this) [id]); + std::for_each(vec.begin(), vec.end(), boost::bind (boost::ref(apply_remove_prediacte (f, -1)), _1)); + boost::remove_edge(id, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +boost::shared_ptr +ClusterGraph::getObject(key k) { + return apply_to_bundle(k, obj_helper (k)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::setObject(key k, boost::shared_ptr val) { + apply_to_bundle(k, obj_helper (k)) = val; + + setChanged(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +std::pair< typename ClusterGraph::template object_iterator, typename ClusterGraph::template object_iterator > +ClusterGraph::getObjects(LocalEdge k) { + + std::vector& vec = fusion::at_c<1> ((*this) [k]); + object_iterator begin(vec.begin(), object_extractor()); + object_iterator end(vec.end(), object_extractor()); + return std::pair< object_iterator, object_iterator > (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::for_each(Functor& f, bool recursive) { + + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + boost::shared_ptr ptr = getObject (* (it.first)) ; + + if(ptr) + f(ptr); + } + + std::pair eit = boost::edges(*this); + + for(; eit.first != eit.second; eit.first++) { + std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects (* (eit.first)); + + for(; goit.first != goit.second; goit.first++) { + if(*goit.first) + f(*goit.first); + } + } + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->template for_each (f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::for_each_object(Functor& f, bool recursive) { + + valid_ptr_apply func(f); + + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + typename details::sps::type& seq = fusion::at_c<2> ((*this) [*it.first]); + fusion::for_each(seq, func); + } + + typedef typename std::vector::iterator iter; + std::pair eit = boost::edges(*this); + + for(; eit.first != eit.second; eit.first++) { + std::vector& vec = fusion::at_c<1> ((*this) [*eit.first]); + + for(iter git = vec.begin(); git != vec.end(); git++) { + typename details::sps::type& seq = fusion::at_c<0> (*git); + fusion::for_each(seq, func); + } + } + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->for_each_object(f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename property::type& +ClusterGraph::getProperty(key k) { + return apply_to_bundle(k, get_prop_helper (k)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::setProperty(key k, typename property::type val) { + apply_to_bundle(k, get_prop_helper (k)) = val; + + setChanged(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::initIndexMaps() { + + //just iterate over all edges and vertices and give them all a unique index + std::pair vit = boost::vertices(*this); + + for(int c = 0; vit.first != vit.second; vit.first++, c++) + setProperty(*vit.first, c); + + std::pair eit = boost::edges(*this); + + for(int c = 0; eit.first != eit.second; eit.first++, c++) + setProperty(*eit.first, c); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, boost::shared_ptr cg) { + + LocalVertex cv = getClusterVertex(cg); + return moveToSubcluster(v, cv, cg); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, LocalVertex Cluster) { + + boost::shared_ptr cg = getVertexCluster(Cluster); + return moveToSubcluster(v, Cluster, cg); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg) { + + std::pair it = boost::out_edges(v, *this); + + /* add the later removed edges to the coressponding existing edges + * (or create new edges between adjacent vertices of moved vertex and cluster). + * also get the edge between cluster and vertex while iterating */ + for(; it.first != it.second; it.first++) { + + LocalVertex target = boost::target(*it.first, *this); + + if(target != Cluster) { + + //get or create the edge between the old edge target and the cluster + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(target, Cluster, *this); + + if(!done) + boost::tie(e, done) = boost::add_edge(target, Cluster, *this); + + //if(!done) TODO: throw + + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*this) [e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + } + + /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster + * if a connection existed */ + LocalVertex nv = boost::add_vertex((*this) [v], *cg); + + //resort cluster parentship if needed + if(isCluster(v)) { + + cg->m_clusters[nv] = m_clusters[v]; + cg->m_clusters[nv]->m_parent = cg; + m_clusters.erase(v); + } + + std::pair moveedge = boost::edge(v, Cluster, *this); + + if(moveedge.second) { + std::vector& vec = fusion::at_c<1> ((*this) [moveedge.first]); + + for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { + + //get the global vertex to which the global edge points and find the local vertex holding this + //global one + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + //bit cumbersome to support moving clusters + target = (cg->getContainingVertex(global.source).first == nv) ? global.target : global.source; + std::pair res = cg->getContainingVertex(target); + //if(!res.second) TODO: throw + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(nv, res.first, *cg); + + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); + + //if(!done) TODO: throw + + //push the global edge to the local edge + fusion::at_c<1> ((*cg) [e]).push_back(*i); + }; + } + + //all global edges concerning the move vertex are processed and it is moved to the subcluster, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + setChanged(); + cg->setChanged(); + + return nv; +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToParent(LocalVertex v) { + + //if(isRoot()) TODO:throw + + //create new vertex + vertex_bundle& vb = (*this) [v]; + LocalVertex nv = boost::add_vertex(vb, *parent()); + + //regrouping if needed + if(isCluster(v)) { + parent()->m_clusters[nv] = m_clusters[v]; + parent()->m_clusters[nv]->m_parent = m_parent; + m_clusters.erase(v); + } + + GlobalVertex gv = fusion::at_c<0> (vb); + + //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) + std::vector edge_vec; + LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); + std::pair it = boost::out_edges(this_v, *parent()); + + for(; it.first != it.second; it.first++) { + //iterate all global edges and find relevant ones + std::vector& vec = fusion::at_c<1> ((*parent()) [*it.first]); + edge_single_iterator i = vec.begin(); + + while(i != vec.end()) { + + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + + //a bit cumbersome to allow cluster moving + if(parent()->getContainingVertex(global.source).first == nv) + target = global.target; + else if(parent()->getContainingVertex(global.target).first == nv) + target = global.source; + else { + i++; + continue; + } + + std::pair res = parent()->getContainingVertex(target); + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(nv, res.first, *parent()); + + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); + + //if(!done) TODO: throw + + //push the global edge bundle to the new local edge and erase it in the old + fusion::at_c<1> ((*parent()) [e]).push_back(*i); + i = vec.erase(i); + } + + //see if we should destroy this edge (no global edges remain in local one) + if(vec.empty()) + edge_vec.push_back(*it.first); + } + + //create a edge between new vertex and this cluster and add all global edges from within this cluster + it = boost::out_edges(v, *this); + LocalEdge e; + + if(it.first != it.second) + e = boost::add_edge(nv, this_v, *parent()).first; + + for(; it.first != it.second; it.first++) { + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*parent()) [e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + + //all global edges concerning the move vertex are processed and it is moved to the parent, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + //it's possible that some local edges in the parent are empty now, let's destroy them + for(std::vector::iterator it = edge_vec.begin(); it != edge_vec.end(); it++) + boost::remove_edge(*it, *parent()); + + setChanged(); + parent()->setChanged(); + return nv; +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getContainingVertex(GlobalVertex id, bool recursive) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + if(id == fusion::at_c<0> ((*this) [*it.first])) + return std::make_pair(*it.first, true); + } + + //check all clusters if they have the id + if(recursive) { + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { + std::pair res = ((*it).second)->getContainingVertex(id); + + if(res.second) + return std::make_pair((*it).first, true); + } + } + + return std::make_pair((LocalVertex) NULL, false); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector >, bool> +ClusterGraph::getContainingVertexGraph(GlobalVertex id) { + + LocalVertex v; + bool done; + boost::tie(v, done) = getContainingVertex(id); + + if(!done) + return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); + + if(isCluster(v) && (getGlobalVertex(v) != id)) + return m_clusters[v]->getContainingVertexGraph(id); + else + return fusion::make_vector(v, sp_base::shared_from_this(), true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getContainingEdge(GlobalEdge id) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); + + if(!((d1 && d2) && (v1 != v2))) + return std::make_pair(LocalEdge(), false); + + return boost::edge(v1, v2, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector*, bool> +ClusterGraph::getContainingEdgeGraph(GlobalEdge id) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); + + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); + + if(v1 == v2) + return m_clusters[v1]->getContainingEdgeGraph(id); + + return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(LocalVertex k, functor f) { + return f((*this) [k]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(LocalEdge k, functor f) { + return f((*this) [k]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(GlobalVertex k, functor f) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + vertex_bundle& p = (*this) [*it.first]; + + if(k == fusion::at_c<0> (p)) + return f(p); + } + + //check all clusters if they have the object + fusion::vector, bool> res = getContainingVertexGraph(k); + + if(!fusion::at_c<2> (res)) { + //TODO: Throw (propeties return reference, but cant init a reference temporarily) + } + + return fusion::at_c<1> (res)->template apply_to_bundle (k, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(GlobalEdge k, functor f) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(k.source); + boost::tie(v2, d2) = getContainingVertex(k.target); + + if(!(d1 && d2)) { + //TODO:Throw + } + + if((v1 == v2) && isCluster(v1)) + return m_clusters[v1]->apply_to_bundle(k, f); + else { + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(v1, v2, *this); + //if(!done) TODO: throw, as there has to be a edge! + return f((*this) [e]); + }; + + +}; + +} //namespace dcm + + +#endif // CLUSTERGRAPH_HPP + + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp new file mode 100644 index 0000000000..d4d34b2add --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp @@ -0,0 +1,449 @@ +/* + 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 detemplate tails. + + 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 DCM_CONSTRAINT_HOLDER_IMP_H +#define DCM_CONSTRAINT_HOLDER_IMP_H + +#include "opendcm/core/constraint.hpp" + +#include +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + + +template +template +Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + + //get the index of the corresbonding equation + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + fusion::copy(fusion::at(objects).values, val.m_eq.values); + val.pure_rotation = fusion::at(objects).pure_rotation; +}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type>, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + +}; + +template +template +Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) + : first(f), second(s), scale(sc), rot_only(rotation_only) { + +}; + +template +template +template< typename T > +void Constraint::holder::Calculater::operator()(T& val) const { + + //if the equation is disabled we don't have anything mapped so avoid accessing it + if(!val.enabled) + return; + + //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 + if(rot_only && !val.pure_rotation) { + + val.m_residual(0) = 0; + if(first->getClusterMode()) { + if(!first->isClusterFixed()) { + val.m_diff_first_rot.setZero(); + val.m_diff_first.setZero(); + } + } + else + val.m_diff_first.setZero(); + + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + val.m_diff_second_rot.setZero(); + val.m_diff_second.setZero(); + } + } + else + val.m_diff_second.setZero(); + + } + //we need to calculate, so lets go for it! + else { + + val.m_eq.setScale(scale); + + val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); + + //now see which way we should calculate the gradient (may be diffrent for both geometries) + if(first->m_parameterCount) { + if(first->getClusterMode()) { + //when the cluster is fixed no maps are set as no parameters exist. + if(!first->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, first->m_diffparam.col(i)); + } + //and now with the translations + for(int i=0; i<3; i++) { + val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, first->m_diffparam.col(i+3)); + } + } + } + else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); + } + } + if(second->m_parameterCount) { + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, second->m_diffparam.col(i)); + } + //and the translation seperated + for(int i=0; i<3; i++) { + val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, second->m_diffparam.col(i+3)); + } + } + } + else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); + } + } + } +}; + +template +template +Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) + : mes(m), first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::MapSetter::operator()(T& val) const { + + if(!val.enabled) + return; + + //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat + //for every parameter in the geometry; + int equation = mes.setResidualMap(val.m_residual); + if(first->getClusterMode()) { + if(!first->isClusterFixed()) { + mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot); + mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); + } + } + else + mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); + + + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + mes.setJacobiMap(equation, second->m_offset_rot, 3, val.m_diff_second_rot); + mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); + } + } + else + mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); +}; + +template +template +Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) + : first(f), second(s), points1(vec1), points2(vec2) { + +}; + +template +template +template< typename T > +void Constraint::holder::PseudoCollector::operator()(T& val) const { + + if(!val.enabled) + return; + + if(first->m_isInCluster && second->m_isInCluster) { + val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); + } + else if(first->m_isInCluster) { + typename Kernel::Vector sec = second->m_parameter; + val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); + } + else if(second->m_isInCluster) { + typename Kernel::Vector fir = first->m_parameter; + val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); + } +}; + +template +template +Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) + : first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::LGZ::operator()(T& val) const { + + typedef typename Sys::Kernel Kernel; + + if(!val.enabled) + return; + + //to treat local gradient zeros we calculate a approximate second derivative of the equations + //only do that if neseccary: residual is not zero + if(!Kernel::isSame(val.m_residual(0),0, 1e-7)) { //TODO: use exact precission and scale value + + //rotations exist only in cluster + if(first->getClusterMode() && !first->isClusterFixed()) { + //LGZ exists for rotations only + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + if(Kernel::isSame(val.m_diff_first_rot(i), 0, 1e-7)) { + + //to get the approximated second derivative we need the slightly moved geometrie + const typename Kernel::Vector p_old = first->m_parameter; + first->m_parameter += first->m_diffparam.col(i)*1e-3; + first->normalize(); + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + first->m_parameter = p_old; + + //let's see if the initial LGZ was a real one + if(!Kernel::isSame(res, 0, 1e-7)) { + + //is a fake zero, let's correct it + val.m_diff_first_rot(i) = res; + }; + }; + }; + } + //and the same for the second one too + if(second->getClusterMode() && !second->isClusterFixed()) { + + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + if(Kernel::isSame(val.m_diff_second_rot(i), 0, 1e-7)) { + + //to get the approximated second derivative we need the slightly moved geometrie + const typename Kernel::Vector p_old = second->m_parameter; + second->m_parameter += second->m_diffparam.col(i)*1e-3; + second->normalize(); + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + second->m_parameter = p_old; + + //let's see if the initial LGZ was a real one + if(!Kernel::isSame(res, 0, 1e-7)) { + + //is a fake zero, let's correct it + val.m_diff_second_rot(i) = res; + }; + }; + }; + }; + }; +}; + +template +template +Constraint::holder::GenericEquations::GenericEquations(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericEquations::operator()(T& val) const { + vec.push_back(val.m_eq); +}; + +template +template +Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericConstraints::operator()(T& val) const { + vec.push_back(val); +}; + +template +template +Constraint::holder::Types::Types(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::Types::operator()(T& val) const { + vec.push_back(&typeid(T)); +}; + +template +template +Constraint::holder::holder(Objects& obj) : m_objects(obj) { + //set the initial values in the equations + fusion::for_each(m_sets, OptionSetter(obj)); +}; + +template +template +void Constraint::holder::calculate(geom_ptr first, geom_ptr second, + Scalar scale, bool rotation_only) { + fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); +}; + +template +template +void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, LGZ(first, second)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { + //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); + //if(creator.need_swap) first.swap(second); + return NULL; +}; + +template +template +void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, MapSetter(mes, first, second)); +}; + +template +template +void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { + fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::clone() { + return new holder(*this); +}; + +template +template +int Constraint::holder::equationCount() { + int count = 0; + EquationCounter counter(count); + fusion::for_each(m_sets, counter); + return count; +}; + +template +template +std::vector +Constraint::holder::getGenericEquations() { + std::vector vec; + fusion::for_each(m_sets, GenericEquations(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getGenericConstraints() { + std::vector vec; + fusion::for_each(m_objects, GenericConstraints(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getEquationTypes() { + std::vector vec; + mpl::for_each< EquationVector >(Types(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getConstraintTypes() { + std::vector vec; + mpl::for_each< ConstraintVector >(Types(vec)); + return vec; +}; + +template +template +void Constraint::holder::disable() { + fusion::for_each(m_sets, disabler()); +}; + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp new file mode 100644 index 0000000000..902943644e --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp @@ -0,0 +1,208 @@ +/* + 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 detemplate tails. + + 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 DCM_CONSTRAINT_IMP_H +#define DCM_CONSTRAINT_IMP_H + +#include "../constraint.hpp" + +#include +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + + + +template +template +void Constraint::initialize(ConstraintVector& cv) { + + //use the compile time unrolling to retrieve the geometry tags + initializeFirstGeometry >(cv, mpl::true_()); +}; + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + + switch(first->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return initializeSecondGeometry,\ + typename mpl::at::type >::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeFirstGeometry (cv, + typename mpl::less< next_which_t, typename mpl::size::type >::type()); + } +}; + +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + switch(second->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return intitalizeFinalize::type >::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeSecondGeometry + (cv, typename mpl::less + < next_which_t + , typename mpl::size::type>::type() + ); + } +}; + +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_ /*is_unrolled_t*/) { + + initializeFromTags(cv); +}; + +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_ /*is_unrolled_t*/) { + //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds + BOOST_ASSERT(false); +} + +template +template +void Constraint::initializeFromTags(ConstraintVector& v) { + + typedef tag_order< tag1, tag2 > order; + + //and build the placeholder + content = new holder(v); + + //geometry order needs to be the one needed by equations + if(order::swapt::value) + first.swap(second); +}; + +template +Constraint::Constraint(geom_ptr f, geom_ptr s) + : first(f), second(s), content(0) { + + //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); + //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); +}; + +template +Constraint::~Constraint() { + delete content; + //first->template disconnectSignal(cf); + //second->template disconnectSignal(cs); +}; + +template +int Constraint::equationCount() { + return content->equationCount(); +}; + +template +void Constraint::calculate(Scalar scale, bool rotation_only) { + content->calculate(first, second, scale, rotation_only); +}; + +template +void Constraint::treatLGZ() { + content->treatLGZ(first, second); +}; + +template +void Constraint::setMaps(MES& mes) { + content->setMaps(mes, first, second); +}; + +template +void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { + content->collectPseudoPoints(first, second, vec1, vec2); +}; + +template +std::vector Constraint::getGenericEquations() { + return content->getGenericEquations(); +}; + +template +std::vector Constraint::getGenericConstraints() { + return content->getGenericConstraints(); +}; + +template +std::vector Constraint::getEquationTypes() { + return content->getEquationTypes(); +}; + +template +std::vector Constraint::getConstraintTypes() { + return content->getConstraintTypes(); +}; + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp new file mode 100644 index 0000000000..2090ac4137 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp @@ -0,0 +1,255 @@ +/* + 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 detemplate tails. + + 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 DCM_EQUATIONS_IMP_H +#define DCM_EQUATIONS_IMP_H + +#include + +#include "../equations.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; + +namespace dcm { + +template +struct pushed_seq; + +/* +template +template +typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type +constraint_sequence::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for this sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector_added; + + //and copy the types in + fusion::nview view_added(vec); + fusion::copy(*this, view_added); + + //insert this object at the end of the sequence + *fusion::find(vec) = val; + + //and return our new extendet sequence + return vec; +}; + +template +template +typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type +constraint_sequence::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for the added sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector_added; + + //and copy the types in + fusion::nview view_added(vec); + fusion::copy(val, view_added); + + //to copy the types of the second sequence is not as easy as before. If types were already present in + //the original sequence they are not added again. therefore we need to find all types of the second sequence + //in the new one and assign the objects to this positions. + + //get a index vector for all second-sequence-elements + typedef typename mpl::transform::S2, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector; + + //and copy the types in + fusion::nview view(vec); + fusion::copy(*this, view); + + //and return our new extendet sequence + return vec; +}; +*/ +template +struct option_copy { + + options* values; + option_copy(options& op) : values(&op) {}; + + template + void operator()(const T& val) const { + if(val.second.first) + fusion::at_key(*values) = val.second; + }; +}; + +template +Derived& Equation::assign(const Derived& eq) { + + //we only copy the values which were set and are therefore valid + option_copy oc(values); + fusion::for_each(eq.values, oc); + + //the assigned eqution can be set back to default for convinience in further usage + const_cast(&eq)->setDefault(); + + return *static_cast(this); +}; + +/* +template +template +typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type +Equation::operator &(T& val) { + + typename pushed_seq::type vec; + *fusion::find(vec) = val; + *fusion::find(vec) = *(static_cast(this)); + return vec; +}; + +template +template +typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type +Equation::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for the added sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector; + + //and copy the types in + fusion::nview view(vec); + fusion::copy(val, view); + + //insert this object into the sequence + *fusion::find(vec) = *static_cast(this); + + //and return our new extendet sequence + return vec; +}; +*/ + +template +void Equation::setDefault() { + fusion::at_key(values) = std::make_pair(false, 0.); + fusion::at_key(values) = std::make_pair(false, bidirectional); +}; + +//convinience stream functions for debugging +template +struct print_pair { + std::basic_ostream* stream; + + template + void operator()(const T& t) const { + *stream << "("< +typename boost::enable_if, std::basic_ostream&>::type +operator << (std::basic_ostream& stream, const Eq& equation) +{ + print_pair pr; + pr.stream = &stream; + stream << typeid(equation).name() << ": "; + fusion::for_each(equation.values, pr); + return stream; +} + +Distance::Distance() : Equation() { + setDefault(); +}; + +Distance& Distance::operator=(const Distance& d) { + return Equation::assign(d); +}; + +void Distance::setDefault() {}; + + + +Orientation::Orientation() : Equation() { + setDefault(); +}; + +Orientation& Orientation::operator=(const Orientation& d) { + return Equation::assign(d); +}; + +void Orientation::setDefault() { + fusion::at_key(values) = std::make_pair(false, parallel); +}; + +Angle::Angle() : Equation() { + setDefault(); +}; + +Angle& Angle::operator=(const Angle& d) { + return Equation::assign(d); +}; + +void Angle::setDefault() { + fusion::at_key(values) = std::make_pair(false, 0.); + fusion::at_key(values) = std::make_pair(false, bidirectional); +}; + + +}; + +#endif //GCM_EQUATIONS_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp new file mode 100644 index 0000000000..91b76fce50 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp @@ -0,0 +1,266 @@ +/* + 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_GEOMETRY_IMP_H +#define GCM_GEOMETRY_IMP_H + +#include + +#include "../geometry.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef USE_LOGGING +#include +#endif + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace details { + +template< typename Kernel, int Dim, typename TagList> +Geometry::Geometry() + : m_isInCluster(false), m_parameter(NULL,0,DS(0,0)), + m_clusterFixed(false), m_init(false) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry")); +#endif + +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::transform(const Transform& t) { + + if(m_isInCluster) + transform(t, m_toplocal); + else + if(m_init) + transform(t, m_rotated); + else + transform(t, m_global); +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::init() { + + m_BaseParameterCount = tag::parameters::value; + m_parameterCount = m_BaseParameterCount; + m_rotations = tag::rotations::value; + m_translations = tag::translations::value; + + m_toplocal.setZero(m_parameterCount); + m_global.resize(m_parameterCount); + m_rotated.resize(m_parameterCount); + m_rotated.setZero(); + + m_diffparam.resize(m_parameterCount,6); + m_diffparam.setZero(); + + m_general_type = tag::weight::value; + m_exact_type = mpl::find::type::pos::value; + + normalize(); + + //new value which is not set into parameter, so init is false + m_init = false; + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init: "< +void Geometry::normalize() { + //directions are not nessessarily normalized, but we need to ensure this in cluster mode + for(int i=m_translations; i!=m_rotations; i++) + m_global.template segment(i*Dim).normalize(); +}; + +template< typename Kernel, int Dim, typename TagList> +typename Kernel::VectorMap& Geometry::getParameterMap() { + m_isInCluster = false; + m_parameterCount = m_BaseParameterCount; + return m_parameter; +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::linkTo(boost::shared_ptr > geom, int offset) { + + init(); + m_link = geom; + m_link_offset = offset; + m_global = geom->m_global.segment(offset, m_BaseParameterCount); +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::initMap(typename Kernel::MappedEquationSystem* mes) { + + //check should not be needed, but how knows... + if(!m_init) { + + if(!isLinked()) { + m_offset = mes->setParameterMap(m_parameterCount, getParameterMap()); + m_parameter = m_global; + m_init = true; + } + else { + //it's important that the linked geometry is initialised, as we going to access its parameter map + if(!m_link->isInitialised()) + m_link->initMap(mes); + + m_offset = m_link->m_offset + m_link_offset; + new(&getParameterMap()) typename Kernel::VectorMap(&m_link->getParameterMap()(m_link_offset), m_parameterCount, typename Kernel::DynStride(1,1)); + } + } +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::setClusterMode(bool iscluster, bool isFixed) { + + m_isInCluster = iscluster; + m_clusterFixed = isFixed; + if(iscluster) { + //we are in cluster, therfore the parameter map should not point to a solver value but to + //the rotated original value; + new(&m_parameter) typename Kernel::VectorMap(&m_rotated(0), m_parameterCount, DS(1,1)); + //the local value is the global one as no transformation was applied yet + m_toplocal = m_global; + m_rotated = m_global; + } + else + new(&m_parameter) typename Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::recalculate(DiffTransform& trans) { + if(!m_isInCluster) + return; + + for(int i=0; i!=m_rotations; i++) { + //first rotate the original to the transformed value + m_rotated.block(i*Dim,0,Dim,1) = trans.rotation()*m_toplocal.template segment(i*Dim); + + //now calculate the gradient vectors and add them to diffparam + for(int j=0; j(i*Dim); + } + //after rotating the needed parameters we translate the stuff that needs to be moved + for(int i=0; i!=m_translations; i++) { + m_rotated.block(i*Dim,0,Dim,1) += trans.translation().vector(); + m_rotated.block(i*Dim,0,Dim,1) *= trans.scaling().factor(); + //calculate the gradient vectors and add them to diffparam + m_diffparam.block(i*Dim,Dim,Dim,Dim).setIdentity(); + } + +#ifdef USE_LOGGING + if(!boost::math::isnormal(m_rotated.norm()) || !boost::math::isnormal(m_diffparam.norm())) { + BOOST_LOG(log) << "Unnormal recalculated value detected: "< +void Geometry::finishCalculation() { + //if fixed nothing needs to be changed + if(m_isInCluster) { + //recalculate(1.); //remove scaling to get right global value + m_global = m_rotated; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish cluster calculation"; +#endif + } + //TODO:non cluster paramter scaling + else { + m_global = m_parameter; + normalize(); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish calculation"; +#endif + }; + + m_init = false; + m_isInCluster = false; + + recalculated(); +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::transform(const Transform& t, VectorType& vec) { + + //everything that needs to be translated needs to be fully transformed + for(int i=0; i!=m_translations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t*v; + } + + for(int i=m_translations; i!=m_rotations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t.rotate(v); + } + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Transformed with cluster: "< +void Geometry::scale(Scalar value) { + + for(int i=0; i!=m_translations; i++) + m_parameter.template segment(i*Dim) *= 1./value; + +}; + +} +} + +#endif // GCM_GEOMETRY_H diff --git a/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp new file mode 100644 index 0000000000..1743344544 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp @@ -0,0 +1,512 @@ +/* + 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 DCM_KERNEL_IMP_H +#define DCM_KERNEL_IMP_H + +#include "../kernel.hpp" +#include + +namespace dcm { + +template +Dogleg::Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif +}; + +template +Dogleg::Dogleg() : tolg(1e-40), tolx(1e-20) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif +}; + +template +void Dogleg::setKernel(Kernel* k) { + + m_kernel = k; +}; + +template +template +void Dogleg::calculateStep(const Eigen::MatrixBase& g, const Eigen::MatrixBase& jacobi, + const Eigen::MatrixBase& residual, Eigen::MatrixBase& h_dl, + const double delta) { + + // get the steepest descent stepsize and direction + const double alpha(g.squaredNorm()/(jacobi*g).squaredNorm()); + const typename Kernel::Vector h_sd = -g; + + // get the gauss-newton step + const typename Kernel::Vector h_gn = (jacobi).fullPivLu().solve(-residual); +#ifdef USE_LOGGING + + if(!boost::math::isfinite(h_gn.norm())) { + BOOST_LOG(log)<< "Unnormal gauss-newton detected: "<= delta) { + //h_dl = alpha*h_sd; + h_dl = (delta/(h_sd.norm()))*h_sd; +#ifdef USE_LOGGING + + if(!boost::math::isfinite(h_dl.norm())) { + BOOST_LOG(log)<< "Unnormal dogleg descent detected: "< +void Dogleg::init(typename Kernel::MappedEquationSystem& sys) { + + if(!sys.isValid()) + throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system"); + + F_old.resize(sys.equationCount()); + g.resize(sys.equationCount()); + J_old.resize(sys.equationCount(), sys.parameterCount()); + + sys.recalculate(); +#ifdef USE_LOGGING + BOOST_LOG(log)<< "initial jacobi: "<(); +#endif + sys.removeLocalGradientZeros(); + +#ifdef USE_LOGGING + BOOST_LOG(log)<< "LGZ jacobi: "<(); +#endif + + err = sys.Residual.norm(); + + F_old = sys.Residual; + J_old = sys.Jacobi; + + g = sys.Jacobi.transpose()*(sys.Residual); + + // get the infinity norm fx_inf and g_inf + g_inf = g.template lpNorm(); + fx_inf = sys.Residual.template lpNorm(); + + delta=5; + nu=2.; + iter=0; + stop=0; + reduce=0; + unused=0; + counter=0; +}; + +template +int Dogleg::solve(typename Kernel::MappedEquationSystem& sys, bool continuous) { + nothing n; + return solve(sys, n, continuous); +}; + +template +template +int Dogleg::solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale, bool continuous) { + + clock_t start = clock(); + + if(!sys.isValid()) + throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system"); + + int maxIterNumber = 5000;//MaxIterations * xsize; + number_type diverging_lim = 1e6*err + 1e12; + + do { + + // check if finished + if(fx_inf <= m_kernel->template getProperty()*sys.Scaling) // Success + stop = 1; + else if(g_inf <= tolg) + throw solving_error() << boost::errinfo_errno(2) << error_message("g infinity norm smaller below limit"); + else if(delta <= tolx) + throw solving_error() << boost::errinfo_errno(3) << error_message("step size below limit"); + else if(iter >= maxIterNumber) + throw solving_error() << boost::errinfo_errno(4) << error_message("maximal iterations reached"); + else if(!boost::math::isfinite(err)) + throw solving_error() << boost::errinfo_errno(5) << error_message("error is inf or nan"); + else if(err > diverging_lim) + throw solving_error() << boost::errinfo_errno(6) << error_message("error diverged"); + + + // see if we are already finished + if(stop) + break; + + number_type err_new; + number_type dF=0, dL=0; + number_type rho; + + //get the update step + calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta); + + // calculate the linear model + dL = 0.5*sys.Residual.norm() - 0.5*(sys.Residual + sys.Jacobi*h_dl).norm(); + + // get the new values + sys.Parameter += h_dl; + sys.recalculate(); + +#ifdef USE_LOGGING + + if(!boost::math::isfinite(sys.Residual.norm())) { + BOOST_LOG(log)<< "Unnormal residual detected: "<0.85) { + delta = std::max(delta,2*h_dl.norm()); + nu = 2; + } + else if(rho < 0.25) { + delta = delta/nu; + nu = 2*nu; + } + + if(dF > 0 && dL > 0) { + + //see if we got too high differentials + if(sys.Jacobi.template lpNorm() > 2) { +#ifdef USE_LOGGING + BOOST_LOG(log)<< "High differential detected: "<()<<" in iteration: "<1 && (counter>50)) { + rescale(); + sys.recalculate(); + counter = 0; + } + + F_old = sys.Residual; + J_old = sys.Jacobi; + + err = sys.Residual.norm(); + g = sys.Jacobi.transpose()*(sys.Residual); + + // get infinity norms + g_inf = g.template lpNorm(); + fx_inf = sys.Residual.template lpNorm(); + + } + else { + sys.Residual = F_old; + sys.Jacobi = J_old; + sys.Parameter -= h_dl; + unused++; +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Reject step in iter "< class Nonlinear> +int Kernel::MappedEquationSystem::parameterCount() { + return m_params; +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::equationCount() { + return m_eqns; +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::rotationOnly() { + return rot_only; +}; + +template class Nonlinear> +Kernel::MappedEquationSystem::MappedEquationSystem(int params, int equations) + : rot_only(false), m_jacobi(equations, params), + m_parameter(params), Residual(equations), + m_params(params), m_eqns(equations), Scaling(1.), + Jacobi(&m_jacobi(0,0),equations,params,DynStride(equations,1)), + Parameter(&m_parameter(0),params,DynStride(1,1)) { + + m_param_rot_offset = 0; + m_param_trans_offset = params; + m_eqn_offset = 0; + + m_jacobi.setZero(); //important as some places are never written +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setParameterMap(int number, VectorMap& map, ParameterType t) { + + if(t == rotation) { + new(&map) VectorMap(&m_parameter(m_param_rot_offset), number, DynStride(1,1)); + m_param_rot_offset += number; + return m_param_rot_offset-number; + } + else { + m_param_trans_offset -= number; + new(&map) VectorMap(&m_parameter(m_param_trans_offset), number, DynStride(1,1)); + return m_param_trans_offset; + } +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setParameterMap(Vector3Map& map, ParameterType t) { + + if(t == rotation) { + new(&map) Vector3Map(&m_parameter(m_param_rot_offset)); + m_param_rot_offset += 3; + return m_param_rot_offset-3; + } + else { + m_param_trans_offset -= 3; + new(&map) Vector3Map(&m_parameter(m_param_trans_offset)); + return m_param_trans_offset; + } +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setResidualMap(VectorMap& map) { + new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1)); + return m_eqn_offset++; +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setJacobiMap(int eqn, int offset, int number, CVectorMap& map) { + new(&map) CVectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setJacobiMap(int eqn, int offset, int number, VectorMap& map) { + new(&map) VectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::isValid() { + if(!m_params || !m_eqns) + return false; + + return true; +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setAccess(ParameterType t) { + + if(t==complete) { + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1)); + } + else if(t==rotation) { + int num = m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); + } + else if(t==general) { + int num = m_params - m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); + } +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setGeneralEquationAccess(bool general) { + rot_only = !general; +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::hasParameterType(ParameterType t) { + + if(t==rotation) + return (m_param_rot_offset>0); + else if(t==general) + return (m_param_trans_offset0); +}; + +template class Nonlinear> +Kernel::Kernel() { + //init the solver + m_solver.setKernel(this); +} + +template class Nonlinear> +SolverInfo Kernel::getSolverInfo() { + + SolverInfo info; + info.iterations = m_solver.iter; + info.error = m_solver.err; + info.time = m_solver.time; + + return info; +} + +//static comparison versions +template class Nonlinear> +template +bool Kernel::isSame(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1-p2).squaredNorm() < precission); +} + +template class Nonlinear> +bool Kernel::isSame(number_type t1, number_type t2, number_type precission) { + return (std::abs(t1-t2) < precission); +} + +template class Nonlinear> +template +bool Kernel::isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1+p2).squaredNorm() < precission); +} + +template class Nonlinear> +template +bool Kernel::isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1-p2).squaredNorm() < getProperty()); +} + +template class Nonlinear> +bool Kernel::isSame(number_type t1, number_type t2) { + return (std::abs(t1-t2) < getProperty()); +} + +template class Nonlinear> +template +bool Kernel::isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1+p2).squaredNorm() < getProperty()); +} + +template class Nonlinear> +int Kernel::solve(MappedEquationSystem& mes) { + + nothing n; + + if(getProperty()==continuous) + m_solver.init(mes); + + return m_solver.solve(mes, n); +}; + +template class Nonlinear> +template +int Kernel::solve(MappedEquationSystem& mes, Functor& f) { + + if(getProperty()==continuous) + m_solver.init(mes); + + return m_solver.solve(mes, f); +}; + +} + +#endif //GCM_KERNEL_H + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp new file mode 100644 index 0000000000..66f3220284 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp @@ -0,0 +1,115 @@ +/* + 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_OBJECT_IMP_H +#define GCM_OBJECT_IMP_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../property.hpp" + +#define EMIT_CALL_DEC(z, n, data) \ + template \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void SignalOwner::emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ + { \ + if(m_emit_signals) {\ + typedef typename mpl::find::type iterator; \ + typedef typename mpl::distance::type, iterator>::type distance; \ + typedef typename fusion::result_of::value_at::type map_type; \ + map_type& map = fusion::at(m_signals); \ + for (typename map_type::iterator it=map.begin(); it != map.end(); it++) \ + (it->second)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + }\ + }; + +namespace dcm { + +template +Object::Object(Sys& system) : m_system(&system) {}; + +template +boost::shared_ptr Object::clone(Sys& newSys) +{ + + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + return np; +}; + +template +SignalOwner::SignalOwner() : m_emit_signals(true), m_signal_count(0) {}; + +template +template +Connection SignalOwner::connectSignal(typename mpl::at::type function) +{ + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map[++m_signal_count] = function; + return m_signal_count; +}; + +template +template +void SignalOwner::disconnectSignal(Connection c) +{ + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map.erase(c); +}; + +template +void SignalOwner::enableSignals(bool onoff) +{ + m_emit_signals = onoff; +}; + +BOOST_PP_REPEAT(5, EMIT_CALL_DEC, ~) + +} + +#endif //GCM_OBJECT_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp new file mode 100644 index 0000000000..33384fdde6 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp @@ -0,0 +1,257 @@ +/* + 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 DCM_SYSTEM_IMP_H +#define DCM_SYSTEM_IMP_H + +#ifdef DCM_EXTERNAL_CORE +#include "kernel_imp.hpp" +#include "transformation_imp.hpp" +#include "clustergraph_imp.hpp" +#include "equations_imp.hpp" +#endif + +#include "../system.hpp" + +#include + +namespace dcm { + +struct clearer { + template + void operator()(T& vector) const { + vector.clear(); + }; +}; + +template +struct cloner { + + System& newSys; + cloner(System& ns) : newSys(ns) {}; + + template + struct test : mpl::and_, + mpl::not_ > > > {}; + + template + typename boost::enable_if< test, void>::type operator()(T& p) const { + p = p->clone(newSys); + newSys.push_back(p); + }; + template + typename boost::enable_if< mpl::not_ >, void>::type operator()(const T& p) const {}; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +System::System() : m_cluster(new Cluster), m_storage(new Storage) +#ifdef USE_LOGGING + , sink(init_log()) +#endif +{ + Type1::system_init(*this); + Type2::system_init(*this); + Type3::system_init(*this); +}; + + +template< typename KernelType, typename T1, typename T2, typename T3 > +System::~System() { +#ifdef USE_LOGGING + stop_log(sink); +#endif +}; + + +template< typename KernelType, typename T1, typename T2, typename T3 > +void System::clear() { + + m_cluster->clearClusters(); + m_cluster->clear(); + fusion::for_each(*m_storage, clearer()); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename std::vector< boost::shared_ptr >::iterator System::begin() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).begin(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename std::vector< boost::shared_ptr >::iterator System::end() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).end(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +std::vector< boost::shared_ptr >& System::objectVector() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +void System::push_back(boost::shared_ptr ptr) { + objectVector().push_back(ptr); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +void System::erase(boost::shared_ptr ptr) { + + std::vector< boost::shared_ptr >& vec = objectVector(); + vec.erase(std::remove(vec.begin(), vec.end(), ptr), vec.end()); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +SolverInfo System::solve() { + clock_t start = clock(); + m_sheduler.execute(*this); + clock_t end = clock(); + + SolverInfo info = m_kernel.getSolverInfo(); + info.time = (double(end-start)* 1000.) / double(CLOCKS_PER_SEC); + + //signal our successful solving + BaseType::template emitSignal(this); + + return info; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +boost::shared_ptr > System::createSubsystem() { + + boost::shared_ptr s = boost::shared_ptr(new System()); + s->m_cluster = m_cluster->createCluster().first; + s->m_storage = m_storage; + s->m_cluster->template setProperty(details::subcluster); +#ifdef USE_LOGGING + stop_log(s->sink); +#endif + + //inform modules that we have a subsystem now + Inheriter1::system_sub(s); + Inheriter2::system_sub(s); + Inheriter3::system_sub(s); + + m_subsystems.push_back(s); + + return s; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +typename std::vector > >::iterator System::beginSubsystems() { + return m_subsystems.begin(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +typename std::vector > >::iterator System::endSubsystems() { + return m_subsystems.end(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename boost::enable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, typename Option::type& >::type +System::getOption() { + return m_options.template getProperty