/** this conversion uses conventions as described on page: * https://www.euclideanspace.com/maths/geometry/rotations/euler/index.htm * Coordinate System: right hand * Positive angle: right hand * Order of euler angles: heading first, then attitude, then bank * matrix row column ordering: * [m00 m01 m02] * [m10 m11 m12] * [m20 m21 m22]*/ publicfinalvoidrotate(matrix m){ // Assuming the angles are in radians. if (m.m10 > 0.998) { // singularity at north pole heading = Math.atan2(m.m02,m.m22); attitude = Math.PI/2; bank = 0; return; } if (m.m10 < -0.998) { // singularity at south pole heading = Math.atan2(m.m02,m.m22); attitude = -Math.PI/2; bank = 0; return; } heading = Math.atan2(-m.m20,m.m00); bank = Math.atan2(-m.m12,m.m11); attitude = Math.asin(m.m10); }
轉成 opencv 的版本, 且對應到我的座標系 (x, z 對調), 最後 x y 軸還加上負號. bank(x) -> attitude(x) heading(y) -> heading(y) attitude(z) -> bank(z) euclideanspace -> 我的座標系(OpennGL)
Vec3f matrix2Euler(const Mat &R){ // Assuming the angles are in radians. float heading, attitude, bank; if (R.at<double>(1,0) > 0.998) { // singularity at north pole heading = atan2(R.at<double>(0,2),R.at<double>(2,2)); attitude = M_PI/2; bank = 0; return Vec3f(bank, heading, attitude); } if (R.at<double>(1,0) < -0.998) { // singularity at south pole heading = atan2(R.at<double>(0,2),R.at<double>(2,2)); attitude = -M_PI/2; bank = 0; return Vec3f(bank, heading, attitude); } heading = atan2(-R.at<double>(2,0),R.at<double>(0,0)); bank = atan2(-R.at<double>(1,2),R.at<double>(1,1)); attitude = asin(R.at<double>(1,0));
// Checks if a matrix is a valid rotation matrix. staticboolisRotationMatrix(const Mat &R) { Mat Rt; transpose(R, Rt); Mat shouldBeIdentity = Rt * R; Mat I = Mat::eye(3,3, shouldBeIdentity.type());
return norm(I, shouldBeIdentity) < 1e-6; }
/** rotation matrix to euler angles * Coordinate System: right hand * Positive angle: right hand * Order of euler angles: heading first, then attitude, then bank * matrix row column ordering: * [m00 m01 m02] * [m10 m11 m12] * [m20 m21 m22]*/ Vec3f matrix2Euler(const Mat &R) { assert(isRotationMatrix(R)); float sy = sqrt(R.at<double>(0,0) * R.at<double>(0,0) + R.at<double>(1,0) * R.at<double>(1,0) ); bool singular = sy < 1e-6; // If
float x, y, z; if (!singular) { x = atan2(R.at<double>(2,1) , R.at<double>(2,2)); y = atan2(-R.at<double>(2,0), sy); z = atan2(R.at<double>(1,0), R.at<double>(0,0)); } else { x = atan2(-R.at<double>(1,2), R.at<double>(1,1)); y = atan2(-R.at<double>(2,0), sy); z = 0; } return Vec3f(x, y, z); }
Vec3f matrix2Euler(const Mat &R) { assert(isRotationMatrix(R)); float sy = sqrt(R.at<double>(0,0) * R.at<double>(0,0) + R.at<double>(1,0) * R.at<double>(1,0) ); bool singular = sy < 1e-6; // If
float x, y, z; if (!singular) { x = atan2(R.at<double>(2,1) , R.at<double>(2,2)); y = atan2(-R.at<double>(2,0), sy); z = atan2(R.at<double>(1,0), R.at<double>(0,0)); } else { x = atan2(-R.at<double>(1,2), R.at<double>(1,1)); y = atan2(-R.at<double>(2,0), sy); z = 0; } return Vec3f(x, y, -z); }
libting - ting was started as a simple cross platform C++ wrapper for threading (thread, mutex, semaphore, message queue and message). But now ting is not only a threading library, now it is a utility framework containing also Network Sockets API library and some other useful stuff, e.g. reference counted pointers etc. See WiKi page for what is there. https://code.google.com/archive/p/ting/
clsocket - SimpleSockets is a lightweight set of classes that allow developers to implement IP based network programs. libsocket - The ultimate socket library for C and C++, supporting TCP, UDP and Unix sockets (DGRAM and STREAM) on Linux, FreeBSD, Solaris. Only ZMQ is better. Practical C++ Sockets