Алгоритм Вопрос:Необходимо динамически увеличивать значение от 00FF00 до FF0000 с течением времени, C#/Java.
Вопрос
Я хочу изменить цвет с ярко-зеленого на темно-красный с течением времени (240 часов).Лучший способ, который я вижу, — это изменить шестнадцатеричную комбинацию с 00FF00 на FF0000.
Я не знаю, как динамически считать до FF0000 от 00FF00 хоть убей.Я рассматриваю период в 10 дней, так что, скорее всего, приращение составит более 240 часов.
Может кто-нибудь мне помочь?
Я никогда не посещал курсы по алгоритмам, поэтому думаю, что это может иметь какое-то отношение к этой проблеме.
Если у вас есть лучший способ сделать это, дайте мне знать.
Я ищу здесь какой-то код.Спасибо ребята.Он может быть на любом языке, но неизбежно будет преобразован в C#.
Решение
Просто подумайте об этом с точки зрения компонентов.Хотя это выглядит как одно большое шестнадцатеричное число, на самом деле это три числа, расположенных рядом.
В начале красный — 0, зеленый — 255 (FF), синий — 0.
В конце красный — 255, зеленый — 0, синий — 0.
Итак, каждые (количество времени, которое у вас есть / 255), увеличивайте красный на 1 и уменьшайте зеленый на 1.
Другие советы
Если вы переходите от яркого цвета к яркому цвету, как предполагают шестнадцатеричные значения, вы можете выполнить интерполяцию в пространство HSV, а не пространство RGB.Пространство HSV приблизительно соответствует тому, как мы думаем о цвете — оттенке, насыщенности и значении.Пространство RGB приблизительно соответствует тому, как работают светочувствительные клетки наших глаз.
Верхний градиент представляет собой линейную интерполяцию RGB от FF0000 до 00FF00.Его среднее значение — 7f7f00, грязно-коричневый.
Средний градиент представляет собой линейную интерполяцию в пространстве HSV.Поскольку и FF0000, и 00FF00 полностью насыщены и имеют одинаковое значение (яркость), интерполяция сохраняет одинаковую яркость и насыщенность повсюду, поэтому центральное значение имеет ярко-желтый цвет ffff00.
Третьей альтернативой может быть вращение вектора в пространстве RGB, что будет означать, что среднее значение равно B4B400 ( B4 hex = 180 dec = 255 / sqrt(2) ), что находится где-то между этими двумя эффектами.Это делается путем вычисления величины каждой конечной точки, а затем масштабирования результата линейной интерполяции RGB так, чтобы он был одинаковой величины, эффективно перемещая вектор по дуге в плоскости двух цветов и начала координат.Поскольку на самом деле мы не одинаково взвешиваем разные цвета по яркости и не видим линейно, это не точно, но у него довольно равномерная интенсивность по всей развертке, тогда как у HSV немного светлее в середине, поскольку у него два значения. на 100%.
удалена мертвая ссылка на Imageshack
В Java, где у вас есть поддержка HSB, алгоритм прост: получите HSB конечных значений, линейно интерполируйте их, как и в других ответах RGB, затем преобразуйте, создайте цвет со значениями h, s, v:
static Color hsvInterpolate ( float mix, Color c0, Color c1 ) {
float[] hsv0 = new float[3];
float[] hsv1 = new float[3];
float alt = 1.0f - mix;
Color.RGBtoHSB( c0.getRed(), c0.getGreen(), c0.getBlue(), hsv0 );
Color.RGBtoHSB( c1.getRed(), c1.getGreen(), c1.getBlue(), hsv1 );
float h = mix * hsv0 [ 0 ] + alt * hsv1 [ 0 ];
float s = mix * hsv0 [ 1 ] + alt * hsv1 [ 1 ];
float v = mix * hsv0 [ 2 ] + alt * hsv1 [ 2 ];
return Color.getHSBColor ( h, s, v );
}
Я не верю, что в C# встроены преобразования, поэтому на самом деле этот код бесполезен.
static Color vectorInterpolate ( float mix, Color c0, Color c1 ) {
float alt = 1.0f - mix;
double x0 = c0.getRed();
double y0 = c0.getGreen();
double z0 = c0.getBlue();
double x1 = c1.getRed();
double y1 = c1.getGreen();
double z1 = c1.getBlue();
double mag0 = sqrt( x0*x0 + y0*y0 + z0*z0 );
double mag1 = sqrt( x1*x1 + y1*y1 + z1*z1 );
double x = mix * x0 + alt * x1;
double y = mix * y0 + alt * y1;
double z = mix * z0 + alt * z1;
double mag = mix * mag0 + alt * mag1;
double scale = mag / sqrt( x*x + y*y + z*z );
return new Color (
clamp ( x * scale ),
clamp ( y * scale ),
clamp ( z * scale ) );
}
static int clamp ( double value ) {
int x = (int) round ( value );
if ( x > 255 ) return 255;
if ( x < 0 ) return 0;
return x;
}
Вероятно, вы захотите найти пересечение вектора с краем RGB-куба, а не просто зажать его, но в данном случае это в любом случае не имеет значения.
В качестве дополнения также стоит рассмотреть пространство HSY, которое ближе к воспринимаемой яркости, как показано на рис. Кубическая спираль Дэйва Грина цветовые интерполяции.
time_remaining (значение варьируется от 0 до 239)
зеленый = 255 * (оставшееся_время / 239)
красный = 255 - зеленый
синий = 0
цвет = (красный, зеленый, синий)
вот быстрый ответ Java от красного до зеленого (конечно, вы можете это изменить), значение — текущее value
вовремя и all
это сумма времени...
public static String progressiveColor(int value, int all){
int red = 255 - (int)((float)(value*255)/(float)all);
int green = (int)((float)(value*255)/(float)all);
return String.format("#%06X", (0xFFFFFF & Color.argb(255, red, green, 0)));
}
Вот Java-код Пита, переведенный на C#, если кто-то его искал.Для моих целей он отлично подходит (от черного до темно-красного и обратно).
static Color VectorInterpolate(float mix, Color c0, Color c1)
{
float alt = 1.0f - mix;
double x0 = c0.R;
double y0 = c0.G;
double z0 = c0.B;
double x1 = c1.R;
double y1 = c1.G;
double z1 = c1.B;
double mag0 = Math.Sqrt(x0 * x0 + y0 * y0 + z0 * z0);
double mag1 = Math.Sqrt(x1 * x1 + y1 * y1 + z1 * z1);
double x = mix * x0 + alt * x1;
double y = mix * y0 + alt * y1;
double z = mix * z0 + alt * z1;
double mag = mix * mag0 + alt * mag1;
double scale = mag / Math.Sqrt(x * x + y * y + z * z);
return Color.FromRgb(Clamp(x * scale), Clamp(y * scale), Clamp(z * scale));
}
static byte Clamp(double value)
{
var x = (int)Math.Round(value);
if (x > 255) return 255;
if (x < 0) return 0;
return (byte) x;
}