Функция разложения цвета на оттенки.

 

В течении месяца, я упорно решал проблему разложения цвета на оттенки. Задача оказалась непростой. За основу исследования я взял цветовую палитру виндоус (та, что в свойствах графика).  Проведя длительное изучение, я все же обнаружил закономерности. И вот как:

  • Сначала, я раскладывал цвет на три основных компоненты, определяя старшую, среднюю, младшую. 
  • Далее, начал строить графики и проводить линии через значения компонент. 
  • Наблюдая изменения цифр в палитре при перетаскивании ползунка, я понял, что существует преломление угла восхождения линий, потому как в определенный момент скорость изменения цифр менялась.
  • Я установил ось преломления линий в центр графика, и увидел, что каждая линия, состоит из двух отрезков, каждый из которых имеет свой угол восхождения.
  • Также, эксперементируя с цветовой палитрой, я понял что есть максимальный угол восхождения старшей компоненты. Сначала я считал, что он равен 67.5 градусов. Однако, практика показала что он равен 63.5 градусов.
  • В течении длительного времени, я не мог понять как правильно составить график отрезков линий цветовых компонент. Было много неизвестных. Но главное, - как найти координату исходного цвета на графике?
  • Продолжая эксперементировать с палитрой, я заметил, что меняя значение цвета на определенное число, ползунок сдвигается на определенное растояние. Постепенно, я понял что расстояние сдвига ползунка, равно половине значения младшей компоненты. 
  • Я предположил, что если найти координату старшей компоненты на линии угла максимального восхождения и прибавлю к этой точке половину значения младшей компоненты, я найду координату исходного цвета на графике. Практика доказала, что предположение было верным.
  • Имея координату исходного цвета и ось преломления, я мог расчитать углы каждого из отрезков и получить значения для каждой компоненты на протяжении ее линии. Для этого воспользовался школьной тригонометрией. 
  • Проверив на бумаге расчеты я приступил к написанию функции. Теперь я хочу поделиться ею со всеми.
//+------------------------------------------------------------------+
//|                                                Full Gradient.mqh |
//|                                                      Peter Konow |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void Диапазон_оттенков(color _Цвет, string &Все_оттенки[256])
{
 color R,G,B,q;
 //------------------------------------------------------
 string Этот_цвет;
 double Тангенс_угла_старшего_треугольника_1,      
        Тангенс_угла_среднего_треугольника_1,                  
        Тангенс_угла_младшего_треугольника_1,                       
        Значение_в_точке_преломления_старшей_компоненты,  
        Значение_в_точке_преломления_средней_компоненты,
        Значение_в_точке_преломления_младшей_компоненты,    
        Тангенс_угла_старшего_треугольника_2,
        Тангенс_угла_среднего_треугольника_2,    
        Тангенс_угла_младшего_треугольника_2;
 //------------------------------------------------------
 double pi = 3.1415926536,
        Comp_1,Comp_2,Comp_3,
        //-----------------------------------------------
        Первая_компонента,
        Вторая_компонента,
        Третья_компонента,
        //-----------------------------------------------
        Исходный_R = GetR(_Цвет), 
        Исходный_G = GetG(_Цвет),  
        Исходный_B = GetB(_Цвет),  
        //-----------------------------------------------
        Старшая_компонента         = Нужная_компонента(Исходный_R,Исходный_G,Исходный_B, 0), 
        Средняя_компонента         = Нужная_компонента(Исходный_R,Исходный_G,Исходный_B, 1), 
        Младшая_компонента         = Нужная_компонента(Исходный_R,Исходный_G,Исходный_B, 2), 
        //-----------------------------------------------
        Координата_исходного_цвета = Старшая_компонента/tan((63.43989*pi)/180) + Младшая_компонента/2; 
        //-----------------------------------------------
        
 //-----------------------------------------------
 if(Старшая_компонента == Исходный_R)R = Старшая_компонента;
 if(Старшая_компонента == Исходный_G)G = Старшая_компонента; 
 if(Старшая_компонента == Исходный_B)B = Старшая_компонента;     
 //------------------------
 if(Средняя_компонента == Исходный_R)R = Средняя_компонента;
 if(Средняя_компонента == Исходный_G)G = Средняя_компонента; 
 if(Средняя_компонента == Исходный_B)B = Средняя_компонента; 
 //------------------------
 if(Младшая_компонента == Исходный_R)R = Младшая_компонента;
 if(Младшая_компонента == Исходный_G)G = Младшая_компонента; 
 if(Младшая_компонента == Исходный_B)B = Младшая_компонента;     
 //==========================================================================================
 if(Координата_исходного_цвета <= 127)
   {
    Тангенс_угла_старшего_треугольника_1  = Старшая_компонента/Координата_исходного_цвета;
    Тангенс_угла_среднего_треугольника_1  = Средняя_компонента/Координата_исходного_цвета;     
    Тангенс_угла_младшего_треугольника_1  = Младшая_компонента/Координата_исходного_цвета;
    //-----------------------------------------------
    Значение_в_точке_преломления_старшей_компоненты  = Тангенс_угла_старшего_треугольника_1*128;
    Значение_в_точке_преломления_средней_компоненты  = Тангенс_угла_среднего_треугольника_1*128;
    Значение_в_точке_преломления_младшей_компоненты  = Тангенс_угла_младшего_треугольника_1*128;    
    //-----------------------------------------------    
    Тангенс_угла_старшего_треугольника_2  = (255 - Значение_в_точке_преломления_старшей_компоненты)/128;
    Тангенс_угла_среднего_треугольника_2  = (255 - Значение_в_точке_преломления_средней_компоненты)/128;       
    Тангенс_угла_младшего_треугольника_2  = (255 - Значение_в_точке_преломления_младшей_компоненты)/128;
    //-----------------------------------------------    
    for(int a1 = 0; a1 < 128; a1++)
      {
       Comp_1 = Тангенс_угла_старшего_треугольника_1*a1;
       Comp_2 = Тангенс_угла_среднего_треугольника_1*a1;
       Comp_3 = Тангенс_угла_младшего_треугольника_1*a1;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       //---------------------------------------------------
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Этот_цвет = (string)MathRound(Первая_компонента) + "," + (string)MathRound(Вторая_компонента) + "," + (string)MathRound(Третья_компонента);
       //---------------------------------------------------------------------------    
       Все_оттенки[a1] = Этот_цвет; 
       //---------------------------------------------------------------------------
      }
    //------------------------------------------------------------------------------
    for(int a2 = 255; a2 >= a1; a2--)
      {
       Comp_1 = 255 - Тангенс_угла_старшего_треугольника_2*q;
       Comp_2 = 255 - Тангенс_угла_среднего_треугольника_2*q;
       Comp_3 = 255 - Тангенс_угла_младшего_треугольника_2*q;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       //---------------------------------------------------       
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Этот_цвет = (string)MathRound(Первая_компонента) + "," + (string)MathRound(Вторая_компонента) + "," + (string)MathRound(Третья_компонента);
       //---------------------------------------------------------------------------    
       Все_оттенки[a2] = Этот_цвет; 
       //---------------------------------------------------------------------------
       q++;
      }
  } 
 //------------------------------------------------------------------------------
 if(Координата_исходного_цвета > 127)
   {
    Тангенс_угла_старшего_треугольника_1  = (255 - Старшая_компонента)/(255 - Координата_исходного_цвета);
    Тангенс_угла_среднего_треугольника_1  = (255 - Средняя_компонента)/(255 - Координата_исходного_цвета);       
    Тангенс_угла_младшего_треугольника_1  = (255 - Младшая_компонента)/(255 - Координата_исходного_цвета);
    //-----------------------------------------------
    Значение_в_точке_преломления_старшей_компоненты  = 255 - (Тангенс_угла_старшего_треугольника_1*128);
    Значение_в_точке_преломления_средней_компоненты  = 255 - (Тангенс_угла_среднего_треугольника_1*128);
    Значение_в_точке_преломления_младшей_компоненты  = 255 - (Тангенс_угла_младшего_треугольника_1*128);    
    //-----------------------------------------------    
    Тангенс_угла_старшего_треугольника_2  = Значение_в_точке_преломления_старшей_компоненты/128;
    Тангенс_угла_среднего_треугольника_2  = Значение_в_точке_преломления_средней_компоненты/128;      
    Тангенс_угла_младшего_треугольника_2  = Значение_в_точке_преломления_младшей_компоненты/128;
    //-----------------------------------------------    
    for(int b1 = 0; b1 < 128; b1++)
      {
       Comp_1 = Тангенс_угла_старшего_треугольника_2*b1;
       Comp_2 = Тангенс_угла_среднего_треугольника_2*b1;
       Comp_3 = Тангенс_угла_младшего_треугольника_2*b1;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       //---------------------------------------------------
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Этот_цвет = (string)MathRound(Первая_компонента) + "," + (string)MathRound(Вторая_компонента) + "," + (string)MathRound(Третья_компонента);
       //---------------------------------------------------------------------------    
       Все_оттенки[b1] = Этот_цвет; 
       //---------------------------------------------------------------------------
      }
    //------------------------------------------------------------------------------
    for(int b2 = 255; b2 >= b1; b2--)
      {
       Comp_1 = 255 - Тангенс_угла_старшего_треугольника_1*q;
       Comp_2 = 255 - Тангенс_угла_среднего_треугольника_1*q;
       Comp_3 = 255 - Тангенс_угла_младшего_треугольника_1*q;
       //---------------------------------------------------
       if(Comp_1 > 255)Comp_1 = 255;
       if(Comp_1 > 255)Comp_2 = 255;
       if(Comp_1 > 255)Comp_3 = 255;
       //---------------------------------------------------       
       if(R == Старшая_компонента)Первая_компонента = Comp_1;
       if(R == Средняя_компонента)Первая_компонента = Comp_2;
       if(R == Младшая_компонента)Первая_компонента = Comp_3;
       //---------------------------------------------------
       if(G == Старшая_компонента)Вторая_компонента = Comp_1;
       if(G == Средняя_компонента)Вторая_компонента = Comp_2;
       if(G == Младшая_компонента)Вторая_компонента = Comp_3;
       //---------------------------------------------------
       if(B == Старшая_компонента)Третья_компонента = Comp_1;
       if(B == Средняя_компонента)Третья_компонента = Comp_2;
       if(B == Младшая_компонента)Третья_компонента = Comp_3;
       //---------------------------------------------------
       Этот_цвет = (string)MathRound(Первая_компонента) + "," + (string)MathRound(Вторая_компонента) + "," + (string)MathRound(Третья_компонента);
       //---------------------------------------------------------------------------    
       Все_оттенки[b2] = Этот_цвет; 
       //---------------------------------------------------------------------------
       q++;
      }
   }   
 //------------------------------------------------------------------------------  
}
//+------------------------------------------------------------------+
//| Получение значения компонента R                                  |
//+------------------------------------------------------------------+
double GetR(const color aColor)
  {
   return(aColor&0xff);
  }
//+------------------------------------------------------------------+
//| Получение значения компонента G                                  |
//+------------------------------------------------------------------+
double GetG(const color aColor)
  {
   return((aColor>>8)&0xff);
  }
//+------------------------------------------------------------------+
//| Получение значения компонента B                                  |
//+------------------------------------------------------------------+
double GetB(const color aColor)
  {
   return((aColor>>16)&0xff);
  }
//--------------------------------------------------------------------
double Нужная_компонента(double C1, double C2, double C3, int Index)
{
 double Components[3]; 
 //----------------------------------------------
 Components[0] = C1;
 Components[1] = C2;
 Components[2] = C3;
 //----------------------------------------------
 ArraySort(Components,WHOLE_ARRAY,0,MODE_DESCEND);
 //----------------------------------------------
 return(Components[Index]);
}

 

Вот скрипт для тестирования:

void OnStart()
  {
   color Main_color     = C'213,0,0';//здесь ставите нужный цвет. Компилируете. Тот же цвет ставите в цветовой палитре виндоус. Сравниваете цвета.
   string Gradient[256];
   //------------------------
   Диапазон_оттенков(Main_color,Gradient);
   //------------------------
   for(int a1 = 0; a1 < 256; a1++)Alert(__FUNCTION__,"  Gradient[",a1,"]  ",Gradient[a1]);
  }
Файлы:
 
Реter Konow:

Вот скрипт для тестирования:

Благодарю! Хорошо бы писать код на английском с комментариями и отправлять такие коды в библиотеку...

 
Также очень интересно, как эта задача решается с помощью класса CCanvas. Как можно получить через него все оттенки исходного цвета?
 
Vladimir Pastushak:

Благодарю! Хорошо бы писать код на английском с комментариями и отправлять такие коды в библиотеку...

Согласен. В свободное время переведу. Вы имеете ввиду кодо-базу?

 
Реter Konow:

Согласен. В свободное время переведу. Вы имеете ввиду кодо-базу?

В кода базе есть раздел библиотеки, там как раз складываются и обновляются такие коды.

 
Vladimir Pastushak:

В кода базе есть раздел библиотеки, там как раз складываются и обновляются такие коды.

Ясно. 

 
Vladimir Pastushak:

Благодарю! Хорошо бы писать код на английском с комментариями и отправлять такие коды в библиотеку...

Для CodeBade безусловно надо писать на международном языке. Но зачем на русскоязычном форуме на этом настаивать???

Лично мне противен этот международный... потому, что я его совсем не знаю и мне гораздо понятней наш родной Русский.

 

В колориметрии, насколько я помню, куча различных систем.

Возможно, там есть готовая система, которая отвечает потребностям, и формулы для перехода между ними.

 
Georgiy Merts:

В колориметрии, насколько я помню, куча различных систем.

Возможно, там есть готовая система, которая отвечает потребностям, и формулы для перехода между ними.

У меня одна функция. Послал цвет, - получил все оттенки. Дальше, - любой градиент можно нарисовать, просто делая цикл по массиву.

 

Чуть позже я сделал изменение. Изначально, функция void. Не возвращает значение. Но после я сделал ее типом int и внизу прибавил

return(Координата_исходного_цвета);

 Таким образом, помимо массива оттенков, функция стала возвращать номер той ячейки, в которой находится посланный в нее исходный цвет. Это облегчает рисование градиента. От исходного цвета можно двигаться либо влево, либо вправо по массиву.

Причина обращения: