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

DrawMolecule.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 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: DrawMolecule.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.139 $      $Date: 2011/07/20 19:45:22 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Displayable version of a DrawMolecule, derived from BaseMolecule and
00020  * Displayable.  This contains all the info for rendering
00021  * the molecule.
00022  *
00023  ***************************************************************************/
00024 
00025 #include "DrawMolecule.h"
00026 #include "AtomColor.h"
00027 #include "AtomRep.h"
00028 #include "AtomSel.h"
00029 #include "utilities.h"
00030 #include "VMDApp.h"
00031 #include "MoleculeList.h"
00032 #include "CommandQueue.h"
00033 #include "CmdAnimate.h"
00034 #include "Stride.h"
00035 #include "PickList.h"
00036 #include "MaterialList.h"
00037 #include "Inform.h"
00038 #include "TextEvent.h"
00039 #include "DisplayDevice.h"
00040 #include "MoleculeGraphics.h"
00041 #include "BondSearch.h"
00042 #include "DrawForce.h"
00043 #include "VolumetricData.h"
00044 #include "CUDAAccel.h"
00045 
00047 
00048 DrawMolecule::DrawMolecule(VMDApp *vmdapp, Displayable *par)
00049         : BaseMolecule(vmdapp->next_molid()), 
00050           Displayable(par), app(vmdapp), repList(8) {
00051   repcounter = 0;
00052   curframe = -1;
00053   active = TRUE;
00054   did_secondary_structure = 0;
00055   molgraphics = new MoleculeGraphics(this);
00056   vmdapp->pickList->add_pickable(molgraphics);
00057   drawForce = new DrawForce(this);
00058 
00059   invalidate_cov_scale();
00060   center[0] = center[1] = center[2] = 0.0f;
00061 
00062   need_find_bonds = 0;
00063 }
00064   
00065 // destructor ... free up any extra allocated space (the child Displayables
00066 // will be deleted by the Displayable destructor)
00067 DrawMolecule::~DrawMolecule() {
00068   int i;
00069 
00070   // delete all molecule representations
00071   for(i=0; i < components(); i++) {
00072     app->pickList->remove_pickable(component(i));
00073     delete component(i);  
00074   }
00075 
00076   app->pickList->remove_pickable(molgraphics);
00077 
00078   // delete all timesteps
00079   for (i=timesteps.num()-1; i>=0; i--) {
00080     delete timesteps[i];
00081     timesteps.remove(i);
00082   }
00083 
00084   delete molgraphics;
00085 }
00086 
00088 
00089 // return Nth component ... change to proper return type
00090 DrawMolItem *DrawMolecule::component(int n) {
00091   if(n >= 0 && n < components())
00092     return repList[n];
00093   else
00094     return NULL;
00095 }
00096 
00097 
00098 // return the component corresponding to the pickable
00099 DrawMolItem *DrawMolecule::component_from_pickable(const Pickable *p) {
00100   for (int i=0; i<components(); i++) 
00101     if (repList[i] == p) return repList[i];
00102   return NULL; // no matching component
00103 }
00104 
00105 
00106 // return the available CUDA device pool to the caller
00107 wkf_threadpool_t * DrawMolecule::cuda_devpool(void) {
00108   return (app->cuda != NULL) ? app->cuda->get_cuda_devpool() : NULL;
00109 }
00110 
00111 
00112 // Return true if ANY representation is displaying atom n
00113 int DrawMolecule::atom_displayed(int n) {
00114   if (displayed() && n >= 0 && n < nAtoms) {
00115     for (int i=(components() - 1); i >= 0; i--) {
00116       if ((repList[i])->atom_displayed(n))
00117         return TRUE; // atom is shown
00118     }
00119   }
00120   return FALSE; // atom is not shown
00121 }
00122 
00123 
00124 // delete the Nth representation ... return success
00125 int DrawMolecule::del_rep(int n) {
00126   DrawMolItem *rep = component(n);
00127   if (rep) {
00128     app->pickList->remove_pickable(rep);
00129     delete rep;         // delete the object
00130     repList.remove(n);  // and it's slot in the representation list
00131     invalidate_cov_scale();
00132   }
00133 
00134   return (rep != NULL);
00135 }
00136 
00137 
00138 void DrawMolecule::add_rep(AtomColor *ac, AtomRep *ar, AtomSel *as, 
00139                           const Material *am) {
00140   // Rep has unique name (unique within the molecule)
00141   char buf[50];
00142   sprintf(buf, "rep%d", repcounter++);
00143   DrawMolItem *rep = new DrawMolItem(buf, this, ac, ar, as);
00144   app->pickList->add_pickable(rep);
00145   rep->change_material(am);
00146   repList.append(rep);
00147   invalidate_cov_scale();
00148 }
00149 
00150 int DrawMolecule::show_rep(int repid, int onoff) {
00151   DrawMolItem *rep = component(repid);
00152   if (rep) {
00153     if (onoff) rep->on();
00154     else rep->off();
00155     invalidate_cov_scale();
00156     return TRUE;
00157   }
00158   return FALSE;
00159 }
00160 
00161 // change the Nth representation ... return success.
00162 // if any object is NULL, that characteristic is not changed.
00163 int DrawMolecule::change_rep(int n, AtomColor *ac, AtomRep *ar, const char *sel) { 
00164   DrawMolItem *rep = component(n);
00165   if (rep) {
00166     rep->change_color(ac);
00167     rep->change_rep(ar);
00168     rep->change_sel(sel);  // returns TRUE if there was no problem, or if
00169                            // sel was NULL meaning no action is to be taken
00170     invalidate_cov_scale();
00171     return TRUE;
00172   }
00173 
00174   return FALSE;
00175 }
00176 
00177 
00178 // redraw all the representations
00179 void DrawMolecule::force_recalc(int reason) {
00180   int numcomp = components();
00181   for (int i=0; i<numcomp; i++) {
00182     component(i)->force_recalc(reason);
00183   }
00184   // The preceding loop updates all the DrawMolItem reps, but other children
00185   // of DrawMolecule (i.e. DrawForce) need to know about the update as well.
00186   // Calling need_matrix_recalc sets the _needUpdate flag for this purpose.
00187   need_matrix_recalc();
00188   app->commandQueue->runcommand(new CmdAnimNewFrame);
00189 
00190   // MOL_REGEN or SEL_REGEN implies our scale factor may have changed.  
00191   if (reason & (DrawMolItem::MOL_REGEN | DrawMolItem::SEL_REGEN)) 
00192     invalidate_cov_scale();
00193 }
00194 
00195 
00196 // tell the rep to update its PBC transformation matrices next prepare cycle
00197 void DrawMolecule::change_pbc() {
00198   int numcomp = components();
00199   for (int i=0; i<numcomp; i++) 
00200     component(i)->change_pbc();
00201   // labels can be made between periodic images, so warn them that the
00202   // distance between images has changed.  Would be better to set a flag
00203   // so that notify can only get called once, inside of prepare().
00204   notify();
00205 }
00206 
00207 
00208 // tell the rep to update its timestep
00209 void DrawMolecule::change_ts() {
00210   int numcomp = components();
00211   for (int i=0; i<numcomp; i++) 
00212     component(i)->change_ts();
00213 
00214   molgraphics->prepare();
00215   drawForce->prepare();
00216 
00217   notify();
00218 
00219   // now that internal state has been updated, notify scripts
00220   app->commandQueue->runcommand( new FrameEvent(id(), curframe) );
00221 }
00222 
00223 
00224 // query whether this molecule contains a highlighted rep
00225 int DrawMolecule::highlighted_rep() const {
00226   if (app->highlighted_molid != id()) 
00227     return -1;
00228   return app->highlighted_rep;
00229 }
00230 
00231 
00232 // get the component by its string name
00233 int DrawMolecule::get_component_by_name(const char *nm) {
00234   // XXX linear search for the name is slow
00235   int numreps = repList.num();
00236   for (int i=0; i<numreps; i++) {
00237     if (!strcmp(repList[i]->name, nm))
00238       return i; // return component
00239   }
00240   return -1; // failed to find a component with that name
00241 }
00242 
00243 
00244 // get the name of the specified component
00245 const char *DrawMolecule::get_component_name(int ind) {
00246   DrawMolItem *rep = component(ind);
00247   if (!rep) 
00248     return FALSE;
00249   return rep->name;
00250 }
00251 
00252 void DrawMolecule::prepare() {
00253   if (needUpdate()) {
00254     notify(); // notify monitors
00255   }
00256 }
00257 
00258 void DrawMolecule::override_current_frame(int n) {
00259     if (n == curframe) return;
00260     int num = timesteps.num();
00261     if ( num==0 ) return;
00262     if ( n<0 ) curframe = 0;
00263     else if ( n>=num ) curframe = num-1;
00264     else curframe = n;
00265     invalidate_cov_scale();
00266 }
00267 
00268 // notify monitors of an update
00269 void DrawMolecule::notify() {
00270   int monnum = monitorlist.num();
00271   int nid = id();
00272   for (int i=0; i<monnum; i++) 
00273     monitorlist[i]->notify(nid);
00274 }
00275 
00276 
00277 // add a new frame
00278 void DrawMolecule::append_frame(Timestep *ts) {
00279   timesteps.append(ts);  // add the timestep to the animation
00280 
00281   // To ensure compatibility with legacy behavior, always advance to the
00282   // newly added frame.  
00283   override_current_frame(timesteps.num() - 1);
00284 
00285   // Notify that curframe changed.  This appears to entail no significant
00286   // overhead: reps update lazily, molgraphics only regenerates if it's been
00287   // modified since the last update, and DrawForce seems to be innocuous as
00288   // well.
00289   change_ts();
00290 
00291   // recenter the molecule when the first coordinate frame is loaded
00292   if (timesteps.num() == 1) {    
00293 #if 0
00294     // XXX this is a nice hack to allow easy benchmarking of real VMD
00295     //     trajectory I/O rates without having to first load some coords
00296     if (getenv("VMDNOCOVCALC") == NULL)
00297 #endif
00298       app->scene_resetview_newmoldata();
00299   }
00300 
00301   // update bonds if needed, when any subsequent frame is loaded
00302   if (timesteps.num() >= 1) {    
00303     // find bonds if necessary
00304     if (need_find_bonds == 1) {     
00305       need_find_bonds = 0;
00306       vmd_bond_search(this, ts, -1, 0); // just add bonds, no dup checking
00307     } else if (need_find_bonds == 2) {
00308       need_find_bonds = 0;
00309       vmd_bond_search(this, ts, -1, 1); // add bonds checking for dups
00310     }
00311   }
00312 
00313   addremove_ts();              // tell all reps to update themselves
00314   app->commandQueue->runcommand(new CmdAnimNewNumFrames); // update frame count
00315 }
00316 
00317 
00318 // duplicate an existing frame
00319 void DrawMolecule::duplicate_frame(const Timestep *ts) {
00320   Timestep *newts;
00321   if (ts == NULL) { // append a 'null' frame
00322     newts = new Timestep(nAtoms);
00323     newts->zero_values();
00324   } else {
00325     newts = new Timestep(*ts);
00326   }
00327   append_frame(newts);
00328 }
00329 
00330 
00331 // delete a frame
00332 void DrawMolecule::delete_frame(int n) {
00333     if (n<0 || n>=timesteps.num()) return;
00334     delete timesteps[n];
00335     timesteps.remove(n);
00336 
00337     // notifications
00338     addremove_ts();
00339     app->commandQueue->runcommand(new CmdAnimNewNumFrames);
00340 
00341     // adjust current frame if necessary
00342     if (curframe >= timesteps.num()) {
00343         curframe = timesteps.num()-1;
00344         change_ts();
00345     }
00346 }
00347 
00348 
00349 // add or remove a timestep
00350 void DrawMolecule::addremove_ts() {
00351   int numcomp = components();
00352   for (int i=0; i<numcomp; i++) 
00353     component(i)->change_traj();
00354 }
00355 
00356 
00357 // return the norm, double-precision arguments
00358 static float dnorm(const double *v) {
00359   return (float)sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
00360 }
00361 
00362 void DrawMolecule::invalidate_cov_scale() {
00363   scalefactor = -1;
00364 }
00365 
00366 // scaling factor required to make the molecule fit within (-1 ... 1)
00367 float DrawMolecule::scale_factor() {
00368   if (scalefactor < 0) update_cov_scale();
00369   if (scalefactor > 0) {
00370     return scalefactor;
00371 
00372   } else if (molgraphics->num_elements() > 0) {
00373     return molgraphics->scale_factor();
00374 
00375   } else if (volumeList.num() > 0) {
00376     // scale factor is 1.5/(maxrange), where maxrange is the largest range
00377     // of the data along any cardinal axis.  That's how Timestep does it, 
00378     // anyway.  The volumetric axes aren't necessarily orthogonal so I'll
00379     // just go with the largest value.
00380     const VolumetricData *data = volumeList[0];
00381     float x=dnorm(data->xaxis), y=dnorm(data->yaxis), z=dnorm(data->zaxis);
00382     float scale_factor = x > y ? x : y;
00383     scale_factor = scale_factor > z ? scale_factor : z;
00384     if (scale_factor > 0) return 1.5f/scale_factor;
00385   }
00386   return 1.0f;
00387 }
00388 
00389 
00390 // center of volume of this molecule
00391 int DrawMolecule::cov(float& x, float& y, float& z) {
00392   if (scalefactor < 0) update_cov_scale();
00393 
00394   if (scalefactor > 0) {
00395     // have valid coordinate data
00396     x = center[0]; y = center[1]; z = center[2];
00397 
00398   } else if (molgraphics->num_elements() > 0) {
00399     // use user-defined graphics to center 
00400     molgraphics->cov(x, y, z);
00401 
00402   } else if (volumeList.num() > 0) {
00403     // use first volumetric data set
00404     const VolumetricData *data = volumeList[0];
00405     x = (float) (data->origin[0] + 
00406         0.5*(data->xaxis[0] + data->yaxis[0] + data->zaxis[0]));
00407     y = (float) (data->origin[1] + 
00408         0.5*(data->xaxis[1] + data->yaxis[1] + data->zaxis[1]));
00409     z = (float) (data->origin[2] + 
00410         0.5*(data->xaxis[2] + data->yaxis[2] + data->zaxis[2]));
00411   } else {
00412     return FALSE;
00413   }
00414   return TRUE;
00415 }
00416 
00417 
00419 int DrawMolecule::recalc_bonds() {
00420   Timestep *ts = current();
00421 
00422   if (ts) {
00423     clear_bonds();                     // clear the existing bond list
00424     vmd_bond_search(this, ts, -1, 0);  // just add bonds, no dup checking
00425     msgInfo << "Bond count: " << count_bonds() << sendmsg;
00426     return 0;
00427   } 
00428 
00429   msgInfo << "No coordinates" << sendmsg;
00430   return -1;
00431 }
00432 
00433 int DrawMolecule::need_secondary_structure(int calc_if_not_yet_done) {
00434   if (did_secondary_structure) return TRUE; 
00435 
00436   if (calc_if_not_yet_done) {
00437     if (!current()) return FALSE; // fails if there's no frame
00438     did_secondary_structure = TRUE;
00439     app->show_stride_message();
00440     if (ss_from_stride(this)) {
00441       msgErr << "Call to Stride program failed." << sendmsg;
00442       return FALSE;
00443     }
00444     return TRUE;
00445   }
00446   // just indicate that we don't need to do the calculation anymore
00447   did_secondary_structure = TRUE;
00448   return TRUE;
00449 }
00450 
00451 void DrawMolecule::invalidate_ss() {
00452   did_secondary_structure = 0;
00453 }
00454 
00455 int DrawMolecule::recalc_ss() {
00456   did_secondary_structure = 0;
00457   int success = need_secondary_structure(1);
00458   did_secondary_structure = 1;
00459 
00460   if (success) for (int i=0; i<components(); i++) component(i)->change_ss();
00461   return success;
00462 }
00463 
00464 void DrawMolecule::register_monitor(DrawMoleculeMonitor *mon) {
00465   monitorlist.append(mon);
00466 }
00467 void DrawMolecule::unregister_monitor(DrawMoleculeMonitor *mon) {
00468   monitorlist.remove(monitorlist.find(mon));
00469 }
00470 
00471 void DrawMolecule::update_cov_scale() {
00472   const Timestep *ts = current();
00473   if (!ts) return;
00474   int i, n = ts->num;
00475   // only do this if there are atoms
00476   if (!n) return;
00477 
00478   float covx, covy, covz;
00479   float minposx, minposy, minposz;
00480   float maxposx, maxposy, maxposz;
00481 
00482   // flags for selected atoms in displayed reps
00483   ResizeArray<int> tmp_(n);  // so I free automatically on return
00484   int *on = &tmp_[0];
00485   for (i=0; i<n; i++) on[i] = 0;
00486   for (int j=0; j<repList.num(); j++) {
00487     const DrawMolItem *rep = repList[j];
00488     if (!rep->displayed()) continue;
00489     const int *flgs = rep->atomSel->on;
00490     for (i=0; i<n; i++) on[i] |= flgs[i];
00491   }
00492   // find the first on atom
00493   int istart = -1;
00494   for (i=0; i<n; i++) {
00495     if (on[i]) {
00496       istart = i;
00497       break;
00498     }
00499   }
00500   if (istart < 0) {
00501     // no selected atoms.  Use all coordinates in this case.
00502     istart = 0;
00503     for (i=0; i<n; i++) on[i] = 1;
00504   }
00505 
00506   // initialize min/max positions with values from the first on atom
00507   const float *mpos = ts->pos + 3*istart;
00508   minposx = maxposx = mpos[0];
00509   minposy = maxposy = mpos[1];
00510   minposz = maxposz = mpos[2];
00511   covx = covy = covz = 0.0;
00512 
00513   int icount = 0;
00514   for (i=istart; i<n; ++i, mpos += 3) {
00515     if (!on[i]) continue;
00516     ++icount;
00517   
00518     const float xpos = mpos[0];
00519     const float ypos = mpos[1]; 
00520     const float zpos = mpos[2]; 
00521 
00522     covx += xpos;
00523     covy += ypos;
00524     covz += zpos;
00525 
00526     if (xpos < minposx) minposx = xpos;
00527     if (xpos > maxposx) maxposx = xpos;
00528 
00529     if (ypos < minposy) minposy = ypos;
00530     if (ypos > maxposy) maxposy = ypos; 
00531 
00532     if (zpos < minposz) minposz = zpos;
00533     if (zpos > maxposz) maxposz = zpos;
00534   }
00535 
00536   // set the center of volume variable now
00537   center[0] = covx; 
00538   center[1] = covy; 
00539   center[2] = covz; 
00540   vec_scale(center, 1.0f / icount, center);
00541  
00542   // calculate center-of-volume and scale factor
00543   scalefactor = maxposx - minposx;
00544 
00545   // prevent getting a zero-scaled scene when loading a single atom.
00546   if (scalefactor == 0.0) {
00547     scalefactor = 3.0;
00548   }
00549 
00550   if ((maxposx - minposx) > scalefactor)
00551     scalefactor = maxposx - minposx;
00552   if ((maxposy - minposy) > scalefactor)
00553     scalefactor = maxposy - minposy;
00554   if ((maxposz - minposz) > scalefactor)
00555     scalefactor = maxposz - minposz;
00556 
00557   scalefactor = 1.5f / scalefactor;
00558 }
00559 

Generated on Wed May 16 01:49:12 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002