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