I am trying to rotate a box on screen in the same way it is done in many applications like powerpoint etc, by clicking and dragging around the object in the direction i want it to rotate.

Using the code below i have managed to make it rotate, by working out the angle between the three points; current mouse position, center of shape to be rotated and the old mouse position. Unfortunatly since i am working out the lengths of the sides with Pythagoras, i only get a positive result, wich leads to my box rotating in one direction only, regardless of the direction i move my mouse

I'm not sure if i'm going about this in completely the wrong way ( i am using a matrix to actually rotate the points, but i don't know if its possible to reverse the operation ), or whether i'm just bing a idiot and forgetting somthing simple i could do, but any help will be appreciated

Thanks in advance

public void Rotate(PointF p) { // Center float cx = Center.X; float cy = Center.Y; // New Position float nx = p.X; float ny = p.Y; // Old Position float ox = m_pnt_MouseTrack.X; float oy = m_pnt_MouseTrack.Y; // Work Out the Lengths of the Sides. // a == new -> old , b == center -> new , c == center -> old float a = (float)(Math.Sqrt(Math.Pow((nx - ox), 2) + Math.Pow((ny - oy), 2))); float b = (float)(Math.Sqrt(Math.Pow((nx - cx), 2) + Math.Pow((ny - cy), 2))); float c = (float)(Math.Sqrt(Math.Pow((cx - ox), 2) + Math.Pow((cy - oy), 2))); // Work out the Direction of the rotation // This is the bit i don't know how to do ... // Cos-1(( a^2 - b^2 - c^2 ) / -4bc) == A float A = (a * a) - (b * b) - (c * c); A /= (-2) * b * c; A = (float)Math.Acos(A); // Rotate the shape using a method i have written elsewhere Rotate(A - (float)Math.PI);}

By the looks of it, your code is only rotating the box around one axis.
If you only want to rotate around (say) the y-axis, then just use (x_new - x_old) to calculate the angle of rotation.

If you wish to rotate around an arbitrary axis, I'd recommend using quaternions rather than matrices.
In the case of matrices, you need to calculate the Euler angles around each axis (and perform them in the right order so as to avoid Gimbal lock etc) - it's quite tedious.

Quaternions are much easier to implement (although a little more abstract). This method of rotating with quaternions is sometimes called 'Arc ball'.

The idea is that you define the axis u to be the line from the centre of rotation, to the 'old' mouse position. Then use the difference in the old and new mouse positions to compute the angle of rotation (one method is to find u x (p_new-p_old)).

I'll be honest a lot of that went a little over my head ( i'm just looking at the info in the links you posted ), so i may have gotten you wrong here.

To start with i'm only dealing in 2d here, so i'm not sure if that makes a difference, and i'm rotating around a fixed point, but thats all working fine

Its not that i'm having any trouble rotateing the box, that works fine, i'm having trouble working out wich way to rotate it

your final paragraph looks like it might be what i'm looking for, but i'll just have to read about quaternions before i can be sure

It seems to me like quaternions are a very clever way of rotating somthing in 3d space, wich i'll remember , but i don't think they really help me ( unless i totally misunderstand your proposed soloution ... wich is unfortunatly likely to be the case )

I think what i really need is a way of finding the angle formed between the three points, but using a method that either gives me results within the range -180>ang>180 or 0>ang>360

You need to learn the sine of the angle as well as the cosine. Then you can use atan2 to get the angle.

public void Rotate(PointF p) { // Center float cx = Center.X; float cy = Center.Y; // New Position float nx = p.X; float ny = p.Y; // Old Position float ox = m_pnt_MouseTrack.X; float oy = m_pnt_MouseTrack.Y; float dx_o = ox - cx; float dy_o = oy - cy; float dx_n = nx - cx; float dy_n = ny - cy; float cross = (dx_o * dy_n) - (dx_n * dy_o); float dot = dx_o * dx_n + dy_o * dy_n; // when vecs a and b are at angle theta, // a cross b = |a| * |b| * sin(theta) // a dot b = |a| * |b| * cos(theta) float angle; if (cross == 0 && dot == 0) { // either old == center or new == center, so rotation // is undefined angle = 0; } else { angle = atan2(cross, dot); } // now use "angle" to rotate your shape}

Now that I know you're working in 2D, I see what you're doing with your code.
In your case, Pythagoras' is only an approximation for the lengths, as there's no guarantee the user is going to form a right-angled triangle. Furthermore (as was the problem) the cosine law does not give an idea for the direction of the angle.

I'd suggest using the cross product. Try,

A = arcsin[(a_x*b_y - b_x*a_y) / sqrt{(a_x*a_x+a_y*a_y)*(b_x*b_x+b_y*b_y)}]

You appear to go (mouse down, mouse up, redraw box) rather than having box follow mouse.

A messy way is to transform box to coordinate system with center of box at (0,0) and mouse down at (ox,0) x>0. Now identify quadrant in which mouse up takes place. Cos(t) = absolute value (ny/nx). Rotate through angle tr.
IF quad 1 tr = t
quad 2 tr = t + 90
quad 3 tr = 180 t
quad 4 tr = -t
Transform box to original cord system.
Draw

Thx Interactive, Sorry for the late reply, i finished work and just got in this morning.

I thought i'd managed to solve it with a really messy hack, involving using i statements to work out what qudrent the mouse was in reletive to the center, and then work out the direction of the mouse relitive to that quadrent, however after a bit more testing this morning, i broke it again ( and it's so messy and awful i'm ashamed of it ).

Your solution looks a lot better, so i'll try implement that and un close this question ( its the first time i've actually asked anything on here so if i do somthing wrong i apologize! ) so that i can award points properly.

Just one question, which points are A and B? I've assumed that they are the old and new mouse positions.

Arcsin only returns an angle in the range (-pi/2, +pi/2), but rotation can happen at any angle. That's why you need to look at both the cross-product and the dot-product. Once you have both of those, you can use atan2 to get the relative angle, which will be anywhere in (-pi, +pi). Just like in my response above. :)

Or if you don't quite follow the cross and dot product stuff, you could just use atan2 twice, once on the old vector and once on the new vector, then subtract to get the angle. At this point the difference will be in the range (-2pi, +2pi) so you might want to normalize the angle.

Or you could use the old and new vectors to come up with the transform without ever going through any trig.

0

Featured Post

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention. Check out this how-to article for more information.

This article provides a brief introduction to tissue engineering, the process by which organs can be grown artificially. It covers the problems with organ transplants, the tissue engineering process, and the current successes and problems of the tecā¦

This article covers the basics of data encryption, what it is, how it works, and why it's important. If you've ever wondered what goes on when you "encrypt" data, you can look here to build a good foundation for your personal learning.

This is a video describing the growing solar energy use in Utah. This is a topic that greatly interests me and so I decided to produce a video about it.

Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210 (2 * 3 * 5 * 7) or 2310 (2 * 3 * 5 * 7 * 11).
The larger templaā¦