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 LinearApproxHelpers.cpp
15 : /// @author Mirko Barthauer
16 : /// @date 17 May 2024
17 : ///
18 : // Provides a tabular data points map with parsing and interpolation support
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <string>
23 : #include <map>
24 : #include <algorithm>
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/common/StringTokenizer.h>
27 : #include <utils/common/UtilExceptions.h>
28 : #include "LinearApproxHelpers.h"
29 :
30 :
31 : double
32 0 : LinearApproxHelpers::getMinimumValue(const LinearApproxMap& map) {
33 0 : if (map.empty()) {
34 0 : throw ProcessError(TL("Cannot determine the minimum value from an empty map."));
35 : }
36 : double minValue = std::numeric_limits<double>::max();
37 0 : for (const auto& item : map) {
38 0 : if (item.second < minValue) {
39 : minValue = item.second;
40 : }
41 : }
42 0 : return minValue;
43 : }
44 :
45 :
46 : double
47 0 : LinearApproxHelpers::getMaximumValue(const LinearApproxMap& map) {
48 0 : if (map.empty()) {
49 0 : throw ProcessError(TL("Cannot determine the maximum value from an empty map."));
50 : }
51 : double maxValue = std::numeric_limits<double>::min();
52 0 : for (const auto& item : map) {
53 0 : if (item.second > maxValue) {
54 : maxValue = item.second;
55 : }
56 : }
57 0 : return maxValue;
58 : }
59 :
60 :
61 : double
62 3775758 : LinearApproxHelpers::getInterpolatedValue(const LinearApproxMap& map, double axisValue) {
63 : LinearApproxHelpers::LinearApproxMap::const_iterator low, prev;
64 : low = map.lower_bound(axisValue);
65 3775758 : if (low == map.end()) {
66 9160 : return (map.rbegin())->second;
67 : }
68 3766598 : if (low == map.begin()) {
69 596055 : return low->second;
70 : }
71 : prev = low;
72 : --prev;
73 3170543 : double range = low->first - prev->first;
74 3170543 : double dist = axisValue - prev->first;
75 : assert(range > 0);
76 : assert(dist > 0);
77 3170543 : double weight = dist / range;
78 3170543 : double res = (1 - weight) * prev->second + weight * low->second;
79 3170543 : return res;
80 : }
81 :
82 :
83 : std::vector<double>
84 0 : LinearApproxHelpers::getValueTable(const std::string& dataString) {
85 : std::vector<double> result;
86 0 : if (!dataString.empty()) {
87 0 : for (std::string value : StringTokenizer(dataString).getVector()) {
88 0 : result.push_back(StringUtils::toDouble(value));
89 0 : }
90 : }
91 0 : return result;
92 0 : }
93 :
94 :
95 : bool
96 0 : LinearApproxHelpers::setPoints(LinearApproxMap& map, const std::string& axisString, const std::string& heightString) {
97 0 : std::vector<double> axisData = getValueTable(axisString);
98 0 : std::vector<double> heightData = getValueTable(heightString);
99 0 : if (heightData.size() > 0 && heightData.size() != axisData.size()) {
100 0 : throw ProcessError(TLF("Mismatching data rows of % axis and % height values.", axisData.size(), heightData.size()));
101 : } else {
102 : auto itA = axisData.begin();
103 : auto itB = heightData.begin();
104 0 : for (; itA != axisData.end() && itB != heightData.end(); ++itA, ++itB) {
105 0 : map.insert({ *itA, *itB });
106 : }
107 : }
108 0 : return true;
109 0 : }
110 :
111 :
112 : void
113 652 : LinearApproxHelpers::scalePoints(LinearApproxMap& map, double keyFactor, double valueFactor) {
114 : LinearApproxMap map2;
115 19254 : for (const auto& item : map) {
116 18602 : map2[item.first * keyFactor] = item.second * valueFactor;
117 : }
118 : map.swap(map2);
119 652 : }
120 :
121 :
122 : void
123 0 : LinearApproxHelpers::scaleValues(LinearApproxMap& map, const double factor) {
124 0 : for (auto& p : map) {
125 0 : p.second *= factor;
126 : }
127 0 : }
128 :
129 :
130 0 : void LinearApproxHelpers::setValues(LinearApproxMap& map, const std::string& heightString) {
131 0 : std::vector<double> heightData = getValueTable(heightString);
132 0 : if (heightData.size() > 0 && heightData.size() != map.size()) {
133 0 : throw ProcessError(TLF("Mismatching data rows of % axis and % height values.", map.size(), heightData.size()));
134 : } else {
135 : std::vector<double>::const_iterator heightIt = heightData.begin();
136 0 : for (auto& p : map) {
137 0 : p.second = *heightIt;
138 : ++heightIt;
139 : }
140 : }
141 0 : }
|