views:

517

answers:

5

I'm trying to add a fade effect to my form by manually changing the opacity of the form but I'm having some trouble calculating the correct value to increment by the Opacity value of the form.

I know I could use the AnimateWindow API but it's showing some unexpected behavior and I'd rather do it manually anyways as to avoid any p/invoke so I could use it in Mono later on.

My application supports speeds ranging from 1 to 10. And I've manually calculated that for a speed of 1 (slowest) I should increment the opacity by 0.005 and for a speed of 10 (fastest) I should increment by 0.1. As for the speeds between 1 and 10, I used the following expression to calculate the correct value:

double opSpeed = (((0.1 - 0.005) * (10 - X)) / (1 - 10)) + 0.1; // X = [1, 10]

I though this could give me a linear value and that that would be OK. However, for X equal 4 and above, it's already too fast. More than it should be. I mean, speeds between 7 and 10, I barely see a difference and the animation speed with these values should be a little more spaced

Note that I still want the fastest increment to be 0.1 and the slowest 0.005. But I need all the others to be linear between them.

What I'm doing wrong?

EDIT: It actually makes sense why it works like this, for instance, for a fixed interval between increments, say a few milliseconds, and with the equation above, if X = 10, then opSpeed = 0.1 and if X = 5, then opSpeed = 0.47. If we think about this, a value of 0.1 will loop 10 times and a value of 0.47 will loop just the double. For such a small interval of just a few milliseconds, the difference between these values is not that much as to differentiate speeds from 5 to 10.

+5  A: 
Suvesh Pratapa
I just tried it and the same problem happens. I barely see a difference in speed between 6 and 10. I think the problem *is* the linear scale that it doesn't work so good for opacity animations.
Nazgulled
You can try something inventive, a decreasing geometric series, perhaps?
Suvesh Pratapa
Can you work out an intermediate value around 5 or something, this would help for finding some sort of nonlinear scale.
Jacob Schlather
A very crazy idea, but do you want to try this?0.005 * (pow(20,1/9)^(X-1))Results in a geometric variation corresponding to 0.005 when X = 1 and 0.1 when X = 10
Suvesh Pratapa
Shouldn't have two pow()'s there? If so, it always results in 0.005. Anyway, I've updated my first post.
Nazgulled
And from a quick test, I'd say that a value of 0.01 would be fine for X = 5. Maybe I'm better off calculating each one of them manually and just code a switch().
Nazgulled
The two pow()s are a result of me trying to raise the 9th root of 20 to X-1.If it is unbelievably complex to implement, forget it. You're right, a manual calculation should save you long term hassle. :)
Suvesh Pratapa
Well, I maybe have applied your suggestion in a wrong way because the result was always 0.005 no matter the value of X. But looking here htpp://tinyurl.com/lnmeuk (Wolfram Alpha link) shows the type of a graph that might just be what I'm looking for. I'll have to double check it...
Nazgulled
Well the graph confirms that it's the right equation for a geometric series. Check for floating point errors.
Suvesh Pratapa
It's almost there... Your solution seems to work much better, however, I've manually tested all 10 values and found that something more like this http://i41.tinypic.com/9v8lqg.jpg would work much better. The left one is your initial solution, the right one was the values I calculated manually. The graph is not perfect because it was drawn in Photoshop. Could you come up with something to match the red graph? Also notice that the values for X=1 and x=10 have changed a bit...
Nazgulled
Try:0.004 * (18.75^((X-1)/9)))and let me know if it works.
Suvesh Pratapa
It still looks too much alike your initial one: http://tinyurl.com/nc393g. The graph needs to be more like the one I drew.
Nazgulled
Hmm, give me some time. I'll get back to you.
Suvesh Pratapa
I'm trying various curve fitting methods to come up with something meaningful given your set of data. It's not trivial, so you should try to do that too in the meantime.
Suvesh Pratapa
Once again, Wolfram|Alpha to the rescue, I haven't realized how powerful it is. With a few keywords from your comments I searched a bit and I guess this is what I want: http://tinyurl.com/lthn9v? What do you think? I'll still mark this one as the correct answer cause it's the best one.
Nazgulled
Yes! This is exactly what you're looking for! :DWOW! I didn't realize Wolfram|Alpha did that, I was trying my paper and pencil curve fitting methods.And funnily, I was coming close to an answer like that.Anyway, congrats! :)
Suvesh Pratapa
Confirmation that that equation is what you're looking for: http://tinyurl.com/m6kf8r
Suvesh Pratapa
I actually didn't know that Wolfram|Alpha did that but I only assumed it did because the Mathemathica software is very powerful. But I found it by searching "curve fitting" in Wolfram, which shows various examples to achieve different things and just went from there. Search for "curve fitting" and you'll see what I mean.
Nazgulled
It ain't working as it should... Using the latest Suvesh's tinyurl, replace X by 1 and you'll see the value is way smaller than what's supposed to be. Replacing by 10, gives a value pretty much close to the one I want but not exactly. I don't understand why... The plot seems correct, why replacing the X value does not work as it should?
Nazgulled
As I said, there is some error usually due to curve fitting methods. This is due to the fact that are infinitely many curve equations possible for a given set of points. What Wolfram|Alpha tried to do was give you an approximation of the equation you were looking for. There is bound to be an error. I'm sorry but I guess you have no other choice. That's how curve fitting works.
Suvesh Pratapa
Then I can't use this solution because the value that that equation gives me when X = 1, it's waaaaaaaaaaaay too slow. The form would take like more than 2 minutes or so to completely show. I think I'll be better off with a switch() and put the values manually.
Nazgulled
I think so. Because if you could come up with the perfect curve given any set of points, you would've solved a centuries-old problem. There are some software packages that do this with really small error though, so if you have the time, try investing in them.
Suvesh Pratapa
+1  A: 

Here's how I'd program that linear relationship. But first I'd like to make clear what I think you're doing.

You want the rate of change in opacity to be a linear function of speed:

o(v) = o1*N1(v) + o2*N2(v) so that 0 <= v <=1 and o(v1) = o1 and o(v2) = o2.

If we choose N1(v) to equal 1-v and N2(v) = v we end up with what you want:

o(v) = o1*(1-v) + o2*v

So, plugging in your values:

v = (u-1)/(10-1) = (u-1)/9

o1 = 0.005 and o2 = 0.1

So the function should look like this:

  1. o(u) = 0.005*{1-(u-1)/9} + 0.1*(u-1)/9
  2. o(u) = 0.005*{(9-u+1)/9} + 0.1*(u-1)/9
  3. o(u) = 0.005*{(10-u)/9} + 0.1(u-1)/9

You can simplify this until you get a simple formula for o(u) where 1 <= u <= 10. Should work fine.

duffymo
oh wow, that's unbelievably complex
Carson Myers
Yeah a little bit complex for a guy stupid in math like me :P
Nazgulled
Not really, they're just simple linear shape functions and a little algebra. What's so hard? 8)
duffymo
It's hard enough that I didn't get it and got all other answers lol... But nevermind, the solution is not a linear equation.
Nazgulled
+1  A: 

If I understand what you're after, you want the equation of a line which passes through these two points in the plane: (1, 0.005) and (10, 0.1). The general equation for such a line (as long as it is not vertical) is y = ax+b. Plug the two points into this equation and solve the resulting set of two linear equations to get

 a = (0.1 - 0.005) / 9 = 0.010555555555...
 b = 0.005 - a        = -0.00555555555...

Then, for each integer x = 1, 2, 3, ..., 10, plug x into y = ax+b to compute y, the value you want.

+4  A: 

Your problem stems from the fact that the human eye is not linear in its response; to be precise, the eye does not register the difference between a luminosity of 0.05 to 0.10 to be the same as the luminosity difference between 0.80 and 0.85. The whole topic is complicated; you may want to search for the phrase "gamma correction" for some additional information. In general, you'll probably want to find an equation which effectively "gamma corrects" for human ocular response, and use that as your fading function.

McWafflestix
perhaps he should apply log to the opacity value just before setting it?
Breton
I accept that the human eye may play it's part on this, but I don't think the problem lies there. Although the luminosity of 0.05 to 0.10 may be different from the one between 0.80 and 0.85, I fail to see what that got to do with my problem. In a linear equation, the opacity increment value when X=6 (for instance) is already too high (for what I want) and the animation will loop just a few times before it reaches 1.0. This makes sense and it doesn't have to do with luminosity. I think this equation (http://tinyurl.com/lnmeuk) might solve my problem, I'll have to check it again.
Nazgulled
+2  A: 
tom10
nicely done. i didn't check him; i assumed it was a simple algebra error. i wanted to take a different approach just in case an alternative would expose the error. but your take on it is correct and very helpful.
duffymo
nice use of python as well. i need to think of it more for problems like this.
duffymo
Thanks. And I find Python to be great for this type of thing. It's fast and easy on the small problems but then scales really well for the large ones.
tom10
Thanks for that, could you edit that graph and post this equation (http://tinyurl.com/lnmeuk) on top of those?
Nazgulled
@Tom - indeed. I'm learning Python, so I should follow your example and use it for things like this. Very nice work on your part.
duffymo
@Nazgulled - I've added the curve you requested. Better, though, would be for Suvesh to edit his response to the non-linear version and post the curve there.
tom10