Git commit 7294844260c45b1363a89b786cd94248477f9938 by Stefan Gerlach.
Committed on 09/04/2016 at 19:31.
Pushed by sgerlach into branch 'analysis_interpolation'.

finished interpolation

1. use evaluation
2. check minimum number of points
3. fix bugs
4. documentation

M  +27   -4    doc/index.docbook
M  +9    -10   src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
M  +25   -14   src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
M  +0    -4    src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
M  +1    -1    src/kdefrontend/dockwidgets/AxisDock.cpp
M  +1    -1    src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
M  +1    -1    src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
M  +1    -1    src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
M  +75   -14   src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp

http://commits.kde.org/labplot/7294844260c45b1363a89b786cd94248477f9938

diff --git a/doc/index.docbook b/doc/index.docbook
index e771d00..7791153 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -51,7 +51,7 @@
 </copyright>
 
 <legalnotice>&FDLNotice;</legalnotice>
-<date>2016-04-03</date>
+<date>2016-04-09</date>
 <releaseinfo>3.1</releaseinfo>
 
 <abstract>
@@ -778,15 +778,38 @@ The menu is only available when a datapicker object is 
selected on the <guilabel
 
 <chapter id="analysis">
   <title>Analysis functions</title>
-  <para>&LabPlot; supports the data analysis functions nonlinear curve fitting 
and Fourier filter.
+  <para>&LabPlot; supports the data analysis functions interpolation, 
nonlinear curve fitting and Fourier filter.
     Both can be applied to any data consisting of x- and y-columns. 
     The analysis functions can be accessed using the Analysis menu or the 
context menu of a worksheet.</para>
   <para>The newly created curves can be customized (line style, symbol style, 
&etc;) like any x-y-curve.</para>  
+  <sect1 id="interpolation">
+    <title>Interpolation</title>
+    <para>
+      Interpolation of data can be done with several algorithm:
+    </para>
+      <itemizedlist>
+       <listitem><para>Linear</para></listitem>
+       <listitem><para>Polynomial</para></listitem>
+       <listitem><para>cubic spline</para></listitem>
+       <listitem><para>cubic spline (periodic)</para></listitem>
+       <listitem><para>Akima spline</para></listitem>
+       <listitem><para>Akima spline (periodic)</para></listitem>
+       <listitem><para>Steffen spline (needs GSL >= 2.0)</para></listitem>
+      </itemizedlist>
+    <para>
+       The interpolating function is calculated with the given number of data 
points an evaluated as:
+    </para>
+      <itemizedlist>
+       <listitem><para>function</para></listitem>
+       <listitem><para>derivative</para></listitem>
+       <listitem><para>second derivative</para></listitem>
+       <listitem><para>integral (starting from zero)</para></listitem>
+      </itemizedlist>
+  </sect1>
+
   <sect1 id="fitting">
     <title>Curve fitting</title>
     <para>
-      <!-- Linear and non-linear fits to data, several fit-models are 
predefined and custom models with 
-      arbitrary number of parameters can be provided -->
       Linear and non-linear curve fitting of data can be done with several 
predefined fit-models 
       (for instance polynomial, exponential, Gaussian or custom) to data 
consisting of x- and y-columns 
       with an optional weight column. With a custom model any function with 
unlimited number of parameters
diff --git a/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp 
b/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
index 733ae27..16b8dc7 100644
--- a/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
+++ b/src/backend/worksheet/plots/cartesian/XYFourierFilterCurve.cpp
@@ -38,11 +38,9 @@
 #include "backend/core/AbstractColumn.h"
 #include "backend/core/column/Column.h"
 #include "backend/lib/commandtemplates.h"
+
 #include <cmath>       // isnan
-/*#include "backend/gsl/ExpressionParser.h"
-#include "backend/gsl/parser_extern.h"
-*/
-//#include <gsl/gsl_version.h>
+#include <gsl_errno.h>
 #include <gsl/gsl_fft_real.h>
 #include <gsl/gsl_fft_halfcomplex.h>
 #include <gsl/gsl_sf_pow_int.h>
@@ -215,7 +213,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
                return;
        }
 
-       //copy all valid data point for the fit to temporary vectors
+       //copy all valid data point for the filter to temporary vectors
        QVector<double> xdataVector;
        QVector<double> ydataVector;
        for (int row=0; row<xDataColumn->rowCount(); ++row) {
@@ -228,7 +226,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
                }
        }
 
-       //number of data points to fit
+       //number of data points to filter
        unsigned int n = ydataVector.size();
        if (n == 0) {
                filterResult.available = true;
@@ -258,12 +256,13 @@ void XYFourierFilterCurvePrivate::recalculate() {
        qDebug()<<"unit :"<<unit<<unit2;
 #endif
 ///////////////////////////////////////////////////////////
+       int status;
        // 1. transform
        gsl_fft_real_workspace *work = gsl_fft_real_workspace_alloc (n);
        gsl_fft_real_wavetable *real = gsl_fft_real_wavetable_alloc (n);
 
-        gsl_fft_real_transform (ydata, 1, n, real, work);
-        gsl_fft_real_wavetable_free (real);
+        status = gsl_fft_real_transform(ydata, 1, n, real, work);
+        gsl_fft_real_wavetable_free(real);
 
        // calculate index
        double cutindex=0, cutindex2=0;
@@ -379,7 +378,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
 
        // 3. back transform
        gsl_fft_halfcomplex_wavetable *hc = gsl_fft_halfcomplex_wavetable_alloc 
(n);
-       gsl_fft_halfcomplex_inverse (ydata, 1, n, hc, work);
+       status = gsl_fft_halfcomplex_inverse(ydata, 1, n, hc, work);
        gsl_fft_halfcomplex_wavetable_free (hc);
        gsl_fft_real_workspace_free (work);
 
@@ -394,7 +393,7 @@ void XYFourierFilterCurvePrivate::recalculate() {
        //write the result
        filterResult.available = true;
        filterResult.valid = true;
-       filterResult.status = i18n("OK");
+       filterResult.status = QString(gsl_strerror(status));;
        filterResult.elapsedTime = timer.elapsed();
 
        //redraw the curve
diff --git a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp 
b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
index 406ce9a..e73ef82 100644
--- a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
+++ b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.cpp
@@ -38,10 +38,9 @@
 #include "backend/core/AbstractColumn.h"
 #include "backend/core/column/Column.h"
 #include "backend/lib/commandtemplates.h"
+
 #include <cmath>       // isnan
-/*#include "backend/gsl/ExpressionParser.h"
-#include "backend/gsl/parser_extern.h"
-*/
+#include <gsl_errno.h>
 #include <gsl/gsl_interp.h>
 #include <gsl/gsl_spline.h>
 
@@ -213,7 +212,7 @@ void XYInterpolationCurvePrivate::recalculate() {
                return;
        }
 
-       //copy all valid data point for the fit to temporary vectors
+       //copy all valid data point for the interpolation to temporary vectors
        QVector<double> xdataVector;
        QVector<double> ydataVector;
        for (int row=0; row<xDataColumn->rowCount(); ++row) {
@@ -228,10 +227,10 @@ void XYInterpolationCurvePrivate::recalculate() {
 
        //number of data points to fit
        unsigned int n = ydataVector.size();
-       if (n == 0) {
+       if (n < 2) {
                interpolationResult.available = true;
                interpolationResult.valid = false;
-               interpolationResult.status = i18n("No data points available.");
+               interpolationResult.status = i18n("Not enough data points 
available.");
                emit (q->dataChanged());
                sourceDataChangedSinceLastInterpolation = false;
                return;
@@ -253,9 +252,8 @@ void XYInterpolationCurvePrivate::recalculate() {
        qDebug()<<"npoints ="<<npoints;
 #endif
 ///////////////////////////////////////////////////////////
+       int status;
        //TODO: 
-       //      * check minimum number of points
-       //      * evaluate "evaluate"
        //      * check Steffen spline with GSL 2.X
 
        gsl_interp_accel *acc = gsl_interp_accel_alloc();
@@ -279,21 +277,34 @@ void XYInterpolationCurvePrivate::recalculate() {
        case XYInterpolationCurve::AkimaPeriodic:
                spline = gsl_spline_alloc(gsl_interp_akima_periodic, n);
                break;
-#if GSL_MAJOR_VERSION >= 2
        case XYInterpolationCurve::Steffen:
+#if GSL_MAJOR_VERSION >= 2
                spline = gsl_spline_alloc(gsl_interp_steffen, n);
-               break;
 #endif
+               break;
        }
 
-       gsl_spline_init (spline, xdata, ydata, n);
+       status = gsl_spline_init (spline, xdata, ydata, n);
 
        xVector->resize(npoints);
        yVector->resize(npoints);
-       for (int i = 0; i<npoints; i++) {
+       for (unsigned int i = 0; i<npoints; i++) {
                double x = min + i*(max-min)/(npoints-1);
                (*xVector)[i] = x;
-               (*yVector)[i] = gsl_spline_eval (spline, x, acc);
+               switch(evaluate) {
+               case XYInterpolationCurve::Function:
+                       (*yVector)[i] = gsl_spline_eval(spline, x, acc);
+                       break;
+               case XYInterpolationCurve::Derivative:
+                       (*yVector)[i] = gsl_spline_eval_deriv(spline, x, acc);
+                       break;
+               case XYInterpolationCurve::Derivative2:
+                       (*yVector)[i] = gsl_spline_eval_deriv2(spline, x, acc);
+                       break;
+               case XYInterpolationCurve::Integral:
+                       (*yVector)[i] = gsl_spline_eval_integ(spline, min, x, 
acc);
+                       break;
+               }
        }
 
        gsl_spline_free(spline);
@@ -304,7 +315,7 @@ void XYInterpolationCurvePrivate::recalculate() {
        //write the result
        interpolationResult.available = true;
        interpolationResult.valid = true;
-       interpolationResult.status = i18n("OK");
+       interpolationResult.status = QString(gsl_strerror(status));;
        interpolationResult.elapsedTime = timer.elapsed();
 
        //redraw the curve
diff --git a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h 
b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
index bc6c9e8..cf0339c 100644
--- a/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
+++ b/src/backend/worksheet/plots/cartesian/XYInterpolationCurve.h
@@ -37,11 +37,7 @@ class XYInterpolationCurve: public XYCurve {
        Q_OBJECT
 
        public:
-#if GSL_MAJOR_VERSION >= 2
                enum InterpolationType 
{Linear,Polynomial,CSpline,CSplinePeriodic,Akima,AkimaPeriodic,Steffen}; // 
TODO:more
-#else
-               enum InterpolationType 
{Linear,Polynomial,CSpline,CSplinePeriodic,Akima,AkimaPeriodic}; // TODO:more
-#endif
                enum InterpolationEval 
{Function,Derivative,Derivative2,Integral};
 
                struct InterpolationData {
diff --git a/src/kdefrontend/dockwidgets/AxisDock.cpp 
b/src/kdefrontend/dockwidgets/AxisDock.cpp
index 42ef646..95a5b1c 100644
--- a/src/kdefrontend/dockwidgets/AxisDock.cpp
+++ b/src/kdefrontend/dockwidgets/AxisDock.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
-    File                 : AxisDock.cc
+    File                 : AxisDock.cpp
     Project              : LabPlot
     Description          : axes widget class
     --------------------------------------------------------------------
diff --git a/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp 
b/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
index 314cc99..62e1f89 100644
--- a/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYEquationCurveDock.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
-    File             : XYEquationCurveDock.h
+    File             : XYEquationCurveDock.cpp
     Project          : LabPlot
     --------------------------------------------------------------------
     Copyright        : (C) 2014 Alexander Semke ([email protected])
diff --git a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp 
b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
index 9d1288d..a5d9445 100644
--- a/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYFitCurveDock.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
-    File             : XYFitCurveDock.h
+    File             : XYFitCurveDock.cpp
     Project          : LabPlot
     --------------------------------------------------------------------
     Copyright        : (C) 2014-2016 Alexander Semke ([email protected])
diff --git a/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp 
b/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
index 8b65d24..0a70b16 100644
--- a/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYFourierFilterCurveDock.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
-    File             : XYFourierFilterCurveDock.h
+    File             : XYFourierFilterCurveDock.cpp
     Project          : LabPlot
     --------------------------------------------------------------------
     Copyright        : (C) 2016 Stefan Gerlach ([email protected])
diff --git a/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp 
b/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
index 269393a..bb6a540 100644
--- a/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
+++ b/src/kdefrontend/dockwidgets/XYInterpolationCurveDock.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
-    File             : XYInterpolationCurveDock.h
+    File             : XYInterpolationCurveDock.cpp
     Project          : LabPlot
     --------------------------------------------------------------------
     Copyright        : (C) 2016 Stefan Gerlach ([email protected])
@@ -33,6 +33,9 @@
 #include "commonfrontend/widgets/TreeViewComboBox.h"
 #include <QMenu>
 #include <QWidgetAction>
+#include <QStandardItemModel>
+#include <gsl_interp.h>        // gsl_interp types
+#include <cmath>        // isnan
 #include <QDebug>
 
 /*!
@@ -102,7 +105,6 @@ void XYInterpolationCurveDock::setupGeneral() {
        connect( uiGeneralTab.cbEval, SIGNAL(currentIndexChanged(int)), this, 
SLOT(evaluateChanged(int)) );
        connect( uiGeneralTab.sbPoints, SIGNAL(valueChanged(int)), this, 
SLOT(numberOfPointsChanged(int)) );
 
-//     connect( uiGeneralTab.pbOptions, SIGNAL(clicked()), this, 
SLOT(showOptions()) );
        connect( uiGeneralTab.pbRecalculate, SIGNAL(clicked()), this, 
SLOT(recalculateClicked()) );
 }
 
@@ -131,6 +133,8 @@ void XYInterpolationCurveDock::initGeneralTab() {
        Q_ASSERT(m_interpolationCurve);
        XYCurveDock::setModelIndexFromColumn(cbXDataColumn, 
m_interpolationCurve->xDataColumn());
        XYCurveDock::setModelIndexFromColumn(cbYDataColumn, 
m_interpolationCurve->yDataColumn());
+       // update list of selectable types
+       xDataColumnChanged(cbXDataColumn->currentModelIndex());
 
        uiGeneralTab.cbType->setCurrentIndex(m_interpolationData.type);
        this->typeChanged(m_interpolationData.type);
@@ -162,11 +166,12 @@ void XYInterpolationCurveDock::setModel() {
        cbXDataColumn->setSelectableClasses(list);
        cbYDataColumn->setSelectableClasses(list);
 
+       connect( cbXDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), 
this, SLOT(xDataColumnChanged(QModelIndex)) );
+       connect( cbYDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), 
this, SLOT(yDataColumnChanged(QModelIndex)) );
+
        cbXDataColumn->setModel(m_aspectTreeModel);
        cbYDataColumn->setModel(m_aspectTreeModel);
 
-       connect( cbXDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), 
this, SLOT(xDataColumnChanged(QModelIndex)) );
-       connect( cbYDataColumn, SIGNAL(currentModelIndexChanged(QModelIndex)), 
this, SLOT(yDataColumnChanged(QModelIndex)) );
        XYCurveDock::setModel();
 }
 
@@ -205,9 +210,6 @@ void XYInterpolationCurveDock::commentChanged(){
 }
 
 void XYInterpolationCurveDock::xDataColumnChanged(const QModelIndex& index) {
-       if (m_initializing)
-               return;
-
        AbstractAspect* aspect = 
static_cast<AbstractAspect*>(index.internalPointer());
        AbstractColumn* column = 0;
        if (aspect) {
@@ -218,9 +220,70 @@ void XYInterpolationCurveDock::xDataColumnChanged(const 
QModelIndex& index) {
        foreach(XYCurve* curve, m_curvesList)
                
dynamic_cast<XYInterpolationCurve*>(curve)->setXDataColumn(column);
 
-       // update range of cutoff spin boxes (like a unit change)
-//     unitChanged(uiGeneralTab.cbUnit->currentIndex());
-//     unit2Changed(uiGeneralTab.cbUnit2->currentIndex());
+       // disable types that need more data points
+       if(column != 0) {
+               unsigned int n=0;
+               for(int row=0;row < column->rowCount();row++)
+                       if (!isnan(column->valueAt(row)) && 
!column->isMasked(row)) 
+                               n++;
+
+               const QStandardItemModel* model = qobject_cast<const 
QStandardItemModel*>(uiGeneralTab.cbType->model());
+               QStandardItem* item = 
model->item(XYInterpolationCurve::Polynomial);
+               if(n < gsl_interp_type_min_size(gsl_interp_polynomial)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::Polynomial)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+               item = model->item(XYInterpolationCurve::CSpline);
+               if(n < gsl_interp_type_min_size(gsl_interp_cspline)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::CSpline)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+               item = model->item(XYInterpolationCurve::CSplinePeriodic);
+               if(n < gsl_interp_type_min_size(gsl_interp_cspline_periodic)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::CSplinePeriodic)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+               item = model->item(XYInterpolationCurve::Akima);
+               if(n < gsl_interp_type_min_size(gsl_interp_akima)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::Akima)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+               item = model->item(XYInterpolationCurve::AkimaPeriodic);
+               if(n < gsl_interp_type_min_size(gsl_interp_akima_periodic)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::AkimaPeriodic)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+
+#if GSL_MAJOR_VERSION >= 2
+               item = model->item(XYInterpolationCurve::Steffen);
+               if(n < gsl_interp_type_min_size(gsl_interp_steffen)) {
+                       item->setFlags(item->flags() & 
~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
+                       if(uiGeneralTab.cbType->currentIndex() == 
XYInterpolationCurve::Steffen)
+                               uiGeneralTab.cbType->setCurrentIndex(0);
+               }
+               else
+                       item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+#endif
+       }
 }
 
 void XYInterpolationCurveDock::yDataColumnChanged(const QModelIndex& index) {
@@ -239,16 +302,14 @@ void XYInterpolationCurveDock::yDataColumnChanged(const 
QModelIndex& index) {
 }
 
 void XYInterpolationCurveDock::typeChanged(int index) {
-       XYInterpolationCurve::InterpolationType type = 
(XYInterpolationCurve::InterpolationType)index;
+       //XYInterpolationCurve::InterpolationType type = 
(XYInterpolationCurve::InterpolationType)index;
        m_interpolationData.type = 
(XYInterpolationCurve::InterpolationType)uiGeneralTab.cbType->currentIndex();
 
-       //TODO
-
        uiGeneralTab.pbRecalculate->setEnabled(true);
 }
 
 void XYInterpolationCurveDock::evaluateChanged(int index) {
-       XYInterpolationCurve::InterpolationEval eval = 
(XYInterpolationCurve::InterpolationEval)index;
+       //XYInterpolationCurve::InterpolationEval eval = 
(XYInterpolationCurve::InterpolationEval)index;
        m_interpolationData.evaluate = 
(XYInterpolationCurve::InterpolationEval)uiGeneralTab.cbEval->currentIndex();
 
        uiGeneralTab.pbRecalculate->setEnabled(true);
_______________________________________________
kde-doc-english mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kde-doc-english

Reply via email to