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 GUIPropertyScheme.h
15 : /// @author Michael Behrisch
16 : /// @author Daniel Krajzewicz
17 : /// @author Jakob Erdmann
18 : /// @date Mon, 20.07.2009
19 : ///
20 : //
21 : /****************************************************************************/
22 : #pragma once
23 : #include <config.h>
24 :
25 : #include <cassert>
26 : #include <vector>
27 : #include <utils/common/RGBColor.h>
28 : #include <utils/iodevices/OutputDevice.h>
29 : #include <utils/gui/images/GUIIcons.h>
30 :
31 :
32 : // ===========================================================================
33 : // class definitions
34 : // ===========================================================================
35 : /**
36 : * @class GUIPropertyScheme
37 : * This class provides a mapping from real values to properties (mainly colors).
38 : * Each color is stored along with a threshold value.
39 : * Color values between thresholds are obtained by interpolation
40 : */
41 :
42 : template<class T>
43 : class GUIPropertyScheme {
44 : public:
45 : /// Constructor
46 8441217 : GUIPropertyScheme(const std::string& name, const std::string& translatedName, const T& baseColor,
47 : const std::string& colName = "", const bool isFixed = false, double baseValue = 0,
48 : RGBColor bgColor = RGBColor::WHITE,
49 : GUIIcon icon = GUIIcon::EMPTY) :
50 8441217 : myName(name),
51 8441217 : myTranslatedName(translatedName),
52 8441217 : myIsInterpolated(!isFixed),
53 8441217 : myIsFixed(isFixed),
54 8441217 : myAllowNegativeValues(false),
55 8441217 : myIcon(icon),
56 8441217 : myBgColor(bgColor) {
57 8441217 : addColor(baseColor, baseValue, colName);
58 8441217 : }
59 :
60 5019144 : GUIPropertyScheme(const std::string& name, const T& baseColor,
61 : const std::string& colName = "", const bool isFixed = false, double baseValue = 0,
62 : RGBColor bgColor = RGBColor::WHITE,
63 : GUIIcon icon = GUIIcon::EMPTY) :
64 5019144 : myName(name),
65 5019144 : myTranslatedName(name),
66 5019144 : myIsInterpolated(!isFixed),
67 5019144 : myIsFixed(isFixed),
68 5019144 : myAllowNegativeValues(false),
69 5019144 : myIcon(icon),
70 5019144 : myBgColor(bgColor) {
71 5019144 : addColor(baseColor, baseValue, colName);
72 5019144 : }
73 :
74 : void setThreshold(const int pos, const double threshold) {
75 0 : myThresholds[pos] = threshold;
76 : }
77 :
78 : void setColor(const int pos, const T& color) {
79 0 : myColors[pos] = color;
80 : }
81 :
82 2110 : bool setColor(const std::string& name, const T& color) {
83 : std::vector<std::string>::iterator nameIt = myNames.begin();
84 : typename std::vector<T>::iterator colIt = myColors.begin();
85 6216 : for (; nameIt != myNames.end(); ++nameIt, ++colIt) {
86 6202 : if (*nameIt == name) {
87 2096 : (*colIt) = color;
88 2096 : return true;
89 : }
90 : }
91 : return false;
92 : }
93 :
94 49212840 : int addColor(const T& color, const double threshold, const std::string& name = "") {
95 : typename std::vector<T>::iterator colIt = myColors.begin();
96 : std::vector<double>::iterator threshIt = myThresholds.begin();
97 : std::vector<std::string>::iterator nameIt = myNames.begin();
98 : int pos = 0;
99 150150141 : while (threshIt != myThresholds.end() && (*threshIt) < threshold) {
100 : ++threshIt;
101 : ++colIt;
102 : ++nameIt;
103 100937301 : pos++;
104 : }
105 49212840 : myColors.insert(colIt, color);
106 49212840 : myThresholds.insert(threshIt, threshold);
107 49212840 : myNames.insert(nameIt, name);
108 49212840 : return pos;
109 : }
110 :
111 0 : void removeColor(const int pos) {
112 : assert(pos < (int)myColors.size());
113 0 : myColors.erase(myColors.begin() + pos);
114 0 : myThresholds.erase(myThresholds.begin() + pos);
115 0 : myNames.erase(myNames.begin() + pos);
116 0 : }
117 :
118 2467 : void clear() {
119 : myColors.clear();
120 : myThresholds.clear();
121 : myNames.clear();
122 2467 : }
123 :
124 69645105 : T getColor(const double value) const {
125 69645105 : if (myColors.size() == 1 || value < myThresholds.front()) {
126 43252363 : return myColors.front();
127 : }
128 : typename std::vector<T>::const_iterator colIt = myColors.begin() + 1;
129 : std::vector<double>::const_iterator threshIt = myThresholds.begin() + 1;
130 31224247 : while (threshIt != myThresholds.end() && (*threshIt) <= value) {
131 : ++threshIt;
132 : ++colIt;
133 : }
134 26392742 : if (threshIt == myThresholds.end()) {
135 352547 : return myColors.back();
136 : }
137 26040195 : if (!myIsInterpolated) {
138 25922479 : return *(colIt - 1);
139 : }
140 117716 : double lowVal = *(threshIt - 1);
141 117716 : return interpolate(*(colIt - 1), *colIt, (value - lowVal) / ((*threshIt) - lowVal));
142 : }
143 :
144 : void setInterpolated(const bool interpolate, double interpolationStart = 0.f) {
145 2425 : myIsInterpolated = interpolate;
146 2425 : if (interpolate) {
147 2425 : myThresholds[0] = interpolationStart;
148 : }
149 : }
150 :
151 : const std::string& getName() const {
152 458539 : return myName;
153 : }
154 :
155 : const std::string& getTranslatedName() const {
156 : return myTranslatedName;
157 : }
158 :
159 : const std::vector<T>& getColors() const {
160 : return myColors;
161 : }
162 :
163 : const std::vector<double>& getThresholds() const {
164 : return myThresholds;
165 : }
166 :
167 : bool isInterpolated() const {
168 0 : return myIsInterpolated;
169 : }
170 :
171 : const std::vector<std::string>& getNames() const {
172 : return myNames;
173 : }
174 :
175 : bool isFixed() const {
176 15694 : return myIsFixed;
177 : }
178 :
179 : bool allowsNegativeValues() const {
180 0 : return myAllowNegativeValues;
181 : }
182 :
183 : void setAllowsNegativeValues(bool value) {
184 3270021 : myAllowNegativeValues = value;
185 : }
186 :
187 : GUIIcon getIcon() const {
188 0 : return myIcon;
189 : }
190 :
191 : const RGBColor& getBackgroundColor() const {
192 0 : return myBgColor;
193 : }
194 :
195 0 : void save(OutputDevice& dev, const std::string& prefix = "") const {
196 : const int precision = dev.getPrecision();
197 : const bool checkPrecision = precision <= 2; // 2 is default precision (see SystemFrame)
198 0 : const std::string tag = getTagName(myColors);
199 :
200 0 : dev.openTag(tag);
201 0 : dev.writeAttr(SUMO_ATTR_NAME, prefix + myName);
202 0 : if (!myIsFixed) {
203 0 : dev.writeAttr(SUMO_ATTR_INTERPOLATED, myIsInterpolated);
204 : }
205 : typename std::vector<T>::const_iterator colIt = myColors.begin();
206 : std::vector<double>::const_iterator threshIt = myThresholds.begin();
207 : std::vector<std::string>::const_iterator nameIt = myNames.begin();
208 0 : while (threshIt != myThresholds.end()) {
209 0 : dev.openTag(SUMO_TAG_ENTRY);
210 : dev.writeAttr(SUMO_ATTR_COLOR, *colIt);
211 0 : if (!myIsFixed && (*threshIt) != std::numeric_limits<double>::max()) {
212 0 : const double t = *threshIt;
213 0 : if (checkPrecision && t != 0 && fabs(t) < 0.01) {
214 0 : dev.setPrecision(8);
215 : }
216 : dev.writeAttr(SUMO_ATTR_THRESHOLD, t);
217 0 : dev.setPrecision(precision);
218 : }
219 0 : if ((*nameIt) != "") {
220 : dev.writeAttr(SUMO_ATTR_NAME, *nameIt);
221 : }
222 0 : dev.closeTag();
223 : ++threshIt;
224 : ++colIt;
225 : ++nameIt;
226 : }
227 0 : dev.closeTag();
228 0 : }
229 :
230 0 : bool operator==(const GUIPropertyScheme& c) const {
231 0 : return myName == c.myName && myColors == c.myColors && myThresholds == c.myThresholds && myIsInterpolated == c.myIsInterpolated;
232 : }
233 :
234 :
235 : /// @brief specializations for GUIColorScheme
236 : RGBColor interpolate(const RGBColor& min, const RGBColor& max, double weight) const {
237 117716 : return RGBColor::interpolate(min, max, weight);
238 : }
239 :
240 : std::string getTagName(std::vector<RGBColor>) const {
241 0 : return toString(SUMO_TAG_COLORSCHEME);
242 : }
243 :
244 :
245 : /// @brief specializations for GUIScaleScheme
246 : double interpolate(const double& min, const double& max, double weight) const {
247 0 : return min + (max - min) * weight;
248 : }
249 :
250 : std::string getTagName(std::vector<double>) const {
251 0 : return toString(SUMO_TAG_SCALINGSCHEME);
252 : }
253 :
254 :
255 : private:
256 : std::string myName;
257 : std::string myTranslatedName;
258 : std::vector<T> myColors;
259 : std::vector<double> myThresholds;
260 : bool myIsInterpolated;
261 : std::vector<std::string> myNames;
262 : bool myIsFixed;
263 : bool myAllowNegativeValues;
264 : GUIIcon myIcon;
265 : RGBColor myBgColor;
266 :
267 : };
268 :
269 : typedef GUIPropertyScheme<RGBColor> GUIColorScheme;
270 : typedef GUIPropertyScheme<double> GUIScaleScheme;
|