Rotation algorithm needed

When I display a letter in either the XY, YZ or XZ plane in my LED cube, I would like to be able to rotate it in 90 degree steps within that plane.

I am storing my letters as a list of lines which in turn contain a start and end point (x, y, z).

So can anyone point me in the direction of a suitable algorithm without me having to re-invent the wheel by figuring out the maths from scratch.

So can anyone point me in the direction of a suitable algorithm without me having to re-invent the wheel by figuring out the maths from scratch.

Displaying letters on a different plane, orthogonal to the one that they are currently on, is a simple matter of using the three values in a different order. There is nothing hard about that.

for a sphere

x=radius*sin(j)cos(i);
y=radius
sin(j)sin(i);
z=radius
cos(j);

i and j are angles like latitude and longitude

AmbiLobe:
for a sphere

x=radius*sin(j)cos(i);
y=radius
sin(j)sin(i);
z=radius
cos(j);

i and j are angles like latitude and longitude

If I do some rounding, then hopefully these will result in whole numbers such that new points don't fall out of alignment with the letter.

I was doing an algorithm to flip, for example, the points in an XY letter to the XZ plane.
But I wanted to prevent the same flip being inadvertently done twice.
So I was trying to figure out which plane (XY, XZ or YZ) a line was on by examining the coordinates of the ends of the line.
Damn.....I just could not get it to work!
Apparently it is impossible to distinguish a horizontal line in the XY plane from a vertical line in the YZ plane simply via comparisons between Z1, and Z2 etc.
There must be a sound mathematical way to do it but perhaps it is beyond my mathematical ability.
In the end I just stored an enum value in my polyline class (which I use to store letters) that told me in which plane the polyline was oriented.
I set this explicitly each time I change the orientation of the letter.

Apparently it is impossible to distinguish a horizontal line in the XY plane from a vertical line in the YZ plane simply via comparisons between Z1, and Z2 etc.
There must be a sound mathematical way to do it

Distinguish in what way? A 3D line is distinct from another 3D line is any coordinate of either end is different.

PaulS:

Apparently it is impossible to distinguish a horizontal line in the XY plane from a vertical line in the YZ plane simply via comparisons between Z1, and Z2 etc.
There must be a sound mathematical way to do it

Distinguish in what way? A 3D line is distinct from another 3D line is any coordinate of either end is different.

A line that is in the XY plane......X varies with Y but Z is the same for both ends of the line
A line that is in the XZ plane......X varies with Z but Y is the same for both ends of the line
A line that is in the YZ plane......Y varies with Z but X is the same for both ends of the line
A line that is in the XYZ planes......Y varies with both X and Z

Consider a letter displayed on the XY face of the cube which you want to swap to the or the YZ face of the cube - it is a simple matter of swapping the X and Z for the coordinates of each end of a line.

That was my general idea however it turned out to be mathematically flawed when you try to determine the orientation of the letter based upon its individual lines.

Consider the lines:
1,1,4->1,8,4
1,4,1->8,4,1
1,1,1->8,8,8

For the first line for example, if the two Xs are always the same, then you could say the line moves in the YZ plane as you vary the Zs and Ys.

Compared to the second line, where the Zs are always the same and the line could be said to move in the XY plane as you vary the Xs and Ys.

The third line moves through all 3 planes simultaneously.

Perhaps it is through vector mathematics that you could distinguish them, but I am afraid I don't remember enough about vectors to enable me to figure it out.

Are you planning on displaying text other than on the faces of the cube?

PaulS:
Are you planning on displaying text other than on the faces of the cube?

I want to do things like allow a letter to drop from top to bottom and bounce a little and then flip up to a vertical position and also perhaps rotate about the Y axis.

I have defined my letters in this manner:

void cRGB_Cube::makeXYPlaneA(cPolyline& rPolyline)
{
	rPolyline.addLine(cLine(1, 1, 1, 1, 6, 1));
	rPolyline.addLine(cLine(2, 1, 1, 2, 6, 1));
	rPolyline.addLine(cLine(7, 1, 1, 7, 6, 1));
	rPolyline.addLine(cLine(8, 1, 1, 8, 6, 1));
	rPolyline.addLine(cLine(1, 6, 1, 3, 8, 1));
	rPolyline.addLine(cLine(2, 6, 1, 3, 7, 1));
	rPolyline.addLine(cLine(7, 6, 1, 6, 7, 1));
	rPolyline.addLine(cLine(8, 6, 1, 6, 8, 1));
	rPolyline.addLine(cLine(3, 7, 1, 6, 7, 1));
	rPolyline.addLine(cLine(3, 8, 1, 6, 8, 1));
	rPolyline.addLine(cLine(2, 3, 1, 6, 3, 1));
	rPolyline.addLine(cLine(2, 4, 1, 6, 4, 1));
	[b]rPolyline.setOrient(eXYPlane);[/b]
}

I didn't want to have to do 26 x 3 polylines defining each of the letters in each plane.

I figured out that simply swapping Xs with Zs etc translated the above letter to the YZ plane nicely.

However I needed a means to determine which plane it was currently in.

The following works nicely however it still baffles me why I can't do it without the enum explicitly telling me which orientation the letter is currently in.

void cPolyline::flipTo(eOrietationType eNewOrient)
{
	if (m_eOrient != eNewOrient)
	{
		if (m_eOrient == eXYPlane)
		{
			if (eNewOrient == eXZPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)
					m_LineList[nI].swapYZ();
			}
			else if (eNewOrient == eYZPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)
					m_LineList[nI].swapXZ();
			}
		}
		else if (m_eOrient == eXZPlane)
		{
			if (eNewOrient == eXYPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)\
					m_LineList[nI].swapYZ();
			}
			else if (eNewOrient == eYZPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)
					m_LineList[nI].swapXY();
			}
		}
		else if (m_eOrient == eYZPlane)
		{
			if (eNewOrient == eXYPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)
					m_LineList[nI].swapXZ();
			}
			else if (eNewOrient == eXZPlane)
			{
				for (int nI = 0; nI < m_nCount; nI++)
					m_LineList[nI].swapXY();
			}
		}
		m_eOrient = eNewOrient;
	}
}

See a graphics book.
Rotations (in fact, ALL graphics transformations, including scaling and translation) are usually implemented as matrix multiplications. Your array of points is one matix, and you multiply it by a 3x3 "transformation matrix" to do ... everything.
For rotations, the matrix will contain sines and cosines of the angle (which are conveniently 0 and 1 for 90 degree rotations!)

(however, note that rotating a object about an origin or axes is NOT the same as rotating about the OBJECT's center. So you usually have to do something like create a transformation matrix that translates the object to the origin, rotates it, and translates it back to where it was. Since matrix multiplication is associative [ ((( P * T1) * R1) * T2) == (P * (T1R1T2)) ], you still only need one matrix multiply for each object's rotation. It's all pretty neat.)

(Usually, this sort of stuff is done in "real" space; floating point numbers for all the coordinates and such. I imagine that you could do a lot of optimization for the small range of integers that are useful on an LED cube...)

All 90 rotations in the planes are of the form
X, Y <- Y, -X
or similar (swap coords and change the sign of one of them). This is about the origin so a
translation may also be needed.

swapping coords is a reflection about the line X=Y, changing the sign is a reflection about the other axis.
Two reflections = rotation of twice the angle between the mirror planes. The X=Y plane is at 45 degrees
to X and Y axes...

westfw:
Rotations (in fact, ALL graphics transformations, including scaling and translation) are usually implemented as matrix multiplications.

I haven't used it myself, but there's a MatrixMath library in the playground.

westfw:
See a graphics book.
Rotations (in fact, ALL graphics transformations, including scaling and translation) are usually implemented as matrix multiplications. Your array of points is one matix, and you multiply it by a 3x3 "transformation matrix" to do ... everything.
For rotations, the matrix will contain sines and cosines of the angle (which are conveniently 0 and 1 for 90 degree rotations!)
http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations

(however, note that rotating a object about an origin or axes is NOT the same as rotating about the OBJECT's center. So you usually have to do something like create a transformation matrix that translates the object to the origin, rotates it, and translates it back to where it was. Since matrix multiplication is associative [ ((( P * T1) * R1) * T2) == (P * (T1R1T2)) ], you still only need one matrix multiply for each object's rotation. It's all pretty neat.)

(Usually, this sort of stuff is done in "real" space; floating point numbers for all the coordinates and such. I imagine that you could do a lot of optimization for the small range of integers that are useful on an LED cube...)

Oh gawd! Matrices!

I never found matrices particularly intuitive in first year maths.

Don't know whether it was because I didn't have a particular mathematical ability or whether I found it a little dull and therefore did not apply myself to it as much as I could have.

Either way, to do rotations, it looks as though I have a bit of a learning curve to start up, refreshing my memory on matrices.

But now that you're a computer programmer, you don't have to understand it, you only have to implement it and use it.

westfw:
But now that you're a computer programmer, you don't have to understand it, you only have to implement it and use it.

Mmmm.

2-D matrices were bad enough, but it is going to do my head in trying to get it around 3-D matrices multiplication etc.

And now that I can flip from plane to plane freely in my RGB LED cube simulator, I can see that I need to do a 90 degree clockwise rotation when I flip from XZ to YZ. Otherwise the letter is laying on its side.

Matrices are probably a bit overkill for these simple transformations, particularly if you don't have prior understanding of them. If your coordinates are relative to the center of the cube, you can do all those rotations by simply swapping x/y/z coordinates and flipping their signs properly. Matrices would help you in figuring out how to do that exactly, but you can also do that with some trial and error as well which is probably faster than having necessary grasp of matrix math (: That, or have someone with understanding of matrix math giving you the proper swapping/sign flip operations for each face.

boylesg:
I never found matrices particularly intuitive in first year maths.

The only time I ever really had fun with math was using matrix math for 3D calcs and rendering back in high school.

Then I took the Stanford ML Class in 2011 (now available from Coursera), taught by Prof. Andrew Ng.

All the programming done in the class used a language called Octave, which is basically an open-source version of Matlab (not quite as fancy - but it won't empty your savings account like Matlab will).

The main primitive in both languages is a vector. Just about everything numeric is defined as vectors and matrices (there are also scalar values); performing the standard operations (addition, subtraction, multiplication, division) on them is easy-peesy; you multiple a vector and a matrix, and you get your answer - but understanding how and why you got that answer, well, requires knowing matrix math. I had to do a crash-course on linear algebra (which is what matrix math is a part of) to understand this, because I hadn't touched it in so long...

But anyhow - it started to become fun. Then the course started introducing how you could use such representations to implement things like neural networks; since each neuron could be represented in a matrix fashion, and the math can be done in parallel... Oh - and once you could reduce a problem to a matrix representation, you could call an optimization function to speed up the process; depending on the package (and both matlab and octave have support - in the case of octave, you just have to compile the package right) - you can farm out the process to multiple threads, multiple cores - or even multiple CPUs.

Suddenly - I wanted a Beowulf cluster very, very badly (I would settle for an NVidia Tesla workstation, even!)...

From that course (and later, after taking the Udacity CS373 course - which used Python with a simple matrix math library) - I suddenly both understood - to a certain level - what and how parallel programming entailed, and why so many books back in the 1980s, regarding the "5th Generation Computing Initiative" (anybody else here remember that?) - mentioned how difficult it was to reduce a problem in such a manner to a parallel representation (mainly because there are only certain classes of problems that can be reduced in this manner - but also because it is so damn hard to think in this manner). But I found it (to an extent) somewhat easy.

My only regret is that I found that I could understand this stuff late in life (I just recently turned 40) - had only not been the idiot teenager that I was, I probably would have had no problem with such problems had I gone to college and/or university. So - now I just play with this stuff for fun (when needed).

So much of what is termed "machine learning" and "artificial intelligence" today absolutely relies on an understanding of linear algebra (as well as a couple of subject which I really need a refresher course in - statistics and probability); depending on whether those subjects hold any interest for you, make sure you brush up on all of that if you need to!

The good news is that it's NOT a 3d matrix. It's just a list of points - one dimension indexed by point#, and the other dimension is just 3, form x,y,z.

Cool!

It wasn't as much of a mind bender as I assumed it would be.

This function works nicely for the XY plane:

void cPolyline::rotate(int nAngle, cLine& rLine)
{
	cLine newLine;

	if (m_eOrient == eXYPlane)
	{
		if (nAngle == 90)
		{
			newLine.m_StartPoint.m_nX = -rLine.m_StartPoint.m_nY + 9;
			newLine.m_StartPoint.m_nY = rLine.m_StartPoint.m_nX;
			newLine.m_EndPoint.m_nX = -rLine.m_EndPoint.m_nY + 9;
			newLine.m_EndPoint.m_nY = rLine.m_EndPoint.m_nX;
			rLine = newLine;
		}
		else if (nAngle == -90)
		{
			rotate(90, rLine);
			rotate(180, rLine);
		}
		else if (nAngle == 180)
		{
			rotate(90, rLine);
			rotate(90, rLine);
		}
		else if (nAngle == -180)
		{
			rotate(180, rLine);
		}
		else if (nAngle == 270)
		{
			rotate(90, rLine);
			rotate(90, rLine);
			rotate(90, rLine);
		}
		else if (nAngle == -270)
		{
			rotate(-90, rLine);
		}
	}
	else if (m_eOrient == eYZPlane)
	{
	}
	else if (m_eOrient == eXZPlane)
	{
	}
}

The matrix approach feels like exactly the right approach for this problem, to me. It's how to generalise the concept of swapping X, Y and Z coordinates around and making some of them negative and so on. I'd argue that it is no more complex than coding the coordinate transformations individually, and gives you massively more flexibility. For example it would be possible to shrink and expand the image, display it on diagonal planes and so on just by applying a different transformation matrix. Also, using the transformation approach makes it easy to apply multiple transformations so that you can stretch, rotate and translate the image independently which will come in very handy if you ever want to produce a moving image. It also means you can control multiple images separately and then sum then to produce a combined image, so your image can contain multiple elements that are positioned and moved independently. If this is anything more than a quick hack, time spent getting your head around matrix transformations would IMO be time well spent.

PeterH:
The matrix approach feels like exactly the right approach for this problem, to me. It's how to generalise the concept of swapping X, Y and Z coordinates around and making some of them negative and so on. I'd argue that it is no more complex than coding the coordinate transformations individually, and gives you massively more flexibility. For example it would be possible to shrink and expand the image, display it on diagonal planes and so on just by applying a different transformation matrix. Also, using the transformation approach makes it easy to apply multiple transformations so that you can stretch, rotate and translate the image independently which will come in very handy if you ever want to produce a moving image. It also means you can control multiple images separately and then sum then to produce a combined image, so your image can contain multiple elements that are positioned and moved independently. If this is anything more than a quick hack, time spent getting your head around matrix transformations would IMO be time well spent.

Normally I would agree but it seems fairly pointless generalizing rotations for a 8 x 8 LED cube.

The easiest option seems to be the best option in this case.