Forum Moderators: open
I use sine waves a lot to calculate smooth animation, acceleration, deceleration, fading colour etc....
So I have the formula:
(object/coordinate/colour/other) is (travelling/fading) at (x) (pixels/steps) per (some time).
I know what I want the ending (location/speed/colour) to be, but what I need to know, is the time it will take to get there based on a sine wave. Is there a way of calculating it, or should I just stick with the way I am currently doing it - add up all values I get from the sine wave?
Hmmm, ok, lets take an actual reale worlde example.
I have an image. Lets say it's a little arrow or something. Now, when I hover the mouse over something I want the arrow to move at 300px per second.
I would use a sine wave to accelerate it over say 1/2 a second to smooth the motion.
Now, I have a specific point where I want the arrow to stop, I know the total distance it should have travelled, and I want it to take 1/2 a second to slow down and stop.
But how do I know when to begin deceleration? When the sine wave kicks in to start slowing down, how far will it travel before it stops?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset:utf-8">
<title></title>
</head>
<body>
<div id="container">
<input type="button" id="activate" value="Animate">
<div id="test" style="overflow:hidden;height:1em;width:1.5em;background-color:#f00;">--></div>
</div>
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.4.1/build/animation/animation-min.js"></script>
<script type="text/javascript">
YAHOO.util.Event.on(window, 'load', function() {
var myAnim = new YAHOO.util.Motion('test', {
points : { to : [0, 0] } // I decided to calculate this just before animation
}, 1, YAHOO.util.Easing.easeBoth); // Duration: 1 second, with easing to start and stop
YAHOO.util.Event.on('activate', 'click', function() {
// Calculate the motion
// Get the current X and Y location
var x = YAHOO.util.Dom.getX('test');
var y = YAHOO.util.Dom.getY('test');
// Determine how much to move it. In this example, I'm either moving it
// 300px to the right, or 300px to the left, depending on the current X.
var movepx = (x < 300? 300: -300);
myAnim.attributes.points = {
from : [x, y], to : [x + movepx, y]
};
myAnim.animate();
});
});
</script>
</body>
</html>
As far as the inner workings of this particular example, you might be able to look through the YUI code to see how they're doing it.
I have a specific point where I want the arrow to stop, I know the total distance it should have travelled, and I want it to take 1/2 a second to slow down and stop
The average speed while stoping will be pi/4 initial speed ( I think ).
So work out dist at initial speed over 1/2 sec and multiply by pi/4 (0.7853981634)
so if I understand your question correctly, you are interested in 'motion control' where you want to accelerate to certain speed, travel at constant speed for a while, and then decelerate to reach your wanted position (location).
There are few simple and complex ways to do this (and is well understood in some engineering disciplines). Simplest way is to use 'triangle' velocity profile - you linearly accelerate for half a distance and then you start to linearly decelerate until you reach your final position (if you plot velocity on y-axis and distance on the x-axis profile will look look a triangle, hence the name).
Another approach is to use "trapezoidal" (trap) velocity profile - you linearly accelerate for a short distance , continue to move at constant velocity for a while, and then linearly decelerate to final position (velocity profile depicts trapezoid hence the name :) )
You can also use sinusoidal profile...
From what you are describing ("...smoothly accelerate , travel at 300 px/s, smoothly decelerate...") my understanding is that you want "composite" profile. In your case - to use part of the sine curve to describe acceleration and deceleration, with constant velocity in between. However you are asking, for "time to do final smooth deceleration until you reach your final destination" - it's certainly possible to figure that out, but usually velocity profiles are thought of in terms of deceleration before reaching final position (final position value is known...and it seems that in your problem you know where flying arrow needs to stop).
Usually "composite" profiles are stitched together from , say, three different basic profiles, while monitoring acceleration (a), but you seem to want to express in in terms of distance. So you would say something like:
- while x is less then some distance (d) ["needed for smooth travel"]use sine velocity profile
-while x is equal to d but less then d1 ["dist. before smooth deceleration ] velocity is 300px/sec {some constant velocity]
- while x is equal to d1 but less then final distance use sine vel profile
above can be written nicer but I just wanted to show that you will have to use 3 formulas to describe the motion. Definitely possible, but perhaps too complex for the scenario you described - it will take bunch of code to describe motion (or maybe not, if you over simplified your example....). I would suggest to just use sine velocity profile, make sine period really big and use just 1/2 period. While the arrow will always accelerate or decelerate (no constant velocity) but with big enough period user looking at the arrow on the screen will not be able to tell the difference. So here are some formulas - you can use them to derive "composite" profile if you so wish)...
I am assuming that you know your final distance (or how long you want to travel). So here is some math and I'll try to simplify it a bit
sine formula in simplest form is given as:
y = A*(sin angle)
where
y is , in your case, velocity at certain angle (distance) during travel
A is maximum amplitude - in your case it would be either maximum velocity in pixels/sec (or constant velocity for composite profile)
we also know that velocity can be expressed as
v = distance / time
Now each wave has a period, which is time for a wave to complete one full cycle (generally - start at minimum (0) raises to max value goes to minimum vale and comes back to 0 ). Period is expressed in units of time (usually seconds).
Interestingly, you can describe a wave by it's wavelength - which is distance it takes a wave to complete one full cycle (note that it's same full cycle as described for above period - useful huh :) ). Note that wavelength is expressed in units of distance (nanometers, meters, or pixels in your case :) ).
Doing a little math, and rearranging basic sine formula and velocity formula, we come up with equation which can express velocity in terms of distance - that's what notation v(x) means
v(x) = A*sin ((2*pi*x) / wavelength)
Because we want to use only 'top' part of the sine wave, i.e only accelerate and then decelerate) AND we know the total distance traveled you can rewrite it as
v = A*sin ((2*pi*x)/ (2*D))
where
v - velocity value for a given distance during travel
A - maximum velocity ( say 300 pixels/sec)
x - is individual distance point (ex. if you want arrow to travel from 0 to 1000 pixels, x would be incremental values of 0,1,2,3,4,...998,999,1000; I used example with increment of 1 but you can change it to whatever suits you)
D - total distance traveled that you want (say 1000 pixels)
In your code limit x to maximum value of D to only get half a period.
HTH and makes sense :)
wow that's long!
to answer your question, remember that 1/4 cycle is 90 degrees which is pi/2.
so the area under a triangular wave would be pi/4 or about .785 and the area under a square wave is pi/2 or about 1.57 and the area under the sine wave is equal 1.0 for that period. (not 0.5 as i mistakenly wrote before)
therefore if the initial velocity is 10 inches/second and you stopped it in 0.5 seconds it will stop in 5 inches.
if the initial velocity is 10 inches/second and you stopped it in 0.5 seconds it will stop in 5 inches
if you left the velocity unchanged it will travel 5 inchs in 0.5 seconds.
the integral for a sin wave is 1 as you state, over a period of pi/2.
the integral of 1 (constant motion) over some period is pi/2
therfore ratio of sin vs const = 2/pi
In other worlds you need to divide integral by period to get average.
You can also use sinusoidal profile...
Yes, this is what I want.
You explained what I wanted a lot better than I did! One complete phase of the sine wave is up, down, down more, and up again.
What I'm using, as I'm sure many animators have done, is use the first 1/4 phase to speed up, the second quarter to slow down. So I'm left with a velocity curve that looks like an upside down. And yes, as per your suggestion I am using a variable to keep track of the curve, so I get to the top of the curve, then travel at constant speed, then switch back to the sinewave to do the second curve.
So, I guess what I'm asking, if I know the length of the profile, how do I calculate how long the sine parts will be?