[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

How can i find a negitive angle from three points

Posted on 2009-04-22
12
Medium Priority
?
379 Views
Last Modified: 2012-05-06
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

0
Comment
Question by:ClearRock
  • 7
  • 2
  • 2
  • +1
12 Comments
 
LVL 25

Expert Comment

by:InteractiveMind
ID: 24205431
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
 

Author Comment

by:ClearRock
ID: 24205601
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
 

Author Comment

by:ClearRock
ID: 24205663
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:ClearRock
ID: 24205797
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
 

Author Comment

by:ClearRock
ID: 24206327
I've solved my own problem now, using a bit of a hack, bet hey it works. Thanks for your suggestion anyway though
0
 
LVL 22

Expert Comment

by:NovaDenizen
ID: 24206977
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
 
LVL 25

Accepted Solution

by:
InteractiveMind earned 1000 total points
ID: 24207012
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
 
LVL 27

Expert Comment

by:aburr
ID: 24207281
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
 

Author Comment

by:ClearRock
ID: 24212779
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
 

Author Comment

by:ClearRock
ID: 24212802
I Closed it thinking i had a solution, when further testing revealed that i did not.
0
 

Author Closing Comment

by:ClearRock
ID: 31573299
Thank you, worked first time ( after i actually read the bit at the bottom after 'where' ).
0
 
LVL 22

Expert Comment

by:NovaDenizen
ID: 24216579
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

How to Use the Help Bell

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.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Suggested Courses
Course of the Month19 days, 4 hours left to enroll

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question