00001 // Frame.cc - a coordinate system. 00002 // 00003 // Copyright (C) 2001--2004 Sam Varner 00004 // 00005 // This file is part of Vamos Automotive Simulator. 00006 // 00007 // This program is free software; you can redistribute it and/or modify 00008 // it under the terms of the GNU General Public License as published by 00009 // the Free Software Foundation; either version 2 of the License, or 00010 // (at your option) any later version. 00011 // 00012 // This program is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 // 00017 // You should have received a copy of the GNU General Public License 00018 // along with this program; if not, write to the Free Software 00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 00021 #include <vamos/body/Frame.h> 00022 #include <vamos/geometry/Conversions.h> 00023 00024 #include <cassert> 00025 #include <cmath> 00026 00027 using Vamos_Geometry::Three_Vector; 00028 using Vamos_Geometry::Three_Matrix; 00029 00030 //* Class Frame 00031 00032 //** Constructors 00033 00034 // Specify the position and orientation. 00035 Vamos_Body::Frame:: 00036 Frame (const Three_Vector& position, const Three_Matrix& orientation) : 00037 m_position (position), 00038 m_orientation (orientation) 00039 { 00040 } 00041 00042 // Take the parent's orientation. 00043 Vamos_Body::Frame:: 00044 Frame (const Three_Vector& position) : 00045 m_position (position) 00046 { 00047 m_orientation.identity (); 00048 } 00049 00050 // Make a frame that's coincident with the parent frame. 00051 Vamos_Body::Frame:: 00052 Frame () 00053 { 00054 m_orientation.identity (); 00055 } 00056 00057 // VEC is a vector in the parent's frame. The representation of VEC 00058 // in this frame is returned. 00059 Three_Vector Vamos_Body::Frame:: 00060 transform_in (const Three_Vector& vec) const 00061 { 00062 return rotate_in (vec - m_position); 00063 } 00064 00065 // VEC is a vector in this frame. The representation of VEC in the 00066 // parent's frame is returned. 00067 Three_Vector Vamos_Body::Frame:: 00068 transform_out (const Three_Vector& vec) const 00069 { 00070 return rotate_out (vec) + m_position; 00071 } 00072 00073 // Same as transform_out (VEC) above, except that the rotation is 00074 // about the point PIVOT expressed in this frame's coordinates. 00075 Three_Vector Vamos_Body::Frame:: 00076 transform_out (const Three_Vector& vec, const Three_Vector& pivot) const 00077 { 00078 return rotate_out (vec - pivot) + m_position; 00079 } 00080 00081 // Rotate the frame about the vector delta_theta, by an angle equal to 00082 // the magnitude of DELTA_THETA. 00083 void Vamos_Body::Frame:: 00084 rotate (const Three_Vector& delta_theta) 00085 { 00086 m_orientation.rotate (delta_theta); 00087 } 00088 00089 // Express the orientation of this frame as a vector in the parent 00090 // frame and a rotation about that vector. ANGLE holds the rotation 00091 // angle when the function returns. The returned vector has a 00092 // magnitude of sin (ANGLE). The values returned are suitable for use 00093 // with the glRotate functions. 00094 Three_Vector Vamos_Body::Frame:: 00095 axis_angle (double* angle) const 00096 { 00097 // To convert the rotation matrix representation of the body's orientation 00098 // to an axis-angle orientation, we transform first to a quaternion 00099 // representation. The matrix-to-quaternion and quaternion-to-axis-angle 00100 // transformations are described in the Matrix and Quaternion FAQ 00101 // (matrixfaq.htm) in the doc directory. 00102 00103 // Make a local reference to the tranformation matrix for brevity. 00104 const Three_Matrix& omat = m_orientation; 00105 00106 // Convert from matrix to quaternion 00107 double trace = omat [0][0] + omat [1][1] + omat [2][2] + 1.0; 00108 double s, w, x, y, z; 00109 s = w = x = y = z = 0.0; 00110 if (trace > 0.0) 00111 { 00112 s = 0.5 / sqrt (trace); 00113 w = 0.25 / s; 00114 x = (omat [2][1] - omat [1][2]) * s; 00115 y = (omat [0][2] - omat [2][0]) * s; 00116 z = (omat [1][0] - omat [0][1]) * s; 00117 } 00118 else 00119 { 00120 // Find the largest diagonal element and do the appropriate 00121 // transformation. 00122 double largest = omat [0][0]; 00123 int index = 0; 00124 if (omat [1][1] > largest) 00125 { 00126 largest = omat [1][1]; 00127 index = 1; 00128 } 00129 00130 if (omat [2][2] > largest) 00131 { 00132 largest = omat [2][2]; 00133 s = sqrt (1.0 - omat [0][0] - omat [1][1] + omat [2][2]) * 2.0; 00134 w = (omat [0][1] + omat [1][0]) / s; 00135 x = (omat [0][2] + omat [2][0]) / s; 00136 y = (omat [1][2] + omat [2][1]) / s; 00137 z = 0.5 / s; 00138 } 00139 else if (index == 0) 00140 { 00141 s = sqrt (1.0 + omat [0][0] - omat [1][1] - omat [2][2]) * 2.0; 00142 w = (omat [1][2] + omat [2][1]) / s; 00143 x = 0.5 / s; 00144 y = (omat [0][1] + omat [1][0]) / s; 00145 z = (omat [0][2] + omat [2][0]) / s; 00146 } 00147 else 00148 { 00149 assert (index == 1); 00150 s = sqrt (1.0 - omat [0][0] + omat [1][1] - omat [2][2]) * 2.0; 00151 w = (omat [0][2] + omat [2][0]) / s; 00152 x = (omat [0][1] + omat [1][0]) / s; 00153 y = 0.5 / s; 00154 z = (omat [1][2] + omat [2][1]) / s; 00155 } 00156 } 00157 00158 // Convert from quaternion to angle-axis. 00159 *angle = Vamos_Geometry::rad_to_deg (acos (w) * 2.0); 00160 00161 // The return value would be divided by sin (angle) to give a unit 00162 // vector, but glRotate* () does not care about the length so we'll 00163 // leave it as is. 00164 return Three_Vector (x, y, z); 00165 }
1.4.6