1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    RGBColor.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @author  Laura Bieker
15 /// @date    Sept 2002
16 /// @version $Id$
17 ///
18 // A RGB-color definition
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <cmath>
28 #include <cassert>
29 #include <string>
30 #include <sstream>
31 #include <utils/common/RandHelper.h>
32 #include <utils/common/StringTokenizer.h>
33 #include <utils/common/ToString.h>
34 #include <utils/common/StringUtils.h>
35 #include <utils/common/MsgHandler.h>
36 #include <utils/common/StdDefs.h>
37 #include "RGBColor.h"
38 
39 
40 // ===========================================================================
41 // static member definitions
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 std::mt19937 RGBColor::myRNG;
60 
61 // ===========================================================================
62 // method definitions
63 // ===========================================================================
RGBColor()64 RGBColor::RGBColor()
65     : myRed(0), myGreen(0), myBlue(0), myAlpha(0) {}
66 
67 
RGBColor(unsigned char red,unsigned char green,unsigned char blue,unsigned char alpha)68 RGBColor::RGBColor(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
69     : myRed(red), myGreen(green), myBlue(blue), myAlpha(alpha) {}
70 
71 
RGBColor(const RGBColor & col)72 RGBColor::RGBColor(const RGBColor& col)
73     : myRed(col.myRed), myGreen(col.myGreen), myBlue(col.myBlue), myAlpha(col.myAlpha) {}
74 
75 
~RGBColor()76 RGBColor::~RGBColor() {}
77 
78 
79 void
set(unsigned char r,unsigned char g,unsigned char b,unsigned char a)80 RGBColor::set(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
81     myRed = r;
82     myGreen = g;
83     myBlue = b;
84     myAlpha = a;
85 }
86 
87 
88 std::ostream&
operator <<(std::ostream & os,const RGBColor & col)89 operator<<(std::ostream& os, const RGBColor& col) {
90     if (col == RGBColor::RED) {
91         return os << "red";
92     }
93     if (col == RGBColor::GREEN) {
94         return os << "green";
95     }
96     if (col == RGBColor::BLUE) {
97         return os << "blue";
98     }
99     if (col == RGBColor::YELLOW) {
100         return os << "yellow";
101     }
102     if (col == RGBColor::CYAN) {
103         return os << "cyan";
104     }
105     if (col == RGBColor::MAGENTA) {
106         return os << "magenta";
107     }
108     if (col == RGBColor::ORANGE) {
109         return os << "orange";
110     }
111     if (col == RGBColor::WHITE) {
112         return os << "white";
113     }
114     if (col == RGBColor::BLACK) {
115         return os << "black";
116     }
117     if (col == RGBColor::GREY) {
118         return os << "grey";
119     }
120     os << static_cast<int>(col.myRed) << ","
121        << static_cast<int>(col.myGreen) << ","
122        << static_cast<int>(col.myBlue);
123     if (col.myAlpha < 255) {
124         os << "," << static_cast<int>(col.myAlpha);
125     }
126     return os;
127 }
128 
129 
130 bool
operator ==(const RGBColor & c) const131 RGBColor::operator==(const RGBColor& c) const {
132     return myRed == c.myRed && myGreen == c.myGreen && myBlue == c.myBlue && myAlpha == c.myAlpha;
133 }
134 
135 
136 bool
operator !=(const RGBColor & c) const137 RGBColor::operator!=(const RGBColor& c) const {
138     return myRed != c.myRed || myGreen != c.myGreen || myBlue != c.myBlue || myAlpha != c.myAlpha;
139 }
140 
141 
142 RGBColor
invertedColor() const143 RGBColor::invertedColor() const {
144     // obtain inverse colors
145     const unsigned char r = (unsigned char)(255 - (int)myRed);
146     const unsigned char g = (unsigned char)(255 - (int)myGreen);
147     const unsigned char b = (unsigned char)(255  - (int)myBlue);
148     // return inverted RBColor
149     return RGBColor(r, g, b, myAlpha);
150 }
151 
152 
153 RGBColor
changedBrightness(int change,int toChange) const154 RGBColor::changedBrightness(int change, int toChange) const {
155     const unsigned char red = (unsigned char)(MIN2(MAX2(myRed + change, 0), 255));
156     const unsigned char blue = (unsigned char)(MIN2(MAX2(myBlue + change, 0), 255));
157     const unsigned char green = (unsigned char)(MIN2(MAX2(myGreen + change, 0), 255));
158     int changed = ((int)red - (int)myRed) + ((int)blue - (int)myBlue) + ((int)green - (int)myGreen);
159     const RGBColor result(red, green, blue, myAlpha);
160     if (changed == toChange * change) {
161         return result;
162     } else if (changed == 0) {
163         return result;
164     } else {
165         const int maxedColors = (red != myRed + change ? 1 : 0) + (blue != myBlue + change ? 1 : 0) + (green != myGreen + change ? 1 : 0);
166         if (maxedColors == 3) {
167             return result;
168         } else {
169             const int toChangeNext = 3 - maxedColors;
170             return result.changedBrightness((int)((toChange * change - changed) / toChangeNext), toChangeNext);
171         }
172     }
173 }
174 
175 
176 RGBColor
parseColor(std::string coldef)177 RGBColor::parseColor(std::string coldef) {
178     std::transform(coldef.begin(), coldef.end(), coldef.begin(), tolower);
179     if (coldef == "red") {
180         return RED;
181     }
182     if (coldef == "green") {
183         return GREEN;
184     }
185     if (coldef == "blue") {
186         return BLUE;
187     }
188     if (coldef == "yellow") {
189         return YELLOW;
190     }
191     if (coldef == "cyan") {
192         return CYAN;
193     }
194     if (coldef == "magenta") {
195         return MAGENTA;
196     }
197     if (coldef == "orange") {
198         return ORANGE;
199     }
200     if (coldef == "white") {
201         return WHITE;
202     }
203     if (coldef == "black") {
204         return BLACK;
205     }
206     if (coldef == "grey" || coldef == "gray") {
207         return GREY;
208     }
209     unsigned char r = 0;
210     unsigned char g = 0;
211     unsigned char b = 0;
212     unsigned char a = 255;
213     if (coldef[0] == '#') {
214         const int coldesc = StringUtils::hexToInt(coldef);
215         if (coldef.length() == 7) {
216             r = static_cast<unsigned char>((coldesc & 0xFF0000) >> 16);
217             g = static_cast<unsigned char>((coldesc & 0x00FF00) >> 8);
218             b = coldesc & 0xFF;
219         } else if (coldef.length() == 9) {
220             r = static_cast<unsigned char>((coldesc & 0xFF000000) >> 24);
221             g = static_cast<unsigned char>((coldesc & 0x00FF0000) >> 16);
222             b = static_cast<unsigned char>((coldesc & 0x0000FF00) >> 8);
223             a = coldesc & 0xFF;
224         } else {
225             throw EmptyData();
226         }
227     } else {
228         std::vector<std::string> st = StringTokenizer(coldef, ",").getVector();
229         if (st.size() == 3 || st.size() == 4) {
230             try {
231                 r = static_cast<unsigned char>(StringUtils::toInt(st[0]));
232                 g = static_cast<unsigned char>(StringUtils::toInt(st[1]));
233                 b = static_cast<unsigned char>(StringUtils::toInt(st[2]));
234                 if (st.size() == 4) {
235                     a = static_cast<unsigned char>(StringUtils::toInt(st[3]));
236                 }
237                 if (r <= 1 && g <= 1 && b <= 1 && (st.size() == 3 || a <= 1)) {
238                     throw NumberFormatException("(color component) " + coldef);
239                 }
240             } catch (NumberFormatException&) {
241                 r = static_cast<unsigned char>(StringUtils::toDouble(st[0]) * 255. + 0.5);
242                 g = static_cast<unsigned char>(StringUtils::toDouble(st[1]) * 255. + 0.5);
243                 b = static_cast<unsigned char>(StringUtils::toDouble(st[2]) * 255. + 0.5);
244                 if (st.size() == 4) {
245                     a = static_cast<unsigned char>(StringUtils::toDouble(st[3]) * 255. + 0.5);
246                 }
247             }
248         } else {
249             throw EmptyData();
250         }
251     }
252     return RGBColor(r, g, b, a);
253 }
254 
255 
256 RGBColor
parseColorReporting(const std::string & coldef,const std::string & objecttype,const char * objectid,bool report,bool & ok)257 RGBColor::parseColorReporting(
258     const std::string& coldef, const std::string& objecttype,
259     const char* objectid, bool report, bool& ok) {
260     UNUSED_PARAMETER(report);
261     try {
262         return parseColor(coldef);
263     } catch (NumberFormatException&) {
264     } catch (EmptyData&) {
265     }
266     ok = false;
267     std::ostringstream oss;
268     oss << "Attribute 'color' in definition of ";
269     if (objectid == nullptr) {
270         oss << "a ";
271     }
272     oss << objecttype;
273     if (objectid != nullptr) {
274         oss << " '" << objectid << "'";
275     }
276     oss << " is not a valid color.";
277     WRITE_ERROR(oss.str());
278     return RGBColor();
279 }
280 
281 
282 RGBColor
interpolate(const RGBColor & minColor,const RGBColor & maxColor,double weight)283 RGBColor::interpolate(const RGBColor& minColor, const RGBColor& maxColor, double weight) {
284     if (weight < 0) {
285         weight = 0;
286     }
287     if (weight > 1) {
288         weight = 1;
289     }
290     const unsigned char r = (unsigned char)((int)minColor.myRed   + (((int)maxColor.myRed   - (int)minColor.myRed)   * weight));
291     const unsigned char g = (unsigned char)((int)minColor.myGreen + (((int)maxColor.myGreen - (int)minColor.myGreen) * weight));
292     const unsigned char b = (unsigned char)((int)minColor.myBlue  + (((int)maxColor.myBlue  - (int)minColor.myBlue)  * weight));
293     const unsigned char a = (unsigned char)((int)minColor.myAlpha + (((int)maxColor.myAlpha - (int)minColor.myAlpha) * weight));
294     return RGBColor(r, g, b, a);
295 }
296 
297 
298 RGBColor
fromHSV(double h,double s,double v)299 RGBColor::fromHSV(double h, double s, double v) {
300     h /= 60.;
301     const int i = int(floor(h));
302     double f = h - i;
303     if (i % 2 == 0) {
304         f = 1. - f;
305     }
306     const unsigned char m = static_cast<unsigned char>(v * (1 - s) * 255. + 0.5);
307     const unsigned char n = static_cast<unsigned char>(v * (1 - s * f) * 255. + 0.5);
308     const unsigned char vv = static_cast<unsigned char>(v * 255. + 0.5);
309     switch (i) {
310         case 6:
311         case 0:
312             return RGBColor(vv, n, m, 255);
313         case 1:
314             return RGBColor(n, vv, m, 255);
315         case 2:
316             return RGBColor(m, vv, n, 255);
317         case 3:
318             return RGBColor(m, n, vv, 255);
319         case 4:
320             return RGBColor(n, m, vv, 255);
321         case 5:
322             return RGBColor(vv, m, n, 255);
323     }
324     return RGBColor(255, 255, 255, 255);
325 }
326 
327 RGBColor
randomHue(double s,double v)328 RGBColor::randomHue(double s, double v) {
329     return fromHSV(RandHelper::rand(360, &myRNG), s, v);
330 }
331 
332 /****************************************************************************/
333 
334