Rotating a vector around an axis with quaternion - c++

I am trying to learn 3d programming, and right now I am trying to understand how to use quaternions to rotate a vector around an axis.
As far as I understand, to rotate a vector v around an axis a, after converting both vectors to quaternions, we multiply v by a, then the product by the conjugate of a.
I want to rotate v(0,1,0) around a(1,0,0) by 90 degrees, and I should get a resulting vector v(0,0,1) (or 0,0,-1, depending on the direction of the rotation).
I am not getting the output I am expecting.
Here is the code:
int main()
{
//I want to rotate this vector about the x axis by PI/2 radians:
Quaternion v(0, 1, 0, 0);
v.normalize();
float angle = PI / 2.0f;
float cos = math::cos(angle / 2.0f);
float sin = math::sin(angle / 2.0f);
Quaternion q(1.0f*sin, 0.0f*sin, 0.0f*sin, cos);
std::cout << "q not normalized = " <<"\t"<< q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
q.normalize();
std::cout << "q normalized = " <<"\t\t"<< q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
std::cout << std::endl;
Quaternion r;
//I multiply the vector v by the quaternion v, then I multiply by the conjugate.
r = q * v;
//do I need to normalize here?
r = r * q.conjugate();
//and here?
//shouldn't the resulting vector be 0,0,1?
std::cout << "r not normalized = " << "\t" << r.x << " " << r.y << " " << r.z << " " << r.w << std::endl;
r.normalize();
std::cout << "r normalized = " << "\t\t" << r.x << " " << r.y << " " << r.z << " " << r.w << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
and here is the output:
q not normalized, which is same as q normalized:
x = 0.707107, y = 0, z = 0, w = 0.707107
r not normalized:
x = 0.707107, y = 0, z = 1, w = -2.12132
r normalized:
x = 0.288675, y = 0, z = 0.408248, w = -0.866025
what am I doing wrong?
did I even understand anything from this process?

Basically to rotate an vector along x axis (1,0,0) with angle 90 deg, use below method, this works for both Euler and quaternion
| 1 0 0 | | 0 | | 0 |
| 0 cos90 -sin90 | * | 1 | = | 0 |
| 0 sin90 cos90 | | 0 | | 1 |
Read about rotation matrices http://en.wikipedia.org/wiki/Rotation_matrix

Related

What is the expected rotation direction when using glm's rotate function?

I'm writing a static function that uses GLM's rotate() function to rotate a vector about an arbitrary axis.
I wrote a simple test to check my work, and I found that the rotations occur in the opposite direction than what I expected.
I rotate a unit vector (0,0,1) about the X axis (1,0,0) in steps of pi/4. I expected that since OpenGL (and GLM?) use a right-handed coordinate system, the rotations would occur in a counter-clockwise direction about the X axis. Instead, they're occurring in clockwise direction.
vec3& RotateVector(vec3& targetVector, float const& radians, vec3 const &axis)
{
mat4 rotation = glm::rotate(mat4(1.0f), radians, axis);
targetVector = (vec4(targetVector, 0.0f) * rotation).xyz();
return targetVector;
}
vec3 test(0, 0, 1);
cout << "test initial vals: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14f / 4.0f, vec3(1, 0, 0) );
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 /4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
When I run the code above, I get the following output:
test initial vals: 0 0 1
Rotated test: 0 0.706825 0.707388
Rotated test: 0 1 0.000796229
Rotated test: 0 0.707951 -0.706262
Rotated test: 0 0.00159246 -0.999999
The output shows that the rotation is moving clockwise about the X axis.
Why is that? I'd expect that OpenGL's right handed coordinate system would adhere to the right hand rule? Am I missing something, or am I just confused?
You're using the matrices transposed, and since rotation matrices are orthogonal matrices, this has the effect of using the inverse of those matrices: R^-1 = R^T.
glm mimics classic GL conventions with mat4 * vec4 multiplication order, where vec4 is a column vector.
When you write vec4 * mat4, vec4 is interpreted as row vector, and since (A*B)^T = B^T * A^T, you get the same result as transpose(mat4) * vec4.

Why are the matrices not initialized/printed correctly?

I am playing around with cv::Mat and think my code really behaves weird, although I follow the syntax described in here.
Code:
std::cout << "parameter for matrices: " << "x = " << X << " y = " << Y << " psi = " << Psi << std::endl;
double dataRot[] = { cos(Psi), -sin(Psi), sin(Psi), cos(Psi) };
double dataTrans[] = { X, Y };
cv::Mat matRot(2, 2, CV_32FC1, dataRot);
cv::Mat matTrans(2, 1, CV_32FC1, dataTrans);
std::cout << "matRot = " << matRot.at<double>(0,0) << "," << matRot.at<double>(0,1) << ";" << matRot.at<double>(1,0) << "," << matRot.at<double>(1,1) << std::endl;
std::cout << "matRot = " << matRot << std::endl;
std::cout << "matTrans = " << matTrans.at<double>(0,0) << "," << matTrans.at<double>(0,1) << std::endl;
std::cout << "matTrans = " << matTrans << std::endl;
matOut = matRot*matIn + matTrans*cv::Mat::ones(1, matIn.cols, CV_32FC1);
Output:
parameter for matrices: x = 20.5 y = 20 psi = 0
matRot = 1,-0;-0,0
matRot = [0, 1.875;
0, -0]
matTrans = 20.5,20
matTrans = [0; 2.8203125]
Why is the identity matrix not initalized correctly?
And why does the second way of printing a matrix deliver wrong results?
Any help is appreciated.
Since you're working with double, the OpenCV matrix type should be CV_64FC1:
cv::Mat matRot(2, 2, CV_64FC1, dataRot);
cv::Mat matTrans(2, 1, CV_64FC1, dataTrans);
For simplicity, you can also use:
cv::Matx22d matRot(cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Matx21d matTrans(X, Y);
or:
cv::Mat1d matRot = (cv::Mat1d(2,2) << cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Mat1d matTrans = (cv::Mat1d(2,1) << X, Y);
and access values like:
std::cout << matRot(row, col);

Relation between QTransform scale and boundingRect.size()

I have little concern about what is relation between QTransform scale and width and height return values in boundingRect() method of QGraphicsItem.
Actually I want to scale QGraphicsItem as its boundingRect size. i.e. if size of my item initially 100,100 that I am passing in boundingRect() method after that I am increasing the size of item by mousemove event. If my increased width and height is 400,300 respectively is my scale factors 4,3?
Any help will be appreciable.
This is code
this->setPos(minMax().first.x(), minMax().first.y());
qreal w = minMax().second.x() - minMax().first.x();
qreal h = minMax().second.y() - minMax().first.y();
qreal scaleFactorW = w / boundingRect().width();
qreal scaleFactorH = h / boundingRect().height();
QTransform trans;
trans.scale(scaleFactorW, scaleFactorH);
setTransform(trans);
bottomPoints = QPointF(w, h);
minMax function is:
float xMin = 0, xMax = 0, yMin = 0, yMax = 0;
QList<double> xValues, yValues;
xValues << shaper[0]->scenePos().x() << shaper[1]->scenePos().x() << shaper[2]->scenePos().x() << shaper[3]->scenePos().x() << shaper[4]->scenePos().x() << shaper[5]->scenePos().x() << shaper[6]->scenePos().x() << shaper[7]->scenePos().x();
yValues << shaper[0]->scenePos().y() << shaper[1]->scenePos().y() << shaper[2]->scenePos().y() << shaper[3]->scenePos().y() << shaper[4]->scenePos().y() << shaper[5]->scenePos().y() << shaper[6]->scenePos().y() << shaper[7]->scenePos().y();
qSort(xValues.begin(), xValues.end());
qSort(yValues.begin(), yValues.end());
xMin = xValues.first();
xMax = xValues.last();
yMin = yValues.first();
yMax = yValues.last();
return qMakePair(QPointF(xMin, yMin), QPointF(xMax, yMax));
shaper is qgraphicsitem by which I am resizing item.
Thanks :)
Thanks for showing your code.
As I said before,
trans.scale(scaleFactorW, scaleFactorH);
won't change the size returned by QGraphicsItem::boundingRect.
But in fact, QGraphicsItem::setScale has the same behaviour and the boundingRect() for the item doesn't change either.
QTransform::scale and QGraphicsItem::setScale are not the same, but both are useful to change the image size. Well, in the case of QTransform, you're scaling the coordinate system.
I think an example is the best way of explaining myself.
(this inherits QGraphicsItem)
qWarning() << "QGraphicsItem::scale(): " << this->scale();
QRectF br = this->boundingRect();
qWarning() << "QGraphicsItem::boundingRect() size / x / y / w / h: " << br.size() << " / "
<< br.x() << " / "
<< br.y() << " / "
<< br.width() << " / "
<< br.height();
QTransform trans = this->transform();
trans.scale(2.0, 2.0);
this->setTransform(trans);
/*
Comment trans.scale(2.0, 2.0) and uncomment the following line
to check the difference using the logs.
*/
// this->setScale(2.0);
qWarning() << "QGraphicsItem::scale(): " << this->scale();
br = this->boundingRect();
qWarning() << "QGraphicsItem::boundingRect() size / x / y / w / h: " << br.size() << " / "
<< br.x() << " / "
<< br.y() << " / "
<< br.width() << " / "
<< br.height();
qWarning() << "boundingRect * item_scale: " << this->boundingRect().size() * this->scale();

C++ Simple calculation outputting 0.0000000000000000 instead of 0.003333

The calculation for dx and dy is returning 0 and I don't see what the issue is. The console seems to show all the correct values are being used.
void drawBackground()
{
double r, g, b, dx, dy, Wx, Wy, Wz;
Ray ray;
cout << "xmax: " << sceneDescription::imagePlaneXmax << " xmin: " << sceneDescription::imagePlaneXmin << endl;
cout << "ymax: " << sceneDescription::imagePlaneYmax << " ymin: " << sceneDescription::imagePlaneYmin << endl;
cout << "Iw: " << sceneDescription::Iw << " Ih: " << sceneDescription::Ih << endl;
cout << " " << endl;
dx = (sceneDescription::imagePlaneXmax - (sceneDescription::imagePlaneXmin))/sceneDescription::Iw;
dy = (sceneDescription::imagePlaneYmax - (sceneDescription::imagePlaneYmin))/sceneDescription::Ih;
std::cout << "dx: "<< boost::format("%1$.16f") % dx << " dy: "<< boost::format("%1$.16f") % dy << endl;
}
sceneDescription.h
#include <glm/glm.hpp>
using namespace glm;
class sceneDescription{
public:
static const int imagePlaneXmin = -1;
static const int imagePlaneXmax = 1;
static const int imagePlaneYmin = -1;
static const int imagePlaneYmax = 1;
static const int Iw = 600;
static const int Ih = 800;
};
Console output:
xmax: 1 xmin: -1
ymax: 1 ymin: -1
Iw: 600 Ih: 800
dx: 0.0000000000000000 dy: 0.0000000000000000
The problem is that the statement:
dx = (sceneDescription::imagePlaneXmax -
(sceneDescription::imagePlaneXmin))/sceneDescription::Iw;
will give the following result:
(1-(-1))/600 = 2/600 = 0.00 (since this is integer division).
You may want to cast the number to double.
Something like this would work:
dx = (double)(sceneDescription::imagePlaneXmax -
(sceneDescription::imagePlaneXmin)) / sceneDescription::Iw;
Since cast operator has higher priority than division, the numerator will be cast by (double) and the denominator will be cast implicitly giving the double result.
Hope that helps!

sin() cos() ring formula

This is the source code:
#include <Windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;
#define d_open fstream::in | fstream::out | fstream::app | fstream::ate
#define Space " "
#define d_qq "\""
struct point3D
{
float X;
float Y;
float Z;
};
struct ObjectStruct
{
point3D T_LT;
point3D T_LB;
point3D T_RT;
point3D T_RB;
point3D B_LT;
point3D B_LB;
point3D B_RT;
point3D B_RB;
};
void CreateObject(ObjectStruct myobject)
{
fstream outmap;
outmap.open("prefab.map", d_open);
float * X = new float[6];
float * Y = new float[6];
float * Z = new float[6];
float * X2 = new float[6];
float * Y2 = new float[6];
float * Z2 = new float[6];
float * X3 = new float[6];
float * Y3 = new float[6];
float * Z3 = new float[6];
X[0] = myobject.T_LT.X;
Y[0] = myobject.T_LT.Y;
Z[0] = myobject.T_LT.Z;
X2[0] = myobject.T_RT.X;
Y2[0] = myobject.T_RT.Y;
Z2[0] = myobject.T_RT.Z;
X3[0] = myobject.T_RB.X;
Y3[0] = myobject.T_RB.Y;
Z3[0] = myobject.T_RB.Z;
X[1] = myobject.B_LB.X;
Y[1] = myobject.B_LB.Y;
Z[1] = myobject.B_LB.Z;
X2[1] = myobject.B_RB.X;
Y2[1] = myobject.B_RB.Y;
Z2[1] = myobject.B_RB.Z;
X3[1] = myobject.B_RT.X;
Y3[1] = myobject.B_RT.Y;
Z3[1] = myobject.B_RT.Z;
X[2] = myobject.T_LT.X;
Y[2] = myobject.T_LT.Y;
Z[2] = myobject.T_LT.Z;
X2[2] = myobject.T_LB.X;
Y2[2] = myobject.T_LB.Y;
Z2[2] = myobject.T_LB.Z;
X3[2] = myobject.B_LB.X;
Y3[2] = myobject.B_LB.Y;
Z3[2] = myobject.B_LB.Z;
X[3] = myobject.B_RT.X;
Y[3] = myobject.B_RT.Y;
Z[3] = myobject.B_RT.Z;
X2[3] = myobject.B_RB.X;
Y2[3] = myobject.B_RB.Y;
Z2[3] = myobject.B_RB.Z;
X3[3] = myobject.T_RB.X;
Y3[3] = myobject.T_RB.Y;
Z3[3] = myobject.T_RB.Z;
X[4] = myobject.T_RT.X;
Y[4] = myobject.T_RT.Y;
Z[4] = myobject.T_RT.Z;
X2[4] = myobject.T_LT.X;
Y2[4] = myobject.T_LT.Y;
Z2[4] = myobject.T_LT.Z;
X3[4] = myobject.B_LT.X;
Y3[4] = myobject.B_LT.Y;
Z3[4] = myobject.B_LT.Z;
X[5] = myobject.B_RB.X;
Y[5] = myobject.B_RB.Y;
Z[5] = myobject.B_RB.Z;
X2[5] = myobject.B_LB.X;
Y2[5] = myobject.B_LB.Y;
Z2[5] = myobject.B_LB.Z;
X3[5] = myobject.T_LB.X;
Y3[5] = myobject.T_LB.Y;
Z3[5] = myobject.T_LB.Z;
outmap
<< "{" << endl
<< "( " << X[0] << Space << Y[0] << Space << Z[0] << " ) "
<< "( " << X2[0] << Space << Y2[0] << Space << Z2[0] << " ) "
<< "( " << X3[0] << Space << Y3[0] << Space << Z3[0] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 " << endl
<< "( " << X[1] << Space << Y[1] << Space << Z[1] << " ) "
<< "( " << X2[1] << Space << Y2[1] << Space << Z2[1] << " ) "
<< "( " << X3[1] << Space << Y3[1] << Space << Z3[1] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1 " << endl
<< "( " << X[2] << Space << Y[2] << Space << Z[2] << " ) "
<< "( " << X2[2] << Space << Y2[2] << Space << Z2[2] << " ) "
<< "( " << X3[2] << Space << Y3[2] << Space << Z3[2] << " ) "
<< "YELLOW"
<< " [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[3] << Space << Y[3] << Space << Z[3] << " ) "
<< "( " << X2[3] << Space << Y2[3] << Space << Z2[3] << " ) "
<< "( " << X3[3] << Space << Y3[3] << Space << Z3[3] << " ) "
<< "YELLOW"
<< " [ 0 1 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[4] << Space << Y[4] << Space << Z[4] << " ) "
<< "( " << X2[4] << Space << Y2[4] << Space << Z2[4] << " ) "
<< "( " << X3[4] << Space << Y3[4] << Space << Z3[4] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "( " << X[5] << Space << Y[5] << Space << Z[5] << " ) "
<< "( " << X2[5] << Space << Y2[5] << Space << Z2[5] << " ) "
<< "( " << X3[5] << Space << Y3[5] << Space << Z3[5] << " ) "
<< "YELLOW"
<< " [ 1 0 0 0 ] [ 0 0 -1 0 ] 0 1 1 " << endl
<< "}" << endl;
delete [] X;
delete [] Y;
delete [] Z;
delete [] X2;
delete [] Y2;
delete [] Z2;
delete [] X3;
delete [] Y3;
delete [] Z3;
outmap.flush();
//
outmap.close();
}
int main(int argc, char ** argv)
{
//HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitle("Prefab Creator by Raichu (xgm.ru,d3scene.ru)");
Sleep(200);
SetConsoleTitle("PrefabTool by Raichu v0.1");
int select = 0;
cout << "Available shapes: 1-Ring, 2-Cube, 3-Triangle" << endl;
cin >> select;
if (select == 1)
{
cout << "Enter quantity of objects:" << endl;
int quality;
cin >> quality;
if (quality > 200 || quality < 10)
{
cout << "Error... Restart..." << endl;
return main(argc, argv);
}
cout << "Enter Ring radius:(example 20.0)" << endl;
float WhSz;
cin >> WhSz;
float inangle = 360 / quality;
//system("cls");
float X1_, X2_, Y1_, Y2_;
float X1, X2, Y1, Y2;
float a = 0;
X1_ = WhSz * cos(a);
Y1_ = WhSz * sin(a);
X2_ = (WhSz + 4) * cos(a);
Y2_ = (WhSz + 4) * sin(a);
a = inangle;
for (; a <= 360; )
{
X1 = WhSz * cos(a);
Y1 = WhSz * sin(a);
X2 = (WhSz + 4) * cos(a);
Y2 = (WhSz + 4) * sin(a);
#pragma region TEST
//cout << "X:" << X1 << " Y:" << Y1 << endl;
/* COORD xy;
xy.X = X1;
xy.Y = Y1;
SetConsoleCursorPosition(console, xy);
cout << "+" << endl;
xy.X = X2;
xy.Y = Y2;
SetConsoleCursorPosition(console, xy);
cout << "?" << endl;*/
#pragma endregion
ObjectStruct NewObject;
/* down */
NewObject.B_LB.Z = NewObject.B_LT.Z = NewObject.B_RB.Z = NewObject.B_RT.Z = -5;
/* top */
NewObject.T_LB.Z = NewObject.T_LT.Z = NewObject.T_RB.Z = NewObject.T_RT.Z = 5;
NewObject.T_LT.X = NewObject.B_LT.X = X2_;
NewObject.T_LT.Y = NewObject.B_LT.Y = Y2_;
NewObject.T_LB.X = NewObject.B_LB.X = X1_;
NewObject.T_LB.Y = NewObject.B_LB.Y = Y1_;
NewObject.T_RT.X = NewObject.B_RT.X = X2;
NewObject.T_RT.Y = NewObject.B_RT.Y = Y2;
NewObject.T_RB.X = NewObject.B_RB.X = X1;
NewObject.T_RB.Y = NewObject.B_RB.Y = Y1;
CreateObject(NewObject);
X1_ = X1;
Y1_ = Y1;
X2_ = X2;
Y2_ = Y2;
//a += inangle/3; // - Create SUN
a += inangle;
}
}
system("pause");
return 0;
}
problem code:
if (select == 1)
{
cout << "Enter quantity of objects:" << endl;
int quality;
cin >> quality;
if (quality > 200 || quality < 10)
{
cout << "Error... Restart..." << endl;
return main(argc, argv);
}
cout << "Enter Ring radius:(example 20.0)" << endl;
float WhSz;
cin >> WhSz;
float inangle = 360 / quality;
//system("cls");
float X1_, X2_, Y1_, Y2_;
float X1, X2, Y1, Y2;
float a = 0;
X1_ = WhSz * cos(a);
Y1_ = WhSz * sin(a);
X2_ = (WhSz + 4) * cos(a);
Y2_ = (WhSz + 4) * sin(a);
a = inangle;
for (; a <= 360; )
{
X1 = WhSz * cos(a);
Y1 = WhSz * sin(a);
X2 = (WhSz + 4) * cos(a);
Y2 = (WhSz + 4) * sin(a);
#pragma region TEST
//cout << "X:" << X1 << " Y:" << Y1 << endl;
/* COORD xy;
xy.X = X1;
xy.Y = Y1;
SetConsoleCursorPosition(console, xy);
cout << "+" << endl;
xy.X = X2;
xy.Y = Y2;
SetConsoleCursorPosition(console, xy);
cout << "?" << endl;*/
#pragma endregion
ObjectStruct NewObject;
/* down */
NewObject.B_LB.Z = NewObject.B_LT.Z = NewObject.B_RB.Z = NewObject.B_RT.Z = -5;
/* top */
NewObject.T_LB.Z = NewObject.T_LT.Z = NewObject.T_RB.Z = NewObject.T_RT.Z = 5;
NewObject.T_LT.X = NewObject.B_LT.X = X2_;
NewObject.T_LT.Y = NewObject.B_LT.Y = Y2_;
NewObject.T_LB.X = NewObject.B_LB.X = X1_;
NewObject.T_LB.Y = NewObject.B_LB.Y = Y1_;
NewObject.T_RT.X = NewObject.B_RT.X = X2;
NewObject.T_RT.Y = NewObject.B_RT.Y = Y2;
NewObject.T_RB.X = NewObject.B_RB.X = X1;
NewObject.T_RB.Y = NewObject.B_RB.Y = Y1;
CreateObject(NewObject);
X1_ = X1;
Y1_ = Y1;
X2_ = X2;
Y2_ = Y2;
//a += inangle/3; // - Create SUN
a += inangle;
}
}
I want to create a ring using objects. It turns 3 turns (3 layers) instead of one. How to fix it? It seems the problem in degrees, but I can not understand.
(sorry for that that I use a translator Google Translate)
sin and cos take radians as input, not degrees. You'll need to convert your angles to radians before passing them into sin and cos:
X1 = WhSz * cos(a * 3.141592654 / 180.0);