Problem

I made a start at translating the accepted answer’s code here into C#. Any suggestions on the correctness of the translation and the correctness of the original code would be very much appreciated.

```
public class RgbValues
{
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
}
public static RgbValues GetRgbValues(float minimumValue, float maximumValue, float value)
{
var rgbValues = new RgbValues();
var halfmax = (minimumValue + maximumValue) / 2.0;
rgbValues.Blue = (int) Math.Max(0.0, 255.0 * (1.0 - value/halfmax));
rgbValues.Red = (int)Math.Max(0.0, 255.0 * (value / halfmax - 1.0));
rgbValues.Green = 255 - rgbValues.Blue - rgbValues.Red;
return rgbValues;
}
```

What is a bit worrying is that:

```
GetRgbValues(10, 10113, 10113)
```

should really caclulate:

```
red = 255, green = 0, blue = 0
```

rather than:

```
red = 254, green = 1, blue = 0
```

I guess there is some rounding issue.

Any ideas?

Solution

Calculations like these can be hard to understand, so I would try to strive for something that is *clearly* correct, not just correct.

What I would do:

- normalize the value from [min,max]$[min,max]$ to [0,2]$[0,2]$
- realize that the “strength” of a color is 1−|value−color|$1-|value-color|$ (where color$color$ is 0$0$ for blue, 1$1$ for green and 2$2$ for red), so compute that
- clip the computer strength to remove negative numbers
- finally multiply it by 255$255$ and convert to
`int`

(while also rounding the value, to avoid bias towards smaller numbers)

In code:

```
public static RgbValues GetRgbValues(float minimum, float maximum, float value)
{
var normalizedValue = Normalize(minimum, maximum, value);
return new RgbValues
{
Blue = Distance(normalizedValue, 0),
Green = Distance(normalizedValue, 1),
Red = Distance(normalizedValue, 2)
};
}
private static float Normalize(float minimum, float maximum, float value)
{
return (value - minimum) / (maximum - minimum) * 2;
}
private static int Distance(float value, float color)
{
var distance = Math.Abs(value - color);
var colorStrength = 1 - distance;
if (colorStrength < 0)
colorStrength = 0;
return (int)Math.Round(colorStrength * 255);
}
```

This code is longer than the original, but I think it’s also clearer about what it does. I didn’t figure out what your code did until I read the SO question, I think it’s much more likely I would have succeeded with this code.

That’s because the formula is not correct, but with the specific values of `minimumValue`

and `maximumValue`

in the question, the result happens to be the same.

The value of `halfmax`

should be half the difference between the min and max:

```
double halfmax = (maximumValue - minimumValue) / 2.0;
```

The `minimumvalue`

should be subtracted from `value`

:

```
rgbValues.Blue = (int)Math.Max(0.0, 255.0 * (1 - (value - minimiumValue) / halfmax));
rgbValues.Red = (int)Math.Max(0.0, 255.0 * ((value - minimiumValue) / halfmax - 1));
```

The basis for the formula is this way of interpolating any color component between a start value and end value at the min and max points, respectively:

```
color = start + (end - start) * (value - min) / (max - min)
```

With the blue starting at 1 and ending at -1, and red starting at -1 and ending at 1, you get:

```
blue = 1 - 2 * (value - min) / (max - min)
red = -1 + 2 * (value - min) / (max - min)
```

The inverse of `2 / (max - min)`

is what was calculated as `halfmax`

, giving:

```
blue = 1 - (value - min) / halfmax
red = -1 + (value - min) / halfmax
```