From f9b30c0db34c00de8b7a3d0724f3b46e23dfd590 Mon Sep 17 00:00:00 2001 From: tiv Date: Fri, 12 Apr 2019 10:45:25 +0300 Subject: [PATCH] 0030623: Draw Harness - support hex color codes within ViewerTest::ParseColor() 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. --- src/Draw/Draw.hxx | 17 +- src/Draw/Draw_VariableCommands.cxx | 49 +++++- src/NCollection/NCollection_Mat4.hxx | 11 ++ src/NCollection/NCollection_Vec2.hxx | 12 ++ src/NCollection/NCollection_Vec3.hxx | 13 ++ src/NCollection/NCollection_Vec4.hxx | 14 ++ src/Quantity/FILES | 1 + src/Quantity/Quantity_Color.cxx | 16 ++ src/Quantity/Quantity_Color.hxx | 26 ++- src/Quantity/Quantity_ColorRGBA.cxx | 200 +++++++++++++++++++++++ src/Quantity/Quantity_ColorRGBA.hxx | 30 ++++ src/ViewerTest/ViewerTest.cxx | 236 +++++++++++++++++++++------ src/ViewerTest/ViewerTest.hxx | 24 +-- 13 files changed, 583 insertions(+), 66 deletions(-) create mode 100644 src/Quantity/Quantity_ColorRGBA.cxx diff --git a/src/Draw/Draw.hxx b/src/Draw/Draw.hxx index 929cd2958d..e718316461 100644 --- a/src/Draw/Draw.hxx +++ b/src/Draw/Draw.hxx @@ -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); diff --git a/src/Draw/Draw_VariableCommands.cxx b/src/Draw/Draw_VariableCommands.cxx index a4d34bec48..b571def3b4 100644 --- a/src/Draw/Draw_VariableCommands.cxx +++ b/src/Draw/Draw_VariableCommands.cxx @@ -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 (aParsedRealValue); + if (static_cast (aParsedIntegerValue) != aParsedRealValue) + { + return false; + } + theParsedIntegerValue = aParsedIntegerValue; + return true; +} + //======================================================================= //function : Set //purpose : set a TCL var diff --git a/src/NCollection/NCollection_Mat4.hxx b/src/NCollection/NCollection_Mat4.hxx index df74c37ff4..c0ea4fefdd 100755 --- a/src/NCollection/NCollection_Mat4.hxx +++ b/src/NCollection/NCollection_Mat4.hxx @@ -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 + explicit NCollection_Mat4 (const NCollection_Mat4& 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. diff --git a/src/NCollection/NCollection_Vec2.hxx b/src/NCollection/NCollection_Vec2.hxx index c1ebb0509a..f54cae29de 100644 --- a/src/NCollection/NCollection_Vec2.hxx +++ b/src/NCollection/NCollection_Vec2.hxx @@ -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 + explicit NCollection_Vec2 (const NCollection_Vec2& theOtherVec2) + { + v[0] = static_cast (theOtherVec2[0]); + v[1] = static_cast (theOtherVec2[1]); + } + //! Assign new values to the vector. void SetValues (const Element_t theX, const Element_t theY) diff --git a/src/NCollection/NCollection_Vec3.hxx b/src/NCollection/NCollection_Vec3.hxx index 7a4e45b9f8..fc2b48155b 100644 --- a/src/NCollection/NCollection_Vec3.hxx +++ b/src/NCollection/NCollection_Vec3.hxx @@ -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 + explicit NCollection_Vec3 (const NCollection_Vec3& theOtherVec3) + { + v[0] = static_cast (theOtherVec3[0]); + v[1] = static_cast (theOtherVec3[1]); + v[2] = static_cast (theOtherVec3[2]); + } + //! Assign new values to the vector. void SetValues (const Element_t theX, const Element_t theY, diff --git a/src/NCollection/NCollection_Vec4.hxx b/src/NCollection/NCollection_Vec4.hxx index f049585df3..b3c84aea9a 100644 --- a/src/NCollection/NCollection_Vec4.hxx +++ b/src/NCollection/NCollection_Vec4.hxx @@ -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 + explicit NCollection_Vec4 (const NCollection_Vec4& theOtherVec4) + { + v[0] = static_cast (theOtherVec4[0]); + v[1] = static_cast (theOtherVec4[1]); + v[2] = static_cast (theOtherVec4[2]); + v[3] = static_cast (theOtherVec4[3]); + } + //! Assign new values to the vector. void SetValues (const Element_t theX, const Element_t theY, diff --git a/src/Quantity/FILES b/src/Quantity/FILES index 121a03b3ac..fa0ce019e5 100755 --- a/src/Quantity/FILES +++ b/src/Quantity/FILES @@ -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 diff --git a/src/Quantity/Quantity_Color.cxx b/src/Quantity/Quantity_Color.cxx index 3c056ff8eb..1662a5799e 100644 --- a/src/Quantity/Quantity_Color.cxx +++ b/src/Quantity/Quantity_Color.cxx @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -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 diff --git a/src/Quantity/Quantity_Color.hxx b/src/Quantity/Quantity_Color.hxx index a31c38da5d..07ce584ec6 100644 --- a/src/Quantity/Quantity_Color.hxx +++ b/src/Quantity/Quantity_Color.hxx @@ -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 index 0000000000..b7ade567a5 --- /dev/null +++ b/src/Quantity/Quantity_ColorRGBA.cxx @@ -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 + +#include + +#include + +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 + 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 (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 (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 (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); +} diff --git a/src/Quantity/Quantity_ColorRGBA.hxx b/src/Quantity/Quantity_ColorRGBA.hxx index 8f91d9fea3..c67cd52489 100644 --- a/src/Quantity/Quantity_ColorRGBA.hxx +++ b/src/Quantity/Quantity_ColorRGBA.hxx @@ -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)); } diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 550011206f..bee28db33e 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -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 (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 + static bool parseNumericalColor (Standard_Integer& theNumberOfColorComponents, + const char* const* const theColorComponentStrings, + NCollection_Vec4& 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 (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)) { - theColor = Quantity_ColorRGBA (aColor); - if (theArgNb >= 2 - && theToParseAlpha) + return 1; + } + if (theArgNb >= 1 && Quantity_ColorRGBA::ColorFromName (theArgVec[0], theColor)) + { + 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; } - theColor = Quantity_ColorRGBA (anRgba); - return aNbComps; + if (parseRealColor (aNumberOfColorComponentsParsed, theArgVec, theColor)) + { + return aNumberOfColorComponentsParsed; + } + return 0; } - return 0; } diff --git a/src/ViewerTest/ViewerTest.hxx b/src/ViewerTest/ViewerTest.hxx index a4d11658b6..b9665cfc7d 100644 --- a/src/ViewerTest/ViewerTest.hxx +++ b/src/ViewerTest/ViewerTest.hxx @@ -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)