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

Generated on Mon Sep 8 01:25:55 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002