00001
00016 #include <cmath>
00017 #include <dlrCommon/functional.h>
00018 #include <dlrNumeric/rotations.h>
00019 #include <dlrNumeric/utilities.h>
00020
00021 namespace {
00022
00023 const double rotationsEpsilon_ = 1.0E-10;
00024
00025 }
00026
00027 namespace dlr {
00028
00029 namespace numeric {
00030
00031 Quaternion
00032 angleAxisToQuaternion(double angle, const Vector3D& axis, bool isNormalized)
00033 {
00034
00035 double angleOverTwo = angle / 2.0;
00036 double cosineValue = std::cos(angleOverTwo);
00037 double sineValue = std::sin(angleOverTwo);
00038
00039
00040 if(isNormalized) {
00041 return Quaternion(cosineValue, sineValue * axis.x(),
00042 sineValue * axis.y(), sineValue * axis.z());
00043 }
00044
00045
00046 Vector3D axisCopy = axis;
00047 double axisMagnitude = magnitude(axis);
00048 if(axisMagnitude != 0.0) {
00049 axisCopy /= axisMagnitude;
00050 } else {
00051
00052 axisCopy.setValue(1.0, 0.0, 0.0);
00053 }
00054 return Quaternion(cosineValue, sineValue * axisCopy.x(),
00055 sineValue * axisCopy.y(), sineValue * axisCopy.z());
00056 }
00057
00058
00059 Vector3D
00060 angleAxisToRollPitchYaw(double angle, const Vector3D& axis,
00061 bool isNormalized)
00062 {
00063 Quaternion quaternion = angleAxisToQuaternion(angle, axis, isNormalized);
00064 return quaternionToRollPitchYaw(quaternion);
00065 }
00066
00067
00068 Transform3D
00069 angleAxisToTransform3D(double angle, const Vector3D& axis, bool isNormalized)
00070 {
00071 Quaternion quaternion = angleAxisToQuaternion(angle, axis, isNormalized);
00072 return quaternionToTransform3D(quaternion);
00073 }
00074
00075
00076 std::pair<double, Vector3D>
00077 quaternionToAngleAxis(const Quaternion& quaternion)
00078 {
00079
00080 Quaternion quaternionCopy(quaternion);
00081 quaternionCopy.normalize();
00082
00083
00084 double cosineHalfTheta = quaternionCopy.s();
00085 Vector3D sineTimesAxis(
00086 quaternionCopy.i(), quaternionCopy.j(), quaternionCopy.k());
00087 double sineHalfTheta = magnitude(sineTimesAxis);
00088
00089
00090 double angle = 2 * std::atan2(sineHalfTheta, cosineHalfTheta);
00091 if(sineHalfTheta == 0.0) {
00092 return std::make_pair(angle, Vector3D(1.0, 0.0, 0.0));
00093 }
00094 return std::make_pair(angle, sineTimesAxis / sineHalfTheta);
00095 }
00096
00097
00098 Vector3D
00099 quaternionToRollPitchYaw(const Quaternion& quaternion)
00100 {
00101
00102 Transform3D transform3D = quaternionToTransform3D(quaternion);
00103 return transform3DToRollPitchYaw(transform3D);
00104 }
00105
00106
00107 Transform3D
00108 quaternionToTransform3D(const Quaternion& quaternion)
00109 {
00110
00111 Quaternion quaternionCopy(quaternion);
00112 quaternionCopy.normalize();
00113
00114
00115 double ii = 2.0 * quaternionCopy.i() * quaternionCopy.i();
00116 double jj = 2.0 * quaternionCopy.j() * quaternionCopy.j();
00117 double kk = 2.0 * quaternionCopy.k() * quaternionCopy.k();
00118 double si = 2.0 * quaternionCopy.s() * quaternionCopy.i();
00119 double sj = 2.0 * quaternionCopy.s() * quaternionCopy.j();
00120 double sk = 2.0 * quaternionCopy.s() * quaternionCopy.k();
00121 double ij = 2.0 * quaternionCopy.i() * quaternionCopy.j();
00122 double ik = 2.0 * quaternionCopy.i() * quaternionCopy.k();
00123 double jk = 2.0 * quaternionCopy.j() * quaternionCopy.k();
00124
00125 return Transform3D(1 - jj - kk, ij - sk, ik + sj, 0.0,
00126 ij + sk, 1 - ii - kk, jk - si, 0.0,
00127 ik - sj, jk + si, 1 - ii - jj, 0.0,
00128 0.0, 0.0, 0.0, 1);
00129 }
00130
00131
00132 std::pair<double, Vector3D>
00133 rollPitchYawToAngleAxis(const Vector3D& rollPitchYaw)
00134 {
00135 Quaternion quaternion = rollPitchYawToQuaternion(rollPitchYaw);
00136 return quaternionToAngleAxis(quaternion);
00137 }
00138
00139
00140 Quaternion
00141 rollPitchYawToQuaternion(const Vector3D& rollPitchYaw)
00142 {
00143 Transform3D transform3D = rollPitchYawToTransform3D(rollPitchYaw);
00144 return transform3DToQuaternion(transform3D);
00145 }
00146
00147
00148 Transform3D
00149 rollPitchYawToTransform3D(const Vector3D& rollPitchYaw)
00150 {
00151
00152 double cosineRoll = std::cos(rollPitchYaw.x());
00153 double cosinePitch = std::cos(rollPitchYaw.y());
00154 double cosineYaw = std::cos(rollPitchYaw.z());
00155
00156 double sineRoll = std::sin(rollPitchYaw.x());
00157 double sinePitch = std::sin(rollPitchYaw.y());
00158 double sineYaw = std::sin(rollPitchYaw.z());
00159
00160
00161
00162 Transform3D rollTransform(1.0, 0.0, 0.0, 0.0,
00163 0.0, cosineRoll, -sineRoll, 0.0,
00164 0.0, sineRoll, cosineRoll, 0.0,
00165 0.0, 0.0, 0.0, 1.0);
00166 Transform3D pitchTransform(cosinePitch, 0.0, sinePitch, 0.0,
00167 0.0, 1.0, 0.0, 0.0,
00168 -sinePitch, 0.0, cosinePitch, 0.0,
00169 0.0, 0.0, 0.0, 1.0);
00170 Transform3D yawTransform(cosineYaw, -sineYaw, 0.0, 0.0,
00171 sineYaw, cosineYaw, 0.0, 0.0,
00172 0.0, 0.0, 1.0, 0.0,
00173 0.0, 0.0, 0.0, 1.0);
00174
00175
00176 return rollTransform * (pitchTransform * yawTransform);
00177 }
00178
00179
00180 std::pair<double, Vector3D>
00181 transform3DToAngleAxis(const Transform3D& transform3D)
00182 {
00183 Quaternion quaternion = transform3DToQuaternion(transform3D);
00184 return quaternionToAngleAxis(quaternion);
00185 }
00186
00187
00188
00189
00190
00191 Quaternion
00192 transform3DToQuaternion(const Transform3D& transform3D)
00193 {
00194
00195
00196 double t00 = transform3D.value<0, 0>();
00197 double t01 = transform3D.value<0, 1>();
00198 double t02 = transform3D.value<0, 2>();
00199 double t10 = transform3D.value<1, 0>();
00200 double t11 = transform3D.value<1, 1>();
00201 double t12 = transform3D.value<1, 2>();
00202 double t20 = transform3D.value<2, 0>();
00203 double t21 = transform3D.value<2, 1>();
00204 double t22 = transform3D.value<2, 2>();
00205
00206
00207 double sSquaredTimesFour = (1.0 + t00 + t11 + t22);
00208
00209 if(sSquaredTimesFour < 0.0) {
00210 sSquaredTimesFour = 0.0;
00211 }
00212 double sValue = std::sqrt(sSquaredTimesFour) / 2.0;
00213
00214 if(sValue > 1.0) {
00215 sValue = 1.0;
00216 }
00217
00218
00219
00220
00221 Vector3D axis0(t21 - t12, t02 - t20, t10 - t01);
00222
00223
00224
00225 int axisOfLargestRotation = 0;
00226 if(t00 > t11) {
00227 if(t00 > t22) {
00228 axisOfLargestRotation = 0;
00229 } else {
00230 axisOfLargestRotation = 2;
00231 }
00232 } else {
00233 if(t11 > t22) {
00234 axisOfLargestRotation = 1;
00235 } else {
00236 axisOfLargestRotation = 2;
00237 }
00238 }
00239
00240
00241 if(axisOfLargestRotation == 0) {
00242 Vector3D axis1(1.0 + t00 - t11 - t22, t10 + t01, t20 + t02);
00243 if(axis0.x() >= 0) {
00244 axis0 += axis1;
00245 } else {
00246 axis0 -= axis1;
00247 }
00248 } else if(axisOfLargestRotation == 1) {
00249 Vector3D axis1(t10 + t01, 1.0 + t11 - t00 - t22, t21 + t12);
00250 if(axis0.y() >= 0) {
00251 axis0 += axis1;
00252 } else {
00253 axis0 -= axis1;
00254 }
00255 } else if(axisOfLargestRotation == 2) {
00256 Vector3D axis1(t20 + t02, t21 + t12, 1.0 + t22 - t00 - t11);
00257 if(axis0.z() >= 0) {
00258 axis0 += axis1;
00259 } else {
00260 axis0 -= axis1;
00261 }
00262 }
00263
00264
00265 double axisMagnitudeSquared = dot(axis0, axis0);
00266 if(approximatelyEqual(axisMagnitudeSquared, 0.0, rotationsEpsilon_)) {
00267
00268
00269 if(sValue >= 0) {
00270 return Quaternion(1.0, 0.0, 0.0, 0.0);
00271 } else {
00272 return Quaternion(-1.0, 0.0, 0.0, 0.0);
00273 }
00274 }
00275 axis0 *= std::sqrt((1 - (sValue * sValue)) / axisMagnitudeSquared);
00276
00277
00278 return Quaternion( sValue, axis0.x(), axis0.y(), axis0.z());
00279 }
00280
00281
00282 Vector3D
00283 transform3DToRollPitchYaw(const Transform3D& transform3D)
00284 {
00285
00286 const double piOverTwo = 1.57079632679;
00287
00288
00289 double sinePitch = transform3D.value<0, 2>();
00290 double cosinePitch = std::sqrt(
00291 transform3D.value<0, 0>() * transform3D.value<0, 0>()
00292 + transform3D.value<0, 1>() * transform3D.value<0, 1>());
00293 double pitch = std::atan2(sinePitch, cosinePitch);
00294
00295
00296 double roll;
00297 double yaw;
00298 if((!approximatelyEqual(pitch, piOverTwo, rotationsEpsilon_))
00299 && (!approximatelyEqual(pitch, -piOverTwo, rotationsEpsilon_))) {
00300 double cosinePitch = std::cos(pitch);
00301 roll = std::atan2(-(transform3D.value<1, 2>() / cosinePitch),
00302 (transform3D.value<2, 2>() / cosinePitch));
00303 yaw = std::atan2(-(transform3D.value<0, 1>() / cosinePitch),
00304 (transform3D.value<0, 0>() / cosinePitch));
00305 } else {
00306 roll = std::atan2(transform3D.value<2, 1>(),
00307 transform3D.value<1, 1>());
00308 yaw = 0.0;
00309 }
00310 return Vector3D(roll, pitch, yaw);
00311 }
00312
00313
00314 }
00315
00316 }