0030623: Draw Harness - support hex color codes within ViewerTest::ParseColor() IR-2019-04-13 master
authortiv <tiv@opencascade.com>
Fri, 12 Apr 2019 07:45:25 +0000 (10:45 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 12 Apr 2019 15:48:18 +0000 (18:48 +0300)
ViewerTest::ParseColor() function is improved to be able to parse the following set of input arguments:
  - "Red Green Blue [Alpha]", where Red, Green, Blue, Alpha must be integers within the range [0, 255] or reals within the range [0.0, 1.0]. Note that "0 0 1" triple is parsed as "0.0 0.0 1.0" and will be interpreted as a blue color.
  - "ColorName [Alpha]", where ColorName is one of WHITE, BLACK, RED, GREEN, BLUE, etc. (look at Quantity_NameOfColor enumeration for all possible variants). Alpha may be integer or real, as described at the previous list item.
  - #HHH, [#]HHH[H], [#]HHHHHH[HH], where H is a hexadecimal digit (0 .. 9, a .. f, or A .. F). There are a short hexadecimal RGB, RGBA formats, and a usual RGB[A], respectively.

13 files changed:
src/Draw/Draw.hxx
src/Draw/Draw_VariableCommands.cxx
src/NCollection/NCollection_Mat4.hxx
src/NCollection/NCollection_Vec2.hxx
src/NCollection/NCollection_Vec3.hxx
src/NCollection/NCollection_Vec4.hxx
src/Quantity/FILES
src/Quantity/Quantity_Color.cxx
src/Quantity/Quantity_Color.hxx
src/Quantity/Quantity_ColorRGBA.cxx [new file with mode: 0644]
src/Quantity/Quantity_ColorRGBA.hxx
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest.hxx

index 929cd29..e718316 100644 (file)
@@ -95,12 +95,25 @@ public:
   //! Converts numeric expression, that can involve DRAW
   //! variables, to real value.
   Standard_EXPORT static Standard_Real Atof (const Standard_CString Name);
-  
+
+  //! Converts the numeric expression, that can involve DRAW variables, to a real value
+  //! @param theExpressionString the strings that containes the expression involving DRAW variables to be parsed
+  //! @param theParsedRealValue a real value that is a result of parsing
+  //! @return true if parsing was successfull, or false otherwise
+  Standard_EXPORT static bool ParseReal (const Standard_CString theExpressionString, Standard_Real& theParsedRealValue);
+
   //! Converts numeric expression, that can involve DRAW
   //! variables, to integer value.
   //! Implemented as cast of Atof() to integer.
   Standard_EXPORT static Standard_Integer Atoi (const Standard_CString Name);
-  
+
+  //! Converts the numeric expression, that can involve DRAW variables, to an integer value
+  //! @param theExpressionString the strings that containes the expression involving DRAW variables to be parsed
+  //! @param theParsedIntegerValue an integer value that is a result of parsing
+  //! @return true if parsing was successfull, or false otherwise
+  Standard_EXPORT static bool ParseInteger (const Standard_CString theExpressionString,
+                                            Standard_Integer&      theParsedIntegerValue);
+
   //! Returns last graphic selection description.
   Standard_EXPORT static void LastPick (Standard_Integer& view, Standard_Integer& X, Standard_Integer& Y, Standard_Integer& button);
   
index a4d34be..b571def 100644 (file)
@@ -1122,9 +1122,10 @@ static Standard_Real Parse(char*& name)
     }
   }
 }
+
 //=======================================================================
-//function : Atof
-//purpose  : 
+// function : Atof
+// purpose  :
 //=======================================================================
 Standard_Real Draw::Atof(const Standard_CString name)
 {
@@ -1132,6 +1133,7 @@ Standard_Real Draw::Atof(const Standard_CString name)
   char* n = new char[1+strlen(name)];
   char* b = n;
   strcpy(n,name);
+  Draw_ParseFailed = Standard_False;
   Standard_Real x = Parse(n);
   while ((*n == ' ') || (*n == '\t')) n++;
   if (*n) Draw_ParseFailed = Standard_True;
@@ -1139,10 +1141,51 @@ Standard_Real Draw::Atof(const Standard_CString name)
   return x;
 }
 
+//=======================================================================
+// function : ParseReal
+// purpose  :
+//=======================================================================
+bool Draw::ParseReal (const Standard_CString theExpressionString, Standard_Real& theParsedRealValue)
+{
+  const Standard_Real aParsedRealValue = Atof (theExpressionString);
+  if (Draw_ParseFailed)
+  {
+    Draw_ParseFailed = Standard_False;
+    return false;
+  }
+  theParsedRealValue = aParsedRealValue;
+  return true;
+}
+
+//=======================================================================
+// function : Atoi
+// purpose  :
+//=======================================================================
 Standard_Integer Draw::Atoi(const Standard_CString name)
 {
-  return (Standard_Integer ) Draw::Atof(name);
+  return (Standard_Integer) Draw::Atof(name);
 }
+
+//=======================================================================
+// function : ParseInteger
+// purpose  :
+//=======================================================================
+bool Draw::ParseInteger (const Standard_CString theExpressionString, Standard_Integer& theParsedIntegerValue)
+{
+  Standard_Real aParsedRealValue = 0.0;
+  if (!ParseReal (theExpressionString, aParsedRealValue))
+  {
+    return false;
+  }
+  const Standard_Integer aParsedIntegerValue = static_cast<Standard_Integer> (aParsedRealValue);
+  if (static_cast<Standard_Real> (aParsedIntegerValue) != aParsedRealValue)
+  {
+    return false;
+  }
+  theParsedIntegerValue = aParsedIntegerValue;
+  return true;
+}
+
 //=======================================================================
 //function : Set
 //purpose  : set a TCL var
index df74c37..c0ea4fe 100755 (executable)
@@ -49,6 +49,17 @@ public:
     InitIdentity();
   }
 
+  //! Conversion constructor (explicitly converts some 4 x 4 matrix with other element type
+  //! to a new 4 x 4 matrix with the element type Element_t,
+  //! whose elements are static_cast'ed corresponding elements of theOtherMat4 matrix)
+  //! @tparam OtherElement_t the element type of the other 4 x 4 matrix theOtherVec4
+  //! @param theOtherMat4 the 4 x 4 matrix that needs to be converted
+  template <typename OtherElement_t>
+  explicit NCollection_Mat4 (const NCollection_Mat4<OtherElement_t>& theOtherMat4)
+  {
+    ConvertFrom (theOtherMat4);
+  }
+
   //! Get element at the specified row and column.
   //! @param theRow [in] the row.to address.
   //! @param theCol [in] the column to address.
index c1ebb05..f54cae2 100644 (file)
@@ -57,6 +57,18 @@ public:
     v[1] = theY;
   }
 
+  //! Conversion constructor (explicitly converts some 2-component vector with other element type
+  //! to a new 2-component vector with the element type Element_t,
+  //! whose elements are static_cast'ed corresponding elements of theOtherVec2 vector)
+  //! @tparam OtherElement_t the element type of the other 2-component vector theOtherVec2
+  //! @param theOtherVec2 the 2-component vector that needs to be converted
+  template <typename OtherElement_t>
+  explicit NCollection_Vec2 (const NCollection_Vec2<OtherElement_t>& theOtherVec2)
+  {
+    v[0] = static_cast<Element_t> (theOtherVec2[0]);
+    v[1] = static_cast<Element_t> (theOtherVec2[1]);
+  }
+
   //! Assign new values to the vector.
   void SetValues (const Element_t theX,
                   const Element_t theY)
index 7a4e45b..fc2b481 100644 (file)
@@ -73,6 +73,19 @@ public:
     v[2] = theZ;
   }
 
+  //! Conversion constructor (explicitly converts some 3-component vector with other element type
+  //! to a new 3-component vector with the element type Element_t,
+  //! whose elements are static_cast'ed corresponding elements of theOtherVec3 vector)
+  //! @tparam OtherElement_t the element type of the other 3-component vector theOtherVec3
+  //! @param theOtherVec3 the 3-component vector that needs to be converted
+  template <typename OtherElement_t>
+  explicit NCollection_Vec3 (const NCollection_Vec3<OtherElement_t>& theOtherVec3)
+  {
+    v[0] = static_cast<Element_t> (theOtherVec3[0]);
+    v[1] = static_cast<Element_t> (theOtherVec3[1]);
+    v[2] = static_cast<Element_t> (theOtherVec3[2]);
+  }
+
   //! Assign new values to the vector.
   void SetValues (const Element_t theX,
                   const Element_t theY,
index f049585..b3c84ae 100644 (file)
@@ -73,6 +73,20 @@ public:
     v[3] = theW;
   }
 
+  //! Conversion constructor (explicitly converts some 4-component vector with other element type
+  //! to a new 4-component vector with the element type Element_t,
+  //! whose elements are static_cast'ed corresponding elements of theOtherVec4 vector)
+  //! @tparam OtherElement_t the element type of the other 4-component vector theOtherVec4
+  //! @param theOtherVec4 the 4-component vector that needs to be converted
+  template <typename OtherElement_t>
+  explicit NCollection_Vec4 (const NCollection_Vec4<OtherElement_t>& theOtherVec4)
+  {
+    v[0] = static_cast<Element_t> (theOtherVec4[0]);
+    v[1] = static_cast<Element_t> (theOtherVec4[1]);
+    v[2] = static_cast<Element_t> (theOtherVec4[2]);
+    v[3] = static_cast<Element_t> (theOtherVec4[3]);
+  }
+
   //! Assign new values to the vector.
   void SetValues (const Element_t theX,
                   const Element_t theY,
index 121a03b..fa0ce01 100755 (executable)
@@ -14,6 +14,7 @@ Quantity_CoefficientOfExpansion.hxx
 Quantity_Color.cxx
 Quantity_Color.hxx
 Quantity_ColorHasher.hxx
+Quantity_ColorRGBA.cxx
 Quantity_ColorRGBA.hxx
 Quantity_ColorRGBAHasher.hxx
 Quantity_ColorDefinitionError.hxx
index 3c056ff..1662a57 100644 (file)
@@ -16,6 +16,7 @@
 #include <Quantity_Color.hxx>
 
 #include <Quantity_ColorDefinitionError.hxx>
+#include <Quantity_ColorRGBA.hxx>
 #include <Standard_ErrorHandler.hxx>
 #include <Standard_OutOfRange.hxx>
 #include <TCollection_AsciiString.hxx>
@@ -66,6 +67,21 @@ Standard_Boolean Quantity_Color::ColorFromName (const Standard_CString theName,
   return Standard_False;
 }
 
+//=======================================================================
+// function : ColorFromHex
+// purpose  :
+//=======================================================================
+bool Quantity_Color::ColorFromHex (const Standard_CString theHexColorString, Quantity_Color& theColor)
+{
+  Quantity_ColorRGBA aColorRGBA;
+  if (!Quantity_ColorRGBA::ColorFromHex (theHexColorString, aColorRGBA, true))
+  {
+    return false;
+  }
+  theColor = aColorRGBA.GetRGB();
+  return true;
+}
+
 Quantity_Color::Quantity_Color () {
 
        Quantity_Color::ValuesOf
index a31c38d..07ce584 100644 (file)
@@ -222,7 +222,31 @@ Standard_Boolean operator == (const Quantity_Color& Other) const
   //! corresponds to "BLACK" is Quantity_NOC_BLACK.
   //! Returns false if name is unknown.
   Standard_EXPORT static Standard_Boolean ColorFromName (const Standard_CString theName, Quantity_NameOfColor& theColor);
-  
+
+  //! Finds color from predefined names.
+  //! For example, the name of the color which
+  //! corresponds to "BLACK" is Quantity_NOC_BLACK.
+  //! Returns false if name is unknown.
+  //! @param theColorNameString the color name
+  //! @param theColor a found color
+  //! @return false if the color name is unknown, or true if the search by color name was successful
+  static Standard_Boolean ColorFromName (const Standard_CString theColorNameString, Quantity_Color& theColor)
+  {
+    Quantity_NameOfColor aColorName = Quantity_NOC_BLACK;
+    if (!ColorFromName (theColorNameString, aColorName))
+    {
+      return false;
+    }
+    theColor = aColorName;
+    return true;
+  }
+
+  //! Parses the string as a hex color (like "#FF0" for short RGB color, or "#FFFF00" for RGB color)
+  //! @param theHexColorString the string to be parsed
+  //! @param theColor a color that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  Standard_EXPORT static bool ColorFromHex (const Standard_CString theHexColorString, Quantity_Color& theColor);
+
   //! Converts HLS components into RGB ones.
   Standard_EXPORT static void HlsRgb (const Standard_Real H, const Standard_Real L, const Standard_Real S, Standard_Real& R, Standard_Real& G, Standard_Real& B);
   
diff --git a/src/Quantity/Quantity_ColorRGBA.cxx b/src/Quantity/Quantity_ColorRGBA.cxx
new file mode 100644 (file)
index 0000000..b7ade56
--- /dev/null
@@ -0,0 +1,200 @@
+// Created on: 2019-03-22
+// Created by: Timur Izmaylov
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Quantity_ColorRGBA.hxx>
+
+#include <Graphic3d_Vec4.hxx>
+
+#include <algorithm>
+
+namespace
+{
+
+  //! The integer type used to represent some color or color component
+  typedef unsigned int ColorInteger;
+
+  //! Defines all possible lengths of strings representing color in hex format
+  enum HexColorLength
+  {
+    HexColorLength_ShortRGB  = 3, //!< short RGB hex color format
+    HexColorLength_ShortRGBA = 4, //!< short RGBA hex color format
+    HexColorLength_RGB       = 6, //!< RGB hex color format
+    HexColorLength_RGBA      = 8  //!< RGBA hex color format
+  };
+
+  //! Takes next color component from the integer representing a color (it is a step in a process of a conversion
+  //! implemented by the function ConvertIntegerToColorRGBA)
+  //! @param theColorInteger the integer representing a color
+  //! @param theColorComponentBase the base of the numeral system used to represent a color
+  //! @return a color component taken from the integer
+  static Standard_ShortReal takeColorComponentFromInteger (ColorInteger&      theColorInteger,
+                                                           const ColorInteger theColorComponentBase)
+  {
+    Standard_ASSERT_RETURN (theColorComponentBase >= 2,
+                            __FUNCTION__ ": 'theColorComponentBase' must be greater than 1.",
+                            0.0f);
+    const ColorInteger       aColorComponentMaxValue  = theColorComponentBase - 1;
+    const ColorInteger       aColorComponentAsInteger = theColorInteger % theColorComponentBase;
+    const Standard_ShortReal aColorComponent          = aColorComponentAsInteger * 1.0f / aColorComponentMaxValue;
+    theColorInteger /= theColorComponentBase;
+    return aColorComponent;
+  }
+
+  //! Converts the integer representing a color to a RGBA color object
+  //! @param theColorInteger the integer representing a color (using the numerical system based
+  //! on theColorComponentBase value, where color components represent digits:
+  //! an alpha component is a low number and a red component is a high number)
+  //! @param theColorComponentBase the base of the numeral system used to represent a color
+  //! @param hasAlphaComponent true if the integer to be converted contains an alpha component value
+  //! @param theColor a color that is a result of a conversion
+  //! @return true if a conversion was successful, or false otherwise
+  static bool convertIntegerToColorRGBA (ColorInteger        theColorInteger,
+                                         const ColorInteger  theColorComponentBase,
+                                         const bool          hasAlphaComponent,
+                                         Quantity_ColorRGBA& theColor)
+  {
+    Standard_ASSERT_RETURN (theColorComponentBase >= 2,
+                            __FUNCTION__ ": 'theColorComponentBase' must be greater than 1.",
+                            0.0f);
+    Graphic3d_Vec4 aColor (1.0f);
+    if (hasAlphaComponent)
+    {
+      const Standard_ShortReal anAlphaComponent = takeColorComponentFromInteger (theColorInteger,
+                                                                                 theColorComponentBase);
+      aColor.a()                                = anAlphaComponent;
+    }
+    for (Standard_Integer aColorComponentIndex = 2; aColorComponentIndex >= 0; --aColorComponentIndex)
+    {
+      const Standard_ShortReal aColorComponent = takeColorComponentFromInteger (theColorInteger, theColorComponentBase);
+      aColor[aColorComponentIndex]             = aColorComponent;
+    }
+    if (theColorInteger != 0)
+    {
+      return false;
+    }
+    theColor = Quantity_ColorRGBA (aColor);
+    return true;
+  }
+
+  //! Converts the string to an integer number using the number base
+  //! @tparam TheNumber the type of a resulting number
+  //! @param theString the string to be converted
+  //! @param theNumber a number that is the result of the conversion
+  //! @param theBase the base of a numeral system used to represent a number in a string form
+  //! @return true if a conversion was successful, or false otherwise
+  template <typename TheNumber>
+  static bool convertStringToInteger (const char* const theString, TheNumber& theNumber, const TheNumber theBase = 10)
+  {
+    std::stringstream aConversionStringStream;
+    aConversionStringStream << std::setbase (theBase) << theString;
+    if (aConversionStringStream.fail())
+    {
+      return false;
+    }
+    aConversionStringStream >> theNumber;
+    if (aConversionStringStream.fail())
+    {
+      return false;
+    }
+    return true;
+  }
+
+  //! Checks if the character is a hexadecimal digit (0 .. 9, a .. f, A .. F)
+  //! @param theCharacter the character to be checked
+  //! @return true if the checking character is a hexadecimal digit, or false otherwise
+  static bool isHexDigit (const char theCharacter)
+  {
+    return std::isxdigit (static_cast<unsigned char> (theCharacter)) != 0;
+  }
+
+  //! Checks if the string consists only of hexadecimal digits (0 .. 9, a .. f, A .. F)
+  //! @param theString the string to be checked
+  //! @param theLength the length of the checked string
+  //! @return true if the checking string consists only of hexadecimal digits, or false otherwise
+  //! an empty string is not interpreted as a hex string
+  static bool isHexString (const char* const theString, const std::size_t theLength)
+  {
+    if (theLength == 0)
+    {
+      return false;
+    }
+    // std::all_of is not used due to VS2008 compilability limitation
+    return std::count_if (theString, theString + theLength, isHexDigit) == static_cast<std::ptrdiff_t> (theLength);
+  }
+
+} // namespace
+
+//=======================================================================
+// function : ColorFromHex
+// purpose  :
+//=======================================================================
+bool Quantity_ColorRGBA::ColorFromHex (const char* const   theHexColorString,
+                                       Quantity_ColorRGBA& theColor,
+                                       const bool          theAlphaComponentIsOff)
+{
+  std::size_t aHexColorStringLength = std::strlen (theHexColorString);
+  if (aHexColorStringLength == 0)
+  {
+    return false;
+  }
+
+  const bool        hasPrefix       = (theHexColorString[0] == '#');
+  const std::size_t aPrefixLength   = hasPrefix ? 1 : 0;
+  const char* const aHexColorString = theHexColorString + aPrefixLength;
+  aHexColorStringLength -= aPrefixLength;
+  if (!isHexString (aHexColorString, aHexColorStringLength))
+  {
+    return false;
+  }
+
+  ColorInteger aHexColorInteger;
+  if (!convertStringToInteger (aHexColorString, aHexColorInteger, 16u))
+  {
+    return false;
+  }
+
+  bool hasAlphaComponent = false;
+  bool isShort           = false;
+  switch (static_cast<HexColorLength> (aHexColorStringLength))
+  {
+    case HexColorLength_ShortRGBA:
+      hasAlphaComponent = true;
+      Standard_FALLTHROUGH
+    case HexColorLength_ShortRGB:
+      isShort = true;
+      break;
+    case HexColorLength_RGBA:
+      hasAlphaComponent = true;
+      break;
+    case HexColorLength_RGB:
+      break;
+    default:
+      return false;
+  }
+  if (theAlphaComponentIsOff && hasAlphaComponent)
+  {
+    return false;
+  }
+  // to distinguish with a usual integer color component value
+  if (isShort && !hasAlphaComponent && !hasPrefix)
+  {
+    return false;
+  }
+
+  const ColorInteger THE_HEX_COLOR_COMPONENT_BASE       = 1 << 8;
+  const ColorInteger THE_HEX_COLOR_COMPONENT_SHORT_BASE = 1 << 4;
+  const ColorInteger aColorComponentBase = isShort ? THE_HEX_COLOR_COMPONENT_SHORT_BASE : THE_HEX_COLOR_COMPONENT_BASE;
+  return convertIntegerToColorRGBA (aHexColorInteger, aColorComponentBase, hasAlphaComponent, theColor);
+}
index 8f91d9f..c67cd52 100644 (file)
@@ -91,6 +91,36 @@ public:
   //! Two colors are considered to be equal if their distance is no greater than Epsilon().
   bool operator== (const Quantity_ColorRGBA& theOther) const { return IsEqual (theOther); }
 
+  //! Finds color from predefined names.
+  //! For example, the name of the color which
+  //! corresponds to "BLACK" is Quantity_NOC_BLACK.
+  //! Returns false if name is unknown.
+  //! An alpha component is set to 1.0.
+  //! @param theColorNameString the color name
+  //! @param theColor a found color
+  //! @return false if the color name is unknown, or true if the search by color name was successful
+  static Standard_Boolean ColorFromName (const Standard_CString theColorNameString, Quantity_ColorRGBA& theColor)
+  {
+    Quantity_ColorRGBA aColor;
+    if (!Quantity_Color::ColorFromName (theColorNameString, aColor.ChangeRGB()))
+    {
+      return false;
+    }
+    theColor = aColor;
+    return true;
+  }
+
+  //! Parses the string as a hex color (like "#FF0" for short RGB color, "#FF0F" for short RGBA color,
+  //! "#FFFF00" for RGB color, or "#FFFF00FF" for RGBA color)
+  //! @param theHexColorString the string to be parsed
+  //! @param theColor a color that is a result of parsing
+  //! @param theAlphaComponentIsOff the flag that indicates if a color alpha component is presented
+  //! in the input string (false) or not (true)
+  //! @return true if parsing was successful, or false otherwise
+  Standard_EXPORT static bool ColorFromHex (const char* const   theHexColorString,
+                                            Quantity_ColorRGBA& theColor,
+                                            const bool          theAlphaComponentIsOff = false);
+
 private:
 
   static void myTestSize3() { Standard_STATIC_ASSERT (sizeof(float) * 3 == sizeof(Quantity_Color)); }
index 5500112..bee28db 100644 (file)
@@ -82,9 +82,169 @@ extern int ViewerMainLoop(Standard_Integer argc, const char** argv);
 #define DEFAULT_FREEBOUNDARY_COLOR Quantity_NOC_GREEN
 #define DEFAULT_MATERIAL           Graphic3d_NOM_BRASS
 
+namespace
+{
+
+  const Standard_Integer THE_MAX_INTEGER_COLOR_COMPONENT = 255;
+
+  const Standard_ShortReal THE_MAX_REAL_COLOR_COMPONENT = 1.0f;
+
+  //! Parses string and get an integer color component (only values within range 0 .. 255 are allowed)
+  //! @param theColorComponentString the string representing the color component
+  //! @param theIntegerColorComponent an integer color component that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
+                                            Standard_Integer&      theIntegerColorComponent)
+  {
+    Standard_Integer anIntegerColorComponent;
+    if (!Draw::ParseInteger (theColorComponentString, anIntegerColorComponent))
+    {
+      return false;
+    }
+    if ((anIntegerColorComponent < 0) || (anIntegerColorComponent > THE_MAX_INTEGER_COLOR_COMPONENT))
+    {
+      return false;
+    }
+    theIntegerColorComponent = anIntegerColorComponent;
+    return true;
+  }
+
+  //! Parses the string and gets a real color component from it (only values within range 0.0 .. 1.0 are allowed)
+  //! @param theColorComponentString the string representing the color component
+  //! @param theRealColorComponent a real color component that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  static bool parseNumericalColorComponent (const Standard_CString theColorComponentString,
+                                            Standard_ShortReal&    theRealColorComponent)
+  {
+    Standard_Real aRealColorComponent;
+    if (!Draw::ParseReal (theColorComponentString, aRealColorComponent))
+    {
+      return false;
+    }
+    const Standard_ShortReal aShortRealColorComponent = static_cast<Standard_ShortReal> (aRealColorComponent);
+    if ((aShortRealColorComponent < 0.0f) || (aShortRealColorComponent > THE_MAX_REAL_COLOR_COMPONENT))
+    {
+      return false;
+    }
+    theRealColorComponent = aShortRealColorComponent;
+    return true;
+  }
+
+  //! Parses the string and gets a real color component from it (integer values 2 .. 255 are scaled to the 0.0 .. 1.0
+  //! range, values 0 and 1 are leaved as they are)
+  //! @param theColorComponentString the string representing the color component
+  //! @param theColorComponent a color component that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  static bool parseColorComponent (const Standard_CString theColorComponentString,
+                                   Standard_ShortReal&    theColorComponent)
+  {
+    Standard_Integer anIntegerColorComponent;
+    if (parseNumericalColorComponent (theColorComponentString, anIntegerColorComponent))
+    {
+      if (anIntegerColorComponent == 1)
+      {
+        theColorComponent = THE_MAX_REAL_COLOR_COMPONENT;
+      }
+      else
+      {
+        theColorComponent = anIntegerColorComponent * 1.0f / THE_MAX_INTEGER_COLOR_COMPONENT;
+      }
+      return true;
+    }
+    return parseNumericalColorComponent (theColorComponentString, theColorComponent);
+  }
+
+  //! Parses the array of strings and gets an integer color (only values within range 0 .. 255 are allowed and at least
+  //! one of components must be greater than 1)
+  //! @tparam TheNumber the type of resulting color vector elements
+  //! @param theNumberOfColorComponents the number of color components
+  //! @param theColorComponentStrings the array of strings representing color components
+  //! @param theNumericalColor a 4-component vector that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  template <typename TheNumber>
+  static bool parseNumericalColor (Standard_Integer&            theNumberOfColorComponents,
+                                   const char* const* const     theColorComponentStrings,
+                                   NCollection_Vec4<TheNumber>& theNumericalColor)
+  {
+    for (Standard_Integer aColorComponentIndex = 0; aColorComponentIndex < theNumberOfColorComponents;
+         ++aColorComponentIndex)
+    {
+      const char* const aColorComponentString = theColorComponentStrings[aColorComponentIndex];
+      TheNumber         aNumericalColorComponent;
+      if (parseNumericalColorComponent (aColorComponentString, aNumericalColorComponent))
+      {
+        theNumericalColor[aColorComponentIndex] = aNumericalColorComponent;
+      }
+      else
+      {
+        if (aColorComponentIndex == 3)
+        {
+          theNumberOfColorComponents = 3;
+        }
+        else
+        {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  //! Parses an array of strings and get an integer color (only values within range 0 .. 255 are allowed and at least
+  //! one of components must be greater than 1)
+  //! @param theNumberOfColorComponents the number of color components
+  //! @param theColorComponentStrings the array of strings representing color components
+  //! @param theColor a color that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  static bool parseIntegerColor (Standard_Integer&        theNumberOfColorComponents,
+                                 const char* const* const theColorComponentStrings,
+                                 Quantity_ColorRGBA&      theColor)
+  {
+    const Standard_Integer THE_COLOR_COMPONENT_NOT_PARSED = -1;
+    Graphic3d_Vec4i        anIntegerColor (THE_COLOR_COMPONENT_NOT_PARSED);
+    if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, anIntegerColor))
+    {
+      return false;
+    }
+
+    const bool hasColorComponentGreaterThanOne = (anIntegerColor.maxComp() > 1);
+    if (anIntegerColor.a() == THE_COLOR_COMPONENT_NOT_PARSED)
+    {
+      anIntegerColor.a() = THE_MAX_INTEGER_COLOR_COMPONENT;
+    }
+
+    Graphic3d_Vec4 aRealColor (anIntegerColor);
+    if (hasColorComponentGreaterThanOne)
+    {
+      aRealColor /= static_cast<Standard_ShortReal> (THE_MAX_INTEGER_COLOR_COMPONENT);
+    }
+    theColor = Quantity_ColorRGBA (aRealColor);
+    return true;
+  }
+
+  //! Parses an array of strings and get a real color (only values within range 0.0 .. 1.0 are allowed)
+  //! @param theNumberOfColorComponents the number of color components
+  //! @param theColorComponentStrings the array of strings representing color components
+  //! @param theColor a color that is a result of parsing
+  //! @return true if parsing was successful, or false otherwise
+  static bool parseRealColor (Standard_Integer&        theNumberOfColorComponents,
+                              const char* const* const theColorComponentStrings,
+                              Quantity_ColorRGBA&      theColor)
+  {
+    Graphic3d_Vec4 aRealColor (THE_MAX_REAL_COLOR_COMPONENT);
+    if (!parseNumericalColor (theNumberOfColorComponents, theColorComponentStrings, aRealColor))
+    {
+      return false;
+    }
+    theColor = Quantity_ColorRGBA (aRealColor);
+    return true;
+  }
+
+} // namespace
+
 //=======================================================================
-//function : GetColorFromName
-//purpose  : get the Quantity_NameOfColor from a string
+// function : GetColorFromName
+// purpose  : get the Quantity_NameOfColor from a string
 //=======================================================================
 
 Quantity_NameOfColor ViewerTest::GetColorFromName (const Standard_CString theName)
@@ -94,67 +254,47 @@ Quantity_NameOfColor ViewerTest::GetColorFromName (const Standard_CString theNam
   return aColor;
 }
 
-
 //=======================================================================
-//function : parseColor
-//purpose  :
+// function : parseColor
+// purpose  :
 //=======================================================================
-Standard_Integer ViewerTest::parseColor (Standard_Integer  theArgNb,
-                                         const char**      theArgVec,
-                                         Quantity_ColorRGBA& theColor,
-                                         bool theToParseAlpha)
+Standard_Integer ViewerTest::parseColor (const Standard_Integer   theArgNb,
+                                         const char* const* const theArgVec,
+                                         Quantity_ColorRGBA&      theColor,
+                                         const bool               theToParseAlpha)
 {
-  Quantity_NameOfColor aColor = Quantity_NOC_BLACK;
-  if (theArgNb >= 1
-   && Quantity_Color::ColorFromName (theArgVec[0], aColor))
+  if ((theArgNb >= 1) && Quantity_ColorRGBA::ColorFromHex (theArgVec[0], theColor, !theToParseAlpha))
+  {
+    return 1;
+  }
+  if (theArgNb >= 1 && Quantity_ColorRGBA::ColorFromName (theArgVec[0], theColor))
   {
-    theColor = Quantity_ColorRGBA (aColor);
-    if (theArgNb >= 2
-     && theToParseAlpha)
+    if (theArgNb >= 2 && theToParseAlpha)
     {
-      const TCollection_AsciiString anAlphaStr (theArgVec[1]);
-      if (anAlphaStr.IsRealValue())
+      const Standard_CString anAlphaStr = theArgVec[1];
+      Standard_ShortReal     anAlphaComponent;
+      if (parseColorComponent (anAlphaStr, anAlphaComponent))
       {
-        float anAlpha = (float )anAlphaStr.RealValue();
-        if (anAlpha < 0.0f || anAlpha > 1.0f)
-        {
-          std::cout << "Syntax error: alpha should be within range 0..1!\n";
-          return 0;
-        }
+        theColor.SetAlpha (anAlphaComponent);
         return 2;
       }
     }
     return 1;
   }
-  else if (theArgNb >= 3)
+  if (theArgNb >= 3)
   {
-    Graphic3d_Vec4 anRgba (0.0f, 0.0f, 0.0f, 1.0f);
-    Standard_Integer aNbComps = Min (theArgNb, theToParseAlpha ? 4 : 3);
-    for (int aCompIter = 0; aCompIter < aNbComps; ++aCompIter)
+    const Standard_Integer aNumberOfColorComponentsToParse = Min (theArgNb, theToParseAlpha ? 4 : 3);
+    Standard_Integer       aNumberOfColorComponentsParsed  = aNumberOfColorComponentsToParse;
+    if (parseIntegerColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
     {
-      const TCollection_AsciiString anRgbaStr (theArgVec[aCompIter]);
-      if (!anRgbaStr.IsRealValue())
-      {
-        if (aCompIter == 3)
-        {
-          anRgba.a() = 1.0f;
-          aNbComps = 3;
-          break;
-        }
-        return 0;
-      }
-
-      anRgba[aCompIter] = (float )anRgbaStr.RealValue();
-      if (anRgba[aCompIter] < 0.0 || anRgba[aCompIter] > 1.0)
-      {
-        std::cout << "Error: RGBA color values should be within range 0..1!\n";
-        return 0;
-      }
+      return aNumberOfColorComponentsParsed;
+    }
+    if (parseRealColor (aNumberOfColorComponentsParsed, theArgVec, theColor))
+    {
+      return aNumberOfColorComponentsParsed;
     }
-    theColor = Quantity_ColorRGBA (anRgba);
-    return aNbComps;
+    return 0;
   }
-
   return 0;
 }
 
index a4d1165..b9665cf 100644 (file)
@@ -153,22 +153,22 @@ public:
   //! Handles either color specified by name (single argument)
   //! or by RGB(A) components (3-4 arguments) in range 0..1.
   //! The result is stored in theColor on success.
-  //! Returns number of handled arguments (1, 3 or 4) or 0 on syntax error.
-  static Standard_Integer ParseColor (Standard_Integer  theArgNb,
-                                      const char**      theArgVec,
-                                      Quantity_ColorRGBA& theColor)
+  //! Returns number of handled arguments (1, 2, 3 or 4) or 0 on syntax error.
+  static Standard_Integer ParseColor (const Standard_Integer   theArgNb,
+                                      const char* const* const theArgVec,
+                                      Quantity_ColorRGBA&      theColor)
   {
     return parseColor (theArgNb, theArgVec, theColor, true);
   }
 
   //! Parses RGB color argument(s).
   //! Returns number of handled arguments (1 or 3) or 0 on syntax error.
-  static Standard_Integer ParseColor (Standard_Integer theArgNb,
-                                      const char**     theArgVec,
-                                      Quantity_Color&  theColor)
+  static Standard_Integer ParseColor (const Standard_Integer   theArgNb,
+                                      const char* const* const theArgVec,
+                                      Quantity_Color&          theColor)
   {
     Quantity_ColorRGBA anRgba;
-    Standard_Integer aNbParsed = parseColor (theArgNb, theArgVec, anRgba, false);
+    const Standard_Integer aNbParsed = parseColor (theArgNb, theArgVec, anRgba, false);
     if (aNbParsed != 0)
     {
       theColor = anRgba.GetRGB();
@@ -236,11 +236,11 @@ private:
   //! Handles either color specified by name (single argument)
   //! or by RGB(A) components (3-4 arguments) in range 0..1.
   //! The result is stored in theColor on success.
-  //! Returns number of handled arguments (1, 3 or 4) or 0 on syntax error.
-  Standard_EXPORT static Standard_Integer parseColor (Standard_Integer  theArgNb,
-                                                      const char**      theArgVec,
+  //! Returns number of handled arguments (1, 2, 3 or 4) or 0 on syntax error.
+  Standard_EXPORT static Standard_Integer parseColor (Standard_Integer    theArgNb,
+                                                      const char* const*  theArgVec,
                                                       Quantity_ColorRGBA& theColor,
-                                                      bool theToParseAlpha);
+                                                      bool                theToParseAlpha);
 
   //! Parses ZLayer name.
   //! @param theArg [in] layer name, enumeration alias or index (of existing Layer)