]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Pipeline.cxx.d
Moved to version 1.0
[cpPlugins.git] / lib / cpPlugins / Pipeline.cxx.d
1 // =========================================================================
2 // @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
3 // =========================================================================
4
5 $include "Value.e"
6
7 #include <cpPlugins/Pipeline.h>
8 #include <boost/property_tree/ptree.hpp>
9 #include <boost/property_tree/xml_parser.hpp>
10 #include <boost/tokenizer.hpp>
11
12 // -------------------------------------------------------------------------
13 cpPlugins::Pipeline::TAdjMatrix::
14 TAdjMatrix( )
15 {
16 }
17
18 // -------------------------------------------------------------------------
19 cpPlugins::Pipeline::TAdjMatrix::
20 ~TAdjMatrix( )
21 {
22 }
23
24 // -------------------------------------------------------------------------
25 bool cpPlugins::Pipeline::TAdjMatrix::
26 HasConnection(
27   const std::string& oObj, const std::string& dObj,
28   const std::string& oPort, const std::string& dPort
29   ) const
30 {
31   TMatrix::const_iterator m = this->m_Matrix.find( oObj );
32   if( m != this->m_Matrix.end( ) )
33   {
34     TRow::const_iterator r = m->second.find( dObj );
35     if( r != m->second.end( ) )
36       return( r->second.find( TEdge( oPort, dPort ) ) != r->second.end( ) );
37     else
38       return( false );
39   }
40   else
41     return( false );
42 }
43
44 // -------------------------------------------------------------------------
45 cpPlugins::Pipeline::TAdjMatrix::
46 TEdges& cpPlugins::Pipeline::TAdjMatrix::
47 operator()( const std::string& o, const std::string& d )
48 {
49   TMatrix::iterator m = this->m_Matrix.find( o );
50   if( m != this->m_Matrix.end( ) )
51   {
52     TRow::iterator r = m->second.find( d );
53     if( r != m->second.end( ) )
54       return( r->second );
55   } // end if
56
57   // If not found...
58   this->m_Matrix[ o ][ d ] = TEdges( );
59   return( this->operator()( o, d ) );
60 }
61
62 // -------------------------------------------------------------------------
63 const cpPlugins::Pipeline::TAdjMatrix::
64 TEdges& cpPlugins::Pipeline::TAdjMatrix::
65 operator()( const std::string& o, const std::string& d ) const
66 {
67   TMatrix::const_iterator m = this->m_Matrix.find( o );
68   if( m != this->m_Matrix.end( ) )
69   {
70     TRow::const_iterator r = m->second.find( d );
71     if( r != m->second.end( ) )
72       return( r->second );
73   } // end if
74
75   // If not found...
76   cpPluginsErrorMacro( << "Connection not found." );
77 }
78
79 // -------------------------------------------------------------------------
80 template< >
81 void cpPlugins::Pipeline::TAdjMatrix::
82 SaveXML( boost::property_tree::ptree* node ) const
83 {
84   TMatrix::const_iterator m = this->m_Matrix.begin( );
85   for( ; m != this->m_Matrix.end( ); ++m )
86   {
87     TRow::const_iterator r = m->second.begin( );
88     for( ; r != m->second.end( ); r++ )
89     {
90       for( const TEdge& e: r->second )
91       {
92         boost::property_tree::ptree c;
93         c.put( "<xmlattr>.from", e.first + "@" + m->first );
94         c.put( "<xmlattr>.to", e.second + "@" + r->first );
95         node->add_child( "pipeline.connection", c );
96
97       } // end for
98     } // end for
99   } // end for
100 }
101
102 // -------------------------------------------------------------------------
103 void cpPlugins::Pipeline::
104 Clear( )
105 {
106   // TODO
107 }
108
109 // -------------------------------------------------------------------------
110 cpPlugins::ProcessObject* cpPlugins::Pipeline::
111 CreateNode( const std::string& class_name, const std::string& node_name )
112 {
113   // Create object
114   cpPlugins::ProcessObject::SharedPtr p = this->m_Mgr.Create( class_name );
115   if( !p )
116     cpPluginsErrorMacro(
117       << "Something went wrong creating an object of type \""
118       << class_name << "\""
119       );
120
121   // Assign an unique name to it
122   std::string u = ( node_name == "" )? class_name: node_name;
123   while( !( this->m_Nodes.insert( TNodes::value_type( u, p ) ).second ) )
124     u += "_";
125   p->SetName( u );
126   p->SetPipeline( this );
127   p->SetExecutionDebug( this->GetExecutionDebug( ) );
128
129   // Connect parameters
130   std::set< std::string > names;
131   {{#t}}
132   names = p->Get{{t}}ValueNames( );
133   for( const std::string& n: names )
134     this->Configure{{t}}Value( n + "@" + u, p->Get{{t}}ValueTemplate( n ) );
135   names.clear( );
136   {{/t}}
137
138   // TODO: connect set/sequences
139
140   return( p.get( ) );
141 }
142
143 // -------------------------------------------------------------------------
144 cpPlugins::ProcessObject* cpPlugins::Pipeline::
145 GetNode( const std::string& name )
146 {
147   TNodes::iterator i = this->m_Nodes.find( name );
148   if( i != this->m_Nodes.end( ) )
149     return( i->second.get( ) );
150   else
151     return( NULL );
152 }
153
154 // -------------------------------------------------------------------------
155 const cpPlugins::ProcessObject* cpPlugins::Pipeline::
156 GetNode( const std::string& name ) const
157 {
158   TNodes::const_iterator i = this->m_Nodes.find( name );
159   if( i != this->m_Nodes.end( ) )
160     return( i->second.get( ) );
161   else
162     return( NULL );
163 }
164
165 // -------------------------------------------------------------------------
166 void cpPlugins::Pipeline::
167 Connect(
168   const std::string& oObj, const std::string& dObj,
169   const std::string& oPort, const std::string& dPort
170   )
171 {
172   TNodes::iterator oIt = this->m_Nodes.find( oObj );
173   TNodes::iterator dIt = this->m_Nodes.find( dObj );
174   TNodes::iterator eIt = this->m_Nodes.end( );
175   if( oIt == eIt || dIt == eIt )
176     cpPluginsErrorMacro( this, << "Connection not possible." );
177   if( this->m_AdjMatrix.HasConnection( oObj, dObj, oPort, dPort ) )
178     return;
179
180   // Check destination node
181   cpPlugins::ProcessObject::SharedPtr dest = dIt->second;
182   if( !dest )
183     cpPluginsErrorMacro(
184       this, << "Invalid destination \"" << dObj << "\"."
185       );
186
187   // Process source node
188   cpPlugins::Filter* src = oIt->second->Cast< cpPlugins::Filter >( );
189   if( src == NULL )
190     this->_Connect(
191       oIt->second->Cast< cpPlugins::Functor >( ), oPort, dest.get( ), dPort
192       );
193   else
194     this->_Connect( src, oPort, dest.get( ), dPort );
195
196   // Update adjacency matrix
197   this->m_AdjMatrix( oObj, dObj ).insert( TEdge( oPort, dPort ) );
198 }
199
200 // -------------------------------------------------------------------------
201 void cpPlugins::Pipeline::
202 Connect( const std::string& src, const std::string& dest )
203 {
204   std::string oObj, dObj, oPort, dPort;
205   Self::_ParseComponentName( src, oObj, oPort );
206   Self::_ParseComponentName( dest, dObj, dPort );
207   this->Connect( oObj, dObj, oPort, dPort );
208 }
209
210 // -------------------------------------------------------------------------
211 void cpPlugins::Pipeline::
212 LoadXML( const std::string& fname )
213 {
214   boost::property_tree::ptree xml;
215   boost::property_tree::read_xml( fname, xml );
216
217   // Check for a single pipeline
218   const boost::property_tree::ptree* pipeline = NULL;
219   for( const boost::property_tree::ptree::value_type& v: xml )
220   {
221     if( v.first == "pipeline" )
222     {
223       if( pipeline != NULL )
224         cpPluginsErrorMacro( << "Multiple pipelines are not supported." );
225       pipeline = &( v.second );
226
227     } // end if
228   } // end for
229
230   // Ok, seems ok to reset current pipeline
231   this->Clear( );
232
233   // Get description
234   boost::optional< std::string > desc =
235     pipeline->get_optional< std::string >( "<xmlattr>.desc" );
236   if( desc )
237     this->m_Description = desc.get( );
238
239   // Load nodes
240   for( const boost::property_tree::ptree::value_type& node: *pipeline )
241   {
242     if( node.first == "node" )
243     {
244       std::string name = node.second.get< std::string >( "<xmlattr>.name" );
245       std::string cname = node.second.get< std::string >( "<xmlattr>.class" );
246       cpPlugins::ProcessObject* n = this->CreateNode( cname, name );
247       n->LoadXML( node );
248
249     } // end if
250   } // end for
251
252   // Load connections
253   for( const boost::property_tree::ptree::value_type& c: *pipeline )
254     if( c.first == "connection" )
255       this->Connect(
256         c.second.get< std::string >( "<xmlattr>.from" ),
257         c.second.get< std::string >( "<xmlattr>.to" )
258         );
259 }
260
261 // -------------------------------------------------------------------------
262 void cpPlugins::Pipeline::
263 SaveXML( const std::string& fname ) const
264 {
265   boost::property_tree::ptree d;
266   if( this->m_Description != "" )
267     d.put( "pipeline.<xmlattr>.desc", this->m_Description );
268
269   // Save nodes
270   TNodes::const_iterator n = this->m_Nodes.begin( );
271   for( ; n != this->m_Nodes.end( ); ++n )
272     n->second->SaveXML( &d );
273
274   // Save connections
275   this->m_AdjMatrix.SaveXML( &d );
276
277   // Real write
278   boost::property_tree::xml_writer_settings< std::string > s( ' ', 2 );
279   boost::property_tree::write_xml( fname, d, std::locale( ), s );
280 }
281
282 // -------------------------------------------------------------------------
283 bool cpPlugins::Pipeline::
284 GetExecutionDebug( ) const
285 {
286   return( this->m_PipelineExecutionDebug );
287 }
288
289 // -------------------------------------------------------------------------
290 void cpPlugins::Pipeline::
291 SetExecutionDebug( bool d )
292 {
293   this->m_PipelineExecutionDebug = d;
294   for( TNodes::value_type& n: this->m_Nodes )
295     n.second->SetExecutionDebug( d );
296 }
297
298 // -------------------------------------------------------------------------
299 {{#t}}
300 void cpPlugins::Pipeline::
301 Modified{{t}}Value( const std::string& name )
302 {
303   // Guess information
304   std::string n, v;
305   Self::_ParseComponentName( name, n, v );
306
307   // Find node
308   TNodes::iterator node = this->m_Nodes.find( n );
309   if( node == this->m_Nodes.end( ) )
310     cpPluginsErrorMacro(
311       this, << "Unknown node \"" << n << "\"."
312       );
313
314   // Get configured value and continue
315   node->second->Set{{t}}Value( v, this->Get{{t}}Value( name ) );
316   this->Superclass::Modified{{t}}Value( name );
317 }
318
319 // -------------------------------------------------------------------------
320 void cpPlugins::Pipeline::
321 Modified{{t}}Set( const std::string& name )
322 {
323   std::cout << "Modified{{t}}Set: " << name << std::endl;
324   this->Superclass::Modified{{t}}Set( name );
325 }
326
327 // -------------------------------------------------------------------------
328 void cpPlugins::Pipeline::
329 Modified{{t}}Sequence( const std::string& name )
330 {
331   std::cout << "Modified{{t}}Sequence: " << name << std::endl;
332   this->Superclass::Modified{{t}}Sequence( name );
333 }
334 {{/t}}
335
336 // -------------------------------------------------------------------------
337 void cpPlugins::Pipeline::
338 ModifiedChoice( const std::string& name )
339 {
340   std::cout << "ModifiedChoice: " << name << std::endl;
341   this->Superclass::ModifiedChoice( name );
342 }
343
344 // -------------------------------------------------------------------------
345 void cpPlugins::Pipeline::
346 DefineInput(
347   const std::string& input, const std::string& node, const std::string& port
348   )
349 {
350   if(
351     this->m_InputRelations.insert(
352       TPortRelations::value_type( input, TEdge( node, port ) )
353       ).second
354     )
355     this->Modified( );
356 }
357
358 // -------------------------------------------------------------------------
359 void cpPlugins::Pipeline::
360 SetInput( const std::string& name, cpPlugins::DataObject* data )
361 {
362   // Guess information
363   std::string n, o;
364   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
365   if( rIt != this->m_InputRelations.end( ) )
366   {
367     n = rIt->second.first;
368     o = rIt->second.second;
369   }
370   else
371     Self::_ParseComponentName( name, n, o );
372
373   // Find node
374   TNodes::iterator node = this->m_Nodes.find( n );
375   if( node == this->m_Nodes.end( ) )
376     cpPluginsErrorMacro(
377       this, << "Unknown node \"" << n << "\"."
378       );
379   node->second->SetInput( o, data );
380 }
381
382 // -------------------------------------------------------------------------
383 cpPlugins::DataObject* cpPlugins::Pipeline::
384 GetInput( const std::string& name, const unsigned int id )
385 {
386   // Guess information
387   std::string n, o;
388   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
389   if( rIt != this->m_InputRelations.end( ) )
390   {
391     n = rIt->second.first;
392     o = rIt->second.second;
393   }
394   else
395     Self::_ParseComponentName( name, n, o );
396
397   // Find node
398   TNodes::iterator node = this->m_Nodes.find( n );
399   if( node == this->m_Nodes.end( ) )
400     cpPluginsErrorMacro(
401       this, << "Unknown node \"" << n << "\"."
402       );
403   return( node->second->GetInput( o, id ) );
404 }
405
406 // -------------------------------------------------------------------------
407 const cpPlugins::DataObject* cpPlugins::Pipeline::
408 GetInput( const std::string& name, const unsigned int id ) const
409 {
410   // Guess information
411   std::string n, o;
412   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
413   if( rIt != this->m_InputRelations.end( ) )
414   {
415     n = rIt->second.first;
416     o = rIt->second.second;
417   }
418   else
419     Self::_ParseComponentName( name, n, o );
420
421   // Find node
422   TNodes::const_iterator node = this->m_Nodes.find( n );
423   if( node == this->m_Nodes.end( ) )
424     cpPluginsErrorMacro(
425       this, << "Unknown node \"" << n << "\"."
426       );
427   return( node->second->GetInput( o, id ) );
428 }
429
430 // -------------------------------------------------------------------------
431 bool cpPlugins::Pipeline::
432 HasInput( const std::string& name ) const
433 {
434   // Guess information
435   std::string n, o;
436   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
437   if( rIt != this->m_InputRelations.end( ) )
438   {
439     n = rIt->second.first;
440     o = rIt->second.second;
441   }
442   else
443     Self::_ParseComponentName( name, n, o );
444
445   // Find node
446   TNodes::const_iterator node = this->m_Nodes.find( n );
447   if( node == this->m_Nodes.end( ) )
448     cpPluginsErrorMacro(
449       this, << "Unknown node \"" << n << "\"."
450       );
451   return( node->second->HasInput( n ) );
452 }
453
454 // -------------------------------------------------------------------------
455 void cpPlugins::Pipeline::
456 DefineOutput(
457   const std::string& output, const std::string& node, const std::string& port
458   )
459 {
460   if(
461     this->m_OutputRelations.insert(
462       TPortRelations::value_type( output, TEdge( node, port ) )
463       ).second
464     )
465     this->Modified( );
466 }
467
468 // -------------------------------------------------------------------------
469 cpPlugins::DataObject* cpPlugins::Pipeline::
470 GetOutput( const std::string& name )
471 {
472   // Guess information
473   std::string n, o;
474   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
475   if( rIt != this->m_OutputRelations.end( ) )
476   {
477     n = rIt->second.first;
478     o = rIt->second.second;
479   }
480   else
481     Self::_ParseComponentName( name, n, o );
482
483   // Find node
484   TNodes::iterator node = this->m_Nodes.find( n );
485   if( node == this->m_Nodes.end( ) )
486     cpPluginsErrorMacro(
487       this, << "Unknown node \"" << n << "\"."
488       );
489   cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
490   if( f != NULL )
491     return( f->GetOutput( o ) );
492   else
493     cpPluginsErrorMacro(
494       this, << "Node \"" << n << "\" does not have outputs."
495       );
496 }
497
498 // -------------------------------------------------------------------------
499 const cpPlugins::DataObject* cpPlugins::Pipeline::
500 GetOutput( const std::string& name ) const
501 {
502   // Guess information
503   std::string n, o;
504   TPortRelations::const_iterator rIt = this->m_OutputRelations.find( name );
505   if( rIt != this->m_OutputRelations.end( ) )
506   {
507     n = rIt->second.first;
508     o = rIt->second.second;
509   }
510   else
511     Self::_ParseComponentName( name, n, o );
512
513   // Find node
514   TNodes::const_iterator node = this->m_Nodes.find( n );
515   if( node == this->m_Nodes.end( ) )
516     cpPluginsErrorMacro(
517       this, << "Unknown node \"" << n << "\"."
518       );
519   const cpPlugins::Filter* f = node->second->Cast< cpPlugins::Filter >( );
520   if( f != NULL )
521     return( f->GetOutput( o ) );
522   else
523     cpPluginsErrorMacro(
524       this, << "Node \"" << n << "\" does not have outputs."
525       );
526 }
527
528 // -------------------------------------------------------------------------
529 cpPlugins::Pipeline::
530 Pipeline( )
531   : Superclass( ),
532     m_Description( "" ),
533     m_PipelineExecutionDebug( false )
534 {
535   this->m_Mgr.Configure( );
536 }
537
538 // -------------------------------------------------------------------------
539 cpPlugins::Pipeline::
540 ~Pipeline( )
541 {
542 }
543
544 // -------------------------------------------------------------------------
545 void cpPlugins::Pipeline::
546 _GenerateData( )
547 {
548   for( TNodes::value_type& v: this->m_Nodes )
549     v.second->Cast< cpPlugins::ProcessObject >( )->Update( );
550 }
551
552 // -------------------------------------------------------------------------
553 void cpPlugins::Pipeline::
554 _Connect(
555   Filter* src, const std::string& srcPort,
556   ProcessObject* dest, const std::string& destPort
557   )
558 {
559   if( src->HasOutValue( srcPort ) && dest->HasInValue( destPort ) )
560   {
561   }
562   else if( src->HasOutput( srcPort ) && dest->HasInput( destPort ) )
563     dest->SetInput( destPort, src->GetOutput( srcPort ) );
564   else
565     cpPluginsErrorMacro(
566       this,
567       << "Invalid connection from \"" << src->GetName( ) << "\" to \""
568       << dest->GetName( ) << " (" << srcPort << "->" << destPort << ")"
569       );
570 }
571
572 // -------------------------------------------------------------------------
573 void cpPlugins::Pipeline::
574 _Connect(
575   Functor* functor, const std::string& functorValue,
576   ProcessObject* dest, const std::string& destValue
577   )
578 {
579   if( functorValue == "Functor" )
580   {
581     Filter* filter = dynamic_cast< Filter* >( dest );
582     if( filter != NULL )
583       filter->SetFunctor( destValue, functor );
584     else
585       cpPluginsErrorMacro( this, << "Invalid functor connection." );
586   }
587   else
588   {
589     if(
590       functor->HasOutValue( functorValue ) && dest->HasInValue( destValue )
591       )
592       dest->SetInValuePtr(
593         destValue, functor->GetOutValuePtr( functorValue )
594         );
595     else
596       cpPluginsErrorMacro(
597         this,
598         << "Invalid connection from \"" << functor->GetName( ) << "\" to \""
599         << dest->GetName( ) << " (" << functorValue << "->"
600         << destValue << ")"
601         );
602   } // end if
603 }
604
605 // -------------------------------------------------------------------------
606 void cpPlugins::Pipeline::
607 _ParseComponentName(
608   const std::string& name,
609   std::string& node,
610   std::string& component
611   )
612 {
613   typedef boost::char_separator< char > _TSep;
614   typedef boost::tokenizer< _TSep > _TTok;
615
616   // Get parameter info
617   _TTok tok( name, _TSep( "@" ) );
618   std::vector< std::string > tokens;
619   for( _TTok::const_iterator tIt = tok.begin( ); tIt != tok.end( ); ++tIt )
620     tokens.push_back( *tIt );
621
622   // Try another distribution
623   if( tokens.size( ) != 2 )
624   {
625   } // end if
626
627   // Nothing else to do?
628   if( tokens.size( ) != 2 )
629     cpPluginsErrorMacro(
630       << "Unknown input value parameter \"" << name << "\"."
631       );
632
633   // Names
634   component = tokens[ 0 ];
635   node = tokens[ 1 ];
636 }
637
638 // eof - $RCSfile$