views:

496

answers:

4
var colors = new Color[] { 
    Color.Blue, 
    Color.Green, 
    Color.Yellow, 
    Color.Orange, 
    Color.Red 
};

var min = 0;
var max = 400;

I'm trying to get the color in between these values based on another number. So for example if I wanted to the color for the value 350, it would be 50% orange and 50% red.

EDIT - Reworded for clarity

The only way I can think of doing it is creating a gradient image in photoshop, then calculating the offset and grabbing the pixel RGB value. However this seems extremely hacky and I would like to do it by some kind of calculation.

Any ideas?

A: 

Color has the properties R, G, and B. You can take your input value, divide it by 100 to get the bottom color (clipping it at 3). Add one to that to get the top color. Then grab R, G, and B from the bottom and top colors, create a weighted average of each based on value % 100, and make a new Color with those values.

Conspicuous Compiler
+6  A: 

You could use linear interpolation to mix the R, G and B values (and A if you want). Here's some example code for a Windows Form project. Just add a trackbar with range 0 to 400 and wire up the trackbar's scroll event to the handler below:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    byte interpolate(byte a, byte b, double p)
    {
        return (byte)(a * (1 - p) + b * p);
    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        int v = trackBar1.Value;
        BackColor = getColor(v);
    }

    private Color getColor(int v)
    {
        SortedDictionary<int, Color> d = new SortedDictionary<int, Color>();
        d.Add(0, Color.Blue);
        d.Add(100, Color.Green);
        d.Add(200, Color.Yellow);
        d.Add(300, Color.Orange);
        d.Add(400, Color.Red);

        KeyValuePair<int, Color> kvp_previous = new KeyValuePair<int,Color>(-1, Color.Black);
        foreach (KeyValuePair<int, Color> kvp in d)
        {
            if (kvp.Key > v)
            {
                double p = (v - kvp_previous.Key) / (double)(kvp.Key - kvp_previous.Key);
                Color a = kvp_previous.Value;
                Color b = kvp.Value;
                Color c = Color.FromArgb(
                    interpolate(a.R, b.R, p),
                    interpolate(a.G, b.G, p),
                    interpolate(a.B, b.B, p));
                return c;
            }
            kvp_previous = kvp;
        }

        return Color.Black;
    }
}

You could also use this idea with HSL colors as suggested by nobugz.

Note: This code is just proof-of-concept. In a real application you would want to create a class to encapsulate the color choosing logic, make it more customizable, and error handling, etc. It's also not optimized for speed. If speed is an important consideration then you should probably use a look-up table instead.

Mark Byers
Excellent, thanks!
Griz
+1  A: 

Something like this might work for you...though, this is completely untested. The idea is that you calculate what two colors you need, and after that you mix these two based on the percentage value which you can calculate. As said, completely untested.

using System.Convert;

public static Color oddColorFunction(int value)
{
    Color colors = new Color[] { Color.Blue, Color.Green, Color.Yellow, Color.Orange, Color.Red };
    int min = 0;
    int max = 400;

    decimal range = max / colors.Length;

    Color leftColor = ToInt32(Decimal.Floor(value / range));
    Color rightColor = ToInt32(Decimal.Ceiling(value / range));

    return mixColors(colors[leftColor], colors[rightColor], ToInt32(Decimal.Round(value % range * 100)));
}

public static mixColors(Color colorA, Color colorB, int percentage)
{
    //combine colors here based on percentage
    //I'm to lazy to code this :P
}
Bobby