]> Creatis software - bbtk.git/blob - kernel/src/bbtkBlackBox.h
*** empty log message ***
[bbtk.git] / kernel / src / bbtkBlackBox.h
1 /*=========================================================================                                                                               
2   Program:   bbtk
3   Module:    $RCSfile: bbtkBlackBox.h,v $
4   Language:  C++
5   Date:      $Date: 2009/06/08 14:50:02 $
6   Version:   $Revision: 1.27 $
7 =========================================================================*/
8
9 /* ---------------------------------------------------------------------
10
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
13 *
14 *  This software is governed by the CeCILL-B license under French law and 
15 *  abiding by the rules of distribution of free software. You can  use, 
16 *  modify and/ or redistribute the software under the terms of the CeCILL-B 
17 *  license as circulated by CEA, CNRS and INRIA at the following URL 
18 *  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html 
19 *  or in the file LICENSE.txt.
20 *
21 *  As a counterpart to the access to the source code and  rights to copy,
22 *  modify and redistribute granted by the license, users are provided only
23 *  with a limited warranty  and the software's author,  the holder of the
24 *  economic rights,  and the successive licensors  have only  limited
25 *  liability. 
26 *
27 *  The fact that you are presently reading this means that you have had
28 *  knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */                                                                         
30
31
32
33 /**
34  *  \file 
35  *  \brief Class bbtk::BlackBox : abstract black-box interface. 
36  */
37
38 /**
39  * \class bbtk::BlackBox
40  * \brief Abstract black-box interface 
41  */
42  
43 #ifndef __bbtkBlackBox_h__
44 #define __bbtkBlackBox_h__
45
46 #include "bbtkSystem.h"
47 #include "bbtkMessageManager.h"
48 #include "bbtkBlackBoxDescriptor.h"
49 #include "bbtkBlackBoxInputConnector.h"
50 //#include "bbtkBlackBoxOutputConnector.h"
51 #include <set>
52
53 // Signal/slot mechanism for output change events
54 #include <boost/signal.hpp>
55 #include <boost/bind.hpp>
56
57
58 #define bbtkBlackBoxMessage(key,level,mess) \
59   bbtkMessage(key,level,"["<<bbGetName()<<"] "<<mess)
60 #define bbtkBlackBoxDebugMessage(key,level,mess)        \
61   bbtkDebugMessage(key,level,"["<<bbGetName()<<"] "<<mess)
62
63 namespace bbtk
64 {
65
66   
67   struct Void { Void(int = 0) {} };
68   
69   class Factory;
70   class Connection;
71   class BlackBoxOutputConnector;
72  
73
74
75   class BBTK_EXPORT BlackBox : public Object
76   {
77     BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
78
79
80   public: 
81
82     //==================================================================
83     // Types
84     //==================================================================
85     typedef boost::signals::trackable OutputChangeObserverType;
86     typedef boost::signal<void (bbtk::BlackBox::Pointer,
87                                 const std::string&,
88                                 IOStatus)>  OutputChangeSignalType;
89     typedef OutputChangeSignalType::slot_function_type 
90     OutputChangeCallbackType;
91  
92     /// The type of map of output connector pointers
93     typedef std::map<std::string, BlackBoxOutputConnector*> 
94     OutputConnectorMapType;
95     /// The type of map of input connector pointers
96     typedef std::map<std::string, BlackBoxInputConnector*> 
97     InputConnectorMapType;
98     //==================================================================
99
100
101     //==================================================================
102     /// @name Pipeline processing methods
103     ///  Methods which participate to pipeline processing.
104     //@{
105     /// Main processing method of the box.
106     virtual void bbExecute(bool force = false);
107     //@}
108     //==================================================================
109     
110
111
112  
113  
114     //==================================================================
115     /// Returns a pointer on a clone of the box with name <name>
116     virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
117     //==================================================================
118     
119
120    //==================================================================
121     /// @name General accessors
122     ///  Methods which give access to general informations on the box
123     //@{
124
125     /// Returns the pointer on the descriptor of the box
126     virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
127
128     /// Returns the Name of the Type of the BlackBox
129     const std::string& bbGetTypeName() const 
130       { return bbGetDescriptor()->GetTypeName(); }
131  
132     
133     /// Returns the name of the BlackBox (instance)
134     const std::string& bbGetName() const { return bbmName; }
135
136     /// Returns the full name of the BlackBox (instance+type)
137     virtual std::string bbGetFullName() const;
138
139     /// Returns the name with the name of the parent prepended if any
140     virtual std::string bbGetNameWithParent() const;
141     
142     /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
143     BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
144     
145     //@}
146     //==================================================================
147
148  
149
150     //==================================================================
151     /// @name Inputs/Outputs related methods
152     ///  Methods related to the box inputs and outputs
153     //@{
154
155     /// Returns true iff the BlackBox has an input of name label
156     virtual bool bbHasInput(const std::string& label) const;
157     ///  Gets the input type of a given label
158     virtual TypeInfo bbGetInputType( const std::string &label ) const;
159     /// Gets the status of the input called <name>
160     IOStatus bbGetInputStatus( const std::string &name ) const 
161     { return mInputConnectorMap.find(name)->second->GetStatus(); }
162     ///  Gets the data of the input called <name>
163     virtual Data bbGetInput( const std::string &name )  = 0;
164     ///  Gets the data of the input called <name> as a string using an Adaptor if possible (else returns empty string)
165     std::string bbGetInputAsString( const std::string &input); 
166
167  
168    /// Sets the data of the input called <name>.
169     /// If update_time is false then does not update ChangeTime of input
170     virtual void bbSetInput( const std::string &name, Data data,
171                              bool update_time = true ) = 0;
172     /// [SYSTEM]: Sets the data of the input called <name> which **MUST* be a pointer
173     virtual void bbBruteForceSetInputPointer( const std::string &name, 
174                                               void* data, 
175                                               bool update_time = true) =0;
176     
177   
178     /// Returns true iff the BlackBox has an output of name label
179     virtual bool bbHasOutput(const std::string& label) const;
180     ///  Gets the output type of a given label
181     virtual TypeInfo bbGetOutputType( const std::string &label ) const;
182     ///  Gets the data of the output called <name>
183     virtual Data bbGetOutput( const std::string &name ) = 0;
184     ///  Gets the data of the output called <name> as a string using an Adaptor if possible (else returns empty string)
185     std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
186     
187     ///  Sets the data of the output called <name>
188     virtual void bbSetOutput( const std::string &name, Data data) = 0;
189
190
191     ///  Returns the input connectors map
192     InputConnectorMapType&  bbGetInputConnectorMap() 
193     { return mInputConnectorMap; }
194     ///  Returns the input connectors map (const)
195     const InputConnectorMapType&  bbGetInputConnectorMap() const 
196     { return mInputConnectorMap; } 
197    ///  Returns the input connector
198     BlackBoxInputConnector&  bbGetInputConnector(const std::string& n) 
199     { return *(mInputConnectorMap.find(n)->second); }
200     ///  Returns the input connector (const)
201     const BlackBoxInputConnector&  bbGetInputConnector(const std::string& n) const
202     { return *(mInputConnectorMap.find(n)->second); }
203
204
205     ///  Returns the output connectors map
206     OutputConnectorMapType& bbGetOutputConnectorMap() 
207     { return mOutputConnectorMap; }
208     ///  Returns the output connectors map (const)
209     const OutputConnectorMapType& bbGetOutputConnectorMap() const 
210     { return mOutputConnectorMap; }      
211     ///  Returns the output connector
212     BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) 
213     { return *(mOutputConnectorMap.find(n)->second); }
214      ///  Returns the output connector (const)
215     const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const 
216     { return *(mOutputConnectorMap.find(n)->second); }
217
218     //@}
219     //==================================================================
220
221     /// Prints the Help on the BlackBox type 
222     virtual void bbGetHelp(bool full=true) const;
223
224
225
226     //==================================================================
227     /// @name Output signals / observers related methods
228     ///  Methods related to signals emitted by outputs and the 
229     //@{
230
231     //==================================================================
232     /// Adds the function f to the list of functions to call when 
233     /// the output changes.
234     /// f is of type ChangeCallbackType which is basically:
235     /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer, 
236     ///                            const std::string&,
237     ///                            bbtk::IOStatus)
238     /// To pass a member function 'f' of an instance 'c' of a class 'C' 
239     /// as callback you have to 'bind' it, i.e. call:
240     /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
241     /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you 
242     void bbAddOutputObserver(const std::string& output_name, 
243                              OutputChangeCallbackType f); 
244
245     /// Removes the function f from the list of functions to call when 
246     /// the output changes (TO WRITE)
247     void bbRemoveOutputObserver(const std::string& output_name, 
248                                 OutputChangeCallbackType f); 
249    //==================================================================
250     
251
252     //==================================================================
253     /// Signals that the BlackBox outputs have been modified 
254     /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
255     /// This method should be used by widgets in response 
256     /// to user interaction when **ALL** outputs have been modified
257     /// (after the outputs has been updated !).
258     /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
259     /// ** USER INTENDED **
260     virtual void bbSignalOutputModification(bool reaction = true);
261     /// Signals that the BlackBox output "output_name" has been modified 
262     /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !). 
263     /// This method should be used by widgets in response to user interaction 
264     /// only when **ONE** output has been modified
265     /// (after the output has been updated !)
266     /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
267     /// ** USER INTENDED **
268     virtual void bbSignalOutputModification( const std::string& output_name,
269                                              bool reaction = true);
270     /// Signals that the BlackBox vector of outputs "output_name" 
271     /// have been modified.
272     /// Should be used when more than ONE output is modified but not ALL 
273     /// (optimization issue).
274     /// (without marking the box as MODIFIED because its output state is ok). 
275     /// This method should be used by widgets in response to user interaction 
276     /// When more than one output has been changed but not all
277     /// (after the outputs have been updated of course!)
278     /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
279     /// ** USER INTENDED **
280     virtual void bbSignalOutputModification( const std::vector<std::string>& 
281                                              output_name,
282                                              bool reaction = true);
283    //==================================================================
284     //@}
285
286
287
288
289
290
291     //==================================================================
292     /// @name Common inputs / outputs to all boxes
293     //@{
294     /// Returns the value of the input 'BoxProcessMode'
295     std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
296     /// Sets the value of the input 'BoxProcessMode'
297     void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
298     /// The possible values of the input 'BoxProcessMode'
299     typedef enum
300       {
301         Pipeline,
302         Always,
303         Reactive
304       }
305     BoxProcessModeValue;
306     /// Returns the "decoded" value of the input "BoxProcessMode"
307     BoxProcessModeValue bbGetBoxProcessModeValue() const;
308     /// Returns true iff the input 'BoxProcessMode' is set to 'Reactive' (or a synonym)
309     virtual bool bbBoxProcessModeIsReactive() const;
310     /// Returns true iff the input 'BoxProcessMode' is set to 'Always' (or a synonym)
311     virtual bool bbBoxProcessModeIsAlways() const;
312
313     /// Returns the value of the input 'BoxExecute'
314     Void bbGetInputBoxExecute() { return Void(); }
315     /// Sets the value of the input 'BoxExecute'
316     void bbSetInputBoxExecute(Void = 0) {}
317
318     /// Returns the value of the output 'BoxChange'
319     Void bbGetOutputBoxChange() { return Void(); }
320     /// Sets the value of the output 'BoxChange' 
321     void bbSetOutputBoxChange(Void = 0) { } 
322     //@}
323     //==================================================================    
324
325
326
327     
328     virtual void bbPrintHelp(BlackBox::Pointer parentblackbox, 
329                              int detail, int level
330                              );
331
332     /// Does nothing here : overloaded in ComplexBlackBox
333     void bbInsertHTMLGraph(  std::ofstream& s, 
334                              int detail, 
335                              int level,
336                              bool instanceOrtype,
337                              const std::string& output_dir,
338                              bool relative_link ) 
339     {}
340
341     
342     //==================================================================
343     /// @name Window related methods
344     //@{ 
345     virtual void bbSetShown(bool) {}
346     virtual bool bbIsShown() { return false; }
347     //@}
348     //==================================================================
349
350   protected:
351
352
353
354    //==================================================================
355     /// @name User redefinable methods
356     ///  Virtual methods which can be redefined by inherited classes 
357     //@{
358
359
360     //==================================================================
361     /// User can redefine this method to set 
362     /// the default values of the box inputs and outputs
363     /// (it is called in the box constructor)
364     virtual void bbUserSetDefaultValues() {}
365
366     /// User can redefine this method to initialize what must be 
367     /// initialized for the box to work, for example allocate dynamic data.
368     /// It is called once and only once before any call to bbUserCreateWidget
369     /// or bbUserProcess.
370     /// What has been allocated here must be desalocated in 
371     /// bbFinalizeProcessing
372     virtual void bbUserInitializeProcessing() {}
373
374     /// User must redefine this method to uninitialize what has been
375     /// initialized in bbUserInitializeProcessing,
376     /// typically desallocate memory that has been allocated dynamically.
377     /// It is called in the box destructor if and only if (iff) 
378     /// bbUserInitializeProcessing has been called previously.
379     virtual void bbUserFinalizeProcessing() {}
380     ///
381     virtual void bbUserOnShow() {}
382
383     //==================================================================
384     // @}
385     //==================================================================
386
387
388
389
390     //==================================================================    
391
392     /// Write Graphviz-dot description in file. 
393     /// Here dumps a single box description (i/o) but overloaded 
394     /// in ComplexBlackBox to dump the internal pipeline representation 
395     /// recursing into internal boxes descriptions if level>0.
396     /// detail = 1 : draw inputs and outputs (do not draw otherwise)
397     /// instanceOrtype = true : draw inputs and outputs VALUES 
398     ///  (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
399     /// If relative_link is true then creates relative hrefs
400     virtual void bbWriteDotFileBlackBox(FILE *ff,
401                                         BlackBox::Pointer parentblackbox, 
402                                         int detail, int level, 
403                                         bool instanceOrtype,
404                                         bool relative_link );
405     /// Auxiliary method for bbWriteDotFileBlackBox
406     virtual void bbWriteDotInputOutputName(FILE *ff,
407                                            bool inputoutput, 
408                                            int detail, int level);
409     
410      
411     
412      virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname) 
413     { return BlackBox::Pointer();}
414
415     virtual void Check(bool recursive = true);
416
417
418  
419
420     //==================================================================
421     // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER 
422     // (IN INHERITED CLASSES)
423     /// Constructor that take the BlackBox's name
424     BlackBox(const std::string &name);
425     /// Constructor from an existing box (copy) with a new name 
426     BlackBox(BlackBox& from, const std::string &name);
427     //==================================================================
428
429
430
431     //==================================================================
432     /// @name Pipeline processing methods
433     ///  Methods which participate to pipeline processing.
434     //@{
435     //==================================================================   
436     /// Recursive execution method
437     /// 
438     /// \param caller : The connection which invoked the method; null if called by bbExecute
439     virtual void bbRecursiveExecute(Connection::Pointer caller);
440     //==================================================================
441     
442     //==================================================================
443     /// Updates the BlackBox inputs
444     /// Calls RecursiveExecute on all BlackBoxInputConnector
445     /// \returns The maximum of final IOStatus after each input update
446     IOStatus bbUpdateInputs();
447     //==================================================================
448
449           
450     //==================================================================
451     /// Actual CreateWindow method (vitual)
452     /// Overloaded in AtomicBlacBox and descendants 
453     virtual void bbCreateWindow()
454     {
455       //  bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
456     }
457     //==================================================================
458     
459     //==================================================================
460     /// Actual ShowWindow method (vitual)
461     /// Overloaded in AtomicBlacBox and descendants 
462     virtual void bbShowWindow()
463     {
464       //  bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
465     }
466     //==================================================================
467     
468                   
469    //==================================================================
470     /// Actual processing method (vitual)
471     /// Overloaded in AtomicBlacBox and descendants 
472     virtual void bbProcess() 
473     {
474       bbtkError("BlackBox::bbProcess called : how can this happen ?");
475 //      this->bbUserProcess(); 
476     }
477     //==================================================================
478
479     //==================================================================
480     /// Computes the final IOStatus of inputs and outputs after processing
481     void bbComputePostProcessStatus();
482     //@}
483     //==================================================================
484
485
486     //==================================================================
487     /// Signals that the input whose connector is c has changed 
488     /// and propagates the info downward
489     /// ** NOT USER INTENDED **
490     virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
491                                          IOStatus s);
492     //==================================================================
493     
494
495
496     //==================================================================
497     /// @name Box con(des)struction / initi(fin)alization methods
498     //@{
499
500     //==================================================================
501     /// Allocates the i/o connectors of the black box
502     virtual void bbAllocateConnectors();
503     /// Desallocates the i/o connectors of the black box
504     virtual void bbDesallocateConnectors();
505     /// Copies the values of the inputs/output from the BlackBox from
506     virtual void bbCopyIOValues(BlackBox& from);
507     //==================================================================
508     
509     //==================================================================  
510     /// Initializes processing IF NEEDED. 
511     /// Calls bbRecursiveInitializeProcessing if the box is in 
512     /// "uninitialized" state and put it in "initialized" state.
513     /// On construction, boxes are "uninitialized".
514     /// See also bbFinalizeProcessing
515     void bbInitializeProcessing();
516
517     /// Finalizes processing IF NEEDED.
518     /// Calls bbRecursiveFinalizeProcessing if the box is in 
519     /// "initialized" state and put it in "uninitialized" state.
520     /// On construction, boxes are "uninitialized".
521     /// See also bbInitializeProcessing
522     void bbFinalizeProcessing();
523
524     /// Abstract prototype of the method which 
525     /// Recursively calls itself for the parent black box and then
526     /// calls bbUserInitializeProcessing for its own class. 
527     /// It is redefined in each black box descendant.
528     /// Allows to call bbUserInitializeProcessing for all inherited classes
529     /// (like a constructor does)
530     virtual void bbRecursiveInitializeProcessing() {}
531
532
533     /// Abstract prototype of the method which 
534     /// calls bbUserFinalizeProcessing for its own class and then 
535     /// recursively calls itself for the parent black box.
536     /// It is redefined in each black box descendant.
537     /// Allows to call bbUserFinalizeProcessing for all inherited classes
538     /// (like a destructor does)
539     virtual void bbRecursiveFinalizeProcessing() {}
540     //==================================================================
541
542     //@}
543     //==================================================================
544
545
546
547  
548   private:
549     //==================================================================
550     friend class Connection;
551     friend class ComplexBlackBox;
552
553     /// Sets the parent of the BlackBox
554     void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
555     
556     //==================================================================
557     /// @name Input/output connection/disconnection
558     /// INTERNAL METHODS used by a Connection to connect/disconnect
559     /// itself to the i/o connectors of the box
560     //@{
561
562     /// Connects the input <name> to the connection c
563     virtual void bbConnectInput( const std::string& name, 
564                                  Connection* c);
565     /// Connects the output <name> to the connection c
566     virtual void bbConnectOutput( const std::string& name, 
567                                   Connection* c);
568     /// Disconnects the input <name> from the connection c
569     virtual void bbDisconnectInput( const std::string& name, 
570                                     Connection* c);
571     /// Disconnects the output <name> from the connection c
572     virtual void bbDisconnectOutput( const std::string& name, 
573                                      Connection* c);
574     //@}
575     //==================================================================
576
577     /// Returns true if the box can "react",
578     /// which means execute in response to an input change 
579     virtual bool bbCanReact() const;
580
581
582
583     //==================================================================
584     /// @name Manage the execution
585     //@{
586     static bool bbGlobalGetSomeBoxExecuting();
587     static void bbGlobalSetSomeBoxExecuting(bool b);
588
589     static void bbGlobalSetFreezeExecution(bool b);
590     static bool bbGlobalGetFreezeExecution();
591
592     static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
593     static void bbGlobalProcessExecutionList();
594
595     //@}
596     
597     /// Returns true iff the box is executing
598     bool bbGetExecuting() const { return bbmExecuting; }
599     /// Sets the bbmExecuting bool returned by bbGetExecuting
600     void bbSetExecuting(bool b) { bbmExecuting = b; }
601
602
603
604   protected:  
605
606     //==================================================================
607   protected:
608
609
610      //==================================================================
611     /// Black box objects have a special deleter 
612     /// which must take care of releasing the descriptor 
613     /// **AFTER** the box is deleted 
614     /// (Releasing it in the destructor may cause dl close and crash)
615     /// Black box deleter 
616     /// 1) Calls the user overloadable bbDelete method
617     /// 2) Releases the box descriptor
618     struct BBTK_EXPORT Deleter : public Object::Deleter
619     { 
620       Deleter(); 
621       int Delete(Object* p);
622     };
623     //==================================================================
624
625     //==================================================================
626     /// Like Object::MakePointer but returns a boost::shared_pointer which uses a BlackBox::Deleter to delete the object instead of the default Object::Deleter
627     template <class U>
628     static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
629     {
630       return MakePointer(s,BlackBox::Deleter(),lock);
631     }
632     //==================================================================
633
634     //==================================================================
635     /// Effective deletion method called by the Deleter.
636     /// The default implementation is to issue 'delete this'
637     /// but it can be redefined in inherited classes to handle special deletion mechanisms (e.g. ref counting, private destructors, such as vtk objects deletion with method Delete, etc.).
638     /// \return The number of remaining references on the object after the call (if meaningfull...): used by bbtk to warn a user if another smart pointing system is still holding the object...
639     virtual int bbDelete() { delete this; return 0; }
640     //==================================================================
641
642
643     //==================================================================
644   private:
645     //==================================================================
646  
647     //==================================================================
648     // ATTRIBUTES
649     /// Is the box initialized ?
650     bool bbmInitialized;
651     /// Is the box executing ?
652     bool bbmExecuting;
653     /// The name of the black-box
654     std::string bbmName;
655     /// The name of the package to which it belongs
656     std::string bbmPackageName;
657     /// The box processing mode
658     /// 0 : "Pipeline" mode 
659     /// 1 : "Always" mode 
660     /// 2 : "Reactive" mode 
661     std::string bbmBoxProcessMode;
662     /// The parent of the black box in the ComplexBlackBox hierarchy
663     BlackBox::WeakPointer bbmParent;
664     //==================================================================
665
666
667    //==================================================================
668     // ATTRIBUTES
669     ///  Map that contains the output connectors of the black box
670     OutputConnectorMapType mOutputConnectorMap; 
671     ///  Map that contains the input connectors of the black box
672     InputConnectorMapType mInputConnectorMap;
673     //==================================================================
674
675
676  };
677   // Class BlackBox
678
679
680
681   /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
682 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
683     boost::bind( METHOD, OBJECT, _1, _2, _3)
684
685
686
687
688  
689 }
690 // namespace bbtk
691 #endif
692