2010-02-21 2 views
3
var colors = new Color[] { 
    Color.Blue, 
    Color.Green, 
    Color.Yellow, 
    Color.Orange, 
    Color.Red 
}; 

var min = 0; 
var max = 400; 

Я пытаюсь получить цвет между этими значениями на основе другого номера. Так, например, если бы я хотел цвет для значения 350, он был бы 50% оранжевым и 50% красным.Как рассчитать цвет на основе диапазона значений в C#?

РЕДАКТИРОВАТЬ - Перефразировано для ясности

Единственным способом я могу думать делать это создание градиента изображения в Photoshop, а затем вычисление смещения и захват пиксел значения RGB. Однако это кажется крайне хакерским, и я хотел бы сделать это с помощью какого-то расчета.

Любые идеи?

+3

Почему бы 350 средняя 50% желтого и 50 % Оранжевый? Я потерялся. –

+0

Err ... Blue = 0, зеленый = 100, желтый = 200, оранжевый = 300, ??? = 400 –

+0

К сожалению, я добавил красный в массив. Таким образом, 350 будет красным/оранжевым. – jimj

ответ

11

Вы можете использовать линейную интерполяцию для смешивания значений R, G и B (и A, если хотите). Вот пример кода для проекта Windows Form. Просто добавьте TrackBar с диапазоном от 0 до 400 и проволоки до EVENT прокрутки, TrackBar к ниже обработчика:

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

Вы также можете использовать эту идею HSL цвета, как предложено nobugz.

Примечание: этот код является просто доказательством концепции. В реальном приложении вы хотели бы создать класс, чтобы инкапсулировать логику выбора цвета, сделать ее более настраиваемой, обрабатывать ошибки и т. Д. Это также не оптимизировано для скорости. Если скорость является важным соображением, то вместо этого вы, вероятно, должны использовать справочную таблицу.

+0

Отлично, спасибо! – jimj

0

Color has the properties R, G, and B. Вы можете взять свое входное значение, делить его на 100, чтобы получить нижний цвет (обрезать его на 3). Добавьте один к этому, чтобы получить верхний цвет. Затем возьмите R, G и B из нижнего и верхнего цветов, создайте средневзвешенное значение каждого из них на основе значения% 100 и создайте новый цвет с этими значениями.

1

Что-то вроде этого может сработать для вас ... хотя это совершенно непроверено. Идея состоит в том, что вы подсчитываете, какие два цвета вам нужны, и после этого вы смешиваете эти два на основе процентного значения, которое вы можете рассчитать. Как сказано, полностью непроверено.

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 
} 
4

Существует одна небольшая ошибка в Mark Байерс ответ, он должен быть изменен на:

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; 
} 
else if (kvp.Key == v) 
{ 
    return kvp.Value; 
} 

В противном случае все, что равно одна из входных точек возвращается в Black. (у меня нет достаточной репутации прокомментировать свой ответ так, насколько я знаю, это мой единственный выход)

+0

Должно быть 'FromRgb', нет? – stijn

+0

'System.Drawing.Color.FromArgb' имеет перегрузки для одного int, 3 ints или 4 ints. В этом классе чертежа не существует 'FromRgb'. Я полностью согласен с его странным, что у меня есть перегрузка Argb, которая не поддерживает передачу альфы ... – Thymine

+0

Моя ошибка: использовала 'System.Windows.Media.Color' при просмотре этого вопроса – stijn

2

Другой способ обобщить решение

/// <summary> 
/// Interpolate colors 0.0 - 1.0   
/// </summary>   
public static Color Interpolate(double percent, params Color[] colors) 
{ 
    int left = (int)Math.Floor(percent * (colors.Length - 1)); 
    int right = (int)Math.Ceiling(percent * (colors.Length - 1)); 
    Color colorLeft = colors[left]; 
    Color colorRight = colors[right]; 

    double step = 1.0/(colors.Length - 1); 
    double percentRight = (percent - (left * step))/step; 
    double percentLeft = 1.0 - percentRight; 

    Color outputColor = new Color(); 

    outputColor.R = (byte)(colorLeft.R * percentLeft + colorRight.R * percentRight); 
    outputColor.G = (byte)(colorLeft.G * percentLeft + colorRight.G * percentRight); 
    outputColor.B = (byte)(colorLeft.B * percentLeft + colorRight.B * percentRight); 
    outputColor.A = (byte)(colorLeft.A * percentLeft + colorRight.A * percentRight); 

    return outputColor; 
} 
+0

R, G, B, A читаются только! Используйте .FromArgb для установки. – Dave

Смежные вопросы