gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > How to rotate something around in a circle?

#140040 - Jeremysr - Wed Sep 12, 2007 11:59 pm

Should be pretty easy if I knew more math but I'm only in grade 10. So can someone explain to me how to rotate something around a certain point? (I'm trying to make a line rotate around one end, kind of like one of those radar... things.)

I'm using PAlib for this if it helps.

#140047 - kusma - Thu Sep 13, 2007 12:47 am

To make a radar-wipe-thingy: Draw a line from (cx,cy) to (cx + sin(theta) * radius, cy - cos(theta) * radius) where (cx, cy) is the center point for the rotation, theta is the rotation amount (a linear function of the time) and radius is, well, the radius of the radar ;)

#140153 - mml - Thu Sep 13, 2007 11:13 pm

This is pretty basic trigonometry, your grade 10 maths textbook probably has a chapter on it somewhere... :)

#140155 - Sukanu - Thu Sep 13, 2007 11:27 pm

One thing to check, make shure if the lib is using 0-2pi or 0-360 for theta, I know I made that mistake the first time I was coding with trig, most libs use the 0-2pi method.

#140166 - calcprogrammer1 - Fri Sep 14, 2007 12:44 am

I took trig last year (I'm in senior year now) and all this trig stuff seems to have escaped over the summer...and now I'm trying to program a calculator >.< The math.h library is useful to get your trig functions, and yes, they're in Radians mode (so that means, 0 to 2pi, with Pi usually being 3.14159.......look it up on a calculator or something). You can convert Radians to Degrees by doing this:

<degrees> = <radians> * ( 180 / pi )

And to use all this, make sure to include math:

#include <math.h> //math functions

Then you can use sin(), cos(), tan(), all that good stuff.
_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.


Last edited by calcprogrammer1 on Fri Sep 14, 2007 1:46 am; edited 1 time in total

#140169 - kusma - Fri Sep 14, 2007 1:22 am

calcprogrammer1 wrote:
with Pi usually being 3.1419

BRRRR! Try again! ;)
(I'm sure you mean 3.14159...etc)

#140171 - calcprogrammer1 - Fri Sep 14, 2007 1:46 am

calcprogrammer1 wrote:
and all this trig stuff seems to have escaped over the summer...


:P

I knew that some part of that post would be incorrect...though I remember that, must've just not hit the button right (Pi does equal 3.14159..., but I did say check your calculator to be sure :)
_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.

#140172 - Jeremysr - Fri Sep 14, 2007 1:49 am

Thanks everyone... I should have said exactly what I was trying to do because I'm not sure kusma's advice will help or not. The radar was just an example... what I want to do is use the stylus to rotate the line. So I thought of two methods I might be able to do it but still have trouble knowing how to do it.

1. Start drawing a line from one point to where the stylus is, but stop after a certain length of the line. But how do I know how long to draw the line? (I want it to stay the same length as it's rotated.)
2. Can I somehow figure out what amount/angle to rotate it by checking what position the stylus is at?

#140181 - calcprogrammer1 - Fri Sep 14, 2007 2:39 am

I'm thinking you could have a center point that you drag around, then you can use the Pythagorean theorem (a^2 + b^2 = c^2), the Law of Sines, Law of Cosines, etc to find the interior angle.

Code:

                     | 90 degrees, 1/2pi radians
                     |
                     |
                     |
<-----------------------------------> 0 degrees/ 0 radians
180 degrees,         |
pi radians           |
                     |
                     |
           270 degrees, 3/2pi radians


That's how you should interpret it, with the center at the middle of your angle thing. Draw a line from the center to the touched point, then drop a vertical line (use the X value of the touched point) to form a triangle. There's tons of trig you can now use to find the angle.

The angle you want is the one at the origin (center) point.
The "opposite" line is the farthest from the angle, it would be the line you drop from the point.
The "adjacent" line is the x-axis in this case, length is from origin to x value of touched point.
The "hypotenuse" is the angled line between the origin and the touched point. If you use the lengths of the other two lines (adj. and opp. lines) as A and B, then the length of the hypotenuse equals the square root of a^2 + b^2 (the Pythagorean theorem).
Code:

|     /|
|    / |
|   / ----------hypotenuse
|  /   |
| /    |-------opposite
|/     |     adjacent (x axis)
------------------------->

The angle can be found using these trig functions:
sin = opposite/hypotenuse
cos = adjacent/hypotenuse
tan = opposite/adjacent
_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.

#140183 - Jeremysr - Fri Sep 14, 2007 2:52 am

Ok, the only part I don't understand is how do I get the angle (of the final line I want to draw on the screen) once I have the lengths of those three lines?

#140185 - calcprogrammer1 - Fri Sep 14, 2007 3:02 am

Ok, I'm looking it up (I knew all this last year...but I forgot), I think, if you call the angle you're looking at A:

Code:

^        /|C
|       / |
|      /  |
|     /   |
|    /    |
|   /b    |a
|  /      |
| /       |
|/A      B|
-----------------
      c


You're trying to find angle A. To get angle A, you can use the Sine function:

sin A = opp/hyp

sin A = a/b

Correct me if I'm wrong, but if I remember correctly you use the arcsine function, sometimes called arcsin() or sin-1(), to do the opposite of Sine. This way, you'd take a (which is the Y position of the touched point minus the Y position of the center) and divide it by b (which you find using the Pythagorean theorem). Then you do the arcsin() of the resulting number to find the angle.

Capital letters represent angle measures (in Radians) and lowercase represent lengths of the lines.

You can convert that to degrees by multiplying by (180/pi).
_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.

#140187 - Jeremysr - Fri Sep 14, 2007 3:08 am

Thanks! I'll go try it out. :)

#140193 - Sukanu - Fri Sep 14, 2007 4:22 am

Actually I think a better way would be is convert to a pseudo polar cordiance(and this is if you are rotating around a tip)


Code:

^        /|B
|       / |
|      /  |
|     /   |
|    /    |
|   /     |
|  /      |
| /       |
|/A      C|
-----------------
       

I am going to use some janky use of BBcode to represent lines so where you see so you have AB that represents the line AB(I know the line should go on top but BBcode won't let me do that) and A represents point A and B alone represents point B

The first thing you need to do is find the length of your line

now you can use the Pythagorean theorem but since we cant assume that the user started their line at (0,0) we need to take the differences
Code:

Bx-Ax = Δx
By-Ay = Δy
(Δx)^2 + (Δy)^2 = AB^2

now AB is our radius

Now you need the starting theta, that is easy because you already have Δx and Δy you just use
Code:

theta = tan(Δy/Δx)

now we use
Code:
(Ax + sin(theta) * radius, Ay - cos(theta) * radius)

and that will give us our new end point to redraw our line, you just add or subtract to the theta to rotate.

#140194 - Jeremysr - Fri Sep 14, 2007 4:28 am

I just found a PAlib function where you give it two points on the screen and it returns the angle. Would that work instead of having to do all this math that I don't understand very good? :P

#140196 - Sukanu - Fri Sep 14, 2007 4:37 am

Jeremysr wrote:
I just found a PAlib function where you give it two points on the screen and it returns the angle. Would that work instead of having to do all this math that I don't understand very good? :P


Yes it will probibly have a function to give it two points and it will give you a length. use those two values to plug in to the last equation I gave to give you your new B point coords.

EDIT---

yep just use PA_Distance and sqrt it or PA_TrueDistance

to use the sites termonolgy
Code:

length = PA_TrueDistance (x1, y1, x2, y2)
angle = PA_GetAngle (x1, y1, x2, y2)     
x2 = x1 + sin(angle + yourChange) * length
y2 = y1 - cos(angle + yourChange) * length

#140197 - Jeremysr - Fri Sep 14, 2007 4:50 am

Right now I just need to get the angle of the end of the line to the position of the stylus. Then I can use that angle to rotate the line so it points to where the stylus is.

I'm not sure about this but it seems like you're showing me how to just make the line rotate, right?

#140198 - calcprogrammer1 - Fri Sep 14, 2007 4:56 am

I'm thinking you have like a circle or something on the touch screen, or something with a center point (like a radar). It's possible to just draw a line from the center point to wherever the touch point is (I forget how to check pen location in PAlib, but the PA_Draw16bitLine(screen,x1,y1,x2,y2,color); function should do what you want, if you just want to draw a line). You're saying angle, if you just want a line from one point to another, you don't need to calculate an angle. If you want to find the angle that a touch point is in relation to a point on the screen (say, how far around the circle you touch), then you can use trig functions to find the angle. If I knew more of what you wanted to do, I might know what to do.
_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.

#140199 - Sukanu - Fri Sep 14, 2007 4:57 am

Yea, I was showing how to rotate, look at my edits for updates. I am not sure if I understand the question now.

#140202 - Jeremysr - Fri Sep 14, 2007 5:12 am

Quote:
If you want to find the angle that a touch point is in relation to a point on the screen (say, how far around the circle you touch), then you can use trig functions to find the angle.


That's what I want to do.

I already have a line that can rotate like "radar" but I want the stylus to control the angle of it. I want the line to stay the same length, so I can't just draw it right to the stylus. It has to go towards the stylus but only be a certain length.

Here's some code that I thought would work, but Desmume freezes when it gets to PA_GetAngle() and my M3 won't even load the .nds...

Code:
   while (1) {
      if (Stylus.Newpress) {
            PA_Draw8bitLineEx(SCREEN_BOTTOM, 120, 95, x + sin(rot_amount) * 30, y - cos(rot_amount) * 30, 0, 5); // Erase old line
            rot_amount = (PA_GetAngle(120, 95, Stylus.X, Stylus.Y) >> 8) * 0.01252;
            PA_Draw8bitLineEx(SCREEN_BOTTOM, 120, 95, x + sin(rot_amount) * 30, y - cos(rot_amount) * 30, 1, 5);
            
            PA_WaitForVBL();
      }
      
      PA_WaitForVBL();
   }


(The 0.01252 is the same as 1 PAlib degree in the line-drawing code (which I got from kusma's first post))

#140205 - calcprogrammer1 - Fri Sep 14, 2007 5:23 am

If you can, stay away from the PA_ angle functions (I've had crashes using PA_sin() and such before, and reverted to using the math.h ones). Use the C math library instead (though it looks like you're using it already). GetAngle must do the same thing that I explained how to do with trig.

Hmm...

this isn't true C++, just pseudocode:

tan A = opp/adj (use this function to find the angle)
Code:

customGetAngle(x1, y1, x2, y2){

     adj = x2 - x1;
     opp = y2 - y1;
     angle = arctan(opp/adj);
     //convert to degrees
     angle = angle * (180/3.14159)//......and on and on, there may be a Pi constant
     return angle;
}


This is designed with the assumption of only using quadrant I (the positive-X, positive-Y quadrant), you might be able to use it in others, if not, you'd need to use an absolute-value on the points then modify it accordingly, but see if this works for quadrant I first.

I'm not sure, but that's how I'd do it. I think arctan() is a math function, it might be different though. Either way, you'll need to add this if you don't have it:

Code:

#include "math.h"

_________________
DS Firmware 1, Datel Games n' Music card / Chism's FW hacked GBA MP v2 CF

There's no place like 127.0.0.1.

#140216 - hi2u - Fri Sep 14, 2007 7:45 am

On a side note, unless you've covered this already, PAlib uses a different angle system.
_________________
hi2u

#140289 - tepples - Sat Sep 15, 2007 1:13 am

hi2u wrote:
On a side note, unless you've covered this already, PAlib uses a different angle system.

I've seen trig functions based on 256-part circles in a lot of places. FutureBASIC and BASIC Stamp call the unit of 1/256 circle a "brad". The fixed-point trig in the Allegro library also uses a 256-part circle. It would appear that the 512-part circle of PAlib is no harder to understand.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#140335 - Cearn - Sat Sep 15, 2007 1:16 pm

Since you don't seem to need a rotation, just a direction, you don't need angles at all. All you have to do is find the distance vector between the points and scale it down to your desired radius R.

Say you have two points, x0=(x0, y0) for the circle origin and the stylus point x1=(x1, y1). The difference will be dx= (dx, dy) = x1-x0. This will have a length L = sqrt(dx² + dy²). Dividing dx by L will give you a vector in the right direction of unit length; multiplying by the radius again gives a distance vector of the desired length. To avoid problems during the integer division, do the multiplication first: new dx= dx*R/L = (dx*R/L, dx*R/L). Since the DS has hardware division and square root, the routine should be quite fast if done this way.

Code (untested. I hope div32 gives signed results >_>)
Code:
int x0, y0, radius;      // circle origin and desired radius
int dx=0, dy=0, len;

while(1)
{
   if(Stylus.Presses)
   {
      // Erase old line
      PA_Draw8bitLineEx(SCREEN_BOTTOM, x0, y0, x0+dx, y0+dy, 0, 5);

      // Scale distance vector to radius length (also add something for div/0 plz)
      dx= Stylus.X - x0;
      dy= Stylus.Y - y0;
      len= sqrt32(dx*dx + dy*dy);
      dx= div32(dx*radius, len);
      dy= div32(dy*radius, len);
      
      // Draw new line
      PA_Draw8bitLineEx(SCREEN_BOTTOM, x0, y0, x0+dx, y0+dy, 1, 5);
   }
   PA_WaitForVBL();
}