Rotation of a point about the z-axis - c++

I have 3 vectors in 3D space. Let's call them xaxis, yaxis, and zaxis. These vectors are centered about an arbitrary point somewhere in 3D space. I am interested in rotating the xaxis and yaxis vectors about the zaxis vector a number of degrees θ.
For the following code with values being arbitrary and unimportant:
double xaxis[3], yaxis[3], zaxis[3], point[3], theta;
How would I go about rotating xaxis and yaxis about the zaxis by theta degrees?
Future Note: These attempts do not work. See my answer for the proper solution, which was found with the help of BlueRaja-DannyPflughoeft
My attempt at matrix-based rotation:
double rx[3][3];
double ry[3][3];
double rz[3][3];
double r[3][3];
rx[0][0] = 1;
rx[0][1] = 0;
rx[0][2] = 0;
rx[1][0] = 0;
rx[1][1] = cos(theta);
rx[1][2] = sin(theta);
rx[2][0] = 0;
rx[2][1] = -1.0 * sin(theta);
rx[2][2] = cos(theta);
ry[0][0] = cos(theta);
ry[0][1] = 0;
ry[0][2] = -1.0 * sin(theta);
ry[1][0] = 0;
ry[1][1] = 1;
ry[1][2] = 0;
ry[2][0] = sin(theta);
ry[2][1] = 0;
ry[2][2] = cos(theta);
//No rotation wanted on the zaxis
rz[0][0] = cos(0);
rz[0][1] = sin(0);
rz[0][2] = 0;
rz[1][0] = -1.0 * sin(0);
rz[1][1] = cos(0);
rz[1][2] = 0;
rz[2][0] = 0;
rz[2][1] = 0;
rz[2][2] = 1;
vtkMath::Multiply3x3(rx, ry, r); //Multiplies rx by ry and stores into r
vtkMath::Multiply3x3(r, rz, r); //Multiplies r by rz and stores into r
vtkMath::Multiply3x3(r, xaxis, xaxis);//multiplies a 3x3 by a 3x1
vtkMath::Multiply3x3(r, yaxis, yaxis);//multiplies a 3x3 by a 3x1
This attempt only worked when the plane was in the x-y plane:
double x, y;
x = xaxis[0];
y = xaxis[1];
xaxis[0] = x * cos(theta) - y * sin(theta);
xaxis[1] = x * sin(theta) + y * cos(theta);
x = yaxis[0];
y = yaxis[1];
yaxis[0] = x * cos(theta) - y * sin(theta);
yaxis[1] = x * sin(theta) + y * cos(theta);
Using the axis-angle approach given by BlueRaja-DannyPflughoeft:
double c = cos(theta);
double s = sin(theta);
double C = 1.0 - c;
double Q[3][3];
Q[0][0] = xaxis[0] * xaxis[0] * C + c;
Q[0][1] = xaxis[1] * xaxis[0] * C + xaxis[2] * s;
Q[0][2] = xaxis[2] * xaxis[0] * C - xaxis[1] * s;
Q[1][0] = xaxis[1] * xaxis[0] * C - xaxis[2] * s;
Q[1][1] = xaxis[1] * xaxis[1] * C + c;
Q[1][2] = xaxis[2] * xaxis[1] * C + xaxis[0] * s;
Q[2][0] = xaxis[1] * xaxis[2] * C + xaxis[1] * s;
Q[2][1] = xaxis[2] * xaxis[1] * C - xaxis[0] * s;
Q[2][2] = xaxis[2] * xaxis[2] * C + c;
double x = Q[2][1] - Q[1][2], y = Q[0][2] - Q[2][0], z = Q[1][0] - Q[0][1];
double r = sqrt(x * x + y * y + z * z);
//xaxis[0] /= r;
//xaxis[1] /= r;
//xaxis[2] /= r;
xaxis[0] = x;// ?
xaxis[1] = y;
xaxis[2] = z;

Thanks to BlueRaja - Danny Pflughoeft:
double c = cos(theta);
double s = sin(theta);
double C = 1.0 - c;
double Q[3][3];
Q[0][0] = zaxis[0] * zaxis[0] * C + c;
Q[0][1] = zaxis[1] * zaxis[0] * C + zaxis[2] * s;
Q[0][2] = zaxis[2] * zaxis[0] * C - zaxis[1] * s;
Q[1][0] = zaxis[1] * zaxis[0] * C - zaxis[2] * s;
Q[1][1] = zaxis[1] * zaxis[1] * C + c;
Q[1][2] = zaxis[2] * zaxis[1] * C + zaxis[0] * s;
Q[2][0] = zaxis[0] * zaxis[2] * C + zaxis[1] * s;
Q[2][1] = zaxis[2] * zaxis[1] * C - zaxis[0] * s;
Q[2][2] = zaxis[2] * zaxis[2] * C + c;
xaxis[0] = xaxis[0] * Q[0][0] + xaxis[0] * Q[0][1] + xaxis[0] * Q[0][2];
xaxis[1] = xaxis[1] * Q[1][0] + xaxis[1] * Q[1][1] + xaxis[1] * Q[1][2];
xaxis[2] = xaxis[2] * Q[2][0] + xaxis[2] * Q[2][1] + xaxis[2] * Q[2][2]; // Multiply a 3x3 by 3x1 and store it as the new rotated axis
yaxis[0] = yaxis[0] * Q[0][0] + yaxis[0] * Q[0][1] + yaxis[0] * Q[0][2];
yaxis[1] = yaxis[1] * Q[1][0] + yaxis[1] * Q[1][1] + yaxis[1] * Q[1][2];
yaxis[2] = yaxis[2] * Q[2][0] + yaxis[2] * Q[2][1] + yaxis[2] * Q[2][2]; // Multiply a 3x3 by 3x1 and store it as the new rotated axis

I see that following matrix multiplication is wrong!
As stated above it can be factored with xaxis[0]
xaxis[0] = xaxis[0] * Q[0][0] + xaxis[0] * Q[0][1] + xaxis[0] * Q[0][2];
xaxis[0] = xaxis[0] * (Q[0][0] + Q[0][1] + Q[0][2]);
This does not look like a matrix multiplication. It should be:
xaxis1[0] = xaxis[0] * Q[0][0] + xaxis[1] * Q[0][1] + xaxis[2] * Q[0][2];
xaxis1[1] = xaxis[0] * Q[1][0] + xaxis[1] * Q[1][1] + xaxis[2] * Q[1][2];
xaxis1[2] = xaxis[0] * Q[2][0] + xaxis[1] * Q[2][1] + xaxis[2] * Q[2][2]; // Multiply a 3x3 by 3x1 and store it as the new rotated axis
yaxis1[0] = yaxis[0] * Q[0][0] + yaxis[1] * Q[0][1] + yaxis[2] * Q[0][2];
yaxis1[1] = yaxis[0] * Q[1][0] + yaxis[1] * Q[1][1] + yaxis[2] * Q[1][2];
yaxis1[2] = yaxis[0] * Q[2][0] + yaxis[1] * Q[2][1] + yaxis[2] * Q[2][2]; // Multiply a 3x3 by 3x1 and store it as the new rotated axis

Related

OpenGL how to create a sphere from half-sphere in c++

So, from a material I have, I managed to somehow complete it to half-sphere, the original destination. But now I have to make a sphere from the said half-sphere and I'm lost. I haven't met an answer online that has a fourth parameter (raze). Can someone tell me what I'm missing?
The code:
void drawSphere(double r, int lats, int longs, double raze) {
double alpha = acos((r - raze)/r);
bool ind = true;
int i, j;
for(i = 0; i <= lats; i++) {
double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
if (lat0>alpha && lat1>alpha){
if (ind){
ind = false;
double z0 = sin(alpha);
double zr0 = cos(alpha);
double lat1 = M_PI * (-0.5 + (double) (i-1) / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glColor3f(1, 0, 0);
//glNormal3f(x * zr0, y * zr0, z0);
glVertex3f(r * x * zr0, r * y * zr0, r * z0);
//glNormal3f(x * zr1, y * zr1, z1);
glVertex3f(r * x * zr1, r * y * zr1, r * z1);
}
glEnd();
}
glBegin(GL_QUAD_STRIP);
for(j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glColor3f(1, 0, 0);
//glNormal3f(x * zr0, y * zr0, z0);
glVertex3f(r * x * zr0, r * y * zr0, r * z0);
//glNormal3f(x * zr1, y * zr1, z1);
glVertex3f(r * x * zr1, r * y * zr1, r * z1);
}
glEnd();};
}
}
For a full sphere raze must be equal r. However, the condition if (lat0>alpha && lat1>alpha) is wrong. It has to be:
if (lat0 >= -alpha && lat1 <= alpha)
Note that for a full sphere you need to draw slices from -M_PI/2 to M_PI/2. That means if (lat0 >= -M_PI/2 && lat1 < -M_PI/2).

How to calculate normal for the cylindrical bevel

I am trying to add bevel to a cylinder , but i am have an issue with calculating the normals for the bevel
the
this is how i am calculating the data for vertices
struct Vertices
{
float x;
float y;
float z;
}
float pieStartAngle = 0.0 * (M_PI / 180.0f);
float angleCircle = 0.0f;
// First fill all the position of vertices
for (int k = 0; k < totalNumberOfPies; k++)
{
for (int i = 0; i < segmentPerPie + 1; i++)
{
Vertices temp;
float initialAngle = pieStartAngle;
angleCircle = (stdvecValuePercent[k] / 100.0f) * totalAngle;
float angle = initialAngle + ((angleCircle *(M_PI / 180)) * i / segmentPerPie);
float x, y, z, tx, ty, tz;
float innerX, innerY, innerZ, innerTx, innerTy;
x = cos(angle) * (radius - bevel);
y = sin(angle) * (radius - bevel);
z = 0.0;
temp.x = x;
temp.y = y;
temp.z = z;
vertices.push_back(temp);
x = cos(angle) * radius;
y = sin(angle) * radius;
z = 0.0 + bevel;
temp.x = x;
temp.y = y;
temp.z = z;
vertices.push_back(temp);
}
pieStartAngle += angleCircle * (M_PI / 180);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
this is how i am calculating the data for normals , i am taking the cross product of three verices to get the vector perpendicular to the face.
for (int i = 0; i < vertices.size(); i++)
{
glm::vec3 vec1 = glm::vec3(vertices[i].x - vertices[i + 1].x, vertices[i].y - vertices[i + 1].y, vertices[i].z - vertices[i + 1].z);
glm::vec3 vec2 = glm::vec3(vertices[i].x - vertices[i + 2].x, vertices[i].y - vertices[i + 2].y, vertices[i].z - vertices[i + 2].z);
glm::vec3 crossProduct = glm::cross(glm::normalize(vec1), glm::normalize(vec2));
crossProduct = glm::normalize(crossProduct);
bevelData.push_back(vertices[i].x);
bevelData.push_back(vertices[i].y);
bevelData.push_back(vertices[i].z);
bevelData.push_back(crossProduct.x );
bevelData.push_back(crossProduct.y );
bevelData.push_back(crossProduct.z);
bevelData.push_back(0.0);
bevelData.push_back(0.0);
}

OpenGl rotate custom implementation

I'm trying to code my custom implementation of Opengl glRotatef(angle,x,y,z) function.
I wrote the rotation matrix, but when I try to use it, the effect is not the same as the original function. Here is my code;
void mglRotate(float angle, float x, float y, float z)
{
float angle_rad = angle * (PI/180.0f);
float c = cos(angle_rad);
float s = sin(angle_rad);
float t = 1 - c;
float m[16] = {
c+x*x*t,y*x*t+z*s,z*x*t-y*s,0,
x*y*t-z*s,c+y*y*t,z*y*t+x*s,0,
x*z*t+y*s,y*z*t-x*s,z*z*t+c,0,
0,0,0,1
};
glMultMatrixf(m);
}
Where is my mistake?
There is a library glm, that does exactly the same thing as old openGL functions. You can compare your implementation with implementation in glm and figure it out :)
template <typename T>
GLM_FUNC_QUALIFIER detail::tmat4x4<T> rotate
(
detail::tmat4x4<T> const & m,
T const & angle,
detail::tvec3<T> const & v
)
{
T a = radians(angle);
T c = cos(a);
T s = sin(a);
detail::tvec3<T> axis = normalize(v);
detail::tvec3<T> temp = (T(1) - c) * axis;
detail::tmat4x4<T> Rotate(detail::tmat4x4<T>::null);
Rotate[0][0] = c + temp[0] * axis[0];
Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];
Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];
Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];
Rotate[1][1] = c + temp[1] * axis[1];
Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];
Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];
Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];
Rotate[2][2] = c + temp[2] * axis[2];
detail::tmat4x4<T> Result(detail::tmat4x4<T>::null);
Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
Result[3] = m[3];
return Result;
}
The one thing that seems wrong to me in your code is that you don't normalize the axis.

How to obtain axis-angle from rotation matrix?

I need to obtain some data from an openGL rotation matrix. I need to obtain the equivalent euler angles (already did it), the equivalent quaternion (did it, but just copying it from the Internet) and the equivalent axis-angle.
I dont know if a rotation matrix can be expresed as a single rotation of a certain angle around an certain vector. Are these equivalent? If they are, how can I obtain one from the other?
Also, i would like to understand better the meaning of a quaternion, and the insides of a rotation matrix. Where should i go to learn about this?
Yes any rotation matrix/unit quaternion is equivalent to a rotation around a single axis. If we call this axis n and the angle theta then the quaternion for this rotation is:
[n * sin(theta / 2) cos(theta / 2)]
To reconstruct this use acos on the w element of the quaternion to get theta / 2. After you have theta you can divide x,y and z component with sin(theta / 2) to reconstruct the axis.
Here's a function which converts a 3x3 matrix into an axis, angle (using a quatention, so perhaps theres a more efficient way which bypasses that step).
void axis_angle_from_mat3(float r_axis[3], float *r_angle, float mat[3][3])
{
float q[4];
/* -------------------------------------------------------------------- */
/* matrix to quaternion */
double tr, s;
float tmat[3][3];
/* work on a copy */
memcpy(tmat, mat, sizeof(tmat));
/* normalize the matrix */
int i;
for (i = 0; i < 3; i++) {
float d = (tmat[i][0] * tmat[i][0] + tmat[i][1] * tmat[i][1] + tmat[i][2] * tmat[i][2]);
if (d > 1.0e-35f) {
d = sqrtf(d);
tmat[i][0] /= d;
tmat[i][1] /= d;
tmat[i][2] /= d;
}
else {
tmat[i][0] = 0.0f;
tmat[i][1] = 0.0f;
tmat[i][2] = 0.0f;
d = 0.0f;
}
}
tr = 0.25 * (double)(1.0f + tmat[0][0] + tmat[1][1] + tmat[2][2]);
if (tr > (double)1e-4f) {
s = sqrt(tr);
q[0] = (float)s;
s = 1.0 / (4.0 * s);
q[1] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[3] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
}
else {
if (tmat[0][0] > tmat[1][1] && tmat[0][0] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[0][0] - tmat[1][1] - tmat[2][2]);
q[1] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
}
else if (tmat[1][1] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[1][1] - tmat[0][0] - tmat[2][2]);
q[2] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[1] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
else {
s = 2.0f * sqrtf(1.0f + tmat[2][2] - tmat[0][0] - tmat[1][1]);
q[3] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
q[1] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
q[2] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
}
/* normalize the quat */
float len;
len = sqrtf(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
if (len != 0.0f) {
q[0] /= len;
q[1] /= len;
q[2] /= len;
q[3] /= len;
}
else {
q[1] = 1.0f;
q[0] = q[2] = q[3] = 0.0f;
}
/* -------------------------------------------------------------------- */
/* quaternion to axis angle */
float ha, si;
ha = acosf(q[0]);
si = sinf(ha);
*r_angle = ha * 2;
if (fabsf(si) < FLT_EPSILON)
si = 1.0f;
r_axis[0] = q[1] / si;
r_axis[1] = q[2] / si;
r_axis[2] = q[3] / si;
}

Gradient algorithm produces little white dots

I'm working on an algorithm to generate point to point linear gradients. I have a rough proof of concept implementation done:
GLuint OGLENGINEFUNCTIONS::CreateGradient( std::vector<ARGBCOLORF> &input,POINTFLOAT start, POINTFLOAT end, int width, int height,bool radial )
{
std::vector<POINT> pol;
std::vector<GLubyte> pdata(width * height * 4);
std::vector<POINTFLOAT> linearpts;
std::vector<float> lookup;
float distance = GetDistance(start,end);
RoundNumber(distance);
POINTFLOAT temp;
float incr = 1 / (distance + 1);
for(int l = 0; l < 100; l ++)
{
POINTFLOAT outA;
POINTFLOAT OutB;
float dirlen;
float perplen;
POINTFLOAT dir;
POINTFLOAT ndir;
POINTFLOAT perp;
POINTFLOAT nperp;
POINTFLOAT perpoffset;
POINTFLOAT diroffset;
dir.x = end.x - start.x;
dir.y = end.y - start.y;
dirlen = sqrt((dir.x * dir.x) + (dir.y * dir.y));
ndir.x = static_cast<float>(dir.x * 1.0 / dirlen);
ndir.y = static_cast<float>(dir.y * 1.0 / dirlen);
perp.x = dir.y;
perp.y = -dir.x;
perplen = sqrt((perp.x * perp.x) + (perp.y * perp.y));
nperp.x = static_cast<float>(perp.x * 1.0 / perplen);
nperp.y = static_cast<float>(perp.y * 1.0 / perplen);
perpoffset.x = static_cast<float>(nperp.x * l * 0.5);
perpoffset.y = static_cast<float>(nperp.y * l * 0.5);
diroffset.x = static_cast<float>(ndir.x * 0 * 0.5);
diroffset.y = static_cast<float>(ndir.y * 0 * 0.5);
outA.x = end.x + perpoffset.x + diroffset.x;
outA.y = end.y + perpoffset.y + diroffset.y;
OutB.x = start.x + perpoffset.x - diroffset.x;
OutB.y = start.y + perpoffset.y - diroffset.y;
for (float i = 0; i < 1; i += incr)
{
temp = GetLinearBezier(i,outA,OutB);
RoundNumber(temp.x);
RoundNumber(temp.y);
linearpts.push_back(temp);
lookup.push_back(i);
}
for (unsigned int j = 0; j < linearpts.size(); j++) {
if(linearpts[j].x < width && linearpts[j].x >= 0 &&
linearpts[j].y < height && linearpts[j].y >=0)
{
pdata[linearpts[j].x * 4 * width + linearpts[j].y * 4 + 0] = (GLubyte) j;
pdata[linearpts[j].x * 4 * width + linearpts[j].y * 4 + 1] = (GLubyte) j;
pdata[linearpts[j].x * 4 * width + linearpts[j].y * 4 + 2] = (GLubyte) j;
pdata[linearpts[j].x * 4 * width + linearpts[j].y * 4 + 3] = (GLubyte) 255;
}
}
lookup.clear();
linearpts.clear();
}
return CreateTexture(pdata,width,height);
}
It works as I would expect most of the time, but at certain angles it produces little white dots. I can't figure out what does this.
This is what it looks like at most angles (good) http://img9.imageshack.us/img9/5922/goodgradient.png
But once in a while it looks like this (bad): http://img155.imageshack.us/img155/760/badgradient.png
What could be causing the white dots?
Is there maybe also a better way to generate my gradients if no solution is possible for this?
Thanks
I think you have a bug indexing into the pdata byte vector. Your x domain is [0, width) but when you multiply out the indices you're doing x * 4 * width. It should probably be x * 4 + y * 4 * width or x * 4 * height + y * 4 depending on whether you're data is arranged row or column major.