forked from rosh/MQL5Book
228 lines
6.3 KiB
MQL5
228 lines
6.3 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| ColorMix.mqh |
| |
//| https://www.mql5.com |
| |
//+------------------------------------------------------------------+
| |
| |
//+------------------------------------------------------------------+
| |
//| Color converters between RGB and HSV, color mixer and blender |
| |
//+------------------------------------------------------------------+
| |
namespace ColorMix
| |
{
| |
// handy local macros
| |
// RGB bytes order 012 in uint, which is actually BGR
| |
#define RGB(R,G,B) (color)((uint)(R) | ((uint)(G) << 8) | ((uint)(B) << 16))
| |
#define CLR_R(C) ((C) & 0xFF)
| |
#define CLR_G(C) (((C) >> 8) & 0xFF)
| |
#define CLR_B(C) (((C) >> 16) & 0xFF)
| |
| |
//+------------------------------------------------------------------+
| |
//| Convert Hue/Saturation/Value into color (RGB components) |
| |
//| H = 0..360 (angle), S = 0..1, V = 0..1 |
| |
//+------------------------------------------------------------------+
| |
color HSVtoRGB(double H, double S = 1.0, double V = 1.0)
| |
{
| |
int r = 0, g = 0, b = 0;
| |
| |
if(S < 0 || S > 1) S = 1;
| |
if(V < 0 || V > 1) V = 1;
| |
| |
if(S == 0.0)
| |
{
| |
r = (int)(V * 255);
| |
g = (int)(V * 255);
| |
b = (int)(V * 255);
| |
}
| |
else
| |
{
| |
if(H >= 360.0 || H < 0) H = 0.0;
| |
else H /= 60;
| |
int i = (int)H;
| |
double f = H - i;
| |
double m, n, k;
| |
m = V * (1 - S);
| |
n = V * (1 - S * f);
| |
k = V * (1 - S * (1 - f));
| |
| |
switch(i)
| |
{
| |
case 0:
| |
r = (int)(V * 255);
| |
g = (int)(k * 255);
| |
b = (int)(m * 255);
| |
break;
| |
case 1:
| |
r = (int)(n * 255);
| |
g = (int)(V * 255);
| |
b = (int)(m * 255);
| |
break;
| |
case 2:
| |
r = (int)(m * 255);
| |
g = (int)(V * 255);
| |
b = (int)(k * 255);
| |
break;
| |
case 3:
| |
r = (int)(m * 255);
| |
g = (int)(n * 255);
| |
b = (int)(V * 255);
| |
break;
| |
case 4:
| |
r = (int)(k * 255);
| |
g = (int)(m * 255);
| |
b = (int)(V * 255);
| |
break;
| |
case 5:
| |
r = (int)(V * 255);
| |
g = (int)(m * 255);
| |
b = (int)(n * 255);
| |
break;
| |
}
| |
}
| |
return (color)RGB(r, g, b);
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Find max of 3 RGB components |
| |
//+------------------------------------------------------------------+
| |
int RGBmax(int R, int G, int B)
| |
{
| |
if(R > G)
| |
{
| |
if(R > B) return R;
| |
else return B;
| |
}
| |
else
| |
{
| |
if(G > B) return G;
| |
else return B;
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Find min of 3 RGB components |
| |
//+------------------------------------------------------------------+
| |
int RGBmin(int R, int G, int B)
| |
{
| |
if(R < G)
| |
{
| |
if(R < B) return R;
| |
else return B;
| |
}
| |
else
| |
{
| |
if(G < B) return G;
| |
else return B;
| |
}
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Convert RGB color in Hue/Saturation/Value |
| |
//| H = 0..360 (angle), S = 0..1, V = 0..1 |
| |
//+------------------------------------------------------------------+
| |
void RGBtoHSV(color rgb, double &H, double &S, double &V)
| |
{
| |
int r = CLR_R(rgb);
| |
int g = CLR_G(rgb);
| |
int b = CLR_B(rgb);
| |
| |
H = 0;
| |
| |
// determine the value (brightness)
| |
V = RGBmax(r, g, b);
| |
| |
// determine saturation
| |
double temp = RGBmin(r, g, b);
| |
| |
if(V == 0)
| |
{
| |
S = 0;
| |
}
| |
else
| |
{
| |
S = (V - temp) / V;
| |
}
| |
| |
// determine the hue
| |
if(S == 0)
| |
{
| |
H = 0;
| |
}
| |
else
| |
{
| |
double Cr, Cg, Cb;
| |
Cr = (V - r) / (V - temp);
| |
Cg = (V - g) / (V - temp);
| |
Cb = (V - b) / (V - temp);
| |
// the color is between yellow and magenta
| |
if(r == V)
| |
H = Cb - Cg;
| |
// the color is between cyan and yellow
| |
if(g == V)
| |
H = 2 + Cr - Cb;
| |
// the color is between magenta and cyan
| |
if(b == V)
| |
H = 4 + Cg - Cr;
| |
// convert to degrees
| |
H = 60 * H;
| |
// prevent negative value
| |
if(H < 0)
| |
H += 360;
| |
}
| |
V /= 255;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Construct a color (one of several grades) between 2 given colors |
| |
//| using hue circle or linear manner |
| |
//+------------------------------------------------------------------+
| |
color RotateColors(const color clr1, const color clr2, const int gradeCount, const int i, const bool colourScheme = true)
| |
{
| |
color clr;
| |
| |
if(colourScheme)
| |
{
| |
double hh, s, v;
| |
double h1, s1, v1;
| |
double h2, s2, v2;
| |
| |
RGBtoHSV(clr1, h1, s1, v1);
| |
RGBtoHSV(clr2, h2, s2, v2);
| |
| |
hh = h1 + ((h2 - h1) / (gradeCount)) * i;
| |
s = s1 + ((s2 - s1) / (gradeCount)) * i;
| |
v = v1 + ((v2 - v1) / (gradeCount)) * i;
| |
if(hh < 0) hh += 360;
| |
if(hh > 360) hh -= 360;
| |
clr = HSVtoRGB(hh, s, v);
| |
}
| |
else
| |
{
| |
int r, g, b;
| |
int r1 = CLR_R(clr1), g1 = CLR_G(clr1), b1 = CLR_B(clr1);
| |
int r2 = CLR_R(clr2), g2 = CLR_G(clr2), b2 = CLR_B(clr2);
| |
| |
r = (int)(r1 + (((r2 - r1) / (1.0 * gradeCount)) * i));
| |
g = (int)(g1 + (((g2 - g1) / (1.0 * gradeCount)) * i));
| |
b = (int)(b1 + (((b2 - b1) / (1.0 * gradeCount)) * i));
| |
clr = RGB(r, g, b);
| |
}
| |
| |
return clr;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| Mix 2 colors linear manner |
| |
//+------------------------------------------------------------------+
| |
color BlendColors(const int col1, const int col2, const double a = 0.5)
| |
{
| |
int r1 = CLR_R(col1), g1 = CLR_G(col1), b1 = CLR_B(col1),
| |
r2 = CLR_R(col2), g2 = CLR_G(col2), b2 = CLR_B(col2);
| |
return RGB(r1 + a * (r2 - r1), g1 + a * (g2 - g1), b1 + a * (b2 - b1));
| |
}
| |
| |
#undef RGB
| |
#undef CLR_R
| |
#undef CLR_G
| |
#undef CLR_B
| |
| |
} // namespace ColorMix
| |
//+------------------------------------------------------------------+
|