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: P_Tool.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.84 $ $Date: 2019年01月24日 04:57:13 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * This is Paul's new Tracker code -- pgrayson@ks.uiuc.edu 00019 * 00020 * 00021 ***************************************************************************/ 00022 00023 #include "P_Tracker.h" 00024 #include "P_Feedback.h" 00025 #include "P_Buttons.h" 00026 #include "P_Tool.h" 00027 #include "DispCmds.h" 00028 #include "Scene.h" 00029 #include "VMDApp.h" 00030 #include "AtomSel.h" 00031 #include "MoleculeList.h" 00032 #include "PickList.h" 00033 #include "Displayable.h" 00034 00036 class DrawTool : public Displayable { 00037 public: 00038 DrawTool(Displayable *aParent) 00039 : Displayable(aParent) { 00040 00041 rot_off(); // don't listen to anyone else's transformations 00042 scale_on(); 00043 set_scale(1); 00044 scale_off(); 00045 glob_trans_off(); 00046 cent_trans_off(); 00047 00048 // set up the display list once, since it never changes 00049 DispCmdCone cone; 00050 DispCmdColorIndex drawcolor; 00051 float base[3] = {0, 0.0, 0.0}; 00052 float tip[3] = {-0.7f, 0.0, 0.0}; 00053 append(DMATERIALON); 00054 drawcolor.putdata(REGTAN, cmdList); 00055 cone.putdata(tip, base, 0.07f, 0, 40, cmdList); 00056 tip[0] = -0.6f; 00057 00058 base[0] = -0.6f; 00059 base[1] = 0.1f; 00060 base[2] = 0.0f; 00061 cone.putdata(base, tip, 0.04f, 0, 20, cmdList); 00062 } 00063 }; 00064 00065 00066 Tool::Tool(int serialno, VMDApp *vmdapp, Displayable *aParent) 00067 : UIObject(vmdapp), my_id(serialno) { 00068 00069 tracker = NULL; 00070 buttons = NULL; 00071 feedback = NULL; 00072 amalive = 1; 00073 00074 lost_sensor=0; 00075 wasgrabbing=0; 00076 forcescale = 1; 00077 springscale = 1; 00078 00079 targeted_atom = targeted_molecule = -1; 00080 // As long as a rep is targeted, the targeted molecule must be valid and 00081 // not change. 00082 targeted_rep = NULL; 00083 sel_total_mass = 0; 00084 00085 dtool = new DrawTool(aParent); 00086 } 00087 00088 Tool::~Tool() { 00089 delete dtool; 00090 delete [] targeted_rep; 00091 if (!lost_sensor) { 00092 delete tracker; 00093 delete buttons; 00094 delete feedback; 00095 } 00096 } 00097 00098 void Tool::clear_devices() { 00099 forceoff(); 00100 delete tracker; tracker = NULL; 00101 delete buttons; buttons = NULL; 00102 delete feedback; feedback = NULL; 00103 } 00104 00105 int Tool::add_tracker(VMDTracker *t, const SensorConfig *config) { 00106 delete tracker; 00107 tracker = t; 00108 if (tracker) { 00109 trackerDev = (char *)config->getdevice(); 00110 return tracker->start(config); 00111 } 00112 return TRUE; 00113 } 00114 int Tool::add_feedback(Feedback *f, const SensorConfig *config) { 00115 delete feedback; 00116 feedback = f; 00117 if (feedback) { 00118 feedbackDev = (char *)config->getdevice(); 00119 return feedback->start(config); 00120 } 00121 return TRUE; 00122 } 00123 int Tool::add_buttons(Buttons *b, const SensorConfig *config) { 00124 delete buttons; 00125 buttons = b; 00126 if (buttons) { 00127 buttonDev = (char *)config->getdevice(); 00128 return buttons->start(config); 00129 } 00130 return TRUE; 00131 } 00132 00133 int Tool::remove_device(const char *device) { 00134 if (tracker && !strcmp(device, (const char *)trackerDev)) { 00135 delete tracker; 00136 tracker = NULL; 00137 } else if (feedback && !strcmp(device, (const char *)feedbackDev)) { 00138 delete feedback; 00139 feedback = NULL; 00140 } else if (buttons && !strcmp(device, (const char *)buttonDev)) { 00141 delete buttons; 00142 buttons = NULL; 00143 } else { 00144 return 0; 00145 } 00146 return 1; 00147 } 00148 00149 int Tool::steal_sensor(Tool *from) { 00150 clear_devices(); 00151 tracker = from->tracker; 00152 buttons = from->buttons; 00153 feedback = from->feedback; 00154 trackerDev = from->trackerDev; 00155 buttonDev = from->buttonDev; 00156 feedbackDev = from->feedbackDev; 00157 00158 springscale = from->springscale; 00159 forcescale = from->forcescale; 00160 from->lost_sensor = 1; 00161 return TRUE; 00162 } 00163 void Tool::getdevices(char **ret) { 00164 int i=0; 00165 if (tracker) ret[i++] = (char *)(const char *)trackerDev; 00166 if (buttons) ret[i++] = (char *)(const char *)buttonDev; 00167 if (feedback) ret[i++] = (char *)(const char *)feedbackDev; 00168 ret[i] = NULL; 00169 } 00170 00171 int Tool::isgrabbing() { 00172 if (buttons) return buttons->state(0); 00173 return 0; 00174 } 00175 00176 const float *Tool::position() const { 00177 if (tracker) return pos; 00178 return NULL; 00179 } 00180 00181 const Matrix4 *Tool::orientation() { 00182 if (tracker) return &orient; 00183 return NULL; 00184 } 00185 00186 void Tool::update() { 00187 if (tracker) { 00188 tracker->update(); 00189 if (!tracker->alive()) { 00190 msgWarn << "Tool: lost connection to tracker " << tracker->device_name() 00191 << sendmsg; 00192 amalive = 0; 00193 delete tracker; 00194 tracker = NULL; 00195 } else { 00196 const float *tmp = tracker->position(); 00197 for (int i=0; i<tracker->dimension(); i++) pos[i] = tmp[i]; 00198 orient.loadmatrix(tracker->orientation()); 00199 } 00200 } 00201 if (buttons) buttons->update(); 00202 if (feedback) feedback->update(); 00203 } 00204 00205 int Tool::check_event() { 00206 update(); 00207 00208 // subclass-specific action 00209 do_event(); 00210 00211 // update the visual orientation of the tool if there is a tracker 00212 if (tracker) { 00213 dtool->rot_on(); 00214 dtool->glob_trans_on(); 00215 dtool->set_rot(*orientation()); 00216 dtool->set_glob_trans(position()[0], position()[1], position()[2]); 00217 dtool->rot_off(); 00218 dtool->glob_trans_off(); 00219 } 00220 return 1; 00221 } 00222 00223 void Tool::setscale(float sc) { 00224 if (tracker) tracker->set_scale(sc); 00225 } 00226 float Tool::getscale() { 00227 if (tracker) return tracker->get_scale(); 00228 return 0; 00229 } 00230 00231 void Tool::setoffset(float *offset) { 00232 if (tracker) tracker->set_offset(offset); 00233 } 00234 const float *Tool::getoffset() { 00235 if (tracker) return tracker->get_offset(); 00236 return NULL; 00237 } 00238 00239 int Tool::assign_rep(int mol, int rep) { 00240 Molecule *m = app->moleculeList->mol_from_id(mol); 00241 if (!m) return FALSE; 00242 DrawMolItem *item = m->component(rep); 00243 if (!item) return FALSE; 00244 clear_rep(); 00245 targeted_rep = stringdup(item->name); 00246 targeted_molecule = mol; 00247 const AtomSel *sel = item->atomSel; 00248 00249 // get the total mass 00250 sel_total_mass=0; 00251 const float *mass = m->mass(); 00252 for (int i=sel->firstsel; i<=sel->lastsel; i++) { 00253 if (sel->on[i]) { 00254 sel_total_mass += mass[i]; 00255 } 00256 } 00257 00258 // kill the highlight 00259 if (app->pickList) { 00260 app->pickList->pick_callback_clear((char *)"uivr"); 00261 } 00262 return TRUE; 00263 } 00264 00265 int Tool::get_targeted_atom(int *molret, int *atomret) const { 00266 if (targeted_rep != NULL) return 0; // must be an atom 00267 if (targeted_molecule == -1) return 0; // must be targeted 00268 *molret = targeted_molecule; 00269 *atomret = targeted_atom; 00270 return 1; 00271 } 00272 00273 void Tool::tool_location_update() { 00274 int tag; 00275 00276 // pick a nearby atom if necessary 00277 if(position() && make_callbacks && !targeted_rep) 00278 app->pickList->pick_check(3, position(), tag, NULL, 00279 0.2f,(char *)"uivr"); 00280 } 00281 00282 int Tool::target(int target_type, float *mpos, int just_checking) { 00283 int mol = -1; 00284 int atom = -1; 00285 int tag = -1; 00286 Molecule *m; 00287 Matrix4 globm; 00288 00289 mpos[0]=mpos[1]=mpos[2]=0; 00290 00291 // is the position NULL? 00292 if(!position()) return 0; 00293 00294 // are we selecting something? 00295 if(targeted_rep && target_type == TARGET_TUG) { 00296 // Check that the targeted rep still exists 00297 int repid = app->molrep_get_by_name(targeted_molecule, targeted_rep); 00298 if (repid >= 0 && app->molecule_numframes(targeted_molecule) > 0) { 00299 Molecule *m = app->moleculeList->mol_from_id(targeted_molecule); 00300 Timestep *ts = m->current(); 00301 const AtomSel *sel = m->component(repid)->atomSel; 00302 00303 // Loop over each atom in the selection to get the COM. 00304 float com[3] = {0,0,0}; 00305 const float *amass = m->mass(); 00306 for (int i=sel->firstsel; i<=sel->lastsel; i++) { 00307 if (sel->on[i]) { 00308 float mass = amass[i]; 00309 float *p = ts->pos + 3*i; 00310 com[0] += p[0]*mass; 00311 com[1] += p[1]*mass; 00312 com[2] += p[2]*mass; 00313 } 00314 } 00315 vec_scale(com,1/sel_total_mass,com); 00316 00317 // Now transform the coordinates for the tracker 00318 globm = m->tm; // use centering as well, so we find the exact atom 00319 globm.multpoint3d(com,mpos); 00320 00321 return 1; 00322 } else { 00323 // Our targeted rep has flown the coop. Fall back on regular target 00324 clear_rep(); 00325 } 00326 } 00327 00328 if(targeted_molecule == -1) { 00329 Pickable *p=NULL; 00330 if (app->display) { 00331 if(make_callbacks) { 00332 p = app->pickList->pick_check(3, position(), tag, NULL, 0.2f, 00333 (char *)"uivr"); 00334 } else { 00335 p = app->pickList->pick_check(3, position(), tag, NULL, 0.2f); 00336 } 00337 00338 if (p) { 00339 Molecule *m = app->moleculeList->check_pickable(p); 00340 if (m) { 00341 mol = m->id(); 00342 atom = tag; 00343 } 00344 } 00345 } 00346 00347 if (atom == -1 || mol == -1) return 0; 00348 00349 if(!just_checking) { 00350 targeted_atom = atom; 00351 targeted_molecule = mol; 00352 } 00353 } 00354 else { 00355 atom = targeted_atom; 00356 mol = targeted_molecule; 00357 } 00358 00359 m = app->moleculeList->mol_from_id(mol); 00360 00361 /* verify sanity */ 00362 if(m==NULL) { 00363 msgErr << "Tool: Bad molecule ID found." << sendmsg; 00364 let_go(); 00365 return 0; 00366 } 00367 00368 /* Now return the correct position to the targeting tool */ 00369 if(target_type == TARGET_GRAB) { // target a molecule 00370 globm.translate(m->globt); 00371 vec_copy(mpos, m->globt); 00372 } else { // target an atom 00373 globm = m->tm; // use centering as well, so we find the exact atom 00374 Timestep *ts = m->current(); 00375 if(ts->pos == NULL) { 00376 msgErr << "Timestep has NULL position." << sendmsg; 00377 } 00378 00379 float *p = ts->pos + 3*atom; 00380 00381 globm.multpoint3d(p,mpos); 00382 } 00383 00384 return 1; 00385 } 00386 00387 void Tool::tug(const float *theforce) { 00388 Molecule *m = app->moleculeList->mol_from_id(targeted_molecule); 00389 if (!m) return; 00390 00391 Matrix4 rot = m->rotm; 00392 // since this is an orthogonal matrix, a transpose is an inverse 00393 rot.transpose(); 00394 float force[3]; 00395 rot.multpoint3d(theforce, force); 00396 00397 if (targeted_rep) { 00398 // if there is a selection, pull with a total force <force> 00399 const AtomSel *sel = m->component( 00400 app->molrep_get_by_name(targeted_molecule, targeted_rep))->atomSel; 00401 const float *amass = m->mass(); 00402 for (int i=sel->firstsel; i<=sel->lastsel; i++) { 00403 if (sel->on[i]) { 00404 float mass = amass[i]; 00405 float atomforce[3]; 00406 vec_scale(atomforce,mass/sel_total_mass,force); 00407 m->addForce(i, atomforce); 00408 } 00409 } 00410 } 00411 else { 00412 // otherwise just pull with a simple force 00413 m->addForce(targeted_atom, force); 00414 } 00415 } 00416 00417 void Tool::dograb() { 00418 Molecule *m; 00419 Matrix4 rot; 00420 float p[3], mpos[3], mdiff[3], mrotdiff[3], mchange[3], futurepos[3]; 00421 00422 m = app->moleculeList->mol_from_id(targeted_molecule); 00423 if(m==NULL) return; 00424 00425 mpos[0] = m->globt[0]; 00426 mpos[1] = m->globt[1]; 00427 mpos[2] = m->globt[2]; 00428 00429 if (grabs) { 00430 last_rot.inverse(); 00431 rot=*orientation(); 00432 rot.multmatrix(last_rot); 00433 p[0] = position()[0] - last_pos[0]; 00434 p[1] = position()[1] - last_pos[1]; 00435 p[2] = position()[2] - last_pos[2]; 00436 00437 // apply the translation due to translation of the tracker 00438 app->scene_translate_by(p[0], p[1], p[2]); 00439 // where the molecule will be after that command 00440 vec_add(futurepos,p,mpos); 00441 00442 // rotate the molecule about its center 00443 app->scene_rotate_by(rot.mat); 00444 00445 // compute the vector between the molecule and the tracker 00446 vec_sub(mdiff,futurepos,position()); 00447 // rotate that 00448 rot.multpoint3d(mdiff, mrotdiff); 00449 // and subtract 00450 vec_sub(mchange,mrotdiff,mdiff); 00451 00452 // giving us the translation for the molecule due to rotation 00453 app->scene_translate_by(mchange[0],mchange[1], mchange[2]); 00454 } else { 00455 int i; 00456 #ifdef VMDVRJUGGLER 00457 // VR Juggler: 00458 // do this through VMDApp, so the cmd is sent to the slaves as well 00459 for(i=0; i<app->moleculeList->num(); i++) { 00460 int id = app->moleculeList->molecule(i)->id(); 00461 app->molecule_fix(id, true); 00462 } 00463 int id = m->id(); 00464 app->molecule_fix(id, false); 00465 #else 00466 for(i=0; i<app->moleculeList->num(); i++) 00467 app->moleculeList->molecule(i)->fix(); 00468 m->unfix(); 00469 #endif 00470 } 00471 00472 last_rot = *orientation(); 00473 last_pos[0] = position()[0]; 00474 last_pos[1] = position()[1]; 00475 last_pos[2] = position()[2]; 00476 } 00477 00478 void Tool::ungrab() { 00479 int i; 00480 if (!targeted_molecule) 00481 targeted_molecule = -1; 00482 #ifdef VMDVRJUGGLER 00483 // VR Juggler: 00484 // do this through VMDApp, so the cmd is sent to the slaves as well 00485 for(i=0; i<app->moleculeList->num(); i++) { 00486 int id = app->moleculeList->molecule(i)->id(); 00487 app->molecule_fix(id, false); 00488 } 00489 #else 00490 for(i=0;i<app->moleculeList->num();i++) 00491 app->moleculeList->molecule(i)->unfix(); 00492 #endif 00493 } 00494 00495 float Tool::getTargetScale() { 00496 if (targeted_molecule != -1) { 00497 return app->moleculeList->mol_from_id(targeted_molecule)->scale; 00498 } 00499 return 0; 00500 } 00501 00502 int Tool::dimension() { 00503 if (tracker) return tracker->dimension(); 00504 return 0; 00505 } 00506 00507 void Tool::setplaneconstraint(float k, const float *p, const float *n) { 00508 float scaledpoint[3]; 00509 if (!feedback) return; 00510 if (!tracker) return; 00511 const float *offset = tracker->get_offset(); 00512 const float scale = tracker->get_scale(); 00513 scaledpoint[0] = p[0]/scale-offset[0]; 00514 scaledpoint[1] = p[1]/scale-offset[1]; 00515 scaledpoint[2] = p[2]/scale-offset[2]; 00516 feedback->zeroforce(); 00517 feedback->addplaneconstraint(springscale*k,scaledpoint,n); 00518 } 00519 00520 void Tool::addplaneconstraint(float k, const float *p, const float *n) { 00521 float scaledpoint[3]; 00522 if (!feedback) return; 00523 if (!tracker) return; 00524 const float *offset = tracker->get_offset(); 00525 const float scale = tracker->get_scale(); 00526 scaledpoint[0] = p[0]/scale-offset[0]; 00527 scaledpoint[1] = p[1]/scale-offset[1]; 00528 scaledpoint[2] = p[2]/scale-offset[2]; 00529 feedback->addplaneconstraint(springscale*k,scaledpoint,n); 00530 } 00531 00532 void Tool::setconstraint(float k, const float *p) { 00533 float scaledcenter[3]; 00534 if (!feedback) return; 00535 if (!tracker) return; 00536 const float *offset = tracker->get_offset(); 00537 const float scale = tracker->get_scale(); 00538 scaledcenter[0] = p[0]/scale-offset[0]; 00539 scaledcenter[1] = p[1]/scale-offset[1]; 00540 scaledcenter[2] = p[2]/scale-offset[2]; 00541 feedback->zeroforce(); 00542 feedback->addconstraint(springscale*k,scaledcenter); 00543 } 00544 00545 void Tool::setforcefield(const float *o, const float *force, 00546 const float *jacobian) { 00547 00548 float sforce[3]; 00549 float scaledjacobian[9]; 00550 int i; 00551 if (!tracker) return; 00552 if (!feedback) return; 00553 const float scale = tracker->get_scale(); 00554 for (i=0; i<3; i++) sforce[i] = force[i]*springscale; 00555 for(i=0;i<9;i++) scaledjacobian[i] = jacobian[i]*springscale/scale; 00556 feedback->zeroforce(); 00557 feedback->addforcefield(o, sforce, scaledjacobian); 00558 } 00559 00560 void Tool::sendforce() { 00561 if (tracker && feedback) feedback->sendforce(position()); 00562 } 00563 void Tool::forceoff() { 00564 if (feedback) feedback->forceoff(); 00565 } 00566