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_RotateTool.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.46 $ $Date: 2019年01月17日 21:21:01 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * This is Paul's new Tracker code -- pgrayson@ks.uiuc.edu 00019 * 00020 * 00021 ***************************************************************************/ 00022 00023 #ifdef VMDVRPN 00024 00025 #include <math.h> 00026 00027 #include "Matrix4.h" 00028 #include "quat.h" 00029 #include "utilities.h" 00030 #include "Displayable.h" 00031 #include "Command.h" 00032 #include "UIObject.h" 00033 #include "JString.h" 00034 00035 #include "P_Buttons.h" 00036 #include "P_Feedback.h" 00037 #include "P_Tracker.h" 00038 #include "P_Tool.h" 00039 #include "P_RotateTool.h" 00040 #include "P_UIVR.h" 00041 00042 int RotateTool::isgrabbing() { 00043 if(grab_toggle && constrained != -1) return 1; 00044 else return 0; 00045 } 00046 00047 RotateTool::RotateTool(int id, VMDApp *vmdapp, Displayable *disp) 00048 : Tool(id,vmdapp, disp) { 00049 grab_toggle = 0; 00050 button_was_down = 0; 00051 constrained = 0; 00052 } 00053 00054 void RotateTool::do_event() { 00055 int i,j; 00056 float newpos[3], point[3], normal[3], cpoint[3]; 00057 q_vec_type qpoint, qnormal, last_qpoint; 00058 q_type rot; 00059 q_matrix_type qmat; 00060 Matrix4 mat; 00061 00062 if(!wasgrabbing && isgrabbing()) { 00063 target(TARGET_GRAB, newpos, 0); 00064 } 00065 wasgrabbing = isgrabbing(); 00066 00067 if (orientation() == NULL) { 00068 return; 00069 } 00070 00071 if(button_was_down && !Tool::isgrabbing()) { 00072 grab_toggle = !grab_toggle; 00073 button_was_down = 0; 00074 } 00075 else if(!button_was_down && Tool::isgrabbing()) { 00076 button_was_down = 1; 00077 } 00078 00079 if(!constrained && (Tool::isgrabbing() || grab_toggle)) { 00080 q_make(qoffset,1,0,0,0); 00081 00082 // get the center of rotation 00083 if(!target(TARGET_GRAB, rotatecenter, 0)) { 00084 constrained = -1; 00085 return; 00086 } 00087 00088 // compute the radius of rotation 00089 rotateradius = distance(Tool::position(), rotatecenter); 00090 00091 // record the current position, direction and normal to the sphere 00092 for(i=0;i<dimension();i++) { 00093 old_pos[i] = Tool::position()[i]; 00094 old_normal[i] = old_pos[i]/rotateradius; 00095 qpoint[i] = (double)orientation()->mat[4*0+i]; 00096 qnormal[i] = -(double)old_normal[i]; 00097 } 00098 00099 // set up the starting position 00100 for(i=0;i<4;i++) for(j=0;j<4;j++) 00101 start.mat[4*i+j] = orientation()->mat[4*i+j]; 00102 00103 // and rotate it to be normal, just for show 00104 q_from_two_vecs(rot,qpoint,qnormal); 00105 q_to_row_matrix(qmat,rot); 00106 for(i=0;i<4;i++) for(j=0;j<4;j++) mat.mat[4*i+j]=(float) qmat[i][j]; 00107 mat.multmatrix(start); 00108 start=mat; 00109 00110 // set this flag last so it doesn't affect orientation computations 00111 constrained=1; 00112 } 00113 else if(constrained && !(Tool::isgrabbing() || grab_toggle)){ 00114 let_go(); 00115 constrained=0; 00116 forceoff(); 00117 } 00118 00119 if(constrained == 1) { 00120 float dist; 00121 // set up the position we are reporting 00122 dist = distance(Tool::position(),rotatecenter) / rotateradius; 00123 for(i=0;i<dimension();i++) { 00124 constrainedpos[i] = rotatecenter[i] + 00125 (Tool::position()[i] - rotatecenter[i])/dist; 00126 } 00127 00128 // constrain the position to a plane 00129 vec_sub(normal,Tool::position(),rotatecenter); 00130 vec_normalize(normal); 00131 vec_scale(cpoint,rotateradius,normal); 00132 vec_add(point,rotatecenter,cpoint); 00133 setplaneconstraint(100,point,normal); 00134 00135 // now add detentes (!) 00136 for(i=0;i<3;i++) { 00137 dist = (constrainedpos[i] - rotatecenter[i])/rotateradius; 00138 if(dist < 0.1 && dist > -0.1) { 00139 float normal[3]={0,0,0}; 00140 normal[i]=1; 00141 addplaneconstraint(100,rotatecenter,normal); 00142 } 00143 } 00144 00145 sendforce(); 00146 00147 // compute the difference between the old normal and the new; 00148 // rotate the offset matrix by this amount. 00149 for(i=0;i<dimension();i++) { 00150 qpoint[i] = normal[i]; 00151 last_qpoint[i] = old_normal[i]; 00152 old_normal[i] = normal[i]; 00153 } 00154 q_from_two_vecs(rot,last_qpoint,qpoint); 00155 q_mult(qoffset,rot,qoffset); 00156 q_to_row_matrix(qmat,qoffset); 00157 for(i=0;i<4;i++) { 00158 for(j=0;j<4;j++) { 00159 mat.mat[4*i+j]=(float) qmat[i][j]; 00160 } 00161 } 00162 offset = mat; 00163 } 00164 } 00165 00166 const float *RotateTool::position() const { 00167 const float *newpos = Tool::position(); 00168 if(constrained != 1) return newpos; 00169 return constrainedpos; 00170 } 00171 00172 const Matrix4 *RotateTool::orientation() { 00173 if(constrained != 1) { 00174 return Tool::orientation(); 00175 } 00176 product = offset; 00177 product.multmatrix(start); 00178 return &product; 00179 } 00180 00181 #endif