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