LCOV - code coverage report
Current view: top level - src/utils/common - RGBColor.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 67.9 % 196 133
Test Date: 2024-11-22 15:46:21 Functions: 73.9 % 23 17

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    RGBColor.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker
      19              : /// @date    Sept 2002
      20              : ///
      21              : // A RGB-color definition
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <cmath>
      26              : #include <cassert>
      27              : #include <string>
      28              : #include <sstream>
      29              : #include <utils/common/RandHelper.h>
      30              : #include <utils/common/StringTokenizer.h>
      31              : #include <utils/common/ToString.h>
      32              : #include <utils/common/StringUtils.h>
      33              : #include <utils/common/MsgHandler.h>
      34              : #include <utils/common/StdDefs.h>
      35              : 
      36              : #include "RGBColor.h"
      37              : 
      38              : 
      39              : // ===========================================================================
      40              : // static member definitions
      41              : // ===========================================================================
      42              : 
      43              : const RGBColor RGBColor::RED = RGBColor(255, 0, 0, 255);
      44              : const RGBColor RGBColor::GREEN = RGBColor(0, 255, 0, 255);
      45              : const RGBColor RGBColor::BLUE = RGBColor(0, 0, 255, 255);
      46              : const RGBColor RGBColor::YELLOW = RGBColor(255, 255, 0, 255);
      47              : const RGBColor RGBColor::CYAN = RGBColor(0, 255, 255, 255);
      48              : const RGBColor RGBColor::MAGENTA = RGBColor(255, 0, 255, 255);
      49              : const RGBColor RGBColor::ORANGE = RGBColor(255, 128, 0, 255);
      50              : const RGBColor RGBColor::WHITE = RGBColor(255, 255, 255, 255);
      51              : const RGBColor RGBColor::BLACK = RGBColor(0, 0, 0, 255);
      52              : const RGBColor RGBColor::GREY = RGBColor(128, 128, 128, 255);
      53              : const RGBColor RGBColor::INVISIBLE = RGBColor(0, 0, 0, 0);
      54              : 
      55              : const RGBColor RGBColor::DEFAULT_COLOR = RGBColor::YELLOW;
      56              : const std::string RGBColor::DEFAULT_COLOR_STRING = toString(RGBColor::DEFAULT_COLOR);
      57              : 
      58              : // random colors do not affect the simulation. No initialization is necessary
      59              : SumoRNG RGBColor::myRNG("color");
      60              : 
      61              : // ===========================================================================
      62              : // method definitions
      63              : // ===========================================================================
      64              : 
      65     39242590 : RGBColor::RGBColor(bool valid)
      66     39242590 :     : myRed(0), myGreen(0), myBlue(0), myAlpha(0), myValid(valid) {}
      67              : 
      68              : 
      69     30108390 : RGBColor::RGBColor(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
      70     30108390 :     : myRed(red), myGreen(green), myBlue(blue), myAlpha(alpha), myValid(true) {}
      71              : 
      72              : 
      73              : unsigned char
      74     44649444 : RGBColor::red() const {
      75     44649444 :     return myRed;
      76              : }
      77              : 
      78              : 
      79              : unsigned char
      80     44649444 : RGBColor::green() const {
      81     44649444 :     return myGreen;
      82              : }
      83              : 
      84              : 
      85              : unsigned char
      86     44649444 : RGBColor::blue() const {
      87     44649444 :     return myBlue;
      88              : }
      89              : 
      90              : 
      91              : unsigned char
      92     80240649 : RGBColor::alpha() const {
      93     80240649 :     return myAlpha;
      94              : }
      95              : 
      96              : 
      97              : void
      98          185 : RGBColor::set(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
      99          185 :     myRed = r;
     100          185 :     myGreen = g;
     101          185 :     myBlue = b;
     102          185 :     myAlpha = a;
     103          185 :     myValid = true;
     104          185 : }
     105              : 
     106              : 
     107              : void
     108          801 : RGBColor::setAlpha(unsigned char alpha) {
     109          801 :     myAlpha = alpha;
     110          801 : }
     111              : 
     112              : 
     113              : void
     114         4794 : RGBColor::setValid(const bool value) {
     115         4794 :     myValid = value;
     116         4794 : }
     117              : 
     118              : 
     119              : bool
     120         1124 : RGBColor::isValid() const {
     121         1124 :     return myValid;
     122              : }
     123              : 
     124              : 
     125              : std::ostream&
     126       121556 : operator<<(std::ostream& os, const RGBColor& col) {
     127       121556 :     if (col == RGBColor::RED) {
     128        10393 :         return os << "red";
     129              :     }
     130       111163 :     if (col == RGBColor::GREEN) {
     131        10080 :         return os << "green";
     132              :     }
     133       101083 :     if (col == RGBColor::BLUE) {
     134          632 :         return os << "blue";
     135              :     }
     136       100451 :     if (col == RGBColor::YELLOW) {
     137        61403 :         return os << "yellow";
     138              :     }
     139        39048 :     if (col == RGBColor::CYAN) {
     140          100 :         return os << "cyan";
     141              :     }
     142        38948 :     if (col == RGBColor::MAGENTA) {
     143          184 :         return os << "magenta";
     144              :     }
     145        38764 :     if (col == RGBColor::ORANGE) {
     146           99 :         return os << "orange";
     147              :     }
     148        38665 :     if (col == RGBColor::WHITE) {
     149         1242 :         return os << "white";
     150              :     }
     151        37423 :     if (col == RGBColor::BLACK) {
     152         1841 :         return os << "black";
     153              :     }
     154        35582 :     if (col == RGBColor::GREY) {
     155           32 :         return os << "grey";
     156              :     }
     157        35550 :     if (col == RGBColor::INVISIBLE) {
     158           64 :         return os << "invisible";
     159              :     }
     160        35486 :     os << static_cast<int>(col.myRed) << ","
     161        35486 :        << static_cast<int>(col.myGreen) << ","
     162        35486 :        << static_cast<int>(col.myBlue);
     163        35486 :     if (col.myAlpha < 255) {
     164          832 :         os << "," << static_cast<int>(col.myAlpha);
     165              :     }
     166              :     return os;
     167              : }
     168              : 
     169              : 
     170              : bool
     171       698238 : RGBColor::operator==(const RGBColor& c) const {
     172       698238 :     return (myRed == c.myRed) && (myGreen == c.myGreen) && (myBlue == c.myBlue) && (myAlpha == c.myAlpha) && (myValid == c.myValid);
     173              : }
     174              : 
     175              : 
     176              : bool
     177      2505071 : RGBColor::operator!=(const RGBColor& c) const {
     178      2505071 :     return (myRed != c.myRed) || (myGreen != c.myGreen) || (myBlue != c.myBlue) || (myAlpha != c.myAlpha) || (myValid != c.myValid);
     179              : }
     180              : 
     181              : 
     182              : RGBColor
     183            0 : RGBColor::invertedColor() const {
     184              :     // obtain inverse colors
     185            0 :     const unsigned char r = (unsigned char)(255 - (int)myRed);
     186            0 :     const unsigned char g = (unsigned char)(255 - (int)myGreen);
     187            0 :     const unsigned char b = (unsigned char)(255  - (int)myBlue);
     188              :     // return inverted RBColor
     189            0 :     return RGBColor(r, g, b, myAlpha);
     190              : }
     191              : 
     192              : 
     193              : SumoRNG*
     194            0 : RGBColor::getColorRNG() {
     195            0 :     return &myRNG;
     196              : }
     197              : 
     198              : 
     199              : RGBColor
     200      4406407 : RGBColor::changedBrightness(int change, int toChange) const {
     201      4406407 :     const unsigned char red = (unsigned char)(MIN2(MAX2(myRed + change, 0), 255));
     202      4406407 :     const unsigned char blue = (unsigned char)(MIN2(MAX2(myBlue + change, 0), 255));
     203      4406407 :     const unsigned char green = (unsigned char)(MIN2(MAX2(myGreen + change, 0), 255));
     204      4406407 :     int changed = ((int)red - (int)myRed) + ((int)blue - (int)myBlue) + ((int)green - (int)myGreen);
     205      4406407 :     const RGBColor result(red, green, blue, myAlpha);
     206      4406407 :     if (changed == toChange * change) {
     207      2239290 :         return result;
     208      2167117 :     } else if (changed == 0) {
     209            0 :         return result;
     210              :     } else {
     211      4323971 :         const int maxedColors = (red != myRed + change ? 1 : 0) + (blue != myBlue + change ? 1 : 0) + (green != myGreen + change ? 1 : 0);
     212      2167117 :         if (maxedColors == 3) {
     213           60 :             return result;
     214              :         } else {
     215      2167057 :             const int toChangeNext = 3 - maxedColors;
     216      2167057 :             return result.changedBrightness((int)((toChange * change - changed) / toChangeNext), toChangeNext);
     217              :         }
     218              :     }
     219              : }
     220              : 
     221              : 
     222              : RGBColor
     223            0 : RGBColor::changedAlpha(int change) const {
     224            0 :     int alpha = MIN2(MAX2((int)myAlpha + change, 0), 255);
     225            0 :     return RGBColor(myRed, myGreen, myBlue, (unsigned char)alpha);
     226              : }
     227              : 
     228              : 
     229              : RGBColor
     230            0 : RGBColor::multiply(double factor) const {
     231            0 :     const unsigned char red = (unsigned char)floor(MIN2(MAX2(myRed * factor, 0.0), 255.0) + 0.5);
     232            0 :     const unsigned char blue = (unsigned char)floor(MIN2(MAX2(myBlue * factor, 0.0), 255.0) + 0.5);
     233            0 :     const unsigned char green = (unsigned char)floor(MIN2(MAX2(myGreen * factor, 0.0), 255.0) + 0.5);
     234            0 :     return RGBColor(red, green, blue, myAlpha);
     235              : }
     236              : 
     237              : 
     238              : RGBColor
     239        94748 : RGBColor::parseColor(std::string coldef) {
     240        94748 :     coldef = StringUtils::to_lower_case(coldef);
     241        94748 :     if (coldef == "red") {
     242        10631 :         return RED;
     243              :     }
     244        84117 :     if (coldef == "green") {
     245         7614 :         return GREEN;
     246              :     }
     247        76503 :     if (coldef == "blue") {
     248        13128 :         return BLUE;
     249              :     }
     250        63375 :     if (coldef == "yellow") {
     251        12958 :         return YELLOW;
     252              :     }
     253        50417 :     if (coldef == "cyan") {
     254         1526 :         return CYAN;
     255              :     }
     256        48891 :     if (coldef == "magenta") {
     257          837 :         return MAGENTA;
     258              :     }
     259        48054 :     if (coldef == "orange") {
     260          714 :         return ORANGE;
     261              :     }
     262        47340 :     if (coldef == "white") {
     263          459 :         return WHITE;
     264              :     }
     265        46881 :     if (coldef == "black") {
     266          176 :         return BLACK;
     267              :     }
     268        46705 :     if (coldef == "grey" || coldef == "gray") {
     269          773 :         return GREY;
     270              :     }
     271        45932 :     if (coldef == "invisible") {
     272           32 :         return INVISIBLE;
     273              :     }
     274        45900 :     if (coldef == "random") {
     275            0 :         return fromHSV(RandHelper::rand(360, &myRNG),
     276              :                        // prefer more saturated colors
     277              :                        pow(RandHelper::rand(&myRNG), 0.3),
     278              :                        // prefer brighter colors
     279            0 :                        pow(RandHelper::rand(&myRNG), 0.3));
     280              :     }
     281              :     unsigned char r = 0;
     282              :     unsigned char g = 0;
     283              :     unsigned char b = 0;
     284              :     unsigned char a = 255;
     285        45900 :     if (coldef[0] == '#') {
     286          849 :         const int coldesc = StringUtils::hexToInt(coldef);
     287          849 :         if (coldef.length() == 7) {
     288          849 :             r = static_cast<unsigned char>((coldesc & 0xFF0000) >> 16);
     289          849 :             g = static_cast<unsigned char>((coldesc & 0x00FF00) >> 8);
     290          849 :             b = coldesc & 0xFF;
     291            0 :         } else if (coldef.length() == 9) {
     292            0 :             r = static_cast<unsigned char>((coldesc & 0xFF000000) >> 24);
     293            0 :             g = static_cast<unsigned char>((coldesc & 0x00FF0000) >> 16);
     294            0 :             b = static_cast<unsigned char>((coldesc & 0x0000FF00) >> 8);
     295            0 :             a = coldesc & 0xFF;
     296              :         } else {
     297            0 :             throw EmptyData();
     298              :         }
     299              :     } else {
     300       135153 :         std::vector<std::string> st = StringTokenizer(coldef, ",").getVector();
     301        45051 :         if (st.size() == 3 || st.size() == 4) {
     302              :             try {
     303        45038 :                 r = static_cast<unsigned char>(StringUtils::toInt(st[0]));
     304        19319 :                 g = static_cast<unsigned char>(StringUtils::toInt(st[1]));
     305        19246 :                 b = static_cast<unsigned char>(StringUtils::toInt(st[2]));
     306        19221 :                 if (st.size() == 4) {
     307          960 :                     a = static_cast<unsigned char>(StringUtils::toInt(st[3]));
     308              :                 }
     309        19221 :                 if (r <= 1 && g <= 1 && b <= 1 && (st.size() == 3 || a <= 1)) {
     310         6932 :                     throw NumberFormatException("(color component) " + coldef);
     311              :                 }
     312        29283 :             } catch (NumberFormatException&) {
     313        29283 :                 r = static_cast<unsigned char>(StringUtils::toDouble(st[0]) * 255. + 0.5);
     314        29282 :                 g = static_cast<unsigned char>(StringUtils::toDouble(st[1]) * 255. + 0.5);
     315        29282 :                 b = static_cast<unsigned char>(StringUtils::toDouble(st[2]) * 255. + 0.5);
     316        29282 :                 if (st.size() == 4) {
     317          118 :                     a = static_cast<unsigned char>(StringUtils::toDouble(st[3]) * 255. + 0.5);
     318              :                 }
     319        29283 :             }
     320              :         } else {
     321           26 :             throw FormatException("Invalid color definition '" + coldef + "'");
     322              :         }
     323        45051 :     }
     324        45886 :     return RGBColor(r, g, b, a);
     325              : }
     326              : 
     327              : 
     328              : RGBColor
     329         2972 : RGBColor::parseColorReporting(
     330              :     const std::string& coldef, const std::string& objecttype,
     331              :     const char* objectid, bool report, bool& ok) {
     332              :     UNUSED_PARAMETER(report);
     333              :     try {
     334         5944 :         return parseColor(coldef);
     335            0 :     } catch (NumberFormatException&) {
     336            0 :     } catch (EmptyData&) {
     337            0 :     }
     338            0 :     ok = false;
     339            0 :     std::ostringstream oss;
     340            0 :     oss << "Attribute 'color' in definition of ";
     341            0 :     if (objectid == nullptr) {
     342            0 :         oss << "a ";
     343              :     }
     344              :     oss << objecttype;
     345            0 :     if (objectid != nullptr) {
     346            0 :         oss << " '" << objectid << "'";
     347              :     }
     348            0 :     oss << " is not a valid color.";
     349            0 :     WRITE_ERROR(oss.str());
     350            0 :     return RGBColor();
     351            0 : }
     352              : 
     353              : 
     354              : RGBColor
     355       116399 : RGBColor::interpolate(const RGBColor& minColor, const RGBColor& maxColor, double weight) {
     356       116399 :     if (weight < 0) {
     357              :         weight = 0;
     358              :     }
     359       116398 :     if (weight > 1) {
     360              :         weight = 1;
     361              :     }
     362       116399 :     const unsigned char r = (unsigned char)((int)minColor.myRed   + (((int)maxColor.myRed   - (int)minColor.myRed)   * weight));
     363       116399 :     const unsigned char g = (unsigned char)((int)minColor.myGreen + (((int)maxColor.myGreen - (int)minColor.myGreen) * weight));
     364       116399 :     const unsigned char b = (unsigned char)((int)minColor.myBlue  + (((int)maxColor.myBlue  - (int)minColor.myBlue)  * weight));
     365       116399 :     const unsigned char a = (unsigned char)((int)minColor.myAlpha + (((int)maxColor.myAlpha - (int)minColor.myAlpha) * weight));
     366       116399 :     return RGBColor(r, g, b, a);
     367              : }
     368              : 
     369              : 
     370              : RGBColor
     371            0 : RGBColor::fromHSV(double h, double s, double v) {
     372              :     h = MIN2(MAX2(h, 0.), 360.);
     373              :     s = MIN2(MAX2(s, 0.), 1.);
     374              :     v = MIN2(MAX2(v, 0.), 1.);
     375            0 :     h /= 60.;
     376            0 :     const int i = int(floor(h));
     377            0 :     double f = h - i;
     378            0 :     if (i % 2 == 0) {
     379            0 :         f = 1. - f;
     380              :     }
     381            0 :     const unsigned char m = static_cast<unsigned char>(v * (1 - s) * 255. + 0.5);
     382            0 :     const unsigned char n = static_cast<unsigned char>(v * (1 - s * f) * 255. + 0.5);
     383            0 :     const unsigned char vv = static_cast<unsigned char>(v * 255. + 0.5);
     384            0 :     switch (i) {
     385            0 :         case 0:
     386              :         case 6:
     387            0 :             return RGBColor(vv, n, m, 255);
     388            0 :         case 1:
     389            0 :             return RGBColor(n, vv, m, 255);
     390            0 :         case 2:
     391            0 :             return RGBColor(m, vv, n, 255);
     392            0 :         case 3:
     393            0 :             return RGBColor(m, n, vv, 255);
     394            0 :         case 4:
     395            0 :             return RGBColor(n, m, vv, 255);
     396            0 :         case 5:
     397            0 :             return RGBColor(vv, m, n, 255);
     398              :     }
     399            0 :     return RGBColor(255, 255, 255, 255);
     400              : }
     401              : 
     402              : RGBColor
     403            0 : RGBColor::randomHue(double s, double v) {
     404            0 :     return fromHSV(RandHelper::rand(360, &myRNG), s, v);
     405              : }
     406              : 
     407              : 
     408              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1