File indexing completed on 2025-01-05 04:12:50
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 "convolve.h" 0017 #include "objectstore.h" 0018 #include "ui_convolveconfig.h" 0019 0020 #include <gsl/gsl_fft_real.h> 0021 #include <gsl/gsl_fft_halfcomplex.h> 0022 0023 0024 static const QString& VECTOR_IN_ONE = "Vector One In"; 0025 static const QString& VECTOR_IN_TWO = "Vector Two In"; 0026 static const QString& VECTOR_OUT = "Vector Out"; 0027 0028 class ConfigWidgetConvolvePlugin : public Kst::DataObjectConfigWidget, public Ui_ConvolveConfig { 0029 public: 0030 ConfigWidgetConvolvePlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_ConvolveConfig() { 0031 _store = 0; 0032 setupUi(this); 0033 } 0034 0035 ~ConfigWidgetConvolvePlugin() {} 0036 0037 void setObjectStore(Kst::ObjectStore* store) { 0038 _store = store; 0039 _vectorOne->setObjectStore(store); 0040 _vectorTwo->setObjectStore(store); 0041 } 0042 0043 void setupSlots(QWidget* dialog) { 0044 if (dialog) { 0045 connect(_vectorOne, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0046 connect(_vectorTwo, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified())); 0047 } 0048 } 0049 0050 Kst::VectorPtr selectedVectorOne() { return _vectorOne->selectedVector(); }; 0051 void setSelectedVectorOne(Kst::VectorPtr vector) { return _vectorOne->setSelectedVector(vector); }; 0052 0053 Kst::VectorPtr selectedVectorTwo() { return _vectorTwo->selectedVector(); }; 0054 void setSelectedVectorTwo(Kst::VectorPtr vector) { return _vectorTwo->setSelectedVector(vector); }; 0055 0056 virtual void setupFromObject(Kst::Object* dataObject) { 0057 if (ConvolveSource* source = static_cast<ConvolveSource*>(dataObject)) { 0058 setSelectedVectorOne(source->vectorOne()); 0059 setSelectedVectorTwo(source->vectorTwo()); 0060 } 0061 } 0062 0063 virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) { 0064 Q_UNUSED(store); 0065 Q_UNUSED(attrs); 0066 0067 bool validTag = true; 0068 0069 // QStringRef av; 0070 // av = attrs.value("value"); 0071 // if (!av.isNull()) { 0072 // _configValue = QVariant(av.toString()).toBool(); 0073 // } 0074 0075 return validTag; 0076 } 0077 0078 public slots: 0079 virtual void save() { 0080 if (_cfg) { 0081 _cfg->beginGroup("Convolve DataObject Plugin"); 0082 _cfg->setValue("Input Vector One", _vectorOne->selectedVector()->Name()); 0083 _cfg->setValue("Input Vector Two", _vectorTwo->selectedVector()->Name()); 0084 _cfg->endGroup(); 0085 } 0086 } 0087 0088 virtual void load() { 0089 if (_cfg && _store) { 0090 _cfg->beginGroup("Convolve DataObject Plugin"); 0091 QString vectorName = _cfg->value("Input Vector One").toString(); 0092 Kst::Object* object = _store->retrieveObject(vectorName); 0093 Kst::Vector* vector = static_cast<Kst::Vector*>(object); 0094 if (vector) { 0095 setSelectedVectorOne(vector); 0096 } 0097 vectorName = _cfg->value("Input Vector Two").toString(); 0098 Kst::Object* object2 = _store->retrieveObject(vectorName); 0099 Kst::Vector* vector2 = static_cast<Kst::Vector*>(object2); 0100 if (vector2) { 0101 setSelectedVectorTwo(vector2); 0102 } 0103 _cfg->endGroup(); 0104 } 0105 } 0106 0107 private: 0108 Kst::ObjectStore *_store; 0109 0110 }; 0111 0112 0113 ConvolveSource::ConvolveSource(Kst::ObjectStore *store) 0114 : Kst::BasicPlugin(store) { 0115 } 0116 0117 0118 ConvolveSource::~ConvolveSource() { 0119 } 0120 0121 0122 QString ConvolveSource::_automaticDescriptiveName() const { 0123 return tr("Convolve Plugin Object"); 0124 } 0125 0126 0127 void ConvolveSource::change(Kst::DataObjectConfigWidget *configWidget) { 0128 if (ConfigWidgetConvolvePlugin* config = static_cast<ConfigWidgetConvolvePlugin*>(configWidget)) { 0129 setInputVector(VECTOR_IN_ONE, config->selectedVectorOne()); 0130 setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo()); 0131 } 0132 } 0133 0134 0135 void ConvolveSource::setupOutputs() { 0136 setOutputVector(VECTOR_OUT, ""); 0137 } 0138 0139 0140 bool ConvolveSource::algorithm() { 0141 Kst::VectorPtr inputVectorOne = _inputVectors[VECTOR_IN_ONE]; 0142 Kst::VectorPtr inputVectorTwo = _inputVectors[VECTOR_IN_TWO]; 0143 Kst::VectorPtr outputVector = _outputVectors[VECTOR_OUT]; 0144 0145 if (inputVectorOne->length() <= 0 && inputVectorTwo->length() <= 0) { 0146 _errorString = tr("Error: Input Vectors - invalid size"); 0147 return false; 0148 } 0149 0150 double* pdResponse; 0151 double* pdConvolve; 0152 double* pdResult; 0153 double dReal; 0154 double dImag; 0155 0156 Kst::VectorPtr response; 0157 Kst::VectorPtr convolve; 0158 0159 int iLength; 0160 int iLengthNew; 0161 0162 bool bReturn = false; 0163 int iResponseMidpoint; 0164 0165 // determine which is the response function: 0166 // i.e. which is shorter... 0167 if (inputVectorOne->length() < inputVectorTwo->length()) { 0168 response = inputVectorOne; 0169 convolve = inputVectorTwo; 0170 } else { 0171 response = inputVectorTwo; 0172 convolve = inputVectorOne; 0173 } 0174 0175 outputVector->resize(convolve->length(), false); 0176 0177 iResponseMidpoint = response->length() / 2; 0178 iLength = convolve->length() + iResponseMidpoint; 0179 0180 // round iLength up to the nearest factor of two... 0181 iLengthNew = 64; 0182 while (iLengthNew < iLength && iLengthNew > 0) { 0183 iLengthNew *= 2; 0184 } 0185 iLength = iLengthNew; 0186 0187 if (iLength <= 0) { 0188 _errorString = tr("Error: Invalid Input length calculated"); 0189 return false; 0190 } 0191 0192 pdResponse = new double[iLength]; 0193 pdConvolve = new double[iLength]; 0194 if (pdResponse != NULL && pdConvolve != NULL) { 0195 // 0196 // sort the response function into wrap-around order... 0197 // 0198 memset( pdResponse, 0, iLength * sizeof( double ) ); 0199 0200 for (int i = 0; i < iResponseMidpoint; i++) { 0201 pdResponse[i] = response->noNanValue()[iResponseMidpoint+i]; 0202 pdResponse[iLength-iResponseMidpoint+i] = response->noNanValue()[i]; 0203 } 0204 0205 // 0206 // handle the case where the response function has an odd number of points... 0207 // 0208 if (iResponseMidpoint % 2 == 1) { 0209 pdResponse[iResponseMidpoint] = response->noNanValue()[response->length()-1]; 0210 } 0211 0212 // 0213 // zero-pad the convolve array... 0214 // 0215 memset( pdConvolve, 0, iLength * sizeof( double ) ); 0216 memcpy( pdConvolve, convolve->noNanValue(), convolve->length() * sizeof( double ) ); 0217 0218 // 0219 // calculate the FFTs of the two functions... 0220 // 0221 if (gsl_fft_real_radix2_transform( pdResponse, 1, iLength ) == 0) { 0222 if (gsl_fft_real_radix2_transform( pdConvolve, 1, iLength ) == 0) { 0223 // 0224 // multiply the FFTs together... 0225 // 0226 for (int i=0; i < iLength/2; i++) { 0227 if (i==0 || i==(iLength/2)-1) { 0228 pdResponse[i] = pdResponse[i] * pdConvolve[i]; 0229 } else { 0230 dReal = pdResponse[i] * pdConvolve[i] - pdResponse[iLength-i] * pdConvolve[iLength-i]; 0231 dImag = pdResponse[i] * pdConvolve[iLength-i] + pdResponse[iLength-i] * pdConvolve[i]; 0232 0233 pdResponse[i] = dReal; 0234 pdResponse[iLength-i] = dImag; 0235 } 0236 } 0237 0238 // 0239 // do the inverse FFT... 0240 // 0241 if (gsl_fft_halfcomplex_radix2_inverse( pdResponse, 1, iLength) == 0) { 0242 pdResult = outputVector->raw_V_ptr(); 0243 0244 if (pdResult != NULL) { 0245 for (int i = 0; i < convolve->length(); ++i) { 0246 outputVector->raw_V_ptr()[i] = pdResult[i]; 0247 } 0248 0249 memcpy( pdResult, pdResponse, convolve->length() * sizeof( double ) ); 0250 0251 bReturn = true; 0252 } 0253 } 0254 } 0255 } 0256 } 0257 delete[] pdResponse; 0258 delete[] pdConvolve; 0259 0260 return bReturn; 0261 } 0262 0263 0264 Kst::VectorPtr ConvolveSource::vectorOne() const { 0265 return _inputVectors[VECTOR_IN_ONE]; 0266 } 0267 0268 0269 Kst::VectorPtr ConvolveSource::vectorTwo() const { 0270 return _inputVectors[VECTOR_IN_TWO]; 0271 } 0272 0273 0274 QStringList ConvolveSource::inputVectorList() const { 0275 QStringList vectors(VECTOR_IN_ONE); 0276 vectors += VECTOR_IN_TWO; 0277 return vectors; 0278 } 0279 0280 0281 QStringList ConvolveSource::inputScalarList() const { 0282 return QStringList( /*SCALAR_IN*/ ); 0283 } 0284 0285 0286 QStringList ConvolveSource::inputStringList() const { 0287 return QStringList( /*STRING_IN*/ ); 0288 } 0289 0290 0291 QStringList ConvolveSource::outputVectorList() const { 0292 return QStringList(VECTOR_OUT); 0293 } 0294 0295 0296 QStringList ConvolveSource::outputScalarList() const { 0297 return QStringList( /*SCALAR_OUT*/ ); 0298 } 0299 0300 0301 QStringList ConvolveSource::outputStringList() const { 0302 return QStringList( /*STRING_OUT*/ ); 0303 } 0304 0305 0306 void ConvolveSource::saveProperties(QXmlStreamWriter &s) { 0307 Q_UNUSED(s); 0308 // s.writeAttribute("value", _configValue); 0309 } 0310 0311 0312 QString ConvolvePlugin::pluginName() const { return tr("Convolve"); } 0313 QString ConvolvePlugin::pluginDescription() const { return tr("Generates the convolution of one vector with another."); } 0314 0315 0316 Kst::DataObject *ConvolvePlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const { 0317 0318 if (ConfigWidgetConvolvePlugin* config = static_cast<ConfigWidgetConvolvePlugin*>(configWidget)) { 0319 0320 ConvolveSource* object = store->createObject<ConvolveSource>(); 0321 0322 if (setupInputsOutputs) { 0323 object->setupOutputs(); 0324 object->setInputVector(VECTOR_IN_ONE, config->selectedVectorOne()); 0325 object->setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo()); 0326 } 0327 0328 object->setPluginName(pluginName()); 0329 0330 object->writeLock(); 0331 object->registerChange(); 0332 object->unlock(); 0333 0334 return object; 0335 } 0336 return 0; 0337 } 0338 0339 0340 Kst::DataObjectConfigWidget *ConvolvePlugin::configWidget(QSettings *settingsObject) const { 0341 ConfigWidgetConvolvePlugin *widget = new ConfigWidgetConvolvePlugin(settingsObject); 0342 return widget; 0343 } 0344 0345 #ifndef QT5 0346 Q_EXPORT_PLUGIN2(kstplugin_ConvolvePlugin, ConvolvePlugin) 0347 #endif 0348 0349 // vim: ts=2 sw=2 et