00001 00005 /* Copyright © 2009, 2010 James Legg. 00006 This program is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 */ 00011 00012 #include <RotationHandle.h> 00013 00014 #include <cmath> 00015 00016 #include <GL/gl.h> 00017 00018 namespace Track 00019 { 00020 00021 namespace EditAssist 00022 { 00023 00024 void RotationHandle::snap(btVector3 & proposed_position, btVector3 normal) const 00025 { 00026 // first, find screen space length from centre to proposed position. 00027 btVector3 proposed_vector = (proposed_position - centre); 00028 btScalar proposed_length2 = proposed_vector.length2(); 00029 // height above the plane going through centre with normal normal. 00030 btScalar plane_height = proposed_vector.dot(normal); 00031 // use pythagoras' theorem to find square of length across plane. 00032 btScalar screen_length2 = proposed_length2 - plane_height * plane_height; 00033 // Too long? 00034 if (screen_length2 >= length * length) 00035 { 00036 // make perpendicular to normal. 00037 btVector3 new_vector = normal.cross(proposed_vector.cross(normal)); 00038 if (proposed_position.length2() > 0.0) 00039 { 00040 // We've made a vector in a valid direction, use it. 00041 proposed_vector = new_vector; 00042 } 00043 proposed_vector.normalize(); 00044 proposed_vector *= length; 00045 proposed_position = proposed_vector + centre; 00046 } 00047 else // Too short. 00048 { 00049 // Only change the position along the direction of normal. 00050 // There will be two valid position along this line, we pick the 00051 // farthest one in the direction of the normal. 00052 00053 // To calculate the distance to the sphere we need to change the 00054 // vector's basis to a orthonormal basis where one of the components 00055 // is in the direction of the normal. We can then replace this 00056 // component with the distance to the sphere, having calculated where 00057 // it is in the other two directions. 00058 00059 // For example, let the basis B be contain vectors S, T, normal. 00060 // If proposed_vector can be expressed as s * S + t * T + n * normal 00061 // then we replace n with sqrt(length * length - s * s - t* t). 00062 // Then we convert the vector back to the standard basis. 00063 00064 // Find basis S, T, normal: 00065 btVector3 S = normal.cross(btVector3(0.0, 0.0, 1.0)); 00066 if (S.length2() < 0.25) 00067 { 00068 // Try another direction for numerical stablility. 00069 S = normal.cross(btVector3(0.0, 1.0, 0.0)); 00070 } 00071 btVector3 T = normal.cross(S); 00072 T.normalize(); 00073 S = T.cross(normal); 00074 // Find the change of basis coordinates of proposed_vector in S & T. 00075 btScalar s = proposed_vector.dot(S); 00076 btScalar t = proposed_vector.dot(T); 00077 // find ideal distance 00078 btScalar n = std::sqrt(length * length - s * s - t * t); 00079 // now convert back into the standard basis. 00080 proposed_vector = s * S + t * T + n * normal; 00081 proposed_position = centre + proposed_vector; 00082 } 00083 } 00084 00085 void RotationHandle::draw() const 00086 { 00087 // line to handle 00088 glBegin(GL_LINES); 00089 glVertex3f(centre.x(), centre.y(), centre.z()); 00090 glVertex3f(position.x(), position.y(), position.z()); 00091 glEnd(); 00092 00093 // blob on the end. 00094 glBegin(GL_POINTS); 00095 glVertex3f(position.x(), position.y(), position.z()); 00096 glEnd(); 00097 00098 glPushMatrix(); 00099 glTranslatef(position.x(), position.y(), position.z()); 00100 btScalar scale = position.distance(centre); 00101 glScalef(scale, scale, scale); 00102 btVector3 difference = (position - centre).normalized(); 00103 btVector3 cross = difference.cross(btVector3(0.0, 0.0, 1.0)).cross(difference).normalized(); 00104 btVector3 other = cross.cross(difference); 00105 GLfloat mat[16] = {cross.x(), cross.y(), cross.z(), 0, 00106 other.x(), other.y(), other.z(), 0, 00107 difference.x(), difference.y(), difference.z(), 0, 00108 0, 0, 0, 1}; 00109 glMultMatrixf(mat); 00110 float angles[12]; 00111 for (int i = 0; i < 12; i++) 00112 { 00113 angles[i] = -0.392699082 + (float (i)) * 0.065449847; 00114 } 00115 glBegin(GL_LINE_STRIP); 00116 for (int i = 0; i < 12; i++) 00117 { 00118 const float & angle = angles[i]; 00119 glVertex3f(std::sin(angle), 0.0, std::cos(angle) - 1.0); 00120 } 00121 glEnd(); 00122 glBegin(GL_LINE_STRIP); 00123 for (int i = 0; i < 12; i++) 00124 { 00125 const float & angle = angles[i]; 00126 glVertex3f(0.0, std::sin(angle), std::cos(angle) - 1.0); 00127 } 00128 glEnd(); 00129 glPopMatrix(); 00130 } 00131 00132 void RotationHandle::set_length(btScalar new_length) 00133 { 00134 length = new_length; 00135 } 00136 00137 void RotationHandle::set_centre(btVector3 new_centre) 00138 { 00139 centre = new_centre; 00140 } 00141 00142 } 00143 00144 }
Generated at Mon Sep 6 00:41:11 2010 by Doxygen version 1.4.7 for Racer version svn335.