Commit 4c0119f2 authored by Stefan Gerlach's avatar Stefan Gerlach

Add Range class and use in fit

parent 7151383b
......@@ -446,6 +446,13 @@ if (str.isEmpty()) \
else \
d->var = str.toDouble();
#define READ_DOUBLE_VALUE_LOCAL(name, var) \
str = attribs.value(name).toString(); \
if (str.isEmpty()) \
reader->raiseWarning(attributeWarning.subs(name).toString()); \
else \
var = str.toDouble();
#define READ_STRING_VALUE(name, var) \
str = attribs.value(name).toString(); \
if (str.isEmpty()) \
......
......@@ -1618,8 +1618,8 @@ void XYFitCurvePrivate::recalculate() {
xmin = tmpXDataColumn->minimum();
xmax = tmpXDataColumn->maximum();
} else {
xmin = fitData.fitRange.first();
xmax = fitData.fitRange.last();
xmin = fitData.fitRange.left();
xmax = fitData.fitRange.right();
}
DEBUG(" fit range = " << xmin << " .. " << xmax);
......@@ -2120,14 +2120,12 @@ void XYFitCurvePrivate::evaluate(bool preview) {
}
ExpressionParser* parser = ExpressionParser::getInstance();
double xmin{tmpXDataColumn->minimum()}, xmax{tmpXDataColumn->maximum()}; // full data range
Range<double> xRange{tmpXDataColumn->minimum(), tmpXDataColumn->maximum()}; // full data range
if (!fitData.autoEvalRange) { // use given range for evaluation
if (fitData.evalRange.last() != fitData.evalRange.first()) { // avoid zero range
xmin = fitData.evalRange.first();
xmax = fitData.evalRange.last();
}
if (!fitData.evalRange.isZero()) // avoid zero range
xRange = fitData.evalRange;
}
DEBUG(" eval range = " << xmin << " .. " << xmax);
DEBUG(" eval range = " << STDSTRING(xRange.toString()));
xVector->resize((int)fitData.evaluatedPoints);
yVector->resize((int)fitData.evaluatedPoints);
DEBUG(" vector size = " << xVector->size());
......@@ -2136,7 +2134,7 @@ void XYFitCurvePrivate::evaluate(bool preview) {
if (preview) // results not available yet
paramValues = fitData.paramStartValues;
bool rc = parser->evaluateCartesian(fitData.model, QString::number(xmin), QString::number(xmax), (int)fitData.evaluatedPoints,
bool rc = parser->evaluateCartesian(fitData.model, QString::number(xRange.left()), QString::number(xRange.right()), (int)fitData.evaluatedPoints,
xVector, yVector, fitData.paramNames, paramValues);
if (!rc) {
DEBUG(" ERROR: Parsing fit function failed")
......@@ -2193,8 +2191,8 @@ void XYFitCurve::save(QXmlStreamWriter* writer) const {
WRITE_COLUMN(d->xErrorColumn, xErrorColumn);
WRITE_COLUMN(d->yErrorColumn, yErrorColumn);
writer->writeAttribute("autoRange", QString::number(d->fitData.autoRange));
writer->writeAttribute("fitRangeMin", QString::number(d->fitData.fitRange.first(), 'g', 15));
writer->writeAttribute("fitRangeMax", QString::number(d->fitData.fitRange.last(), 'g', 15));
writer->writeAttribute("fitRangeMin", QString::number(d->fitData.fitRange.left(), 'g', 15));
writer->writeAttribute("fitRangeMax", QString::number(d->fitData.fitRange.right(), 'g', 15));
writer->writeAttribute("modelCategory", QString::number(d->fitData.modelCategory));
writer->writeAttribute("modelType", QString::number(d->fitData.modelType));
writer->writeAttribute("xWeightsType", QString::number(d->fitData.xWeightsType));
......@@ -2329,10 +2327,12 @@ bool XYFitCurve::load(XmlStreamReader* reader, bool preview) {
READ_COLUMN(yErrorColumn);
READ_INT_VALUE("autoRange", fitData.autoRange, bool);
READ_DOUBLE_VALUE("xRangeMin", fitData.fitRange.first()); // old name
READ_DOUBLE_VALUE("xRangeMax", fitData.fitRange.last()); // old name
READ_DOUBLE_VALUE("fitRangeMin", fitData.fitRange.first());
READ_DOUBLE_VALUE("fitRangeMax", fitData.fitRange.last());
double left{0}, right{0};
READ_DOUBLE_VALUE_LOCAL("xRangeMin", left); // old name
READ_DOUBLE_VALUE_LOCAL("xRangeMax", right); // old name
READ_DOUBLE_VALUE_LOCAL("fitRangeMin", left);
READ_DOUBLE_VALUE_LOCAL("fitRangeMax", right);
d->fitData.fitRange.setRange(left, right);
READ_INT_VALUE("modelCategory", fitData.modelCategory, nsl_fit_model_category);
READ_INT_VALUE("modelType", fitData.modelType, int);
READ_INT_VALUE("xWeightsType", fitData.xWeightsType, nsl_fit_weight_type);
......
......@@ -30,6 +30,7 @@
#ifndef XYFITCURVE_H
#define XYFITCURVE_H
#include "backend/lib/Range.h"
#include "backend/worksheet/plots/cartesian/XYAnalysisCurve.h"
#include "kdefrontend/spreadsheet/PlotDataDialog.h" //for PlotDataDialog::AnalysisAction. TODO: find a better place for this enum.
......@@ -69,9 +70,8 @@ public:
bool autoRange{true}; // use all data points? (default)
bool autoEvalRange{true}; // evaluate fit function on full data range (default)
//TODO: QPoint?
QVector<double> fitRange{0., 0.}; // x fit range
QVector<double> evalRange{0., 0.}; // x evaluation range
Range<double> fitRange{0., 0.}; // x fit range
Range<double> evalRange{0., 0.}; // x evaluation range
};
struct FitResult {
......
......@@ -1010,12 +1010,11 @@ void XYFitCurveDock::setPlotXRange() {
auto* plot = dynamic_cast<CartesianPlot*>(m_curve->parentAspect());
if (plot != nullptr) {
double rmin = m_fitData.evalRange.first();
double rmax = m_fitData.evalRange.last();
double extend = (rmax-rmin) * 0.05; // +/- 5 percent of range. may be < 0
if (extend != 0.) { // avoid zero range
plot->setXMin(rmin - extend);
plot->setXMax(rmax + extend);
const Range<double> range = m_fitData.evalRange;
const double extend = range.size() * 0.05; // + 5 %
if (!range.isZero()) {
plot->setXMin(range.left() - extend);
plot->setXMax(range.right() + extend);
}
}
}
......@@ -1237,7 +1236,7 @@ void XYFitCurveDock::showFitResult() {
uiGeneralTab.twLog->item(4, 1)->setText(QString::number(fitResult.dof));
uiGeneralTab.twLog->item(5, 1)->setText(QString::number(fitResult.paramValues.size()));
uiGeneralTab.twLog->item(6, 1)->setText(QString::number(m_fitData.fitRange.first()) + " .. " + QString::number(m_fitData.fitRange.last()) );
uiGeneralTab.twLog->item(6, 1)->setText(m_fitData.fitRange.toString());
// show all iterations
QString str;
......
......@@ -59,15 +59,15 @@ FitOptionsWidget::FitOptionsWidget(QWidget* parent, XYFitCurve::FitData* fitData
const auto* plot = static_cast<const CartesianPlot*>(fitCurve->parentAspect());
m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric);
if (!m_dateTimeRange) {
ui.leMin->setText(QString::number(m_fitData->fitRange.first()));
ui.leMax->setText(QString::number(m_fitData->fitRange.last()));
ui.leEvalMin->setText(QString::number(m_fitData->evalRange.first()));
ui.leEvalMax->setText(QString::number(m_fitData->evalRange.last()));
ui.leMin->setText(QString::number(m_fitData->fitRange.left()));
ui.leMax->setText(QString::number(m_fitData->fitRange.right()));
ui.leEvalMin->setText(QString::number(m_fitData->evalRange.left()));
ui.leEvalMax->setText(QString::number(m_fitData->evalRange.right()));
} else {
ui.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.first()) );
ui.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.last()) );
ui.dateTimeEditEvalMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.first()) );
ui.dateTimeEditEvalMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.last()) );
ui.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.left()) );
ui.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->fitRange.right()) );
ui.dateTimeEditEvalMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.left()) );
ui.dateTimeEditEvalMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_fitData->evalRange.right()) );
}
ui.leMin->setVisible(!m_dateTimeRange);
......@@ -139,8 +139,7 @@ void FitOptionsWidget::autoRangeChanged() {
if (xDataColumn) {
const double xMin = xDataColumn->minimum();
const double xMax = xDataColumn->maximum();
m_fitData->fitRange.last() = xMax;
m_fitData->fitRange.first() = xMin;
m_fitData->fitRange.setRange(xMin, xMax);
if (!m_dateTimeRange) {
ui.leMin->setText(QString::number(xMin));
......@@ -176,8 +175,7 @@ void FitOptionsWidget::autoEvalRangeChanged() {
if (xDataColumn) {
const double xMin = xDataColumn->minimum();
const double xMax = xDataColumn->maximum();
m_fitData->evalRange.last() = xMax;
m_fitData->evalRange.first() = xMin;
m_fitData->evalRange.setRange(xMin, xMax);
if (!m_dateTimeRange) {
ui.leEvalMin->setText(QString::number(xMin));
......@@ -193,46 +191,46 @@ void FitOptionsWidget::autoEvalRangeChanged() {
void FitOptionsWidget::fitRangeMinChanged() {
const double xMin = ui.leMin->text().toDouble();
m_fitData->fitRange.first() = xMin;
m_fitData->fitRange.setLeft(xMin);
changed();
}
void FitOptionsWidget::fitRangeMaxChanged() {
const double xMax = ui.leMax->text().toDouble();
m_fitData->fitRange.last() = xMax;
m_fitData->fitRange.setRight(xMax);
changed();
}
void FitOptionsWidget::fitRangeMinDateTimeChanged(const QDateTime& dateTime) {
m_fitData->fitRange.first() = dateTime.toMSecsSinceEpoch();
m_fitData->fitRange.setLeft(dateTime.toMSecsSinceEpoch());
changed();
}
void FitOptionsWidget::fitRangeMaxDateTimeChanged(const QDateTime& dateTime) {
m_fitData->fitRange.last() = dateTime.toMSecsSinceEpoch();
m_fitData->fitRange.setRight(dateTime.toMSecsSinceEpoch());
changed();
}
void FitOptionsWidget::evalRangeMinChanged() {
const double xMin = ui.leEvalMin->text().toDouble();
m_fitData->evalRange.first() = xMin;
m_fitData->evalRange.setLeft(xMin);
changed();
}
void FitOptionsWidget::evalRangeMaxChanged() {
const double xMax = ui.leEvalMax->text().toDouble();
m_fitData->evalRange.last() = xMax;
m_fitData->evalRange.setRight(xMax);
changed();
}
void FitOptionsWidget::evalRangeMinDateTimeChanged(const QDateTime& dateTime) {
m_fitData->evalRange.first() = dateTime.toMSecsSinceEpoch();
m_fitData->evalRange.setLeft(dateTime.toMSecsSinceEpoch());
changed();
}
void FitOptionsWidget::evalRangeMaxDateTimeChanged(const QDateTime& dateTime) {
m_fitData->evalRange.last() = dateTime.toMSecsSinceEpoch();
m_fitData->evalRange.setRight(dateTime.toMSecsSinceEpoch());
changed();
}
......
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