File indexing completed on 2024-12-22 04:18:09

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *   copyright : (C) 2005  University of British Columbia                  *
0006  *                   dscott@phas.ubc.ca                                    *
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 
0016 #include "filterdespike.h"
0017 #include "objectstore.h"
0018 #include "ui_filterdespikeconfig.h"
0019 
0020 static const QString& VECTOR_IN = "Y Vector";
0021 static const QString& SCALAR_NSIGMA_IN = "NSigma Scalar";
0022 static const QString& SCALAR_SPACING_IN = "Spacing Scalar";
0023 static const QString& VECTOR_OUT = "Y";
0024 
0025 class ConfigWidgetFilterDespikePlugin : public Kst::DataObjectConfigWidget, public Ui_FilterDespikeConfig {
0026   public:
0027     ConfigWidgetFilterDespikePlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_FilterDespikeConfig() {
0028       _store = 0;
0029       setupUi(this);
0030     }
0031 
0032     ~ConfigWidgetFilterDespikePlugin() {}
0033 
0034     void setObjectStore(Kst::ObjectStore* store) { 
0035       _store = store; 
0036       _vector->setObjectStore(store);
0037       _scalarNSigma->setObjectStore(store);
0038       _scalarSpacing->setObjectStore(store);
0039       _scalarNSigma->setDefaultValue(5.0);
0040       _scalarSpacing->setDefaultValue(1.0);
0041     }
0042 
0043     void setupSlots(QWidget* dialog) {
0044       if (dialog) {
0045         connect(_vector, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
0046         connect(_scalarNSigma, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
0047         connect(_scalarSpacing, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
0048       }
0049     }
0050 
0051     void setVectorX(Kst::VectorPtr vector) {
0052       setSelectedVector(vector);
0053     }
0054 
0055     void setVectorY(Kst::VectorPtr vector) {
0056       setSelectedVector(vector);
0057     }
0058 
0059     void setVectorsLocked(bool locked = true) {
0060       _vector->setEnabled(!locked);
0061     }
0062 
0063     Kst::VectorPtr selectedVector() { return _vector->selectedVector(); };
0064     void setSelectedVector(Kst::VectorPtr vector) { return _vector->setSelectedVector(vector); };
0065 
0066     Kst::ScalarPtr selectedNSigmaScalar() { return _scalarNSigma->selectedScalar(); };
0067     void setSelectedNSigmaScalar(Kst::ScalarPtr scalar) { return _scalarNSigma->setSelectedScalar(scalar); };
0068 
0069     Kst::ScalarPtr selectedSpacingScalar() { return _scalarSpacing->selectedScalar(); };
0070     void setSelectedSpacingScalar(Kst::ScalarPtr scalar) { return _scalarSpacing->setSelectedScalar(scalar); };
0071 
0072     virtual void setupFromObject(Kst::Object* dataObject) {
0073       if (FilterDespikeSource* source = static_cast<FilterDespikeSource*>(dataObject)) {
0074         setSelectedVector(source->vector());
0075         setSelectedNSigmaScalar(source->nSigmaScalar());
0076         setSelectedSpacingScalar(source->spacingScalar());
0077       }
0078     }
0079 
0080     virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) {
0081       Q_UNUSED(store);
0082       Q_UNUSED(attrs);
0083 
0084       bool validTag = true;
0085 
0086 //       QStringRef av;
0087 //       av = attrs.value("value");
0088 //       if (!av.isNull()) {
0089 //         _configValue = QVariant(av.toString()).toBool();
0090 //       }
0091 
0092       return validTag;
0093     }
0094 
0095   public slots:
0096     virtual void save() {
0097       if (_cfg) {
0098         _cfg->beginGroup("Filter Despike Plugin");
0099         _cfg->setValue("Input Vector", _vector->selectedVector()->Name());
0100         _cfg->setValue("Spacing Scalar", _scalarSpacing->selectedScalar()->Name());
0101         _cfg->setValue("NSigma Scalar", _scalarNSigma->selectedScalar()->Name());
0102         _cfg->endGroup();
0103       }
0104     }
0105 
0106     virtual void load() {
0107       if (_cfg && _store) {
0108         _cfg->beginGroup("Filter Despike Plugin");
0109         QString vectorName = _cfg->value("Input Vector").toString();
0110         Kst::Object* object = _store->retrieveObject(vectorName);
0111         Kst::Vector* vector = static_cast<Kst::Vector*>(object);
0112         if (vector) {
0113           setSelectedVector(vector);
0114         }
0115         QString scalarName = _cfg->value("Spacing Scalar").toString();
0116         _scalarSpacing->setSelectedScalar(scalarName);
0117 
0118         scalarName = _cfg->value("NSigma Scalar").toString();
0119         _scalarNSigma->setSelectedScalar(scalarName);
0120 
0121         _cfg->endGroup();
0122       }
0123     }
0124 
0125   private:
0126     Kst::ObjectStore *_store;
0127 
0128 };
0129 
0130 
0131 FilterDespikeSource::FilterDespikeSource(Kst::ObjectStore *store)
0132 : Kst::BasicPlugin(store) {
0133 }
0134 
0135 
0136 FilterDespikeSource::~FilterDespikeSource() {
0137 }
0138 
0139 
0140 QString FilterDespikeSource::_automaticDescriptiveName() const {
0141   if (vector()) {
0142     return tr("%1 Despiked", "arg 1 is the name of the vector which has been despiked").arg(vector()->descriptiveName());
0143   } else {
0144     return tr("Despike");
0145   }
0146 }
0147 
0148 
0149 QString FilterDespikeSource::descriptionTip() const {
0150   QString tip;
0151 
0152   tip = tr("Despike Filter: %1\n  Spacing: %2\n  NSigma: %3").arg(Name()).arg(spacingScalar()->value()).arg(nSigmaScalar()->value());
0153 
0154   tip += tr("\nInput: %1").arg(vector()->descriptionTip());
0155   return tip;
0156 }
0157 
0158 void FilterDespikeSource::change(Kst::DataObjectConfigWidget *configWidget) {
0159   if (ConfigWidgetFilterDespikePlugin* config = static_cast<ConfigWidgetFilterDespikePlugin*>(configWidget)) {
0160     setInputVector(VECTOR_IN, config->selectedVector());
0161     setInputScalar(SCALAR_NSIGMA_IN, config->selectedNSigmaScalar());
0162     setInputScalar(SCALAR_SPACING_IN, config->selectedSpacingScalar());
0163   }
0164 }
0165 
0166 
0167 void FilterDespikeSource::setupOutputs() {
0168   setOutputVector(VECTOR_OUT, "");
0169 }
0170 
0171 
0172 bool FilterDespikeSource::algorithm() {
0173   Kst::VectorPtr inputVector = _inputVectors[VECTOR_IN];
0174   Kst::ScalarPtr nSigmaScalar = _inputScalars[SCALAR_NSIGMA_IN];
0175   Kst::ScalarPtr spacingScalar = _inputScalars[SCALAR_SPACING_IN];
0176   Kst::VectorPtr outputVector;
0177   // maintain kst file compatibility if the output vector name is changed.
0178   if (_outputVectors.contains(VECTOR_OUT)) {
0179     outputVector = _outputVectors[VECTOR_OUT];
0180   } else {
0181     outputVector = _outputVectors.values().at(0);
0182   }
0183 
0184   int N = inputVector->length();
0185   double last_good;
0186   double mdev = 0;
0187   double cut = nSigmaScalar->value();
0188   int dx = int(spacingScalar->value());
0189   int i;
0190   int spike_start = -1;
0191   int border = dx*2;
0192 
0193   if ( (N < 1) || (cut <= 0) || (dx < 1) || (dx > N/2) ) {
0194     return false;
0195   }
0196 
0197   /* get mean deviation of 3 pt difference */
0198   for (i=dx; i<N-dx; ++i) {
0199     mdev += fabs(inputVector->value(i)-(inputVector->value(i-dx) + inputVector->value(i+dx))*0.5);
0200   }
0201   mdev /= double(N);
0202 
0203   cut *= mdev;
0204 
0205   // resize the output array
0206   outputVector->resize(inputVector->length(), false);
0207 
0208   // for first dx points, do a 2 point difference
0209   last_good = inputVector->value(0);
0210   for (i=0; i<dx; ++i) {
0211     if (fabs(inputVector->value(i) - inputVector->value(i+dx))>cut) {
0212       if (spike_start<0) { 
0213         spike_start = i-border;
0214         if (spike_start<0) {
0215           spike_start = 0;
0216         }
0217       }
0218     } else {
0219       if (spike_start>=0) {
0220         i += 4*border-1; 
0221         if (i>=N) {
0222           i=N-1;
0223         }
0224         for (int j=spike_start; j<=i; j++) {
0225           outputVector->raw_V_ptr()[j] = last_good;
0226         }
0227         spike_start = -1;
0228       }
0229       last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i);
0230     }
0231   }
0232   // do a 3 point difference where it is possible
0233   for (i=dx; i<N-dx; ++i) {
0234     if (fabs(inputVector->value(i) - (inputVector->value(i-dx) + inputVector->value(i+dx))*0.5)>cut) {
0235       if (spike_start<0) { 
0236         spike_start = i-border;
0237         if (spike_start<0) {
0238           spike_start = 0;
0239         }
0240       }
0241     } else {
0242       if (spike_start>=0) {
0243         i += 4*border-1; 
0244         if (i>=N) {
0245           i=N-1;
0246         }
0247         for (int j=spike_start; j<=i; j++) {
0248           outputVector->raw_V_ptr()[j] = last_good;
0249         }
0250         spike_start = -1;
0251       } else {
0252         last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i);
0253       }
0254     }
0255   }
0256   // do a 2 point difference for last dx points
0257   for (i=N-dx-1; i<N; ++i) {
0258     if (fabs(inputVector->value(i-dx) - inputVector->value(i))>cut) {
0259       if (spike_start<0) { 
0260         spike_start = i-border;
0261         if (spike_start<0) {
0262           spike_start = 0;
0263         }
0264       }
0265     } else {
0266       if (spike_start>=0) {
0267         i += 4*border-1;
0268         if (i>=N) {
0269           i=N-1;
0270         }
0271         for (int j=spike_start; j<=i; j++) {
0272           outputVector->raw_V_ptr()[j] = last_good;
0273         }
0274         spike_start = -1;
0275       } else {
0276         last_good = outputVector->raw_V_ptr()[i] = inputVector->value(i);
0277       }
0278     }
0279   }
0280   if (spike_start>=0) {
0281     for (int j=spike_start; j<N; j++) {
0282       outputVector->raw_V_ptr()[j] = last_good;
0283     }
0284   }
0285 
0286   Kst::LabelInfo label_info = inputVector->labelInfo();
0287   label_info.name = tr("Despiked %1").arg(label_info.name);
0288   outputVector->setLabelInfo(label_info);
0289 
0290   return true;
0291 }
0292 
0293 
0294 Kst::VectorPtr FilterDespikeSource::vector() const {
0295   return _inputVectors[VECTOR_IN];
0296 }
0297 
0298 
0299 Kst::ScalarPtr FilterDespikeSource::spacingScalar() const {
0300   return _inputScalars[SCALAR_SPACING_IN];
0301 }
0302 
0303 
0304 Kst::ScalarPtr FilterDespikeSource::nSigmaScalar() const {
0305   return _inputScalars[SCALAR_NSIGMA_IN];
0306 }
0307 
0308 
0309 QStringList FilterDespikeSource::inputVectorList() const {
0310   return QStringList( VECTOR_IN );
0311 }
0312 
0313 
0314 QStringList FilterDespikeSource::inputScalarList() const {
0315   QStringList inputScalars( SCALAR_NSIGMA_IN );
0316   inputScalars += SCALAR_SPACING_IN;
0317   return inputScalars;
0318 }
0319 
0320 
0321 QStringList FilterDespikeSource::inputStringList() const {
0322   return QStringList( /*STRING_IN*/ );
0323 }
0324 
0325 
0326 QStringList FilterDespikeSource::outputVectorList() const {
0327   return QStringList( VECTOR_OUT );
0328 }
0329 
0330 
0331 QStringList FilterDespikeSource::outputScalarList() const {
0332   return QStringList( /*SCALAR_OUT*/ );
0333 }
0334 
0335 
0336 QStringList FilterDespikeSource::outputStringList() const {
0337   return QStringList( /*STRING_OUT*/ );
0338 }
0339 
0340 
0341 void FilterDespikeSource::saveProperties(QXmlStreamWriter &s) {
0342   Q_UNUSED(s);
0343 //   s.writeAttribute("value", _configValue);
0344 }
0345 
0346 
0347 // Name used to identify the plugin.  Used when loading the plugin.
0348 QString FilterDespikePlugin::pluginName() const { return tr("Despike Filter"); }
0349 QString FilterDespikePlugin::pluginDescription() const { return tr("Finds and removes spikes using a 3 point difference."); }
0350 
0351 
0352 Kst::DataObject *FilterDespikePlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const {
0353 
0354   if (ConfigWidgetFilterDespikePlugin* config = static_cast<ConfigWidgetFilterDespikePlugin*>(configWidget)) {
0355 
0356     FilterDespikeSource* object = store->createObject<FilterDespikeSource>();
0357 
0358     if (setupInputsOutputs) {
0359       object->setInputScalar(SCALAR_SPACING_IN, config->selectedSpacingScalar());
0360       object->setInputScalar(SCALAR_NSIGMA_IN, config->selectedNSigmaScalar());
0361       object->setupOutputs();
0362       object->setInputVector(VECTOR_IN, config->selectedVector());
0363     }
0364 
0365     object->setPluginName(pluginName());
0366 
0367     object->writeLock();
0368     object->registerChange();
0369     object->unlock();
0370 
0371     return object;
0372   }
0373   return 0;
0374 }
0375 
0376 
0377 Kst::DataObjectConfigWidget *FilterDespikePlugin::configWidget(QSettings *settingsObject) const {
0378   ConfigWidgetFilterDespikePlugin *widget = new ConfigWidgetFilterDespikePlugin(settingsObject);
0379   return widget;
0380 }
0381 
0382 #ifndef QT5
0383 Q_EXPORT_PLUGIN2(kstplugin_FilterDespikePlugin, FilterDespikePlugin)
0384 #endif
0385 
0386 // vim: ts=2 sw=2 et