LCOV - code coverage report
Current view: top level - src/utils/common - RGBColor.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 132 196 67.3 %
Date: 2024-05-02 15:31:40 Functions: 17 23 73.9 %

          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    35677025 : RGBColor::RGBColor(bool valid)
      66    35677025 :     : myRed(0), myGreen(0), myBlue(0), myAlpha(0), myValid(valid) {}
      67             : 
      68             : 
      69    26346563 : RGBColor::RGBColor(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
      70    26346563 :     : myRed(red), myGreen(green), myBlue(blue), myAlpha(alpha), myValid(true) {}
      71             : 
      72             : 
      73             : unsigned char
      74    39660643 : RGBColor::red() const {
      75    39660643 :     return myRed;
      76             : }
      77             : 
      78             : 
      79             : unsigned char
      80    39660643 : RGBColor::green() const {
      81    39660643 :     return myGreen;
      82             : }
      83             : 
      84             : 
      85             : unsigned char
      86    39660643 : RGBColor::blue() const {
      87    39660643 :     return myBlue;
      88             : }
      89             : 
      90             : 
      91             : unsigned char
      92    71734706 : RGBColor::alpha() const {
      93    71734706 :     return myAlpha;
      94             : }
      95             : 
      96             : 
      97             : void
      98         229 : RGBColor::set(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
      99         229 :     myRed = r;
     100         229 :     myGreen = g;
     101         229 :     myBlue = b;
     102         229 :     myAlpha = a;
     103         229 :     myValid = true;
     104         229 : }
     105             : 
     106             : 
     107             : void
     108        1000 : RGBColor::setAlpha(unsigned char alpha) {
     109        1000 :     myAlpha = alpha;
     110        1000 : }
     111             : 
     112             : 
     113             : void
     114        6655 : RGBColor::setValid(const bool value) {
     115        6655 :     myValid = value;
     116        6655 : }
     117             : 
     118             : 
     119             : bool
     120        1370 : RGBColor::isValid() const {
     121        1370 :     return myValid;
     122             : }
     123             : 
     124             : 
     125             : std::ostream&
     126       84684 : operator<<(std::ostream& os, const RGBColor& col) {
     127       84684 :     if (col == RGBColor::RED) {
     128        6549 :         return os << "red";
     129             :     }
     130       78135 :     if (col == RGBColor::GREEN) {
     131        5497 :         return os << "green";
     132             :     }
     133       72638 :     if (col == RGBColor::BLUE) {
     134         917 :         return os << "blue";
     135             :     }
     136       71721 :     if (col == RGBColor::YELLOW) {
     137       51695 :         return os << "yellow";
     138             :     }
     139       20026 :     if (col == RGBColor::CYAN) {
     140          97 :         return os << "cyan";
     141             :     }
     142       19929 :     if (col == RGBColor::MAGENTA) {
     143         183 :         return os << "magenta";
     144             :     }
     145       19746 :     if (col == RGBColor::ORANGE) {
     146         128 :         return os << "orange";
     147             :     }
     148       19618 :     if (col == RGBColor::WHITE) {
     149        1638 :         return os << "white";
     150             :     }
     151       17980 :     if (col == RGBColor::BLACK) {
     152        1841 :         return os << "black";
     153             :     }
     154       16139 :     if (col == RGBColor::GREY) {
     155          31 :         return os << "grey";
     156             :     }
     157       16108 :     if (col == RGBColor::INVISIBLE) {
     158          62 :         return os << "invisible";
     159             :     }
     160       16046 :     os << static_cast<int>(col.myRed) << ","
     161       16046 :        << static_cast<int>(col.myGreen) << ","
     162       16046 :        << static_cast<int>(col.myBlue);
     163       16046 :     if (col.myAlpha < 255) {
     164         805 :         os << "," << static_cast<int>(col.myAlpha);
     165             :     }
     166             :     return os;
     167             : }
     168             : 
     169             : 
     170             : bool
     171      436734 : RGBColor::operator==(const RGBColor& c) const {
     172      436734 :     return (myRed == c.myRed) && (myGreen == c.myGreen) && (myBlue == c.myBlue) && (myAlpha == c.myAlpha) && (myValid == c.myValid);
     173             : }
     174             : 
     175             : 
     176             : bool
     177     2160823 : RGBColor::operator!=(const RGBColor& c) const {
     178     2160823 :     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     2807661 : RGBColor::changedBrightness(int change, int toChange) const {
     201     2807661 :     const unsigned char red = (unsigned char)(MIN2(MAX2(myRed + change, 0), 255));
     202     2807661 :     const unsigned char blue = (unsigned char)(MIN2(MAX2(myBlue + change, 0), 255));
     203     2807661 :     const unsigned char green = (unsigned char)(MIN2(MAX2(myGreen + change, 0), 255));
     204     2807661 :     int changed = ((int)red - (int)myRed) + ((int)blue - (int)myBlue) + ((int)green - (int)myGreen);
     205     2807661 :     const RGBColor result(red, green, blue, myAlpha);
     206     2807661 :     if (changed == toChange * change) {
     207     1433708 :         return result;
     208     1373953 :     } else if (changed == 0) {
     209           0 :         return result;
     210             :     } else {
     211     2765721 :         const int maxedColors = (red != myRed + change ? 1 : 0) + (blue != myBlue + change ? 1 : 0) + (green != myGreen + change ? 1 : 0);
     212     1373953 :         if (maxedColors == 3) {
     213           0 :             return result;
     214             :         } else {
     215     1373953 :             const int toChangeNext = 3 - maxedColors;
     216     1373953 :             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       79721 : RGBColor::parseColor(std::string coldef) {
     240      159442 :     coldef = StringUtils::to_lower_case(coldef);
     241       79721 :     if (coldef == "red") {
     242        8156 :         return RED;
     243             :     }
     244       71565 :     if (coldef == "green") {
     245        5334 :         return GREEN;
     246             :     }
     247       66231 :     if (coldef == "blue") {
     248       12638 :         return BLUE;
     249             :     }
     250       53593 :     if (coldef == "yellow") {
     251       12258 :         return YELLOW;
     252             :     }
     253       41335 :     if (coldef == "cyan") {
     254        1488 :         return CYAN;
     255             :     }
     256       39847 :     if (coldef == "magenta") {
     257         799 :         return MAGENTA;
     258             :     }
     259       39048 :     if (coldef == "orange") {
     260         700 :         return ORANGE;
     261             :     }
     262       38348 :     if (coldef == "white") {
     263         866 :         return WHITE;
     264             :     }
     265       37482 :     if (coldef == "black") {
     266         180 :         return BLACK;
     267             :     }
     268       73870 :     if (coldef == "grey" || coldef == "gray") {
     269         734 :         return GREY;
     270             :     }
     271       36568 :     if (coldef == "invisible") {
     272          26 :         return INVISIBLE;
     273             :     }
     274       36542 :     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       36542 :     if (coldef[0] == '#') {
     286        1092 :         const int coldesc = StringUtils::hexToInt(coldef);
     287        1092 :         if (coldef.length() == 7) {
     288        1092 :             r = static_cast<unsigned char>((coldesc & 0xFF0000) >> 16);
     289        1092 :             g = static_cast<unsigned char>((coldesc & 0x00FF00) >> 8);
     290        1092 :             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      106350 :         std::vector<std::string> st = StringTokenizer(coldef, ",").getVector();
     301       35450 :         if (st.size() == 3 || st.size() == 4) {
     302             :             try {
     303       35433 :                 r = static_cast<unsigned char>(StringUtils::toInt(st[0]));
     304       25913 :                 g = static_cast<unsigned char>(StringUtils::toInt(st[1]));
     305       25813 :                 b = static_cast<unsigned char>(StringUtils::toInt(st[2]));
     306       25785 :                 if (st.size() == 4) {
     307         933 :                     a = static_cast<unsigned char>(StringUtils::toInt(st[3]));
     308             :                 }
     309       25785 :                 if (r <= 1 && g <= 1 && b <= 1 && (st.size() == 3 || a <= 1)) {
     310        7310 :                     throw NumberFormatException("(color component) " + coldef);
     311             :                 }
     312       13303 :             } catch (NumberFormatException&) {
     313       13303 :                 r = static_cast<unsigned char>(StringUtils::toDouble(st[0]) * 255. + 0.5);
     314       13301 :                 g = static_cast<unsigned char>(StringUtils::toDouble(st[1]) * 255. + 0.5);
     315       13301 :                 b = static_cast<unsigned char>(StringUtils::toDouble(st[2]) * 255. + 0.5);
     316       13301 :                 if (st.size() == 4) {
     317         118 :                     a = static_cast<unsigned char>(StringUtils::toDouble(st[3]) * 255. + 0.5);
     318             :                 }
     319       13303 :             }
     320             :         } else {
     321          34 :             throw FormatException("Invalid color definition '" + coldef + "'");
     322             :         }
     323       35450 :     }
     324       36523 :     return RGBColor(r, g, b, a);
     325             : }
     326             : 
     327             : 
     328             : RGBColor
     329        2875 : 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        5750 :         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      112230 : RGBColor::interpolate(const RGBColor& minColor, const RGBColor& maxColor, double weight) {
     356      112230 :     if (weight < 0) {
     357             :         weight = 0;
     358             :     }
     359      112230 :     if (weight > 1) {
     360             :         weight = 1;
     361             :     }
     362      112230 :     const unsigned char r = (unsigned char)((int)minColor.myRed   + (((int)maxColor.myRed   - (int)minColor.myRed)   * weight));
     363      112230 :     const unsigned char g = (unsigned char)((int)minColor.myGreen + (((int)maxColor.myGreen - (int)minColor.myGreen) * weight));
     364      112230 :     const unsigned char b = (unsigned char)((int)minColor.myBlue  + (((int)maxColor.myBlue  - (int)minColor.myBlue)  * weight));
     365      112230 :     const unsigned char a = (unsigned char)((int)minColor.myAlpha + (((int)maxColor.myAlpha - (int)minColor.myAlpha) * weight));
     366      112230 :     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 1.14