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