Commit 9e8e7a6d authored by Bruno Colombet's avatar Bruno Colombet

Fixes:

- CompuMedics plugin was not ordering the channels in the right way.
- DeltamedTxtBin plugin bug
- Montage features now take into account the bad channels.
parent a94289bd
......@@ -164,6 +164,7 @@ void AwMontageDial::loadMontage()
if (path.isEmpty())
return;
AwChannelList channels = AwMontageManager::instance()->load(path);
removeBadChannels(channels);
if (channels.isEmpty())
return;
static_cast<AwChannelListModel *>(m_ui.tvDisplay->model())->setMontage(channels);
......@@ -330,7 +331,8 @@ void AwMontageDial::addChannelsByTypes()
for (auto l : labels) {
auto asRecorded = m_asRecorded[l];
if (asRecorded)
channels << new AwChannel(asRecorded);
if (!asRecorded->isBad())
channels << new AwChannel(asRecorded);
}
if (!channels.isEmpty())
static_cast<AwChannelListModel *>(m_ui.tvDisplay->model())->addChannels(channels);
......@@ -354,9 +356,18 @@ void AwMontageDial::computeSEEGMontageFromEEGChannels()
}
void AwMontageDial::removeBadChannels(AwChannelList& channels)
{
foreach(AwChannel *c, channels)
if (c->isBad() || m_badChannelsLabels.contains(c->name()))
channels.removeAll(c);
}
void AwMontageDial::makeECOGBipolar()
{
auto channels = AwChannel::getChannelsOfType(m_asRecorded.values(), AwChannel::ECoG);
removeBadChannels(channels);
if (channels.isEmpty()) {
AwMessageBox::information(this, tr("ECoG Bipolar"), tr("Could not make a bipolar montage (no ECoG channels in data file.)"));
return;
......@@ -366,6 +377,13 @@ void AwMontageDial::makeECOGBipolar()
AwChannelList dup = AwChannel::duplicateChannels(channels);
AwECoGDialog dlg(dup);
if (dlg.exec() == QDialog::Accepted) {
// check for valid references
for (auto c : dup) {
if (c->hasReferences())
if (m_badChannelsLabels.contains(c->referenceName()))
c->clearRefName();
}
// check for remaining monopolar channels
foreach(AwChannel *c, dup) {
if (!c->hasReferences()) {
......@@ -384,11 +402,11 @@ void AwMontageDial::makeECOGBipolar()
void AwMontageDial::setAVGRefMontage()
{
auto channels = AwChannel::getChannelsOfType(m_asRecorded.values(), AwChannel::EEG);
removeBadChannels(channels);
if (channels.isEmpty()) {
AwMessageBox::information(this, tr("EEG AVG"), tr("Could not make a EEG AVG Ref. montage (no EEG channels in data file.)"));
return;
}
// make a montage with ONLY SEEG as bipolar, remove all other channels.
auto dup = AwChannel::duplicateChannels(channels);
for (auto c : dup)
......@@ -399,11 +417,11 @@ void AwMontageDial::setAVGRefMontage()
void AwMontageDial::setSEEGAVGRefMontage()
{
auto channels = AwChannel::getChannelsOfType(m_asRecorded.values(), AwChannel::SEEG);
removeBadChannels(channels);
if (channels.isEmpty()) {
AwMessageBox::information(this, tr("SEEG AVG"), tr("Could not make a SEEG AVG Ref. montage (no SEEG channels in data file.)"));
return;
}
// make a montage with ONLY SEEG as bipolar, remove all other channels.
auto dup = AwChannel::duplicateChannels(channels);
for (auto c : dup)
......@@ -414,11 +432,11 @@ void AwMontageDial::setSEEGAVGRefMontage()
void AwMontageDial::makeSEEGBipolar()
{
auto seegChannels = AwChannel::getChannelsOfType(m_asRecorded.values(), AwChannel::SEEG);
removeBadChannels(seegChannels);
if (seegChannels.isEmpty()) {
AwMessageBox::information(this, tr("SEEG Bipolar"), tr("Could not make a bipolar montage (no SEEG channels in data file.)"));
return;
}
// make a montage with ONLY SEEG as bipolar, remove all other channels.
auto dup = AwChannel::duplicateChannels(seegChannels);
// clear montage
......@@ -445,11 +463,13 @@ void AwMontageDial::makeSEEGBipolar()
auto nextNumber = number.toInt() + 1;
auto ref = QString("%1%2").arg(elec).arg(nextNumber);
if (m_asRecorded.contains(ref))
c->setReferenceName(ref);
if (!m_badChannelsLabels.contains(ref))
c->setReferenceName(ref);
else {
ref = QString("%1%2").arg(elecCopy).arg(nextNumber);
if (m_asRecorded.contains(ref))
c->setReferenceName(ref);
if (!m_badChannelsLabels.contains(ref))
c->setReferenceName(ref);
}
}
}
......@@ -468,6 +488,8 @@ void AwMontageDial::makeSEEGBipolar()
void AwMontageDial::unsetBadChannel(const QString& label)
{
m_badChannelsLabels.removeAll(label);
if (m_asRecorded.contains(label))
m_asRecorded[label]->setBad(false);
}
//
......@@ -488,6 +510,8 @@ void AwMontageDial::setBadChannel(const QString& electrodeLabel)
delete channels.takeFirst();
m_badChannelsLabels << electrodeLabel;
if (m_asRecorded.contains(electrodeLabel))
m_asRecorded[electrodeLabel]->setBad(true);
}
......@@ -585,7 +609,6 @@ void AwMontageDial::addChannelsToMontage()
if (channel) {
if (channel->isBad())
continue;
//channels << new AwChannel(channel);
channels << channel->duplicate();
}
}
......
......@@ -134,6 +134,8 @@ private:
void sortLabelsByTypes();
void updateButtonAddByTypes();
void createContextMenuAndActions();
/** remove bad channels directly in the specified list. **/
void removeBadChannels(AwChannelList& channels);
};
#endif // MONTAGEDIAL_H
......@@ -218,7 +218,7 @@ void AwPluginManager::checkForScriptPlugins(const QString& startingPath)
dirs.removeAll("..");
for (auto folder : dirs) {
QString name = folder;
QString desc, processType, category, compiledPath, flags;
QString desc, processType, category, compiledPath, flags, inputFlags;
int type = AwProcessPlugin::Background; // default type if none defined
bool isMATLABCompiled = false, isPythonCompiled = false;
QString pluginPath = dir.absolutePath() + "/" + folder;
......@@ -281,6 +281,11 @@ void AwPluginManager::checkForScriptPlugins(const QString& startingPath)
if (res.size() == 2)
category = res.at(1).trimmed();
}
else if (line.contains("input_flags")) {
QStringList res = line.split("=");
if (res.size() == 2)
inputFlags = res.at(1).trimmed();
}
else if (line.contains("flags")) {
QStringList res = line.split("=");
if (res.size() == 2)
......@@ -304,6 +309,7 @@ void AwPluginManager::checkForScriptPlugins(const QString& startingPath)
plugin->setPluginDir(pluginPath);
plugin->category = category;
setFlagsForScriptPlugin(plugin, flags);
setInputFlagsForScriptPlugin(plugin, inputFlags);
loadProcessPlugin(plugin);
}
if (isPythonScript || isPythonCompiled) {
......@@ -321,11 +327,31 @@ void AwPluginManager::checkForScriptPlugins(const QString& startingPath)
plugin->category = category;
setFlagsForScriptPlugin(plugin, flags);
loadProcessPlugin(plugin);
//AwProcessPlugin *p = m_processFactory.getPluginByName(name);
}
}
}
void AwPluginManager::setInputFlagsForScriptPlugin(AwScriptPlugin *plugin, const QString& flags)
{
if (flags.isEmpty())
return;
QStringList tokens;
if (flags.contains(":")) {
tokens = flags.split(":");
if (tokens.isEmpty())
return;
}
else
tokens << flags;
int f = 0;
for (auto s : tokens) {
auto token = s.toLower();
if (token == "getallmarkers")
f |= Aw::ProcessInput::GetAllMarkers;
}
plugin->setInputFlags(f);
}
void AwPluginManager::setFlagsForScriptPlugin(AwScriptPlugin *plugin, const QString& flags)
{
if (flags.isEmpty())
......
......@@ -105,6 +105,7 @@ private:
void loadUserPlugins();
void checkForScriptPlugins(const QString& startingPath);
void setFlagsForScriptPlugin(AwScriptPlugin *plugin, const QString& flags);
void setInputFlagsForScriptPlugin(AwScriptPlugin *plugin, const QString& flags);
void loadFileIOReaderPlugin(AwFileIOPlugin *plugin);
void loadFileIOWriterPlugin(AwFileIOPlugin *plugin);
......
......@@ -614,30 +614,6 @@ void AwProcessManager::runProcess(AwBaseProcess *process, const QStringList& arg
process->setInputFlags(process->inputFlags() | Aw::ProcessInput::ProcessIgnoresChannelSelection);
if (!skipDataFile) {
//// UPDATE 18/11/2014
//if (process->plugin()->flags() & Aw::ProcessFlags::PluginAcceptsTimeSelections) {
// if (process->pdi.input.markers().isEmpty()) { // if empty at this stage => the user launches the plugin with no time selections.
// // so, feed input with markers which have duration from MarkersManager
// auto markers = AwMarkerManager::instance()->getMarkers();
// for (auto m : markers) {
// if (m->duration() > 0.)
// process->pdi.input.addMarker(new AwMarker(m));
// }
// if (process->pdi.input.markers().isEmpty()) {
// int res = AwMessageBox::question(NULL, tr("Process Input"),
// tr("This process is designed to get time selections as input but none are set.\nThe process will be launched on the whole data."),
// QMessageBox::Ok | QMessageBox::Abort);
// if (res == QMessageBox::Abort) {
// process->plugin()->deleteInstance(process);
// return;
// }
// else {
// // create a marker as input which covers whole data
// process->pdi.input.addMarker(new AwMarker("whole data", 0., m_currentReader->infos.totalDuration()));
// }
// }
// }
//}
auto selectedChannels = AwDisplay::instance()->selectedChannels();
if (process->inputFlags() & Aw::ProcessInput::ProcessRequiresChannelSelection && selectedChannels.isEmpty()) {
AwMessageBox::critical(NULL, tr("Process Input"),
......
......@@ -31,6 +31,7 @@ void AwScriptPlugin::setNameAndDesc(const QString& n, const QString& desc)
{
name = n;
description = desc;
m_inputFlags = 0;
}
void AwScriptPlugin::initProcess(AwScriptProcess *p)
......@@ -39,8 +40,10 @@ void AwScriptPlugin::initProcess(AwScriptProcess *p)
p->pdi.input.pluginDirPath = m_pluginDir;
// Fixed input as any channels by default
if (!(m_flags & Aw::ProcessFlags::ProcessDoesntRequireData))
if (!(m_flags & Aw::ProcessFlags::ProcessDoesntRequireData)) {
p->pdi.addInputChannel(-1, 1, 0);
p->pdi.setInputFlags(m_inputFlags);
}
}
void AwScriptPlugin::checkIOForProcess(AwScriptProcess *p)
......
......@@ -58,8 +58,10 @@ public:
void initProcess(AwScriptProcess *process);
inline bool isCompiled() { return m_isCompiled; }
inline void setAsCompiled(bool f) { m_isCompiled = f; }
void setInputFlags(int flags) { m_inputFlags = flags; }
protected:
bool m_isCompiled;
int m_inputFlags; // input flags to set when instantiating the process.
void checkIOForProcess(AwScriptProcess *p);
QString m_path; // path to script or executable file
QString m_pluginDir; // path to the directory where the plugin is installed.
......
......@@ -61,6 +61,9 @@ qint64 BrainVisionIO::readDataFromChannels(float start, float duration, QList<Aw
if (channelList.isEmpty())
return 0;
if (duration <= 0)
return 0;
qint64 max_samples = 0;
qint64 nSamplesRead = 0;
......@@ -84,13 +87,6 @@ qint64 BrainVisionIO::readDataFromChannels(float start, float duration, QList<Aw
nSamples = infos.totalSamples() - nStart;
qint64 totalSize = nSamples * nbChannels;
if (channelList.isEmpty())
return 0;
if (duration <= 0)
return 0;
qint64 read = 0;
switch (m_binaryData)
......
......@@ -9,6 +9,7 @@
#include <QDebug>
#include <QSqlError>
#endif
#include <AwCore.h>
CompumedicsReaderPlugin::CompumedicsReaderPlugin() : AwFileIOPlugin()
{
......@@ -73,29 +74,6 @@ void CompumedicsReader::getResources(const QString& path)
AwFileIO::FileStatus CompumedicsReader::openFile(const QString &path)
{
getResources(path);
//// check for EEGData.ini => the only element, normaly, in m_iniFiles
//QFile EEGData(m_iniFiles.first());
//if (!EEGData.open(QIODevice::ReadOnly | QIODevice::Text)) {
// m_error = QString("Failed to open %1").arg(m_iniFiles.first());
// return AwFileIO::FileAccess;
//}
//quint64 nSamples;
//QTextStream stream(&EEGData);
//while (!stream.atEnd()) {
// auto line = stream.readLine();
// if (line.contains("size in samples")) {
// auto tokens = line.split("=");
// if (tokens.size() != 2) {
// m_error = QString("Wrong information in EEGData.ini");
// return AwFileIO::WrongFormat;
// }
// nSamples = tokens.value(1).toInt();
// break;
// }
//}
//EEGData.close();
// Open the binary data file
m_rdaFile.setFileName(m_rdaFiles.first());
if (!m_rdaFile.open(QIODevice::ReadOnly)) {
......@@ -127,6 +105,7 @@ AwFileIO::FileStatus CompumedicsReader::openFile(const QString &path)
}
sdyFile.close();
QHash<QString, AwChannel *> channels;
AwChannelList orderedChannels;
QDomElement root = doc.documentElement();
auto elements = root.elementsByTagName("Study");
if (elements.isEmpty()) {
......@@ -159,6 +138,7 @@ AwFileIO::FileStatus CompumedicsReader::openFile(const QString &path)
chan->setSamplingRate(m_samplingRate);
chan->setUnit(AwChannel::unitForType(AwChannel::EEG));
channels[name] = chan;
orderedChannels << chan;
}
}
// get creation date and time
......@@ -193,10 +173,10 @@ AwFileIO::FileStatus CompumedicsReader::openFile(const QString &path)
}
}
for (auto chan : channels.values()) {
for (auto chan : orderedChannels) {
infos.addChannel(chan);
delete chan;
}
AW_DESTROY_LIST(orderedChannels);
auto block = infos.newBlock();
block->setDuration(m_numSamples / m_samplingRate);
......
......@@ -140,7 +140,7 @@ qint64 DeltamedBTReader::readDataFromChannels(float start, float duration, QList
nSamples = infos.totalSamples() - nStart;
qint64 totalSize = nSamples * nbChannels;
m_file.seek(startSample);
m_file.seek(startSample * sizeof(qint16));
qint16 *buf = new qint16[totalSize];
qint64 read = m_file.read((char *)buf, totalSize * sizeof(qint16));
read /= sizeof(qint16);
......@@ -153,11 +153,9 @@ qint64 DeltamedBTReader::readDataFromChannels(float start, float duration, QList
foreach(AwChannel *c, channelList) {
int index = infos.indexOfChannel(c->name());
float *data = c->newData(read);
qint64 count = 0;
while (count < read) {
*data++ = (float)buf[index + count * nbChannels] * (m_gainsx1000[index] / 1000.);
count++;
}
float gf = (float)m_gainsx1000[index] / 1000.;
for (auto i = 0; i < read; i++)
c->data()[i] = (float)buf[index + i * nbChannels] * gf;
}
delete[] buf;
return read;
......
// AnyWave Marker File
m1 -1 1 0
m2 1 1.5 8
m3 5.5 1.53458 0
m3 5.5 1.5 0
m4 10 2 2
m5 22 5 0 A2,
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