Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
I started adding on to a program I use that will convert a bunch of stills images in to an mp4 video file.

i have one large NSImage that is 5120 x 720. At each frame I adjust the NSRect x.origin to slide the image a little. The image needs to move 1280 pixels over 30 frames. By just dividing these values I get an x.origin value 42.666.... I am trying to accelerate and decelerate the image over 30 frames? Dividing them gives me a constant speed, I am looking to ramp up and then down the velocity over time.

I did a google search on acceleration and get lots of mathematical equations but I am at a loss for converting this to code? I have Time and Distance but can't seem to get figure out the multiplier?

Here is the code so far, not that it really makes a difference to the question.

Code:
#import "FramesGenerator.h"

@implementation FramesGenerator
@synthesize importImage, frameNumber;

-(void)startProcess{
    frameSlideSpeed = 42.666;
    if (!framesArray) {
        framesArray = [[NSMutableArray alloc]init];
    }
   
    for (int i = 0; i < totalFrames; i++) {
        [self createFrame];
    }
}

-(void)createFrame{
    NSImage *toSaveImage = [[NSImage alloc] initWithSize:CGSizeMake(1280, 720)]; // image to save after created.
    [toSaveImage lockFocus]; //prep for writing to layer
    [importImage drawInRect:NSMakeRect((frameSlideSpeed * frameNumber) * -1, 0, 1280 * 4, 720) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
    [toSaveImage unlockFocus];
    frameNumber++; // starts with 1
    [framesArray addObject:toSaveImage];
}

@end
 
This may be best explained by an example. The table below show the acceleration, velocity (integral of acceleration), and position (integral of velocity) for each frame using a constant acceleration of +5 pixels/frame for the first 15 frames, and then -5 pixels/frame for the last 15 frames.

Frame Acceleration Velocity Position
0 0 0 0
1 5 5 5
2 5 10 15
3 5 15 30
4 5 20 50
5 5 25 75
6 5 30 105
7 5 35 140
8 5 40 180
9 5 45 225
10 5 50 275
11 5 55 330
12 5 60 390
13 5 65 455
14 5 70 525
15 5 75 600
16 -5 70 670
17 -5 65 735
18 -5 60 795
19 -5 55 850
20 -5 50 900
21 -5 45 945
22 -5 40 985
23 -5 35 1020
24 -5 30 1050
25 -5 25 1075
26 -5 20 1095
27 -5 15 1110
28 -5 10 1120
29 -5 5 1125
30 -5 0 1125

At each frame the new velocity is the sum of the previous velocity and the current acceleration, and the new position is the sum of the previous position and the new velocity. You can see that the velocity in pixels/frame ramps up from 0 to 75, and then down from 75 back to 0 over the course of the 30 frames. At the same time the position increase from 0 to 1125.

This is an example of Euler numerical integration.

To get the image to move some specific number of pixels you will have to vary the acceleration and deceleration. The deceleration does not have to be the same as the acceleration. To have the image stop smoothly at the end frame the velocity must be 0, so the integral of the positive acceleration must be equal to the integral of the negative acceleration. You could accelerate twice as hard as you decelerate, but you would have to decelerate twice as long to get back to zero velocity.

HTH
 
This may be best explained by an example. The table below show the acceleration, velocity (integral of acceleration), and position (integral of velocity) for each frame using a constant acceleration of +5 pixels/frame for the first 15 frames, and then -5 pixels/frame for the last 15 frames.

Frame Acceleration Velocity Position
0 0 0 0
1 5 5 5
2 5 10 15
3 5 15 30
4 5 20 50
5 5 25 75
6 5 30 105
7 5 35 140
8 5 40 180
9 5 45 225
10 5 50 275
11 5 55 330
12 5 60 390
13 5 65 455
14 5 70 525
15 5 75 600
16 -5 70 670
17 -5 65 735
18 -5 60 795
19 -5 55 850
20 -5 50 900
21 -5 45 945
22 -5 40 985
23 -5 35 1020
24 -5 30 1050
25 -5 25 1075
26 -5 20 1095
27 -5 15 1110
28 -5 10 1120
29 -5 5 1125
30 -5 0 1125

At each frame the new velocity is the sum of the previous velocity and the current acceleration, and the new position is the sum of the previous position and the new velocity. You can see that the velocity in pixels/frame ramps up from 0 to 75, and then down from 75 back to 0 over the course of the 30 frames. At the same time the position increase from 0 to 1125.

This is an example of Euler numerical integration.

To get the image to move some specific number of pixels you will have to vary the acceleration and deceleration. The deceleration does not have to be the same as the acceleration. To have the image stop smoothly at the end frame the velocity must be 0, so the integral of the positive acceleration must be equal to the integral of the negative acceleration. You could accelerate twice as hard as you decelerate, but you would have to decelerate twice as long to get back to zero velocity.

HTH
Thanks, that seems to easy? I don't know why I was looking for a more complicated solution. I will try it out now. That solution will be a linear motion but should work fine. Thanks for taking the time!
 
This may be best explained by an example. The table below show the acceleration, velocity (integral of acceleration), and position (integral of velocity) for each frame using a constant acceleration of +5 pixels/frame for the first 15 frames, and then -5 pixels/frame for the last 15 frames.

Frame Acceleration Velocity Position
0 0 0 0
1 5 5 5
2 5 10 15
3 5 15 30
4 5 20 50
5 5 25 75
6 5 30 105
7 5 35 140
8 5 40 180
9 5 45 225
10 5 50 275
11 5 55 330
12 5 60 390
13 5 65 455
14 5 70 525
15 5 75 600
16 -5 70 670
17 -5 65 735
18 -5 60 795
19 -5 55 850
20 -5 50 900
21 -5 45 945
22 -5 40 985
23 -5 35 1020
24 -5 30 1050
25 -5 25 1075
26 -5 20 1095
27 -5 15 1110
28 -5 10 1120
29 -5 5 1125
30 -5 0 1125

At each frame the new velocity is the sum of the previous velocity and the current acceleration, and the new position is the sum of the previous position and the new velocity. You can see that the velocity in pixels/frame ramps up from 0 to 75, and then down from 75 back to 0 over the course of the 30 frames. At the same time the position increase from 0 to 1125.

This is an example of Euler numerical integration.

To get the image to move some specific number of pixels you will have to vary the acceleration and deceleration. The deceleration does not have to be the same as the acceleration. To have the image stop smoothly at the end frame the velocity must be 0, so the integral of the positive acceleration must be equal to the integral of the negative acceleration. You could accelerate twice as hard as you decelerate, but you would have to decelerate twice as long to get back to zero velocity.

HTH
This code gets me close to 1280. Seems like there would be a more elegant way of doing this, but it works?

Code:
for (int i = 0; i < 30; i++) {
        if (i < 15) { // speed up for first 15 frames
            speed = incramentor++ * 5.75 + lastSpeed;
            lastSpeed = speed;
        }
        else{
            speed = (incramentor-- * 5.75) + lastSpeed;
            lastSpeed = speed;
        }
        currentPosition = speed * -1; // need the image to move to the left so I multiply the results by -1
        pIntArray[counter] = currentPosition; // store the values in an C int Array
        counter++;
   }
 
Here's a simple solution:



Take your standard (x,y) coordinate axes and change them to (t,v), time and velocity. If you travel a constant velocity v0 to some time t0, and if you graph this, you end up with a nice little box whose area represents the distance you just traveled since distance = velocity * time. The shape doesn't have to be a rectangle. Your velocity can vary up and down over the course of your travel time and the area under the curve will always represent the distance traveled. The slope of the line (or slope of the tangent line if it's a curve) represents the acceleration since that is equal to the rate of change of velocity with respect to time.



You probably want a trapezoid. Start at (0,0), accelerate upwards at constant rate for a period of time, level off the velocity for awhile, and then decelerate back to zero -- (30, 0) in your case. The area of this trapezoid will be 1280. You will probably wish to accelerate and decelerate for the same amount of time, although you certainly don't have to. For this example, I will assume you will wish to accelerate, maintain a constant velocity and decelerate over a time period of 10 frames each.



Google "area of a trapezoid". There they provide you with an area of a trapezoid calculator. The base of the trapezoid b is your total time of 30 frames. The top of the trapezoid a represents the time spent traveling at a constant velocity. The slope of c is your acceleration and the slope of d is your deceleration. (The lengths of c and d are irrelevant other than the fact the length of their horizontal components = the time spent accelerating or decelerating.) The height of the trapezoid h represents the constant velocity you'll be traveling at after you've stopped accelerating.



Given Area A = (a+b)/2 * h, we can rewrite that to h = 2*A/(a+b). Thus, h = 2*1280/(10+30) = 64, which is your constant velocity in pixels per frame. Now since you're accelerating over a time of 10 frames, your acceleration during these 10 frames will be the slope of c = h/10 = 6.4 pixels per frame per frame. Your initial velocity will start at zero, and for the first 10 frames you will add 6.4 to it. For the next 10 frames, your acceleration goes to zero and your velocity will remain constant, and for the last 10 frames your acceleration goes to -6.4 and you continue to add this to the velocity. The distance traveled each frame is equal to the velocity at that time (d = v when time = 1), and of course the cumulative distance traveled is the sum of these velocities.



Here's the chart: (frame, acceleration, velocity, distance)

v = previous v + previous a

d = previous d + current velocity



f a v d

0 6.4 0 0

1 6.4 6.4 6.4

2 6.4 12.8 19.2

3 6.4 19.2 38.4

4 6.4 25.6 64

5 6.4 32 96

6 6.4 38.4 134.4

7 6.4 44.8 179.2

8 6.4 51.2 230.4

9 6.4 57.6 288

10 0 64 352

11 0 64 416

12 0 64 480

13 0 64 544

14 0 64 608

15 0 64 672

16 0 64 736

17 0 64 800

18 0 64 864

19 0 64 928

20 -6.4 64 992

21 -6.4 57.6 1049.6

22 -6.4 51.2 1100.8

23 -6.4 44.8 1145.6

24 -6.4 38.4 1184

25 -6.4 32 1216

26 -6.4 25.6 1241.6

27 -6.4 19.2 1260.8

28 -6.4 12.8 1273.6

29 -6.4 6.4 1280

30 -6.4 0 1280


So why is v = 0 at frame 30 and d = 1280 at frame 30? It's just the way I've got it set up. Your 30 frames are actually frames 0 - 29. v is actually the velocity at the beginning of that frame which equals the velocity at the "end" of the previous frame, so I included a frame 30 just to show that the velocity did indeed go to 0. (Or 1.776E-15 if you prefer.) Your last frame (frame 29) should reflect the final distance and it does.

How's the artillery game coming along?
 
Last edited:
Here's a simple of solution:



Take your standard (x,y) coordinate axes and change them to (t,v), time and velocity. If you travel a constant velocity v0 to some time t0, and if you graph this, you end up with a nice little box whose area represents the distance you just traveled since distance = velocity * time. The shape doesn't have to be a rectangle. Your velocity can vary up and down over the course of your travel time and the area under the curve will always represent the distance traveled. The slope of the line (or slope of the tangent line if it's a curve) represents the acceleration since that is equal to the rate of change of velocity with respect to time.



You probably want a trapezoid. Start at (0,0), accelerate upwards at constant rate for a period of time, level off the velocity for awhile, and then decelerate back to zero -- (30, 0) in your case. The area of this trapezoid will be 1280. You will probably wish to accelerate and decelerate for the same amount of time, although you certainly don't have to. For this example, I will assume you will wish to accelerate, maintain a constant velocity and decelerate over a time period of 10 frames each.



Google "area of a trapezoid". There they provide you with an area of a trapezoid calculator. The base of the trapezoid b is your total time of 30 frames. The top of the trapezoid a represents the time spent traveling at a constant velocity. The slope of c is your acceleration and the slope of d is your deceleration. (The lengths of c and d are irrelevant other than the fact the length of their horizontal components = the time spent accelerating or decelerating.) The height of the trapezoid h represents the constant velocity you'll be traveling at after you've stopped accelerating.



Given Area A = (a+b)/2 * h, we can rewrite that to h = 2*A/(a+b). Thus, h = 2*1280/(10+30) = 64, which is your constant velocity in pixels per frame. Now since you're accelerating over a time of 10 frames, your acceleration during these 10 frames will be the slope of c = h/10 = 6.4 pixels per frame per frame. Your initial velocity will start at zero, and for the first 10 frames you will add 6.4 to it. For the next 10 frames, your acceleration goes to zero and your velocity will remain constant, and for the last 10 frames your acceleration goes to -6.4 and you continue to add this to the velocity. The distance traveled each frame is equal to the velocity at that time (d = v when time = 1), and of course the cumulative distance traveled is the sum of these velocities.



Here's the chart: (frame, acceleration, velocity, distance)

v = previous v + previous a

d = previous d + current velocity



f a v d

0 6.4 0 0

1 6.4 6.4 6.4

2 6.4 12.8 19.2

3 6.4 19.2 38.4

4 6.4 25.6 64

5 6.4 32 96

6 6.4 38.4 134.4

7 6.4 44.8 179.2

8 6.4 51.2 230.4

9 6.4 57.6 288

10 0 64 352

11 0 64 416

12 0 64 480

13 0 64 544

14 0 64 608

15 0 64 672

16 0 64 736

17 0 64 800

18 0 64 864

19 0 64 928

20 -6.4 64 992

21 -6.4 57.6 1049.6

22 -6.4 51.2 1100.8

23 -6.4 44.8 1145.6

24 -6.4 38.4 1184

25 -6.4 32 1216

26 -6.4 25.6 1241.6

27 -6.4 19.2 1260.8

28 -6.4 12.8 1273.6

29 -6.4 6.4 1280

30 -6.4 0 1280


So why is v = 0 at frame 30 and d = 1280 at frame 30? It's just the way I've got it set up. Your 30 frames are actually frames 0 - 29. v is actually the velocity at the beginning of that frame which equals the velocity at the "end" of the previous frame, so I included a frame 30 just to show that the velocity did indeed go to 0. (Or 1.776E-15 if you prefer.) Your last frame (frame 29) should reflect the final distance and it does.

How's the artillery game coming along?
Hey, thanks for that detailed explanation! I have been gone this weekend but look forward to rewriting this code this week.

The artillery game, Castles & Canons!!! I was making good progress with that. It was tough coming up with an AI to play against and making an AI is still a bit complicated. Got graphics from an artist friend of mine. Then one day I sat Cocos 2D and working with sprites seemed easier so I started to recode for Sprites and they had some physics that I could tap into as well. As I was getting into that Apple released their sprite kit and made working with physics MUCH easier. But at that point I had already started with Cocos 2D so I started adding and changing code for SpriteKit.

I don't seem to have the time to write code faster then Apple and everyone updates code and makes new frameworks. I struggled with Canon Ball math and now with physics I don't need it.

As I work on larger projects I can see how beneficial it would be to work within a team to get projects finished. I barely write code faster then it gets depreciated. :)

I will return to it soon though, thanks for asking!
 
Thanks Vegard7, I got it working this morning perfectly. I don't know why but it took me a couple days to wrap my head around this concept but I get it now.

Thanks!
 
Thanks Vegard7, I got it working this morning perfectly. I don't know why but it took me a couple days to wrap my head around this concept but I get it now.

Thanks!

Glad to have helped. If, after you've worked on your artillery game some more, you repost an update on where you're at with your physics I might throw in my two cents. I'm unfamiliar with Cocos 2D and its physics engine, so I wouldn't be able to be of any help there. And since I'm evil: have an airplane fly over and try shooting it down with your cannon's AI. And no cheating (e.g. limit your shell's velocity to 4 times the airplane's velocity, and don't shoot dozens of rounds over a variety of angles -- shoot only one round every few seconds at where you calculate the airplane will be.) Good fun.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.