82 changes: 82 additions & 0 deletions src/plugins/filters/movingaverage/movingaverage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***************************************************************************
* *
* copyright : (C) 2019 Jonathan Liu *
* net147@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef MOVINGAVERAGEPLUGIN_H
#define MOVINGAVERAGEPLUGIN_H

#include <QFile>

#include <basicplugin.h>
#include <dataobjectplugin.h>

class MovingAverageSource : public Kst::BasicPlugin {
Q_OBJECT

public:
virtual QString _automaticDescriptiveName() const;

virtual QString descriptionTip() const;

Kst::VectorPtr vector() const;
Kst::ScalarPtr scalarSamples() const;

virtual void change(Kst::DataObjectConfigWidget *configWidget);

void setupOutputs();
virtual bool algorithm();

virtual QStringList inputVectorList() const;
virtual QStringList inputScalarList() const;
virtual QStringList inputStringList() const;
virtual QStringList outputVectorList() const;
virtual QStringList outputScalarList() const;
virtual QStringList outputStringList() const;

virtual void setProperty(const QString &key, const QString &val);

virtual void saveProperties(QXmlStreamWriter &s);

bool weighted() const { return _weighted; }
void setWeighted(bool value) { _weighted = value; }

protected:
MovingAverageSource(Kst::ObjectStore *store);
~MovingAverageSource();
bool _weighted;

friend class Kst::ObjectStore;


};


class MovingAveragePlugin : public QObject, public Kst::DataObjectPluginInterface {
Q_OBJECT
Q_INTERFACES(Kst::DataObjectPluginInterface)
Q_PLUGIN_METADATA(IID "com.kst.DataObjectPluginInterface/2.0")
public:
virtual ~MovingAveragePlugin() {}

virtual QString pluginName() const;
virtual QString pluginDescription() const;

virtual DataObjectPluginInterface::PluginTypeID pluginType() const { return Filter; }

virtual bool hasConfigWidget() const { return true; }

virtual Kst::DataObject *create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs = true) const;

virtual Kst::DataObjectConfigWidget *configWidget(QSettings *settingsObject) const;
};

#endif
// vim: ts=2 sw=2 et
11 changes: 11 additions & 0 deletions src/plugins/filters/movingaverage/movingaverage.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include(../../plugins_sub.pri)

TARGET = $$kstlib(kstplugin_movingaverage)

SOURCES += \
movingaverage.cpp

HEADERS += \
movingaverage.h

FORMS += movingaverageconfig.ui
92 changes: 92 additions & 0 deletions src/plugins/filters/movingaverage/movingaverageconfig.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MovingAverageConfig</class>
<widget class="QWidget" name="MovingAverageConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>425</width>
<height>55</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,1,0">
<item row="1" column="1">
<widget class="Kst::ScalarSelector" name="_scalarSamples" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Samples: </string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Y: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="_weighted">
<property name="text">
<string>Weighted</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="Kst::VectorSelector" name="_vector" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Kst::VectorSelector</class>
<extends>QWidget</extends>
<header>vectorselector.h</header>
</customwidget>
<customwidget>
<class>Kst::ScalarSelector</class>
<extends>QWidget</extends>
<header>scalarselector.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
10 changes: 10 additions & 0 deletions src/plugins/filters/movingmedian/kstplugin_movingmedian.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Desktop Entry]
Type=Service
ServiceTypes=Kst Data Object
X-KDE-ModuleType=Plugin
X-KDE-Library=movingmedian
X-Kst-Plugin-Author=Jonathan Liu
Name=Moving Median Data Object Plugin
Name[en_GB]=Moving Median Data Object Plugin
Comment=Implements a Moving Median Data Object Plugin for Kst.
Comment[en_GB]=Implements a Moving Median Data Object Plugin for Kst.
284 changes: 284 additions & 0 deletions src/plugins/filters/movingmedian/movingmedian.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/***************************************************************************
* *
* copyright : (C) 2019 Jonathan Liu *
* net147@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/


#include "movingmedian.h"
#include "objectstore.h"
#include "ui_movingmedianconfig.h"
#include <algorithm>

static const QString& VECTOR_IN = "Y Vector";
static const QString& SCALAR_IN = "Samples Scalar";
static const QString& VECTOR_OUT = "Y";

class ConfigMovingMedianPlugin : public Kst::DataObjectConfigWidget, public Ui_MovingMedianConfig {
public:
ConfigMovingMedianPlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_MovingMedianConfig() {
_store = 0;
setupUi(this);
}

~ConfigMovingMedianPlugin() {}

void setObjectStore(Kst::ObjectStore* store) {
_store = store;
_vector->setObjectStore(store);
_scalarSamples->setObjectStore(store);
}

void setupSlots(QWidget* dialog) {
if (dialog) {
connect(_vector, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
connect(_scalarSamples, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
}
}

void setVectorX(Kst::VectorPtr vector) {
setSelectedVector(vector);
}

void setVectorY(Kst::VectorPtr vector) {
setSelectedVector(vector);
}

void setVectorsLocked(bool locked = true) {
_vector->setEnabled(!locked);
}

Kst::VectorPtr selectedVector() { return _vector->selectedVector(); }
void setSelectedVector(Kst::VectorPtr vector) { return _vector->setSelectedVector(vector); }

Kst::ScalarPtr selectedScalar() { return _scalarSamples->selectedScalar(); }
void setSelectedScalar(Kst::ScalarPtr scalar) { return _scalarSamples->setSelectedScalar(scalar); }

virtual void setupFromObject(Kst::Object* dataObject) {
if (MovingMedianSource* source = static_cast<MovingMedianSource*>(dataObject)) {
setSelectedVector(source->vector());
setSelectedScalar(source->scalarSamples());
}
}

virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) {
Q_UNUSED(store);
Q_UNUSED(attrs);

bool validTag = true;

// QStringRef av;
// av = attrs.value("value");
// if (!av.isNull()) {
// _configValue = QVariant(av.toString()).toBool();
// }

return validTag;
}

public slots:
virtual void save() {
if (_cfg) {
_cfg->beginGroup("Moving Median DataObject Plugin");
_cfg->setValue("Input Vector", _vector->selectedVector()->Name());
_cfg->setValue("Input Scalar", _scalarSamples->selectedScalar()->Name());
_cfg->endGroup();
}
}

virtual void load() {
if (_cfg && _store) {
_cfg->beginGroup("Moving Median DataObject Plugin");
QString vectorName = _cfg->value("Input Vector").toString();
Kst::Object* object = _store->retrieveObject(vectorName);
Kst::Vector* vector = static_cast<Kst::Vector*>(object);
if (vector) {
setSelectedVector(vector);
}
QString scalarName = _cfg->value("Input Scalar").toString();
_scalarSamples->setSelectedScalar(scalarName);

_cfg->endGroup();
}
}

private:
Kst::ObjectStore *_store;

};


MovingMedianSource::MovingMedianSource(Kst::ObjectStore *store)
: Kst::BasicPlugin(store) {
}


MovingMedianSource::~MovingMedianSource() {
}


QString MovingMedianSource::_automaticDescriptiveName() const {
if (vector()) {
return tr("%1 Moving Median").arg(vector()->descriptiveName());
} else {
return tr("Moving Median");
}
}

QString MovingMedianSource::descriptionTip() const {
QString tip;

tip = tr("Moving Median: %1\n").arg(Name());

tip += tr("\nInput: %1").arg(vector()->descriptionTip());
return tip;
}


void MovingMedianSource::change(Kst::DataObjectConfigWidget *configWidget) {
if (ConfigMovingMedianPlugin* config = static_cast<ConfigMovingMedianPlugin*>(configWidget)) {
setInputVector(VECTOR_IN, config->selectedVector());
setInputScalar(SCALAR_IN, config->selectedScalar());
}
}


void MovingMedianSource::setupOutputs() {
setOutputVector(VECTOR_OUT, "");
}


// TODO
bool MovingMedianSource::algorithm() {
Kst::VectorPtr inputVector = _inputVectors[VECTOR_IN];
Kst::ScalarPtr inputScalar = _inputScalars[SCALAR_IN];
Kst::VectorPtr outputVector;
// maintain kst file compatibility if the output vector name is changed.
if (_outputVectors.contains(VECTOR_OUT)) {
outputVector = _outputVectors[VECTOR_OUT];
} else {
outputVector = _outputVectors.values().at(0);
}


/* Memory allocation */
outputVector->resize(inputVector->length(), true);

double const *v_in = inputVector->noNanValue();
double *v_out = outputVector->raw_V_ptr();
int s_in = int(inputScalar->value());
static QVector<double> buffer;

buffer.reserve(s_in);

for (int i = 0; i < inputVector->length(); ++i) {
int divisor = qMin(i + 1, s_in);

buffer.clear();

for (int j = i - divisor + 1; j <= i; ++j)
buffer.append(v_in[j]);

std::stable_sort(buffer.begin(), buffer.end());

int middleIndex = buffer.size() / 2;

if (buffer.size() % 2 == 0)
v_out[i] = (buffer.at(middleIndex - 1) + buffer.at(middleIndex)) / 2;
else
v_out[i] = buffer.at(middleIndex);
}

return true;
}


Kst::VectorPtr MovingMedianSource::vector() const {
return _inputVectors[VECTOR_IN];
}

Kst::ScalarPtr MovingMedianSource::scalarSamples() const {
return _inputScalars[SCALAR_IN];
}


QStringList MovingMedianSource::inputVectorList() const {
return QStringList( VECTOR_IN );
}


QStringList MovingMedianSource::inputScalarList() const {
return QStringList( SCALAR_IN );
}


QStringList MovingMedianSource::inputStringList() const {
return QStringList( /*STRING_IN*/ );
}


QStringList MovingMedianSource::outputVectorList() const {
return QStringList( VECTOR_OUT );
}


QStringList MovingMedianSource::outputScalarList() const {
return QStringList( /*SCALAR_OUT*/ );
}


QStringList MovingMedianSource::outputStringList() const {
return QStringList( /*STRING_OUT*/ );
}


void MovingMedianSource::saveProperties(QXmlStreamWriter &s) {
Q_UNUSED(s);
// s.writeAttribute("value", _configValue);
}


QString MovingMedianPlugin::pluginName() const { return tr("Moving Median"); }
QString MovingMedianPlugin::pluginDescription() const { return tr("Computes the moving median of the input vector."); }


Kst::DataObject *MovingMedianPlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const {

if (ConfigMovingMedianPlugin* config = static_cast<ConfigMovingMedianPlugin*>(configWidget)) {

MovingMedianSource* object = store->createObject<MovingMedianSource>();

if (setupInputsOutputs) {
object->setInputScalar(SCALAR_IN, config->selectedScalar());
object->setupOutputs();
object->setInputVector(VECTOR_IN, config->selectedVector());
}

object->setPluginName(pluginName());

object->writeLock();
object->registerChange();
object->unlock();

return object;
}
return 0;
}


Kst::DataObjectConfigWidget *MovingMedianPlugin::configWidget(QSettings *settingsObject) const {
ConfigMovingMedianPlugin *widget = new ConfigMovingMedianPlugin(settingsObject);
return widget;
}

#ifndef QT5
Q_EXPORT_PLUGIN2(kstplugin_BinPlugin, MovingMedianPlugin)
#endif

// vim: ts=2 sw=2 et
76 changes: 76 additions & 0 deletions src/plugins/filters/movingmedian/movingmedian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/***************************************************************************
* *
* copyright : (C) 2019 Jonathan Liu *
* net147@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef MOVINGMEDIANPLUGIN_H
#define MOVINGMEDIANPLUGIN_H

#include <QFile>

#include <basicplugin.h>
#include <dataobjectplugin.h>

class MovingMedianSource : public Kst::BasicPlugin {
Q_OBJECT

public:
virtual QString _automaticDescriptiveName() const;

virtual QString descriptionTip() const;

Kst::VectorPtr vector() const;
Kst::ScalarPtr scalarSamples() const;

virtual void change(Kst::DataObjectConfigWidget *configWidget);

void setupOutputs();
virtual bool algorithm();

virtual QStringList inputVectorList() const;
virtual QStringList inputScalarList() const;
virtual QStringList inputStringList() const;
virtual QStringList outputVectorList() const;
virtual QStringList outputScalarList() const;
virtual QStringList outputStringList() const;

virtual void saveProperties(QXmlStreamWriter &s);

protected:
MovingMedianSource(Kst::ObjectStore *store);
~MovingMedianSource();

friend class Kst::ObjectStore;


};


class MovingMedianPlugin : public QObject, public Kst::DataObjectPluginInterface {
Q_OBJECT
Q_INTERFACES(Kst::DataObjectPluginInterface)
Q_PLUGIN_METADATA(IID "com.kst.DataObjectPluginInterface/2.0")
public:
virtual ~MovingMedianPlugin() {}

virtual QString pluginName() const;
virtual QString pluginDescription() const;

virtual DataObjectPluginInterface::PluginTypeID pluginType() const { return Filter; }

virtual bool hasConfigWidget() const { return true; }

virtual Kst::DataObject *create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs = true) const;

virtual Kst::DataObjectConfigWidget *configWidget(QSettings *settingsObject) const;
};

#endif
// vim: ts=2 sw=2 et
11 changes: 11 additions & 0 deletions src/plugins/filters/movingmedian/movingmedian.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
include(../../plugins_sub.pri)

TARGET = $$kstlib(kstplugin_movingmedian)

SOURCES += \
movingmedian.cpp

HEADERS += \
movingmedian.h

FORMS += movingmedianconfig.ui
85 changes: 85 additions & 0 deletions src/plugins/filters/movingmedian/movingmedianconfig.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MovingMedianConfig</class>
<widget class="QWidget" name="MovingMedianConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>425</width>
<height>55</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="Kst::VectorSelector" name="_vector" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Samples: </string>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Kst::ScalarSelector" name="_scalarSamples" native="true"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Y: </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Kst::VectorSelector</class>
<extends>QWidget</extends>
<header>vectorselector.h</header>
</customwidget>
<customwidget>
<class>Kst::ScalarSelector</class>
<extends>QWidget</extends>
<header>scalarselector.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
2 changes: 2 additions & 0 deletions src/widgets/datasourceselector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ void DataSourceSelector::chooseFile() {
QString file;
QPointer<DataSourceSelectorDialog> dialog = new DataSourceSelectorDialog( _file, this );

dialog->setFileMode(QFileDialog::ExistingFile);

if (dialog->exec() == QDialog::Accepted) {
file = dialog->selectedDataSource();

Expand Down