Commit 0b274be2 authored by Stefan Gerlach's avatar Stefan Gerlach

[backend] Improve Range class

parent 4de64b34
...@@ -40,40 +40,40 @@ ...@@ -40,40 +40,40 @@
template<class T> template<class T>
class Range { class Range {
public: public:
Range() : m_left(0), m_right(0) {} Range() : m_min(0), m_max(0) {}
Range(T left, T right) { Range(T min, T max) {
this->setRange(left, right); this->setRange(min, max);
} }
~Range() = default; ~Range() = default;
T left() const { return m_left; } T min() const { return m_min; }
T right() const { return m_right; } T max() const { return m_max; }
void setLeft(T left) { m_left = left; } // no check (use first) void setMin(T min) { m_min = min; } // no check (use first)
void setRight(T right) { m_right = std::max(m_left, right); } void setMax(T max) { m_max = std::max(m_min, max); }
void setRange(T left, T right) { void setRange(T min, T max) {
m_left = left; m_min = min;
m_right = std::max(left, right); m_max = std::max(min, max);
} }
T size() const { return m_right - m_left; } T size() const { return m_max - m_min; }
bool isZero() const { return (m_right == m_left); } bool isZero() const { return (m_max == m_min); }
bool inside(const Range<T>& other) const { return ( m_left <= other.left() && m_right >= other.right() ); } bool inside(const Range<T>& other) const { return ( m_min <= other.min() && m_max >= other.max() ); }
bool inside(T value) const { return ( m_left <= value && m_right >= value ); } bool inside(T value) const { return ( m_min <= value && m_max >= value ); }
void translate(T offset) { m_left += offset; m_right += offset; } void translate(T offset) { m_min += offset; m_max += offset; }
bool operator==(const Range<T>& other) const { return ( m_left == other.left() && m_right == other.right() ); } bool operator==(const Range<T>& other) const { return ( m_min == other.min() && m_max == other.max() ); }
Range<T>& operator=(const Range<T>& other) { Range<T>& operator=(const Range<T>& other) {
m_left = other.left(); m_min = other.min();
m_right = other.right(); m_max = other.max();
return *this; return *this;
} }
//! Return a string in the format '[left, right]' //! Return a string in the format '[min, max]'
QString toString() const { QString toString() const {
return "[" + QString::number(m_left) + ", " + QString::number(m_right) + "]"; return "[" + QString::number(m_min) + ", " + QString::number(m_max) + "]";
} }
//TODO: touches(), merge(), subtract(), split(), etc. (see Interval) //TODO: touches(), merge(), subtract(), split(), etc. (see Interval)
private: private:
T m_left; // lower limit T m_min; // lower limit
T m_right; // upper limit T m_max; // upper limit
}; };
#endif #endif
......
...@@ -1613,15 +1613,12 @@ void XYFitCurvePrivate::recalculate() { ...@@ -1613,15 +1613,12 @@ void XYFitCurvePrivate::recalculate() {
QVector<double> ydataVector; QVector<double> ydataVector;
QVector<double> xerrorVector; QVector<double> xerrorVector;
QVector<double> yerrorVector; QVector<double> yerrorVector;
double xmin, xmax; Range<double> xRange{tmpXDataColumn->minimum(), tmpXDataColumn->maximum()};
if (fitData.autoRange) { if (!fitData.autoRange) {
xmin = tmpXDataColumn->minimum(); if (!fitData.fitRange.isZero()) // avoid zero range
xmax = tmpXDataColumn->maximum(); xRange.setRange(fitData.fitRange.min(), fitData.fitRange.max());
} else {
xmin = fitData.fitRange.left();
xmax = fitData.fitRange.right();
} }
DEBUG(" fit range = " << xmin << " .. " << xmax); DEBUG(" fit range = " << xRange.min() << " .. " << xRange.max());
//logic from XYAnalysisCurve::copyData(), extended by the handling of error columns. //logic from XYAnalysisCurve::copyData(), extended by the handling of error columns.
//TODO: decide how to deal with non-numerical error columns //TODO: decide how to deal with non-numerical error columns
...@@ -1670,8 +1667,7 @@ void XYFitCurvePrivate::recalculate() { ...@@ -1670,8 +1667,7 @@ void XYFitCurvePrivate::recalculate() {
y = tmpYDataColumn->dateTimeAt(row).toMSecsSinceEpoch(); y = tmpYDataColumn->dateTimeAt(row).toMSecsSinceEpoch();
} }
// only when inside given range if (x >= xRange.min() && x <= xRange.max()) { // only when inside given range
if (x >= xmin && x <= xmax) {
if ((!xErrorColumn && !yErrorColumn) || !fitData.useDataErrors) { // x-y if ((!xErrorColumn && !yErrorColumn) || !fitData.useDataErrors) { // x-y
xdataVector.append(x); xdataVector.append(x);
ydataVector.append(y); ydataVector.append(y);
...@@ -2058,7 +2054,7 @@ void XYFitCurvePrivate::recalculate() { ...@@ -2058,7 +2054,7 @@ void XYFitCurvePrivate::recalculate() {
} else { // only selected range } else { // only selected range
size_t j = 0; size_t j = 0;
for (int i = 0; i < tmpXDataColumn->rowCount(); i++) { for (int i = 0; i < tmpXDataColumn->rowCount(); i++) {
if (tmpXDataColumn->valueAt(i) >= xmin && tmpXDataColumn->valueAt(i) <= xmax) if (tmpXDataColumn->valueAt(i) >= xRange.min() && tmpXDataColumn->valueAt(i) <= xRange.max())
residualsVector->data()[i] = - gsl_vector_get(s->f, j++); residualsVector->data()[i] = - gsl_vector_get(s->f, j++);
else // outside range else // outside range
residualsVector->data()[i] = 0; residualsVector->data()[i] = 0;
...@@ -2134,7 +2130,7 @@ void XYFitCurvePrivate::evaluate(bool preview) { ...@@ -2134,7 +2130,7 @@ void XYFitCurvePrivate::evaluate(bool preview) {
if (preview) // results not available yet if (preview) // results not available yet
paramValues = fitData.paramStartValues; paramValues = fitData.paramStartValues;
bool rc = parser->evaluateCartesian(fitData.model, QString::number(xRange.left()), QString::number(xRange.right()), (int)fitData.evaluatedPoints, bool rc = parser->evaluateCartesian(fitData.model, QString::number(xRange.min()), QString::number(xRange.max()), (int)fitData.evaluatedPoints,
xVector, yVector, fitData.paramNames, paramValues); xVector, yVector, fitData.paramNames, paramValues);
if (!rc) { if (!rc) {
DEBUG(" ERROR: Parsing fit function failed") DEBUG(" ERROR: Parsing fit function failed")
...@@ -2191,8 +2187,8 @@ void XYFitCurve::save(QXmlStreamWriter* writer) const { ...@@ -2191,8 +2187,8 @@ void XYFitCurve::save(QXmlStreamWriter* writer) const {
WRITE_COLUMN(d->xErrorColumn, xErrorColumn); WRITE_COLUMN(d->xErrorColumn, xErrorColumn);
WRITE_COLUMN(d->yErrorColumn, yErrorColumn); WRITE_COLUMN(d->yErrorColumn, yErrorColumn);
writer->writeAttribute("autoRange", QString::number(d->fitData.autoRange)); writer->writeAttribute("autoRange", QString::number(d->fitData.autoRange));
writer->writeAttribute("fitRangeMin", QString::number(d->fitData.fitRange.left(), 'g', 15)); writer->writeAttribute("fitRangeMin", QString::number(d->fitData.fitRange.min(), 'g', 15));
writer->writeAttribute("fitRangeMax", QString::number(d->fitData.fitRange.right(), 'g', 15)); writer->writeAttribute("fitRangeMax", QString::number(d->fitData.fitRange.max(), 'g', 15));
writer->writeAttribute("modelCategory", QString::number(d->fitData.modelCategory)); writer->writeAttribute("modelCategory", QString::number(d->fitData.modelCategory));
writer->writeAttribute("modelType", QString::number(d->fitData.modelType)); writer->writeAttribute("modelType", QString::number(d->fitData.modelType));
writer->writeAttribute("xWeightsType", QString::number(d->fitData.xWeightsType)); writer->writeAttribute("xWeightsType", QString::number(d->fitData.xWeightsType));
......
...@@ -1013,8 +1013,8 @@ void XYFitCurveDock::setPlotXRange() { ...@@ -1013,8 +1013,8 @@ void XYFitCurveDock::setPlotXRange() {
const Range<double> range = m_fitData.evalRange; const Range<double> range = m_fitData.evalRange;
const double extend = range.size() * 0.05; // + 5 % const double extend = range.size() * 0.05; // + 5 %
if (!range.isZero()) { if (!range.isZero()) {
plot->setXMin(range.left() - extend); plot->setXMin(range.min() - extend);
plot->setXMax(range.right() + extend); plot->setXMax(range.max() + extend);
} }
} }
} }
......
...@@ -59,15 +59,15 @@ FitOptionsWidget::FitOptionsWidget(QWidget* parent, XYFitCurve::FitData* fitData ...@@ -59,15 +59,15 @@ FitOptionsWidget::FitOptionsWidget(QWidget* parent, XYFitCurve::FitData* fitData
const auto* plot = static_cast<const CartesianPlot*>(fitCurve->parentAspect()); const auto* plot = static_cast<const CartesianPlot*>(fitCurve->parentAspect());
m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric); m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric);
if (!m_dateTimeRange) { if (!m_dateTimeRange) {
ui.leMin->setText(QString::number(m_fitData->fitRange.left())); ui.leMin->setText(QString::number(m_fitData->fitRange.min()));
ui.leMax->setText(QString::number(m_fitData->fitRange.right())); ui.leMax->setText(QString::number(m_fitData->fitRange.max()));
ui.leEvalMin->setText(QString::number(m_fitData->evalRange.left())); ui.leEvalMin->setText(QString::number(m_fitData->evalRange.min()));
ui.leEvalMax->setText(QString::number(m_fitData->evalRange.right())); ui.leEvalMax->setText(QString::number(m_fitData->evalRange.max()));
} else { } else {
ui.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.left()) ); ui.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.min()) );
ui.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.right()) ); ui.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.max()) );
ui.dateTimeEditEvalMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.left()) ); ui.dateTimeEditEvalMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.min()) );
ui.dateTimeEditEvalMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.right()) ); ui.dateTimeEditEvalMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.max()) );
} }
ui.leMin->setVisible(!m_dateTimeRange); ui.leMin->setVisible(!m_dateTimeRange);
...@@ -191,52 +191,52 @@ void FitOptionsWidget::autoEvalRangeChanged() { ...@@ -191,52 +191,52 @@ void FitOptionsWidget::autoEvalRangeChanged() {
void FitOptionsWidget::fitRangeMinChanged() { void FitOptionsWidget::fitRangeMinChanged() {
const double xMin = ui.leMin->text().toDouble(); const double xMin = ui.leMin->text().toDouble();
m_fitData->fitRange.setLeft(xMin); m_fitData->fitRange.setMin(xMin);
changed(); changed();
} }
void FitOptionsWidget::fitRangeMaxChanged() { void FitOptionsWidget::fitRangeMaxChanged() {
const double xMax = ui.leMax->text().toDouble(); const double xMax = ui.leMax->text().toDouble();
m_fitData->fitRange.setRight(xMax); m_fitData->fitRange.setMax(xMax);
changed(); changed();
} }
void FitOptionsWidget::fitRangeMinDateTimeChanged(const QDateTime& dateTime) { void FitOptionsWidget::fitRangeMinDateTimeChanged(const QDateTime& dateTime) {
m_fitData->fitRange.setLeft(dateTime.toMSecsSinceEpoch()); m_fitData->fitRange.setMin(dateTime.toMSecsSinceEpoch());
changed(); changed();
} }
void FitOptionsWidget::fitRangeMaxDateTimeChanged(const QDateTime& dateTime) { void FitOptionsWidget::fitRangeMaxDateTimeChanged(const QDateTime& dateTime) {
m_fitData->fitRange.setRight(dateTime.toMSecsSinceEpoch()); m_fitData->fitRange.setMax(dateTime.toMSecsSinceEpoch());
changed(); changed();
} }
void FitOptionsWidget::evalRangeMinChanged() { void FitOptionsWidget::evalRangeMinChanged() {
const double xMin = ui.leEvalMin->text().toDouble(); const double xMin = ui.leEvalMin->text().toDouble();
m_fitData->evalRange.setLeft(xMin); m_fitData->evalRange.setMin(xMin);
changed(); changed();
} }
void FitOptionsWidget::evalRangeMaxChanged() { void FitOptionsWidget::evalRangeMaxChanged() {
const double xMax = ui.leEvalMax->text().toDouble(); const double xMax = ui.leEvalMax->text().toDouble();
m_fitData->evalRange.setRight(xMax); m_fitData->evalRange.setMax(xMax);
changed(); changed();
} }
void FitOptionsWidget::evalRangeMinDateTimeChanged(const QDateTime& dateTime) { void FitOptionsWidget::evalRangeMinDateTimeChanged(const QDateTime& dateTime) {
m_fitData->evalRange.setLeft(dateTime.toMSecsSinceEpoch()); m_fitData->evalRange.setMin(dateTime.toMSecsSinceEpoch());
changed(); changed();
} }
void FitOptionsWidget::evalRangeMaxDateTimeChanged(const QDateTime& dateTime) { void FitOptionsWidget::evalRangeMaxDateTimeChanged(const QDateTime& dateTime) {
m_fitData->evalRange.setRight(dateTime.toMSecsSinceEpoch()); m_fitData->evalRange.setMax(dateTime.toMSecsSinceEpoch());
changed(); changed();
} }
void FitOptionsWidget::applyClicked() { void FitOptionsWidget::applyClicked() {
m_fitData->maxIterations = ui.leMaxIterations->text().toFloat(); m_fitData->maxIterations = ui.leMaxIterations->text().toFloat(); //TODO: float?
m_fitData->eps = ui.leEps->text().toFloat(); m_fitData->eps = ui.leEps->text().toFloat(); // TODO: float?
m_fitData->evaluatedPoints = ui.leEvaluatedPoints->text().toInt(); m_fitData->evaluatedPoints = ui.leEvaluatedPoints->text().toInt();
m_fitData->useDataErrors = ui.cbUseDataErrors->isChecked(); m_fitData->useDataErrors = ui.cbUseDataErrors->isChecked();
m_fitData->useResults = ui.cbUseResults->isChecked(); m_fitData->useResults = ui.cbUseResults->isChecked();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment