casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Animator.h
Go to the documentation of this file.
00001 //# Animator.h: movie control for one or more WorldCanvasHolders
00002 //# Copyright (C) 1996,1997,1999,2000
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id$
00027 
00028 #ifndef TRIALDISPLAY_ANIMATOR_H
00029 #define TRIALDISPLAY_ANIMATOR_H
00030 
00031 //# aips includes
00032 #include <casa/aips.h>
00033 #include <casa/Containers/List.h>
00034 
00035 //# display library includes
00036 #include <display/DisplayEvents/WCRefreshEH.h>
00037 
00038 namespace casa { //# NAMESPACE CASA - BEGIN
00039 
00040 //# forwards
00041 class WorldCanvasHolder;
00042 class Animator;
00043 
00044 // <summary>
00045 // WorldCanvas refresh event handler for Animator class.
00046 // </summary>
00047 //
00048 // <synopsis>
00049 // This class is a simple implementation of a WCRefreshEH which 
00050 // passes WorldCanvas refresh events on to an Animator object.
00051 // </synopsis>
00052 
00053 class AnimatorRefEH : public WCRefreshEH {
00054  public:
00055   AnimatorRefEH(Animator *animator);
00056   virtual ~AnimatorRefEH() {};
00057   virtual void operator()(const WCRefreshEvent &ev);
00058  private:
00059   Animator *itsAnimator;
00060 };
00061 
00062 // <summary>
00063 // Animation controller for WorldCanvasHolders.
00064 // </summary>
00065 // <use visibility=export>
00066 // 
00067 // <reviewed reviewer="" date="yyyy/mm/dd" tests="" demos="">
00068 // </reviewed>
00069 // 
00070 // <prerequisite>
00071 //   <li> Attribute
00072 //   <li> AttributeBuffer
00073 //   <li> WorldCanvasHolder
00074 //   <li> DisplayData
00075 // </prerequisite>
00076 //
00077 // <etymology>
00078 // An Animator animates animations
00079 // </etymology>
00080 //
00081 // <synopsis> 
00082 //  TBW
00083 // </synopsis>
00084 // <example> 
00085 //
00086 // First example is making a simple movie of all the
00087 // channels in a data cube 
00088 //
00089 // <srcblock> 
00090 // // Create a PixelCanvas for X11 to draw on
00091 // X11PixelCanvas(parent, xpcctbl, width, height) ;
00092 // // and a World Coordinate  interface for this PixelCanvas
00093 // WorldCanvas  wCnvs(&pixelCnvs);
00094 //
00095 // // Create a WorldCanvasHolder
00096 // WorldCanvasHolder wCnvsHldr(&wCnvs);
00097 //
00098 // // Create an ImageDisplayData object of the data cube to display the 
00099 // // channels (assuming 3rd axis is velocity in this cube) 
00100 // ImageDisplayData cube(myDataSet, 0, 1, 2); 
00101 // // and register this with the WorldCanvasHolder
00102 // wCnvsHldr.addDisplayData(&cube);
00103 //
00104 // // Create an Animator for the WorldCanvasHolder and register the
00105 // // WorldCanvasHolder
00106 // Animator animator;
00107 // animator.addWorldCanvasHolder(&wCnvsHldr);
00108 //
00109 // // start with first channel
00110 // animator.setMin(0.0);            
00111 // // last channel of cube (assuming it has 30 channels)
00112 // animator.setMax(29.0);
00113 // // go in steps of one channel
00114 // animator.setStep(1.0);
00115 // // only one channel at a time, so tolerance must be less than 1.0
00116 // anomator.setTolerance(0.1);
00117 // // display new channel every 0.2 sec
00118 // animator.setUpdateInterval(0.2);
00119 // // we want a normal boring movie
00120 // animator.setNextMode(animator::NEXT_FORWARD); 
00121 // // and we define the channel (ie index)
00122 // animator.setMatchMode(Animator::MATCH_INDEX);
00123 // // set the Update method
00124 // animator.setUpdateMode(Animator::UPDATE_DIRECT);
00125 // // and start the movie
00126 // animator.startMovie();
00127 //       .
00128 //       .
00129 //       .
00130 // // After a while we want to change to Rock & Roll mode:
00131 // animator.setMovieMode(Animator::NEXT_ROCKandROLL);
00132 //       .
00133 //       .
00134 //       .
00135 // // and after another while we stop
00136 // animator.stopMovie();
00137 // </srcblock>
00138 // Second example is that we want to blink between channel 20 of the previous
00139 // cube and an optical image
00140 // <srcblock>
00141 // // Create an ImageDataDisplay of the image and register with
00142 // // the WorldCanvasHolder
00143 // ImageDataDisplay image(myImage, 0, 2);
00144 // wCnvsHldr.addDisplayData(&image);
00145 //
00146 // // Create a List to contain the AttributeBuffers
00147 // List<void *> buffList;
00148 // // and an iterator for this list
00149 // ListIter<void *> it(&buffList);
00150 //
00151 // // Create AttributeBuffers and fill them
00152 // AttributeBuffer atBuff1;
00153 // // This is to mark the cube. The name and value of the Attribute or 
00154 // // Attributes that can be used is arbitrary, as long as the different 
00155 // // AttributeBuffers in the List select different datasets (even that is
00156 // // not really necessary, but you will be blinking between the same frames 
00157 // // and not many people will get excited about that....)
00158 // atBuff1.add("AjaxWordtKampioen", "yes");
00159 // it.addRight((void *) &attBuff1);
00160 // 
00161 // // the buffer for the image
00162 // AttributeBuffer atBuff2;
00163 // atBuff2.add("AjaxWordtKampioen", "of course");
00164 // at.addRight((void *) &attBuff2);
00165 //
00166 // // and set this list on the Animator
00167 // animator.setBlinkList(&buffList);
00168 // 
00169 // // Set the same attributes on the DisplayDatas so the Attribute matching
00170 // // mechanism between the WorldCanvasHolder and the DisplayDatas will select
00171 // // the right data at the right time automatically
00172 // cube.addAttribute(attBuff1);
00173 // image.addAttribute(attBuff2);
00174 //
00175 // // Tell animator to use channel 20
00176 // animator.gotoCoord(20.0);
00177 // // The Animator should write "zIndex" to select channel 20
00178 // animator.setMatchMode(Animator::MATCH_INDEX);
00179 // // Because we set the UpdateMode to UPDATE_BLINK, the zIndex does
00180 // // not change each time the timer goes off.
00181 // animator.setUpdateMode(Animator::UPDATE_BLINK);
00182 // // and the blinking can start:
00183 // animator.startMovie();
00184 //       .
00185 //       .
00186 //       .
00187 // // After a while we want to blink between channel 19 and the optical image.
00188 // // this is done by setting NextMode to NEXT_BACKWARD and invoke nextCoord().
00189 // // Of course we could also have used only animator.prevCoord(), but just
00190 // // to show the principle...
00191 // animator.setNextMode(Animator::NEXT_BACKWARD);
00192 // animator.nextCoord();
00193 
00194 // 
00195 // // We can add a third data set, set "AjaxWordtKampioen" to "always" for that data,
00196 // // and the blinking is between 3 datasets: 
00197 //
00198 // // stop the blinking
00199 // animator.stopMovie(); 
00200 //
00201 // // Create DisplayData from data
00202 // ImageDataDisplay image2(mySecondImage, 0, 2);
00203 //
00204 // // Add to WorldCanvasHolder
00205 // wCnvsHldr.addDisplayData(&image2);
00206 //
00207 // //Setup AttributeBuffer
00208 // AttributeBuffer atBuff3;
00209 // atBuff3.add("AjaxWordtKampioen", "always");
00210 //
00211 // // add to data
00212 // image2.addAttribute(attBuff3);
00213 //
00214 // // and add to List
00215 // at.addRight((void *) &attBuff3);
00216 //
00217 // // set the updated list on the animator (strictly speaking not neseccary
00218 // // here, because animator already has the address of this List, but...)
00219 // animator.setBlinkList(&buffList);
00220 //
00221 // //and go!!!
00222 // animator.startMovie();
00223 // </srcblock>
00224 // The third example is to run movies, selected on world coordinates on two 
00225 // WorldCanvasHolders in synch:
00226 // <srcblock>
00227 // // Create a PixelCanvas for X11 to draw on
00228 // X11PixelCanvas(parent, xpcctbl, width, height) ;
00229 // // and two  WorldCanvases side by side on the same PixelCanvas
00230 // WorldCanvas wCnvs1(&pixelCanvas, 0.0, 0.25, 0.5, 0.5);
00231 // WorldCanvas wCnvs2(&pixelCanvas, 0.5, 0.25, 0.5, 0.5);
00232 //
00233 // // A WorldCanvasHolder for each WorldCanvas
00234 // WorldCanvasHolder wCnvsHldr1(&wCnvs1);
00235 // WorldCanvasHolder wCnvsHldr2(&wCnvs2);
00236 //
00237 // // We have an HI data cube of an object
00238 // ImageDisplayData HIcube(HIdata, 0, 1, 2);
00239 // // that we display on the first WorldCanvas
00240 // wCnvsHldr1.addDisplayData(HIcube);
00241 // 
00242 // // and we have a CO cube of the same object that we display on the second
00243 // // WorldCanvas
00244 // ImageDisplayData COcube(COdata, 0, 1, 2);
00245 // wCnvsHldr2.addDisplayData(COcube);
00246 // 
00247 // // Create an animator and register the two WorldCanvasHolders
00248 // Animator animator;
00249 // animator.addWorldCanvasHolder(wCnvsHldr1);
00250 // animator.addWorldCanvasHolder(wCnvsHldr2);
00251 //
00252 // // Set the movie parameters:
00253 // // Select on world coordinate (ie velocity)
00254 // animator.setMatchMode(Animator::MATCH_WORLD);
00255 // // start and end velocities
00256 // animator.setMinAndMax(1200.0, 1400.0);
00257 // // and the tolerance to 10.0 and the step to 20.0
00258 // animator.setTolerance(10.0):
00259 // animator.setStep(20.0);
00260 //
00261 // // Set speed of movies and the mode
00262 // animator.setUpdateInterval(0.2);
00263 // animator.setNextMode(Animator::ROCKandROLL);
00264 //
00265 // // Now, on the first canvas a movie will be played of the HI data, and on
00266 // // the second canvas a movie of the CO data. Because the selection is done
00267 // // on world coordinate, the two movies display the data of the same 
00268 // // velocity (within the tolerance of 10.0), in steps of 20.0, synchronized,
00269 // // regardless of the channel separation of the two datasets:
00270 // animator.startMovie();
00271 // 
00272 // </srcblock>
00273 // </example>
00274 //
00275 //
00276 // <motivation> To allow for easy control of movies, possibly synchonous on
00277 // more than one WorldCanvas, as well as lay the basis for the userinterface
00278 // for this, a central class is needed that controls sequences of DisplayData.
00279 // </motivation>
00280 //
00281 // <todo>
00282 //   <li> make Animator know about Units
00283 // </todo>
00284 
00285 class Animator {
00286 
00287  public:
00288 
00289   // Defines the way the Animator calculates the Z coordinate of the next
00290   // frame in the sequence. This defines the behaviour of the member
00291   // nextCoord().
00292   enum NextMode {
00293     // Movie in forward direction. Step is added, if the Z coordinate is larger
00294     // than maximum then display minimum, increment again until maximum, etc.
00295     // This is the default.
00296     NEXT_FORWARD,
00297     // Movie in backward direction. Step is subtracted, if Z coordinate is
00298     // smaller than mimnimum then display maximum, decrement until minimum,
00299     // etc etc
00300     NEXT_BACKWARD, 
00301     // Movie goes up and down the sequence. Step is added until the Z
00302     // coordinate is larger than maximum, then step is subtracted until the Z
00303     // coordinate is smaller than minimum, then step is added, and so on, and
00304     // so on
00305     NEXT_ROCKANDROLL 
00306   };  
00307   
00308   // Defines wheter the sequence is defined using the index in the sequence or
00309   // by the world coordinate of the 'Z-axis' (the "zValue" or "zIndex" used by the
00310   // WorldCanvasHolders and the DisplayDatas), or only by the AttributeBuffers
00311   enum MatchMode {
00312     // Sequence is defined by writing Attribute "zIndex" with the value of the
00313     // Z coordinate to WorldCanvasHolders, plus the ones from the List of
00314     // AttributeBuffers.  
00315     // This is the default
00316     MATCH_INDEX,
00317     // Sequence is defined by writing Attribute "zValue"with the value of the
00318     // Z coordinate to WorldCanvasHolders, plus the ones from the List of
00319     // AttributeBuffers
00320     MATCH_WORLD,
00321     // Only the Attributes from the List of AttributeBuffers are written
00322     MATCH_LIST_ONLY
00323   };
00324 
00325   // Decides whether the Z coordinate should be changed according to the
00326   // NextMode before each update or not
00327   enum UpdateMode {
00328     // Do change the Z coordinate before each update. Use this for 'normal
00329     // movies'.
00330     // This is the default.
00331     UPDATE_DIRECT,
00332     // Do not change Z coordinate, but rely on the AttributeBuffers to change
00333     // what is displayed. Use this for blinking.
00334     UPDATE_BLINK
00335   };
00336   
00337 
00338   
00339   // Constructor
00340   Animator();
00341   
00342   //Destrutor
00343   virtual ~Animator();
00344   
00345   // Go to next Z coordinate in sequence
00346   virtual void nextCoord();
00347 
00348   // Go to previous Z coordinate in sequence
00349   virtual void prevCoord();
00350 
00351   // Go to  Z coordinate zCoord
00352   virtual void gotoCoord(Double zCoord);
00353   
00354   // Set increment in the Z coordinate for the movie
00355   // <group>
00356   virtual void setStep(uInt zIncrement);
00357   virtual void setStep(Double zIncrement);
00358   // </group>
00359 
00360   // Set the tolerance in the Z coordinate
00361   // <group>
00362   virtual void setTolerance(uInt tolerance);
00363   virtual void setTolerance(Double tolerance);
00364   // </group>
00365   
00366   // Set the minimum and maximum Z coordinate for the movie
00367   virtual void setMinAndMaxCoord(Double zMin, Double zMax);
00368 
00369   // Set whether "zIndex", "zValue" or none of the two should be written
00370   // additionally to the AttributeBuffers.
00371   virtual void setMatchMode(Animator::MatchMode match);
00372 
00373 
00374   // Set the way the increments are done, ie. it defines the action of
00375   // nextCoord() (options NEXT_FORWARD, NEXT_BACKWARD, UPDATE_ROCKANDROLL)
00376   virtual void setNextMode(Animator::NextMode  mode);
00377   
00378 
00379   // Set whether an increment should be done before each update (UPDATE_DIRECT or
00380   // UPDATE_BLINK)
00381   virtual void setUpdateMode(Animator::UpdateMode mode);
00382   
00383   // Set update interval of movie in milliseconds
00384   virtual void setUpdateInterval(Double interval);
00385   
00386   // Set the list of additional Attributes that the Animator  places on the
00387   // WorldCanvasHolders before each update.
00388   virtual void setBlinkRestrictions(List<void *> *attBuffers);
00389 
00390   // Remove the List with AttributeBuffers
00391   virtual void clearBlinkRestrictions();
00392 
00393     // Stop and start movie
00394   // <group>
00395   virtual void startMovie();
00396   virtual void stopMovie();
00397   // </group>
00398 
00399   // Return the length of the movie. In UpdateMode UPDATE_DIRECT this is the
00400   // number of frames that follow from the minimum and maximum Z coordiante
00401   // and the step. In UPDATE_BLINK mode this is the length of the List of
00402   // AttributeBuffers set on the Animator using setBlinkAttributes
00403   virtual uInt getMovieLength();
00404   
00405   // Return the current position in the movie.  This is really a bad
00406   // thing, but needed in the interim for the viewer.
00407   virtual Int getCurrentPosition();
00408 
00409   // Reset the Animator. This will set the minimum coordiante to 0, the
00410   // maximum to the number of elements registered with the WorldCanvasHolders,
00411   // the step to 1.0 and the update mode to MATCH_INDEX
00412   virtual void reset();
00413   
00414   // Add a WorldCanvasHolder to the list controlled by this Animator
00415   virtual void addWorldCanvasHolder(WorldCanvasHolder *newHolder);
00416 
00417   // Remove a WorldCanvasHolder from the list controlled by this Animator
00418   virtual void removeWorldCanvasHolder(WorldCanvasHolder& holder);
00419   
00420   // Refresh event handler - just used to see if resetCoordinates was
00421   // set.  If so, then we should partially reset the animator.
00422   virtual void operator()(const WCRefreshEvent& ev);
00423 
00424 private:
00425 
00426   // List of WorldCanvasHolders
00427   List<void *> holderList;
00428 
00429   // List of the AttributeBuffers
00430   List<void *> *attBufList;
00431   
00432   // parameters of movies
00433   Double minCoord;
00434   Double maxCoord;
00435 
00436   // Increment for computing currentCoord. Always postive
00437   Double movieStep;
00438 
00439   // State variables
00440   // Tolerance for coordinate Restriction
00441   Double coordTolerance;
00442   // Current Z coordiante
00443   Double currentCoord;
00444   // the MatchMode
00445   Animator::MatchMode matchMode;
00446   // the NextMode
00447   Animator::NextMode nextMode;
00448   // The UpdateMode
00449   Animator::UpdateMode updateMode;  
00450   // and the interval of the timer
00451   Double updateInterval;
00452 
00453   // The number of the AttributeBuffer to use. Computed by computeNewCoord()
00454   // Has to be Int, not uInt! (because I sometimes subtract 1!)
00455   Int numberInList;
00456   
00457   // In which direction the movie is currently going
00458   Int movieDirection;
00459   
00460   // Compute, based on the UPDATE_MODE and NEXT_MODE, the Z coordinate of the
00461   // new frame to display (ie. the new currentCoord). If the updateMode ==
00462   // UPDATE_BLINK, nothing happens. If the updateMode == UPDATE_DIRECT, the
00463   // value of currentCoord is incremented or decremented with the absolute
00464   // value of movieStep, depending in whether the next_Mode is NEXT_FORWARD,
00465   // NEXT_BACKWARD or NEXT_ROCKANDROLL and whether the new value goes outside
00466   // the bounds set by minCoord and maxCoord.
00467   void computeNextCoord(Int addOrSubtract);
00468   
00469   // Helper routine for computeNewCoord(). If addOrSubtract > 0, 1 is added to
00470   // number, if addOrSubtract < 0, 1 is subtracted
00471   void increment(Int& number, Int addOrSubtract);
00472 
00473   // Helper routine for computeNewCoord(). The inverse of <src>increment(Int&,
00474   // Int)</src>
00475   void decrement(Int& number, Int addOrSubtract);
00476 
00477   // Helper routine for computeNewCoord(). If addOrSubtract > 0, movieStep is added to
00478   // number, if addOrSubtract < 0, movieStep is subtracted
00479   void increment(Double& number, Int addOrSubtract); 
00480 
00481   // Helper routine for computeNewCoord(). The inverse of <src>increment(Double&,
00482   // Int)</src>
00483   void decrement(Double& number, Int addOrSubtract);
00484   
00485   
00486   // Write the necessary Attributes to all the WorldCanvasHolders. The content
00487   // of one of the registered AttributeBuffer is always written. If the
00488   // updateMode == UPDATE_DIRECT the n-th AttributeBuffer is written, where n
00489   // is the sequence number of the frame, based on minCoord and movieStep. If
00490   // the updateMode == UPDATE_BLINK the Animator just loops through the list
00491   // of AttributeBuffers based on numberInList.
00492   // If MatchMode == MATCH_INDEX also an Attribute is written with name
00493   // "zIndex" and with the value of currentCoord.
00494   // If MatchMode == MATCH_COORD also an Attribute is written with name
00495   // "zValue" and with the value of currentCoord.
00496   void writeRestrictions();
00497 
00498   // Invoke refresh() on all the WorldCanvasHolders registered with the
00499   // Animator
00500   void refresh();
00501   
00502   // Return the number of AttributeBuffers in the List of AttributeBuffer
00503   Int listLen();
00504 
00505   // refresh event handler
00506   AnimatorRefEH *itsAnimatorRefEH;
00507   
00508 };
00509 
00510 
00511 } //# NAMESPACE CASA - END
00512 
00513 #endif