fw4spl
fwData/src/fwData/Graph.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2018.
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 #include "fwData/Graph.hpp"
8 
9 #include "fwData/Edge.hpp"
10 #include "fwData/Exception.hpp"
11 #include "fwData/Node.hpp"
12 #include "fwData/Port.hpp"
13 #include "fwData/registry/macros.hpp"
14 
15 #include <fwCom/Signal.hpp>
16 #include <fwCom/Signal.hxx>
17 #include <fwCom/Signals.hpp>
18 
19 #include <utility>
20 
21 fwDataRegisterMacro( ::fwData::Graph );
22 
23 namespace fwData
24 {
25 
26 const bool Graph::UP_STREAM = true;
27 const bool Graph::DOWN_STREAM = false;
28 
29 const ::fwCom::Signals::SignalKeyType Graph::s_UPDATED_SIG = "updated";
30 
31 //------------------------------------------------------------------------------
32 
34  m_sigUpdated(UpdatedSignalType::New())
35 {
36  // Init
37 
38  // Register
39  m_signals( s_UPDATED_SIG, m_sigUpdated);
40 
41 }
42 
43 //------------------------------------------------------------------------------
44 
46 {
47 }
48 
49 //------------------------------------------------------------------------------
50 
51 bool Graph::addNode( Node::sptr node)
52 {
53  return m_nodes.insert(node).second;
54 }
55 
56 //------------------------------------------------------------------------------
57 
58 bool Graph::removeNode( Node::csptr node)
59 {
60  // test if connected edge to it
61  if ( haveConnectedEdges(node) )
62  {
63  return false;
64  }
65  return (m_nodes.erase( Node::constCast(node) ) > 0 );
66 }
67 
68 //------------------------------------------------------------------------------
69 
70 Graph::NodeContainer& Graph::getNodes()
71 {
72  return m_nodes;
73 }
74 
75 //------------------------------------------------------------------------------
76 
77 const Graph::NodeContainer& Graph::getNodes() const
78 {
79  return m_nodes;
80 }
81 
82 //------------------------------------------------------------------------------
83 
84 bool Graph::haveConnectedEdges(Node::csptr node ) const
85 {
86  for(const auto& connection : m_connections)
87  {
88  if ( connection.second.first == node || connection.second.second == node)
89  {
90  return true;
91  }
92  }
93  return false;
94 }
95 
96 //------------------------------------------------------------------------------
97 
99  Node::csptr nodeSource,
100  std::string nodeSourceOutputPortID,
101  Node::csptr nodeDestination,
102  std::string nodeDestinationInputPortID,
103  std::string EdgeNature )
104 {
105  ::fwData::Edge::sptr nEdge = ::fwData::Edge::New();
106  nEdge->setIdentifiers( nodeSourceOutputPortID, nodeDestinationInputPortID );
107  nEdge->setNature( EdgeNature );
108  if ( addEdge( nEdge, nodeSource, nodeDestination ) )
109  {
110  return nEdge; // success return new Edge
111  }
112  else
113  {
114  return ::fwData::Edge::sptr(); // failure
115  }
116 }
117 
118 //------------------------------------------------------------------------------
119 
120 bool Graph::addEdge(Edge::sptr edge, Node::csptr nodeSource, Node::csptr nodeDestination)
121 {
122  // edge not already recorded
123  if (m_connections.find( edge ) != m_connections.end() )
124  {
125  return false; // edge already stored
126  }
127  // node registered ?
128  if (m_nodes.find( Node::constCast(nodeSource) ) == m_nodes.end() )
129  {
130  return false; // node already stored
131  }
132  // node registered ?
133  if ( m_nodes.find( Node::constCast(nodeDestination) ) == m_nodes.end() )
134  {
135  return false; // node already stored
136  }
137 
138  // test port existence
139  Port::sptr sourcePort = nodeSource->findPort( edge->getIdentifiers().first, DOWN_STREAM );
140  if ( !sourcePort )
141  {
142  return false; // port doesn't exist
143  }
144 
145  // test port existence
146  Port::sptr sourceDest = nodeDestination->findPort( edge->getIdentifiers().second, UP_STREAM );
147  if ( !sourceDest )
148  {
149  return false; // port doesn't exist
150  }
151 
152  // test port compatibility
153  if ( sourcePort->getType() != sourceDest->getType() )
154  {
155  return false; // incompatible type
156  }
157 
158  m_connections[ edge ] = std::make_pair( Node::constCast(nodeSource), Node::constCast(nodeDestination) );
159 
160  return true;
161 }
162 
163 //------------------------------------------------------------------------------
164 
165 bool Graph::removeEdge(Edge::sptr edge)
166 {
167  return ( m_connections.erase(edge) != 0 );
168 }
169 
170 //------------------------------------------------------------------------------
171 
172 Node::sptr Graph::getSourceNode(Edge::sptr edge)
173 {
174  return getNode( edge, UP_STREAM );
175 }
176 
177 //------------------------------------------------------------------------------
178 
179 Node::sptr Graph::getDestinationNode( Edge::sptr edge )
180 {
181  return getNode( edge, DOWN_STREAM );
182 }
183 
184 //------------------------------------------------------------------------------
185 
186 Node::sptr Graph::getNode( Edge::sptr edge, bool upStream )
187 {
188  ConnectionContainer::iterator i;
189  i = m_connections.find( edge );
190 
191  // check edge is valid ?
192  if ( i == m_connections.end() )
193  {
194  return Node::sptr();
195  }
196 
197  if( upStream )
198  {
199  return (*i).second.first;
200  }
201  else
202  {
203  return (*i).second.second;
204  }
205 }
206 
207 //------------------------------------------------------------------------------
208 
209 std::vector< Edge::sptr > Graph::getInputEdges( Node::csptr node )
210 {
211  return getEdges( node, UP_STREAM );
212 }
213 
214 //------------------------------------------------------------------------------
215 
216 std::vector< Edge::sptr > Graph::getOutputEdges( Node::csptr node )
217 {
218  return getEdges( node, DOWN_STREAM );
219 }
220 
221 //------------------------------------------------------------------------------
222 
223 std::vector< Edge::sptr > Graph::getEdges( const Node::csptr& node, bool upStream,
224  const std::string& nature,
225  const std::string& portID
226  )
227 {
228  SLM_ASSERT("Node " + node->getID() + " not found in graph", m_nodes.find( Node::constCast(node) ) !=
229  m_nodes.end());
230  SLM_ASSERT("Port " + portID + " not found on node" + node->getID(),
231  portID.empty() || node->findPort(portID, upStream));
232 
233  std::vector< Edge::sptr > result;
234  result.reserve(4);
235 
236  for(const auto& connection : m_connections)
237  {
238  const Edge::sptr& edge = connection.first;
239  const Node::sptr& nodeFrom = connection.second.first;
240  const Node::sptr& nodeTo = connection.second.second;
241 
242  bool isConnectedEdge = ( upStream ? nodeTo : nodeFrom ) == node;
243  if( !isConnectedEdge)
244  {
245  continue;
246  }
247 
248  bool isCorrectPort = portID.empty() || portID == ( upStream ? edge->getToPortID() : edge->getFromPortID() );
249  if( !isCorrectPort)
250  {
251  continue;
252  }
253 
254  bool isCorrectNature = nature.empty() || edge->getNature() == nature;
255  if( !isCorrectNature)
256  {
257  continue;
258  }
259 
260  result.push_back( edge );
261  }
262 
263  return result;
264 }
265 
266 //------------------------------------------------------------------------------
267 
268 std::vector< ::fwData::Node::sptr > Graph::getNodes( const ::fwData::Node::csptr& node,
269  bool upStream,
270  const std::string& nature,
271  const std::string& portID )
272 {
273  std::vector< Edge::sptr > edges;
274  edges = getEdges( node, upStream, nature, portID);
275 
276  std::vector< Node::sptr > nodes;
277  for(const Edge::sptr& edge : edges )
278  {
279  Node::sptr distantNode;
280  distantNode = ( upStream ? m_connections[edge].first : m_connections[edge].second );
281 
282  if( std::find( nodes.begin(), nodes.end(), distantNode ) == nodes.end() )
283  {
284  nodes.push_back(distantNode);
285  }
286  }
287 
288  return nodes;
289 }
290 
291 //------------------------------------------------------------------------------
292 
293 size_t Graph::getNbNodes() const
294 {
295  return m_nodes.size();
296 }
297 
298 //------------------------------------------------------------------------------
299 
300 size_t Graph::getNbEdges() const
301 {
302  return m_connections.size();
303 }
304 
305 //------------------------------------------------------------------------------
306 
307 const Graph::ConnectionContainer& Graph::getConnections() const
308 {
309  return m_connections;
310 }
311 
312 //------------------------------------------------------------------------------
313 
314 Graph::ConnectionContainer& Graph::getConnections()
315 {
316  return m_connections;
317 }
318 
319 //------------------------------------------------------------------------------
320 
321 void Graph::shallowCopy(const Object::csptr& _source )
322 {
323  Graph::csptr other = Graph::dynamicConstCast(_source);
324  FW_RAISE_EXCEPTION_IF( ::fwData::Exception(
325  "Unable to copy" + (_source ? _source->getClassname() : std::string("<NULL>"))
326  + " to " + this->getClassname()), !bool(other) );
327  this->fieldShallowCopy( _source );
328  m_nodes = other->m_nodes;
329  m_connections = other->m_connections;
330 }
331 
332 //------------------------------------------------------------------------------
333 
334 void Graph::cachedDeepCopy(const Object::csptr& _source, DeepCopyCacheType& cache)
335 {
336  Graph::csptr other = Graph::dynamicConstCast(_source);
337  FW_RAISE_EXCEPTION_IF( ::fwData::Exception(
338  "Unable to copy" + (_source ? _source->getClassname() : std::string("<NULL>"))
339  + " to " + this->getClassname()), !bool(other) );
340  this->fieldDeepCopy( _source, cache );
341 
342  std::map< ::fwData::Node::sptr, ::fwData::Node::sptr > correspondenceBetweenNodes;
343  typedef std::pair< Edge::sptr, std::pair< Node::sptr, Node::sptr > > ConnectionContainerElt;
344 
345  m_nodes.clear();
346  for(const ::fwData::Node::sptr& node : other->m_nodes)
347  {
348  ::fwData::Node::sptr newNode = ::fwData::Object::copy(node, cache);
349  bool addOK = this->addNode(newNode);
350  OSLM_ASSERT("Node "<<newNode->getID() <<" can't be added ", addOK );
351  FwCoreNotUsedMacro(addOK);
352  correspondenceBetweenNodes.insert(std::make_pair(node, newNode));
353  }
354 
355  m_connections.clear();
356  for(const ConnectionContainerElt& connection : other->m_connections)
357  {
358  // Edge deep copy .
359  ::fwData::Edge::sptr newEdge = ::fwData::Object::copy(connection.first, cache);
360  ::fwData::Node::sptr oldNode1 = (connection.second).first;
361  ::fwData::Node::sptr oldNode2 = (connection.second).second;
362  if ((correspondenceBetweenNodes.find(Node::constCast(oldNode1)) != correspondenceBetweenNodes.end())
363  && (correspondenceBetweenNodes.find(Node::constCast(oldNode2)) != correspondenceBetweenNodes.end()))
364  {
365  // Add new Edge
366  this->addEdge(newEdge, correspondenceBetweenNodes[oldNode1], correspondenceBetweenNodes[oldNode2]);
367  }
368  }
369  correspondenceBetweenNodes.clear();
370 }
371 
372 //------------------------------------------------------------------------------
373 
374 } // namespace fwData
This class defines a graph object.
FWDATA_API size_t getNbNodes() const
virtual const std::string & getClassname() const override
return full object&#39;s classname with its namespace, i.e. fwCore::BaseObject
FWDATA_API size_t getNbEdges() const
#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
Key class used to restrict access to Object construction. See http://www.drdobbs.com/184402053.
Implements data exception class.
virtual FWDATA_API ~Graph()
Destructor.
FWDATA_API std::vector< Edge::sptr > getOutputEdges(Node::csptr _node)
Get output edges.
FWDATA_API std::vector< Edge::sptr > getEdges(const Node::csptr &_node, bool _upStream, const std::string &_nature="", const std::string &_portID="")
Get a vector of edges.
FWDATA_API bool removeNode(Node::csptr _node)
remove a node
FWDATA_API bool haveConnectedEdges(Node::csptr _node) const
Check if an edge is connected to the node.
FWDATA_API Edge::sptr makeConnection(Node::csptr _nodeSource, std::string _nodeSourceOutputPortID, Node::csptr _nodeDestination, std::string _nodeDestinationInputPortID, std::string _EdgeNature)
create an edge from given info and add edge in the graph
FWDATA_API bool removeEdge(Edge::sptr _edge)
remove an edge
static FWDATA_APIconst::fwCom::Signals::SignalKeyType s_UPDATED_SIG
Updated signal key.
FWDATA_API void fieldDeepCopy(const ::fwData::Object::csptr &source)
A deep copy of fields (objects in m_children)
FWDATA_API bool addEdge(Edge::sptr _edge, Node::csptr _nodeSource, Node::csptr _nodeDestination)
Add and edge.
#define SLM_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:308
static FWDATA_API::fwData::Object::sptr copy(const ::fwData::Object::csptr &source)
return a copy of the source. if source is a null pointer, return a null pointer.
FWDATA_API std::vector< Edge::sptr > getInputEdges(Node::csptr _node)
Get input edges.
FWDATA_API Node::sptr getNode(Edge::sptr _edge, bool _upStream)
Get node.
FWDATA_API Node::sptr getSourceNode(Edge::sptr _edge)
Get source node.
FWDATA_API Graph(::fwData::Object::Key key)
Constructor.
UpdatedSignalType::sptr m_sigUpdated
Updated signal.
FWDATA_API Node::sptr getDestinationNode(Edge::sptr _edge)
Get destination node.
Contains the representation of the data objects used in the framework.
FWDATA_API void fieldShallowCopy(const ::fwData::Object::csptr &source)
A shallow copy of fields (objects in m_children)
FWDATA_API NodeContainer & getNodes()
Get the node container.
FWDATA_API bool addNode(Node::sptr _node)
add a node
FWDATA_API const ConnectionContainer & getConnections() const
Get the connection container.