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.org/sumo
3// Copyright (C) 2001-2022 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>
35
36#include "RGBColor.h"
37
38
39// ===========================================================================
40// static member definitions
41// ===========================================================================
42
43const RGBColor RGBColor::RED = RGBColor(255, 0, 0, 255);
44const RGBColor RGBColor::GREEN = RGBColor(0, 255, 0, 255);
45const RGBColor RGBColor::BLUE = RGBColor(0, 0, 255, 255);
46const RGBColor RGBColor::YELLOW = RGBColor(255, 255, 0, 255);
47const RGBColor RGBColor::CYAN = RGBColor(0, 255, 255, 255);
48const RGBColor RGBColor::MAGENTA = RGBColor(255, 0, 255, 255);
49const RGBColor RGBColor::ORANGE = RGBColor(255, 128, 0, 255);
50const RGBColor RGBColor::WHITE = RGBColor(255, 255, 255, 255);
51const RGBColor RGBColor::BLACK = RGBColor(0, 0, 0, 255);
52const RGBColor RGBColor::GREY = RGBColor(128, 128, 128, 255);
53const RGBColor RGBColor::INVISIBLE = RGBColor(0, 0, 0, 0);
54
57
58// random colors do not affect the simulation. No initialization is necessary
60
61// ===========================================================================
62// method definitions
63// ===========================================================================
64
66 : myRed(0), myGreen(0), myBlue(0), myAlpha(0), myValid(valid) {}
67
68
69RGBColor::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
73unsigned char
75 return myRed;
76}
77
78
79unsigned char
81 return myGreen;
82}
83
84
85unsigned char
87 return myBlue;
88}
89
90
91unsigned char
93 return myAlpha;
94}
95
96
97void
98RGBColor::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
107void
108RGBColor::setAlpha(unsigned char alpha) {
109 myAlpha = alpha;
110}
111
112
113void
114RGBColor::setValid(const bool value) {
115 myValid = value;
116}
117
118
119bool
121 return myValid;
122}
123
124
125std::ostream&
126operator<<(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
170bool
172 return (myRed == c.myRed) && (myGreen == c.myGreen) && (myBlue == c.myBlue) && (myAlpha == c.myAlpha) && (myValid == c.myValid);
173}
174
175
176bool
178 return (myRed != c.myRed) || (myGreen != c.myGreen) || (myBlue != c.myBlue) || (myAlpha != c.myAlpha) || (myValid != c.myValid);
179}
180
181
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
193SumoRNG*
195 return &myRNG;
196}
197
198
200RGBColor::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
223RGBColor::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
230RGBColor::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
239RGBColor::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 InvalidArgument("Invalid color definition '" + coldef + "'");
322 }
323 }
324 return RGBColor(r, g, b, a);
325}
326
327
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
355RGBColor::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
371RGBColor::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
403RGBColor::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:274
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:71
T MAX2(T a, T b)
Definition: StdDefs.h:77
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:76
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,...