From 02bc130c42ecc2b068943c69e626b6b2df4eb17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 25 Apr 2013 12:14:01 +0200 Subject: [PATCH] add opendcm constraint solver --- .../Assembly/App/opendcm/.kdev_include_paths | 1 + src/Mod/Assembly/App/opendcm/core.hpp | 28 + .../App/opendcm/core/clustergraph.hpp | 1520 +++++++++++++++++ .../Assembly/App/opendcm/core/constraint.hpp | 512 ++++++ .../Assembly/App/opendcm/core/equations.hpp | 189 ++ .../Assembly/App/opendcm/core/geometry.hpp | 481 ++++++ src/Mod/Assembly/App/opendcm/core/kernel.hpp | 425 +++++ src/Mod/Assembly/App/opendcm/core/logging.hpp | 94 + src/Mod/Assembly/App/opendcm/core/object.hpp | 269 +++ .../Assembly/App/opendcm/core/property.hpp | 167 ++ .../Assembly/App/opendcm/core/sheduler.hpp | 100 ++ src/Mod/Assembly/App/opendcm/core/system.hpp | 327 ++++ src/Mod/Assembly/App/opendcm/core/traits.hpp | 101 ++ .../App/opendcm/core/transformation.hpp | 292 ++++ src/Mod/Assembly/App/opendcm/externalize.hpp | 73 + src/Mod/Assembly/App/opendcm/module3d.hpp | 32 + .../Assembly/App/opendcm/module3d/angle.hpp | 149 ++ .../App/opendcm/module3d/clustermath.hpp | 770 +++++++++ .../Assembly/App/opendcm/module3d/defines.hpp | 33 + .../App/opendcm/module3d/distance.hpp | 292 ++++ src/Mod/Assembly/App/opendcm/module3d/dof.hpp | 133 ++ .../App/opendcm/module3d/geometry.hpp | 160 ++ .../Assembly/App/opendcm/module3d/module.hpp | 546 ++++++ .../App/opendcm/module3d/parallel.hpp | 215 +++ .../Assembly/App/opendcm/module3d/solver.hpp | 367 ++++ .../Assembly/App/opendcm/module3d/state.hpp | 95 ++ .../App/opendcm/modulePart/geometry.hpp | 92 + .../App/opendcm/modulePart/module.hpp | 558 ++++++ .../App/opendcm/moduleState/defines.hpp | 36 + .../moduleState/edge_vertex_generator.hpp | 72 + .../moduleState/edge_vertex_generator_imp.hpp | 57 + .../moduleState/edge_vertex_parser.hpp | 71 + .../moduleState/edge_vertex_parser_imp.hpp | 55 + .../App/opendcm/moduleState/extractor.hpp | 119 ++ .../App/opendcm/moduleState/generator.hpp | 82 + .../App/opendcm/moduleState/generator_imp.hpp | 72 + .../App/opendcm/moduleState/indent.hpp | 63 + .../App/opendcm/moduleState/karma_trans.hpp | 155 ++ .../App/opendcm/moduleState/module.hpp | 98 ++ .../opendcm/moduleState/object_generator.hpp | 72 + .../moduleState/object_generator_imp.hpp | 57 + .../App/opendcm/moduleState/object_parser.hpp | 98 ++ .../opendcm/moduleState/object_parser_imp.hpp | 63 + .../App/opendcm/moduleState/parser.hpp | 82 + .../App/opendcm/moduleState/parser_imp.hpp | 71 + .../moduleState/property_generator.hpp | 102 ++ .../moduleState/property_generator_imp.hpp | 43 + .../opendcm/moduleState/property_parser.hpp | 120 ++ .../moduleState/property_parser_imp.hpp | 60 + .../App/opendcm/moduleState/traits.hpp | 53 + .../App/opendcm/moduleState/traits_impl.hpp | 160 ++ src/Mod/Assembly/App/opendcm/modulepart.hpp | 29 + src/Mod/Assembly/App/opendcm/modulestate.hpp | 29 + 53 files changed, 9940 insertions(+) create mode 100644 src/Mod/Assembly/App/opendcm/.kdev_include_paths create mode 100644 src/Mod/Assembly/App/opendcm/core.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/clustergraph.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/constraint.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/equations.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/kernel.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/logging.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/object.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/property.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/sheduler.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/system.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/traits.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/transformation.hpp create mode 100644 src/Mod/Assembly/App/opendcm/externalize.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/angle.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/defines.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/distance.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/dof.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/parallel.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/solver.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/state.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulePart/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/defines.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/indent.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/traits.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulepart.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulestate.hpp diff --git a/src/Mod/Assembly/App/opendcm/.kdev_include_paths b/src/Mod/Assembly/App/opendcm/.kdev_include_paths new file mode 100644 index 0000000000..c0f755818f --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/.kdev_include_paths @@ -0,0 +1 @@ +/usr/include/eigen3 diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp new file mode 100644 index 0000000000..8d03a1d7fe --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -0,0 +1,28 @@ +/* + 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_CORE_H +#define DCM_CORE_H + +#include "core/geometry.hpp" +#include "core/kernel.hpp" +#include "core/system.hpp" + +#endif //DCM_CORE_H + diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp new file mode 100644 index 0000000000..fac9f172ce --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -0,0 +1,1520 @@ +/* + 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 CLUSTERGRAPH_HPP +#define CLUSTERGRAPH_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "property.hpp" +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace details { + +typedef boost::adjacency_list_traits list_traits; +typedef int universalID; + +struct IDgen { + universalID* counter; + + IDgen() { + counter = new universalID(10); + }; + IDgen(universalID id) { + counter = new universalID(id); + }; + ~IDgen() { + delete counter; + }; + universalID generate() { + return ++(*counter); + }; + universalID count() { + return (*counter); + }; + void setCount(universalID id) { + *counter = id; + }; +}; + +typedef boost::shared_ptr IDpointer; + +struct clear_ptr { + template + void operator()(T& t) const { + t.reset(); + }; +}; + +template +struct sps { //shared_ptr sequence + typedef typename mpl::transform >::type spv; + typedef typename fusion::result_of::as_vector::type type; +}; + +} + +typedef details::list_traits::vertex_descriptor LocalVertex; +typedef details::list_traits::edge_descriptor LocalEdge; +typedef details::universalID GlobalVertex; +struct GlobalEdge { + GlobalVertex source; + GlobalVertex target; + details::universalID ID; + + bool operator==(const GlobalEdge& second) const { + return ID==second.ID; + }; + bool operator!=(const GlobalEdge& second) const { + return ID!=second.ID; + }; + bool valid() { + return ID>9; + }; +}; + + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, + boost::undirectedS, + fusion::vector< GlobalVertex, typename details::pts::type, + typename details::sps::type>, + fusion::vector< typename details::pts::type, + std::vector< fusion::vector< typename details::sps::type, GlobalEdge > > > >, + public boost::noncopyable, + public boost::enable_shared_from_this > { + +public: + typedef fusion::vector< typename details::sps::type, GlobalEdge > edge_bundle_single; + typedef fusion::vector< typename details::pts::type, std::vector< edge_bundle_single > > edge_bundle; + typedef typename std::vector< edge_bundle_single >::iterator edge_single_iterator; + typedef fusion::vector< GlobalVertex, typename details::pts::type, + typename details::sps::type > vertex_bundle; + + + typedef boost::adjacency_list< boost::listS, boost::listS, + boost::undirectedS, vertex_bundle, edge_bundle > Graph; + + typedef boost::enable_shared_from_this > sp_base; + + //if changed_prop is not a property we have to add it now + typedef typename mpl::if_< + boost::is_same< + typename mpl::find::type, + typename mpl::end::type >, + typename mpl::push_back::type, + cluster_prop >::type cluster_properties; + + typedef typename details::pts::type cluster_bundle; + + typedef typename boost::graph_traits::vertex_iterator local_vertex_iterator; + typedef typename boost::graph_traits::edge_iterator local_edge_iterator; + typedef typename boost::graph_traits::out_edge_iterator local_out_edge_iterator; + + typedef std::map > ClusterMap; + + cluster_bundle m_cluster_bundle; + + typedef edge_prop edge_properties; + typedef vertex_prop vertex_properties; + +private: + struct global_extractor { + typedef GlobalEdge& result_type; + template + result_type operator()(T& bundle) const { + return fusion::at_c<1>(bundle); + }; + }; + 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); + }; + }; + + template + struct object_extractor { + + typedef boost::shared_ptr base_type; + typedef base_type& result_type; + typedef typename mpl::find::type iterator; + 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)); + }; + }; + + 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 + typedef boost::transform_iterator global_edge_iterator; + typedef boost::transform_iterator global_vertex_iterator; + + template + struct object_iterator : public boost::transform_iterator, edge_single_iterator> { + object_iterator(edge_single_iterator it, object_extractor f) + : boost::transform_iterator,edge_single_iterator>(it, f) {}; + }; + + typedef typename ClusterMap::iterator cluster_iterator; + typedef typename ClusterMap::const_iterator const_cluster_iterator; + + ClusterGraph() : m_id(new details::IDgen) {}; + + ClusterGraph(boost::shared_ptr g) : m_parent(g), m_id(new details::IDgen) { + if(g) m_id = g->m_id; + }; + + ~ClusterGraph() {}; + + /** + * @brief Copys the Clustergraph into a new one + * + * Copys this cluster and all subclusters into the give one, which is cleared bevore copying. Be + * aware that all objects and properties are only copied, and as some are shared pointers (namely + * all objects) you may have to clone them. If needed this can be done with the supplied functor, + * which receives all copied objects to his function operator which returns the new object. + * @param into The Graph that should be a copy of this + * @param functor The function objects which gets the graph objects and returns the ones for the + * 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 + 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); + }; + + template + bool operator==(const T& other) const { + return this == &other; + }; + + template + bool operator!=(const T& other) const { + return !(this == &other); + }; + + void setChanged() { + setClusterProperty(true); + }; + + /* ******************************************************* + * Cluster Property + * *******************************************************/ + template + typename P::type& getClusterProperty() { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(m_cluster_bundle); + }; + template + typename P::type& getSubclusterProperty(LocalVertex v) { + return getVertexCluster(v)->getClusterProperty

(); + }; + + template + void setClusterProperty(typename P::type p) { + getClusterProperty

() = p; + }; + + + /* ******************************************************* + * Subclustering + * *******************************************************/ + 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); + }; + + boost::shared_ptr parent() { + return m_parent; + }; + + const boost::shared_ptr parent() const { + return m_parent; + }; + bool isRoot() const { + return m_parent ? false : true; + }; + + boost::shared_ptr root() { + return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + }; + + const boost::shared_ptr root() const { + return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + }; + + std::pair clusters() { + return std::make_pair(m_clusters.begin(), m_clusters.end()); + } + std::pair clusters() const { + return std::make_pair(m_clusters.begin(), m_clusters.end()); + } + + std::size_t numClusters() const { + return m_clusters.size(); + } + + bool isCluster(LocalVertex v) { + return (m_clusters.find(v) != m_clusters.end()); + }; + + 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(); + }; + + 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; + } + return LocalVertex(); + }; + + template + void removeCluster(boost::shared_ptr g, Functor& f) { + removeCluster(getClusterVertex(g), f); + }; + void removeCluster(boost::shared_ptr g) { + placehoder p; + removeCluster(getClusterVertex(g), p); + }; + void clearClusters() { + m_clusters.clear(); + }; + + /** + * @brief Remove a subcluster and applys the functor to all removed edges and vertices + * + * All downstream elements of the local vertex v will be removed after the functor is applied to there + * edges and vertices. Note that the LocalVertex which represents the cluster to delete is not passed + * to the functor. When ever the cluster is changed it will be passed to the functor, so that it need + * to have three overloads: operator()(GlobalEdge), operator()(GlobalVertex), operator()(ClusterGraph&) + * + * @param v Local vertex which is a cluster and which should be deleted + * @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()) + return; //TODO:throw + + 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); + }; + +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); + } + } + }; + + + + /* ******************************************************* + * Creation Handling + * *******************************************************/ + +public: + /** + * @brief Add a vertex to the local cluster + * + * @return fusion:vector< LocalVertex, GlobalVertex > with 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()); + }; + + 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); + }; + + /** + * @brief Returns the edge between the local vertices + * + * This function is the same as boost::edge(source, target, Graph) and only added for convienience. + * + * @param source LocalEdge as edge source + * @param target LocalEdge as edge target + * @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); + }; + + /** + * @brief Add a edge between two vertices, defined by local descriptors. + * + * Add an edge that connects the two vertices and in the local clustergraph and assign the GlobalEdge to it. The + * LocalVertex parameters should not represent a cluster which would result in the functions failure. If there's + * already a local edge between the vertices a new global edge will be added and returned. Failure will be + * recocnisable by a false value in the returned type sequence. + * + * @param source The first vertex the edge should connect + * @param target The second vertex the edge should connect + * @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); + }; + + /** + * @brief Add a edge between two vertices, defined by global descriptors. + * + * Adds an edge between vertices which are not nesseccarily in this local cluster and have therefore to be + * identified with global descriptors. The only condition for source and target vertex is that both must be + * in the local cluster or any of its subclusters. If thats not the case, the function will fail. On success + * a new GlobalEdge will be created, but not neccessarily a local one. If the vertices are in different cluster + * which are already connected the global edge will be added to this connecting local edge. Thats the one returned + * in the seqence. Note that it's possible that the local edge belongs to another subcluster and therefore can't be + * used in the local cluster. This case is indicated by the scope return value. + * + * @param source The first vertex the edge should connect + * @param target The second vertex the edge should connect + * @return fusion:vector< LocalEdge, GlobalEdge, success, scope > with the new global edge descriptor and the local + * 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) { + + 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); + }; + + /** + * @brief Get an iterator to all the global edges hold by this local edge + * + * Local edges can hold multiple global ones, for example when they connect at least one cluster. Therefore a direct + * LocalEdge - GlobalEdge mapping is not possible. Instead you can access all GlobalEdge's hold by this local one in + * a normal iterating manner. + * + * @param e the local edge for which the global descriptors are wanted + * @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); + }; + + /** + * @brief Get the count of all global edges + * + * Local edges can hold multiple global ones, for example when they connect at least one cluster. To get the + * number of all global edges in this local one you can use this function. + * + * @param e the local edge for which the global descriptors are wanted + * @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(); + }; + + /** + * @brief Get the local edge which holds the specified global edge. + * + * Note that GlobalEdge must be in a local edge of this cluster, means the connected vertices must be in this + * or one of it's subclusters (but not the same). Also if the containing LocalEdge is not in this cluster, but in one of it's + * subclusters, the function fails and the returned edge is invalid. + * + * @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); + }; + + /** + * @brief Get the local edge which holds the specified global one and the subcluster in which it is valid. + * + * The function only fails when the global edge is hold by a local one upstream in the cluster + * herarchy. + * + * @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); + }; + + /** + * @brief Get the GlobalVertex assiociated with this local one. + * + * @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; + }; + + /** + * @brief Get the LocalVertex which corresponds to the golab one + * + * The GlobalVertex has to be in this cluster or any of it's subclusters. If its in a subcluster, the returned + * LocalVertex will represent this cluster. If the GlobalVertex is not in this clusters scope the function fails. + * + * @param GlobalVertex + * @return std::pair< LocalVertex, bool > The LocalVertex containing the global one and an success indicator + **/ + std::pair getLocalVertex(GlobalVertex e) { + return getContainingVertex(e); + }; + + /** + * @brief Get the local vertex which holds the specified global one and the subcluster in which it is valid. + * + * The function only fails when the global vertex is hold by a local one upstream in the cluster + * herarchy. + * + * @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); + }; + + + /* ******************************************************* + * Remove Handling + * *******************************************************/ +private: + + template + struct apply_remove_prediacte { + Functor& func; + GlobalVertex vert; + GlobalEdge edge; + bool isEdge; + + 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; + 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); + + 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); + if(!res.second) + return; //TODO:throw + + //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); + }; + +public: + /** + * @brief Removes a vertex from the local cluster and applys functor to removed edges + * + * Removes the vertex from the local graph and invalidates the global vertex id. Also all edges connecting + * to this vertex will be removed after the functor was applied to them. The functor needs to implement + * operato()(GlobalEdge e). Remark that there is no checking done if the vertex is a cluster, so you + * need to make sure it's not, as removing a clustervertex will not delete the coresponding cluster. + * + * @param id Local Vertex which should be removed from the graph + **/ + template + void removeVertex(LocalVertex id, Functor& f) { + removeVertex(getGlobalVertex(id), 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); + }; + + /** + * @brief Removes a vertex from the cluster or it's subclusters and applys functor to removed edges + * + * Removes the vertex from the graph or subclusters and invalidates the global vertex id. Also all edges connecting + * to this vertex will be removed (upstream and downstream) after the functor was applied to them. The functor + * needs to implement operato()(LocalEdge edge). + * + * @param id Global Vertex which should be removed from the graph + **/ + template + void removeVertex(GlobalVertex id, Functor& f) { + root()->downstreamRemoveVertex(id, 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); + }; + + /** + * @brief Removes a global Edge from the cluster or it's subclusters + * + * Removes the edge from the graph or subclusters and invalidates the global edge id. If the local edge holds + * only this global one it will be removed also. + * + * @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)); + }; + + /** + * @brief Removes a local edge from the cluster and calls the functor for all removed global edges + * + * Removes the edge from the graph and invalidates the global edges. The Functor needs to provide + * operator()(GlobalEdge). If no functor is needed just use boost::remove_edge. + * + * @param id Global Edge which should be removed from the graph + * @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); + }; + + + /* ******************************************************* + * 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::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::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::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: + + /** + * @brief Get the desired object at the specified vertex or edge + * + * This function allows to access the objects stored in the graph. If no object of the desired type + * was set before, a empty shared_ptr will be returned. Accessing the object at a local edge is a special + * case, as it can hold many global edges, each with it's own objetcs. Using a LocalEdge as key will + * always return the object for the first GlobalEdge. + * + * @param local or global Vertex/Edge descriptor for which the object is desired + * @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)); + }; + + /** + * @brief Set a object at the specified vertex or edge + * + * Sets the given value at the given key. Note that every entity can hold only one object, so setting + * a new value resets all other objects which were set before. Setting the object at a local edge is a special + * case, as it can hold many global edges, each with it's own objects. Using a LocalEdge as key will + * always set the object for the first GlobalEdge. + * + * @param k local or global Vertex/Edge descriptor for which the object should be set + * @param val the object which should be stored + * @return void + **/ + template + void setObject(key k, boost::shared_ptr val) { + apply_to_bundle(k, obj_helper(k)) = val; + + setChanged(); + }; + + /** + * @brief Get iterator range for all GlobalEdge objects hold by this local edge + * + * LocalEdge's can hold multiple global ones and the iterators can be used to access a specific object type in + * all global edges hold by this local edge. + * + * @param k the LocalEdge over which all Objects should be iterated. + * @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); + }; + + /** + * @brief Applys the functor to each occurence of an object + * + * Each valid object of the given type is extractet and passed to the function object. Vertices + * and edges are searched for valid object pointers, it happens in this order. When a recursive + * search is specified, all subclusters are searched too, but the cluster is passt to the Functor + * first. So make sure a function overload for clusters exist in this case. + * + * @param f the functor to which all valid objects get passed to. + * @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->for_each(f, recursive); + } + } + }; + + /** + * @brief Applys the functor to each object + * + * Each valid object of any type is extractet and passed to the function object. Vertices + * and edges are searched for valid object pointers, it happens in this order. When a recursive + * search is specified, all subclusters are searched too, but the cluster is passt to the Functor + * first. So make sure a function overload for clusters exist in this case. + * + * @param f the functor to which all valid objects get passed to. + * @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); + } + } + }; + + /* ******************************************************* + * 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_::type >, + edge_iterator, vertex_iterator>::type iterator; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + + //used with vertex bundle type + template + typename boost::enable_if::type>, + result_type>::type operator()(bundle& p) { + return property_extractor()(p); + } + + //used with edge bundle type + template + typename boost::enable_if::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 + * + * This function allows to access the properties stored in the graph. If no property of the desired type + * was set before, a default construced will be returned. Accessing the property at a global edge will return + * the property of the holding local edge. + * + * @param local or global Vertex/Edge descriptor for which the property is desired + * @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)); + }; + + /** + * @brief Set a property at the specified vertex or edge + * + * Sets the given value at the given key. Note that every entity can hold one of each property, as opposed + * to objects. Setting the property at a local edge is a special case, as it can hold many global edges, + * each with it's own propertys. Using a LocalEdge as key will always set the property for the first GlobalEdge. + * + * @param k local or global Vertex/Edge descriptor for which the property should be set + * @param val the property value which should be stored + * @return void + **/ + template + void setProperty(key k, typename property::type val) { + apply_to_bundle(k, get_prop_helper(k)) = val; + + setChanged(); + }; + + + /******************************************************** + * Vertex and Cluster moving + * *******************************************************/ + + /** + * @brief Move a vertex to a subcluster + * + * Overloaded convinience function which fetches the local descriptor for the cluster reference and calls + * the full parameter equivalent. Both cluster and vertex must be in the local cluster. + * + * @param v the LocalVertex to be moved + * @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); + }; + + /** + * @brief Move a vertex to a subcluster + * + * Overloaded convinience function which fetches the the cluster reference for the local descriptor and calls + * the full parameter equivalent. Both cluster and vertex must be in the local cluster. + * + * @param v the LocalVertex to be moved + * @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); + }; + + /** + * @brief Move a vertex to a subcluster + * + * This function moves the LocalVertex to the subcluster and reconnects all other vertices and clusters. The + * moved vertex will hold it's global descriptor but get a new local one assigned (the one returned). The same + * stands for all edges which use the moved vertex: global descriptors stay the same, but they are moved to new + * local edges. It's allowed to move cluster vertices with this function. + * The specified cluster has of course to be a valid and direct subcluster, the move vertex also has to be in the + * local cluster. + * + * @param v the LocalVertex to be moved + * @param Cluster the local vertex descriptor representing the subcluster to which v should be moved + * @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; + }; + + + /** + * @brief Move a vertex to the parent cluster. + * + * This function moves a vertex one step up in the subcluster hierarchie and reconnects all other vertices and clusters. + * The moved vertex will hold it's global descriptor but get a new local one assigned (the one returned). The same + * stands for all edges which use the moved vertex: global descriptors stay the same, but they are moved to new + * local edges. Note that this function is the inverse of moveToSubcluster, and doing Pseudocode: + * moveToParent(moveToSubcluster(v)) does nothing (only the local descriptor of the moved vertex is + * diffrent afterwards). + * + * @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)) { + m_parent->m_clusters[nv] = m_clusters[v]; + m_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 = m_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(m_parent->getContainingVertex(global.source).first == nv) target = global.target; + else if(m_parent->getContainingVertex(global.target).first == nv) target = global.source; + else { + i++; + continue; + } + + std::pair res = m_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; + }; + + + /******************************************************** + * Stuff + * *******************************************************/ + + ClusterMap m_clusters; + int test; +protected: + boost::shared_ptr m_parent; + details::IDpointer m_id; + + + /* Searches the global vertex in all local vertices of this graph, and returns the local + * one which holds the global vertex. If not successfull the local vertex returned will be + * invalid and the bool parameter will be false. If recursive = true, all subclusters will + * 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); + }; + + /* 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); + }; + + /* 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); + }; + + /* 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); + }; + + template + typename functor::result_type apply_to_bundle(LocalVertex k, functor f) { + return f((*this)[k]); + }; + + template + typename functor::result_type apply_to_bundle(LocalEdge k, functor f) { + return f((*this)[k]); + }; + + 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)->apply_to_bundle(k, 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]); + }; + + + }; +}; + +} //namespace solver + +#endif // CLUSTERGRAPH_HPP + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp new file mode 100644 index 0000000000..c2f74117fd --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/constraint.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 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 GCM_CONSTRAINT_H +#define GCM_CONSTRAINT_H + + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +#include "traits.hpp" +#include "object.hpp" +#include "equations.hpp" + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + +//type erasure container for constraints +template +class Constraint : public Object { + + typedef typename system_traits::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::DynStride DS; + + typedef boost::shared_ptr geom_ptr; + typedef std::vector > Vec; + +public: + Constraint(Sys& system, geom_ptr f, geom_ptr s); + ~Constraint(); + + virtual boost::shared_ptr clone(Sys& newSys); + +protected: + + template + void initialize(typename fusion::result_of::as_vector::type& obj); + + int equationCount(); + + template< typename creator_type> + void resetType(creator_type& c); + + void calculate(Scalar scale); + + 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 + template + struct EquationSet { + EquationSet() : m_diff_first(NULL,0,DS(0,0)), m_diff_second(NULL,0,DS(0,0)), + m_residual(NULL,0,DS(0,0)) {}; + + Equation m_eq; + typename Kernel::VectorMap m_diff_first; //first geometry diff + typename Kernel::VectorMap m_diff_second; //second geometry diff + typename Kernel::VectorMap m_residual; + + typedef Equation eq_type; + }; + + struct placeholder { + virtual ~placeholder() {} + virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0; + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale) = 0; + virtual int equationCount() = 0; + virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; + virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; + virtual placeholder* clone() = 0; + }; + +public: + template< typename ConstraintVector, typename EquationVector> + struct holder : public placeholder { + + //create a vector of EquationSets with some mpl trickery + typedef typename mpl::fold< EquationVector, mpl::vector<>, + mpl::push_back > >::type eq_set_vector; + typedef typename fusion::result_of::as_vector::type EquationSets; + + typedef typename fusion::result_of::as_vector::type Objects; + + template + struct has_option { + //we get the index of the eqaution in the eqaution vector, and as it is the same + //as the index of the constraint in the constraint vector we can extract the + //option type and check if it is no_option + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + typedef typename mpl::at::type option_type; + typedef mpl::not_ > type; + }; + + struct OptionSetter { + + Objects& objects; + + OptionSetter(Objects& val); + + //only set the value if the equation has a option + template< typename T > + typename boost::enable_if::type, void>::type + operator()(EquationSet& val) const; + //if the equation has no otpion we do nothing! + template< typename T > + typename boost::enable_if::type>, void>::type + operator()(EquationSet& val) const; + }; + + struct Calculater { + + geom_ptr first, second; + Scalar scale; + + Calculater(geom_ptr f, geom_ptr s, Scalar sc); + + template< typename T > + void operator()(T& val) const; + }; + + struct MapSetter { + MES& mes; + geom_ptr first, second; + + MapSetter(MES& m, geom_ptr f, geom_ptr s); + + template< typename T > + void operator()(T& val) const; + }; + + struct PseudoCollector { + Vec& points1; + Vec& points2; + geom_ptr first,second; + + PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); + + template< typename T > + void operator()(T& val) const; + }; + + holder(Objects& obj); + + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale); + virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; + virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); + virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); + virtual placeholder* clone(); + virtual int equationCount() { + return mpl::size::value; + }; + + EquationSets m_sets; + }; + +protected: + template< typename ConstraintVector > + struct creator : public boost::static_visitor { + + typedef typename fusion::result_of::as_vector::type Objects; + Objects& objects; + + creator(Objects& obj); + + template + struct equation { + typedef typename C::template type type; + }; + + template + void operator()(const T1&, const T2&); + + placeholder* p; + bool need_swap; + }; + + placeholder* content; + geom_ptr first, second; + Connection cf, cs; +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template +Constraint::Constraint(Sys& system, geom_ptr f, geom_ptr s) + : first(f), second(s), content(0) { + + this->m_system = &system; + 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 +boost::shared_ptr Constraint::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //copy the internals + np->content = content->clone(); + //and get the geometry pointers right + if(first) { + GlobalVertex v = first->template getProperty(); + np->first = newSys.m_cluster->template getObject(v); + } + if(second) { + GlobalVertex v = second->template getProperty(); + np->second = newSys.m_cluster->template getObject(v); + } + return np; +}; + +template +template +void Constraint::initialize(typename fusion::result_of::as_vector::type& obj) { + + //first create the new placeholder + creator c(obj); + boost::apply_visitor(c, first->m_geometry, second->m_geometry); + + //and now store it + content = c.p; + //geometry order needs to be the one needed by equations + if(c.need_swap) first.swap(second); + +}; + +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) { + content->calculate(first, second, scale); +}; + +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 +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 > >)); + val.m_eq.value = fusion::at(objects).value; +}; + +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) : first(f), second(s), scale(sc) { + +}; + +template +template +template< typename T > +void Constraint::holder::Calculater::operator()(T& val) const { + + 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<6; i++) { + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + } + } + } 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<6; i++) { + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, block); + } + } + } 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 { + + //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, 6, 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, 6, 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(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::holder(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) { + fusion::for_each(m_sets, Calculater(first, second, scale)); +}; + +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< typename ConstraintVector > +Constraint::creator::creator(Objects& obj) : objects(obj) { + +}; + +template +template< typename ConstraintVector > +template +void Constraint::creator::operator()(const T1&, const T2&) { + typedef tag_order< typename geometry_traits::tag, typename geometry_traits::tag > 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 + p = new holder(objects); + need_swap = order::swapt::value; +}; + + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp new file mode 100644 index 0000000000..0e391f48e8 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -0,0 +1,189 @@ +/* + 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 GCM_EQUATIONS_H +#define GCM_EQUATIONS_H + +#include + +namespace dcm { + +struct no_option {}; + +template +struct Pseudo { + typedef std::vector > Vec; + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; +}; + +template +struct Scale { + void setScale(typename Kernel::number_type scale) {}; +}; + +template +struct PseudoScale { + typedef std::vector > Vec; + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + void setScale(typename Kernel::number_type scale) {}; +}; + +struct Distance { + + typedef double option_type; + option_type value; + + Distance() : value(0) {}; + + Distance& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value; + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) { + assert(false); + }; + void setScale(Scalar scale) { + assert(false); + }; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +//the possible directions +enum Direction { Same, Opposite, Both }; + +struct Parallel { + + typedef Direction option_type; + option_type value; + + Parallel() : value(Both) {}; + + Parallel& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +struct Angle { + + typedef double option_type; + option_type value; + + Angle() : value(0) {}; + + Angle& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +//static is needed to restrain the scope of the objects to the current compilation unit. Without it +//every compiled file including this header would define these as global and the linker would find +//multiple definitions of the same objects +static Distance distance; +static Parallel parallel; +static Angle angle; + +}; + +#endif //GCM_EQUATIONS_H + diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp new file mode 100644 index 0000000000..045e685893 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -0,0 +1,481 @@ +/* + 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_H +#define GCM_GEOMETRY_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "object.hpp" +#include "traits.hpp" +#include "logging.hpp" +#include "transformation.hpp" + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace tag { + +struct undefined { + typedef mpl::int_<0> parameters; + typedef mpl::int_<0> transformations; +}; + +//we need to order tags, this values make it easy for module tags +namespace weight { +struct direction : mpl::int_<0> {}; +struct point : mpl::int_<1> {}; +struct line : mpl::int_<2> {}; +struct plane : mpl::int_<3> {}; +struct cylinder : mpl::int_<4> {}; +} +} + +struct orderd_bracket_accessor { + + template + Scalar get(T& t) { + return t[ID]; + }; + template + void set(Scalar value, T& t) { + t[ID] = value; + }; +}; + +struct orderd_roundbracket_accessor { + + template + Scalar get(T& t) { + return t(ID); + }; + template + void set(Scalar value, T& t) { + t(ID) = value; + }; +}; + +//tag ordering (smaller weight is first tag) +template +struct tag_order { + + BOOST_MPL_ASSERT((mpl::not_< mpl::or_< + boost::is_same< typename T1::weight, mpl::int_<0> >, + boost::is_same< typename T2::weight, mpl::int_<0> > > >)); + + typedef typename mpl::less::type swapt; + typedef typename mpl::if_::type first_tag; + typedef typename mpl::if_::type second_tag; +}; + + +//template +//struct type_order : public tag_order< typename geometry_traits::tag, typename geometry_traits::tag > {}; + + +template< typename T> +struct geometry_traits { + BOOST_MPL_ASSERT_MSG(false, NO_GEOMETRY_TRAITS_SPECIFIED_FOR_TYPE, (T)); +}; + +template< typename T> +struct geometry_clone_traits { + T operator()(T& val) { + return T(val); + }; +}; + +struct reset {}; //signal namespace + +namespace detail { + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +class Geometry : public Object) > >, + mpl::pair) > > , + mpl::pair)> > > > { + + typedef mpl::map3< mpl::pair) > >, + mpl::pair) > >, + mpl::pair)> > > Signals; + + typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; + typedef Object Base; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::DynStride DS; + typedef typename Kernel::template transform_type::type Transform; + typedef typename Kernel::template transform_type::diff_type DiffTransform; + + struct cloner : boost::static_visitor { + typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + +#ifdef USE_LOGGING +protected: + src::logger log; +#endif + +public: + typedef mpl::int_ Dimension; + + template + Geometry(T geometry, Sys& system); + + template + void set(T geometry); + + template + typename Visitor::result_type apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); + }; + + //basic ation + void transform(const Transform& t); + + virtual boost::shared_ptr clone(Sys& newSys); + + //allow accessing the internal values in unittests without making them public, + //so that access control of the internal classes is not changed and can be tested +#ifdef TESTING + typename Kernel::Vector& toplocal() { + return m_toplocal; + }; + typename Kernel::Vector& rotated() { + return m_rotated; + }; + int& offset() { + return m_offset; + }; + void clusterMode(bool iscluster, bool isFixed) { + setClusterMode(iscluster, isFixed); + }; + void trans(const Transform& t) { + transform(t); + }; + void recalc(DiffTransform& trans) { + recalculate(trans); + }; + typename Kernel::Vector3 point() { + return getPoint(); + }; + int parameterCount() { + return m_parameterCount; + }; +#endif + +//protected would be the right way, however, visual studio 10 does not find a way to access them even when constraint::holder structs +//are declared friend +//protected: + Variant m_geometry; //Variant holding the real geometry type + int m_BaseParameterCount; //count of the parameters the variant geometry type needs + int m_parameterCount; //count of the used parameters (when in cluster:6, else m_BaseParameterCount) + int m_offset; //the starting point of our parameters in the math system parameter vector + int m_rotations; //count of rotations to be done when original vector gets rotated + int m_translations; //count of translations to be done when original vector gets rotated + bool m_isInCluster, m_clusterFixed, m_init; + typename Kernel::Vector m_toplocal; //the local value in the toplevel cluster used for cuttent solving + typename Kernel::Vector m_global; //the global value outside of all clusters + typename Kernel::Vector m_rotated; //the global value as the rotation of toplocal (used as temp) + typename Kernel::Matrix m_diffparam; //gradient vectors combined as matrix when in cluster + typename Kernel::VectorMap m_parameter; //map to the parameters in the solver + + template + void init(T& t); + + void normalize(); + + typename Sys::Kernel::VectorMap& getParameterMap(); + void initMap(); + + void setClusterMode(bool iscluster, bool isFixed); + bool getClusterMode() { + return m_isInCluster; + }; + bool isClusterFixed() { + return m_clusterFixed; + }; + + void recalculate(DiffTransform& trans); + + typename Kernel::Vector3 getPoint() { + return m_toplocal.template segment(0); + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(typename Kernel::Vector& v) : value(v) {}; + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, value); + } + typename Kernel::Vector& value; + }; + + //use m_value or parametermap as new value, dependend on the solving mode + void finishCalculation(); + + template + void transform(const Transform& t, VectorType& vec); + void scale(Scalar value); +}; + + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +Geometry::Geometry(T geometry, Sys& system) + : m_isInCluster(false), m_geometry(geometry), m_parameter(NULL,0,DS(0,0)), + m_clusterFixed(false), m_init(false) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif + + this->m_system = &system; + init(geometry); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +void Geometry::set(T geometry) { + m_geometry = geometry; + init(geometry); + //Base::template emitSignal( ((Derived*)this)->shared_from_this() ); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +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 +boost::shared_ptr Geometry::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //it's possible that the variant contains pointers, so we need to clone them + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + return np; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +void Geometry::init(T& t) { + + m_BaseParameterCount = geometry_traits::tag::parameters::value; + m_parameterCount = m_BaseParameterCount; + m_rotations = geometry_traits::tag::rotations::value; + m_translations = geometry_traits::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(); + + (typename geometry_traits::modell()).template extract::accessor >(t, m_global); + 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 Sys, typename Derived, typename GeometrieTypeList, int Dim> +typename Sys::Kernel::VectorMap& Geometry::getParameterMap() { + m_isInCluster = false; + m_parameterCount = m_BaseParameterCount; + return m_parameter; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +void Geometry::initMap() { + //when direct parameter solving the global value is wanted (as it's the initial rotation*toplocal) + m_parameter = m_global; + m_init = true; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +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 Sys::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 Sys::Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +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 + }; + apply_visitor v(m_global); + apply(v); + m_init = false; + m_isInCluster = false; + + //emit the signal for recalculation + Base::template emitSignal( ((Derived*)this)->shared_from_this() ); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +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/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp new file mode 100644 index 0000000000..949e3b6549 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -0,0 +1,425 @@ +/* + 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_KERNEL_H +#define GCM_KERNEL_H + +#include +#include +#include + +#include + +#include +#include + +#include "transformation.hpp" +#include "logging.hpp" + + +namespace dcm { + +namespace E = Eigen; + +struct nothing { + void operator()() {}; +}; + +template +struct Dogleg { + +#ifdef USE_LOGGING + src::logger log; +#endif + + typedef typename Kernel::number_type number_type; + number_type tolg, tolx, tolf; + + Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-5) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif + }; + + template + int 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: "< + int solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale) { + + clock_t start = clock(); + clock_t inc_rec = clock(); + + if(!sys.isValid()) return 5; + + bool translate = true; + + typename Kernel::Vector h_dl, F_old(sys.m_eqns), g(sys.m_eqns); + typename Kernel::Matrix J_old(sys.m_eqns, sys.m_params); + + sys.recalculate(); + +#ifdef USE_LOGGING + BOOST_LOG(log)<< "initial jacobi: "<(); +#endif + + number_type 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 + number_type g_inf = g.template lpNorm(); + number_type fx_inf = sys.Residual.template lpNorm(); + + int maxIterNumber = 10000;//MaxIterations * xsize; + number_type diverging_lim = 1e6*err + 1e12; + + number_type delta=5; + number_type nu=2.; + int iter=0, stop=0, reduce=0, unused=0, counter=0; + + + while(!stop) { + + // check if finished + if(fx_inf <= tolf*sys.Scaling) // Success + stop = 1; + else if(g_inf <= tolg) + stop = 2; + else if(delta <= tolx) + stop = 3; + else if(iter >= maxIterNumber) + stop = 4; + else if(!boost::math::isfinite(err)) + stop = 5; + else if(err > diverging_lim) + stop = 6; + + + // 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; + + clock_t start_rec = clock(); + sys.recalculate(); + clock_t end_rec = clock(); + inc_rec += end_rec-start_rec; + +#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 = Dogleg> +struct Kernel { + + //basics + typedef Scalar number_type; + + //linear algebra types 2D + typedef E::Matrix Vector2; + + //Linear algebra types 3D + typedef E::Matrix Vector3; + typedef E::Matrix CVector3; + typedef E::Matrix Matrix3; + typedef E::Matrix Vector; + typedef E::Matrix CVector; + typedef E::Matrix Matrix; + + //mapped types + typedef E::Stride DynStride; + typedef E::Map< Vector3 > Vector3Map; + typedef E::Map< CVector3> CVector3Map; + typedef E::Map< Matrix3 > Matrix3Map; + typedef E::Map< Vector, 0, DynStride > VectorMap; + typedef E::Map< CVector, 0, DynStride > CVectorMap; + typedef E::Map< Matrix, 0, DynStride > MatrixMap; + + //Special types + typedef E::Quaternion Quaternion; + typedef E::Matrix Matrix39; + typedef E::Map< Matrix39 > Matrix39Map; + typedef E::Block MatrixBlock; + + typedef detail::Transform Transform3D; + typedef detail::DiffTransform DiffTransform3D; + + typedef detail::Transform Transform2D; + typedef detail::DiffTransform DiffTransform2D; + + typedef Nonlinear< Kernel > NonlinearSolver; + + template + struct transform_type { + typedef typename boost::mpl::if_c::type type; + typedef typename boost::mpl::if_c::type diff_type; + }; + + template + struct vector_type { + typedef E::Matrix type; + }; + + + struct MappedEquationSystem { + + Matrix Jacobi; + Vector Parameter; + Vector Residual; + number_type Scaling; + int m_params, m_eqns; //total amount + int m_param_offset, m_eqn_offset; //current positions while creation + + MappedEquationSystem(int params, int equations) + : Jacobi(equations, params), + Parameter(params), Residual(equations), + m_params(params), m_eqns(equations), Scaling(1.) { + + m_param_offset = 0; + m_eqn_offset = 0; + + Jacobi.setZero(); //important as some places are never written + }; + + int setParameterMap(int number, VectorMap& map) { + + new(&map) VectorMap(&Parameter(m_param_offset), number, DynStride(1,1)); + m_param_offset += number; + return m_param_offset-number; + }; + int setParameterMap(Vector3Map& map) { + + new(&map) Vector3Map(&Parameter(m_param_offset)); + m_param_offset += 3; + return m_param_offset-3; + }; + int setResidualMap(VectorMap& map) { + new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1)); + return m_eqn_offset++; + }; + void setJacobiMap(int eqn, int offset, int number, CVectorMap& map) { + new(&map) CVectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + }; + void setJacobiMap(int eqn, int offset, int number, VectorMap& map) { + new(&map) VectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + }; + + bool isValid() { + if(!m_params || !m_eqns) return false; + return true; + }; + + virtual void recalculate() = 0; + + }; + + Kernel() {}; + + template + static bool isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1-p2).squaredNorm() < 0.00001); + } + static bool isSame(number_type t1, number_type t2) { + return (std::abs(t1-t2) < 0.00001); + } + template + static bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1+p2).squaredNorm() < 0.00001); + } + + static int solve(MappedEquationSystem& mes) { + nothing n; + return Nonlinear< Kernel >().solve(mes, n); + }; + + template + static int solve(MappedEquationSystem& mes, Functor& f) { + return Nonlinear< Kernel >().solve(mes, f); + }; + +}; + +} + +#endif //GCM_KERNEL_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/logging.hpp b/src/Mod/Assembly/App/opendcm/core/logging.hpp new file mode 100644 index 0000000000..fd915a36fb --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/logging.hpp @@ -0,0 +1,94 @@ +/* + 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_LOGGING_H +#define GCM_LOGGING_H + +#ifdef USE_LOGGING + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace logging = boost::log; +namespace sinks = boost::log::sinks; +namespace src = boost::log::sources; +namespace fmt = boost::log::formatters; +namespace flt = boost::log::filters; +namespace attrs = boost::log::attributes; +namespace keywords = boost::log::keywords; + +namespace dcm { + +static int counter = 0; +typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t; + +inline boost::shared_ptr< sink_t > init_log() { + + //create the filename + std::stringstream str; + str<<"openDCM_"< core = logging::core::get(); + + boost::shared_ptr< sinks::text_file_backend > backend = + boost::make_shared< sinks::text_file_backend >( + keywords::file_name = str.str(), //file name pattern + keywords::rotation_size = 10 * 1024 * 1024 //Rotation size is 10MB + ); + + // Wrap it into the frontend and register in the core. + // The backend requires synchronization in the frontend. + boost::shared_ptr< sink_t > sink(new sink_t(backend)); + + sink->set_formatter( + fmt::stream <<"[" << fmt::attr("Tag") <<"] " + << fmt::if_(flt::has_attr("ID")) [ + fmt::stream << "["<< fmt::attr< std::string >("ID")<<"] "] + << fmt::message() + ); + + core->add_sink(sink); + return sink; +}; + +inline void stop_log(boost::shared_ptr< sink_t >& sink) { + + boost::shared_ptr< logging::core > core = logging::core::get(); + + // Remove the sink from the core, so that no records are passed to it + core->remove_sink(sink); + sink.reset(); +}; + +}; //dcm + +#endif //USE_LOGGING + +#endif //GCM_LOGGING_H diff --git a/src/Mod/Assembly/App/opendcm/core/object.hpp b/src/Mod/Assembly/App/opendcm/core/object.hpp new file mode 100644 index 0000000000..09a1d1ac3e --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/object.hpp @@ -0,0 +1,269 @@ +/* + 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_H +#define GCM_OBJECT_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "property.hpp" + + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +#define EMIT_ARGUMENTS(z, n, data) \ + BOOST_PP_CAT(data, n) + +#define EMIT_CALL_DEF(z, n, data) \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ); + +#define EMIT_CALL_DEC(z, n, data) \ + template \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void Object::emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ + { \ + typedef typename mpl::find::type iterator; \ + typedef typename mpl::distance::type, iterator>::type distance; \ + typedef typename fusion::result_of::value_at::type list_type; \ + list_type& list = fusion::at(m_signals); \ + for (typename list_type::iterator it=list.begin(); it != list.end(); it++) \ + (*it)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + }; + +namespace dcm { + +//few standart signal names +struct remove {}; +struct recalculated {}; + +typedef boost::any Connection; + +/** + * @brief Base class for all object types + * + * This class add's property and signal capabilitys to all deriving classes. For properties it is tigthly + * integrated with the system class: It searches systems property list for the derived class as specified by + * the second template parameter and makes it accessible via appopriate functions. Signals are speciefied by a + * mpl::map with signal name type as key and a boost::function as values. + * + * \tparam Sys class of type System of which the properties are taken + * \tparam Obj the type of the derived object + * \tparam Sig a mpl::map specifing the object's signals by (type - boost::function) pairs + **/ +template +struct Object : public boost::enable_shared_from_this { + + Object() {}; + Object(Sys& system); + + /** + * @brief Create a new object of the same type with the same values + * + * Returns a new shared_ptr for the Drived type with the same properties as the initial one. If + * the new pointer should be used in a new system the parameter \param newSys needs to be that + * new system. Overload this function if you have datamembers in any derived class wich are not + * copyconstructable. + * @tparam Prop property type which should be accessed + * @return Prop::type& a reference to the properties actual value. + **/ + virtual boost::shared_ptr clone(Sys& newSys); + + /** + * @brief Access properties + * + * Returns a reference to the propertys actual value. The property type has to be registerd to the + * System type which was given as template parameter to this object. + * @tparam Prop property type which should be accessed + * @return Prop::type& a reference to the properties actual value. + **/ + template + typename Prop::type& getProperty(); + + /** + * @brief Set properties + * + * Set'S the value of a specified property. The property type has to be registerd to the + * System type which was given as template parameter to this object. Note that setProperty(value) + * is equivalent to getProperty() = value. + * @tparam Prop property type which should be setProperty + * @param value value of type Prop::type which should be set in this object + **/ + template + void setProperty(typename Prop::type value); + + /** + * @brief Connects a slot to a specified signal. + * + * Slots are boost::functions which get called when the signal is emitted. Any valid boost::function + * which ressembles the signal tyes signature can be registert. It is important that the signal type + * was registerd to this object on creation by the appropriate template parameter. + * + * @tparam S the signal which should be intercepted + * @param function boost::function which resembles the signal type's signature + * @return void + **/ + template + Connection connectSignal(typename mpl::at::type function); + + /** + * @brief Disconnects a slot for a specific signal. + * + * Disconnects a slot so that it dosn't get called at signal emittion. It's important to + * disconnect the slot by the same boost:function it was connected with. + * + * @tparam S the signal type of interest + * @param function boost::function with which the slot was connected + * @return void + **/ + template + void disconnectSignal(Connection c); + + /*properties + * search the property map of the system class and get the mpl::vector of properties for the + * derived type. It's imortant to not store the properties but their types. These types are + * stored and accessed as fusion vector. + * */ + typedef typename mpl::at::type Mapped; + typedef typename mpl::if_< boost::is_same, mpl::vector0<>, Mapped>::type Sequence; + typedef typename details::pts::type Properties; + + Properties m_properties; + Sys* m_system; + +protected: + /*signal handling + * extract all signal types to allow index search (inex search on signal functions would fail as same + * signatures are supported for multiple signals). Create std::vectors to allow multiple slots per signal + * and store these vectors in a fusion::vector for easy access. + * */ + typedef typename mpl::fold< Sig, mpl::vector<>, + mpl::push_back > >::type sig_name; + typedef typename mpl::fold< Sig, mpl::vector<>, + mpl::push_back > >::type sig_functions; + typedef typename mpl::fold< sig_functions, mpl::vector<>, + mpl::push_back > >::type sig_vectors; + typedef typename fusion::result_of::as_vector::type Signals; + + Signals m_signals; + +public: + //with no vararg templates before c++11 we need preprocessor to create the overloads of emit signal we need + BOOST_PP_REPEAT(5, EMIT_CALL_DEF, ~) +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +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 +template +typename Prop::type& Object::getProperty() { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(m_properties); +}; + +template +template +void Object::setProperty(typename Prop::type value) { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + fusion::at(m_properties) = value; +}; + +template +template +Connection Object::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 list_type; + list_type& list = fusion::at(m_signals); + return list.insert(list.begin(),function); +}; + +template +template +void Object::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 list_type; + list_type& list = fusion::at(m_signals); + list.erase(boost::any_cast(c)); +}; + +BOOST_PP_REPEAT(5, EMIT_CALL_DEC, ~) + +} + +#endif //GCM_OBJECT_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp new file mode 100644 index 0000000000..dd7b68bbaa --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -0,0 +1,167 @@ +/* + 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_PROPERTY_H +#define GCM_PROPERTY_H + +#include +#include +#include +#include + +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +struct vertex_property {}; +struct edge_property {}; +struct cluster_property {}; +struct object_property {}; + +namespace details { + +template +struct vertex_selector { + typedef typename boost::graph_traits::vertex_descriptor key_type; + typedef typename Graph::vertex_properties sequence_type; +}; + +template +struct edge_selector { + typedef typename boost::graph_traits::edge_descriptor key_type; + typedef typename Graph::edge_properties sequence_type; +}; + +template< typename Kind, typename Graph> +struct property_selector : public mpl::if_, + vertex_selector, edge_selector >::type {}; + +template +struct property_type { + typedef typename T::type type; +}; +template +struct property_kind { + typedef typename T::kind type; +}; + +//property vector to a fusion sequence of the propety types +template +struct pts { //property type sequence + typedef typename mpl::transform >::type ptv; + typedef typename fusion::result_of::as_vector< ptv >::type type; +}; +} + +template +struct is_edge_property : boost::is_same {}; + +template +struct is_vertex_property : boost::is_same {}; + +template +struct is_cluster_property : boost::is_same {}; + +template +struct is_object_property : boost::is_same {}; + +template +class property_map { + +public: + typedef typename dcm::details::property_selector::key_type key_type; + typedef typename Property::type value_type; + typedef typename Property::type& reference; + typedef boost::lvalue_property_map_tag category; + + typedef Property property; + typedef typename dcm::details::property_selector::sequence_type sequence; + + property_map(Graph& g) + : m_graph(g) { } + + Graph& m_graph; +}; + +template +typename property_map::value_type get(const property_map& map, + typename property_map::key_type key) { + + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + return fusion::at(fusion::at_c<0>(map.m_graph[key])); +}; + +template +void put(const property_map& map, + typename property_map::key_type key, + const typename property_map::value_type& value) { + + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + fusion::at(fusion::at_c<0>(map.m_graph[key])) = value; +}; + + +template +typename property_map::reference at(const property_map& map, + typename property_map::key_type key) { + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + return fusion::at(fusion::at_c<0>(map.m_graph[key])); +} + + +//now create some standart properties +//*********************************** + +struct empty_prop { + typedef int kind; + typedef int type; +}; + +struct type_prop { + //states the type of a cluster + typedef cluster_property kind; + typedef int type; +}; + +struct changed_prop { + typedef cluster_property kind; + typedef bool type; +}; + +template +struct id_prop { + typedef object_property kind; + typedef T type; +}; + +} + + +#endif //GCM_PROPERTY_H diff --git a/src/Mod/Assembly/App/opendcm/core/sheduler.hpp b/src/Mod/Assembly/App/opendcm/core/sheduler.hpp new file mode 100644 index 0000000000..873caf6ba3 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/sheduler.hpp @@ -0,0 +1,100 @@ +/* + 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_SHEDULER_H +#define GCM_SHEDULER_H + +#include +#include + +namespace dcm { + +template +struct Job { + + virtual ~Job() {}; + + virtual void execute(Sys& sys) = 0; + + bool operator<(const Job& j) const { + return priority < j.priority; + }; + int priority; +}; + +template +struct FunctorJob : Job { + FunctorJob(functor f) : m_functor(f) { + Job::priority = prior; + }; + virtual void execute(System& sys) { + m_functor(sys); + }; + + functor m_functor; +}; + +template +class Sheduler { + +public: + Sheduler() {}; + ~Sheduler() { + + std::for_each(m_preprocess.begin(), m_preprocess.end(), Deleter()); + std::for_each(m_process.begin(), m_process.end(), Deleter()); + std::for_each(m_postprocess.begin(), m_postprocess.end(), Deleter()); + }; + + void addPreprocessJob(Job* j) { + m_preprocess.insert(j); + }; + void addPostprocessJob(Job* j) { + m_postprocess.insert(j); + }; + void addProcessJob(Job* j) { + m_process.insert(j); + }; + + void execute(Sys& system) { + std::for_each(m_preprocess.begin(), m_preprocess.end(), Executer(system)); + std::for_each(m_process.begin(), m_process.end(), Executer(system)); + std::for_each(m_postprocess.begin(), m_postprocess.end(), Executer(system)); + }; + +protected: + struct Executer { + Executer(Sys& s) : m_system(s) {}; + void operator()(Job* j) { + j->execute(m_system); + }; + Sys& m_system; + }; + struct Deleter { + void operator()(Job* j) { + delete j; + }; + }; + + std::set< Job* > m_preprocess, m_process, m_postprocess; +}; + +} + +#endif //GCM_SHEDULER_H diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp new file mode 100644 index 0000000000..16c931cf4d --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -0,0 +1,327 @@ +/* + 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_SYSTEM_H +#define GCM_SYSTEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "property.hpp" +#include "clustergraph.hpp" +#include "sheduler.hpp" +#include "logging.hpp" +#include "traits.hpp" + +namespace mpl = boost::mpl; + +namespace dcm { + +struct No_Identifier {}; +struct Unspecified_Identifier {}; + + +namespace details { + +enum { subcluster = 10}; + +template +struct vector_fold : mpl::fold< seq, state, + mpl::push_back > {}; + +template +struct edge_fold : mpl::fold< seq, state, + mpl::if_< is_edge_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct vertex_fold : mpl::fold< seq, state, + mpl::if_< is_vertex_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct cluster_fold : mpl::fold< seq, state, + mpl::if_< is_cluster_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct obj_fold : mpl::fold< seq, state, + mpl::if_< mpl::or_< + boost::is_same< details::property_kind, obj>, is_object_property >, + mpl::push_back, mpl::_1 > > {}; + +template +struct property_map { + typedef typename mpl::fold< + objects, mpl::map<>, mpl::insert< mpl::_1, mpl::pair< + mpl::_2, details::obj_fold, mpl::_2 > > > >::type type; +}; +template +struct get_identifier { + typedef typename T::Identifier type; +}; + +template +struct map_fold : mpl::fold< seq, state, mpl::insert > {}; + +struct nothing {}; + +template +struct EmptyModule { + + template + struct type { + struct inheriter {}; + typedef mpl::vector<> properties; + typedef mpl::vector<> objects; + typedef Unspecified_Identifier Identifier; + + static void system_init(T& sys) {}; + static void system_copy(const T& from, T& into) {}; + }; +}; + +template +struct is_shared_ptr : boost::mpl::false_ {}; +template +struct is_shared_ptr > : boost::mpl::true_ {}; + +} + +template< typename KernelType, + typename T1 = details::EmptyModule<1>, + typename T2 = details::EmptyModule<2>, + typename T3 = details::EmptyModule<3> > +class System : public T1::template type< System >::inheriter, + public T2::template type< System >::inheriter, + public T3::template type< System >::inheriter { + + typedef System BaseType; +public: + typedef typename T1::template type< BaseType > Type1; + typedef typename T2::template type< BaseType > Type2; + typedef typename T3::template type< BaseType > Type3; + typedef mpl::vector3 TypeVector; + + //Check if all Identifiers are the same and find out which type it is + typedef typename mpl::fold, + mpl::if_, Unspecified_Identifier>, + mpl::_1, mpl::push_back > > >::type Identifiers; + BOOST_MPL_ASSERT((mpl::or_< + mpl::less_equal::type, mpl::int_<1> >, + mpl::equal< typename mpl::count >::type, typename mpl::size::type > >)); + + typedef typename mpl::if_< mpl::empty, + No_Identifier, typename mpl::at_c::type >::type Identifier; + + +public: + //get all module objects and properties + typedef typename details::vector_fold >::type >::type>::type objects; + + typedef typename details::vector_fold > >::type >::type>::type properties; + + //make the subcomponent lists of objects and properties + typedef typename details::edge_fold< properties, mpl::vector<> >::type edge_properties; + typedef typename details::vertex_fold< properties, mpl::vector<> >::type vertex_properties; + typedef typename details::cluster_fold< properties, + mpl::vector >::type cluster_properties; + + typedef typename details::property_map::type object_properties; + +protected: + //object storage + typedef typename mpl::transform >::type sp_objects; + typedef typename mpl::fold< sp_objects, mpl::vector<>, + mpl::push_back > >::type object_vectors; + typedef typename fusion::result_of::as_vector::type Storage; + + template + friend struct Object; + + struct clearer { + template + void operator()(T& vector) const { + vector.clear(); + }; + }; + +#ifdef USE_LOGGING + boost::shared_ptr< sink_t > sink; +#endif + +public: + typedef ClusterGraph Cluster; + typedef Sheduler< BaseType > Shedule; + typedef KernelType Kernel; + +public: + 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); + + }; + + + ~System() { +#ifdef USE_LOGGING + stop_log(sink); +#endif + }; + + void clear() { + + m_cluster->clearClusters(); + m_cluster->clear(); + fusion::for_each(*m_storage, clearer()); + }; + + template + typename std::vector< boost::shared_ptr >::iterator 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 std::vector< boost::shared_ptr >::iterator 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 + std::vector< boost::shared_ptr >& 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 + void push_back(boost::shared_ptr ptr) { + objectVector().push_back(ptr); + }; + + template + void erase(boost::shared_ptr ptr) { + + std::vector< boost::shared_ptr >& vec = objectVector(); + vec.erase(std::remove(vec.begin(), vec.end(), ptr), vec.end()); + }; + + void solve() { + clock_t start = clock(); + m_sheduler.execute(*this); + clock_t end = clock(); + double ms = (double(end-start)* 1000.) / double(CLOCKS_PER_SEC); + //Base::Console().Message("overall solving time in ms: %f\n", ms); + + }; + + System* createSubsystem() { + + System* s = new System(); + s->m_cluster = m_cluster->createCluster().first; + s->m_storage = m_storage; + s->m_cluster->template setClusterProperty(details::subcluster); + return s; + }; + +private: + 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 {}; + }; + +public: + void copyInto(System& into) const { + + //copy the clustergraph and clone all objects while at it. They are also pushed to the storage + cloner cl(into); + m_cluster->copyInto(into.m_cluster, cl); + + //notify all modules that they are copied + Type1::system_copy(*this, into); + Type2::system_copy(*this, into); + Type3::system_copy(*this, into); + }; + + System* clone() const { + + System* ns = new System(); + this->copyInto(*ns); + return ns; + }; + + boost::shared_ptr m_cluster; + boost::shared_ptr m_storage; + Shedule m_sheduler; + Kernel m_kernel; +}; + +} +#endif //GCM_SYSTEM_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/traits.hpp b/src/Mod/Assembly/App/opendcm/core/traits.hpp new file mode 100644 index 0000000000..1d296f820a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/traits.hpp @@ -0,0 +1,101 @@ +/* + 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_TRAITS_H +#define GCM_TRAITS_H + +#include +#include +#include + +#include +#include +#include + +#include + +namespace mpl = boost::mpl; + +namespace dcm { + +template< typename T > +struct system_traits { + typedef typename T::Kernel Kernel; + typedef typename T::Cluster Cluster; + + template + struct getModule { + + typedef typename mpl::if_< boost::is_base_of, typename T::Type1, typename T::Type2 >::type test1; + typedef typename mpl::if_< boost::is_base_of, test1, typename T::Type3 >::type test2; + typedef typename mpl::if_< boost::is_base_of, test2, mpl::void_ >::type type; + + typedef boost::is_same has_module; + }; +}; + +template +struct compare_traits { + + BOOST_MPL_ASSERT_MSG((mpl::not_ >::value), + YOU_SHOULD_NOT_USE_THIS_TYPE_AS_IDENTIFIER, + (const char*)); + + static bool compare(T& first, T& second) { + return first == second; + }; +}; + +template<> +struct compare_traits { + + static bool compare(std::string& first, std::string& second) { + return !(first.compare(second)); + }; +}; + +template +struct vector_shrink { + typedef typename mpl::copy< seq, mpl::back_inserter< mpl::vector<> > >::type type; +}; + +template +struct vector_shrink< seq, 0 > { + typedef mpl::vector0<> type; +}; +template +struct vector_shrink< seq, 1 > { + typedef mpl::vector1< typename mpl::at_c< seq, 0 >::type > type; +}; + +#define SEQ_TYPES(z, n, data) \ + typename mpl::at_c< seq, n >::type + +#define VECTOR_SHRINK(z, n, data) \ + template< typename seq> \ + struct vector_shrink { \ + typedef BOOST_PP_CAT(mpl::vector, n) < \ + BOOST_PP_ENUM(n, SEQ_TYPES, ~) > type; \ + }; + + BOOST_PP_REPEAT_FROM_TO(2,10, VECTOR_SHRINK, ~) + +}//namespace dcm + +#endif //GCM_TRAITS_H diff --git a/src/Mod/Assembly/App/opendcm/core/transformation.hpp b/src/Mod/Assembly/App/opendcm/core/transformation.hpp new file mode 100644 index 0000000000..cec6c0d469 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/transformation.hpp @@ -0,0 +1,292 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef DCM_TRANSFORMATION_H +#define DCM_TRANSFORMATION_H + +#include +#include +#include + +#include + +namespace dcm { +namespace detail { + +template +class Transform { + +public: + typedef Eigen::Matrix Vector; + typedef typename boost::mpl::if_c< Dim == 3, + Eigen::Quaternion, + Eigen::Rotation2D >::type Rotation; + typedef Eigen::Translation Translation; + typedef Eigen::UniformScaling Scaling; + typedef typename Rotation::RotationMatrixType RotationMatrix; + +protected: + Rotation m_rotation; + Translation m_translation; + Scaling m_scale; + +public: + Transform() : m_rotation(Rotation::Identity()), + m_translation(Translation::Identity()), + m_scale(Scaling(1.)) { }; + + Transform(const Rotation& r) : m_rotation(r), + m_translation(Translation::Identity()), + m_scale(Scaling(1.)) { + m_rotation.normalize(); + }; + + Transform(const Rotation& r, const Translation& t) : m_rotation(r), + m_translation(t), + m_scale(Scaling(1.)) { + m_rotation.normalize(); + }; + + Transform(const Rotation& r, const Translation& t, const Scaling& s) : m_rotation(r), + m_translation(t), + m_scale(s) { + m_rotation.normalize(); + }; + + //access the single parts and manipulate them + //*********************** + const Rotation& rotation() const { + return m_rotation; + } + template + Transform& rotate(const Eigen::RotationBase& rotation) { + m_rotation = rotation.derived().normalized()*m_rotation; + return *this; + } + + const Translation& translation() const { + return m_translation; + } + Transform& translate(const Translation& translation) { + m_translation = m_translation*translation; + return *this; + } + + const Scaling& scaling() const { + return m_scale; + } + Transform& scale(const Scalar& scaling) { + m_scale *= Scaling(scaling); + return *this; + } + Transform& scale(const Scaling& scaling) { + m_scale.factor() *= scaling.factor(); + return *this; + } + + Transform& invert() { + m_rotation = m_rotation.inverse(); + m_translation.vector() = (m_rotation*m_translation.vector()) * (-m_scale.factor()); + m_scale = Scaling(1./m_scale.factor()); + return *this; + }; + Transform inverse() { + Transform res(*this); + res.invert(); + return res; + }; + + //operators for value manipulation + //******************************** + + inline Transform& operator=(const Translation& t) { + m_translation = t; + m_rotation = Rotation::Identity(); + m_scale = Scaling(1.); + return *this; + } + inline Transform operator*(const Translation& t) const { + Transform res = *this; + res.translate(t); + return res; + } + inline Transform& operator*=(const Translation& t) { + return translate(t); + } + + inline Transform& operator=(const Scaling& s) { + m_scale = s; + m_translation = Translation::Identity(); + m_rotation = Rotation::Identity(); + return *this; + } + inline Transform operator*(const Scaling& s) const { + Transform res = *this; + res.scale(s); + return res; + } + inline Transform& operator*=(const Scaling& s) { + return scale(s); + } + + template + inline Transform& operator=(const Eigen::RotationBase& r) { + m_rotation = r.derived(); + m_rotation.normalize(); + m_translation = Translation::Identity(); + m_scale = Scaling(1); + return *this; + } + template + inline Transform operator*(const Eigen::RotationBase& r) const { + Transform res = *this; + res.rotate(r.derived()); + return res; + } + template + inline Transform& operator*=(const Eigen::RotationBase& r) { + return rotate(r.derived()); + } + + inline Transform operator* (const Transform& other) const { + Transform res(*this); + res*= other; + return res; + } + inline Transform& operator*= (const Transform& other) { + rotate(other.rotation()); + other.rotate(m_translation.vector()); + m_translation.vector() += other.translation().vector()/m_scale.factor(); + m_scale.factor() *= other.scaling().factor(); + return *this; + } + + //transform Vectors + //***************** + template + inline Derived& rotate(Eigen::MatrixBase& vec) const { + vec = m_rotation*vec; + return vec.derived(); + } + template + inline Derived& translate(Eigen::MatrixBase& vec) const { + vec = m_translation*vec; + return vec.derived(); + } + template + inline Derived& scale(Eigen::MatrixBase& vec) const { + vec*=m_scale.factor(); + return vec.derived(); + } + template + inline Derived& transform(Eigen::MatrixBase& vec) const { + vec = (m_rotation*vec + m_translation.vector())*m_scale.factor(); + return vec.derived(); + } + template + inline Derived operator*(const Eigen::MatrixBase& vec) const { + return (m_rotation*vec + m_translation.vector())*m_scale.factor(); + } + template + inline void operator()(Eigen::MatrixBase& vec) const { + transform(vec); + } + + //Stuff + //***** + bool isApprox(const Transform& other, Scalar prec) const { + return m_rotation.isApprox(other.rotation(), prec) + && ((m_translation.vector()- other.translation().vector()).norm() < prec) + && (std::abs(m_scale.factor()-other.scaling().factor()) < prec); + }; + void setIdentity() { + m_rotation.setIdentity(); + m_translation = Translation::Identity(); + m_scale = Scaling(1.); + } + static const Transform Identity() { + return Transform(Rotation::Identity(), Translation::Identity(), Scaling(1)); + } + + Transform& normalize() { + m_rotation.normalize(); + return *this; + } +}; + +template +class DiffTransform : public Transform { + + typedef typename Transform::Rotation Rotation; + typedef typename Transform::Translation Translation; + typedef typename Transform::Scaling Scaling; + typedef Eigen::Matrix DiffMatrix; + + DiffMatrix m_diffMatrix; + +public: + DiffTransform() : Transform() { }; + DiffTransform(const Rotation& r) : Transform(r) {}; + DiffTransform(const Rotation& r, const Translation& t) : Transform(r,t) {}; + DiffTransform(const Rotation& r, const Translation& t, const Scaling& s) : Transform(r,t,s) {}; + + DiffTransform(Transform& trans) + : Transform(trans.rotation(), trans.translation(), trans.scaling()) { + + m_diffMatrix.setZero(); + }; + + const DiffMatrix& differential() { + return m_diffMatrix; + }; + inline Scalar& operator()(int f, int s) { + return m_diffMatrix(f,s); + }; + inline Scalar& at(int f, int s) { + return m_diffMatrix(f,s); + }; +}; + +}//detail +}//DCM + +/*When you overload a binary operator as a member function of a class the overload is used + * when the first operand is of the class type.For stream operators, the first operand + * is the stream and not (usually) the custom class. +*/ +template +std::ostream& operator<<(std::ostream& os, const dcm::detail::Transform& t) { + os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl + << "Translation: " << t.translation().vector().transpose() < +std::ostream& operator<<(std::ostream& os, dcm::detail::DiffTransform& t) { + os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl + << "Translation: " << t.translation().vector().transpose() < + + 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_EXTERNALIZE_H +#define DCM_EXTERNALIZE_H + +#include +#include +#include + +#ifdef USE_EXTERNAL + +#define DCM_EXTERNAL_INCLUDE_001 +#define DCM_EXTERNAL_001( System )\ + template struct dcm::details::edge_generator; \ + template struct dcm::details::vertex_generator; \ + + +#define DCM_EXTERNAL_INCLUDE_002 +#define DCM_EXTERNAL_002( System )\ + template struct dcm::details::obj_gen; \ + +#define DCM_EXTERNAL_INCLUDE_003 +#define DCM_EXTERNAL_003( System )\ + template struct dcm::details::vertex_prop_gen; \ + template struct dcm::details::edge_prop_gen; \ + template struct dcm::details::cluster_prop_gen; + +#define DCM_EXTERNAL_INCLUDE_004 +#define DCM_EXTERNAL_004( System )\ + template struct dcm::generator; \ + +#define DCM_EXTERNAL_INCLUDE_005 +#define DCM_EXTERNAL_005( System )\ + template struct dcm::details::vertex_prop_par; \ + template struct dcm::details::edge_prop_par; \ + template struct dcm::details::cluster_prop_par; + +#define DCM_EXTERNAL_INCLUDE_006 +#define DCM_EXTERNAL_006( System )\ + template struct dcm::details::obj_par; \ + +#define DCM_EXTERNAL_INCLUDE_007 +#define DCM_EXTERNAL_007( System )\ + template struct dcm::details::edge_parser; \ + template struct dcm::details::vertex_parser; \ + +#define DCM_EXTERNAL_INCLUDE_008 +#define DCM_EXTERNAL_008( System )\ + template struct dcm::parser; \ + +#else +#define DCM_EXTERNALIZE( System ) +#endif + +#endif //DCM_EXTERNALIZE_H + diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp new file mode 100644 index 0000000000..a62bbb59a0 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -0,0 +1,32 @@ +/* + 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_MODULE3D_H +#define DCM_MODULE3D_H + +#define DCM_USE_MODULE3D + +#include "module3d/geometry.hpp" +#include "module3d/distance.hpp" +#include "module3d/parallel.hpp" +#include "module3d/angle.hpp" +#include "module3d/module.hpp" + +#endif //DCM_MODULE3D_H + diff --git a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp new file mode 100644 index 0000000000..94d9e9efbe --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp @@ -0,0 +1,149 @@ +/* + 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 GCM_ANGLE_HPP +#define GCM_ANGLE_HPP + +#include "geometry.hpp" + +namespace dcm { + +//the calculations( same as we always calculate directions we can outsource the work to this functions) +namespace angle_detail { + +template +inline typename Kernel::number_type calc(T d1, + T d2, + typename Kernel::number_type angle) { + + return d1.dot(d2) / (d1.norm()*d2.norm()) - angle; +}; + + +template +inline typename Kernel::number_type calcGradFirst(T d1, + T d2, + T dd1) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + return dd1.dot(d2)/norm - (d1.dot(d2) * (d1.dot(dd1)/d1.norm())*d2.norm()) / std::pow(norm,2); +}; + +template +inline typename Kernel::number_type calcGradSecond(T d1, + T d2, + T dd2) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + return d1.dot(dd2)/norm - (d1.dot(d2) * (d2.dot(dd2)/d2.norm())*d1.norm()) / std::pow(norm,2); +}; + +template +inline void calcGradFirstComp(T d1, + T d2, + T grad) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + grad = d2/norm - (d1.dot(d2)/std::pow(norm,2))*d1/d1.norm(); +}; + +template +inline void calcGradSecondComp(T d1, + T d2, + T grad) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + grad = d1/norm - (d1.dot(d2)/std::pow(norm,2))*d2/d2.norm(); +}; + +} +/* +template< typename Kernel, typename Tag1, typename Tag2 > +struct Angle3D { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + Scalar m_angle; + + Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; + + //template definition + void setScale(Scalar scale){ + assert(false); + }; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; +}; + +template< typename Kernel > +struct Angle3D< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Scalar m_angle; + + Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; + + Scalar getEquationScaling(typename Kernel::Vector& local1, typename Kernel::Vector& local2) { + return 1.; + } + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return angle::calc(param1.template tail<3>(), param2.template tail<3>(), m_angle); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return angle::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>()); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return angle::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>()); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + angle::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + angle::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + }; +}; + +//planes like lines have the direction as segment 3-5, so we can use the same implementations +template< typename Kernel > +struct Angle3D< Kernel, tag::plane3D, tag::plane3D > : public Angle3D {}; +template< typename Kernel > +struct Angle3D< Kernel, tag::line3D, tag::plane3D > : public Angle3D {}; +*/ +} + +#endif //GCM_ANGLE_HPP \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp new file mode 100644 index 0000000000..13cb030ccb --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -0,0 +1,770 @@ +/* + 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_CLUSTERMATH_H +#define GCM_CLUSTERMATH_H + +#include +#include + +#include +#include +#include +#include "defines.hpp" + +#define MAXFAKTOR 1.2 //the maximal distance allowd by a point normed to the cluster size +#define MINFAKTOR 0.8 //the minimal distance allowd by a point normed to the cluster size +#define SKALEFAKTOR 1. //the faktor by which the biggest size is multiplied to get the scale value +#define NQFAKTOR 0.5 //the faktor by which the norm quaternion is multiplied with to get the RealScalar +//norm quaternion to generate the unit quaternion + +namespace dcm { +namespace details { + +enum Scalemode { + one, + two, + three, + multiple_inrange, + multiple_outrange +}; + +template +struct ClusterMath { + +public: + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + + typedef typename Kernel::number_type Scalar; + + typename Kernel::Transform3D m_transform, m_ssrTransform, m_resetTransform; + typename Kernel::DiffTransform3D m_diffTrans; + typename Kernel::Vector3Map m_normQ; + typename Kernel::Quaternion m_resetQuaternion; + + int m_offset; + bool init, fix; + std::vector m_geometry; + + typename Kernel::Vector3Map m_translation; + //shift scale stuff + typename Kernel::Vector3 midpoint, m_shift, scale_dir, maxm, minm, max, fixtrans; + Scalemode mode; + Scalar m_scale; + + typedef std::vector > Vec; + Vec m_points, m_pseudo; + +#ifdef USE_LOGGING + src::logger log; +#endif + +public: + ClusterMath(); + + void setParameterOffset(int offset); + int getParameterOffset(); + + typename Kernel::Vector3Map& getNormQuaternionMap(); + typename Kernel::Vector3Map& getTranslationMap(); + void initMaps(); + void initFixMaps(); + + typename Kernel::Transform3D& getTransform(); + void mapsToTransform(typename Kernel::Transform3D& trans); + void transformToMaps(typename Kernel::Transform3D& trans); + + void finishCalculation(); + void finishFixCalculation(); + + void resetClusterRotation(typename Kernel::Transform3D& trans); + + void calcDiffTransform(typename Kernel::DiffTransform3D& trans); + void recalculate(); + + void addGeometry(Geom g); + void clearGeometry(); + std::vector& getGeometry(); + + struct map_downstream { + + details::ClusterMath& m_clusterMath; + typename Kernel::Transform3D m_transform; + bool m_isFixed; + + map_downstream(details::ClusterMath& cm, bool fix); + + void operator()(Geom g); + void operator()(boost::shared_ptr c); + }; + + void mapClusterDownstreamGeometry(boost::shared_ptr cluster); + + //Calculate the scale of the cluster. Therefore the midpoint is calculated and the scale is + // defined as the max distance between the midpoint and the points. + Scalar calculateClusterScale(); + + void applyClusterScale(Scalar scale, bool isFixed); + +private: + Scalar calcOnePoint(const typename Kernel::Vector3& p); + + Scalar calcTwoPoints(const typename Kernel::Vector3& p1, const typename Kernel::Vector3& p2); + + Scalar calcThreePoints(const typename Kernel::Vector3& p1, + const typename Kernel::Vector3& p2, const typename Kernel::Vector3& p3); +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + + +template +ClusterMath::ClusterMath() : m_normQ(NULL), m_translation(NULL), init(false) { + + m_resetTransform = typename Kernel::Quaternion(1,1,1,1); + m_shift.setZero(); + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Clustermath3D")); +#endif +}; + +template +void ClusterMath::setParameterOffset(int offset) { + m_offset = offset; +}; + +template +int ClusterMath::getParameterOffset() { + return m_offset; +}; + +template +typename ClusterMath::Kernel::Vector3Map& ClusterMath::getNormQuaternionMap() { + return m_normQ; +}; + +template +typename ClusterMath::Kernel::Vector3Map& ClusterMath::getTranslationMap() { + return m_translation; +}; + +template +void ClusterMath::initMaps() { + + transformToMaps(m_transform); + init = true; + midpoint.setZero(); + m_shift.setZero(); + m_ssrTransform.setIdentity(); + m_diffTrans = m_transform; + fix=false; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init transform: "< +void ClusterMath::initFixMaps() { + //when fixed no maps exist + new(&m_translation) typename Kernel::Vector3Map(&fixtrans(0)); + m_translation = m_transform.translation().vector(); + init = true; + midpoint.setZero(); + m_shift.setZero(); + m_ssrTransform.setIdentity(); + m_diffTrans = m_transform; + fix=true; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init fix transform: "< +typename ClusterMath::Kernel::Transform3D& ClusterMath::getTransform() { + return m_transform; +}; + +template +void ClusterMath::mapsToTransform(typename ClusterMath::Kernel::Transform3D& trans) { + //add scale only after possible reset + typename Kernel::Transform3D::Scaling scale(m_transform.scaling()); + trans = m_diffTrans; + trans *= scale; +}; + +template +void ClusterMath::transformToMaps(typename ClusterMath::Kernel::Transform3D& trans) { + + const typename Kernel::Quaternion& m_quaternion = trans.rotation(); + if(m_quaternion.w() < 1.) { + Scalar s = std::acos(m_quaternion.w())/std::sin(std::acos(m_quaternion.w())); + m_normQ = m_quaternion.vec()*s; + m_normQ /= NQFAKTOR; + } else { + m_normQ.setZero(); + } + m_translation = trans.translation().vector(); +}; + +template +void ClusterMath::finishCalculation() { + + mapsToTransform(m_transform); + init=false; + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish calculation"; +#endif + + m_transform = m_ssrTransform*m_transform; + + //scale all geometries back to the original size + m_diffTrans *= typename Kernel::Transform3D::Scaling(1./m_ssrTransform.scaling().factor()); + typedef typename std::vector::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(m_diffTrans); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish transform:"< +void ClusterMath::finishFixCalculation() { +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish fix calculation"; +#endif + typedef typename std::vector::iterator iter; + m_transform *= m_ssrTransform.inverse(); + typename Kernel::DiffTransform3D diff(m_transform); + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(diff); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish fix transform:"< +void ClusterMath::resetClusterRotation(typename ClusterMath::Kernel::Transform3D& trans) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Reset cluster rotation:"<::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) { + (*it)->transform(m_resetTransform); + }; +}; + +template +void ClusterMath::calcDiffTransform(typename ClusterMath::Kernel::DiffTransform3D& trans) { + + Scalar norm = m_normQ.norm(); + trans.setIdentity(); + + if(norm < 0.1) { + if(norm == 0) { + trans *= typename Kernel::Transform3D::Translation(m_translation); + resetClusterRotation(trans); + } else { + const Scalar fac = std::sin(NQFAKTOR*norm)/norm; + trans = typename Kernel::Quaternion(std::cos(NQFAKTOR*norm), m_normQ(0)*fac, m_normQ(1)*fac,m_normQ(2)*fac); + trans *= typename Kernel::Transform3D::Translation(m_translation); + resetClusterRotation(trans); + } + transformToMaps(trans); + return; + } + + const Scalar fac = std::sin(NQFAKTOR*norm)/norm; + trans = typename Kernel::Quaternion(std::cos(NQFAKTOR*norm), m_normQ(0)*fac, m_normQ(1)*fac, m_normQ(2)*fac); + trans *= typename Kernel::Transform3D::Translation(m_translation); +}; + +template +void ClusterMath::recalculate() { + + + calcDiffTransform(m_diffTrans); + + const typename Kernel::Quaternion Q = m_diffTrans.rotation(); + + // now calculate the gradient quaternions and calculate the diff rotation matrices + // m_normQ = (a,b,c) + // n = ||m_normQ|| + // + // Q = (a/n sin(n), b/n sin(n), c/n sin(n), cos(n)) + // + + //n=||m_normQ||, sn = sin(n)/n, sn3 = sin(n)/n^3, cn = cos(n)/n, divn = 1/n; + const Scalar n = m_normQ.norm(); + const Scalar sn = std::sin(NQFAKTOR*n)/n; + const Scalar mul = (NQFAKTOR*std::cos(NQFAKTOR*n)-sn)/std::pow(n,2); + + //dxa = dQx/da + const Scalar dxa = sn + std::pow(m_normQ(0),2)*mul; + const Scalar dxb = m_normQ(0)*m_normQ(1)*mul; + const Scalar dxc = m_normQ(0)*m_normQ(2)*mul; + + const Scalar dya = m_normQ(1)*m_normQ(0)*mul; + const Scalar dyb = sn + std::pow(m_normQ(1),2)*mul; + const Scalar dyc = m_normQ(1)*m_normQ(2)*mul; + + const Scalar dza = m_normQ(2)*m_normQ(0)*mul; + const Scalar dzb = m_normQ(2)*m_normQ(1)*mul; + const Scalar dzc = sn + std::pow(m_normQ(2),2)*mul; + + const Scalar dwa = -sn*NQFAKTOR*m_normQ(0); + const Scalar dwb = -sn*NQFAKTOR*m_normQ(1); + const Scalar dwc = -sn*NQFAKTOR*m_normQ(2); + + //write in the diffrot matrix, starting with dQ/dx + m_diffTrans.at(0,0) = -4.0*(Q.y()*dya+Q.z()*dza); + m_diffTrans.at(0,1) = -2.0*(Q.w()*dza+dwa*Q.z())+2.0*(Q.x()*dya+dxa*Q.y()); + m_diffTrans.at(0,2) = 2.0*(dwa*Q.y()+Q.w()*dya)+2.0*(dxa*Q.z()+Q.x()*dza); + m_diffTrans.at(1,0) = 2.0*(Q.w()*dza+dwa*Q.z())+2.0*(Q.x()*dya+dxa*Q.y()); + m_diffTrans.at(1,1) = -4.0*(Q.x()*dxa+Q.z()*dza); + m_diffTrans.at(1,2) = -2.0*(dwa*Q.x()+Q.w()*dxa)+2.0*(dya*Q.z()+Q.y()*dza); + m_diffTrans.at(2,0) = -2.0*(dwa*Q.y()+Q.w()*dya)+2.0*(dxa*Q.z()+Q.x()*dza); + m_diffTrans.at(2,1) = 2.0*(dwa*Q.x()+Q.w()*dxa)+2.0*(dya*Q.z()+Q.y()*dza); + m_diffTrans.at(2,2) = -4.0*(Q.x()*dxa+Q.y()*dya); + + //dQ/dy + m_diffTrans.at(0,3) = -4.0*(Q.y()*dyb+Q.z()*dzb); + m_diffTrans.at(0,4) = -2.0*(Q.w()*dzb+dwb*Q.z())+2.0*(Q.x()*dyb+dxb*Q.y()); + m_diffTrans.at(0,5) = 2.0*(dwb*Q.y()+Q.w()*dyb)+2.0*(dxb*Q.z()+Q.x()*dzb); + m_diffTrans.at(1,3) = 2.0*(Q.w()*dzb+dwb*Q.z())+2.0*(Q.x()*dyb+dxb*Q.y()); + m_diffTrans.at(1,4) = -4.0*(Q.x()*dxb+Q.z()*dzb); + m_diffTrans.at(1,5) = -2.0*(dwb*Q.x()+Q.w()*dxb)+2.0*(dyb*Q.z()+Q.y()*dzb); + m_diffTrans.at(2,3) = -2.0*(dwb*Q.y()+Q.w()*dyb)+2.0*(dxb*Q.z()+Q.x()*dzb); + m_diffTrans.at(2,4) = 2.0*(dwb*Q.x()+Q.w()*dxb)+2.0*(dyb*Q.z()+Q.y()*dzb); + m_diffTrans.at(2,5) = -4.0*(Q.x()*dxb+Q.y()*dyb); + + //dQ/dz + m_diffTrans.at(0,6) = -4.0*(Q.y()*dyc+Q.z()*dzc); + m_diffTrans.at(0,7) = -2.0*(Q.w()*dzc+dwc*Q.z())+2.0*(Q.x()*dyc+dxc*Q.y()); + m_diffTrans.at(0,8) = 2.0*(dwc*Q.y()+Q.w()*dyc)+2.0*(dxc*Q.z()+Q.x()*dzc); + m_diffTrans.at(1,6) = 2.0*(Q.w()*dzc+dwc*Q.z())+2.0*(Q.x()*dyc+dxc*Q.y()); + m_diffTrans.at(1,7) = -4.0*(Q.x()*dxc+Q.z()*dzc); + m_diffTrans.at(1,8) = -2.0*(dwc*Q.x()+Q.w()*dxc)+2.0*(dyc*Q.z()+Q.y()*dzc); + m_diffTrans.at(2,6) = -2.0*(dwc*Q.y()+Q.w()*dyc)+2.0*(dxc*Q.z()+Q.x()*dzc); + m_diffTrans.at(2,7) = 2.0*(dwc*Q.x()+Q.w()*dxc)+2.0*(dyc*Q.z()+Q.y()*dzc); + m_diffTrans.at(2,8) = -4.0*(Q.x()*dxc+Q.y()*dyc); + + //recalculate all geometries + typedef typename std::vector::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(m_diffTrans); +}; + +template +void ClusterMath::addGeometry(Geom g) { + m_geometry.push_back(g); +}; + +template +void ClusterMath::clearGeometry() { + m_geometry.clear(); +}; + +template +std::vector::Geom>& ClusterMath::getGeometry() { + return m_geometry; +}; + +template +ClusterMath::map_downstream::map_downstream(details::ClusterMath& cm, bool fix) + : m_clusterMath(cm), m_isFixed(fix) { + m_transform = m_clusterMath.getTransform(); +}; + +template +void ClusterMath::map_downstream::operator()(Geom g) { + //allow iteration over all maped geometries + m_clusterMath.addGeometry(g); + //set the offsets so that geometry knows where it is in the parameter map + g->m_offset = m_clusterMath.getParameterOffset(); + //position and offset of the parameters must be set to the clusters values + g->setClusterMode(true, m_isFixed); + //calculate the appropriate local values + typename Kernel::Transform3D trans = m_transform.inverse(); + g->transform(trans); +}; + +template +void ClusterMath::map_downstream::operator()(boost::shared_ptr c) { + m_transform *= c->template getClusterProperty().getTransform(); +}; + + +template +void ClusterMath::mapClusterDownstreamGeometry(boost::shared_ptr cluster) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Map downstream geometry"; +#endif + + map_downstream down(cluster->template getClusterProperty(), + cluster->template getClusterProperty()); + cluster->template for_each(down, true); + //TODO: if one subcluster is fixed the hole cluster should be too, as there are no + // dof's remaining between parts and so nothing can be moved when one part is fixed. +}; + +template +typename ClusterMath::Scalar ClusterMath::calculateClusterScale() { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Calculate cluster scale with transform scale: "<::iterator g_iter; + for(g_iter it = m_geometry.begin(); it != m_geometry.end(); it++) + m_points.push_back((*it)->getPoint()); + + //start scale calculation + if(m_points.empty()) assert(false); //TODO: Throw + else if(m_points.size() == 1) { + const typename Kernel::Vector3 p = m_points[0]; + return calcOnePoint(p); + } else if(m_points.size() == 2) { + const typename Kernel::Vector3 p1 = m_points[0]; + const typename Kernel::Vector3 p2 = m_points[1]; + + if(Kernel::isSame((p1-p2).norm(), 0.)) + return calcOnePoint(p1); + + return calcTwoPoints(p1, p2); + } else if(m_points.size() == 3) { + + const typename Kernel::Vector3 p1 = m_points[0]; + const typename Kernel::Vector3 p2 = m_points[1]; + const typename Kernel::Vector3 p3 = m_points[2]; + + const typename Kernel::Vector3 d = p2-p1; + const typename Kernel::Vector3 e = p3-p1; + + if(Kernel::isSame(d.norm(), 0.)) { + + if(Kernel::isSame(e.norm(), 0.)) + return calcOnePoint(p1); + + return calcTwoPoints(p1, p3); + } else if(Kernel::isSame(e.norm(), 0.)) { + return calcTwoPoints(p1, p2); + } else if(!Kernel::isSame((d/d.norm() - e/e.norm()).norm(), 0.) && + !Kernel::isSame((d/d.norm() + e/e.norm()).norm(), 0.)) { + return calcThreePoints(p1, p2, p3); + } + //three points on a line need to be treaded as multiple points + } + + //more than 3 points dont have a exakt solution. we search for a midpoint from which all points + //are at least MAXFAKTOR*scale away, but not closer than MINFAKTOR*scale + + //get the bonding box to get the center of points + Scalar xmin=1e10, xmax=1e-10, ymin=1e10, ymax=1e-10, zmin=1e10, zmax=1e-10; + for(iter it = m_points.begin(); it != m_points.end(); it++) { + typename Kernel::Vector3 v = (*it); + xmin = (v(0) +void ClusterMath::applyClusterScale(Scalar scale, bool isFixed) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Apply cluster scale: "<::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) { + (*it)->recalculate(diff); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Fixed cluster geometry value:" << (*it)->m_rotated.transpose(); +#endif + }; + return; + } + + //if this is our scale then just applie the midpoint as shift + if(Kernel::isSame(scale, m_scale)) { + + } + //if only one point exists we extend the origin-point-line to match the scale + else if(mode==details::one) { + if(Kernel::isSame(midpoint.norm(),0)) + midpoint << scale, 0, 0; + else midpoint += scale*scale_dir; + } + //two and three points form a rectangular triangle, so same procedure + else if(mode==details::two || mode==details::three) { + + midpoint+= scale_dir*std::sqrt(std::pow(scale,2) - std::pow(m_scale,2)); + } + //multiple points + else if(mode==details::multiple_outrange) { + + if(scale_dir(0)) { + Scalar d = std::pow(maxm(1),2) + std::pow(maxm(2),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(0) += maxm(0) + h; + } else if(scale_dir(1)) { + Scalar d = std::pow(maxm(0),2) + std::pow(maxm(2),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(1) += maxm(1) + h; + } else { + Scalar d = std::pow(maxm(0),2) + std::pow(maxm(1),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(2) += maxm(2) + h; + } + } else { + + //TODO: it's possible that for this case we get too far away from the outer points. + // The m_scale for "midpoint outside the bounding box" may be bigger than the + // scale to applie, so it results in an error. + //get the closest point + typedef typename Vec::iterator iter; + for(iter it = m_points.begin(); it != m_points.end(); it++) { + + const Eigen::Vector3d point = (*it)-midpoint; + if(point.norm()::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->transform(ssTrans); + + //set the new rotation and translation + m_transform = ssTrans.inverse()*m_transform; + m_ssrTransform *= ssTrans; + + transformToMaps(m_transform); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "sstrans scale: "< +typename ClusterMath::Scalar ClusterMath::calcOnePoint(const typename ClusterMath::Kernel::Vector3& p) { + + //one point can have every scale when moving the midpoint on the origin - point vector + midpoint = p; + scale_dir = -midpoint; + scale_dir.normalize(); + mode = details::one; + m_scale = 0.; + return 0.; +}; + +template +typename ClusterMath::Scalar ClusterMath::calcTwoPoints(const typename ClusterMath::Kernel::Vector3& p1, + const typename ClusterMath::Kernel::Vector3& p2) { + + //two points have their minimal scale at the mid position. Scaling perpendicular to this + //line allows arbitrary scale values. Best is to have the scale dir move towards the origin + //as good as possible. + midpoint = p1+(p2-p1)/2.; + scale_dir = (p2-p1).cross(midpoint); + scale_dir = scale_dir.cross(p2-p1); + if(!Kernel::isSame(scale_dir.norm(),0)) scale_dir.normalize(); + else scale_dir(0) = 1; + mode = details::two; + m_scale = (p2-p1).norm()/2.; + return m_scale; +}; + +template +typename ClusterMath::Scalar ClusterMath::calcThreePoints(const typename ClusterMath::Kernel::Vector3& p1, + const typename ClusterMath::Kernel::Vector3& p2, const typename ClusterMath::Kernel::Vector3& p3) { + + //Three points form a triangle with it's minimal scale at the center of it's outer circle. + //Arbitrary scale values can be achieved by moving perpendicular to the triangle plane. + typename Kernel::Vector3 d = p2-p1; + typename Kernel::Vector3 e = p3-p1; + + typename Kernel::Vector3 f = p1+0.5*d; + typename Kernel::Vector3 g = p1+0.5*e; + scale_dir = d.cross(e); + + typename Kernel::Matrix3 m; + m.row(0) = d.transpose(); + m.row(1) = e.transpose(); + m.row(2) = scale_dir.transpose(); + + typename Kernel::Vector3 res(d.transpose()*f, e.transpose()*g, scale_dir.transpose()*p1); + + midpoint = m.colPivHouseholderQr().solve(res); + scale_dir.normalize(); + mode = details::three; + m_scale = (midpoint-p1).norm(); + + return m_scale; + +}; + +}//details +}//dcm + + +#endif //GCM_CLUSTERMATH_H + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp new file mode 100644 index 0000000000..60549e18cb --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp @@ -0,0 +1,33 @@ +/* + 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_DEFINES_3D_H +#define GCM_DEFINES_3D_H + +namespace dcm { +namespace details { + +enum { cluster3D = 100}; + +struct m3d {}; //base of module3d::type to allow other modules check for it + +} +} + +#endif diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp new file mode 100644 index 0000000000..b36d30ad01 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -0,0 +1,292 @@ +/* + 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 GCM_DISTANCE3D_H +#define GCM_DISTANCE3D_H + +#include "geometry.hpp" +#include + +namespace dcm { + +template +struct Distance::type< Kernel, tag::point3D, tag::point3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value, sc_value; + + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& param1, Vector& param2) { + return (param1-param2).norm() - sc_value; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return (param1-param2).dot(dparam1) / (param1-param2).norm(); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return (param1-param2).dot(-dparam2) / (param1-param2).norm(); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient = (param1-param2) / (param1-param2).norm(); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient = (param2-param1) / (param1-param2).norm(); + }; +}; + +template +struct Distance::type< Kernel, tag::point3D, tag::plane3D > { + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value, sc_value; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D plane3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) { + //typename Kernel::Vector3 pp = param1.head(3)- ((param1.head(3)-param2.head(3)).dot(param2.tail(3)) / param2.tail(3).norm()*(param2.tail(3))); + //v2.push_back(pp); + typename Kernel::Vector3 dir = (param1.template head<3>()-param2.template head<3>()).cross(param2.template segment<3>(3)); + dir = param2.template segment<3>(3).cross(dir).normalized(); + typename Kernel::Vector3 pp = param2.head(3) + (param1.head(3)-param2.head(3)).norm()*dir; + v2.push_back(pp); +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = (param1.head(3)-param2.head(3)).dot(param2.tail(3)) / param2.tail(3).norm() - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "< +struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { + Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance plane3D plane3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +template +struct Distance::type< Kernel, tag::point3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef typename Kernel::Vector3 Vector3; + typedef std::vector > Vec; + + Scalar value, sc_value; + Vector3 diff, n, dist; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D line3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& point, Vec& v1, typename Kernel::Vector& line, Vec& v2) { + Vector3 pp = line.head(3) + (line.head(3)-point.head(3)).norm()*line.segment(3,3); +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + v2.push_back(pp); + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& point, Vector& line) { + //diff = point1 - point2 + n = line.template segment<3>(3); + diff = line.template head<3>() - point.template head<3>(); + dist = diff - diff.dot(n)*n; + const Scalar res = dist.norm() - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "<(); + const Vector3 d_dist = d_diff - d_diff.dot(n)*n; + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal first cluster gradient detected: "<(); + const Vector3 d_n = dline.template segment<3>(3); + const Vector3 d_dist = d_diff - ((d_diff.dot(n)+diff.dot(d_n))*n + diff.dot(n)*d_n); + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal second cluster gradient detected: "<(3) = -(mult*diff + diff.dot(n)*dist)/dist.norm(); + }; +}; + +template +struct Distance::type< Kernel, tag::line3D, tag::line3D > : public Distance::type< Kernel, tag::point3D, tag::line3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::line3D >() { + Distance::type< Kernel, tag::point3D, tag::line3D >::tag.set("Distance line3D line3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +template +struct Distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Distance::type< Kernel, tag::line3D, tag::line3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { + Distance::type< Kernel, tag::line3D, tag::line3D >::tag.set("Distance cylinder3D cylinder3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); + g(6) = 0; + }; +}; + +}//namespace dcm + +#endif //GCM_DISTANCE3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/dof.hpp b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp new file mode 100644 index 0000000000..dbfc79eb11 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp @@ -0,0 +1,133 @@ +/* + 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_DOF_H +#define GCM_DOF_H + +#include +#include + +namespace dcm { + +enum remaining { + nothing = 0, + line, + plane, + volume +}; + +template +class Dof { + + typedef typename K::Vector3 Vec; + typedef std::pair VecID; + +public: + typedef std::vector ConstraintVector; + typedef std::pair Result; + + Dof() : m_translation(volume), m_rotation(volume) {}; + + int dofTranslational() { + return m_translation; + }; + int dofRotational() { + return m_rotation; + }; + int dof() { + return dofTranslational() + dofRotational(); + }; + + + Result removeTranslationDirection(Vec& v, C constraint) { + + if(m_translation == nothing) { + ConstraintVector cv; + cv.push_back(tp1.second); + cv.push_back(tp2.second); + cv.push_back(tp3.second); + return std::make_pair(false,cv); + } else if(m_translation == volume) { + + m_translation = plane; + tp1 = std::make_pair(v, constraint); + } else if(m_translation == plane) { + + if(K::isSame(tp1.first, v) || K::isOpposite(tp1.first, v)) { + ConstraintVector cv; + cv.push_back(tp1.second); + return std::make_pair(false,cv); + } + m_translation = line; + tp2 = std::make_pair(v, constraint); + } else if(m_translation == line) { + + if(tp1.first.cross(tp2.first).dot(v) < 0.001) { + ConstraintVector cv; + cv.push_back(tp1.second); + cv.push_back(tp2.second); + return std::make_pair(false,cv); + } + m_translation = nothing; + tp3 = std::make_pair(v, constraint); + } + + return std::make_pair(true, ConstraintVector()); + }; + + Result allowOnlyRotationDirection(Vec& v, C constraint) { + + if(m_rotation == nothing) { + ConstraintVector cv; + cv.push_back(rp1.second); + cv.push_back(rp2.second); + return std::make_pair(false, cv); + } else if(m_rotation == volume) { + + m_rotation = line; + rp1 = std::make_pair(v, constraint); + } else if(m_rotation == plane) { + + return std::make_pair(false, ConstraintVector()); //error as every function call removes 2 dof's + } else if(m_rotation == line) { + + if(K::isSame(rp1.first, v) || K::isOpposite(rp1.first, v)) { + ConstraintVector cv; + cv.push_back(rp1.second); + return std::make_pair(false, cv); + } + m_rotation = nothing; + rp2 = std::make_pair(v, constraint); + } + + return std::make_pair(true, ConstraintVector()); + }; + + +private: + int m_translation, m_rotation; + VecID tp1,tp2,tp3; //translation pairs + VecID rp1, rp2; //rotation pairs + + +}; + +} + +#endif //GCM_DOF_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp new file mode 100644 index 0000000000..9fedadc8e8 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp @@ -0,0 +1,160 @@ +/* + 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_3D_H +#define GCM_GEOMETRY_3D_H + +#include + +namespace dcm { +namespace tag { + +struct point3D { + typedef mpl::int_<3> parameters; + typedef mpl::int_<1> rotations; + typedef mpl::int_<1> translations; + typedef weight::point weight; +}; + +struct direction3D { + typedef mpl::int_<3> parameters; + typedef mpl::int_<1> rotations; + typedef mpl::int_<0> translations; + typedef weight::direction weight; +}; + +struct line3D { + typedef mpl::int_<6> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::line weight; +}; + +struct plane3D { + typedef mpl::int_<6> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::plane weight; +}; + +struct cylinder3D { + typedef mpl::int_<7> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::cylinder weight; +}; +} + +namespace modell { + + struct XYZ { + /*Modell XYZ: + * 0 = X; + * 1 = Y; + * 2 = Z; + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + }; + }; + + struct XYZ2 { + /*Modell XYZ2: two xyz parts after each other + * 0 = X; + * 1 = Y; + * 2 = Z; + * 3 = X dir; + * 4 = Y dir; + * 5 = Z dir; + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + v(3) = a.template get(t); + v(4) = a.template get(t); + v(5) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + a.template set(v(3), t); + a.template set(v(4), t); + a.template set(v(5), t); + }; + }; + + struct XYZ2P { + /*Modell XYZ2P: two xyz parts after each other and one parameter + * 0 = X; + * 1 = Y; + * 2 = Z; + * 3 = X dir; + * 4 = Y dir; + * 5 = Z dir; + * 6 = Parameter + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + v(3) = a.template get(t); + v(4) = a.template get(t); + v(5) = a.template get(t); + v(6) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + a.template set(v(3), t); + a.template set(v(4), t); + a.template set(v(5), t); + a.template set(v(6), t); + }; + }; + +} + +} + +#endif //GCM_GEOMETRY_3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp new file mode 100644 index 0000000000..73623f39f4 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -0,0 +1,546 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_MODULE_3D_H +#define GCM_MODULE_3D_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "opendcm/core.hpp" +#include "opendcm/core/object.hpp" +#include "opendcm/core/clustergraph.hpp" +#include "opendcm/core/sheduler.hpp" +#include "opendcm/core/traits.hpp" +#include "opendcm/core/geometry.hpp" +#include "geometry.hpp" +#include "distance.hpp" +#include "parallel.hpp" +#include "angle.hpp" +#include "solver.hpp" +#include "defines.hpp" +#include "clustermath.hpp" + +namespace mpl = boost::mpl; + +namespace dcm { + +namespace details { + +template +struct distance { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type type; + BOOST_MPL_ASSERT((mpl::not_< boost::is_same::type > >)); +}; +} +}//dcm + +namespace dcm { + +template +struct Module3D { + + template + struct type : details::m3d { + struct Constraint3D; + struct Geometry3D; + struct vertex_prop; + struct inheriter_base; + + typedef boost::shared_ptr Geom; + typedef boost::shared_ptr Cons; + + typedef mpl::map1< mpl::pair > > ConsSignal; + + typedef ID Identifier; + + typedef details::MES MES; + typedef details::SystemSolver SystemSolver; + + template + class Geometry3D_id : public detail::Geometry { + + typedef detail::Geometry Base; + +#ifdef USE_LOGGING + attrs::mutable_constant< std::string > log_id; +#endif + public: + template + Geometry3D_id(T geometry, Sys& system); + + template + void set(T geometry, Identifier id); + //somehow the base class set funtion is not found + template + void set(T geometry); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Geometry3D : public mpl::if_, + detail::Geometry, Geometry3D_id >::type { + + typedef vertex_prop vertex_propertie; + + template + Geometry3D(T geometry, Sys& system); + + //allow accessing the internals by module3d classes but not by users + friend struct details::ClusterMath; + friend struct details::ClusterMath::map_downstream; + friend struct details::SystemSolver; + friend struct details::SystemSolver::Rescaler; + friend class detail::Constraint; + }; + + template + class Constraint3D_id : public detail::Constraint { + + typedef detail::Constraint base; + public: + Constraint3D_id(Sys& system, Geom f, Geom s); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Constraint3D : public mpl::if_, + detail::Constraint, + Constraint3D_id >::type { + + Constraint3D(Sys& system, Geom first, Geom second); + + friend struct details::SystemSolver; + friend struct details::SystemSolver::Rescaler; + friend struct details::MES; + friend struct inheriter_base; + }; + + struct inheriter_base { + + inheriter_base(); + + template + Geom createGeometry3D(T geom); + void removeGeometry3D(Geom g); + + template + Cons createConstraint3D(Geom first, Geom second, T1 constraint1); + void removeConstraint3D(Cons c); + + protected: + Sys* m_this; + void apply_edge_remove(GlobalEdge e); + }; + + struct inheriter_id : public inheriter_base { + + protected: + using inheriter_base::m_this; + + public: + template + Geom createGeometry3D(T geom, Identifier id); + template + Cons createConstraint3D(Identifier id, Geom first, Geom second, T constraint1); + + void removeGeometry3D(Identifier id); + void removeConstraint3D(Identifier id); + + bool hasGeometry3D(Identifier id); + Geom getGeometry3D(Identifier id); + bool hasConstraint3D(Identifier id); + Cons getConstraint3D(Identifier id); + }; + + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; + + struct math_prop { + typedef cluster_property kind; + typedef details::ClusterMath type; + }; + struct fix_prop { + typedef cluster_property kind; + typedef bool type; + }; + struct vertex_prop { + typedef Geometry3D kind; + typedef GlobalVertex type; + }; + struct edge_prop { + typedef Constraint3D kind; + typedef GlobalEdge type; + }; + + typedef mpl::vector4 properties; + typedef mpl::vector objects; + + static void system_init(Sys& sys) { + sys.m_sheduler.addProcessJob(new SystemSolver()); + }; + static void system_copy(const Sys& from, Sys& into) { + //nothing to to as all objects and properties are copyed with the clustergraph + }; + }; +}; + +namespace details { +//allow direct access to the stored geometry in a Geometry3D, copyed from boost variant get +template +struct get_visitor { +private: + + typedef typename boost::add_pointer::type pointer; + typedef typename boost::add_reference::type reference; + +public: + + typedef pointer result_type; + +public: + pointer operator()(reference operand) const { + return boost::addressof(operand); + } + + template + pointer operator()(const U&) const { + return static_cast(0); + } +}; +} + +template +typename boost::add_reference::type get(G geom) { + + typedef typename boost::add_pointer::type T_ptr; + details::get_visitor v; + T_ptr result = geom->apply(v); + + //if (!result) + //TODO:throw bad_get(); + return *result; +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + + +template +template +template +template +Module3D::type::Geometry3D_id::Geometry3D_id(T geometry, Sys& system) + : detail::Geometry(geometry, system) +#ifdef USE_LOGGING + , log_id("No ID") +#endif +{ + +#ifdef USE_LOGGING + Base::log.add_attribute("ID", log_id); +#endif +}; + +template +template +template +template +void Module3D::type::Geometry3D_id::set(T geometry, Identifier id) { + this->template setProperty >(id); + Base::set(geometry); +}; + +template +template +template +template +void Module3D::type::Geometry3D_id::set(T geometry) { + Base::set(geometry); +}; + +template +template +template +typename Module3D::template type::Identifier& +Module3D::type::Geometry3D_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +template +void Module3D::type::Geometry3D_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +#ifdef USE_LOGGING + std::stringstream str; + str<template getProperty >(); + log_id.set(str.str()); + BOOST_LOG(Base::log)<<"Identifyer set: "< +template +template +Module3D::type::Geometry3D::Geometry3D(T geometry, Sys& system) + : mpl::if_, + detail::Geometry, + Geometry3D_id >::type(geometry, system) { + +}; + +template +template +template +Module3D::type::Constraint3D_id::Constraint3D_id(Sys& system, Geom f, Geom s) + : detail::Constraint(system, f, s) { + +}; + +template +template +template +typename Module3D::template type::Identifier& +Module3D::type::Constraint3D_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +template +void Module3D::type::Constraint3D_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +}; + +template +template +Module3D::type::Constraint3D::Constraint3D(Sys& system, Geom first, Geom second) + : mpl::if_, + detail::Constraint, + Constraint3D_id >::type(system, first, second) { + +}; + +template +template +Module3D::type::inheriter_base::inheriter_base() { + m_this = ((Sys*) this); +}; + +template +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_base::createGeometry3D(T geom) { + + Geom g(new Geometry3D(geom, * ((Sys*) this))); + fusion::vector res = m_this->m_cluster->addVertex(); + m_this->m_cluster->template setObject (fusion::at_c<0> (res), g); + g->template setProperty(fusion::at_c<1>(res)); + m_this->push_back(g); + return g; +}; + +template +template +void Module3D::type::inheriter_base::removeGeometry3D(Geom g) { + + GlobalVertex v = g->template getProperty(); + + //check if this vertex holds a constraint + Cons c = m_this->m_cluster->template getObject(v); + if(c) + c->template emitSignal(c); + + //emit remove geometry signal bevore actually deleting it, in case anyone want to access the + //graph before + g->template emitSignal(g); + + //remove the vertex from graph and emit all edges that get removed with the functor + boost::function functor = boost::bind(&inheriter_base::apply_edge_remove, this, _1); + m_this->m_cluster->removeVertex(v, functor); + m_this->erase(g); +}; + +template +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_base::createConstraint3D(Geom first, Geom second, T1 constraint1) { + + //build a constraint vector + typedef mpl::vector<> cvec; + typedef typename mpl::if_< mpl::is_sequence, + typename mpl::fold< T1, cvec, mpl::push_back >::type, + mpl::vector1 >::type cvec1; + + //make a fusion sequence to hold the objects (as they hold the options) + typedef typename fusion::result_of::as_vector::type covec; + //set the objects + covec cv; + fusion::at_c<0>(cv) = constraint1; + + //now create the constraint + Cons c(new Constraint3D(*m_this, first, second)); + //set the type and values + c->template initialize(cv); + + //add it to the clustergraph + fusion::vector res; + res = m_this->m_cluster->addEdge(first->template getProperty(), + second->template getProperty()); + if(!fusion::at_c<2>(res)) { + Cons rc; + return rc; //TODO: throw + }; + m_this->m_cluster->template setObject (fusion::at_c<1> (res), c); + //add the coresbondig edge to the constraint + c->template setProperty(fusion::at_c<1>(res)); + //store the constraint in general object vector of main system + m_this->push_back(c); + + return c; +}; + +template +template +void Module3D::type::inheriter_base::removeConstraint3D(Cons c) { + + GlobalEdge e = c->template getProperty(); + c->template emitSignal(c); + m_this->m_cluster->removeEdge(e); + m_this->erase(c); +}; + +template +template +void Module3D::type::inheriter_base::apply_edge_remove(GlobalEdge e) { + Cons c = m_this->m_cluster->template getObject(e); + c->template emitSignal(c); + m_this->erase(c); +}; + +template +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_id::createGeometry3D(T geom, Identifier id) { + Geom g = inheriter_base::createGeometry3D(geom); + g->setIdentifier(id); + return g; +}; + +template +template +void Module3D::type::inheriter_id::removeGeometry3D(Identifier id) { + + if(hasGeometry3D(id)) + inheriter_base::removeGeometry3D(getGeometry3D(id)); +}; + +template +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_id::createConstraint3D(Identifier id, Geom first, Geom second, T constraint1) { + + Cons c = inheriter_base::createConstraint3D(first, second, constraint1); + c->setIdentifier(id); + return c; +}; + +template +template +void Module3D::type::inheriter_id::removeConstraint3D(Identifier id) { + + if(hasConstraint3D(id)) + removeConstraint3D(getConstraint3D(id)); +}; + + +template +template +bool Module3D::type::inheriter_id::hasGeometry3D(Identifier id) { + if(getGeometry3D(id)) return true; + return false; +}; + +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_id::getGeometry3D(Identifier id) { + std::vector< Geom >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Geom(); +}; + +template +template +bool Module3D::type::inheriter_id::hasConstraint3D(Identifier id) { + if(getConstraint3D(id)) return true; + return false; +}; + +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_id::getConstraint3D(Identifier id) { + std::vector< Cons >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Cons(); +}; + +}//dcm + +#endif //GCM_GEOMETRY3D_H + + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp new file mode 100644 index 0000000000..440fa10329 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -0,0 +1,215 @@ +/* + 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 GCM_PARALLEL_H +#define GCM_PARALLEL_H + +#include + +#include "geometry.hpp" +#include + +using boost::math::isnormal; + +namespace dcm { + +//the calculations( same as we always calculate directions we can outsource the work to this functions) +namespace parallel_detail { + +template +inline typename Kernel::number_type calc(T d1, + T d2, + Direction dir) { + + switch(dir) { + case Same: + return (d1-d2).norm(); + case Opposite: + return (d1+d2).norm(); + case Both: + if(d1.dot(d2) >= 0) { + return (d1-d2).norm(); + } + return (d1+d2).norm(); + default: + assert(false); + } + return 0; +}; + + +template +inline typename Kernel::number_type calcGradFirst(T d1, + T d2, + T dd1, + Direction dir) { + + typename Kernel::number_type res; + switch(dir) { + case Same: + res = ((d1-d2).dot(dd1) / (d1-d2).norm()); + break; + case Opposite: + res= ((d1+d2).dot(dd1) / (d1+d2).norm()); + break; + case Both: + if(d1.dot(d2) >= 0) { + res = (((d1-d2).dot(dd1) / (d1-d2).norm())); + break; + } + res = (((d1+d2).dot(dd1) / (d1+d2).norm())); + break; + } + if((isnormal)(res)) return res; + return 0; +}; + +template +inline typename Kernel::number_type calcGradSecond(T d1, + T d2, + T dd2, + Direction dir) { + + typename Kernel::number_type res; + switch(dir) { + case Same: + res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); + break; + case Opposite: + res = ((d1+d2).dot(dd2) / (d1+d2).norm()); + break; + case Both: + if(d1.dot(d2) >= 0) { + res = (((d1-d2).dot(-dd2) / (d1-d2).norm())); + break; + } + res = (((d1+d2).dot(dd2) / (d1+d2).norm())); + break; + } + if((isnormal)(res)) return res; + return 0; +}; + +template +inline void calcGradFirstComp(T d1, + T d2, + T grad, + Direction dir) { + + switch(dir) { + case Same: + grad = (d1-d2) / (d1-d2).norm(); + return; + case Opposite: + grad = (d1+d2) / (d1+d2).norm(); + return; + case Both: + assert(false); + } +}; + +template +inline void calcGradSecondComp(T d1, + T d2, + T grad, + Direction dir) { + + switch(dir) { + case Same: + grad = (d2-d1) / (d1-d2).norm(); + return; + case Opposite: + grad = (d2+d1) / (d1+d2).norm(); + return; + case Both: + assert(false); + } +}; + +} + +template< typename Kernel > +struct Parallel::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Direction value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return parallel_detail::calc(param1.template tail<3>(), param2.template tail<3>(), value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return parallel_detail::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>(), value); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return parallel_detail::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>(), value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); + }; + }; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::PseudoScale{ + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Direction value; + + Scalar calculate(Vector& param1, Vector& param2) { + return parallel_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return parallel_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), + dparam1.template segment<3>(3), value); + + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return parallel_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), + dparam2.template segment<3>(3), value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), + gradient.template segment<3>(3), value); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), + gradient.template segment<3>(3), value); + }; + }; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::line3D, tag::plane3D > : public Parallel::type {}; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::plane3D, tag::plane3D > : public Parallel::type {}; + +} + +#endif //GCM_ANGLE diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp new file mode 100644 index 0000000000..9502154b3c --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -0,0 +1,367 @@ +/* + 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_SOLVER_3D_H +#define GCM_SOLVER_3D_H + +#include + +#include "defines.hpp" +#include "clustermath.hpp" +#include "opendcm/core/sheduler.hpp" +#include "opendcm/core/traits.hpp" + +namespace dcm { +namespace details { + +template +struct MES : public system_traits::Kernel::MappedEquationSystem { + + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + typedef typename Kernel::number_type Scalar; + typedef typename system_traits::Kernel::MappedEquationSystem Base; + + boost::shared_ptr m_cluster; + + MES(boost::shared_ptr cl, int par, int eqn); + virtual void recalculate(); +}; + +template +struct SystemSolver : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + typedef typename module3d::vertex_prop vertex_prop; + + typedef MES Mes; + +#ifdef USE_LOGGING + src::logger log; +#endif + struct Rescaler { + + boost::shared_ptr cluster; + Mes& mes; + int rescales; + + Rescaler(boost::shared_ptr c, Mes& m); + + void operator()(); + + Scalar scaleClusters(); + void collectPseudoPoints(boost::shared_ptr parent, + LocalVertex cluster, + std::vector >& vec); + }; + + SystemSolver(); + virtual void execute(Sys& sys); + void solveCluster(boost::shared_ptr cluster, Sys& sys); +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template +MES::MES(boost::shared_ptr cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) { + +}; + +template +void MES::recalculate() { + + //first calculate all clusters + typedef typename Cluster::cluster_iterator citer; + std::pair cit = m_cluster->clusters(); + for(; cit.first != cit.second; cit.first++) { + + if(!(*cit.first).second->template getClusterProperty()) + (*cit.first).second->template getClusterProperty().recalculate(); + + }; + + //with everything updated just nicely we can compute the constraints + typedef typename Cluster::template object_iterator oiter; + typedef typename boost::graph_traits::edge_iterator eiter; + std::pair eit = boost::edges(*m_cluster); + for(; eit.first != eit.second; eit.first++) { + //as always: every local edge can hold multiple global ones, so iterate over all constraints + //hold by the individual edge + std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); + for(; oit.first != oit.second; oit.first++) { + if(*oit.first) + (*oit.first)->calculate(Base::Scaling); + } + } +}; + +template +SystemSolver::Rescaler::Rescaler(boost::shared_ptr c, Mes& m) : cluster(c), mes(m), rescales(0) { + +}; + +template +void SystemSolver::Rescaler::operator()() { + mes.Scaling = scaleClusters(); + rescales++; +}; + +template +typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() { + + typedef typename Cluster::cluster_iterator citer; + std::pair cit = cluster->clusters(); + //get the maximal scale + Scalar sc = 0; + for(cit = cluster->clusters(); cit.first != cit.second; cit.first++) { + //fixed cluster are irrelevant for scaling + if((*cit.first).second->template getClusterProperty()) continue; + + //get the biggest scale factor + details::ClusterMath& math = (*cit.first).second->template getClusterProperty(); + + //math.m_pseudo.clear(); + //collectPseudoPoints(cluster, (*cit.first).first, math.m_pseudo); + + const Scalar s = math.calculateClusterScale(); + sc = (s>sc) ? s : sc; + } + //if no scaling-value returned we can use 1 + sc = (Kernel::isSame(sc,0)) ? 1. : sc; + + typedef typename boost::graph_traits::vertex_iterator iter; + std::pair it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + if(cluster->isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + c->template getClusterProperty().applyClusterScale(sc, + c->template getClusterProperty()); + } else { + Geom g = cluster->template getObject(*it.first); + g->scale(sc*SKALEFAKTOR); + } + } + return 1./(sc*SKALEFAKTOR); +}; + +template +void SystemSolver::Rescaler::collectPseudoPoints( + boost::shared_ptr::Cluster> parent, + LocalVertex cluster, + std::vector::Kernel::Vector3, + Eigen::aligned_allocator::Kernel::Vector3> >& vec) { + + std::vector > vec2; + typedef typename Cluster::template object_iterator c_iter; + typedef typename boost::graph_traits::out_edge_iterator e_iter; + std::pair it = boost::out_edges(cluster, *parent); + for(; it.first != it.second; it.first++) { + + std::pair< c_iter, c_iter > cit = parent->template getObjects(*it.first); + for(; cit.first != cit.second; cit.first++) { + Cons c = *(cit.first); + + if(!c) + continue; + + //get the first global vertex and see if we have it in the wanted cluster or not + GlobalVertex v = c->first->template getProperty(); + std::pair res = parent->getLocalVertex(v); + if(!res.second) + return; //means the geometry is in non of the clusters which is not allowed + + if(res.first == cluster) + c->collectPseudoPoints(vec, vec2); + else + c->collectPseudoPoints(vec2, vec); + } + } +}; + +template +SystemSolver::SystemSolver() { + Job::priority = 1000; +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("SystemSolver3D")); +#endif +}; + +template +void SystemSolver::execute(Sys& sys) { + solveCluster(sys.m_cluster, sys); +}; + +template +void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sys) { + + //set out and solve all relevant subclusters + typedef typename Cluster::cluster_iterator citer; + std::pair cit = cluster->clusters(); + for(; cit.first != cit.second; cit.first++) { + + boost::shared_ptr c = (*cit.first).second; + if(c->template getClusterProperty() && + c->template getClusterProperty() == details::cluster3D) + solveCluster(c, sys); + } + + int params=0, constraints=0; + typename Kernel::number_type scale = 1; + + //get the ammount of parameters and constraint equations we need + typedef typename boost::graph_traits::vertex_iterator iter; + std::pair it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + //when cluster and not fixed it has trans and rot parameter + if(cluster->isCluster(*it.first)) { + if(!cluster->template getSubclusterProperty(*it.first)) { + params += 6; + } + } else { + params += cluster->template getObject(*it.first)->m_parameterCount; + }; + } + + //count the equations in the constraints + typedef typename Cluster::template object_iterator ocit; + typedef typename boost::graph_traits::edge_iterator e_iter; + std::pair e_it = boost::edges(*cluster); + for(; e_it.first != e_it.second; e_it.first++) { + std::pair< ocit, ocit > it = cluster->template getObjects(*e_it.first); + for(; it.first != it.second; it.first++) + constraints += (*it.first)->equationCount(); + }; + + + //initialise the system with now known size + //std::cout<<"constraints: "<isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + details::ClusterMath& cm = c->template getClusterProperty(); + //only get maps and propagate downstream if not fixed + if(!c->template getClusterProperty()) { + //set norm Quaternion as map to the parameter vector + int offset = mes.setParameterMap(cm.getNormQuaternionMap()); + //set translation as map to the parameter vector + mes.setParameterMap(cm.getTranslationMap()); + //write initail values to the parameter maps + //remember the parameter offset as all downstream geometry must use this offset + cm.setParameterOffset(offset); + //wirte initial values + cm.initMaps(); + } else cm.initFixMaps(); + + //map all geometrie within that cluster to it's rotation matrix + //for collecting all geometries which need updates + cm.clearGeometry(); + cm.mapClusterDownstreamGeometry(c); + + } else { + Geom g = cluster->template getObject(*it.first); + int offset = mes.setParameterMap(g->m_parameterCount, g->getParameterMap()); + g->m_offset = offset; + //init the parametermap with initial values + g->initMap(); + } + } + + //and now the constraints to set the residual and gradient maps + typedef typename Cluster::template object_iterator oiter; + e_it = boost::edges(*cluster); + for(; e_it.first != e_it.second; e_it.first++) { + + //as always: every local edge can hold multiple global ones, so iterate over all constraints + //hold by the individual edge + std::pair< oiter, oiter > oit = cluster->template getObjects(*e_it.first); + for(; oit.first != oit.second; oit.first++) { + + //set the maps + Cons c = *oit.first; + if(c) c->setMaps(mes); + //TODO: else throw (as every global edge was counted as one equation) + } + } + + int stop = 0; + Rescaler re(cluster, mes); + re(); + stop = Kernel::solve(mes, re); +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Numbers of rescale: "<isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + if(!cluster->template getSubclusterProperty(*it.first)) + c->template getClusterProperty().finishCalculation(); + else + c->template getClusterProperty().finishFixCalculation(); + + std::vector& vec = c->template getClusterProperty().getGeometry(); + for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) + (*vit)->finishCalculation(); + + } else { + Geom g = cluster->template getObject(*it.first); + g->scale(mes.Scaling); + g->finishCalculation(); + } + } + //we have solved this cluster + cluster->template setClusterProperty(false); +}; + +}//details +}//dcm + +#endif //DCM_SOLVER_3D_HPP diff --git a/src/Mod/Assembly/App/opendcm/module3d/state.hpp b/src/Mod/Assembly/App/opendcm/module3d/state.hpp new file mode 100644 index 0000000000..458d03b333 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/state.hpp @@ -0,0 +1,95 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULE3D_STATE_HPP +#define DCM_MODULE3D_STATE_HPP + +#include "module.hpp" +#include "opendcm/moduleState/traits.hpp" +#include +#include + +namespace karma = boost::spirit::karma; +namespace ascii = boost::spirit::karma::ascii; +namespace phx = boost::phoenix; + +namespace dcm { + +namespace details { + +struct geom_visitor : public boost::static_visitor { + + template + int operator()(T& i) const { + return geometry_traits::tag::weight::value; + }; +}; + +template +int getWeight(boost::shared_ptr ptr) { + return boost::apply_visitor(geom_visitor(), ptr->m_geometry); +}; + +template +void getStdVector(typename Kernel::Vector& eigen, std::vector& vec) { + vec.resize(eigen.size()); + for(int i=0; i +struct parser_generate< typename Module3D::type::Geometry3D, System> + : public mpl::true_{}; + +template +struct parser_generator< typename Module3D::type::Geometry3D, System, iterator > { + + typedef typename Sys::Kernel Kernel; + typedef typename typename Module3D::type::Geometry3D Geometry; + typedef karma::rule() > generator; + static void init(generator& r) { + r = karma::lit("Geometry3D\n") + << ascii::string[karma::_1 = phx::bind(&details::getWeight, karma::_val)] + << "\n" + << (karma::double_ % " ")[phx::bind(&details::getStdVector, )] + }; +}; + +template +struct parser_parse< typename Module3D::type::Geometry3D, System> + : public mpl::true_{}; + +template +struct parser_parser< typename Module3D::type::Geometry3D, System, iterator > { + + typedef typename Module3D::type::Geometry3D object_type; + + typedef qi::rule(System*), qi::space_type> parser; + static void init(parser& r) { + r = qi::lexeme[qi::lit("object 1 prop")[ qi::_val = + phx::construct >( phx::new_(*qi::_r1))]] >> ("HaHAHAHAHA"); + }; +}; + +} + + +#endif //DCM_MODULE3D_STATE_HPP \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp b/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp new file mode 100644 index 0000000000..bba3700537 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp @@ -0,0 +1,92 @@ +/* + 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_PART_H +#define GCM_GEOMETRY_PART_H + +#include +#include + +namespace dcm { +namespace tag { + +struct part {}; + +} + +namespace modell { + + struct quaternion_wxyz_vec3 { + /*Modell XYZ: + * 0 = w; + * 1 = x; + * 2 = y; + * 3 = z; + */ + template + void extract(Type& t, typename Kernel::Transform3D& trans) { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D::Rotation Rotation; + typedef typename Kernel::Transform3D::Translation Translation; + + Accessor a; + Rotation r; + r.w() = a.template get(t); + r.x() = a.template get(t); + r.y() = a.template get(t); + r.z() = a.template get(t); + + Translation tr;; + tr.vector()(0) = a.template get(t); + tr.vector()(1) = a.template get(t); + tr.vector()(2) = a.template get(t); + + trans = r; + trans *= tr; + } + + template + void inject(Type& t, typename Kernel::Transform3D& trans) { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D::Rotation Rotation; + typedef typename Kernel::Transform3D::Translation Translation; + + Accessor a; + + const Rotation& r = trans.rotation(); + a.template set(r.w(), t); + a.template set(r.x(), t); + a.template set(r.y(), t); + a.template set(r.z(), t); + + const Translation& tr = trans.translation(); + a.template set(tr.vector()(0), t); + a.template set(tr.vector()(1), t); + a.template set(tr.vector()(2), t); + + a.finalize(t); + }; + }; +} + +} + +#endif //GCM_GEOMETRY_PART_H diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp new file mode 100644 index 0000000000..c52b74bcb7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -0,0 +1,558 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_MODULE_PART_H +#define GCM_MODULE_PART_H + +#include "opendcm/core.hpp" +#include "opendcm/core/traits.hpp" +#include "opendcm/core/clustergraph.hpp" +#include "opendcm/core/property.hpp" +#include "opendcm/module3d.hpp" + +#include +#include + +namespace mpl = boost::mpl; + +namespace dcm { + +enum { clusterPart = 110}; + +enum CoordinateFrame {Local, Global}; + +template +struct ModulePart { + + template + struct type { + + + struct Part; + struct PrepareCluster; + struct EvaljuateCluster; + typedef boost::shared_ptr Partptr; + typedef mpl::map2< mpl::pair >, + mpl::pair > > PartSignal; + + typedef ID Identifier; + + class Part_base : public Object { + protected: + +#ifdef USE_LOGGING + src::logger log; +#endif + + //check if we have module3d in this system + typedef typename system_traits::template getModule::type module3d; + BOOST_MPL_ASSERT((mpl::not_ >)); + + //define what we need + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + + typedef typename boost::make_variant_over< Typelist >::type Variant; + typedef Object base; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D Transform; + + struct cloner : boost::static_visitor { + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(Transform& t) : m_transform(t) {}; + + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, m_transform); + } + Transform& m_transform; + }; + + public: + using Object::m_system; + + template + Part_base(T geometry, Sys& system, boost::shared_ptr cluster); + + template + typename Visitor::result_type apply(Visitor& vis); + + template + Geom addGeometry3D(T geom, CoordinateFrame frame = Global); + + template + void set(T geometry); + + virtual boost::shared_ptr clone(Sys& newSys); + + public: + Variant m_geometry; + Transform m_transform; + boost::shared_ptr m_cluster; + + void finishCalculation(); + void fix(bool fix_value); + }; + + struct Part_id : public Part_base { + + template + Part_id(T geometry, Sys& system, boost::shared_ptr cluster); + + template + typename Part_base::Geom addGeometry3D(T geom, Identifier id, CoordinateFrame frame = Global); + + template + void set(T geometry, Identifier id); + + bool hasGeometry3D(Identifier id); + typename Part_base::Geom getGeometry3D(Identifier id); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Part : public mpl::if_, Part_base, Part_id>::type { + + typedef typename mpl::if_, Part_base, Part_id>::type base; + + template + Part(T geometry, Sys& system, boost::shared_ptr cluster); + + friend struct PrepareCluster; + friend struct EvaljuateCluster; + }; + + + struct inheriter_base { + + inheriter_base(); + + template + Partptr createPart(T geometry); + void removePart(Partptr p); + + template + void setTransformation(T geom) { + + typedef typename system_traits::template getModule::type module3d; + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + + (typename geometry_traits::modell()).template extract::accessor >(geom, cm.getTransform()); + }; + + template + T getTransformation() { + + T geom; + getTransformation(geom); + return geom; + }; + template + void getTransformation(T& geom) { + + typedef typename system_traits::template getModule::type module3d; + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + + (typename geometry_traits::modell()).template inject::accessor >(geom, cm.getTransform()); + }; + + protected: + Sys* m_this; + + //function object to emit remove signal too al geometry which is deleted by part deletion + struct remover { + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + + Sys& system; + remover(Sys& s); + //see if we have a geometry or a constraint and emit the remove signal + void operator()(GlobalVertex v); + //we delete all global edges connecting to this part + void operator()(GlobalEdge e); + void operator()(boost::shared_ptr g) {}; + }; + }; + + struct inheriter_id : public inheriter_base { + + template + Partptr createPart(T geometry, Identifier id); + bool hasPart(Identifier id); + Partptr getPart(Identifier id); + }; + + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; + + typedef mpl::vector0<> properties; + typedef mpl::vector1 objects; + + struct PrepareCluster : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::template getModule::type module3d; + + PrepareCluster(); + virtual void execute(Sys& sys); + }; + + struct EvaljuateCluster : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::template getModule::type module3d; + + EvaljuateCluster(); + virtual void execute(Sys& sys); + }; + + static void system_init(Sys& sys) { + sys.m_sheduler.addPreprocessJob(new PrepareCluster()); + sys.m_sheduler.addPostprocessJob(new EvaljuateCluster()); + }; + static void system_copy(const Sys& from, Sys& into) {}; + }; +}; + +template +template +template +ModulePart::type::Part_base::Part_base(T geometry, Sys& system, boost::shared_ptr cluster) + : Object(system), m_geometry(geometry), m_cluster(cluster) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Part3D")); +#endif + + (typename geometry_traits::modell()).template extract::accessor >(geometry, m_transform); + + cluster->template setClusterProperty(false); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init: "< +template +template +typename Visitor::result_type ModulePart::type::Part_base::apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); +}; + +template +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_base::addGeometry3D(T geom, CoordinateFrame frame) { + Geom g(new Geometry3D(geom, *m_system)); + if(frame == Local) + g->transform(m_transform); + + fusion::vector res = m_cluster->addVertex(); + m_cluster->template setObject (fusion::at_c<0> (res), g); + g->template setProperty(fusion::at_c<1>(res)); + m_system->template objectVector().push_back(g); + + return g; +}; + +template +template +template +void ModulePart::type::Part_base::set(T geometry) { + Part_base::m_geometry = geometry; + (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); +}; + +template +template +boost::shared_ptr::template type::Part> +ModulePart::type::Part_base::clone(Sys& newSys) { + + //we need to reset the cluster pointer to the new system cluster + LocalVertex lv = Object::m_system->m_cluster->getClusterVertex(m_cluster); + GlobalVertex gv = Object::m_system->m_cluster->getGlobalVertex(lv); + + boost::shared_ptr np = Object::clone(newSys); + //there may be pointer inside the variant + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + + fusion::vector, bool> res = newSys.m_cluster->getLocalVertexGraph(gv); + if(!fusion::at_c<2>(res)) { + //todo: throw + return np; + } + np->m_cluster = fusion::at_c<1>(res)->getVertexCluster(fusion::at_c<0>(res)); + + return np; +}; + +template +template +void ModulePart::type::Part_base::finishCalculation() { + + m_transform.normalize(); + apply_visitor vis(m_transform); + apply(vis); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "New Value: "<(((Part*)this)->shared_from_this()); +}; + +template +template +void ModulePart::type::Part_base::fix(bool fix_value) { + m_cluster->template setClusterProperty(fix_value); +}; + +template +template +template +ModulePart::type::Part_id::Part_id(T geometry, Sys& system, boost::shared_ptr cluster) + : Part_base(geometry, system, cluster) { + +}; + +template +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_id::addGeometry3D(T geom, Identifier id, CoordinateFrame frame) { + + typename Part_base::Geom g = Part_base::addGeometry3D(geom, frame); + g->setIdentifier(id); + return g; +}; + +template +template +template +void ModulePart::type::Part_id::set(T geometry, Identifier id) { + Part_base::set(geometry); + setIdentifier(id); +}; + +template +template +bool ModulePart::type::Part_id::hasGeometry3D(Identifier id) { + typename Part_base::Geom g = Part_base::m_system->getGeometry3D(id); + if(!g) return false; + + //get the global vertex and check if it is a child of the part cluster + GlobalVertex v = g->template getProperty(); + return Part_base::m_cluster->getLocalVertex(v).second; +}; + +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_id::getGeometry3D(Identifier id) { + return Part_base::m_system->getGeometry3D(id); +}; + +template +template +typename ModulePart::template type::Identifier& +ModulePart::type::Part_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +void ModulePart::type::Part_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +}; + +template +template +template +ModulePart::type::Part::Part(T geometry, Sys& system, boost::shared_ptr cluster) + : mpl::if_, + Part_base, Part_id>::type(geometry, system, cluster) { + +}; + +template +template +ModulePart::type::inheriter_base::inheriter_base() { + m_this = ((Sys*) this); +}; + +template +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_base::createPart(T geometry) { + + typedef typename system_traits::Cluster Cluster; + std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); + Partptr p(new Part(geometry, * ((Sys*) this), res.first)); + + m_this->m_cluster->template setObject (res.second, p); + m_this->push_back(p); + + res.first->template setClusterProperty(clusterPart); + return p; +}; + +template +template +void ModulePart::type::inheriter_base::removePart(Partptr p) { + + remover r(*m_this); + m_this->m_cluster->removeCluster(p->m_cluster, r); + p->template emitSignal(p); + m_this->erase(p); +}; + +template +template +ModulePart::type::inheriter_base::remover::remover(Sys& s) : system(s) { + +}; + +template +template +void ModulePart::type::inheriter_base::remover::operator()(GlobalVertex v) { + Geom g = system.m_cluster->template getObject(v); + if(g) { + g->template emitSignal(g); + system.erase(g); + } + Cons c = system.m_cluster->template getObject(v); + if(c) { + c->template emitSignal(c); + system.erase(c); + } +}; + +template +template +void ModulePart::type::inheriter_base::remover::operator()(GlobalEdge e) { + Cons c = system.m_cluster->template getObject(e); + if(c) { + c->template emitSignal(c); + system.erase(c); + } +}; + +template +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_id::createPart(T geometry, Identifier id) { + Partptr p = inheriter_base::createPart(geometry); + p->setIdentifier(id); + return p; +}; + +template +template +bool ModulePart::type::inheriter_id::hasPart(Identifier id) { + if(getPart(id)) return true; + return false; +}; + +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_id::getPart(Identifier id) { + std::vector< Partptr >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Partptr(); +}; + +template +template +ModulePart::type::PrepareCluster::PrepareCluster() { + Job::priority = 1000; +}; + +template +template +void ModulePart::type::PrepareCluster::execute(Sys& sys) { + //get all parts and set their values to the cluster's + typedef typename std::vector::iterator iter; + for(iter it = sys.template begin(); it != sys.template end(); it++) { + + details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + cm.getTransform() = (*it)->m_transform; + }; +}; + +template +template +ModulePart::type::EvaljuateCluster::EvaljuateCluster() { + Job::priority = 1000; +}; + +template +template +void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { + //get all parts and set their values to the cluster's + typedef typename std::vector::iterator iter; + for(iter it = sys.template begin(); it != sys.template end(); it++) { + + details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + (*it)->m_transform = cm.getTransform(); + (*it)->finishCalculation(); + }; +}; + +} + +#endif //GCM_MODULEPART_H + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp b/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp new file mode 100644 index 0000000000..d77c5cfda7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp @@ -0,0 +1,36 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_DEFINES_STATE_H +#define DCM_DEFINES_STATE_H + +#include "opendcm/core/property.hpp" +#include "opendcm/core/clustergraph.hpp" + +namespace dcm { +namespace details { + +struct cluster_vertex_prop { + typedef GlobalVertex type; + typedef cluster_property kind; +}; +} +} + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp new file mode 100644 index 0000000000..7182c5c4ca --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp @@ -0,0 +1,72 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_GENERATOR_H +#define DCM_EDGE_GENERATOR_H + +#include "property_generator.hpp" +#include "object_generator.hpp" +#include "extractor.hpp" + +#include +#include +#include + +#include + +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; + +namespace dcm { +namespace details { + +template +struct edge_generator : karma::grammar >()> { + + edge_generator(); + + karma::rule >()> edge_range; + karma::rule()> edge; + karma::rule&()> globaledge_range; + karma::rule globaledge; + details::edge_prop_gen edge_prop; + details::obj_gen objects; + Extractor ex; +}; + +template +struct vertex_generator : karma::grammar()> { + + vertex_generator(); + + karma::rule()> vertex_range; + karma::rule vertex; + details::vertex_prop_gen vertex_prop; + details::obj_gen objects; + Extractor ex; +}; + +}//details +}//dcm + +#ifndef USE_EXTERNAL + #include "edge_vertex_generator_imp.hpp" +#endif + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp new file mode 100644 index 0000000000..40d6fa78ed --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp @@ -0,0 +1,57 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_GENERATOR_IMP_H +#define DCM_EDGE_GENERATOR_IMP_H + +#include "edge_vertex_generator.hpp" + +namespace dcm { +namespace details { + +template +edge_generator::edge_generator() : edge_generator::base_type(edge_range) { + + globaledge = karma::int_[phx::bind(&Extractor::getGlobalEdgeID, ex, karma::_val, karma::_1)] + << " source=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeSource, ex, karma::_val, karma::_1)] + << " target=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeTarget, ex, karma::_val, karma::_1)] << '>' + << "+" << objects[karma::_1 = phx::at_c<0>(karma::_val)] << "-\n" ; + + + globaledge_range = *(karma::lit("")); + + edge = karma::lit("source=")<(karma::_val)] << " target="<(karma::_val)] << ">+" + << edge_prop[karma::_1 = phx::at_c<0>(phx::at_c<0>(karma::_val))] + << karma::eol << globaledge_range[karma::_1 = phx::at_c<1>(phx::at_c<0>(karma::_val))] << '-' << karma::eol; + + edge_range = (karma::lit("")) % karma::eol; +}; + +template +vertex_generator::vertex_generator() : vertex_generator::base_type(vertex_range) { + + vertex = karma::int_ << ">+" << vertex_prop << objects << "-\n"; + + vertex_range = '\n' << (karma::lit("")) % karma::eol; +}; + +}//details +}//dcm + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp new file mode 100644 index 0000000000..d4172fb3af --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp @@ -0,0 +1,71 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_VERTEX_PARSER_H +#define DCM_EDGE_VERTEX_PARSER_H + +#include +#include "opendcm/core/clustergraph.hpp" +#include "extractor.hpp" + +namespace qi = boost::spirit::qi; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +template +struct edge_parser : qi::grammar< IIterator, fusion::vector(typename Sys::Cluster*, Sys*), + qi::space_type > { + + edge_parser(); + details::obj_par objects; + Injector in; + + qi::rule(typename Sys::Cluster*, Sys*), qi::space_type> edge; + qi::rule global_edge; + details::edge_prop_par edge_prop; + + }; + +template +struct vertex_parser : qi::grammar< IIterator, fusion::vector(typename Sys::Cluster*, Sys*), + qi::space_type> { + + vertex_parser(); + + details::obj_par objects; + Injector in; + + qi::rule(typename Sys::Cluster*, Sys*), qi::space_type> vertex; + details::vertex_prop_par prop; + + }; + +} +} + +//#ifndef USE_EXTERNAL +//#include "edge_vertex_parser_imp.hpp" +//#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp new file mode 100644 index 0000000000..8b43333a09 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp @@ -0,0 +1,55 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_PARSER_IMP_H +#define DCM_EDGE_PARSER_IMP_H + +#include "edge_vertex_parser.hpp" + +namespace dcm { +namespace details { + +template +edge_parser::edge_parser() : edge_parser::base_type(edge) { + + global_edge = qi::lit("> qi::lit("id=") >> qi::int_[phx::bind(&GlobalEdge::ID, phx::at_c<1>(qi::_val)) = qi::_1] + >> qi::lit("source=") >> qi::int_[phx::bind(&GlobalEdge::source, phx::at_c<1>(qi::_val)) = qi::_1] + >> qi::lit("target=") >> qi::int_[phx::bind(&GlobalEdge::target, phx::at_c<1>(qi::_val)) = qi::_1] >> '>' + >> objects(qi::_r1)[phx::at_c<0>(qi::_val) = qi::_1] >> ""; + + edge = (qi::lit("> "source=" >> qi::int_ >> "target=" >> qi::int_ >> '>')[qi::_val = phx::bind((&Sys::Cluster::addEdgeGlobal), qi::_r1, qi::_1, qi::_2)] + >> edge_prop[phx::bind(&Injector::setEdgeProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> *global_edge(qi::_r2) + >> (""); +}; + +template +vertex_parser::vertex_parser() : vertex_parser::base_type(vertex) { + + vertex = qi::lit("::addVertex, in, qi::_r1, qi::_val)] >> qi::lit("id=") + >> qi::int_[phx::at_c<1>(qi::_val) = phx::bind(&Sys::Cluster::setGlobalVertex, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> '>' >> prop[phx::bind(&Injector::setVertexProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> objects(qi::_r2)[phx::bind(&Injector::setVertexObjects, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> (""); +}; + +}//details +}//dcm + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp new file mode 100644 index 0000000000..7d2e4ed7c7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp @@ -0,0 +1,119 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EXTRACTOR_H +#define DCM_EXTRACTOR_H + +#include "defines.hpp" +#include +#include + +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +template +struct Extractor { + + typedef typename boost::graph_traits::vertex_iterator viter; + typedef typename boost::graph_traits::edge_iterator eiter; + + void getVertexRange(typename Sys::Cluster& cluster, std::vector& range) { + std::pair res = boost::vertices(cluster); + for(; res.first != res.second; res.first++) + range.push_back(cluster[*res.first]); + }; + void getEdgeRange(typename Sys::Cluster& cluster, + std::vector >& range) { + + std::pair res = boost::edges(cluster); + for(; res.first != res.second; res.first++) + range.push_back(fusion::make_vector(cluster[*res.first], + cluster.getGlobalVertex(boost::source(*res.first, cluster)), + cluster.getGlobalVertex(boost::target(*res.first, cluster)))); + + }; + void getGlobalEdgeSource(typename Sys::Cluster::edge_bundle_single b, int& source) { + source = fusion::at_c<1>(b).source; + }; + void getGlobalEdgeTarget(typename Sys::Cluster::edge_bundle_single b, int& target) { + target = fusion::at_c<1>(b).target; + }; + void getGlobalEdgeID(typename Sys::Cluster::edge_bundle_single b, int& id) { + id = fusion::at_c<1>(b).ID; + }; + void setVertexID(typename Sys::Cluster* cluster, LocalVertex v, long& l) { + if(v) + l = cluster->getGlobalVertex(v); + else + l = 0; + }; + void getClusterRange(typename Sys::Cluster& cluster, std::vector >& range) { + + typedef typename Sys::Cluster::const_cluster_iterator iter; + + for(iter it = cluster.m_clusters.begin(); it != cluster.m_clusters.end(); it++) { + range.push_back( std::make_pair( cluster.getGlobalVertex((*it).first), (*it).second.get() )); + }; + }; +}; + +template +struct Injector { + + void setClusterProperties(typename Sys::Cluster* cluster, + typename details::pts::type& prop) { + cluster->m_cluster_bundle = prop; + }; + void setVertexProperties(typename Sys::Cluster* cluster, LocalVertex v, + typename details::pts::type& prop) { + fusion::at_c<1>(cluster->operator[](v)) = prop; + }; + void setVertexObjects(typename Sys::Cluster* cluster, LocalVertex v, + typename details::sps::type& obj) { + fusion::at_c<2>(cluster->operator[](v)) = obj; + }; + + void setEdgeProperties(typename Sys::Cluster* cluster, LocalEdge e, + typename details::pts::type& prop) { + fusion::at_c<0>(cluster->operator[](e)) = prop; + }; + void setVertexProperty(typename Sys::Cluster* cluster, int value) { + cluster->template setClusterProperty(value); + }; + void addCluster(typename Sys::Cluster* cluster, typename Sys::Cluster* addcl) { + LocalVertex v = cluster->getLocalVertex(addcl->template getClusterProperty()).first; + cluster->m_clusters[v] = boost::shared_ptr(addcl); + }; + void addVertex(typename Sys::Cluster* cluster, fusion::vector& vec) { + vec = cluster->addVertex(); + }; +}; + + + +}//namespace dcm + +#endif //DCM_GENERATOR_H + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp new file mode 100644 index 0000000000..ab77c556c9 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp @@ -0,0 +1,82 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_GENERATOR_H +#define DCM_GENERATOR_H + +#include "property_generator.hpp" +#include "edge_vertex_generator.hpp" +#include "extractor.hpp" + +#include + +#include "traits.hpp" +#include "traits_impl.hpp" +#include "indent.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +template +struct generator : karma::grammar { + + typedef typename Sys::Cluster graph; + typedef typename graph::cluster_bundle graph_bundle; + typedef typename boost::graph_traits::vertex_iterator viter; + typedef typename boost::graph_traits::edge_iterator eiter; + + generator(); + + karma::rule start; + + karma::rule()> cluster_pair; + karma::rule cluster; + details::cluster_prop_gen cluster_prop; + + details::vertex_generator vertex_range; + details::edge_generator edge_range; + + Extractor ex; +}; + +}//namespace dcm + +#ifndef USE_EXTERNAL +#include "generator_imp.hpp" +#endif + +#endif //DCM_GENERATOR_H + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp new file mode 100644 index 0000000000..f258c065b6 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp @@ -0,0 +1,72 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_GENERATOR_IMP_H +#define DCM_GENERATOR_IMP_H + +#include "generator.hpp" +#include "opendcm/core/clustergraph.hpp" +//#include "karma_trans.hpp" + +#include +#include +#include + + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (T1)(T2)(T3)(T4), + (dcm::ClusterGraph) (T1)(T2)(T3)(T4), + (int, test) + (typename dcm::details::pts::type, m_cluster_bundle)) + + +namespace boost { namespace spirit { namespace traits +{ + template + struct transform_attribute* const, dcm::ClusterGraph&, karma::domain> + { + typedef dcm::ClusterGraph& type; + static type pre(dcm::ClusterGraph* const& val) { + return *val; + } + }; +}}} + +namespace dcm { + +template +generator::generator() : generator::base_type(start) { + + cluster %= karma::omit[karma::int_] << cluster_prop << -vertex_range[phx::bind(&Extractor::getVertexRange, ex, karma::_val, karma::_1)] + << -karma::buffer["\n" << edge_range[phx::bind(&Extractor::getEdgeRange, ex, karma::_val, karma::_1)]] + << -karma::buffer["\n" << (cluster_pair % karma::eol)[phx::bind(&Extractor::getClusterRange, ex, karma::_val, karma::_1)]] << "-\n" + << ""; + + cluster_pair %= karma::lit("+" + << karma::attr_cast(cluster); + + start %= karma::lit("+") << cluster; +}; + +}//namespace dcm + +#endif //DCM_GENERATOR_H + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp b/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp new file mode 100644 index 0000000000..6d731bca92 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp @@ -0,0 +1,63 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_INDENT_H +#define DCM_INDENT_H + +#include +#include +#include + +class indent_filter : public boost::iostreams::output_filter { +public: + explicit indent_filter() : indent(0) {}; + + template + bool put(Sink& dest, int c) { + + if(c == '+') { + indent++; + return true; + } else if(c == '-') { + indent--; + return true; + } else if(c == '\n') { + bool ret = boost::iostreams::put(dest, c); + for(int i=0; (i + void close(Source&) { + indent = 0; + } +private: + int indent; +}; + +#endif //DCM_INDENT_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp b/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp new file mode 100644 index 0000000000..1bff3f0840 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp @@ -0,0 +1,155 @@ +/*////////////////////////////////////////////////////////////////////////////// + Copyright (c) 2011 Jamboree + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +//////////////////////////////////////////////////////////////////////////////*/ +#ifndef BOOST_SPIRIT_REPOSITORY_KARMA_TRANS +#define BOOST_SPIRIT_REPOSITORY_KARMA_TRANS + + +#if defined(_MSC_VER) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace boost { namespace spirit { namespace repository +{ + namespace tag + { + struct trans {}; + } + + namespace karma + { + // enables trans(f)[...] + template + inline + spirit::stateful_tag_type trans(F f) + { + return spirit::stateful_tag_type(f); + } + + // enables trans(f)[...] + template + inline + spirit::stateful_tag_type trans(F f) + { + return spirit::stateful_tag_type(f); + } + } +}}} + + +namespace boost { namespace spirit +{ + /////////////////////////////////////////////////////////////////////////// + // Enablers + /////////////////////////////////////////////////////////////////////////// + // enables trans(f)[...] + template + struct use_directive > + : mpl::true_ {}; +}} // namespace boost::spirit + + +namespace boost { namespace spirit { namespace repository {namespace karma +{ + template + struct trans_directive + : spirit::karma::unary_generator > + { + typedef Subject subject_type; + + template + struct attribute + : mpl::eval_if + < + is_same + , traits::attribute_of + , mpl::identity + > + {}; + + trans_directive(Subject const& subject, F f) + : subject(subject), f(f) + {} + + template + < + typename OutputIterator, typename Context + , typename Delimiter, typename Attribute + > + bool generate + ( + OutputIterator& sink, Context& ctx, Delimiter const& d + , Attribute const& attr) const + { + return subject.generate(sink, ctx, d, f(attr)); + } + + template + info what(Context& context) const + { + return info("trans", subject.what(context)); + } + + Subject subject; + F f; + }; +}}}} // namespace boost::spirit::repository::karma + + +namespace boost { namespace spirit { namespace karma +{ + /////////////////////////////////////////////////////////////////////////// + // Generator generators: make_xxx function (objects) + /////////////////////////////////////////////////////////////////////////// + template + struct make_directive, Subject, Modifiers> + { + typedef repository::karma::trans_directive result_type; + + template + result_type operator()( + StatefulTag const& tag, Subject const& subject, unused_type) const + { + return result_type(subject, tag.data_); + } + }; +}}} // namespace boost::spirit::karma + + +namespace boost { namespace spirit { namespace traits +{ + /////////////////////////////////////////////////////////////////////////// + template + struct has_semantic_action > + : unary_has_semantic_action {}; + + /////////////////////////////////////////////////////////////////////////// + template + struct handles_container + < + repository::karma::trans_directive + , Attribute, Context, Iterator + > + : mpl::false_ {}; // FIXME +}}} // namespace boost::spirit::traits + + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp new file mode 100644 index 0000000000..c3a3a4d136 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp @@ -0,0 +1,98 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULE_STATE_H +#define DCM_MODULE_STATE_H + +#include + +#include "indent.hpp" +#include "generator.hpp" +#include "parser.hpp" +#include "defines.hpp" + +#include +#include + +namespace qi = boost::spirit::qi; + +namespace dcm { + +struct ModuleState { + + template + struct type { + + typedef Unspecified_Identifier Identifier; + + struct inheriter { + + inheriter() { + m_this = (Sys*) this; + }; + + Sys* m_this; + + void saveState(std::ostream& stream) { + + boost::iostreams::filtering_ostream indent_stream; + indent_stream.push(indent_filter()); + indent_stream.push(stream); + + std::ostream_iterator out(indent_stream); + generator gen; + + karma::generate(out, gen, *m_this->m_cluster); + }; + + void loadState(std::istream& stream) { + + //disable skipping of whitespace + stream.unsetf(std::ios::skipws); + + // wrap istream into iterator + boost::spirit::istream_iterator begin(stream); + boost::spirit::istream_iterator end; + + // use iterator to parse file data + parser par; + m_this->clear(); + typename Sys::Cluster* cl_ptr = m_this->m_cluster.get(); + qi::phrase_parse(begin, end, par(m_this), qi::space, cl_ptr); + }; + }; + + + //add only a property to the cluster as we need it to store the clusers global vertex + typedef mpl::vector1 properties; + typedef mpl::vector0<> objects; + + //nothing to do on startup + static void system_init(Sys& sys) {}; + }; +}; + +} + +#endif //DCM_MODULE_STATE_H + + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp new file mode 100644 index 0000000000..85a50bb99a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp @@ -0,0 +1,72 @@ +#ifndef DCM_OBJECT_GENERATOR_H +#define DCM_OBJECT_GENERATOR_H + +#include "property_generator.hpp" + +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + + +namespace details { + + //grammar for a single object + template + struct obj_grammar : public karma::grammar()> { + typename Gen::generator subrule; + karma::rule()> start; + details::prop_gen prop; + + obj_grammar(); + static void getProperties(boost::shared_ptr ptr, typename details::pts::type& seq); + }; + + //when objects should not be generated we need to get a empy rule, as obj_rule_init + //trys always to access the rules attribute and when the parser_generator trait is not + //specialitzed it's impossible to have the attribute type right in the unspecialized trait + template + struct obj_generator_fold : mpl::fold< seq, state, + mpl::if_< parser_generate, + mpl::push_back > >, + mpl::push_back > > {}; + + //currently max. 10 objects are supported + template + struct obj_gen : public karma::grammar::type()> { + + typedef typename Sys::objects ObjectList; + + //create a vector with the appropriate rules for all objects. Do this with the rule init struct, as it gives + //automatic initialisation of the rules when the objects are created + typedef typename obj_generator_fold >::type init_rules_vector; + //push back a empty rule so that we know where to go when nothing is to do + typedef typename mpl::push_back::type rules_vector; + + //create the fusion sequence of our rules + typedef typename fusion::result_of::as_vector::type rules_sequnce; + + //this struct returns the right accessvalue for the sequences. If we access a value bigger than the property vector size + //we use the last rule, as we made sure this is an empty one + template + struct index : public mpl::if_< mpl::less, mpl::size >, + mpl::int_, typename mpl::size::prior >::type {}; + //this struct tells us if we should execute the generator + template + struct valid : public mpl::less< mpl::int_, mpl::size > {}; + + rules_sequnce rules; + karma::rule::type()> obj; + + obj_gen(); + }; +} //namespace details +}//dcm + +#ifndef USE_EXTERNAL + #include "object_generator_imp.hpp" +#endif + +#endif //DCM_OBJECT_GENERATOR_H \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp new file mode 100644 index 0000000000..1114f19e88 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp @@ -0,0 +1,57 @@ +#ifndef DCM_OBJECT_GENERATOR_IMP_H +#define DCM_OBJECT_GENERATOR_IMP_H + + +#include "traits_impl.hpp" +#include "object_generator.hpp" +#include "property_generator_imp.hpp" + +using namespace boost::spirit::karma; +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + + +namespace details { + +template +obj_grammar::obj_grammar() : obj_grammar::base_type(start) { + Gen::init(subrule); + start = lit("\n") << '+' << eol << subrule + << prop[phx::bind(&obj_grammar::getProperties, _val, karma::_1)] + << '-' << eol << lit(""); +}; + +template +void obj_grammar::getProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { + + if(ptr) seq = ptr->m_properties; + else { + //TODO: throw + }; +}; + +template +obj_gen::obj_gen() : obj_gen::base_type(obj) { + + obj = -(eps(valid<0>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<1>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<2>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<3>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<4>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<5>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<6>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<7>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<8>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<9>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]); + +}; + +} //namespace details +}//dcm + +#endif //DCM_OBJECT_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp new file mode 100644 index 0000000000..ab4525865b --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp @@ -0,0 +1,98 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_OBJECT_PARSER_H +#define DCM_OBJECT_PARSER_H + +#include "property_parser.hpp" + +namespace dcm { +namespace details { + +template +struct empty_obj_parser : public qi::grammar(Sys*), qi::space_type> { + qi::rule(Sys*), qi::space_type> start; + empty_obj_parser(): empty_obj_parser::base_type(start) { + //start = qi::eps(false); +}; +}; + +//grammar for a single object +template +struct obj_parser : public qi::grammar(Sys*), qi::space_type> { + typename Par::parser subrule; + qi::rule(Sys*), qi::space_type> start; + prop_par prop; + + obj_parser(); + + static void setProperties(boost::shared_ptr ptr, typename details::pts::type& seq); +}; + +//when objects should not be generated we need to get a empy rule, as obj_rule_init +//trys always to access the rules attribute and when the parser_generator trait is not +//specialitzed it's impossible to have the attribute type right in the unspecialized trait +template +struct obj_parser_fold : mpl::fold< seq, state, + mpl::if_< parser_parse, + mpl::push_back > >, + mpl::push_back > > > {}; + +//currently max. 10 objects are supported +template +struct obj_par : public qi::grammar::type(Sys*), + qi::space_type> { + + typedef typename Sys::objects ObjectList; + + //create a vector with the appropriate rules for all objects. Do this with the rule init struct, as it gives + //automatic initialisation of the rules when the objects are created + typedef typename obj_parser_fold >::type init_rules_vector; + //push back a empty rule so that we know where to go when nothing is to do + typedef typename mpl::push_back::type, Sys> >::type rules_vector; + + //create the fusion sequence of our rules + typedef typename fusion::result_of::as_vector::type rules_sequnce; + + //this struct returns the right accessvalue for the sequences. If we access a value bigger than the property vector size + //we use the last rule, as we made sure this is an empty one + template + struct index : public mpl::if_< mpl::less, mpl::size >, + mpl::int_, typename mpl::size::prior >::type {}; + //this struct tells us if we should execute the generator + template + struct valid : public mpl::less< mpl::int_, mpl::size > {}; + + rules_sequnce rules; + qi::rule::type(Sys*), qi::space_type> obj; + + obj_par(); + }; + +}//details +}//DCM + +#ifndef USE_EXTERNAL + #include "property_parser_imp.hpp" +#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp new file mode 100644 index 0000000000..4ee6027612 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp @@ -0,0 +1,63 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_OBJECT_PARSER_IMP_H +#define DCM_OBJECT_PARSER_IMP_H + +#include "object_parser.hpp" +#include "property_parser_imp.hpp" + +namespace dcm { +namespace details { + +template +obj_parser::obj_parser(): obj_parser::base_type(start) { + Par::init(subrule); + start = qi::lit("") >> subrule(qi::_r1)[qi::_val = qi::_1] + >> qi::eps(qi::_val)[ phx::bind(&Sys::template push_back, qi::_r1, qi::_val)] + >> prop[phx::bind(&obj_parser::setProperties, qi::_val, qi::_1)] + >> qi::lit(""); +}; + +template +void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { + if(ptr) ptr->m_properties = seq; +}; + +template +obj_par::obj_par(): obj_par::base_type(obj) { + + obj = -(qi::eps(valid<0>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<1>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<2>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<3>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<4>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<5>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<6>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<7>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<8>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<9>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]); + +}; + +}//details +}//DCM + + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp new file mode 100644 index 0000000000..1ff58c444e --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp @@ -0,0 +1,82 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_H +#define DCM_PARSER_H + +#include + +#include +#include +#include +#include + +#include "opendcm/core/clustergraph.hpp" + +#include "property_parser.hpp" +#include "object_parser.hpp" +#include "edge_vertex_parser.hpp" +#include "extractor.hpp" + +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; +namespace phx = boost::phoenix; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +struct sp : qi::grammar { + + qi::rule start; + sp() : sp::base_type(start) { + start %= +qi::char_; +}; +static void print(std::string s) { + std::cout<<"parsed string:"< +struct parser : qi::grammar, qi::space_type> { + + typedef typename Sys::Cluster graph; + + parser(); + + qi::rule, qi::space_type> cluster; + details::cluster_prop_par cluster_prop; + + details::obj_par objects; + + details::vertex_parser vertex; + details::edge_parser edge; + + sp str; + Injector in; +}; + +} + +#ifndef USE_EXTERNAL +#include "parser_imp.hpp" +#endif + +#endif //DCM_PARSER_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp new file mode 100644 index 0000000000..6b9f42b812 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp @@ -0,0 +1,71 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_IMP_H +#define DCM_PARSER_IMP_H + +#include + +#include "opendcm/core/system.hpp" + +#include +#include +#include + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (T1)(T2)(T3)(T4), + (dcm::ClusterGraph) (T1)(T2)(T3)(T4), + (typename dcm::details::pts::type, m_cluster_bundle)) + +#include "parser.hpp" + + +namespace boost { namespace spirit { namespace traits +{ + template + struct transform_attribute*, dcm::ClusterGraph, qi::domain> + { + typedef dcm::ClusterGraph& type; + static type pre(dcm::ClusterGraph* const& val) { + return *val; + } + static void post(dcm::ClusterGraph* const& val, dcm::ClusterGraph const& attr) {} + static void fail(dcm::ClusterGraph* const&) {} + }; +}}} + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +template +parser::parser() : parser::base_type(cluster) { + + cluster %= qi::lit("" + >> -(qi::eps( qi::_a > 0 )[qi::_val = phx::new_()]) + >> qi::eps[phx::bind(&Injector::setVertexProperty, in, qi::_val, qi::_a)] + >> qi::attr_cast(cluster_prop >> qi::eps) + >> qi::omit[*vertex(qi::_val, qi::_r1)] + >> qi::omit[*edge(qi::_val, qi::_r1)] + >> qi::omit[*(cluster(qi::_r1)[phx::bind(&Injector::addCluster, in, qi::_val, qi::_1)])] + >> "";// >> str[&sp::print]; +}; + +} +#endif //DCM_PARSER_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp new file mode 100644 index 0000000000..5637679a6d --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp @@ -0,0 +1,102 @@ +#ifndef DCM_PROPERTY_GENERATOR_H +#define DCM_PROPERTY_GENERATOR_H + +#include +#include + +#include +#include +#include +#include + +#include "traits.hpp" + +namespace karma = boost::spirit::karma; +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +namespace details { + +//a grammar that does nothing exept failing +struct empty_grammar : public karma::grammar { + karma::rule start; + empty_grammar(): empty_grammar::base_type(start) { + start = karma::eps(true); + }; + empty_grammar(const empty_grammar& other) : empty_grammar::base_type(start) {}; +}; + +template +struct skip_grammar : public karma::grammar { + karma::rule start; + skip_grammar() : skip_grammar::base_type(start) { + start = karma::eps(true); + }; + skip_grammar(const skip_grammar& other) : skip_grammar::base_type(start) {}; +}; + +//grammar for a single property +template +struct prop_grammar : public karma::grammar { + typename Gen::generator subrule; + karma::rule start; + prop_grammar(); + prop_grammar(const prop_grammar& other) : prop_grammar::base_type(start) {}; +}; + +template +struct prop_generator_fold : mpl::fold< seq, state, + mpl::if_< parser_generate, + mpl::push_back > >, + mpl::push_back > > > {}; + +//grammar for a fusion sequence of properties. currently max. 10 properties are supported +template +struct prop_gen : karma::grammar::type&()> { + + //create a vector with the appropriate rules for all properties. + typedef typename prop_generator_fold >::type init_rules_sequence; + //allow max 10 types as the following code expect this + BOOST_MPL_ASSERT((mpl::less_equal< mpl::size, mpl::int_<10> >)); + //we want to process 10 elements, so create a vector with (10-prop.size()) empty rules + //and append it to our rules vector + typedef mpl::range_c, mpl::size >::value > range; + typedef typename mpl::fold< range, + init_rules_sequence, + mpl::push_back >::type rules_sequence; + + typename fusion::result_of::as_vector::type rules; + karma::rule::type&()> prop; + + prop_gen(); +}; + +//special prop classes for better externalisaton, therefore the outside constructor to avoid auto inline +template +struct cluster_prop_gen : public prop_gen { + cluster_prop_gen(); +}; + +template +struct vertex_prop_gen : public prop_gen { + vertex_prop_gen(); +}; + +template +struct edge_prop_gen : public prop_gen { + edge_prop_gen(); +}; + +}//details +}//dcm + +#ifndef USE_EXTERNAL +#include "property_generator_imp.hpp" +#endif + +#endif //DCM_PROPERTY_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp new file mode 100644 index 0000000000..38fa4ed749 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp @@ -0,0 +1,43 @@ +#ifndef DCM_PROPERTY_GENERATOR_IMP_H +#define DCM_PROPERTY_GENERATOR_IMP_H + +#include "property_generator.hpp" +#include "traits_impl.hpp" + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +namespace details { + +//grammar for a single property +template +prop_grammar::prop_grammar() : prop_grammar::base_type(start) { + + Gen::init(subrule); + start = karma::lit("\n") << '+' << karma::eol << subrule + << '-' << karma::eol << karma::lit(""); +}; + +template +prop_gen::prop_gen() : prop_gen::base_type(prop) { + + prop = fusion::at_c<0>(rules) << fusion::at_c<1>(rules) << fusion::at_c<2>(rules) + << fusion::at_c<3>(rules) << fusion::at_c<4>(rules) << fusion::at_c<5>(rules) + << fusion::at_c<6>(rules) << fusion::at_c<7>(rules) << fusion::at_c<8>(rules) + << fusion::at_c<9>(rules); +}; + +template +cluster_prop_gen::cluster_prop_gen() : prop_gen() {}; + +template +vertex_prop_gen::vertex_prop_gen() : prop_gen() {}; + +template +edge_prop_gen::edge_prop_gen() : prop_gen() {}; + +}//details +}//dcm + +#endif //DCM_PROPERTY_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp new file mode 100644 index 0000000000..6e404bfa87 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp @@ -0,0 +1,120 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PROPERTY_PARSER_H +#define DCM_PROPERTY_PARSER_H + +#include +#include +#include +#include + +#include +#include + +namespace fusion = boost::fusion; +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; +namespace phx = boost::phoenix; +namespace mpl = boost::mpl; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +struct empty_parser : public qi::grammar { + qi::rule start; + empty_parser(): empty_parser::base_type(start) { + start = qi::eps(true); + }; + empty_parser(const empty_parser& other) : empty_parser::base_type(start) {}; +}; + +template +struct skip_parser : public qi::grammar { + qi::rule start; + skip_parser() : skip_parser::base_type(start) { + start = qi::eps(true); + }; + skip_parser(const skip_parser& other) : skip_parser::base_type(start) {}; +}; + +template +struct prop_parser : qi::grammar { + + typename Par::parser subrule; + qi::rule start; + prop_parser(); + prop_parser(const prop_parser& other) : prop_parser::base_type(start) {}; +}; + +template +struct prop_parser_fold : mpl::fold< seq, state, + mpl::if_< dcm::parser_parse, + mpl::push_back > >, + mpl::push_back > > > {}; + +//grammar for a fusion sequence of properties. currently max. 10 properties are supported +template +struct prop_par : qi::grammar::type(), qi::space_type> { + + //create a vector with the appropriate rules for all properties. + typedef typename prop_parser_fold >::type init_rules_sequence; + //allow max 10 types as the following code expect this + BOOST_MPL_ASSERT((mpl::less_equal< mpl::size, mpl::int_<10> >)); + //we want to process 10 elements, so create a vector with (10-prop.size()) empty rules + //and append it to our rules vector + typedef mpl::range_c, mpl::size >::value > range; + typedef typename mpl::fold< range, + init_rules_sequence, + mpl::push_back >::type rules_sequence; + + typename fusion::result_of::as_vector::type rules; + qi::rule::type(), qi::space_type> prop; + + prop_par(); +}; + + //special prop classes for better externalisaton, therefore the outside constructor to avoid auto inline + template + struct cluster_prop_par : public prop_par { + cluster_prop_par(); + }; + + template + struct vertex_prop_par : public prop_par { + vertex_prop_par(); + }; + + template + struct edge_prop_par : public prop_par { + edge_prop_par(); + }; + +} //DCM +} //details + +#ifndef USE_EXTERNAL + #include "property_parser_imp.hpp" +#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp new file mode 100644 index 0000000000..4fa920c8d6 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp @@ -0,0 +1,60 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PROPERTY_PARSER_IMP_H +#define DCM_PROPERTY_PARSER_IMP_H + +#include "property_parser.hpp" + + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +template +prop_parser::prop_parser() : prop_parser::base_type(start) { + Par::init(subrule); + start %= qi::lit("") >> subrule >> qi::lit(""); +}; + + +template +prop_par::prop_par() : prop_par::base_type(prop) { + + prop %= fusion::at_c<0>(rules) >> fusion::at_c<1>(rules) >> fusion::at_c<2>(rules) + >> fusion::at_c<3>(rules) >> fusion::at_c<4>(rules) >> fusion::at_c<5>(rules) + >> fusion::at_c<6>(rules) >> fusion::at_c<7>(rules) >> fusion::at_c<8>(rules) + >> fusion::at_c<9>(rules); +}; + +template +cluster_prop_par::cluster_prop_par() : prop_par() {}; + +template +vertex_prop_par::vertex_prop_par() : prop_par() {}; + +template +edge_prop_par::edge_prop_par() : prop_par() {}; + +} //DCM +} //details + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp new file mode 100644 index 0000000000..94c4a9b4af --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp @@ -0,0 +1,53 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_TRAITS_H +#define DCM_PARSER_TRAITS_H + +#include +#include + +namespace dcm { + +template +struct parser_generate : public boost::mpl::false_ {}; + +template +struct parser_generator { + typedef int generator; + + static void init(generator& r) { + assert(false); + }; +}; + +template +struct parser_parse : public boost::mpl::false_ {}; + +template +struct parser_parser { + typedef int parser; + + static void init(parser& r) { + assert(false); + }; +}; + +} +#endif //DCM_PARSER_TRAITS_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp new file mode 100644 index 0000000000..bb49a7eb94 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp @@ -0,0 +1,160 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +//move the traits specializations outside of the traits definition to avoid the spirit header parsing every +//time this module is included and just parse it in externalisation mode when the generator is build + +#ifndef DCM_PARSER_TRAITS_IMPL_H +#define DCM_PARSER_TRAITS_IMPL_H + +#include "traits.hpp" +#include "defines.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace karma = boost::spirit::karma; +namespace qi = boost::spirit::qi; + +namespace boost { +namespace spirit { +namespace traits { +template <> +struct create_generator { + + typedef BOOST_TYPEOF(karma::eps(false)) type; + static type call() { + return karma::eps(false); + } +}; +} +} +} + +namespace dcm { + + template +struct parser_generate : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("clustertype\n") << karma::int_ <<""; + }; +}; + +template +struct parser_generate : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("clusterchanged\n") << karma::bool_ <<""; + }; +}; + +template +struct parser_generate, System> + : public mpl::not_ > {}; + +template +struct parser_generator, System, iterator> { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("id\n") << karma::auto_ <<""; + }; +}; + + template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("clustertype") >> ("") >> qi::int_ >>""; + }; +}; + +template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("clusterchanged") >> ("") >> qi::bool_ >>""; + }; +}; + +template +struct parser_parse, System> + : public mpl::not_ > {}; + +template +struct parser_parser, System, iterator> { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("id") >> ("") >> qi::auto_ >>""; + }; +}; +/* +template +struct parser_generate + : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("id\n") << karma::int_ <<""; + }; +}; + +template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("id") >> ("") >> qi::int_ >>""; + }; +};*/ + +} //namespace dcm + +#endif //DCM_PARSER_TRAITS_IMPL_H \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/modulepart.hpp b/src/Mod/Assembly/App/opendcm/modulepart.hpp new file mode 100644 index 0000000000..b121ea2e32 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulepart.hpp @@ -0,0 +1,29 @@ +/* + 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_MODULEPART_H +#define DCM_MODULEPART_H + +#define DCM_USE_MODULEPART + +#include "modulePart/geometry.hpp" +#include "modulePart/module.hpp" + +#endif //DCM_MODULEPART_H + diff --git a/src/Mod/Assembly/App/opendcm/modulestate.hpp b/src/Mod/Assembly/App/opendcm/modulestate.hpp new file mode 100644 index 0000000000..3b5ef5f074 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulestate.hpp @@ -0,0 +1,29 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULEPARSER_H +#define DCM_MODULEPARSER_H + +#define DCM_USE_MODULESTATE + +#include "moduleState/module.hpp" +#include "moduleState/traits.hpp" + +#endif //DCM_MODULEPARSER_H +