OGS
DiagramList.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "DiagramList.h"
5
6#include <QFile>
7#include <QTextStream>
8#include <limits>
9
10#include "BaseLib/DateTools.h"
11#include "BaseLib/Logging.h"
12#include "BaseLib/StringTools.h"
13#include "GeoLib/SensorData.h"
14#include "GetDateTime.h"
15
17
19
21{
22 auto min = std::min_element(_coords.begin(), _coords.end(),
23 [](auto const& c0, auto const& c1)
24 { return c0.first < c1.first; });
25 if (min != _coords.end())
26 {
27 return min->first;
28 }
29 return std::numeric_limits<float>::max();
30}
31
33{
34 float max = std::numeric_limits<float>::lowest();
35 std::size_t nCoords = _coords.size();
36 for (std::size_t i = 0; i < nCoords; i++)
37 {
38 if (_coords[i].first > max)
39 {
40 max = _coords[i].first;
41 }
42 }
43 return max;
44}
45
47{
48 float min = std::numeric_limits<float>::max();
49 std::size_t nCoords = _coords.size();
50 for (std::size_t i = 0; i < nCoords; i++)
51 {
52 if (_coords[i].second < min)
53 {
54 min = _coords[i].second;
55 }
56 }
57 return min;
58}
59
61{
62 float max = std::numeric_limits<float>::lowest();
63 std::size_t nCoords = _coords.size();
64 for (std::size_t i = 0; i < nCoords; i++)
65 {
66 if (_coords[i].second > max)
67 {
68 max = _coords[i].second;
69 }
70 }
71 return max;
72}
73
74bool DiagramList::getPath(QPainterPath& path, float scaleX, float scaleY)
75{
76 QPointF p;
77 if (getPoint(p, 0))
78 {
79 QPainterPath pp(QPointF(p.x() * scaleX, p.y() * scaleY));
80 path = pp;
81
82 std::size_t nCoords = _coords.size();
83 for (std::size_t i = 1; i < nCoords; i++)
84 {
85 getPoint(p, i);
86 path.lineTo(QPointF(p.x() * scaleX, p.y() * scaleY));
87 }
88 return true;
89 }
90
91 return false;
92}
93
94bool DiagramList::getPoint(QPointF& p, std::size_t i)
95{
96 if (i < _coords.size())
97 {
98 p.setX(_coords[i].first);
99 p.setY(_coords[i].second);
100 return true;
101 }
102
103 return false;
104}
105
106/*
107 * Reads an external list into the coordinate arrays.
108 * This method uses files containing the following format:
109 * xValue <tab> yValue
110 * Both values may be int or double.
111 */
112/*
113 int DiagramList::readList(char* path)
114 {
115 int date;
116 double xVal, yVal;
117 QString line;
118 QStringList fields;
119
120 QFile file(path);
121 QTextStream in( &file );
122
123 if (!file.open(QIODevice::ReadOnly))
124 {
125 return 0;
126 }
127
128 while (!in.atEnd()) {
129 line = in.readLine();
130 fields = line.split('\t');
131 if (fields.size() >= 2) {
132 xVal = fields.takeFirst().toDouble();
133 yVal = fields.takeFirst().toDouble();
134 xCoords.push_back(xVal);
135 yCoords.push_back(yVal);
136 }
137 else return 0;
138 }
139
140 file.close();
141 update();
142
143 return 1;
144 }*/
145
146int DiagramList::readList(const QString& path, std::vector<DiagramList*>& lists)
147{
148 QFile file(path);
149 QTextStream in(&file);
150
151 if (!file.open(QIODevice::ReadOnly))
152 {
153 qDebug("Could not open file...");
154 return 0;
155 }
156
157 QString line = in.readLine();
158 QStringList fields = line.split('\t');
159 int nLists(fields.size() - 1);
160
161 if (fields.size() >= 2)
162 {
163 fields.takeFirst();
164 for (int i = 0; i < nLists; i++)
165 {
166 auto* l = new DiagramList;
167 l->setName(fields.takeFirst());
168 // value = strtod(BaseLib::replaceStringreplaceString(",", ".",
169 // fields.takeFirst().toStdString()).c_str(),0);
170 // l->setStartDate(startDate);
171 // l->addNextPoint(0,value);
172 lists.push_back(l);
173 }
174
175 bool first_loop(true);
176 QDateTime startDate;
177 QDateTime currentDate;
178 unsigned line_count(1);
179
180 while (!in.atEnd())
181 {
182 line = in.readLine();
183 line_count++;
184 fields = line.split('\t');
185 if (fields.size() >= (nLists + 1))
186 {
187 QString const stringDate = fields.takeFirst();
188 currentDate = getDateTime(stringDate);
189 if (first_loop)
190 {
191 startDate = currentDate;
192 for (int i = 0; i < nLists; i++)
193 {
194 lists[i]->setStartDate(startDate);
195 }
196 first_loop = false;
197 }
198
199 auto const numberOfSecs =
200 static_cast<float>(startDate.secsTo(currentDate));
201 for (int i = 0; i < nLists; i++)
202 {
203 float const value = static_cast<float>(
205 ",", ".", fields.takeFirst().toStdString())
206 .c_str(),
207 nullptr));
208 lists[i]->addNextPoint(numberOfSecs, value);
209 }
210 }
211 else
212 {
213 WARN("DiagramList::readList(): Unexpected format in line {:d}.",
214 line_count);
215 file.close();
216 return 0;
217 }
218 }
219 }
220 else
221 {
222 qDebug("Unexpected file format...");
223 file.close();
224 return 0;
225 }
226
227 file.close();
228
229 for (int i = 0; i < nLists; i++)
230 {
231 lists[i]->update();
232 }
233
234 return nLists;
235}
236
238 std::vector<DiagramList*>& lists)
239{
240 std::vector<SensorDataType> const& time_series_names(
241 data->getTimeSeriesNames());
242 int nLists(time_series_names.size());
243
244 std::vector<std::size_t> time_steps;
245 if (data->getStepSize() > 0)
246 {
247 const std::size_t start = data->getStartTime();
248 const std::size_t end = data->getEndTime();
249 const std::size_t stepsize = data->getStepSize();
250 for (std::size_t i = start; i <= end; i += stepsize)
251 {
252 time_steps.push_back(i);
253 }
254 }
255 else
256 {
257 time_steps = data->getTimeSteps();
258 }
259
260 bool is_date(false);
261
262 if (!(BaseLib::int2date(time_steps[0])).empty())
263 {
264 is_date = true;
265 }
266
267 std::size_t nValues(time_steps.size());
268
269 for (int i = 0; i < nLists; i++)
270 {
271 auto const* time_series = data->getTimeSeries(time_series_names[i]);
272 if (!time_series)
273 {
274 continue;
275 }
276
277 auto* l = new DiagramList;
278 l->setName(QString::fromStdString(
279 SensorData::convertSensorDataType2String(time_series_names[i])));
280 l->setXLabel("Time");
281 lists.push_back(l);
282
283 if (is_date)
284 {
285 l->setXUnit("day");
286 QDateTime const startDate(
287 getDateTime(BaseLib::int2date(time_steps[0])));
288 lists[i]->setStartDate(startDate);
289 for (std::size_t j = 0; j < nValues; j++)
290 {
291 QDateTime const currentDate(
292 getDateTime(BaseLib::int2date(time_steps[j])));
293 auto numberOfSecs =
294 static_cast<float>(startDate.secsTo(currentDate));
295 lists[i]->addNextPoint(numberOfSecs, (*time_series)[j]);
296 }
297 }
298 else
299 {
300 l->setXUnit("time step");
301 for (std::size_t j = 0; j < nValues; j++)
302 {
303 lists[i]->addNextPoint(static_cast<float>(time_steps[j]),
304 (*time_series)[j]);
305 }
306 }
307
308 lists[i]->update();
309 }
310
311 return nLists;
312}
313
314void DiagramList::truncateToRange(QDateTime const& start, QDateTime const& end)
315{
316 auto start_secs = static_cast<float>(_startDate.secsTo(start));
317 if (start_secs < 0)
318 {
319 start_secs = 0;
320 }
321 auto end_secs = static_cast<float>(_startDate.secsTo(end));
322 if (end_secs < start_secs)
323 {
324 end_secs = _coords.back().first;
325 }
326
327 if (start_secs == 0 && end_secs == _coords.back().first)
328 {
329 return;
330 }
331
332 _coords.erase(std::remove_if(
333 _coords.begin(), _coords.end(),
334 [&](std::pair<float, float> const& c)
335 { return (c.first < start_secs || c.first > end_secs); }),
336 _coords.end());
337 _startDate = start;
338 for (auto& c : _coords)
339 {
340 c.first -= start_secs;
341 }
342 update();
343}
344
346 std::vector<std::pair<QDateTime, float>> const& coords)
347{
348 if (coords.empty())
349 {
350 return;
351 }
352
353 _startDate = coords[0].first;
354 std::transform(coords.begin(), coords.end(), std::back_inserter(_coords),
355 [this](auto const& p)
356 {
357 return std::make_pair(
358 static_cast<float>(_startDate.daysTo(p.first)),
359 p.second);
360 });
361
362 update();
363}
364
365void DiagramList::setList(std::vector<std::pair<float, float>> const& coords)
366{
367 if (coords.empty())
368 {
369 return;
370 }
371
372 this->_startDate = QDateTime();
373 std::copy(coords.begin(), coords.end(), std::back_inserter(_coords));
374 update();
375}
376
377std::size_t DiagramList::size() const
378{
379 return _coords.size();
380}
381
QDateTime getDateTime(QString const &stringDate)
Converts string into QDateTime-format.
Definition GetDateTime.h:11
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
void update()
Updates the bounds of the data points contained in the list.
bool getPoint(QPointF &p, std::size_t i)
std::size_t size() const
Returns the number of data points.
void truncateToRange(QDateTime const &start, QDateTime const &end)
cut list entries not within the given range
QString _yLabel
DiagramList()
Constructor containing an empty list.
QDateTime _startDate
float calcMinXValue()
Returns the minimum x-value of all the data points.
static int readList(const QString &path, std::vector< DiagramList * > &list)
float calcMaxXValue()
Returns the maximum x-value of all the data points.
float calcMinYValue()
Returns the minimum y-value of all the data points.
float calcMaxYValue()
Returns the maximum y-value of all the data points.
std::vector< std::pair< float, float > > _coords
QString _yUnit
QString _xLabel
void setList(std::vector< std::pair< float, float > > const &coords)
bool getPath(QPainterPath &path, float scaleX, float scaleY)
QString _xUnit
A container for sensor data at an observation site. The class stores a number of time series and has ...
Definition SensorData.h:52
std::size_t getEndTime() const
Returns the last time step.
Definition SensorData.h:93
const std::vector< float > * getTimeSeries(SensorDataType time_series_name) const
Returns the time series with the given name.
const std::vector< std::size_t > & getTimeSteps() const
Returns the time step vector (if it exists)
Definition SensorData.h:87
std::size_t getStartTime() const
Returns the first time step.
Definition SensorData.h:90
const std::vector< SensorDataType > & getTimeSeriesNames() const
Returns all time series names contained in this container.
Definition SensorData.h:81
std::size_t getStepSize() const
Definition SensorData.h:97
static std::string convertSensorDataType2String(SensorDataType t)
Converts Sensor Data Types to Strings.
std::string replaceString(const std::string &searchString, const std::string &replaceString, std::string stringToReplace)
std::string int2date(int date)
Definition DateTools.cpp:31