HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Calculation of RGB values given min and max values

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
calculationandminmaxvaluesrgbgiven

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]\$ to \$[0, 2]\$



  • realize that the "strength" of a color is \$1 - |value - color|\$ (where \$color\$ is \$0\$ for blue, \$1\$ for green and \$2\$ for red), so compute that



  • clip the computer strength to remove negative numbers



  • finally multiply it by \$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.

Code Snippets

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);
}

Context

StackExchange Code Review Q#64708, answer score: 5

Revisions (0)

No revisions yet.