00001 00005 /* Copyright © 2009 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 #include "VertexRotationHandle.h" 00012 00013 #include <cmath> 00014 00015 #include <GL/gl.h> 00016 00017 #include <LinearMath/btQuaternion.h> 00018 00019 #include "../path/Path.h" 00020 #include "../document/RotateVertexDelta.h" 00021 00022 #include <Debug.h> 00023 00024 namespace Track 00025 { 00026 00027 namespace EditAssist 00028 { 00029 00030 00031 VertexRotationHandle::VertexRotationHandle(std::size_t vertex_id, Direction direction) 00032 : vertex_id(vertex_id) 00033 , direction (direction) 00034 { 00035 length = 1.0; 00036 } 00037 00038 boost::shared_ptr<Document::DocumentDelta> VertexRotationHandle::make_delta(btVector3 new_position) const 00039 { 00040 /* Find an angle with minimal difference to the last one that fits the new 00041 * position. 00042 */ 00043 btVector3 new_vector = (new_position - centre) / length; 00044 btVector3 old_vector = (position - centre) / length; 00045 btVector3 cross = old_vector.cross(new_vector); 00046 bool obtuse = (new_vector + old_vector).length2() < 2; 00047 btScalar sin_angle = cross.length(); 00048 00049 // some floating point rounding fixes: 00050 if (std::fabs(sin_angle) < 0.002) 00051 { 00052 if (!obtuse) 00053 { 00054 DEBUG_MESSAGE("Rotation too small, ignoring."); 00055 // Didn't rotate very far. 00056 // Vector is very short: just act as if there was no rotation to 00057 // avoid problems normalising it. 00058 return boost::shared_ptr<Document::DocumentDelta> 00059 ( 00060 new Document::RotateVertexDelta 00061 ( 00062 Document::VertexAngleFinder(vertex_id), 00063 rotation 00064 ) 00065 ); 00066 } 00067 else 00068 { 00069 // We can't rely on the direction we are rotating about, but 00070 // need to rotate about 180 degrees. Guess a direction. 00071 DEBUG_MESSAGE("Rotation too close to 180 degrees, guessing direction."); 00072 return boost::shared_ptr<Document::DocumentDelta> 00073 ( 00074 new Document::RotateVertexDelta 00075 ( 00076 Document::VertexAngleFinder(vertex_id), 00078 rotation * btQuaternion(btVector3(0, 0, 1), M_PI) 00079 ) 00080 ); 00081 } 00082 } 00083 // sin_angle might be just outside the valid range. 00084 if (sin_angle > 1.0) sin_angle = 1.0; 00085 00086 btScalar angle = std::asin(sin_angle); 00087 if (obtuse) 00088 { 00089 angle = M_PI - angle; 00090 } 00091 00092 cross.normalize(); 00093 btQuaternion rotation_difference(cross, angle); 00094 btQuaternion new_angle(rotation_difference * rotation); 00095 00096 return boost::shared_ptr<Document::DocumentDelta> 00097 ( 00098 new Document::RotateVertexDelta 00099 ( 00100 Document::VertexAngleFinder(vertex_id), 00101 new_angle 00102 ) 00103 ); 00104 } 00105 00106 void VertexRotationHandle::update_angle(btQuaternion angle_in) 00107 { 00108 /* The position is centre position + the a vector in the direction the 00109 * handle indicates with the requested length. 00110 */ 00111 rotation = angle_in; 00112 position = centre + length * 00113 btTransform(angle_in)(direction == DIR_FORWARD ? btVector3(0, 1, 0) : btVector3(0, 0, 1)); 00114 } 00115 00116 void VertexRotationHandle::draw() const 00117 { 00118 switch (direction) 00119 { 00120 case DIR_FORWARD: 00121 glColor3ub(0, 255, 0); 00122 break; 00123 case DIR_UP: 00124 glColor3ub(255, 0, 0); 00125 break; 00126 } 00127 RotationHandle::draw(); 00128 } 00129 00130 } 00131 00132 } 00133
Generated at Mon Sep 6 00:41:11 2010 by Doxygen version 1.4.7 for Racer version svn335.