// This file is part of PleoCommand:
// Interactively control Pleo with psychobiological parameters
//
// Copyright (C) 2010 Oliver Hoffmann - Hoffmann_Oliver@gmx.de
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Boston, USA.
package pleocmd.pipe.cvt;
import java.util.ArrayList;
import java.util.List;
import pleocmd.RunnableWithArgument;
import pleocmd.cfg.ConfigDouble;
import pleocmd.cfg.ConfigEnum;
import pleocmd.exc.ConverterException;
import pleocmd.itfc.gui.dgr.DiagramDataSet;
import pleocmd.pipe.data.Data;
import pleocmd.pipe.data.SingleFloatData;
public final class BCICodomainAdaption extends Converter { // NO_UCD
private enum OutOfRangeBehavior {
CutOff, FitToRange
}
private enum Transformation {
Linear
}
private final ConfigDouble cfgSourceMin;
private final ConfigDouble cfgSourceMax;
private final ConfigDouble cfgTargetMin;
private final ConfigDouble cfgTargetMax;
private final ConfigEnum<OutOfRangeBehavior> cfgOutOfRange;
private final ConfigEnum<Transformation> cfgTransformation;
private double dec;
private double inc;
private double fl; // factor for linear transformation
public BCICodomainAdaption() {
addConfig(cfgSourceMin = new ConfigDouble("Source-Minimum", -1000));
addConfig(cfgSourceMax = new ConfigDouble("Source-Maximum", 1000));
addConfig(cfgTargetMin = new ConfigDouble("Target-Minimum", -64));
addConfig(cfgTargetMax = new ConfigDouble("Target-Maximum", 64));
addConfig(cfgOutOfRange = new ConfigEnum<OutOfRangeBehavior>(
"OutOfRange-Behavior", OutOfRangeBehavior.class));
addConfig(cfgTransformation = new ConfigEnum<Transformation>(
"Transformation-Type", Transformation.class));
cfgSourceMin.setChangingContent(new RunnableWithArgument() {
@Override
public Object run(final Object... args) {
final double min = (Double) args[0];
final double max = getCfgSourceMax().getContentGUI();
if (min >= max) getCfgSourceMax().setContentGUI(min + 1);
return null;
}
});
cfgSourceMax.setChangingContent(new RunnableWithArgument() {
@Override
public Object run(final Object... args) {
final double min = getCfgSourceMin().getContentGUI();
final double max = (Double) args[0];
if (min >= max) getCfgSourceMin().setContentGUI(max - 1);
return null;
}
});
cfgTargetMin.setChangingContent(new RunnableWithArgument() {
@Override
public Object run(final Object... args) {
final double min = (Double) args[0];
final double max = getCfgTargetMax().getContentGUI();
if (min >= max) getCfgTargetMax().setContentGUI(min + 1);
return null;
}
});
cfgTargetMax.setChangingContent(new RunnableWithArgument() {
@Override
public Object run(final Object... args) {
final double min = getCfgTargetMin().getContentGUI();
final double max = (Double) args[0];
if (min >= max) getCfgTargetMin().setContentGUI(max - 1);
return null;
}
});
constructed();
}
@Override
protected void configure1() {
dec = cfgSourceMin.getContent();
inc = cfgTargetMin.getContent();
fl = (cfgTargetMax.getContent() - cfgTargetMin.getContent())
/ (cfgSourceMax.getContent() - cfgSourceMin.getContent());
}
@Override
protected void initVisualize0() {
final DiagramDataSet ds = getVisualizeDataSet(0);
if (ds != null) ds.setLabel("Codomain adapted");
}
@Override
public String getInputDescription() {
return SingleFloatData.IDENT;
}
@Override
public String getOutputDescription() {
return SingleFloatData.IDENT;
}
@Override
protected String getShortConfigDescr0() {
return String.format("[%s-%s]=>[%s-%s]", cfgSourceMin.asString(),
cfgSourceMax.asString(), cfgTargetMin.asString(),
cfgTargetMax.asString());
}
@Override
protected List<Data> convert0(final Data data) throws ConverterException {
if (!SingleFloatData.isSingleFloatData(data)) return null;
double val = SingleFloatData.getValue(data);
switch (cfgOutOfRange.getEnum()) {
case CutOff:
// return empty list, so "data" is just dropped
if (val < cfgSourceMin.getContent()
|| val > cfgSourceMax.getContent())
return new ArrayList<Data>(0);
break;
case FitToRange:
if (val < cfgSourceMin.getContent())
val = cfgSourceMin.getContent();
if (val > cfgSourceMax.getContent())
val = cfgSourceMax.getContent();
break;
}
switch (cfgTransformation.getEnum()) {
case Linear:
val = (val - dec) * fl + inc;
break;
}
if (isVisualize()) plot(0, val);
return asList(SingleFloatData.create(val, data));
}
public static String help(final HelpKind kind) {
switch (kind) {
case Name:
return "Codomain Adaption";
case Description:
return "Reduces or enlarges the range of possible values for a "
+ "single channel";
case Config1:
return "Minimum value of source range";
case Config2:
return "Maximum value of source range";
case Config3:
return "Minimum value of target range";
case Config4:
return "Maximum value of target range";
case Config5:
return "Whether to fit values out of the source range to min/max "
+ "or just drop the data block";
case Config6:
return "Kind of transformation from source range to target range";
default:
return null;
}
}
@Override
public String isConfigurationSane() {
if (cfgSourceMin.getContent() >= cfgSourceMax.getContent())
return String.format("%d must be less than %d in source range",
cfgSourceMin.getContent(), cfgSourceMax.getContent());
if (cfgTargetMin.getContent() >= cfgTargetMax.getContent())
return String.format("%d must be less than %d in target range",
cfgTargetMin.getContent(), cfgTargetMax.getContent());
return null;
}
@Override
protected int getVisualizeDataSetCount() {
return 1;
}
protected ConfigDouble getCfgSourceMin() {
return cfgSourceMin;
}
protected ConfigDouble getCfgSourceMax() {
return cfgSourceMax;
}
protected ConfigDouble getCfgTargetMin() {
return cfgTargetMin;
}
protected ConfigDouble getCfgTargetMax() {
return cfgTargetMax;
}
}