casa
$Rev:20696$
|
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