![]() |
|
Failing to rotate a point around a central point |
David Sopala
Member #5,056
September 2004
|
As per my last post I got that problem solved, and I also read that website down near the bottom of the post as per Neil: http://www.helixsoft.nl/articles/circle/sincos.htm This gave me the though to add hit zones or collision circles that identify the hit zones on an object. Seemed simple enough I use a defining point of x,y and rotate that around a central point at the same rate as the image rotates. This is the code I wrote to accomplish my goal, I also have a function to draw green circles to show where the C_Circs are placed on the spider. Currently they aren't drawing correctly I get white circles, but I can see them(guessing it is a mode setting in my drawing routine or the alpha channel). After I use a key to rotate the spider the circles just disappear I assume this is because of some misinterpretation of the atan2 function or a misconversion to a fixed. Going to keep playing with it and see if I can find my error any help would be appreciated. EDIT: Found my circles decided to do a blit to force it to draw without alpha or masking(and learned even more from that!) For some reason the circles are stuck in the top left corner only in a couple rotation positions though. EDIT 2: Attached a copy of what is going on to help explain things. 1void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees)
2{
3 //all we need to do is update the center point (x,y) of the C_Circ
4 //find my current angle
5 //by normalizing the coordinates to the central point of rotation
6 fixed cur_angle = atan2(itofix(x-X),itofix(y-Y));
7 //add Degrees to current angle
8 cur_angle += itofix(Degrees);
9 cur_angle &= 0xFFFFFF;
10 //calculate new x,y from new angle
11
12 int length = sqrt((x-X)*(x-X) + (y-Y)*(y-Y));
13 x = length * fcos(cur_angle);
14 y = length * fsin(cur_angle);
15}
<img src="http://imgur.com/bfHvGkj.jpg" /> |
Johan Halmén
Member #1,550
September 2001
|
Wrong approach. You should not find any current angle, add rotation and use the new angle to find the new point. Theoretically it works, but there's a much shorter way. In your code you seem to forget to add back the center point. Anyway, here's what you should do: If I made an error, the idea should still be clear. Just check it all Ok, you're rotating around X, Y. Do what you did in your code (but don't forget the last part): Or uglify everything by not rotating around origin. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
David Sopala
Member #5,056
September 2004
|
After tinkering with the code I can explain my thought process as to why exactly I was doing things the way I was trying to accomplish them. Johan Halmén said: You should not find any current angle, add rotation and use the new angle to find the new point. The reasoning for that is one of my C_Circ classes may not start at 0 degrees of rotation. These are hit zones on a mob ex(Head shots, body shots, or other vital area shots). This class can potentially start anywhere that is possible in the sprite. Problem I have found: Length is returning inconsistant values for some reason making the points jump all over the place. Loading information into a C_Circ class: Class constructor: C_Circ::C_Circ(int X,int Y,int R) { x = X; y = Y; rad = R; } Here we have the monster rotation code I intend to switch over to vectors for my container, but the netbook I compile on when I am at work on break or whatever doesn't seen to have vector.h and I haven't remembered to copy it over. 1void Monster::Rotate_Left()
2{
3 if(abs(dr - r) > 4)
4 {
5 r -= 5;
6 for(int lcv = 0;lcv < num_col;lcv++)
7 {
8 Hit_Zones[lcv]->Rotate_Around_Point(ceil(MAGIC->w/2),ceil(MAGIC->h/2),r);
9 }
10 }
11 else
12 {
13 r -= abs(dr - r);
14 for(int lcv = 0;lcv < num_col;lcv++)
15 {
16 Hit_Zones[lcv]->Rotate_Around_Point(ceil(MAGIC->w/2),ceil(MAGIC->h/2),r);
17 }
18 }
19}
For the function call to rotate
EDIT: void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { //int Length = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); x = X + (X-x) * fixtoi(fcos(itofix(Degrees))) - (Y-y) * fixtoi(fsin(itofix(Degrees))); y = Y + (X-x) * fixtoi(fsin(itofix(Degrees))) + (Y-y) * fixtoi(fcos(itofix(Degrees))); //x = X + Length * fixtoi(fcos(itofix(Degrees))); //y = Y + Length * fixtoi(fsin(itofix(Degrees))); } EDIT #3:So I started outputting everything into a txt file so I could see what was going on.... What I learned: fixtoi(fsin(itofix(r))) or similar functions will give no precision guess I should have noticed int and not float or something similar... -1 0 1 are the only states given by this method might work for an 8 direction numpad type game, but not for anything with true angles. Rounding errors are going to be a nightmare as I watch the circles slowly move to the origin point as the sprite rotates now... huh<<"C: "<<lcv<<endl; huh<<"WIDTH OF BMP/2: "<<ceil(MAGIC->w/2)<<endl; huh<<"HEIGHT OF BMP/2: "<<ceil(MAGIC->h/2)<<endl; huh<<"HZ_X: "<<Hit_Zones[lcv]->Get_X()<<endl; huh<<"HZ_Y: "<<Hit_Zones[lcv]->Get_Y()<<endl; huh<<"ANGLE: "<<r<<endl; huh<<"SIN ANGLE: "<<fsin(itofix(r))<<endl; huh<<"COS ANGLE: "<<fcos(itofix(r))<<endl; huh<<"d65536 SIN ANGLE: "<<(float)fsin(itofix(r))/65536<<endl; huh<<"d65536 COS ANGLE: "<<(float)fcos(itofix(r))/65536<<endl; huh<<"F_SIN ANGLE: "<<fixtoi(fsin(itofix(r)))<<endl; huh<<"F_COS ANGLE: "<<fixtoi(fcos(itofix(r)))<<endl; huh<<"LENGTH: "<<sqrt((abs(ceil(MAGIC->w/2)-Hit_Zones[lcv]->Get_X()) * abs(ceil(MAGIC->w/2)-Hit_Zones[lcv]->Get_X())) + (abs(ceil(MAGIC->h/2)-Hit_Zones[lcv]->Get_Y()) * abs(ceil(MAGIC->h/2)-Hit_Zones[lcv]->Get_Y())))<<endl<<endl;
1C: 0
2WIDTH OF BMP/2: 45
3HEIGHT OF BMP/2: 45
4HZ_X: 30
5HZ_Y: 45
6ANGLE: -5
7SIN ANGLE: -8022
8COS ANGLE: 65043
9d65536 SIN ANGLE: -0.122406
10d65536 COS ANGLE: 0.992477
11F_SIN ANGLE: 0
12F_COS ANGLE: 1
13LENGTH: 15
14
15C: 1
16WIDTH OF BMP/2: 45
17HEIGHT OF BMP/2: 45
18HZ_X: 41
19HZ_Y: 45
20ANGLE: -5
21SIN ANGLE: -8022
22COS ANGLE: 65043
23d65536 SIN ANGLE: -0.122406
24d65536 COS ANGLE: 0.992477
25F_SIN ANGLE: 0
26F_COS ANGLE: 1
27LENGTH: 4
28
29C: 2
30WIDTH OF BMP/2: 45
31HEIGHT OF BMP/2: 45
32HZ_X: 61
33HZ_Y: 44
34ANGLE: -5
35SIN ANGLE: -8022
36COS ANGLE: 65043
37d65536 SIN ANGLE: -0.122406
38d65536 COS ANGLE: 0.992477
39F_SIN ANGLE: 0
40F_COS ANGLE: 1
41LENGTH: 16.0312
42
43C: 0
44WIDTH OF BMP/2: 45
45HEIGHT OF BMP/2: 45
46HZ_X: 0
47HZ_Y: 0
48ANGLE: 246
49SIN ANGLE: -15924
50COS ANGLE: 63572
51d65536 SIN ANGLE: -0.242981
52d65536 COS ANGLE: 0.970032
53F_SIN ANGLE: 0
54F_COS ANGLE: 1
55LENGTH: 63.6396
56
57C: 1
58WIDTH OF BMP/2: 45
59HEIGHT OF BMP/2: 45
60HZ_X: 0
61HZ_Y: 0
62ANGLE: 246
63SIN ANGLE: -15924
64COS ANGLE: 63572
65d65536 SIN ANGLE: -0.242981
66d65536 COS ANGLE: 0.970032
67F_SIN ANGLE: 0
68F_COS ANGLE: 1
69LENGTH: 63.6396
70
71C: 2
72WIDTH OF BMP/2: 45
73HEIGHT OF BMP/2: 45
74HZ_X: 0
75HZ_Y: 0
76ANGLE: 246
77SIN ANGLE: -15924
78COS ANGLE: 63572
79d65536 SIN ANGLE: -0.242981
80d65536 COS ANGLE: 0.970032
81F_SIN ANGLE: 0
82F_COS ANGLE: 1
83LENGTH: 63.6396
FINAL EDIT: Finally got the issues fixed. Instead of recalculating the length every time(which was introducing rounding issues). Getting rid of the recalculating length fixed most of the issues, just had to do a little bit of sign preservation. void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { if(RX != X || RY != Y) //Not the same rotation point! { RX = X; RY = Y; RL = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); if(X - x > 0)RL *= -1; if(Y - y < 0)RL *= -1; } x = X + (int)(RL * (double)fcos(itofix(Degrees)) / 65536); y = Y + (int)(RL * (double)fsin(itofix(Degrees)) / 65536); }
<img src="http://imgur.com/bfHvGkj.jpg" /> |
Johan Halmén
Member #1,550
September 2001
|
David Sopala said: The reasoning for that is one of my C_Circ classes may not start at 0 degrees of rotation. Irrelevant. You have a point (x, y) and you want to rotate it around point (X, Y) by an angle Degrees, right? And if you want speed, you should calculate cos and sin only once:
As for rounding errors, use doubles, not ints. X and Y may be ints, if they really are just screen coordinates. But x and y, if they define your object position which change through rotation and whatnot, should be doubles. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
David Sopala
Member #5,056
September 2004
|
I wasn't having as much of a problem with the sin / cos rounding, but the sqrt rounding was coming out of no where. I think this solution is faster than yours even assuming I rotate around one point at a time. David Sopala said:
FINAL EDIT: void C_Circ::Rotate_Around_Point(int X,int Y,int Degrees) { if(RX != X || RY != Y) //Not the same rotation point! { RX = X; RY = Y; RL = sqrt((abs(X-x)*abs(X-x))+(abs(Y-y)*abs(Y-y))); if(X - x > 0)RL *= -1; if(Y - y < 0)RL *= -1; } x = X + (int)(RL * (double)fcos(itofix(Degrees)) / 65536); y = Y + (int)(RL * (double)fsin(itofix(Degrees)) / 65536); }
<img src="http://imgur.com/bfHvGkj.jpg" /> |
SiegeLord
Member #7,827
October 2006
![]() |
David Sopala said: I think this solution is faster than yours even assuming I rotate around one point at a time. His solution has one call to sin and cos, while yours has one call to sin and cos and one call to sqrt. How can it possibly be faster? "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
verthex
Member #11,340
September 2009
![]() |
SiegeLord said: How can it possibly be faster? The inverse square root function using that special number with Newtons method might work.
|
David Sopala
Member #5,056
September 2004
|
Mine calls that once assuming one point of rotation. If I recall my asm a compare is a 4 tick command which TBH would be faster than the extra casting calls and the like. His code is also flawed in the fact that Degrees in 0 - 256 so it is missing the conversion there not a big thing. My sqrt only occurs in the first itteration, after that it does not get called again untill we change our rotation point(which never changes as it is the center of the sprite and not a position in the world.) While each sprite has hit zones, they each have a master zone which is used in world calculations. Either code works I think, but origonally his code did not work, and neither did mine I had fixed the issue only to find a few days later that there are replys which I am grateful for as it does help to see from a different point of view. I would rather post my code and get it working my way if it is possible then be shown another possibly more efficent way. I had reffered to his origonal post with 2xsin and 2xcos one call to sqrt(since that part of the code never changes the rotation point) and only one call to cos and sin each seemed alot better. To show what has been accomplished I am attaching an exe. Still need to tweak the movement a little since the spider seems to have issues getting to the correct point when he is walking(a bit of walking sideways apparently fixes that, but looks horrible) <img src="http://imgur.com/bfHvGkj.jpg" /> |
Schyfis
Member #9,752
May 2008
![]() |
I just use this: public void rotateAboutPoint(Location point, float r) { float n = dist(point.getX(), point.getY(), getX(), getY()); float a = point.getX() - getX(), b = point.getY() - getY(); r -= (float)(Math.Atan2(b, a)); moveTo(point.getX() - (float)(n * Math.Cos(r)), point.getY() + (float)(n * Math.Sin(r))); } It's probably slow, but it works just fine and is easy to understand. ________________________________________________________________________________________________________ |
David Sopala
Member #5,056
September 2004
|
Isn't atan2 undefined for angle = 0? I know that was in the reading I did... <img src="http://imgur.com/bfHvGkj.jpg" /> |
Johan Halmén
Member #1,550
September 2001
|
atan2(a, b) is probably undefined when a and b both equal 0. Schyfis said: and is easy to understand Well, go through this: Now you can add r1 and r2... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Years of thorough research have revealed that what people find beautiful about the Mandelbrot set is not the set itself, but all the rest. |
|