Eclipse SUMO - Simulation of Urban MObility
RGBColor.cpp
Go to the documentation of this file.
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 /****************************************************************************/
21 // A RGB-color definition
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <cmath>
26 #include <cassert>
27 #include <string>
28 #include <sstream>
31 #include <utils/common/ToString.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 
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 RGBColor::RGBColor(bool valid)
66  : myRed(0), myGreen(0), myBlue(0), myAlpha(0), myValid(valid) {}
67 
68 
69 RGBColor::RGBColor(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
70  : myRed(red), myGreen(green), myBlue(blue), myAlpha(alpha), myValid(true) {}
71 
72 
73 unsigned char
74 RGBColor::red() const {
75  return myRed;
76 }
77 
78 
79 unsigned char
80 RGBColor::green() const {
81  return myGreen;
82 }
83 
84 
85 unsigned char
86 RGBColor::blue() const {
87  return myBlue;
88 }
89 
90 
91 unsigned char
92 RGBColor::alpha() const {
93  return myAlpha;
94 }
95 
96 
97 void
98 RGBColor::set(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
99  myRed = r;
100  myGreen = g;
101  myBlue = b;
102  myAlpha = a;
103  myValid = true;
104 }
105 
106 
107 void
108 RGBColor::setAlpha(unsigned char alpha) {
109  myAlpha = alpha;
110 }
111 
112 
113 void
114 RGBColor::setValid(const bool value) {
115  myValid = value;
116 }
117 
118 
119 bool
121  return myValid;
122 }
123 
124 
125 std::ostream&
126 operator<<(std::ostream& os, const RGBColor& col) {
127  if (col == RGBColor::RED) {
128  return os << "red";
129  }
130  if (col == RGBColor::GREEN) {
131  return os << "green";
132  }
133  if (col == RGBColor::BLUE) {
134  return os << "blue";
135  }
136  if (col == RGBColor::YELLOW) {
137  return os << "yellow";
138  }
139  if (col == RGBColor::CYAN) {
140  return os << "cyan";
141  }
142  if (col == RGBColor::MAGENTA) {
143  return os << "magenta";
144  }
145  if (col == RGBColor::ORANGE) {
146  return os << "orange";
147  }
148  if (col == RGBColor::WHITE) {
149  return os << "white";
150  }
151  if (col == RGBColor::BLACK) {
152  return os << "black";
153  }
154  if (col == RGBColor::GREY) {
155  return os << "grey";
156  }
157  if (col == RGBColor::INVISIBLE) {
158  return os << "invisible";
159  }
160  os << static_cast<int>(col.myRed) << ","
161  << static_cast<int>(col.myGreen) << ","
162  << static_cast<int>(col.myBlue);
163  if (col.myAlpha < 255) {
164  os << "," << static_cast<int>(col.myAlpha);
165  }
166  return os;
167 }
168 
169 
170 bool
172  return (myRed == c.myRed) && (myGreen == c.myGreen) && (myBlue == c.myBlue) && (myAlpha == c.myAlpha) && (myValid == c.myValid);
173 }
174 
175 
176 bool
178  return (myRed != c.myRed) || (myGreen != c.myGreen) || (myBlue != c.myBlue) || (myAlpha != c.myAlpha) || (myValid != c.myValid);
179 }
180 
181 
182 RGBColor
184  // obtain inverse colors
185  const unsigned char r = (unsigned char)(255 - (int)myRed);
186  const unsigned char g = (unsigned char)(255 - (int)myGreen);
187  const unsigned char b = (unsigned char)(255 - (int)myBlue);
188  // return inverted RBColor
189  return RGBColor(r, g, b, myAlpha);
190 }
191 
192 
193 SumoRNG*
195  return &myRNG;
196 }
197 
198 
199 RGBColor
200 RGBColor::changedBrightness(int change, int toChange) const {
201  const unsigned char red = (unsigned char)(MIN2(MAX2(myRed + change, 0), 255));
202  const unsigned char blue = (unsigned char)(MIN2(MAX2(myBlue + change, 0), 255));
203  const unsigned char green = (unsigned char)(MIN2(MAX2(myGreen + change, 0), 255));
204  int changed = ((int)red - (int)myRed) + ((int)blue - (int)myBlue) + ((int)green - (int)myGreen);
205  const RGBColor result(red, green, blue, myAlpha);
206  if (changed == toChange * change) {
207  return result;
208  } else if (changed == 0) {
209  return result;
210  } else {
211  const int maxedColors = (red != myRed + change ? 1 : 0) + (blue != myBlue + change ? 1 : 0) + (green != myGreen + change ? 1 : 0);
212  if (maxedColors == 3) {
213  return result;
214  } else {
215  const int toChangeNext = 3 - maxedColors;
216  return result.changedBrightness((int)((toChange * change - changed) / toChangeNext), toChangeNext);
217  }
218  }
219 }
220 
221 
222 RGBColor
223 RGBColor::changedAlpha(int change) const {
224  int alpha = MIN2(MAX2((int)myAlpha + change, 0), 255);
225  return RGBColor(myRed, myGreen, myBlue, (unsigned char)alpha);
226 }
227 
228 
229 RGBColor
230 RGBColor::multiply(double factor) const {
231  const unsigned char red = (unsigned char)floor(MIN2(MAX2(myRed * factor, 0.0), 255.0) + 0.5);
232  const unsigned char blue = (unsigned char)floor(MIN2(MAX2(myBlue * factor, 0.0), 255.0) + 0.5);
233  const unsigned char green = (unsigned char)floor(MIN2(MAX2(myGreen * factor, 0.0), 255.0) + 0.5);
234  return RGBColor(red, green, blue, myAlpha);
235 }
236 
237 
238 RGBColor
239 RGBColor::parseColor(std::string coldef) {
240  coldef = StringUtils::to_lower_case(coldef);
241  if (coldef == "red") {
242  return RED;
243  }
244  if (coldef == "green") {
245  return GREEN;
246  }
247  if (coldef == "blue") {
248  return BLUE;
249  }
250  if (coldef == "yellow") {
251  return YELLOW;
252  }
253  if (coldef == "cyan") {
254  return CYAN;
255  }
256  if (coldef == "magenta") {
257  return MAGENTA;
258  }
259  if (coldef == "orange") {
260  return ORANGE;
261  }
262  if (coldef == "white") {
263  return WHITE;
264  }
265  if (coldef == "black") {
266  return BLACK;
267  }
268  if (coldef == "grey" || coldef == "gray") {
269  return GREY;
270  }
271  if (coldef == "invisible") {
272  return INVISIBLE;
273  }
274  if (coldef == "random") {
275  return fromHSV(RandHelper::rand(360, &myRNG),
276  // prefer more saturated colors
277  pow(RandHelper::rand(&myRNG), 0.3),
278  // prefer brighter colors
279  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  if (coldef[0] == '#') {
286  const int coldesc = StringUtils::hexToInt(coldef);
287  if (coldef.length() == 7) {
288  r = static_cast<unsigned char>((coldesc & 0xFF0000) >> 16);
289  g = static_cast<unsigned char>((coldesc & 0x00FF00) >> 8);
290  b = coldesc & 0xFF;
291  } else if (coldef.length() == 9) {
292  r = static_cast<unsigned char>((coldesc & 0xFF000000) >> 24);
293  g = static_cast<unsigned char>((coldesc & 0x00FF0000) >> 16);
294  b = static_cast<unsigned char>((coldesc & 0x0000FF00) >> 8);
295  a = coldesc & 0xFF;
296  } else {
297  throw EmptyData();
298  }
299  } else {
300  std::vector<std::string> st = StringTokenizer(coldef, ",").getVector();
301  if (st.size() == 3 || st.size() == 4) {
302  try {
303  r = static_cast<unsigned char>(StringUtils::toInt(st[0]));
304  g = static_cast<unsigned char>(StringUtils::toInt(st[1]));
305  b = static_cast<unsigned char>(StringUtils::toInt(st[2]));
306  if (st.size() == 4) {
307  a = static_cast<unsigned char>(StringUtils::toInt(st[3]));
308  }
309  if (r <= 1 && g <= 1 && b <= 1 && (st.size() == 3 || a <= 1)) {
310  throw NumberFormatException("(color component) " + coldef);
311  }
312  } catch (NumberFormatException&) {
313  r = static_cast<unsigned char>(StringUtils::toDouble(st[0]) * 255. + 0.5);
314  g = static_cast<unsigned char>(StringUtils::toDouble(st[1]) * 255. + 0.5);
315  b = static_cast<unsigned char>(StringUtils::toDouble(st[2]) * 255. + 0.5);
316  if (st.size() == 4) {
317  a = static_cast<unsigned char>(StringUtils::toDouble(st[3]) * 255. + 0.5);
318  }
319  }
320  } else {
321  throw FormatException("Invalid color definition '" + coldef + "'");
322  }
323  }
324  return RGBColor(r, g, b, a);
325 }
326 
327 
328 RGBColor
330  const std::string& coldef, const std::string& objecttype,
331  const char* objectid, bool report, bool& ok) {
332  UNUSED_PARAMETER(report);
333  try {
334  return parseColor(coldef);
335  } catch (NumberFormatException&) {
336  } catch (EmptyData&) {
337  }
338  ok = false;
339  std::ostringstream oss;
340  oss << "Attribute 'color' in definition of ";
341  if (objectid == nullptr) {
342  oss << "a ";
343  }
344  oss << objecttype;
345  if (objectid != nullptr) {
346  oss << " '" << objectid << "'";
347  }
348  oss << " is not a valid color.";
349  WRITE_ERROR(oss.str());
350  return RGBColor();
351 }
352 
353 
354 RGBColor
355 RGBColor::interpolate(const RGBColor& minColor, const RGBColor& maxColor, double weight) {
356  if (weight < 0) {
357  weight = 0;
358  }
359  if (weight > 1) {
360  weight = 1;
361  }
362  const unsigned char r = (unsigned char)((int)minColor.myRed + (((int)maxColor.myRed - (int)minColor.myRed) * weight));
363  const unsigned char g = (unsigned char)((int)minColor.myGreen + (((int)maxColor.myGreen - (int)minColor.myGreen) * weight));
364  const unsigned char b = (unsigned char)((int)minColor.myBlue + (((int)maxColor.myBlue - (int)minColor.myBlue) * weight));
365  const unsigned char a = (unsigned char)((int)minColor.myAlpha + (((int)maxColor.myAlpha - (int)minColor.myAlpha) * weight));
366  return RGBColor(r, g, b, a);
367 }
368 
369 
370 RGBColor
371 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  h /= 60.;
376  const int i = int(floor(h));
377  double f = h - i;
378  if (i % 2 == 0) {
379  f = 1. - f;
380  }
381  const unsigned char m = static_cast<unsigned char>(v * (1 - s) * 255. + 0.5);
382  const unsigned char n = static_cast<unsigned char>(v * (1 - s * f) * 255. + 0.5);
383  const unsigned char vv = static_cast<unsigned char>(v * 255. + 0.5);
384  switch (i) {
385  case 0:
386  case 6:
387  return RGBColor(vv, n, m, 255);
388  case 1:
389  return RGBColor(n, vv, m, 255);
390  case 2:
391  return RGBColor(m, vv, n, 255);
392  case 3:
393  return RGBColor(m, n, vv, 255);
394  case 4:
395  return RGBColor(n, m, vv, 255);
396  case 5:
397  return RGBColor(vv, m, n, 255);
398  }
399  return RGBColor(255, 255, 255, 255);
400 }
401 
402 RGBColor
403 RGBColor::randomHue(double s, double v) {
404  return fromHSV(RandHelper::rand(360, &myRNG), s, v);
405 }
406 
407 
408 /****************************************************************************/
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
std::ostream & operator<<(std::ostream &os, const RGBColor &col)
Definition: RGBColor.cpp:126
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
bool myValid
flag to check if color is valid
Definition: RGBColor.h:209
static RGBColor interpolate(const RGBColor &minColor, const RGBColor &maxColor, double weight)
Interpolates between two colors.
Definition: RGBColor.cpp:355
unsigned char myRed
The color amounts.
Definition: RGBColor.h:206
void setValid(const bool value)
set valid
Definition: RGBColor.cpp:114
void setAlpha(unsigned char alpha)
Sets a new alpha value.
Definition: RGBColor.cpp:108
static const RGBColor WHITE
Definition: RGBColor.h:192
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.cpp:74
static const std::string DEFAULT_COLOR_STRING
The string description of the default color.
Definition: RGBColor.h:202
static const RGBColor BLUE
Definition: RGBColor.h:187
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.cpp:92
static const RGBColor GREY
Definition: RGBColor.h:194
static const RGBColor YELLOW
Definition: RGBColor.h:188
static SumoRNG myRNG
A random number generator to generate random colors independent of other randomness.
Definition: RGBColor.h:212
static const RGBColor INVISIBLE
Definition: RGBColor.h:195
RGBColor(bool valid=true)
Constructor.
Definition: RGBColor.cpp:65
static SumoRNG * getColorRNG()
get color RNG
Definition: RGBColor.cpp:194
RGBColor multiply(double factor) const
Returns a new color with altered brightness.
Definition: RGBColor.cpp:230
static RGBColor parseColor(std::string coldef)
Parses a color information.
Definition: RGBColor.cpp:239
static RGBColor parseColorReporting(const std::string &coldef, const std::string &objecttype, const char *objectid, bool report, bool &ok)
Parses a color information.
Definition: RGBColor.cpp:329
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.cpp:80
static const RGBColor ORANGE
Definition: RGBColor.h:191
static const RGBColor CYAN
Definition: RGBColor.h:189
RGBColor invertedColor() const
obtain inverted of current RGBColor
Definition: RGBColor.cpp:183
bool isValid() const
check if RGBColor is valid
Definition: RGBColor.cpp:120
static const RGBColor GREEN
Definition: RGBColor.h:186
static RGBColor fromHSV(double h, double s, double v)
Converts the given hsv-triplet to rgb, inspired by http://alvyray.com/Papers/CG/hsv2rgb....
Definition: RGBColor.cpp:371
unsigned char myBlue
Definition: RGBColor.h:206
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.cpp:86
static const RGBColor BLACK
Definition: RGBColor.h:193
RGBColor changedBrightness(int change, int toChange=3) const
Returns a new color with altered brightness.
Definition: RGBColor.cpp:200
bool operator!=(const RGBColor &c) const
Definition: RGBColor.cpp:177
void set(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
assigns new values
Definition: RGBColor.cpp:98
RGBColor changedAlpha(int change) const
Returns a new color with altered opacity.
Definition: RGBColor.cpp:223
unsigned char myGreen
Definition: RGBColor.h:206
static const RGBColor MAGENTA
Definition: RGBColor.h:190
bool operator==(const RGBColor &c) const
Definition: RGBColor.cpp:171
unsigned char myAlpha
Definition: RGBColor.h:206
static const RGBColor DEFAULT_COLOR
The default color (for vehicle types and vehicles)
Definition: RGBColor.h:199
static const RGBColor RED
named colors
Definition: RGBColor.h:185
static RGBColor randomHue(double s=1, double v=1)
Return color with random hue.
Definition: RGBColor.cpp:403
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
std::vector< std::string > getVector()
return vector of strings
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
Definition: StringUtils.cpp:77
static int hexToInt(const std::string &sData)
converts a string with a hex value into the integer value described by it by calling the char-type co...
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...