package pl.edu.fuw.fid.signalanalysis.waveform; import java.awt.Window; import java.awt.event.ActionEvent; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.swing.JOptionPane; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; import org.signalml.app.document.signal.SignalDocument; import org.signalml.app.method.ep.view.tags.TagStyleGroup; import org.signalml.method.bookaverage.TimeFrequencyMapPresenter; import org.signalml.plugin.export.NoActiveObjectException; import org.signalml.plugin.export.signal.ExportedSignalSelection; import org.signalml.plugin.export.signal.SvarogAccessSignal; import org.signalml.plugin.export.signal.Tag; import org.signalml.plugin.export.view.AbstractSignalMLAction; import org.signalml.plugin.export.view.SvarogAccessGUI; import pl.edu.fuw.fid.signalanalysis.AsyncStatus; import pl.edu.fuw.fid.signalanalysis.SimpleSingleSignal; import pl.edu.fuw.fid.signalanalysis.SingleSignal; /** * Base class for action requesting computation of averaged time-frequency maps. * * @author ptr@mimuw.edu.pl */ public class AveragedBaseAction<P> extends AbstractSignalMLAction { private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(AveragedBaseAction.class); private final SvarogAccessGUI guiAccess; private final SvarogAccessSignal signalAccess; private final AveragedBaseDialog dialog; private final Class<? extends ImageRenderer<P>> clazz; public AveragedBaseAction(SvarogAccessGUI guiAccess, SvarogAccessSignal signalAccess, Class<? extends AveragedBaseDialog> dialogClass, Class<? extends ImageRenderer<P>> rendererClass) throws NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { super(); this.guiAccess = guiAccess; this.signalAccess = signalAccess; this.dialog = dialogClass.getConstructor(Window.class, Boolean.class).newInstance(guiAccess.getDialogParent(), true); this.clazz = rendererClass; setText("averaged"); } @Override public void actionPerformed(ActionEvent arg0) { try { // This method is invoked on Swing thread SignalDocument signalDocument = (SignalDocument) signalAccess.getActiveSignalDocument(); AveragedBaseModel<P> model = new AveragedBaseModel<P>(signalDocument); if (dialog.showDialog(model)) { final List<SingleSignal> signals = new LinkedList<SingleSignal>(); final int[] channels = model.selectedChannels; final SingleSignal[] samples = new SimpleSingleSignal[channels.length]; for (int i=0; i<channels.length; ++i) { samples[i] = new SimpleSingleSignal(signalAccess.getActiveProcessedSignalSamples(channels[i])); } Set<String> tagStyleNames = new HashSet<String>(); for (TagStyleGroup tagStyleGroup : model.selectedTags) { tagStyleNames.addAll(tagStyleGroup.getTagStyleNames()); } for (Tag tag : signalDocument.getActiveTag().getTagSet().getTags()) { if (tagStyleNames.contains(tag.getStyle().getName())) { for (int i=0; i<channels.length; ++i) { final int fi = i; int channel = channels[i]; if (tag.getChannel() == ExportedSignalSelection.CHANNEL_NULL || tag.getChannel() == channel) { final int offset = (int) Math.round(tag.getPosition() * samples[fi].getSamplingFrequency()); signals.add(new SingleSignal() { @Override public void getSamples(int start, int length, double[] buffer) { samples[fi].getSamples(start + offset, length, buffer); } @Override public double getSamplingFrequency() { return samples[fi].getSamplingFrequency(); } }); } } } } final PreferencesWithAxes<P> preferences = model.preferences; final ProgressMonitor progressMonitor = new ProgressMonitor(guiAccess.getDialogParent(), "Computing...", null, 0, signals.size()); progressMonitor.setMillisToDecideToPopup(100); progressMonitor.setMillisToPopup(500); final AsyncStatus status = new AsyncStatus() { @Override public boolean isCancelled() { return progressMonitor.isCanceled(); } @Override public void setProgress(double progress) { // nothing here } }; new Thread(new Runnable() { @Override public void run() { try { final double[][] values = new double[preferences.width][preferences.height]; int progress = 0; String title = ""; for (SingleSignal signal : signals) { final ImageRenderer<P> renderer = clazz.getConstructor(SingleSignal.class).newInstance(signal); final ImageResult result = renderer.compute(preferences, status); if (status.isCancelled()) { return; } for (int ix=0; ix<preferences.width; ++ix) { for (int iy=0; iy<preferences.height; ++iy) { values[ix][iy] += result.values[ix][iy].abs(); } } title = result.title; progressMonitor.setProgress(progress++); } double max = 0.0; for (int ix=0; ix<preferences.width; ++ix) { for (int iy=0; iy<preferences.height; ++iy) { max = Math.max(max, values[ix][iy]); } } if (max > 0) { for (int ix=0; ix<preferences.width; ++ix) { for (int iy=0; iy<preferences.height; ++iy) { values[ix][iy] /= max; } } } final String titleFinal = title; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { progressMonitor.close(); TimeFrequencyMapPresenter presenter = new TimeFrequencyMapPresenter(guiAccess.getDialogParent()); presenter.showResults(titleFinal, values, preferences.yMin, preferences.yMax, preferences.xMax - preferences.xMin); } }); } catch (final Exception ex) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { progressMonitor.close(); JOptionPane.showMessageDialog(guiAccess.getDialogParent(), ex, "Error", JOptionPane.ERROR_MESSAGE); } }); } } }).start(); } } catch (NoActiveObjectException ex) { JOptionPane.showMessageDialog(null, "Select valid single-channel signal fragment.", "Error", JOptionPane.ERROR_MESSAGE); } } }