fw4spl
VersionsGraph.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2016.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #ifndef WIN32
8 // To fix problem in class boost::detail::stored_edge_property
9 // Default constructor is a move constructor and no copy constructor is implemented
10 // The instance of the class can not be copied.
11 #define BOOST_NO_CXX11_RVALUE_REFERENCES
12 #define BOOST_NO_CXX11_REF_QUALIFIERS
13 #endif
14 #include <algorithm>
15 #include <boost/graph/graph_traits.hpp>
16 #include <boost/graph/adjacency_list.hpp>
17 #include <boost/graph/dijkstra_shortest_paths.hpp>
18 #include <boost/graph/breadth_first_search.hpp>
19 #include <fwCore/spyLog.hpp>
20 
21 #include "fwAtomsPatch/exceptions/UnknownVersion.hpp"
22 
23 #include "fwAtomsPatch/VersionsGraph.hpp"
24 
25 namespace fwAtomsPatch
26 {
27 
28 class VertexVisitor : public boost::default_bfs_visitor
29 {
30 public:
31 
32  VertexVisitor(std::vector< std::string >* vector) : m_vector(vector)
33  {
34  }
35 
36  void discover_vertex(VersionsGraph::NodeIDType n, VersionsGraph::GraphType g)
37  {
38  m_vector->push_back( g[n].getVersionName());
39  }
40 
41 protected:
42  std::vector< std::string >* m_vector;
43 };
44 
46 {
47 }
48 
49 // ----------------------------------------------------------------------------
50 
52 {
53 }
54 
55 // ----------------------------------------------------------------------------
56 
58 {
59  ::fwCore::mt::WriteLock lock(m_nodesMutex);
60  NodeIDType newNode = this->createOrUpdateNode(node);
61  m_nodes[node] = newNode;
62 }
63 
64 // ----------------------------------------------------------------------------
65 
67 {
68  ::fwCore::mt::WriteLock lock(m_edgesMutex);
69  EdgeIDType newEdge = this->createEdge(edge);
70  m_edges[edge] = newEdge;
71 }
72 
73 // ----------------------------------------------------------------------------
74 
75 VersionsGraph::VersionSeriesType VersionsGraph::shortestPath(const std::string& origin,
76  const std::string& target)
77 {
78  NodeIDType originID = this->getNode(origin);
79  NodeIDType targetID = this->getNode(target);
80  return this->shortestPath(this->getNode(originID), this->getNode(targetID));
81 }
82 
83 // ----------------------------------------------------------------------------
84 
85 VersionsGraph::VersionSeriesType VersionsGraph::shortestPath(const NodeType& origin, const NodeType& target)
86 {
87  VersionSeriesType serie;
88 
89  ::fwCore::mt::ReadLock nodesLock(m_nodesMutex);
90  ::fwCore::mt::ReadLock graphLock(m_graphMutex);
91 
92  std::vector< NodeIDType > predecessor( ::boost::num_vertices(m_graph) );
93  std::vector< int > distances( ::boost::num_vertices(m_graph) );
94 
95  const NodeIDType& vOrig = m_nodes[origin];
96  ::boost::dijkstra_shortest_paths(m_graph, vOrig,
97  ::boost::weight_map(get(&EdgeType::m_weight, m_graph))
98  .predecessor_map(&predecessor[0])
99  .distance_map(::boost::make_iterator_property_map(distances.begin(),
100  ::boost::get(::boost::
101  vertex_index,
102  m_graph )))
103  );
104 
105  NodeIDType current = m_nodes[target];
106 
107  while(current != predecessor[current])
108  {
109  serie.insert(serie.begin(), current);
110  current = predecessor[current];
111  }
112 
113  return serie;
114 }
115 
116 // ----------------------------------------------------------------------------
117 
119 {
120  ::fwCore::mt::ReadLock lock(m_graphMutex);
121  return m_graph[nodeID];
122 }
123 
124 // ----------------------------------------------------------------------------
125 
126 VersionsGraph::NodeIDType VersionsGraph::getNode(const std::string& name) const
127 {
128  ::fwCore::mt::ReadLock lock(m_nodesMutex);
129  ExistingNodesType::const_iterator it;
130  for(it = m_nodes.begin(); it != m_nodes.end(); ++it)
131  {
132  if(it->first.getVersionName() == name)
133  {
134  break;
135  }
136  }
137 
138  if(it == m_nodes.end())
139  {
140  throw ::fwAtomsPatch::exceptions::UnknownVersion("There is no version named \"" + name + "\".");
141  }
142 
143  return it->second;
144 }
145 
146 // ----------------------------------------------------------------------------
147 
148 VersionsGraph::EdgeType VersionsGraph::getEdge(const NodeIDType& origin, const NodeIDType& target)
149 {
150  EdgeIDType edgeID;
151  bool success = false;
152  ::fwCore::mt::ReadLock lock(m_graphMutex);
153  ::boost::tie(edgeID,success) = ::boost::edge(origin, target, m_graph);
154  OSLM_ASSERT("There is no edge between '" << m_graph[origin].getVersionName() <<"' and '"
155  << m_graph[target].getVersionName() << "'.", success);
156  return m_graph[edgeID];
157 }
158 
159 // ----------------------------------------------------------------------------
160 
161 VersionsGraph::LinkedVersionType VersionsGraph::getLinkedVersion(
162  const NodeIDType& originID, const NodeIDType& targetID, LinkDescriptor::VersionIDType current)
163 {
164  NodeType origin = this->getNode(originID);
165  NodeType target = this->getNode(targetID);
166  EdgeType edge = this->getEdge(originID, targetID);
167 
168  bool success = false;
170  LinkDescriptor::LinksType::const_iterator linkIt;
171 
172  //Explicit
173  const LinkDescriptor::LinksType& links = edge.getLinks();
174  linkIt = links.find(current);
175  if(linkIt != links.end())
176  {
177  result = linkIt->second;
178  success = true;
179  }
180  //Implicit
181  else
182  {
183  VersionDescriptor::VersionsType::const_iterator versIt;
184  VersionDescriptor::VersionsType::const_iterator versItEnd = target.getVersions().end();
185  for(versIt = target.getVersions().begin(); versIt != versItEnd; ++versIt)
186  {
187  //Same type
188  if(current.first == versIt->first)
189  {
190  result = *versIt;
191  success = true;
192  break;
193  }
194  }
195  }
196 
197  return std::make_pair(result, success);
198 }
199 
200 // ----------------------------------------------------------------------------
201 
202 VersionsGraph::NodeIDType VersionsGraph::createOrUpdateNode(const NodeType& node)
203 {
204  ExistingNodesType::const_iterator cIt = m_nodes.find(node);
205  if(cIt != m_nodes.end())
206  {
207  return cIt->second;
208  }
209  else
210  {
211  ::fwCore::mt::WriteLock lock(m_graphMutex);
212  NodeIDType v = ::boost::add_vertex(m_graph);
213  m_graph[v] = node;
214  return v;
215  }
216 }
217 
218 // ----------------------------------------------------------------------------
219 
220 VersionsGraph::EdgeIDType VersionsGraph::createEdge(const EdgeType& edge)
221 {
222  NodeIDType origin = this->getNode(edge.getOriginVersion());
223  NodeIDType target = this->getNode(edge.getTargetVersion());
224 
225  EdgeIDType newEdge;
226  bool success = false;
227  ::fwCore::mt::ReadLock lock(m_graphMutex);
228  ::boost::tie(newEdge, success) = ::boost::add_edge(origin, target, edge, m_graph);
229 
230  OSLM_ASSERT("Unable to create the edge between '" << edge.getOriginVersion() << "' "
231  "and '" << edge.getTargetVersion() << "'", success);
232 
233  return newEdge;
234 }
235 
236 // ----------------------------------------------------------------------------
237 
238 std::vector< std::string > VersionsGraph::getConnectedVersions(const std::string &currentVersion)
239 {
240  std::vector< std::string > vector;
241  VertexVisitor vis(&vector);
242  try
243  {
244  ::fwCore::mt::ReadLock lock(m_graphMutex);
245  VersionsGraph::NodeIDType nodeId = this->getNode(currentVersion);
246  ::boost::breadth_first_search( m_graph, nodeId, ::boost::visitor(vis) );
247  vector.erase(vector.begin());
248  }
250  {
251  }
252 
253  return vector;
254 }
255 
256 
257 } // fwAtomsPatch
FWATOMSPATCH_API ~VersionsGraph()
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
const VersionsType & getVersions() const
Returns versions.
const std::string & getOriginVersion() const
Returns origin version.
Version descriptor used to identify a version.
Contains base functionalities used to transform objects from a version to another.
Definition: Abstract.hpp:16
::boost::unique_lock< ReadWriteMutex > WriteLock
Defines a lock of write type for read/write mutex.
Thrown when a given object version is unknown and can&#39;t be processed.
FWATOMSPATCH_API std::vector< std::string > getConnectedVersions(const std::string &currentVersion)
Get connected versions.
FWATOMSPATCH_API LinkedVersionType getLinkedVersion(const NodeIDType &originID, const NodeIDType &targetID, LinkDescriptor::VersionIDType current)
Returns the linked version of the current version and a boolean to say if a match has been found...
FWATOMSPATCH_API NodeType getNode(const NodeIDType &nodeID)
Returns the node matching given node ID.
const std::string & getTargetVersion() const
Returns target version.
Link descriptor used to identify a link between two versions.
::boost::shared_lock< ReadWriteMutex > ReadLock
Defines a lock of read type for read/write mutex.
FWATOMSPATCH_API void addNode(NodeType node)
Add a new version described by the given node.
FWATOMSPATCH_API EdgeType getEdge(const NodeIDType &origin, const NodeIDType &target)
Returns the edge located between given node IDs.
std::pair< std::string, std::string > VersionIDType
VersionID used to link type and version.
FWATOMSPATCH_API VersionsGraph()
std::map< VersionIDType, VersionIDType > LinksType
Links used to link two versions.
const LinksType & getLinks() const
Returns map of links between versions.
FWATOMSPATCH_API void addEdge(EdgeType edge)
Add a new edge described by the given edge.
FWATOMSPATCH_API VersionSeriesType shortestPath(const std::string &origin, const std::string &target)
Compute shortest path between two data version (i.e nodes).
This file defines SpyLog macros. These macros are used to log messages to a file or to the console du...