How can i find a negitive angle from three points

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);
}

Open in new window

ClearRockAsked:
Who is Participating?
 
InteractiveMindConnect With a Mentor Commented:
Sorry, I assumed you were working in 3D.

What was your solution?

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)}]

where

  a = mouse_old - centre
  b = mouse_new - centre

0
 
InteractiveMindCommented:
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)).

See here:
http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
http://cgmath.blogspot.com/2009/03/arc-ball-rotation-using-quaternion.html
and equation (30) onwards, here:
http://mathworld.wolfram.com/Quaternion.html

Ask if you have further questions.
0
 
ClearRockAuthor Commented:
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
0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

 
ClearRockAuthor Commented:
Just noticed another mistake in the code! Replaceing the last three lines...
// Rotate the shape using a method i have written elsewhere
Rotate(A);

Open in new window

0
 
ClearRockAuthor Commented:
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
0
 
ClearRockAuthor Commented:
I've solved my own problem now, using a bit of a hack, bet hey it works. Thanks for your suggestion anyway though
0
 
NovaDenizenCommented:
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
}

Open in new window

0
 
aburrCommented:
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
0
 
ClearRockAuthor Commented:
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.

0
 
ClearRockAuthor Commented:
I Closed it thinking i had a solution, when further testing revealed that i did not.
0
 
ClearRockAuthor Commented:
Thank you, worked first time ( after i actually read the bit at the bottom after 'where' ).
0
 
NovaDenizenCommented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.