logplus/logPlus/Gradient.cpp
2025-12-29 18:13:00 +08:00

533 lines
17 KiB
C++

#include "Gradient.h"
#include <QCoreApplication>
//extern char *GetBinDir(char *str);
BYTE GetRValue(COLORREF colour)
{
QColor color(colour);
return color.red();
}
BYTE GetGValue(COLORREF colour)
{
QColor color(colour);
return color.green();
}
BYTE GetBValue(COLORREF colour)
{
QColor color(colour);
return color.blue();
}
CGradient::CGradient()
{
m_StartPeg.colour = 0x00FFFFFF;//
m_StartPeg.position = 0.0f;
m_EndPeg.colour = 0x00000000;//
m_EndPeg.position = 1.0f;
m_Background.colour = 0x00FFFFFF; //A default pal
m_Background.position = 0.0f;
m_InterpolationMethod = Linear;
m_UseBackground = false;
m_Quantization = -1;
m_FileFlag = "LogPlus";
pegs.clear();
}
CGradient::~CGradient()
{
pegs.clear();
}
//void CGradient::MakeEntries(RGBTRIPLE *lpPal, int iEntryCount)
//{
// float pos;
// COLORREF colour;
// int curpeg;
// if ( iEntryCount < 1 || iEntryCount >= 65535)
// return ;
// InterpolateFn Interpolate = GetInterpolationProc();
// if(pegs.count() > 0)
// {
// //Some things are already constant and so can be found early
// float firstpegpos = pegs[0].position;
// float lastpegpos = pegs[pegs.count()-1].position;
// COLORREF lastpegcolour = pegs[pegs.count()-1].colour;
// for(int i = 0; i < iEntryCount; i++)
// {
// if(m_Quantization == -1)
// pos = (float)i/iEntryCount;
// else
// pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
// if(pos <= firstpegpos)
// {
// colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos, 0, firstpegpos);
// lpPal[i].rgbtRed = GetRValue(colour);
// lpPal[i].rgbtGreen = GetGValue(colour);
// lpPal[i].rgbtBlue = GetBValue(colour);
// }
// else if(pos > lastpegpos)
// {
// colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos, lastpegpos, 1);
// lpPal[i].rgbtRed = GetRValue(colour);
// lpPal[i].rgbtGreen = GetGValue(colour);
// lpPal[i].rgbtBlue = GetBValue(colour);
// }
// else
// {
// curpeg = IndexFromPos(pos);
// colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos, pegs[curpeg].position, pegs[curpeg+1].position);
// lpPal[i].rgbtRed = GetRValue(colour);
// lpPal[i].rgbtGreen = GetGValue(colour);
// lpPal[i].rgbtBlue = GetBValue(colour);
// }
// }
// }
// else
// {
// //When there are no extra peg we can just interpolate the start and end
// for(int i = 0; i < iEntryCount; i++)
// {
// if(m_Quantization == -1)
// pos = (float)i/iEntryCount;
// else
// pos = ((float)(int)(((float)i/iEntryCount)*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
// colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos, 0, 1);
// lpPal[i].rgbtRed = GetRValue(colour);
// lpPal[i].rgbtGreen = GetGValue(colour);
// lpPal[i].rgbtBlue = GetBValue(colour);
// }
// }
// if(m_UseBackground)
// {
// lpPal[0].rgbtRed = GetRValue(m_Background.colour);
// lpPal[0].rgbtGreen = GetGValue(m_Background.colour);
// lpPal[0].rgbtBlue = GetBValue(m_Background.colour);
// }
//}
InterpolateFn CGradient::GetInterpolationProc()
{
switch(m_InterpolationMethod)
{
case Linear: return InterpolateLinear;
case FlatStart: return InterpolateFlatStart;
case FlatMid: return InterpolateFlatMid;
case FlatEnd: return InterpolateFlatEnd;
case Cosine: return InterpolateCosine;
case HSLRedBlue: return InterpolateHSLClockwise;
case HSLBlueRed: return InterpolateHSLAntiClockwise;
case HSLShortest: return InterpolateHSLShortest;
case HSLLongest: return InterpolateHSLLongest;
case Reverse:
{
QVector <CPeg> pegsTemp;
//CArray <CPeg, CPeg&> pegsTemp;
int n = pegs.count();
pegsTemp.clear();
pegsTemp.resize(n);
for (int i=0; i<n; i++)
{
pegsTemp[i].colour = pegs[n-i-1].colour;
}
for (int i=0; i<n; i++)
{
pegs[i].colour = pegsTemp[i].colour;
}
CPeg temp;
temp.colour = m_StartPeg.colour;
m_StartPeg.colour = m_EndPeg.colour;
m_EndPeg.colour = temp.colour;
return InterpolateReverse;
}
default: return 0;
}
}
int CGradient::IndexFromPos(float pos)
{
//ASSERT(pos >= 0.0f && pos <= 1.0f);
if ( pos<0 || pos>1 )
return NONE;
// positions betwen 0 and 1!
if(pos < pegs[0].position)
return STARTPEG;
for(int i = 0; i < pegs.count()-1; i++)
if(pos >= pegs[i].position && pos <= pegs[i+1].position)
return i;
return -1; // Eh? somethings wrong here
}
COLORREF CGradient::InterpolateLinear(COLORREF first, COLORREF second, float position, float start, float end)
{
if(start == end) return first;
if(end - start == 0) return second;
if(position == start) return first;
if(position == end) return second;
return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)),
(BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)),
(BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start)));
}
COLORREF CGradient::InterpolateReverse(COLORREF first, COLORREF second, float position, float start, float end)
{
if(start == end) return first;
if(end - start == 0) return second;
if(position == start) return first;
if(position == end) return second;
// return RGB((BYTE)((GetRValue(first)*(position - start) + GetRValue(second)*(end-position))/(end-start)),
// (BYTE)((GetGValue(first)*(position - start) + GetGValue(second)*(end-position))/(end-start)),
// (BYTE)((GetBValue(first)*(position - start) + GetBValue(second)*(end-position))/(end-start)));
return RGB((BYTE)((GetRValue(second)*(position - start) + GetRValue(first)*(end-position))/(end-start)),
(BYTE)((GetGValue(second)*(position - start) + GetGValue(first)*(end-position))/(end-start)),
(BYTE)((GetBValue(second)*(position - start) + GetBValue(first)*(end-position))/(end-start)));
}
COLORREF CGradient::InterpolateFlatStart(COLORREF first, COLORREF, float, float, float)
{return first;}
COLORREF CGradient::InterpolateFlatMid(COLORREF first, COLORREF second, float, float, float)
{
unsigned short sr, sg, sb, er, eg, eb;
sr = GetRValue(first);
sg = GetGValue(first);
sb = GetBValue(first);
er = GetRValue(second);
eg = GetGValue(second);
eb = GetBValue(second);
return RGB((sr+er)/2, (sg+eg)/2, (sb+eb)/2);
}
COLORREF CGradient::InterpolateFlatEnd(COLORREF, COLORREF second, float, float, float)
{return second;}
COLORREF CGradient::InterpolateCosine(COLORREF first, COLORREF second, float position, float start, float end)
{
float theta = (position-start)/(end-start) * 3.1415927f;
float f = (1 - cosf(theta)) * .5f;
return RGB((BYTE)(((float)GetRValue(first))*(1-f) + ((float)GetRValue(second))*f),
(BYTE)(((float)GetGValue(first))*(1-f) + ((float)GetGValue(second))*f),
(BYTE)(((float)GetBValue(first))*(1-f) + ((float)GetBValue(second))*f));
}
void RGB_to_HSL (float r, float g, float b, float *h, float *s, float *l)
{
float v;
float m;
float vm;
float r2, g2, b2;
v = max(r,g);
v = max(v,b);
m = min(r,g);
m = min(m,b);
if ((*l = (m + v) / 2.0f) <= 0.0f) return;
if ((*s = vm = v - m) > 0.0f) {
*s /= (*l <= 0.5f) ? (v + m ) :
(2.0f - v - m) ;
} else
return;
r2 = (v - r) / vm;
g2 = (v - g) / vm;
b2 = (v - b) / vm;
if (r == v)
*h = (g == m ? 5.0f + b2 : 1.0f - g2);
else if (g == v)
*h = (b == m ? 1.0f + r2 : 3.0f - b2);
else
*h = (r == m ? 3.0f + g2 : 5.0f - r2);
*h /= 6.0f;
}
void HSL_to_RGB(float h, float sl, float l, float *r, float *g, float *b)
{
float v;
v = (l <= 0.5f) ? (l * (1.0f + sl)) : (l + sl - l * sl);
if (v <= 0) {
*r = *g = *b = 0.0f;
} else {
float m;
float sv;
int sextant;
float fract, vsf, mid1, mid2;
m = l + l - v;
sv = (v - m ) / v;
h *= 6.0f;
sextant = (int)h;
fract = h - sextant;
vsf = v * sv * fract;
mid1 = m + vsf;
mid2 = v - vsf;
switch (sextant) {
case 0: *r = v; *g = mid1; *b = m; break;
case 1: *r = mid2; *g = v; *b = m; break;
case 2: *r = m; *g = v; *b = mid1; break;
case 3: *r = m; *g = mid2; *b = v; break;
case 4: *r = mid1; *g = m; *b = v; break;
case 5: *r = v; *g = m; *b = mid2; break;
}
}
}
COLORREF CGradient::InterpolateHSLClockwise(COLORREF first, COLORREF second, float position, float start, float end)
{
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
(float)GetBValue(second)/255.0f, &eh, &es, &el);
sh = sh - floorf(sh);
eh = eh - floorf(eh);
//Interpolate H clockwise
if(eh >= sh) h = (eh*(position - start) + sh*(end-position))/(end-start);
else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start);
h = (h>=1.0f)?h-1.0f:h;
s = ((es*(position - start) + ss*(end-position))/(end-start));
l = ((el*(position - start) + sl*(end-position))/(end-start));
HSL_to_RGB(h, s, l, &r, &g, &b);
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
}
COLORREF CGradient::InterpolateHSLAntiClockwise(COLORREF first, COLORREF second, float position, float start, float end)
{
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
(float)GetBValue(second)/255.0f, &eh, &es, &el);
sh = sh - floorf(sh);
eh = eh - floorf(eh);
//Interpolate H anticlockwise
if(eh <= sh) h = (eh*(position - start) + sh*(end-position))/(end-start);
else h = ((eh + 1.0f)*(position - start) + sh*(end-position))/(end-start);
h = (h>=1.0f)?h-1.0f:h;
s = ((es*(position - start) + ss*(end-position))/(end-start));
l = ((el*(position - start) + sl*(end-position))/(end-start));
HSL_to_RGB(h, s, l, &r, &g, &b);
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
}
COLORREF CGradient::InterpolateHSLLongest(COLORREF first, COLORREF second, float position, float start, float end)
{
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
(float)GetBValue(second)/255.0f, &eh, &es, &el);
sh = sh - (float)floor(sh);
eh = eh - (float)floor(eh);
//Interpolate H short route
if(((eh-sh)-floor(eh-sh) < 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start);
else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start);
//TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h);
h = h - floorf(h);
s = ((es*(position - start) + ss*(end-position))/(end-start));
l = ((el*(position - start) + sl*(end-position))/(end-start));
HSL_to_RGB(h, s, l, &r, &g, &b);
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
}
COLORREF CGradient::InterpolateHSLShortest(COLORREF first, COLORREF second, float position, float start, float end)
{
float sh = 0, ss = 0, sl = 0, eh = 0, es = 0, el = 0, h = 0, s = 0, l = 0, r = 0, g = 0, b = 0;
RGB_to_HSL((float)GetRValue(first)/255.0f, (float)GetGValue(first)/255.0f,
(float)GetBValue(first)/255.0f, &sh, &ss, &sl);
RGB_to_HSL((float)GetRValue(second)/255.0f, (float)GetGValue(second)/255.0f,
(float)GetBValue(second)/255.0f, &eh, &es, &el);
sh = sh - (float)floor(sh);
eh = eh - (float)floor(eh);
//Interpolate H short route
if(((eh-sh)-floor(eh-sh) > 0.5f)?(eh < sh):(eh >= sh)) h = (eh*(position - start) + sh*(end-position))/(end-start);
else h = ((eh+(sh>eh?1.0f:-1.0f))*(position - start) + sh*(end-position))/(end-start);
//TRACE3("sh: %f eh: %f h: %f\n", sh, eh, h);
h = h - floorf(h);
s = ((es*(position - start) + ss*(end-position))/(end-start));
l = ((el*(position - start) + sl*(end-position))/(end-start));
HSL_to_RGB(h, s, l, &r, &g, &b);
return RGB((BYTE)(r*255.0f), (BYTE)(g*255.0f), (BYTE)(b*255.0f));
}
void CGradient::GetColorArray(COLORREF colorArr[])
{
float pos;
InterpolateFn Interpolate = GetInterpolationProc();
//if (pegs.GetSize() > 0)
if (pegs.count() > 0)
{
float firstpegpos = pegs[0].position;
COLORREF fistpegcolour = pegs[0].colour;
float lastpegpos = pegs[pegs.count()-1].position;
COLORREF lastpegcolour = pegs[pegs.count()-1].colour;
//float lastpegpos = pegs[pegs.GetUpperBound()].position;
//COLORREF lastpegcolour = pegs[pegs.GetUpperBound()].colour;
int curpeg;
int index; float pos2; COLORREF colour;
for (index=0,pos=0.0; index<256; index++,pos+=0.003906)
{
if(m_Quantization != -1)
pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
else pos2 = pos;
if (pos2 <= firstpegpos)
{
colour = Interpolate(m_StartPeg.colour, pegs[0].colour, pos2, 0, firstpegpos);
colorArr[index] = colour;
}
else if (pos2 > lastpegpos)
{
colour = Interpolate(lastpegcolour, m_EndPeg.colour, pos2, lastpegpos, 1);
colorArr[index] = colour;
}
else
{
curpeg = IndexFromPos2(pos2);
colour = Interpolate(pegs[curpeg].colour, pegs[curpeg+1].colour, pos2, pegs[curpeg].position, pegs[curpeg+1].position);
colorArr[index] = colour;
}
}
}
else //pegs.size == 0
{
int index; float pos2; COLORREF colour;
for (index=0,pos=0.0; index<256; index++,pos+=0.003906)
{
if (m_Quantization != -1)
pos2 = ((float)(int)(pos*m_Quantization))/m_Quantization + 0.5f / m_Quantization;
else pos2 = pos;
colour = Interpolate(m_StartPeg.colour, m_EndPeg.colour, pos2, 0, 1);
colorArr[index] = colour;
}
}
}
int CGradient::IndexFromPos2(float pos)
{
int begin = 0;
//int end = pegs.GetSize()-1;
int end = pegs.count()-1;
int mid;
while(begin <= end)
{
mid = (begin + end) / 2;
if (pos > pegs[mid].position)
{
begin = mid+1;
}
else
{
end = mid-1;
}
}
// if (mid==0)
// mid =1;
return end;
}
//读取配色方案
void CGradient::Serialize(QString strCfg)//CArchive &ar)
{
//lhj 2019-8-14 配色文件转换成TXT格式
// 保存为TXT格式
// strCfg.TrimLeft();
// strCfg.TrimRight();
strCfg.trimmed();
int i,n;
char str[256],strName[256];
//CString strCipPath;
CPeg peg;
//GetBinDir(str);
memset(str, '\0', sizeof (str));
strcat(str, QCoreApplication::applicationDirPath().toStdString().c_str());
strcat(str,"\\color\\");
strcat(str,strCfg.toStdString().c_str());
//strcat(str,"_clr.cfg");
FILE *fp;
fp=fopen(str,"r");
if ( fp!=NULL)
{
fgets(strName,256,fp);
sscanf(strName,"%s",str);
//m_FileFlag.Format("%s",str);
m_FileFlag = str;
fgets(strName,256,fp);
sscanf(strName,"%ld",&m_Background.colour);
fgets(strName,256,fp);
sscanf(strName,"%ld %ld",&m_StartPeg.colour,&m_EndPeg.colour);
fgets(strName,256,fp);
sscanf(strName,"%d",&i);
m_UseBackground=i;
fgets(strName,256,fp);
sscanf(strName,"%d",&m_Quantization);
fgets(strName,256,fp);
sscanf(strName,"%d",&m_InterpolationMethod);
fgets(strName,256,fp);
sscanf(strName,"%d",&n);
pegs.clear();
for( i = 0; i < n; i++)
{
fgets(strName,256,fp);
sscanf(strName,"%ld %g",&peg.colour,&peg.position);
pegs.append(peg);
}
fclose(fp);
}
}