mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-09-03 14:10:33 +03:00
0031454: Visualization - perceptually uniform color scale
Support of CIE Lab and Lch color spaces is introduced in Quantity_Color: - Enumeration Quantity_TypeOfColor is extended by new values representing CIE Lab and Lch color spaces (with D65 2 deg illuminant). - Conversion of RGB color to and from these color spaces is implemented in Quantity_Color class (within existing API). - Color difference calculation using CIE Delta E 200 formula is implemented in method DeltaE2000(). New methods MakeUniformColors() and SetUniformColors() are added in class AIS_ColorScale, generating and setting color scale based on colors of the same lightness in CIE Lch color model. DRAW commands vcolorconvert and vcolordiff are added to perform conversions and compute difference, respectively. A new option -uniform is added in DRAW command vcolorscale, to set uniform color scale. Added test grid v3d colors (color conversions and difference), test bugs vis bug31454 (uniform color scale)
This commit is contained in:
@@ -289,6 +289,100 @@ void AIS_ColorScale::SetColors (const Aspect_SequenceOfColor& theSeq)
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MakeUniformColors
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Aspect_SequenceOfColor AIS_ColorScale::MakeUniformColors (Standard_Integer theNbColors,
|
||||
Standard_Real theLightness,
|
||||
Standard_Real theHueFrom,
|
||||
Standard_Real theHueTo)
|
||||
{
|
||||
Aspect_SequenceOfColor aResult;
|
||||
|
||||
// adjust range to be within (0, 360], with sign according to theHueFrom and theHueTo
|
||||
Standard_Real aHueRange = std::fmod (theHueTo - theHueFrom, 360.);
|
||||
const Standard_Real aHueEps = Precision::Angular() * 180. / M_PI;
|
||||
if (Abs (aHueRange) <= aHueEps)
|
||||
{
|
||||
aHueRange = (aHueRange < 0 ? -360. : 360.);
|
||||
}
|
||||
|
||||
// treat limit cases
|
||||
if (theNbColors < 1)
|
||||
{
|
||||
return aResult;
|
||||
}
|
||||
if (theNbColors == 1)
|
||||
{
|
||||
Standard_Real aHue = std::fmod (theHueFrom, 360.);
|
||||
if (aHue < 0.)
|
||||
{
|
||||
aHue += 360.;
|
||||
}
|
||||
Quantity_Color aColor (theLightness, 130., aHue, Quantity_TOC_CIELch);
|
||||
aResult.Append (aColor);
|
||||
return aResult;
|
||||
}
|
||||
|
||||
// discretize the range with 1 degree step
|
||||
const int NBCOLORS = 2 + (int)Abs (aHueRange / 1.);
|
||||
Standard_Real aHueStep = aHueRange / (NBCOLORS - 1);
|
||||
NCollection_Array1<Quantity_Color> aGrid (0, NBCOLORS - 1);
|
||||
for (Standard_Integer i = 0; i < NBCOLORS; i++)
|
||||
{
|
||||
Standard_Real aHue = std::fmod (theHueFrom + i * aHueStep, 360.);
|
||||
if (aHue < 0.)
|
||||
{
|
||||
aHue += 360.;
|
||||
}
|
||||
aGrid(i).SetValues (theLightness, 130., aHue, Quantity_TOC_CIELch);
|
||||
}
|
||||
|
||||
// and compute distances between each two colors in a grid
|
||||
TColStd_Array1OfReal aMetric (0, NBCOLORS - 1);
|
||||
Standard_Real aLength = 0.;
|
||||
for (Standard_Integer i = 0, j = NBCOLORS - 1; i < NBCOLORS; j = i++)
|
||||
{
|
||||
aLength += (aMetric(i) = aGrid(i).DeltaE2000 (aGrid(j)));
|
||||
}
|
||||
|
||||
// determine desired step by distance;
|
||||
// normally we aim to distribute colors from start to end
|
||||
// of the range, but if distance between first and last points of the range
|
||||
// is less than that step (e.g. range is full 360 deg),
|
||||
// then distribute by the whole 360 deg scope to ensure that first
|
||||
// and last colors are sufficiently distanced
|
||||
Standard_Real aDStep = (aLength - aMetric.First()) / (theNbColors - 1);
|
||||
if (aMetric.First() < aDStep)
|
||||
{
|
||||
aDStep = aLength / theNbColors;
|
||||
}
|
||||
|
||||
// generate sequence
|
||||
aResult.Append(aGrid(0));
|
||||
Standard_Real aParam = 0., aPrev = 0., aTarget = aDStep;
|
||||
for (int i = 1; i < NBCOLORS; i++)
|
||||
{
|
||||
aParam = aPrev + aMetric(i);
|
||||
while (aTarget <= aParam)
|
||||
{
|
||||
float aCoefPrev = float((aParam - aTarget) / (aParam - aPrev));
|
||||
float aCoefCurr = float((aTarget - aPrev) / (aParam - aPrev));
|
||||
Quantity_Color aColor (aGrid(i).Rgb() * aCoefCurr + aGrid(i-1).Rgb() * aCoefPrev);
|
||||
aResult.Append (aColor);
|
||||
aTarget += aDStep;
|
||||
}
|
||||
aPrev = aParam;
|
||||
}
|
||||
if (aResult.Length() < theNbColors)
|
||||
{
|
||||
aResult.Append (aGrid.Last());
|
||||
}
|
||||
Standard_ASSERT_VOID (aResult.Length() == theNbColors, "Failed to generate requested nb of colors");
|
||||
return aResult;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : SizeHint
|
||||
//purpose :
|
||||
|
@@ -228,6 +228,36 @@ public:
|
||||
//! The length of the sequence should be equal to GetNumberOfIntervals().
|
||||
Standard_EXPORT void SetColors (const Aspect_SequenceOfColor& theSeq);
|
||||
|
||||
//! Populates colors scale by colors of the same lightness value in CIE Lch
|
||||
//! color space, distributed by hue, with perceptually uniform differences
|
||||
//! between consequent colors.
|
||||
//! See MakeUniformColors() for description of parameters.
|
||||
void SetUniformColors (Standard_Real theLightness,
|
||||
Standard_Real theHueFrom, Standard_Real theHueTo)
|
||||
{
|
||||
SetColors (MakeUniformColors (myNbIntervals, theLightness, theHueFrom, theHueTo));
|
||||
SetColorType (Aspect_TOCSD_USER);
|
||||
}
|
||||
|
||||
//! Generates sequence of colors of the same lightness value in CIE Lch
|
||||
//! color space (see #Quantity_TOC_CIELch), with hue values in the specified range.
|
||||
//! The colors are distributed across the range such as to have perceptually
|
||||
//! same difference between neighbour colors.
|
||||
//! For each color, maximal chroma value fitting in sRGB gamut is used.
|
||||
//!
|
||||
//! @param theNbColors - number of colors to generate
|
||||
//! @param theLightness - lightness to be used (0 is black, 100 is white, 32 is
|
||||
//! lightness of pure blue)
|
||||
//! @param theHueFrom - hue value at the start of the scale
|
||||
//! @param theHueTo - hue value defining the end of the scale
|
||||
//!
|
||||
//! Hue value can be out of the range [0, 360], interpreted as modulo 360.
|
||||
//! The colors of the scale will be in the order of increasing hue if
|
||||
//! theHueTo > theHueFrom, and decreasing otherwise.
|
||||
Standard_EXPORT static Aspect_SequenceOfColor
|
||||
MakeUniformColors (Standard_Integer theNbColors, Standard_Real theLightness,
|
||||
Standard_Real theHueFrom, Standard_Real theHueTo);
|
||||
|
||||
//! Returns the position of labels concerning color filled rectangles, Aspect_TOCSP_RIGHT by default.
|
||||
Aspect_TypeOfColorScalePosition GetLabelPosition() const { return myLabelPos; }
|
||||
|
||||
|
@@ -40,6 +40,16 @@ static Standard_Real TheEpsilon = 0.0001;
|
||||
|| theL < 0.0 || theL > 1.0 \
|
||||
|| theS < 0.0 || theS > 1.0) { throw Standard_OutOfRange("Color out"); }
|
||||
|
||||
// Throw exception if CIELab color values are out of range.
|
||||
#define Quantity_ColorValidateLabRange(theL, thea, theb) \
|
||||
if (theL < 0. || theL > 100. || thea < -100. || thea > 100. || theb < -110. || theb > 100.) \
|
||||
{ throw Standard_OutOfRange("Color out"); }
|
||||
|
||||
// Throw exception if CIELch color values are out of range.
|
||||
#define Quantity_ColorValidateLchRange(theL, thec, theh) \
|
||||
if (theL < 0. || theL > 100. || thec < 0. || thec > 135. || \
|
||||
theh < 0.0 || theh > 360.) { throw Standard_OutOfRange("Color out"); }
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Raw color for defining list of standard color
|
||||
@@ -107,6 +117,8 @@ NCollection_Vec3<float> Quantity_Color::valuesOf (const Quantity_NameOfColor the
|
||||
case Quantity_TOC_RGB: return anRgb;
|
||||
case Quantity_TOC_sRGB: return Convert_LinearRGB_To_sRGB (anRgb);
|
||||
case Quantity_TOC_HLS: return Convert_LinearRGB_To_HLS (anRgb);
|
||||
case Quantity_TOC_CIELab: return Convert_LinearRGB_To_Lab (anRgb);
|
||||
case Quantity_TOC_CIELch: return Convert_Lab_To_Lch (Convert_LinearRGB_To_Lab (anRgb));
|
||||
}
|
||||
throw Standard_ProgramError("Internal error");
|
||||
}
|
||||
@@ -189,32 +201,10 @@ bool Quantity_Color::ColorFromHex (const Standard_CString theHexColorString,
|
||||
// function : Quantity_Color
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Quantity_Color::Quantity_Color (const Standard_Real theR1, const Standard_Real theR2, const Standard_Real theR3,
|
||||
Quantity_Color::Quantity_Color (const Standard_Real theC1, const Standard_Real theC2, const Standard_Real theC3,
|
||||
const Quantity_TypeOfColor theType)
|
||||
{
|
||||
switch (theType)
|
||||
{
|
||||
case Quantity_TOC_RGB:
|
||||
{
|
||||
Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
|
||||
myRgb.SetValues (float(theR1), float(theR2), float(theR3));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_sRGB:
|
||||
{
|
||||
Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
|
||||
myRgb.SetValues ((float )Convert_sRGB_To_LinearRGB (theR1),
|
||||
(float )Convert_sRGB_To_LinearRGB (theR2),
|
||||
(float )Convert_sRGB_To_LinearRGB (theR3));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_HLS:
|
||||
{
|
||||
Quantity_ColorValidateHlsRange(theR1, theR2, theR3);
|
||||
myRgb = Convert_HLS_To_LinearRGB (NCollection_Vec3<float> (float(theR1), float(theR2), float(theR3)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
SetValues (theC1, theC2, theC3, theType);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
@@ -259,29 +249,41 @@ void Quantity_Color::ChangeIntensity (const Standard_Real theDelta)
|
||||
// function : SetValues
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Quantity_Color::SetValues (const Standard_Real theR1, const Standard_Real theR2, const Standard_Real theR3,
|
||||
void Quantity_Color::SetValues (const Standard_Real theC1, const Standard_Real theC2, const Standard_Real theC3,
|
||||
const Quantity_TypeOfColor theType)
|
||||
{
|
||||
switch (theType)
|
||||
{
|
||||
case Quantity_TOC_RGB:
|
||||
{
|
||||
Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
|
||||
myRgb.SetValues (float(theR1), float(theR2), float(theR3));
|
||||
Quantity_ColorValidateRgbRange(theC1, theC2, theC3);
|
||||
myRgb.SetValues (float(theC1), float(theC2), float(theC3));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_sRGB:
|
||||
{
|
||||
Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
|
||||
myRgb.SetValues ((float )Convert_sRGB_To_LinearRGB (theR1),
|
||||
(float )Convert_sRGB_To_LinearRGB (theR2),
|
||||
(float )Convert_sRGB_To_LinearRGB (theR3));
|
||||
Quantity_ColorValidateRgbRange(theC1, theC2, theC3);
|
||||
myRgb.SetValues ((float )Convert_sRGB_To_LinearRGB (theC1),
|
||||
(float )Convert_sRGB_To_LinearRGB (theC2),
|
||||
(float )Convert_sRGB_To_LinearRGB (theC3));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_HLS:
|
||||
{
|
||||
Quantity_ColorValidateHlsRange(theR1, theR2, theR3);
|
||||
myRgb = Convert_HLS_To_LinearRGB (NCollection_Vec3<float> (float(theR1), float(theR2), float(theR3)));
|
||||
Quantity_ColorValidateHlsRange(theC1, theC2, theC3);
|
||||
myRgb = Convert_HLS_To_LinearRGB (NCollection_Vec3<float> (float(theC1), float(theC2), float(theC3)));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_CIELab:
|
||||
{
|
||||
Quantity_ColorValidateLabRange(theC1, theC2, theC3);
|
||||
myRgb = Convert_Lab_To_LinearRGB (NCollection_Vec3<float> (float(theC1), float(theC2), float(theC3)));
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_CIELch:
|
||||
{
|
||||
Quantity_ColorValidateLchRange(theC1, theC2, theC3);
|
||||
myRgb = Convert_Lab_To_LinearRGB (Convert_Lch_To_Lab (NCollection_Vec3<float> (float(theC1), float(theC2), float(theC3))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +303,76 @@ void Quantity_Color::Delta (const Quantity_Color& theColor,
|
||||
theDI = Standard_Real (aHls1[1] - aHls2[1]); // light
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : DeltaE2000
|
||||
// purpose : color difference according to CIE Delta E 2000 formula
|
||||
// see http://brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
|
||||
// =======================================================================
|
||||
Standard_Real Quantity_Color::DeltaE2000 (const Quantity_Color& theOther) const
|
||||
{
|
||||
// get color components in CIE Lch space
|
||||
Standard_Real aL1, aL2, aa1, aa2, ab1, ab2;
|
||||
this ->Values (aL1, aa1, ab1, Quantity_TOC_CIELab);
|
||||
theOther.Values (aL2, aa2, ab2, Quantity_TOC_CIELab);
|
||||
|
||||
// mean L
|
||||
Standard_Real aLx_mean = 0.5 * (aL1 + aL2);
|
||||
|
||||
// mean C
|
||||
Standard_Real aC1 = Sqrt (aa1 * aa1 + ab1 * ab1);
|
||||
Standard_Real aC2 = Sqrt (aa2 * aa2 + ab2 * ab2);
|
||||
Standard_Real aC_mean = 0.5 * (aC1 + aC2);
|
||||
Standard_Real aC_mean_pow7 = Pow (aC_mean, 7);
|
||||
static const double a25_pow7 = Pow (25., 7);
|
||||
Standard_Real aG = 0.5 * (1. - Sqrt (aC_mean_pow7 / (aC_mean_pow7 + a25_pow7)));
|
||||
Standard_Real aa1x = aa1 * (1. + aG);
|
||||
Standard_Real aa2x = aa2 * (1. + aG);
|
||||
Standard_Real aC1x = Sqrt (aa1x * aa1x + ab1 * ab1);
|
||||
Standard_Real aC2x = Sqrt (aa2x * aa2x + ab2 * ab2);
|
||||
Standard_Real aCx_mean = 0.5 * (aC1x + aC2x);
|
||||
|
||||
// mean H
|
||||
Standard_Real ah1x = (aC1x > TheEpsilon ? ATan2 (ab1, aa1x) * 180. / M_PI : 270.);
|
||||
Standard_Real ah2x = (aC2x > TheEpsilon ? ATan2 (ab2, aa2x) * 180. / M_PI : 270.);
|
||||
if (ah1x < 0.) ah1x += 360.;
|
||||
if (ah2x < 0.) ah2x += 360.;
|
||||
Standard_Real aHx_mean = 0.5 * (ah1x + ah2x);
|
||||
Standard_Real aDeltahx = ah2x - ah1x;
|
||||
if (Abs (aDeltahx) > 180.)
|
||||
{
|
||||
aHx_mean += (aHx_mean < 180. ? 180. : -180.);
|
||||
aDeltahx += (ah1x >= ah2x ? 360. : -360.);
|
||||
}
|
||||
|
||||
// deltas
|
||||
Standard_Real aDeltaLx = aL2 - aL1;
|
||||
Standard_Real aDeltaCx = aC2x - aC1x;
|
||||
Standard_Real aDeltaHx = 2. * Sqrt (aC1x * aC2x) * Sin (0.5 * aDeltahx * M_PI / 180.);
|
||||
|
||||
// factors
|
||||
Standard_Real aT = 1. - 0.17 * Cos (( aHx_mean - 30.) * M_PI / 180.) +
|
||||
0.24 * Cos ((2. * aHx_mean ) * M_PI / 180.) +
|
||||
0.32 * Cos ((3. * aHx_mean + 6.) * M_PI / 180.) -
|
||||
0.20 * Cos ((4. * aHx_mean - 63.) * M_PI / 180.);
|
||||
|
||||
Standard_Real aLx_mean50_2 = (aLx_mean - 50.) * (aLx_mean - 50.);
|
||||
Standard_Real aS_L = 1. + 0.015 * aLx_mean50_2 / Sqrt (20. + aLx_mean50_2);
|
||||
Standard_Real aS_C = 1. + 0.045 * aCx_mean;
|
||||
Standard_Real aS_H = 1. + 0.015 * aCx_mean * aT;
|
||||
|
||||
Standard_Real aDelta_theta = 30. * Exp (-(aHx_mean - 275.) * (aHx_mean - 275.) / 625.);
|
||||
Standard_Real aCx_mean_pow7 = Pow(aCx_mean, 7);
|
||||
Standard_Real aR_C = 2. * Sqrt (aCx_mean_pow7 / (aCx_mean_pow7 + a25_pow7));
|
||||
Standard_Real aR_T = -aR_C * Sin (2. * aDelta_theta * M_PI / 180.);
|
||||
|
||||
// finally, the difference
|
||||
Standard_Real aDL = aDeltaLx / aS_L;
|
||||
Standard_Real aDC = aDeltaCx / aS_C;
|
||||
Standard_Real aDH = aDeltaHx / aS_H;
|
||||
Standard_Real aDeltaE2000 = Sqrt (aDL * aDL + aDC * aDC + aDH * aDH + aR_T * aDC * aDH);
|
||||
return aDeltaE2000;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Name
|
||||
// purpose :
|
||||
@@ -359,6 +431,22 @@ void Quantity_Color::Values (Standard_Real& theR1, Standard_Real& theR2, Standar
|
||||
theR3 = aHls[2];
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_CIELab:
|
||||
{
|
||||
const NCollection_Vec3<float> aLab = Convert_LinearRGB_To_Lab (myRgb);
|
||||
theR1 = aLab[0];
|
||||
theR2 = aLab[1];
|
||||
theR3 = aLab[2];
|
||||
break;
|
||||
}
|
||||
case Quantity_TOC_CIELch:
|
||||
{
|
||||
const NCollection_Vec3<float> aLch = Convert_Lab_To_Lch (Convert_LinearRGB_To_Lab (myRgb));
|
||||
theR1 = aLch[0];
|
||||
theR2 = aLch[1];
|
||||
theR3 = aLch[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,156 +537,135 @@ NCollection_Vec3<float> Quantity_Color::Convert_sRGB_To_HLS (const NCollection_V
|
||||
return NCollection_Vec3<float> (aHue, aMax, aSaturation);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////// TESTS ////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static void TestOfColor()
|
||||
// =======================================================================
|
||||
// function : CIELab_f
|
||||
// purpose : non-linear function transforming XYZ coordinates to CIE Lab
|
||||
// see http://www.brucelindbloom.com/index.html?Equations.html
|
||||
// =======================================================================
|
||||
static inline double CIELab_f (double theValue)
|
||||
{
|
||||
Standard_Real H, L, S;
|
||||
Standard_Real R, G, B;
|
||||
Standard_Real DC, DI;
|
||||
Standard_Integer i;
|
||||
return theValue > 0.008856451679035631 ? Pow (theValue, 1./3.) : (7.787037037037037 * theValue) + 16. / 116.;
|
||||
}
|
||||
|
||||
std::cout << "definition color tests\n----------------------\n";
|
||||
// =======================================================================
|
||||
// function : CIELab_invertf
|
||||
// purpose : inverse of non-linear function transforming XYZ coordinates to CIE Lab
|
||||
// see http://www.brucelindbloom.com/index.html?Equations.html
|
||||
// =======================================================================
|
||||
static inline double CIELab_invertf (double theValue)
|
||||
{
|
||||
double aV3 = theValue * theValue * theValue;
|
||||
return aV3 > 0.008856451679035631 ? aV3 : (theValue - 16. / 116.) / 7.787037037037037;
|
||||
}
|
||||
|
||||
Quantity_Color C1;
|
||||
Quantity_Color C2 (Quantity_NOC_ROYALBLUE2);
|
||||
Quantity_Color C3 (Quantity_NOC_SANDYBROWN);
|
||||
// =======================================================================
|
||||
// function : Convert_LinearRGB_To_Lab
|
||||
// purpose : convert RGB color to CIE Lab color
|
||||
// see https://www.easyrgb.com/en/math.php
|
||||
// =======================================================================
|
||||
NCollection_Vec3<float> Quantity_Color::Convert_LinearRGB_To_Lab (const NCollection_Vec3<float>& theRgb)
|
||||
{
|
||||
double aR = theRgb[0];
|
||||
double aG = theRgb[1];
|
||||
double aB = theRgb[2];
|
||||
|
||||
// An Introduction to Standard_Object-Oriented Programming and C++ p43
|
||||
// a comment for the "const char *const" declaration
|
||||
const char *const cyan = "YELLOW";
|
||||
const char *const blue = "ROYALBLUE2";
|
||||
const char *const brown = "SANDYBROWN";
|
||||
// convert to XYZ normalized to D65 / 2 deg (CIE 1931) standard illuminant intensities
|
||||
// see http://www.brucelindbloom.com/index.html?Equations.html
|
||||
double aX = (aR * 0.4124564 + aG * 0.3575761 + aB * 0.1804375) * 100. / 95.047;
|
||||
double aY = (aR * 0.2126729 + aG * 0.7151522 + aB * 0.0721750) * 100. / 100.000;
|
||||
double aZ = (aR * 0.0193339 + aG * 0.1191920 + aB * 0.9503041) * 100. / 108.883;
|
||||
|
||||
Standard_Real RR, GG, BB;
|
||||
// convert to Lab
|
||||
double afX = CIELab_f (aX);
|
||||
double afY = CIELab_f (aY);
|
||||
double afZ = CIELab_f (aZ);
|
||||
|
||||
const Standard_Real DELTA = 1.0e-4;
|
||||
double aL = 116. * afY - 16.;
|
||||
double aa = 500. * (afX - afY);
|
||||
double ab = 200. * (afY - afZ);
|
||||
|
||||
std::cout << "Get values and names of color tests\n-----------------------------------\n";
|
||||
return NCollection_Vec3<float> ((float)aL, (float)aa, (float)ab);
|
||||
}
|
||||
|
||||
C1.Values (R, G, B, Quantity_TOC_RGB);
|
||||
if ((R!=1.0) || (G!=1.0) || (B!=0.0))
|
||||
// =======================================================================
|
||||
// function : Convert_Lab_To_LinearRGB
|
||||
// purpose : convert CIE Lab color to RGB
|
||||
// see https://www.easyrgb.com/en/math.php
|
||||
// =======================================================================
|
||||
NCollection_Vec3<float> Quantity_Color::Convert_Lab_To_LinearRGB (const NCollection_Vec3<float>& theLab)
|
||||
{
|
||||
double aL = theLab[0];
|
||||
double aa = theLab[1];
|
||||
double ab = theLab[2];
|
||||
|
||||
// conversion from Lab to RGB can yield point outside of RGB cube,
|
||||
// in such case we will reduce a and b components gradually
|
||||
// (by 0.1% at each step) until we fit into the range;
|
||||
// NB: the procedure could be improved to get more precise
|
||||
// result but this does not seem really crucial
|
||||
const int NBSTEPS = 1000;
|
||||
for (Standard_Integer aRate = NBSTEPS; ; aRate--)
|
||||
{
|
||||
std::cout << "TEST_ERROR : Values () bad default color\n";
|
||||
std::cout << "R, G, B values: " << R << " " << G << " " << B << "\n";
|
||||
}
|
||||
if ( (C1.Red ()!=1.0) || (C1.Green ()!=1.0) || (C1.Blue ()!=0.0) )
|
||||
{
|
||||
std::cout << "TEST_ERROR : Values () bad default color\n";
|
||||
std::cout << "R, G, B values: " << C1.Red () << " " << C1.Green () << " " << C1.Blue () << "\n";
|
||||
}
|
||||
if (strcmp (Quantity_Color::StringName (C1.Name()), cyan) != 0)
|
||||
{
|
||||
std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C1.Name()) << " != YELLOW\n";
|
||||
}
|
||||
double aC = aRate / (double)NBSTEPS;
|
||||
|
||||
RR=0.262745; GG=0.431373; BB=0.933333;
|
||||
C1.SetValues (RR, GG, BB, Quantity_TOC_RGB);
|
||||
C2.Values (R, G, B, Quantity_TOC_RGB);
|
||||
if ((Abs (RR-R) > DELTA)
|
||||
|| (Abs (GG-G) > DELTA)
|
||||
|| (Abs (BB-B) > DELTA))
|
||||
{
|
||||
std::cout << "TEST_ERROR : Values () bad default color\n";
|
||||
std::cout << "R, G, B values: " << R << " " << G << " " << B << "\n";
|
||||
}
|
||||
// convert to XYZ for D65 / 2 deg (CIE 1931) standard illuminant
|
||||
double afY = (aL + 16.) / 116.;
|
||||
double afX = aC * aa / 500. + afY;
|
||||
double afZ = afY - aC * ab / 200.;
|
||||
|
||||
if (C2 != C1)
|
||||
{
|
||||
std::cout << "TEST_ERROR : IsDifferent ()\n";
|
||||
}
|
||||
if (C3 == C1)
|
||||
{
|
||||
std::cout << "TEST_ERROR : IsEqual ()\n";
|
||||
}
|
||||
double aX = CIELab_invertf(afX) * 95.047;
|
||||
double aY = CIELab_invertf(afY) * 100.000;
|
||||
double aZ = CIELab_invertf(afZ) * 108.883;
|
||||
|
||||
std::cout << "Distance C1,C2 " << C1.Distance (C2) << "\n";
|
||||
std::cout << "Distance C1,C3 " << C1.Distance (C3) << "\n";
|
||||
std::cout << "Distance C2,C3 " << C2.Distance (C3) << "\n";
|
||||
std::cout << "SquareDistance C1,C2 " << C1.SquareDistance (C2) << "\n";
|
||||
std::cout << "SquareDistance C1,C3 " << C1.SquareDistance (C3) << "\n";
|
||||
std::cout << "SquareDistance C2,C3 " << C2.SquareDistance (C3) << "\n";
|
||||
// convert to RGB
|
||||
// see http://www.brucelindbloom.com/index.html?Equations.html
|
||||
double aR = (aX * 3.2404542 + aY * -1.5371385 + aZ * -0.4985314) / 100.;
|
||||
double aG = (aX * -0.9692660 + aY * 1.8760108 + aZ * 0.0415560) / 100.;
|
||||
double aB = (aX * 0.0556434 + aY * -0.2040259 + aZ * 1.0572252) / 100.;
|
||||
|
||||
if (strcmp (Quantity_Color::StringName (C2.Name()), blue) != 0)
|
||||
{
|
||||
std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C2.Name()) << " != ROYALBLUE2\n";
|
||||
}
|
||||
|
||||
std::cout << "conversion rgbhls tests\n-----------------------\n";
|
||||
Quantity_Color::RgbHls (R, G, B, H, L, S);
|
||||
Quantity_Color::HlsRgb (H, L, S, R, G, B);
|
||||
RR=0.262745; GG=0.431373; BB=0.933333;
|
||||
if ((Abs (RR-R) > DELTA)
|
||||
|| (Abs (GG-G) > DELTA)
|
||||
|| (Abs (BB-B) > DELTA))
|
||||
{
|
||||
std::cout << "TEST_ERROR : RgbHls or HlsRgb bad conversion\n";
|
||||
std::cout << "RGB init : " << RR << " " << GG << " " << BB << "\n";
|
||||
std::cout << "RGB values : " << R << " " << G << " " << B << "\n";
|
||||
std::cout << "Difference RGB : " << RR-R << " " << GG-G << " " << BB-B << "\n";
|
||||
}
|
||||
|
||||
std::cout << "distance tests\n--------------\n";
|
||||
R = (float ) 0.9568631; G = (float ) 0.6431371; B = (float ) 0.3764711;
|
||||
C2.SetValues (R, G, B, Quantity_TOC_RGB);
|
||||
if (C2.Distance (C3) > DELTA)
|
||||
{
|
||||
std::cout << "TEST_ERROR : Distance () bad result\n";
|
||||
std::cout << "Distance C2 and C3 : " << C2.Distance (C3) << "\n";
|
||||
}
|
||||
|
||||
C2.Delta (C3, DC, DI);
|
||||
if (Abs (DC) > DELTA)
|
||||
{
|
||||
std::cout << "TEST_ERROR : Delta () bad result for DC\n";
|
||||
}
|
||||
if (Abs (DI) > DELTA)
|
||||
{
|
||||
std::cout << "TEST_ERROR : Delta () bad result for DI\n";
|
||||
}
|
||||
|
||||
std::cout << "name tests\n----------\n";
|
||||
R = (float ) 0.9568631; G = (float ) 0.6431371; B = (float ) 0.3764711;
|
||||
C2.SetValues (R, G, B, Quantity_TOC_RGB);
|
||||
if (strcmp (Quantity_Color::StringName (C2.Name()), brown) != 0)
|
||||
{
|
||||
std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C2.Name()) << " != SANDYBROWN\n";
|
||||
}
|
||||
|
||||
std::cout << "contrast change tests\n---------------------\n";
|
||||
for (i=1; i<=10; i++)
|
||||
{
|
||||
C2.ChangeContrast (10.);
|
||||
C2.ChangeContrast (-9.09090909);
|
||||
}
|
||||
C2.Values (R, G, B, Quantity_TOC_RGB);
|
||||
RR=0.956863; GG=0.6431371; BB=0.3764711;
|
||||
if ((Abs (RR-R) > DELTA)
|
||||
|| (Abs (GG-G) > DELTA)
|
||||
|| (Abs (BB-B) > DELTA))
|
||||
{
|
||||
std::cout << "TEST_ERROR : ChangeContrast () bad values\n";
|
||||
std::cout << "RGB init : " << RR << " " << GG << " " << BB << "\n";
|
||||
std::cout << "RGB values : " << R << " " << G << " " << B << "\n";
|
||||
// exit if we are in range or at zero C
|
||||
if (aRate == 0 ||
|
||||
(aR >= 0. && aR <= 1. && aG >= 0. && aG <= 1. && aB >= 0. && aB <= 1.))
|
||||
{
|
||||
return NCollection_Vec3<float>((float)aR, (float)aG, (float)aB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Test
|
||||
// purpose :
|
||||
// function : Convert_Lab_To_Lch
|
||||
// purpose : convert CIE Lab color to CIE Lch color
|
||||
// see https://www.easyrgb.com/en/math.php
|
||||
// =======================================================================
|
||||
void Quantity_Color::Test()
|
||||
NCollection_Vec3<float> Quantity_Color::Convert_Lab_To_Lch (const NCollection_Vec3<float>& theLab)
|
||||
{
|
||||
try
|
||||
{
|
||||
OCC_CATCH_SIGNALS
|
||||
TestOfColor();
|
||||
}
|
||||
catch (Standard_Failure const& anException)
|
||||
{
|
||||
std::cout << anException << std::endl;
|
||||
}
|
||||
double aa = theLab[1];
|
||||
double ab = theLab[2];
|
||||
|
||||
double aC = Sqrt (aa * aa + ab * ab);
|
||||
double aH = (aC > TheEpsilon ? ATan2 (ab, aa) * 180. / M_PI : 0.);
|
||||
|
||||
if (aH < 0.) aH += 360.;
|
||||
|
||||
return NCollection_Vec3<float> (theLab[0], (float)aC, (float)aH);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Convert_Lch_To_Lab
|
||||
// purpose : convert CIE Lch color to CIE Lab color
|
||||
// see https://www.easyrgb.com/en/math.php
|
||||
// =======================================================================
|
||||
NCollection_Vec3<float> Quantity_Color::Convert_Lch_To_Lab (const NCollection_Vec3<float>& theLch)
|
||||
{
|
||||
double aC = theLch[1];
|
||||
double aH = theLch[2];
|
||||
|
||||
aH *= M_PI / 180.;
|
||||
|
||||
double aa = aC * Cos (aH);
|
||||
double ab = aC * Sin (aH);
|
||||
|
||||
return NCollection_Vec3<float> (theLch[0], (float)aa, (float)ab);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@@ -46,12 +46,12 @@ public:
|
||||
|
||||
//! Creates a color according to the definition system theType.
|
||||
//! Throws exception if values are out of range.
|
||||
Standard_EXPORT Quantity_Color (const Standard_Real theR1,
|
||||
const Standard_Real theR2,
|
||||
const Standard_Real theR3,
|
||||
Standard_EXPORT Quantity_Color (const Standard_Real theC1,
|
||||
const Standard_Real theC2,
|
||||
const Standard_Real theC3,
|
||||
const Quantity_TypeOfColor theType);
|
||||
|
||||
//! Define color from RGB values.
|
||||
//! Define color from linear RGB values.
|
||||
Standard_EXPORT explicit Quantity_Color (const NCollection_Vec3<float>& theRgb);
|
||||
|
||||
//! Returns the name of the nearest color from the Quantity_NameOfColor enumeration.
|
||||
@@ -60,20 +60,24 @@ public:
|
||||
//! Updates the color from specified named color.
|
||||
void SetValues (const Quantity_NameOfColor theName) { myRgb = valuesOf (theName, Quantity_TOC_RGB); }
|
||||
|
||||
//! Return the color as vector of 3 float elements.
|
||||
const NCollection_Vec3<float>& Rgb () const { return myRgb; }
|
||||
|
||||
//! Return the color as vector of 3 float elements.
|
||||
operator const NCollection_Vec3<float>&() const { return myRgb; }
|
||||
|
||||
//! Returns in theR1, theR2 and theR3 the components of this color according to the color system definition theType.
|
||||
Standard_EXPORT void Values (Standard_Real& theR1,
|
||||
Standard_Real& theR2,
|
||||
Standard_Real& theR3,
|
||||
//! Returns in theC1, theC2 and theC3 the components of this color
|
||||
//! according to the color system definition theType.
|
||||
Standard_EXPORT void Values (Standard_Real& theC1,
|
||||
Standard_Real& theC2,
|
||||
Standard_Real& theC3,
|
||||
const Quantity_TypeOfColor theType) const;
|
||||
|
||||
//! Updates a color according to the mode specified by theType.
|
||||
//! Throws exception if values are out of range.
|
||||
Standard_EXPORT void SetValues (const Standard_Real theR1,
|
||||
const Standard_Real theR2,
|
||||
const Standard_Real theR3,
|
||||
Standard_EXPORT void SetValues (const Standard_Real theC1,
|
||||
const Standard_Real theC2,
|
||||
const Standard_Real theC3,
|
||||
const Quantity_TypeOfColor theType);
|
||||
|
||||
//! Returns the Red component (quantity of red) of the color within range [0.0; 1.0].
|
||||
@@ -138,6 +142,13 @@ public:
|
||||
Standard_EXPORT void Delta (const Quantity_Color& theColor,
|
||||
Standard_Real& DC, Standard_Real& DI) const;
|
||||
|
||||
//! Returns the value of the perceptual difference between this color
|
||||
//! and @p theOther, computed using the CIEDE2000 formula.
|
||||
//! The difference is in range [0, 100.], with 1 approximately corresponding
|
||||
//! to the minimal percievable difference (usually difference 5 or greater is
|
||||
//! needed for the difference to be recognizable in practice).
|
||||
Standard_EXPORT Standard_Real DeltaE2000 (const Quantity_Color& theOther) const;
|
||||
|
||||
public:
|
||||
|
||||
//! Returns the color from Quantity_NameOfColor enumeration nearest to specified RGB values.
|
||||
@@ -170,6 +181,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
//!@name Routines converting colors between different encodings and color spaces
|
||||
|
||||
//! Parses the string as a hex color (like "#FF0" for short sRGB color, or "#FFFF00" for sRGB color)
|
||||
//! @param theHexColorString the string to be parsed
|
||||
//! @param theColor a color that is a result of parsing
|
||||
@@ -206,6 +220,19 @@ public:
|
||||
return Convert_sRGB_To_LinearRGB (Convert_HLS_To_sRGB (theHls));
|
||||
}
|
||||
|
||||
//! Converts linear RGB components into CIE Lab ones.
|
||||
Standard_EXPORT static NCollection_Vec3<float> Convert_LinearRGB_To_Lab (const NCollection_Vec3<float>& theRgb);
|
||||
|
||||
//! Converts CIE Lab components into CIE Lch ones.
|
||||
Standard_EXPORT static NCollection_Vec3<float> Convert_Lab_To_Lch (const NCollection_Vec3<float>& theLab);
|
||||
|
||||
//! Converts CIE Lab components into linear RGB ones.
|
||||
//! Note that the resulting values may be out of the valid range for RGB.
|
||||
Standard_EXPORT static NCollection_Vec3<float> Convert_Lab_To_LinearRGB (const NCollection_Vec3<float>& theLab);
|
||||
|
||||
//! Converts CIE Lch components into CIE Lab ones.
|
||||
Standard_EXPORT static NCollection_Vec3<float> Convert_Lch_To_Lab (const NCollection_Vec3<float>& theLch);
|
||||
|
||||
//! Convert the color value to ARGB integer value, with alpha equals to 0.
|
||||
//! So the output is formatted as 0x00RRGGBB.
|
||||
//! Note that this unpacking does NOT involve non-linear sRGB -> linear RGB conversion,
|
||||
@@ -235,8 +262,6 @@ public:
|
||||
theColor.SetValues (aColor.r() / 255.0, aColor.g() / 255.0, aColor.b() / 255.0, Quantity_TOC_sRGB);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//! Convert linear RGB component into sRGB using OpenGL specs formula (double precision), also known as gamma correction.
|
||||
static Standard_Real Convert_LinearRGB_To_sRGB (Standard_Real theLinearValue)
|
||||
{
|
||||
@@ -287,8 +312,6 @@ public:
|
||||
Convert_sRGB_To_LinearRGB (theRGB.b()));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//! Convert linear RGB component into sRGB using approximated uniform gamma coefficient 2.2.
|
||||
static float Convert_LinearRGB_To_sRGB_approx22 (float theLinearValue) { return powf (theLinearValue, 2.2f); }
|
||||
|
||||
@@ -311,14 +334,6 @@ public:
|
||||
Convert_sRGB_To_LinearRGB_approx22 (theRGB.b()));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
//! Returns the value used to compare two colors for equality; 0.0001 by default.
|
||||
Standard_EXPORT static Standard_Real Epsilon();
|
||||
|
||||
//! Set the value used to compare two colors for equality.
|
||||
Standard_EXPORT static void SetEpsilon (const Standard_Real theEpsilon);
|
||||
|
||||
//! Converts HLS components into sRGB ones.
|
||||
static void HlsRgb (const Standard_Real theH, const Standard_Real theL, const Standard_Real theS,
|
||||
Standard_Real& theR, Standard_Real& theG, Standard_Real& theB)
|
||||
@@ -339,8 +354,13 @@ public:
|
||||
theS = aHls[2];
|
||||
}
|
||||
|
||||
//! Internal test
|
||||
Standard_EXPORT static void Test();
|
||||
public:
|
||||
|
||||
//! Returns the value used to compare two colors for equality; 0.0001 by default.
|
||||
Standard_EXPORT static Standard_Real Epsilon();
|
||||
|
||||
//! Set the value used to compare two colors for equality.
|
||||
Standard_EXPORT static void SetEpsilon (const Standard_Real theEpsilon);
|
||||
|
||||
//! Dumps the content of me into the stream
|
||||
Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
|
||||
|
@@ -20,13 +20,50 @@
|
||||
//! Identifies color definition systems.
|
||||
enum Quantity_TypeOfColor
|
||||
{
|
||||
Quantity_TOC_RGB, //!< normalized linear RGB (red, green, blue) values within range [0..1] for each component
|
||||
Quantity_TOC_sRGB, //!< normalized non-linear gamma-shifted RGB (red, green, blue) values within range [0..1] for each component
|
||||
Quantity_TOC_HLS, //!< hue + light + saturation components, where:
|
||||
//! - First component is the Hue (H) angle in degrees within range [0.0; 360.0], 0.0 being Red;
|
||||
//! value -1.0 is a special value reserved for grayscale color (S should be 0.0).
|
||||
//! - Second component is the Lightness (L) within range [0.0; 1.0]
|
||||
//! - Third component is the Saturation (S) within range [0.0; 1.0]
|
||||
//! Normalized linear RGB (red, green, blue) values within range [0..1] for each component
|
||||
Quantity_TOC_RGB,
|
||||
|
||||
//! Normalized non-linear gamma-shifted RGB (red, green, blue) values within range [0..1] for each component
|
||||
Quantity_TOC_sRGB,
|
||||
|
||||
//! Hue + light + saturation components, where:
|
||||
//! - First component is the Hue (H) angle in degrees within range [0.0; 360.0], 0.0 being Red;
|
||||
//! value -1.0 is a special value reserved for grayscale color (S should be 0.0).
|
||||
//! - Second component is the Lightness (L) within range [0.0; 1.0]
|
||||
//! - Third component is the Saturation (S) within range [0.0; 1.0]
|
||||
Quantity_TOC_HLS,
|
||||
|
||||
//! CIE L*a*b* color space, constructed to be perceptually uniform for human eye.
|
||||
//! The values are assumed to be with respect to D65 2° white point.
|
||||
//!
|
||||
//! The color is defined by:
|
||||
//! - L: lightness in range [0, 100] (from black to white)
|
||||
//! - a: green-to-red axis, approximately in range [-90, 100]
|
||||
//! - b: blue-to-yellow axis, approximately in range [-110, 95]
|
||||
//!
|
||||
//! Note that not all combinations of L, a, and b values represent visible
|
||||
//! colors, and RGB cube takes only part of visible color space.
|
||||
//!
|
||||
//! When Lab color is converted to RGB, a and b components may be reduced
|
||||
//! (with the same proportion) to fit the result into the RGB range.
|
||||
Quantity_TOC_CIELab,
|
||||
|
||||
//! CIE L*c*h* color space, same as L*a*b* in cylindrical coordinates:
|
||||
//! - L: lightness in range [0, 100] (from black to white)
|
||||
//! - c: chroma, approximately in range [0, 135], 0 corresponds to greyscale
|
||||
//! - h: hue angle, in range [0., 360.]
|
||||
//!
|
||||
//! The hue values of standard colors are approximately:
|
||||
//! - red at 40,
|
||||
//! - yellow at 103,
|
||||
//! - green at 136,
|
||||
//! - cyan at 196,
|
||||
//! - blue at 306,
|
||||
//! - magenta at 328.
|
||||
//!
|
||||
//! When Lch color is converted to RGB, chroma component may be reduced
|
||||
//! to fit the color into the RGB range.
|
||||
Quantity_TOC_CIELch
|
||||
};
|
||||
|
||||
#endif // _Quantity_TypeOfColor_HeaderFile
|
||||
|
@@ -4831,6 +4831,14 @@ static int VColorScale (Draw_Interpretor& theDI,
|
||||
aColorScale->SetColors (aSeq);
|
||||
aColorScale->SetColorType (Aspect_TOCSD_USER);
|
||||
}
|
||||
else if (aFlag == "-uniform")
|
||||
{
|
||||
const Standard_Real aLightness = Draw::Atof (theArgVec[++anArgIter]);
|
||||
const Standard_Real aHueStart = Draw::Atof (theArgVec[++anArgIter]);
|
||||
const Standard_Real aHueEnd = Draw::Atof (theArgVec[++anArgIter]);
|
||||
aColorScale->SetUniformColors (aLightness, aHueStart, aHueEnd);
|
||||
aColorScale->SetColorType (Aspect_TOCSD_USER);
|
||||
}
|
||||
else if (aFlag == "-labels"
|
||||
|| aFlag == "-freelabels")
|
||||
{
|
||||
@@ -13750,6 +13758,91 @@ static int VViewCube (Draw_Interpretor& ,
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===============================================================================================
|
||||
//function : VColorConvert
|
||||
//purpose :
|
||||
//===============================================================================================
|
||||
static int VColorConvert (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
|
||||
{
|
||||
if (theNbArgs != 6)
|
||||
{
|
||||
std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Standard_Boolean convertFrom = (! strcasecmp (theArgVec[1], "from"));
|
||||
if (! convertFrom && strcasecmp (theArgVec[1], "to"))
|
||||
{
|
||||
std::cerr << "Error: first argument must be either \"to\" or \"from\"" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* aTypeStr = theArgVec[2];
|
||||
Quantity_TypeOfColor aType = Quantity_TOC_RGB;
|
||||
if (! strcasecmp (aTypeStr, "srgb"))
|
||||
{
|
||||
aType = Quantity_TOC_sRGB;
|
||||
}
|
||||
else if (! strcasecmp (aTypeStr, "hls"))
|
||||
{
|
||||
aType = Quantity_TOC_HLS;
|
||||
}
|
||||
else if (! strcasecmp (aTypeStr, "lab"))
|
||||
{
|
||||
aType = Quantity_TOC_CIELab;
|
||||
}
|
||||
else if (! strcasecmp (aTypeStr, "lch"))
|
||||
{
|
||||
aType = Quantity_TOC_CIELch;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: unknown colorspace type: " << aTypeStr << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
double aC1 = Draw::Atof (theArgVec[3]);
|
||||
double aC2 = Draw::Atof (theArgVec[4]);
|
||||
double aC3 = Draw::Atof (theArgVec[5]);
|
||||
|
||||
Quantity_Color aColor (aC1, aC2, aC3, convertFrom ? aType : Quantity_TOC_RGB);
|
||||
aColor.Values (aC1, aC2, aC3, convertFrom ? Quantity_TOC_RGB : aType);
|
||||
|
||||
// print values with 6 decimal digits
|
||||
char buffer[1024];
|
||||
Sprintf (buffer, "%.6f %.6f %.6f", aC1, aC2, aC3);
|
||||
theDI << buffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===============================================================================================
|
||||
//function : VColorDiff
|
||||
//purpose :
|
||||
//===============================================================================================
|
||||
static int VColorDiff (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgVec)
|
||||
{
|
||||
if (theNbArgs != 7)
|
||||
{
|
||||
std::cerr << "Error: command syntax is incorrect, see help" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
double aR1 = Draw::Atof (theArgVec[1]);
|
||||
double aG1 = Draw::Atof (theArgVec[2]);
|
||||
double aB1 = Draw::Atof (theArgVec[3]);
|
||||
double aR2 = Draw::Atof (theArgVec[4]);
|
||||
double aG2 = Draw::Atof (theArgVec[5]);
|
||||
double aB2 = Draw::Atof (theArgVec[6]);
|
||||
|
||||
Quantity_Color aColor1 (aR1, aG1, aB1, Quantity_TOC_RGB);
|
||||
Quantity_Color aColor2 (aR2, aG2, aB2, Quantity_TOC_RGB);
|
||||
|
||||
theDI << aColor1.DeltaE2000 (aColor2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : ViewerCommands
|
||||
//purpose :
|
||||
@@ -13992,9 +14085,11 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
|
||||
"\n\t\t: [-labels Label1 Label2 ...] [-label Index Label]"
|
||||
"\n\t\t: [-freeLabels NbOfLabels Label1 Label2 ...]"
|
||||
"\n\t\t: [-xy Left=0 Bottom=0]"
|
||||
"\n\t\t: [-uniform lightness hue_from hue_to]"
|
||||
"\n\t\t: -demo - displays a color scale with demonstratio values"
|
||||
"\n\t\t: -colors - set colors for all intervals"
|
||||
"\n\t\t: -color - set color for specific interval"
|
||||
"\n\t\t: -uniform - generate colors with the same lightness"
|
||||
"\n\t\t: -textpos - horizontal label position relative to color scale bar"
|
||||
"\n\t\t: -labelAtBorder - vertical label position relative to color interval;"
|
||||
"\n\t\t: at border means the value inbetween neighbor intervals,"
|
||||
@@ -14006,7 +14101,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
|
||||
"\n\t\t: -title - set title"
|
||||
"\n\t\t: -reversed - setup smooth color transition between intervals"
|
||||
"\n\t\t: -smoothTransition - swap colorscale direction"
|
||||
"\n\t\t: -hueRange - set hue angles corresponding to minimum and maximum values"
|
||||
"\n\t\t: -hueRange - set hue angles corresponding to minimum and maximum values",
|
||||
__FILE__, VColorScale, group);
|
||||
theCommands.Add("vgraduatedtrihedron",
|
||||
"vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
|
||||
@@ -14606,4 +14701,13 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
|
||||
"\n\t\t: -duration Seconds animation duration in seconds",
|
||||
__FILE__, VViewCube, group);
|
||||
|
||||
theCommands.Add("vcolorconvert" ,
|
||||
"vcolorconvert {from|to} type C1 C2 C2"
|
||||
"\n\t\t: vcolorconvert from type C1 C2 C2: Converts color from specified color space to linear RGB"
|
||||
"\n\t\t: vcolorconvert to type R G B: Converts linear RGB color to specified color space"
|
||||
"\n\t\t: type can be sRGB, HLS, Lab, or Lch",
|
||||
__FILE__,VColorConvert,group);
|
||||
theCommands.Add("vcolordiff" ,
|
||||
"vcolordiff R1 G1 B1 R2 G2 B2: returns CIEDE2000 color difference between two RGB colors",
|
||||
__FILE__,VColorDiff,group);
|
||||
}
|
||||
|
Reference in New Issue
Block a user