Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

cmd_animate.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: cmd_animate.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.52 $       $Date: 2019/01/17 21:21:03 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   text commands for animation control
00019  ***************************************************************************/
00020 
00021 #include <tcl.h>
00022 #include <ctype.h>
00023 #include "config.h"
00024 #include "VMDApp.h"
00025 #include "MoleculeList.h"
00026 #include "TclCommands.h"
00027 #include "Animation.h"
00028 
00029 static void cmd_animate_usage(Tcl_Interp *interp) {
00030   Tcl_AppendResult(interp,
00031       "usage: animate <command> [args...]"
00032       "animate styles\n"
00033       "animate style [once|rock|loop]\n"
00034       "animate dup [|frame <number>] <molecule id>\n"
00035       "animate goto [start|end|<num]\n"
00036       "animate [reverse|rev|forward|for|prev|next|pause]\n"
00037       "animate [speed|skip] [|<value>]\n"
00038       "animate delete all\n"
00039       "animate delete [|beg <num>] [|end <num>] [|skip <num>] <molecule id>\n"
00040       "animate [read|write] <file type> <filename>\n"
00041       "    [|beg <num>] [|end <num>] [|skip <num>] [|waitfor <num/all>]\n"
00042       "    [|sel <atom selection>] [|<molecule id>]",
00043       NULL);
00044 }
00045 
00046 int text_cmd_animate(ClientData cd, Tcl_Interp *interp, int argc, 
00047                             const char *argv[]) {
00048 
00049   VMDApp *app = (VMDApp *)cd;
00050 
00051   // since I cannot easily add this to the rest of the code, I put
00052   // new code here:
00053   if (argc == 1) {
00054     cmd_animate_usage(interp);
00055   }
00056 
00057   if (argc == 2) {
00058     if (!strupncmp(argv[1], "styles", CMDLEN)) {
00059       // enumerate the styles 
00060       size_t loop = 0;
00061       while(loop < sizeof(animationStyleName) / sizeof(char*)) {
00062         Tcl_AppendElement(interp, animationStyleName[loop++]);
00063       }
00064       return TCL_OK;
00065     }
00066     if (!strupncmp(argv[1], "skip", CMDLEN)) {
00067       Tcl_SetObjResult(interp, Tcl_NewIntObj(app->anim->skip()));
00068       return TCL_OK;
00069     }
00070     if (!strupncmp(argv[1], "speed", CMDLEN)) {
00071       Tcl_SetObjResult(interp, Tcl_NewDoubleObj(app->anim->speed()));
00072       return TCL_OK;
00073     }
00074     if (!strupncmp(argv[1], "style", CMDLEN)) {
00075       int style = app->anim->anim_style();
00076       Tcl_AppendElement(interp, animationStyleName[style]);
00077       return TCL_OK;
00078     }
00079     // fall through and let the rest of the code catch the other 2 word cmds
00080   }
00081 
00082   if ((argc == 3 || argc == 5) && !strupncmp(argv[1], "dup", CMDLEN)) {
00083     // option is: animate dup [frame <number>] <molecule id>
00084     // default frame is "now"
00085     // It adds a new animation frame to the molecule, which is a copy of
00086     // the given frame.  If there is no frame, {0, 0, 0} is added.
00087     int frame = -1;
00088     int molid = -1;
00089     // get frame number
00090     if (argc == 3) {
00091       if (!strcmp(argv[2], "top")) {
00092         if (app->moleculeList -> top()) {
00093           molid = app->moleculeList -> top() -> id();
00094         } else {
00095           molid = -1;
00096         }        
00097       } else if (Tcl_GetInt(interp, argv[2], &molid) != TCL_OK) {
00098         Tcl_AppendResult(interp, " in animate dup", NULL);
00099         return TCL_ERROR;
00100       }
00101 
00102     } else {
00103       if (strcmp(argv[2], "frame")) {
00104         // error
00105         Tcl_AppendResult(interp,
00106           "format is: animate dup [frame <number>] <molecule id>", NULL);
00107         return TCL_ERROR;
00108       }
00109       if (!strcmp(argv[3], "now")) { // check special cases
00110         frame = -1;
00111       } else if (!strcmp(argv[3], "null")) {
00112         frame = -2;
00113       } else {
00114         if (Tcl_GetInt(interp, argv[3], &frame) != TCL_OK) {
00115           Tcl_AppendResult(interp, " in animate dup frame", NULL);
00116           return TCL_ERROR;
00117         }
00118       }
00119       if (Tcl_GetInt(interp, argv[4], &molid) != TCL_OK) {
00120         Tcl_AppendResult(interp, " in animate dup", NULL);
00121         return TCL_ERROR;
00122       }
00123     }
00124     if (!app->molecule_dupframe(molid, frame)) return TCL_ERROR;
00125     return TCL_OK;
00126   }
00127  
00128 
00129   if (argc == 2) {
00130     Animation::AnimDir newDir;
00131     if(!strupncmp(argv[1], "reverse", CMDLEN) ||
00132             !strupncmp(argv[1], "rev", CMDLEN))
00133       newDir = Animation::ANIM_REVERSE;
00134     else if(!strupncmp(argv[1], "forward", CMDLEN) ||
00135             !strupncmp(argv[1], "for", CMDLEN))
00136       newDir = Animation::ANIM_FORWARD;
00137     else if(!strupncmp(argv[1], "prev", CMDLEN))
00138       newDir = Animation::ANIM_REVERSE1;
00139     else if(!strupncmp(argv[1], "next", CMDLEN))
00140       newDir = Animation::ANIM_FORWARD1;
00141     else if(!strupncmp(argv[1], "pause", CMDLEN))
00142       newDir = Animation::ANIM_PAUSE;
00143     else {
00144       cmd_animate_usage(interp);
00145       return TCL_ERROR;                // error
00146     }
00147     app->animation_set_dir(newDir);
00148   } else if(argc == 3) {
00149     if(!strupncmp(argv[1], "skip", CMDLEN)) {
00150       int tmp;
00151       if (Tcl_GetInt(interp, argv[2], &tmp) != TCL_OK) {
00152         Tcl_AppendResult(interp, " in animate skip", NULL);
00153         return TCL_ERROR;
00154       }
00155       app->animation_set_stride(tmp);
00156     } else if(!strupncmp(argv[1], "delete", CMDLEN)) {
00157       if(!strupncmp(argv[2], "all", CMDLEN)) {
00158         int molid = app->molecule_top();
00159         int last = app->molecule_numframes(molid)-1;
00160         int rc = app->molecule_deleteframes(molid, 0, last, -1);
00161         return rc ? TCL_OK : TCL_ERROR;
00162       } else {
00163         cmd_animate_usage(interp);
00164         return TCL_ERROR;                // error
00165       }
00166     } else if(!strupncmp(argv[1], "speed", CMDLEN))
00167       app->animation_set_speed((float) atof(argv[2]));
00168     else if(!strupncmp(argv[1], "style", CMDLEN)) {
00169       int newStyle = Animation::ANIM_ONCE;
00170       Animation::AnimStyle enumVal;
00171       while(newStyle < Animation::ANIM_TOTAL_STYLES) {
00172         if(!strupncmp(argv[2], animationStyleName[newStyle], CMDLEN))
00173           break;
00174         newStyle++;
00175       }
00176       if(newStyle == Animation::ANIM_ONCE)
00177         enumVal = Animation::ANIM_ONCE;
00178       else if(newStyle == Animation::ANIM_ROCK)
00179         enumVal = Animation::ANIM_ROCK;
00180       else if(newStyle == Animation::ANIM_LOOP)
00181         enumVal = Animation::ANIM_LOOP;
00182       else {
00183         Tcl_AppendResult(interp, 
00184         "Unknown animate style '" ,argv[2] ,"'\n", NULL);
00185         Tcl_AppendResult(interp, "Valid styles are: ", NULL);
00186         newStyle = Animation::ANIM_ONCE;
00187         while(newStyle < Animation::ANIM_TOTAL_STYLES) {
00188           Tcl_AppendElement(interp, animationStyleName[newStyle]); 
00189           newStyle ++;
00190         }
00191         return TCL_ERROR;                // error, unknown style
00192       }
00193       app->animation_set_style(enumVal);
00194     } else if(!strupncmp(argv[1], "goto", CMDLEN)) {
00195       int newframe;
00196       if(!strupncmp(argv[2], "start", CMDLEN))
00197         newframe = -1;
00198       else if(!strupncmp(argv[2], "end", CMDLEN))
00199         newframe = -2;
00200       else if(isdigit(argv[2][0]))
00201         newframe = atoi(argv[2]);
00202       else {
00203         Tcl_AppendResult(interp, "Bad goto parameter '" ,argv[2] ,"'\n", NULL);
00204         Tcl_AppendResult(interp, 
00205           "Valid values are a non-negative number, 'start', or 'end'.", NULL);
00206         return TCL_ERROR;                // error, bad frame goto command
00207       }
00208       app->animation_set_frame(newframe);
00209     } else {
00210       cmd_animate_usage(interp);
00211       return TCL_ERROR; // 3 option parameter, didn't understand 3rd term
00212     }
00213   } else if(argc >= 4) {
00214     int bf = 0, ef = (-1), fs = 1, mid = (-1);
00215     const char *fileType = NULL; 
00216     const char *fileName = NULL;
00217     int do_action = (-1);
00218     int currarg = 1;
00219     int waitfor = FileSpec::WAIT_BACK;
00220 
00221     // find out what to do first
00222     if(!strupncmp(argv[currarg], "read", CMDLEN)) {
00223       do_action = 0;
00224     } else if(!strupncmp(argv[currarg], "write", CMDLEN)) {
00225       do_action = 1;
00226       waitfor = FileSpec::WAIT_ALL; // waitfor 'all' by default
00227     } else if(!strupncmp(argv[currarg], "delete", CMDLEN)) {
00228       do_action = 2;
00229       fs = -1; // for "delete", fs=1 means do not delete any frames.
00230     } else {
00231       cmd_animate_usage(interp);
00232       return TCL_ERROR;
00233     }
00234     currarg++;
00235 
00236     // if reading or writing, get file type and name
00237     if(do_action == 0 || do_action == 1) {
00238       fileType = argv[currarg++];
00239       fileName = argv[currarg++];
00240     }
00241     
00242     AtomSel *selection = NULL;
00243     ResizeArray<int> volsets;
00244     mid = app->molecule_top();
00245     // find if any beg, end, or skip specifiers
00246     while(currarg < argc) {
00247       if(currarg < (argc - 1)) {
00248         if(!strupncmp(argv[currarg], "beg", CMDLEN)) {
00249           bf = atoi(argv[currarg+1]);
00250           currarg += 2;
00251         } else if(!strupncmp(argv[currarg], "end", CMDLEN)) {
00252           ef = atoi(argv[currarg+1]);
00253           currarg += 2;
00254         } else if(!strupncmp(argv[currarg], "skip", CMDLEN)) {
00255           fs = atoi(argv[currarg+1]);
00256           currarg += 2;
00257         } else if(do_action == 2 && argc == 4 && currarg == 2 &&
00258                         !strupncmp(argv[currarg], "all", CMDLEN)) {
00259           if (strcmp(argv[currarg+1], "top"))
00260             mid = atoi(argv[currarg+1]);
00261           else
00262             mid = app->molecule_top();
00263           currarg += 2;
00264         } else if ((do_action == 0 || do_action == 1) && 
00265                    !strupncmp(argv[currarg], "waitfor", CMDLEN)) {
00266           const char *arg = argv[currarg+1];
00267           if (!strupncmp(arg, "all", CMDLEN))
00268             waitfor = FileSpec::WAIT_ALL;
00269           else
00270             waitfor = atoi(arg);
00271           currarg += 2;
00272         } else if (do_action == 1 && // writing
00273                    !strupncmp(argv[currarg], "sel", CMDLEN)) {
00274           // interpret the next argument as an atom selection
00275           const char *selstr = argv[currarg+1];
00276           if (!(selection = tcl_commands_get_sel(interp, selstr))) {
00277             Tcl_AppendResult(interp, "Invalid atom selection ", selstr, NULL);
00278             return TCL_ERROR;
00279           }
00280           currarg += 2;
00281         } else if (do_action == 1 && // writing
00282                    !strupncmp(argv[currarg], "volsets", CMDLEN)) {
00283           // interpret the next argument as a list of volsets
00284           const char *volstr = argv[currarg+1];
00285           int nsets;
00286           const char **setstrs;
00287           if (Tcl_SplitList(interp, volstr, &nsets, &setstrs) != TCL_OK) {
00288               Tcl_AppendResult(interp, "Invalid volset argument: ", volstr, NULL);
00289               return TCL_ERROR;
00290           }
00291           for (int i=0; i<nsets; i++) {
00292               int tmp;
00293               if (Tcl_GetInt(interp, setstrs[i], &tmp) != TCL_OK) {
00294                   Tcl_Free((char *)setstrs);
00295                   return TCL_ERROR;
00296               }
00297               volsets.append(tmp);
00298           }
00299           Tcl_Free((char *)setstrs);
00300           currarg += 2;
00301         } else
00302           return TCL_ERROR;
00303       } else {
00304         // only one item left; it must be the molecule id
00305         if (strcmp(argv[currarg], "top")) {
00306           mid = atoi(argv[currarg++]);
00307         } else {
00308           mid = app->molecule_top();
00309           currarg++;
00310         }
00311       }
00312     }
00313     
00314     // if a selection was given, make sure the molid of the selection matches
00315     // the molid for the write command.  This ensures that the number of atoms
00316     // in the selection matches those in the molecule.
00317     if (selection) {
00318       if (mid != selection->molid()) {
00319         Tcl_SetResult(interp, (char *) "ERROR: animate: Molecule in selection must match animation molecule.", TCL_STATIC);
00320         return TCL_ERROR;
00321       }
00322     }
00323     
00324     // do action now
00325     FileSpec spec;
00326     spec.first = bf; 
00327     spec.last = ef; 
00328     spec.stride = fs; 
00329     spec.waitfor = waitfor;
00330     if (do_action == 0) {
00331       int rc = app->molecule_load(mid, fileName, fileType, &spec);
00332       if (rc < 0) return TCL_ERROR;
00333 
00334     } else if (do_action == 1) {
00335       spec.selection = selection ? selection->on : NULL;
00336       if (volsets.num()) {
00337         // make a copy of the setids, since FileSpec frees its setids pointer
00338         spec.nvolsets = volsets.num();
00339         spec.setids = new int[spec.nvolsets];
00340         for (int i=0; i<spec.nvolsets; i++) spec.setids[i] = volsets[i];
00341       }
00342       int numwritten = app->molecule_savetrajectory(mid, fileName, fileType, 
00343               &spec);
00344       if (numwritten < 0) return TCL_ERROR;
00345       Tcl_SetObjResult(interp, Tcl_NewIntObj(numwritten));
00346 
00347     } else if (do_action == 2)
00348       app->molecule_deleteframes(mid, bf, ef, fs);
00349 
00350     else
00351       return TCL_ERROR;
00352 
00353   } else
00354     return TCL_ERROR;
00355     
00356   // if here, everything worked out ok
00357   return TCL_OK;
00358 }
00359 
00360 // read raw bytes into a typestep
00361 // Usage; rawtimestep <molid> <bytearray> -start index -frame whichframe 
00362 // Optional start parameter specifies where in the byte array to start reading
00363 // The array must contain at least (12*numatoms) bytes beginning from start 
00364 // or an error will be returned.
00365 // -frame parameter can be last, current, append, or a valid frame number.
00366 //   If 'last' and there are no frames, a new frame will be created.
00367 //   If 'current' and there are no frames, error.
00368 //   If 'append', always append.
00369 
00370 int cmd_rawtimestep(ClientData cd, Tcl_Interp *interp, int argc,
00371     Tcl_Obj * const objv[]) {
00372   VMDApp *app = (VMDApp *)cd;
00373   Molecule *mol;
00374   Timestep *ts;
00375   int molid=-1, start=0, frame=-1, length, neededLength;
00376   unsigned char *bytes;
00377 
00378   if (argc != 3 && argc != 5 && argc != 7) {
00379     Tcl_WrongNumArgs(interp, 1,objv, 
00380         "<molid> <bytearray> ?-start index? ?-frame whichframe?");
00381     return TCL_ERROR;
00382   }
00383 
00384   // get molid, either "top" or a number.
00385   if (!strcmp(Tcl_GetStringFromObj(objv[1], NULL), "top")) 
00386     molid = app->molecule_top();
00387   else if (Tcl_GetIntFromObj(interp, objv[1], &molid) != TCL_OK)
00388     return TCL_ERROR;
00389   if (!(mol = app->moleculeList->mol_from_id(molid))) {
00390     Tcl_SetResult(interp, (char *) "rawtimestep: invalid molid", TCL_STATIC);
00391     return TCL_ERROR;
00392   }
00393 
00394   // Read raw bytes and get length
00395   if (!(bytes = Tcl_GetByteArrayFromObj(objv[2], &length))) {
00396     Tcl_SetResult(interp, (char *) "rawtimestep: could not read bytearray", TCL_STATIC);
00397     return TCL_ERROR;
00398   }
00399 
00400   // Read optional frame and start otions
00401   for (int iarg=3; iarg<argc; iarg += 2) {
00402     const char *opt = Tcl_GetStringFromObj(objv[iarg], NULL);
00403     if (!strcmp(opt, "-start")) {
00404       if (Tcl_GetIntFromObj(interp, objv[iarg+1], &start) != TCL_OK)
00405         return TCL_ERROR;
00406     } else if (!strcmp(opt, "-frame")) {
00407       // check for "last", "current", "append", otherwise must be numeric and
00408       // in the correct range
00409       const char *strframe = Tcl_GetStringFromObj(objv[iarg+1], NULL);
00410       if (!strcmp(strframe, "last")) {
00411         // allow frame to be -1 if the number of frames is zero, which 
00412         // corresponds to "append".
00413         frame = mol->numframes()-1;
00414       } else if (!strcmp(strframe, "current")) {
00415         frame = mol->frame();
00416       } else if (!strcmp(strframe, "append")) {
00417         frame = -1;
00418       } else {
00419         int tmpframe = -1;
00420         if (Tcl_GetIntFromObj(interp, objv[iarg+1], &tmpframe) != TCL_OK) 
00421           return TCL_ERROR;
00422         if (tmpframe < 0 || tmpframe >= mol->numframes()) {
00423           Tcl_SetResult(interp, (char *) "rawtimestep: invalid frame specified.",
00424               TCL_STATIC);
00425           return TCL_ERROR;
00426         }
00427         frame = tmpframe;
00428       }
00429     } else {
00430       Tcl_SetResult(interp, (char *) "rawtimestep: valid options are -frame and -start",
00431           TCL_STATIC);
00432       return TCL_ERROR;
00433     }
00434   }
00435 
00436   // Check that the size of the byte array and the start option are valid
00437   neededLength = 12L*mol->nAtoms;
00438   if (length-start < neededLength) {
00439     Tcl_SetResult(interp, (char *) "rawtimestep: not enough bytes!", TCL_STATIC);
00440     return TCL_ERROR;
00441   }
00442 
00443   // Get the timestep - either existing or new
00444   ts = (frame < 0) ? new Timestep(mol->nAtoms) 
00445                    : mol->get_frame(frame);
00446   if (!ts) {
00447     Tcl_SetResult(interp, (char *) "rawtimestep: Unable to find timestep!", TCL_STATIC);
00448     return TCL_ERROR;
00449   }
00450   memcpy(ts->pos, bytes+start, neededLength);
00451   if (frame < 0) {
00452     mol->append_frame(ts);
00453   } else {
00454     mol->force_recalc(DrawMolItem::MOL_REGEN);
00455   }
00456   return TCL_OK;
00457 }
00458 
00459 
00460 // return timestep as byte array.
00461 // arguments: molid, frame
00462 int cmd_gettimestep(ClientData cd, Tcl_Interp *interp, int argc,
00463     Tcl_Obj * const objv[]) {
00464   if (argc != 3) {
00465     Tcl_WrongNumArgs(interp, 1, objv, "molid frame");
00466     return TCL_ERROR;
00467   }
00468 
00469   VMDApp *app = (VMDApp *)cd;
00470   int molid = -1;
00471   const char *molidstr = Tcl_GetStringFromObj(objv[1], NULL);
00472   if (!strcmp(molidstr, "top")) {
00473     molid = app->molecule_top();
00474   } else if (Tcl_GetIntFromObj(interp, objv[1], &molid) != TCL_OK) {
00475     return TCL_ERROR;
00476   }
00477 
00478   Molecule *mol = app->moleculeList->mol_from_id(molid);
00479   if (!mol) {
00480     Tcl_AppendResult(interp, "Invalid molid: ", molidstr, NULL);
00481     return TCL_ERROR;
00482   }
00483 
00484   int frame;
00485   if (Tcl_GetIntFromObj(interp, objv[2], &frame) != TCL_OK)
00486     return TCL_ERROR;
00487 
00488   if (frame < 0 || frame >= mol->numframes()) {
00489     Tcl_AppendResult(interp, "Invalid frame for molecule ", molidstr, NULL);
00490     return TCL_ERROR;
00491   }
00492 
00493   Timestep *ts = mol->get_frame(frame);
00494   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
00495         (const unsigned char *)(ts->pos),   // bytes
00496         3L*mol->nAtoms*sizeof(float)));      // length
00497 
00498   return TCL_OK;
00499 }
00500 

Generated on Thu Apr 25 02:42:00 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002