internal static Blend SigmaBellShape(float focus, float scale)
{
Blend blend = new Blend();
float pos = 0.0f;
int count = 511; /* total no of samples */
int index;
float sigma;
float mean;
float fall_off_len = 2.0f; /* curve fall off length in terms of SIGMA */
float delta; /* distance between two samples */
float phi; /* variable to hold the value of Phi - Normal Distribution - CFD etc... */
/* we get a curve not starting from 0 and not ending at 1.
* so we subtract the starting value and divide by the curve
* height to make it fit in the 0 to scale range
*/
float curve_bottom;
float curve_top;
float curve_height;
if (focus == 0 || focus == 1) {
count = 256;
}
if (blend.Positions.Length != count) {
blend = new Blend(count);
}
/* Set the blend colors. We use integral of the Normal Distribution,
* i.e. Cumulative Distribution Function (CDF).
*
* Normal distribution:
*
* y (x) = (1 / sqrt (2 * PI * sq (sigma))) * exp (-sq (x - mu)/ (2 * sq (sigma)))
*
* where, y = height of normal curve,
* sigma = standard deviation
* mu = mean
* OR
* y (x) = peak * exp ( - z * z / 2)
* where, z = (x - mu) / sigma
*
* In this curve, peak would occur at mean i.e. for x = mu. This results in
* a peak value of peak = (1 / sqrt (2 * PI * sq (sigma))).
*
* Cumulative distribution function:
* Ref: http://mathworld.wolfram.com/NormalDistribution.html
* see function Phi(x) below - Φ(x)
*
* D (x) = Phi(z)
* where, z = (x - mu) / sigma
*
*/
if (focus == 0) {
/* right part of the curve with a complete fall in fall_off_len * SIGMAs */
sigma = 1.0f / fall_off_len;
mean = 0.5f;
delta = 1.0f / 255.0f;
curve_bottom = (float)Phi((1.0f - mean) / sigma);
curve_top = (float)Phi((focus - mean) / sigma);
curve_height = curve_top - curve_bottom;
/* set the start */
blend.Positions[0] = focus;
blend.Factors[0] = scale;
for (index = 1, pos = delta; index < 255; index++, pos += delta)
{
blend.Positions[index] = pos;
phi = (float)Phi((pos - mean) / sigma);
blend.Factors[index] = (scale / curve_height) *
(phi - curve_bottom);
}
/* set the end */
blend.Positions [count - 1] = 1.0f;
blend.Factors [count - 1] = 0.0f;
}
else if (focus == 1) {
/* left part of the curve with a complete rise in fall_off_len * SIGMAs */
sigma = 1.0f / fall_off_len;
mean = 0.5f;
delta = 1.0f / 255.0f;
curve_bottom = (float)Phi((0.0f - mean) / sigma);
curve_top = (float)Phi((focus - mean) / sigma);
curve_height = curve_top - curve_bottom;
/* set the start */
blend.Positions[0] = 0.0f;
blend.Factors[0] = 0.0f;
for (index = 1, pos = delta; index < 255; index++, pos += delta)
{
blend.Positions[index] = pos;
phi = (float)Phi((pos - mean) / sigma);
blend.Factors[index] = (scale / curve_height) *
(pos - curve_bottom);
}
/* set the end */
blend.Positions [count - 1] = focus;
blend.Factors [count - 1] = scale;
}
else {
/* left part of the curve with a complete fall in fall_off_len * SIGMAs */
sigma = focus / (2 * fall_off_len);
mean = focus / 2.0f;
delta = focus / 255.0f;
/* set the start */
blend.Positions [0] = 0.0f;
blend.Factors [0] = 0.0f;
curve_bottom = (float)Phi((0.0f - mean) / sigma);
curve_top = (float)Phi((focus - mean) / sigma);
curve_height = curve_top - curve_bottom;
for (index = 1, pos = delta; index < 255; index++, pos += delta) {
blend.Positions [index] = pos;
phi = (float)Phi((pos - mean) / sigma);
blend.Factors [index] = (scale / curve_height) *
(phi - curve_bottom);
}
blend.Positions [index] = focus;
blend.Factors [index] = scale;
/* right part of the curve with a complete fall in fall_off_len * SIGMAs */
sigma = (1.0f - focus) / (2 * fall_off_len);
mean = (1.0f + focus) / 2.0f;
delta = (1.0f - focus) / 255.0f;
curve_bottom = (float)Phi((1.0f - mean) / sigma);
curve_top = (float)Phi((focus - mean) / sigma);
curve_height = curve_top - curve_bottom;
index ++;
pos = focus + delta;
for (; index < 510; index++, pos += delta) {
blend.Positions [index] = pos;
phi = (float)Phi((pos - mean) / sigma);
blend.Factors [index] = (scale / curve_height) *
(phi - curve_bottom);
}
/* set the end */
blend.Positions [count - 1] = 1.0f;
blend.Factors [count - 1] = 0.0f;
}
return blend;
}