0029528: Visualization, TKOpenGl - allow defining sRGB textures
[occt.git] / src / Quantity / Quantity_Color.cxx
1 // Created by: NW,JPB,CAL
2 // Copyright (c) 1991-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Quantity_Color.hxx>
17
18 #include <Quantity_ColorRGBA.hxx>
19 #include <Standard_ErrorHandler.hxx>
20 #include <Standard_OutOfRange.hxx>
21 #include <Standard_Dump.hxx>
22 #include <TCollection_AsciiString.hxx>
23
24 #include <string.h>
25
26 #define RGBHLS_H_UNDEFINED -1.0
27
28 static Standard_Real TheEpsilon = 0.0001;
29
30 // Throw exception if RGB values are out of range.
31 #define Quantity_ColorValidateRgbRange(theR, theG, theB) \
32   if (theR < 0.0 || theR > 1.0 \
33    || theG < 0.0 || theG > 1.0 \
34    || theB < 0.0 || theB > 1.0) { throw Standard_OutOfRange("Color out"); }
35
36 // Throw exception if HLS values are out of range.
37 #define Quantity_ColorValidateHlsRange(theH, theL, theS) \
38   if ((theH < 0.0 && theH != RGBHLS_H_UNDEFINED && theS != 0.0) \
39    || (theH > 360.0) \
40     || theL < 0.0 || theL > 1.0 \
41     || theS < 0.0 || theS > 1.0) { throw Standard_OutOfRange("Color out"); }
42
43 namespace
44 {
45   //! Raw color for defining list of standard color
46   struct Quantity_StandardColor
47   {
48     const char*             StringName;
49     NCollection_Vec3<float> sRgbValues;
50     NCollection_Vec3<float> RgbValues;
51     Quantity_NameOfColor    EnumName;
52
53     Quantity_StandardColor (Quantity_NameOfColor theName,
54                             const char* theStringName,
55                             const NCollection_Vec3<float>& thesRGB,
56                             const NCollection_Vec3<float>& theRGB)
57     : StringName (theStringName),
58       sRgbValues (thesRGB),
59       RgbValues (theRGB),
60       EnumName (theName) {}
61   };
62 }
63
64 // Note that HTML/hex sRGB representation is ignored
65 #define RawColor(theName, theHex, SRGB, sR, sG, sB, RGB, theR, theG, theB) \
66   Quantity_StandardColor(Quantity_NOC_##theName, #theName, NCollection_Vec3<float>(sR##f, sG##f, sB##f), NCollection_Vec3<float>(theR##f, theG##f, theB##f))
67
68 //! Name list of standard materials (defined within enumeration).
69 static const Quantity_StandardColor THE_COLORS[] =
70 {
71 #include "Quantity_ColorTable.pxx"
72 };
73
74 // =======================================================================
75 // function : Epsilon
76 // purpose  :
77 // =======================================================================
78 Standard_Real Quantity_Color::Epsilon()
79 {
80   return TheEpsilon;
81 }
82
83 // =======================================================================
84 // function : SetEpsilon
85 // purpose  :
86 // =======================================================================
87 void Quantity_Color::SetEpsilon (const Standard_Real theEpsilon)
88 {
89   TheEpsilon = theEpsilon;
90 }
91
92 // =======================================================================
93 // function : valuesOf
94 // purpose  :
95 // =======================================================================
96 NCollection_Vec3<float> Quantity_Color::valuesOf (const Quantity_NameOfColor theName,
97                                                   const Quantity_TypeOfColor theType)
98 {
99   if ((Standard_Integer )theName < 0 || (Standard_Integer )theName > Quantity_NOC_WHITE)
100   {
101     throw Standard_OutOfRange("Bad name");
102   }
103
104   const NCollection_Vec3<float>& anRgb = THE_COLORS[theName].RgbValues;
105   switch (theType)
106   {
107     case Quantity_TOC_RGB:  return anRgb;
108     case Quantity_TOC_sRGB: return Convert_LinearRGB_To_sRGB (anRgb);
109     case Quantity_TOC_HLS:  return Convert_LinearRGB_To_HLS (anRgb);
110   }
111   throw Standard_ProgramError("Internal error");
112 }
113
114 // =======================================================================
115 // function : StringName
116 // purpose  :
117 // =======================================================================
118 Standard_CString Quantity_Color::StringName (const Quantity_NameOfColor theName)
119 {
120   if ((Standard_Integer )theName < 0 || (Standard_Integer )theName > Quantity_NOC_WHITE)
121   {
122     throw Standard_OutOfRange("Bad name");
123   }
124   return THE_COLORS[theName].StringName;
125 }
126
127 // =======================================================================
128 // function : ColorFromName
129 // purpose  :
130 // =======================================================================
131 Standard_Boolean Quantity_Color::ColorFromName (const Standard_CString theName,
132                                                 Quantity_NameOfColor&  theColor)
133 {
134   TCollection_AsciiString aName (theName);
135   aName.UpperCase();
136   if (aName.Search("QUANTITY_NOC_") == 1)
137   {
138     aName = aName.SubString (14, aName.Length());
139   }
140
141   for (Standard_Integer anIter = Quantity_NOC_BLACK; anIter <= Quantity_NOC_WHITE; ++anIter)
142   {
143     Standard_CString aColorName = THE_COLORS[anIter].StringName;
144     if (aName == aColorName)
145     {
146       theColor = (Quantity_NameOfColor )anIter;
147       return Standard_True;
148     }
149   }
150
151   // aliases
152   if      (aName == "BLUE1")       { theColor = Quantity_NOC_BLUE1; }
153   else if (aName == "CHARTREUSE1") { theColor = Quantity_NOC_CHARTREUSE1; }
154   else if (aName == "CYAN1")       { theColor = Quantity_NOC_CYAN1; }
155   else if (aName == "GOLD1")       { theColor = Quantity_NOC_GOLD1; }
156   else if (aName == "GREEN1")      { theColor = Quantity_NOC_GREEN1; }
157   else if (aName == "LIGHTCYAN1")  { theColor = Quantity_NOC_LIGHTCYAN1; }
158   else if (aName == "MAGENTA1")    { theColor = Quantity_NOC_MAGENTA1; }
159   else if (aName == "ORANGE1")     { theColor = Quantity_NOC_ORANGE1; }
160   else if (aName == "ORANGERED1")  { theColor = Quantity_NOC_ORANGERED1; }
161   else if (aName == "RED1")        { theColor = Quantity_NOC_RED1; }
162   else if (aName == "TOMATO1")     { theColor = Quantity_NOC_TOMATO1; }
163   else if (aName == "YELLOW1")     { theColor = Quantity_NOC_YELLOW1; }
164   else
165   {
166     return Standard_False;
167   }
168
169   return Standard_True;
170 }
171
172 //=======================================================================
173 // function : ColorFromHex
174 // purpose  :
175 //=======================================================================
176 bool Quantity_Color::ColorFromHex (const Standard_CString theHexColorString,
177                                    Quantity_Color& theColor)
178 {
179   Quantity_ColorRGBA aColorRGBA;
180   if (!Quantity_ColorRGBA::ColorFromHex (theHexColorString, aColorRGBA, true))
181   {
182     return false;
183   }
184   theColor = aColorRGBA.GetRGB();
185   return true;
186 }
187
188 // =======================================================================
189 // function : Quantity_Color
190 // purpose  :
191 // =======================================================================
192 Quantity_Color::Quantity_Color (const Standard_Real theR1, const Standard_Real theR2, const Standard_Real theR3,
193                                 const Quantity_TypeOfColor theType)
194 {
195   switch (theType)
196   {
197     case Quantity_TOC_RGB:
198     {
199       Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
200       myRgb.SetValues (float(theR1), float(theR2), float(theR3));
201       break;
202     }
203     case Quantity_TOC_sRGB:
204     {
205       Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
206       myRgb.SetValues ((float )Convert_sRGB_To_LinearRGB (theR1),
207                        (float )Convert_sRGB_To_LinearRGB (theR2),
208                        (float )Convert_sRGB_To_LinearRGB (theR3));
209       break;
210     }
211     case Quantity_TOC_HLS:
212     {
213       Quantity_ColorValidateHlsRange(theR1, theR2, theR3);
214       myRgb = Convert_HLS_To_LinearRGB (NCollection_Vec3<float> (float(theR1), float(theR2), float(theR3)));
215       break;
216     }
217   }
218 }
219
220 // =======================================================================
221 // function : Quantity_Color
222 // purpose  :
223 // =======================================================================
224 Quantity_Color::Quantity_Color (const NCollection_Vec3<float>& theRgb)
225 : myRgb (theRgb)
226 {
227   Quantity_ColorValidateRgbRange(theRgb.r(), theRgb.g(), theRgb.b());
228 }
229
230 // =======================================================================
231 // function : ChangeContrast
232 // purpose  :
233 // =======================================================================
234 void Quantity_Color::ChangeContrast (const Standard_Real theDelta)
235 {
236   NCollection_Vec3<float> aHls = Convert_LinearRGB_To_HLS (myRgb);
237   aHls[2] += aHls[2] * Standard_ShortReal (theDelta) / 100.0f; // saturation
238   if (!((aHls[2] > 1.0f) || (aHls[2] < 0.0f)))
239   {
240     myRgb = Convert_HLS_To_LinearRGB (aHls);
241   }
242 }
243
244 // =======================================================================
245 // function : ChangeIntensity
246 // purpose  :
247 // =======================================================================
248 void Quantity_Color::ChangeIntensity (const Standard_Real theDelta)
249 {
250   NCollection_Vec3<float> aHls = Convert_LinearRGB_To_HLS (myRgb);
251   aHls[1] += aHls[1] * Standard_ShortReal (theDelta) / 100.0f; // light
252   if (!((aHls[1] > 1.0f) || (aHls[1] < 0.0f)))
253   {
254     myRgb = Convert_HLS_To_LinearRGB (aHls);
255   }
256 }
257
258 // =======================================================================
259 // function : SetValues
260 // purpose  :
261 // =======================================================================
262 void Quantity_Color::SetValues (const Standard_Real theR1, const Standard_Real theR2, const Standard_Real theR3,
263                                 const Quantity_TypeOfColor theType)
264 {
265   switch (theType)
266   {
267     case Quantity_TOC_RGB:
268     {
269       Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
270       myRgb.SetValues (float(theR1), float(theR2), float(theR3));
271       break;
272     }
273     case Quantity_TOC_sRGB:
274     {
275       Quantity_ColorValidateRgbRange(theR1, theR2, theR3);
276       myRgb.SetValues ((float )Convert_sRGB_To_LinearRGB (theR1),
277                        (float )Convert_sRGB_To_LinearRGB (theR2),
278                        (float )Convert_sRGB_To_LinearRGB (theR3));
279       break;
280     }
281     case Quantity_TOC_HLS:
282     {
283       Quantity_ColorValidateHlsRange(theR1, theR2, theR3);
284       myRgb = Convert_HLS_To_LinearRGB (NCollection_Vec3<float> (float(theR1), float(theR2), float(theR3)));
285       break;
286     }
287   }
288 }
289
290 // =======================================================================
291 // function : Delta
292 // purpose  :
293 // =======================================================================
294 void Quantity_Color::Delta (const Quantity_Color& theColor,
295                             Standard_Real& theDC,
296                             Standard_Real& theDI) const
297 {
298   const NCollection_Vec3<float> aHls1 = Convert_LinearRGB_To_HLS (myRgb);
299   const NCollection_Vec3<float> aHls2 = Convert_LinearRGB_To_HLS (theColor.myRgb);
300   theDC = Standard_Real (aHls1[2] - aHls2[2]); // saturation
301   theDI = Standard_Real (aHls1[1] - aHls2[1]); // light
302 }
303
304 // =======================================================================
305 // function : Name
306 // purpose  :
307 // =======================================================================
308 Quantity_NameOfColor Quantity_Color::Name() const
309 {
310   // it is better finding closest sRGB color (closest to human eye) instead of linear RGB color,
311   // as enumeration defines color names for human
312   const NCollection_Vec3<float> ansRgbVec (Convert_LinearRGB_To_sRGB (NCollection_Vec3<Standard_Real> (myRgb)));
313   Standard_ShortReal aDist2 = ShortRealLast();
314   Quantity_NameOfColor aResName = Quantity_NOC_BLACK;
315   for (Standard_Integer aColIter = Quantity_NOC_BLACK; aColIter <= Quantity_NOC_WHITE; ++aColIter)
316   {
317     const Standard_ShortReal aNewDist2 = (ansRgbVec - THE_COLORS[aColIter].sRgbValues).SquareModulus();
318     if (aNewDist2 < aDist2)
319     {
320       aResName = Quantity_NameOfColor (aColIter);
321       aDist2 = aNewDist2;
322       if (aNewDist2 == 0.0f)
323       {
324         break;
325       }
326     }
327   }
328   return aResName;
329 }
330
331 // =======================================================================
332 // function : Values
333 // purpose  :
334 // =======================================================================
335 void Quantity_Color::Values (Standard_Real& theR1, Standard_Real& theR2, Standard_Real& theR3,
336                              const Quantity_TypeOfColor theType) const
337 {
338   switch (theType)
339   {
340     case Quantity_TOC_RGB:
341     {
342       theR1 = myRgb.r();
343       theR2 = myRgb.g();
344       theR3 = myRgb.b();
345       break;
346     }
347     case Quantity_TOC_sRGB:
348     {
349       theR1 = Convert_LinearRGB_To_sRGB ((Standard_Real )myRgb.r());
350       theR2 = Convert_LinearRGB_To_sRGB ((Standard_Real )myRgb.g());
351       theR3 = Convert_LinearRGB_To_sRGB ((Standard_Real )myRgb.b());
352       break;
353     }
354     case Quantity_TOC_HLS:
355     {
356       const NCollection_Vec3<float> aHls = Convert_LinearRGB_To_HLS (myRgb);
357       theR1 = aHls[0];
358       theR2 = aHls[1];
359       theR3 = aHls[2];
360       break;
361     }
362   }
363 }
364
365 // =======================================================================
366 // function : Convert_HLS_To_sRGB
367 // purpose  : Reference: La synthese d'images, Collection Hermes
368 // =======================================================================
369 NCollection_Vec3<float> Quantity_Color::Convert_HLS_To_sRGB (const NCollection_Vec3<float>& theHls)
370 {
371   float aHue = theHls[0];
372   const float aLight = theHls[1];
373   const float aSaturation = theHls[2];
374   if (aSaturation == 0.0f
375    && aHue == RGBHLS_H_UNDEFINED)
376   {
377     return NCollection_Vec3<float> (aLight, aLight, aLight);
378   }
379
380   int aHueIndex = 0;
381   float lmuls = aLight * aSaturation;
382   if (aHue == 360.0f)
383   {
384     aHue = 0.0;
385     aHueIndex = 0;
386   }
387   else
388   {
389     aHue /= 60.0f;
390     aHueIndex = (int )aHue;
391   }
392
393   switch (aHueIndex)
394   {
395     case 0: return NCollection_Vec3<float> (aLight,
396                                             aLight - lmuls + lmuls * aHue,
397                                             aLight - lmuls);
398     case 1: return NCollection_Vec3<float> (aLight + lmuls - lmuls * aHue,
399                                             aLight,
400                                             aLight - lmuls);
401     case 2: return NCollection_Vec3<float> (aLight - lmuls,
402                                             aLight,
403                                             aLight - 3 * lmuls + lmuls * aHue);
404     case 3: return NCollection_Vec3<float> (aLight - lmuls,
405                                             aLight + 3 * lmuls - lmuls * aHue,
406                                             aLight);
407     case 4: return NCollection_Vec3<float> (aLight - 5 * lmuls + lmuls * aHue,
408                                             aLight - lmuls,
409                                             aLight);
410     case 5 : return NCollection_Vec3<float> (aLight,
411                                              aLight - lmuls,
412                                              aLight + 5 * lmuls - lmuls * aHue);
413   }
414   throw Standard_OutOfRange("Color out");
415 }
416
417 // =======================================================================
418 // function : Convert_sRGB_To_HLS
419 // purpose  : Reference: La synthese d'images, Collection Hermes
420 // =======================================================================
421 NCollection_Vec3<float> Quantity_Color::Convert_sRGB_To_HLS (const NCollection_Vec3<float>& theRgb)
422 {
423   float aPlus = 0.0f;
424   float aDiff = theRgb.g() - theRgb.b();
425
426   // compute maximum from RGB components, which will be a luminance
427   float aMax = theRgb.r();
428   if (theRgb.g() > aMax) { aPlus = 2.0; aDiff = theRgb.b() - theRgb.r(); aMax = theRgb.g(); }
429   if (theRgb.b() > aMax) { aPlus = 4.0; aDiff = theRgb.r() - theRgb.g(); aMax = theRgb.b(); }
430
431   // compute minimum from RGB components
432   float min = theRgb.r();
433   if (theRgb.g() < min) min = theRgb.g();
434   if (theRgb.b() < min) min = theRgb.b();
435
436   const float aDelta = aMax - min;
437
438   // compute saturation
439   float aSaturation = 0.0f;
440   if (aMax != 0.0f) aSaturation = aDelta / aMax;
441
442   // compute hue
443   float aHue = RGBHLS_H_UNDEFINED;
444   if (aSaturation != 0.0f)
445   {
446     aHue = 60.0f * (aPlus + aDiff / aDelta);
447     if (aHue < 0.0f) aHue += 360.0f;
448   }
449   return NCollection_Vec3<float> (aHue, aMax, aSaturation);
450 }
451
452 ///////////////////////////////////////////////////////////////////////////////
453 //////////////////////////////////// TESTS ////////////////////////////////////
454 ///////////////////////////////////////////////////////////////////////////////
455 static void TestOfColor()
456 {
457   Standard_Real H, L, S;
458   Standard_Real R, G, B;
459   Standard_Real DC, DI;
460   Standard_Integer i;
461
462   std::cout << "definition color tests\n----------------------\n";
463
464   Quantity_Color C1;
465   Quantity_Color C2 (Quantity_NOC_ROYALBLUE2);
466   Quantity_Color C3 (Quantity_NOC_SANDYBROWN);
467
468   // An Introduction to Standard_Object-Oriented Programming and C++ p43
469   // a comment for the "const char *const" declaration
470   const char *const cyan = "YELLOW";
471   const char *const blue = "ROYALBLUE2";
472   const char *const brown = "SANDYBROWN";
473
474   Standard_Real RR, GG, BB;
475
476   const Standard_Real DELTA = 1.0e-4;
477
478   std::cout << "Get values and names of color tests\n-----------------------------------\n";
479
480   C1.Values (R, G, B, Quantity_TOC_RGB);
481   if ((R!=1.0) || (G!=1.0) || (B!=0.0))
482   {
483     std::cout << "TEST_ERROR : Values () bad default color\n";
484     std::cout << "R, G, B values: " << R << " " << G << " " << B << "\n";
485   }
486   if ( (C1.Red ()!=1.0) || (C1.Green ()!=1.0) || (C1.Blue ()!=0.0) )
487   {
488     std::cout << "TEST_ERROR : Values () bad default color\n";
489     std::cout << "R, G, B values: " << C1.Red () << " " << C1.Green () << " " << C1.Blue () << "\n";
490   }
491   if (strcmp (Quantity_Color::StringName (C1.Name()), cyan) != 0)
492   {
493     std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C1.Name()) <<  " != YELLOW\n";
494   }
495
496   RR=0.262745; GG=0.431373; BB=0.933333;
497   C1.SetValues (RR, GG, BB, Quantity_TOC_RGB);
498   C2.Values (R, G, B, Quantity_TOC_RGB);
499   if ((Abs (RR-R) > DELTA)
500    || (Abs (GG-G) > DELTA)
501    || (Abs (BB-B) > DELTA))
502   {
503     std::cout << "TEST_ERROR : Values () bad default color\n";
504     std::cout << "R, G, B values: " << R << " " << G << " " << B << "\n";
505   }
506
507   if (C2 != C1)
508   {
509     std::cout << "TEST_ERROR : IsDifferent ()\n";
510   }
511   if (C3 == C1)
512   {
513     std::cout << "TEST_ERROR : IsEqual ()\n";
514   }
515
516   std::cout << "Distance C1,C2 " << C1.Distance (C2) << "\n";
517   std::cout << "Distance C1,C3 " << C1.Distance (C3) << "\n";
518   std::cout << "Distance C2,C3 " << C2.Distance (C3) << "\n";
519   std::cout << "SquareDistance C1,C2 " << C1.SquareDistance (C2) << "\n";
520   std::cout << "SquareDistance C1,C3 " << C1.SquareDistance (C3) << "\n";
521   std::cout << "SquareDistance C2,C3 " << C2.SquareDistance (C3) << "\n";
522
523   if (strcmp (Quantity_Color::StringName (C2.Name()), blue) != 0)
524   {
525     std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C2.Name()) <<  " != ROYALBLUE2\n";
526   }
527
528   std::cout << "conversion rgbhls tests\n-----------------------\n";
529   Quantity_Color::RgbHls (R, G, B, H, L, S);
530   Quantity_Color::HlsRgb (H, L, S, R, G, B);
531   RR=0.262745; GG=0.431373; BB=0.933333;
532   if ((Abs (RR-R) > DELTA)
533    || (Abs (GG-G) > DELTA)
534    || (Abs (BB-B) > DELTA))
535   {
536     std::cout << "TEST_ERROR : RgbHls or HlsRgb bad conversion\n";
537     std::cout << "RGB init : " << RR << " " << GG << " " << BB << "\n";
538     std::cout << "RGB values : " << R << " " << G << " " << B << "\n";
539     std::cout << "Difference RGB : " << RR-R << " " << GG-G << " " << BB-B << "\n";
540   }
541
542   std::cout << "distance tests\n--------------\n";
543   R = (float ) 0.9568631; G = (float ) 0.6431371; B = (float ) 0.3764711;
544   C2.SetValues (R, G, B, Quantity_TOC_RGB);
545   if (C2.Distance (C3) > DELTA)
546   {
547     std::cout << "TEST_ERROR : Distance () bad result\n";
548     std::cout << "Distance C2 and C3 : " << C2.Distance (C3) << "\n";
549   }
550
551   C2.Delta (C3, DC, DI);
552   if (Abs (DC) > DELTA)
553   {
554     std::cout << "TEST_ERROR : Delta () bad result for DC\n";
555   }
556   if (Abs (DI) > DELTA)
557   {
558     std::cout << "TEST_ERROR : Delta () bad result for DI\n";
559   }
560
561   std::cout << "name tests\n----------\n";
562   R = (float ) 0.9568631; G = (float ) 0.6431371; B = (float ) 0.3764711;
563   C2.SetValues (R, G, B, Quantity_TOC_RGB);
564   if (strcmp (Quantity_Color::StringName (C2.Name()), brown) != 0)
565   {
566     std::cout << "TEST_ERROR : StringName () " << Quantity_Color::StringName (C2.Name()) <<  " != SANDYBROWN\n";
567   }
568
569   std::cout << "contrast change tests\n---------------------\n";
570   for (i=1; i<=10; i++)
571   {
572     C2.ChangeContrast (10.);
573     C2.ChangeContrast (-9.09090909);
574   }
575   C2.Values (R, G, B, Quantity_TOC_RGB);
576   RR=0.956863; GG=0.6431371; BB=0.3764711;
577   if ((Abs (RR-R) > DELTA)
578    || (Abs (GG-G) > DELTA)
579    || (Abs (BB-B) > DELTA))
580   {
581     std::cout << "TEST_ERROR : ChangeContrast () bad values\n";
582     std::cout << "RGB init : " << RR << " " << GG << " " << BB << "\n";
583     std::cout << "RGB values : " << R << " " << G << " " << B << "\n";
584   }
585 }
586
587 // =======================================================================
588 // function : Test
589 // purpose  :
590 // =======================================================================
591 void Quantity_Color::Test()
592 {
593   try
594   {
595     OCC_CATCH_SIGNALS
596     TestOfColor();
597   }
598   catch (Standard_Failure const& anException)
599   {
600     std::cout << anException << std::endl;
601   }
602 }
603
604 //=======================================================================
605 //function : DumpJson
606 //purpose  : 
607 //=======================================================================
608 void Quantity_Color::DumpJson (Standard_OStream& theOStream, const Standard_Integer) const
609 {
610   OCCT_DUMP_CLASS_BEGIN (theOStream, Quantity_Color);
611   OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "RGB", 3, myRgb.r(), myRgb.g(), myRgb.b())
612 }