##// END OF EJS Templates
Adds unit test for filling data holes at beginning/end of the series
Adds unit test for filling data holes at beginning/end of the series

File last commit:

r1024:fa3d932b9e7e
r1025:7f55942fb5ec
Show More
DataSeriesUtils.cpp
81 lines | 3.4 KiB | text/x-c | CppLexer
/ core / src / Data / DataSeriesUtils.cpp
#include "Data/DataSeriesUtils.h"
Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils")
void DataSeriesUtils::fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
double resolution, double fillValue, double minBound,
double maxBound)
{
if (resolution == 0. || std::isnan(resolution)) {
qCWarning(LOG_DataSeriesUtils())
<< "Can't fill data holes with a null resolution, no changes will be made";
return;
}
if (xAxisData.empty()) {
qCWarning(LOG_DataSeriesUtils())
<< "Can't fill data holes for empty data, no changes will be made";
return;
}
// Gets the number of values per x-axis data
auto nbComponents = valuesData.size() / xAxisData.size();
// Generates fill values that will be used to complete values data
std::vector<double> fillValues(nbComponents, fillValue);
// Checks if there are data holes on the beginning of the data and generates the hole at the
// extremity if it's the case
auto minXAxisData = xAxisData.front();
if (!std::isnan(minBound) && minBound < minXAxisData) {
auto holeSize = static_cast<int>((minXAxisData - minBound) / resolution);
if (holeSize > 0) {
xAxisData.insert(xAxisData.begin(), minXAxisData - holeSize * resolution);
valuesData.insert(valuesData.begin(), fillValues.begin(), fillValues.end());
}
}
// Same for the end of the data
auto maxXAxisData = xAxisData.back();
if (!std::isnan(maxBound) && maxBound > maxXAxisData) {
auto holeSize = static_cast<int>((maxBound - maxXAxisData) / resolution);
if (holeSize > 0) {
xAxisData.insert(xAxisData.end(), maxXAxisData + holeSize * resolution);
valuesData.insert(valuesData.end(), fillValues.begin(), fillValues.end());
}
}
// Generates other data holes
auto xAxisIt = xAxisData.begin();
while (xAxisIt != xAxisData.end()) {
// Stops at first value which has a gap greater than resolution with the value next to it
xAxisIt = std::adjacent_find(
xAxisIt, xAxisData.end(),
[resolution](const auto &a, const auto &b) { return (b - a) > resolution; });
if (xAxisIt != xAxisData.end()) {
auto nextXAxisIt = xAxisIt + 1;
// Gets the values that has a gap greater than resolution between them
auto lowValue = *xAxisIt;
auto highValue = *nextXAxisIt;
// Completes holes between the two values by creating new values (according to the
// resolution)
for (auto i = lowValue + resolution; i < highValue; i += resolution) {
// Gets the iterator of values data from which to insert fill values
auto nextValuesIt = valuesData.begin()
+ std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents;
// New value is inserted before nextXAxisIt
nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1;
// New values are inserted before nextValuesIt
valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end());
}
// Moves to the next value to continue loop on the x-axis data
xAxisIt = nextXAxisIt;
}
}
}