tags:

views:

113

answers:

4

Hi am just doing a little animation which moves an object from point a to point b or by angle/radians.

what I currently have is this

Point CalcMove(Point pt, double angle, int speed)
    {
        Point ret = pt;

        ret.X = (int)(ret.X + speed * Math.Sin(DegToRad(angle)));
        ret.Y = (int)(ret.Y + speed * Math.Cos(DegToRad(angle)));

        return ret;
    }

but it doesn't look what i expected.

please help?

update:
oh and am using NETCF


CalcMove(Point pt, double angle, int speed)
"Point pt" is the current object location. "angle" is where the object should go. "speed" is the step.


so after days of work..
here's what I have worked on .. Neko for Windows Mobile 6.5

A: 

yes, your formula is incorrect a bit:

let's call the actual angle α and the angle you want to rotate to is β d is length of the line : d = sqrt(x*x + y*y)

To calculate new coordinates we need:

sin(α+β) = cos β sin α + sin β cos α

cos(α+β) = cos α cos β – sin α sin β

cos α = x / d sin α = y / d

New coords will be: x = sin(α+β)*d y = cos(α+β)*d

all together:

double d = Math.Sqrt(x*x + y*y);
double sina = pt.Y / d;
double cosa = pt.X / d;
double sinb = Math.Sin(DegToRad(angle));
double cosb = Math.Cos(DegToRad(angle));

ret.X = (int)(cosb*sina + sinb*cosa);
ret.Y = (int)(cosa*cosb - sina*sinb);
Andrey
thanks Andrey. Does this works when my angle is from 0 - 360? sorry for a very dumb question.. but where does x and y from "double d = Math.Sqrt(x*x + y*y);" will come from?
Nullstr1ng
they are pt.X and pt.Y
Andrey
More complicated than it needs to be.
Ed Swangren
A: 

For angle, the formula is: upwards-steps / rightwards-steps = tan (angle in degrees)

So, if you are wanting something to move at a 45° angle:

tan (45) = 1. Since 1= 1/1: move one pixel up for every one pixel moved right.

if you want to move something at a 35° angle: tan (35) = 0.7.... Since 0.7 = 1/0.7: move one pixel up for every 0.7 pixels right OR 10 pixels up for every 7 pixels right.

Note that trying to move 90° means moving infinity steps up for every step right (will move directly upwards), because tan(90) = ∞

update: Code sample to show what I mean. It works with a gradient of the line the point is to travel (rise over run):

Point CalcMove(Point pt, double angle, int speed)
    {
        Point ret = pt;
        if (angle == 90) { ret.Y += speed; }
        else if (angle == 270) { ret.Y -= speed; }
        else {
             ret.Y = (int)(ret.X + speed * Math.Tan(angle));
             ret.X = (int)(ret.Y + speed);
        }
        return ret;
    }

Note my error catching of tan(90) and tan(270)

Matt
what was that???
Andrey
I added a code sample to demonstrate
Matt
You can do this more easily with a simple rotation matrix.
Ed Swangren
This is also wrong when you consider the fact that Math.Tan takes its argument in raidans, not degrees. you don't need any special error handling when using a rotation like mine below.
Ed Swangren
ah well, got me there... :'(
Matt
Sorry! =) I feel bad voting down people who try to help, but there are more simple solutions to this.
Ed Swangren
I still have my dignity! My name is at http://wordpress.org/development/2010/06/thelonious/ forever ;)
Matt
Ahh, see, you've got me there; I know very little about web development being a systems engineer =)
Ed Swangren
+1  A: 

Use a rotation matrix. This code will move from a point (x,y) by theta radians to a new point (px, px)

Point Rotate(x, y, theta)
    int px = (x * Math.Cos(theta)) - (y * Math.Sin(theta));
    int py = (y * Math.Cos(theta)) + (x * Math.Sin(theta));
    return new Point(px, py);
end

The matrix used above,

[cosθ - sinθ][x]
[cosθ + sinθ][y]

Will move a point around the circle clockwise when using graphical coordinates.

I did the exact same thing last week. You can animate this by finding the total theta that you wish to move and then divide that by the number of frames (or steps). Now, start every move at some arbitrary point (for example, (0, radius)) and increment some counter totalSteps and move always beginning from that initial point. If you simply move the point itself each frame you will accumulate some error, but if you always move from the initial point by the current increment, stopping when the increment == totalTheta, it will be perfect. Let me know if that makes sense.

Maybe I should illustrate a bit more. Let's say you have a method "BeginMove":

double totalTheta = 0;
double increment = 0;
double currentTheta = 0;
bool moving = false;
void BeginMove()
{
    totalTheta = (2 * Math.PI) / numObjects;
    increment = totalTheta / steps;
    currentTheta = 0;
    moving = true;
}

Now you have a method which updates the move every frame:

void Update
{
    if (!moving) return;
    // do a min/max to ensure that you never pass totalTheta when incrementing.
    // there will be more error handling, but this is the basic idea.
    currentTheta += increment;
    SomeObject.Location = Rotate(0, radius, currentTheta);
    moving = (currentTheta < totalTheta);
}

There will obviously be more logic here depending upon your exact situation, but the idea is:

  1. Find the total theta to move.
  2. Find the increment (totalTheta / steps)
  3. Maintain a running total of how much you have moved already.
  4. Increment the running total by the angle increment before each move.
  5. Start each move from the same (arbitrary) point on the circle and rotate by the running total.
  6. Repeat until the running total == total theta.
Ed Swangren
will try this one too.
Nullstr1ng
I just did this last week for a video game project (a hobby of mine). It definitely works, so let me know if you run into any trouble.
Ed Swangren
will definitely try. creating new sample project now and will report back
Nullstr1ng
oh and does radius starts from 0(left) to 360?
Nullstr1ng
radius is the radius of your circle. I just chose an arbitrary location on the circle as a starting point. The point I chose would be the bottom-most point on the circle.
Ed Swangren
The important part is that you begin each move from the same starting point on the circle, wherever that may be.
Ed Swangren
Let me know if you have trouble and I will put together a functional example at lunch.
Ed Swangren
hey Ed. am very interested on your code. are you able to give a working C# sample project?
Nullstr1ng
Sure, I'll do it tomorrow at lunch. For now, bed.
Ed Swangren
hey Ed. this is what I was working on. Hope you like it :D (Windows Mobile 6.5 only) Neko Windows Mobile http://forum.xda-developers.com/showthread.php?t=705076
Nullstr1ng
Nice job! So I assume that you no longer need the sample?
Ed Swangren
Thanks Ed. I might still need it for better algo.
Nullstr1ng
A: 

after every test-fail of those suggested codes (shame on me).. I just came up with a very old solution.

to draw a circle per xypixel, here's a way I done it before back in TurboBasic(dos)

x = xcenter + radius * Cos(radian)
y = ycenter + radius * Sin(radian)

I applied the same idea by making xy center as the object location, radius is just a value the increments (per step), and the radian was calculated from the last xy object location and the destination xy

now I have my object that moves from point A to point B

Nullstr1ng