RotationHandle.cpp

Go to the documentation of this file.
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 }

Get Racer at SourceForge.net. Fast, secure and Free Open Source software downloads

Generated at Mon Sep 6 00:41:11 2010 by Doxygen version 1.4.7 for Racer version svn335.