package pl.edu.fuw.fid.signalanalysis.wavelet; import pl.edu.fuw.fid.signalanalysis.logaxis.LogarithmicAxis; import java.io.IOException; import java.net.URL; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.Event; import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; import javafx.geometry.Pos; import javafx.scene.chart.NumberAxis; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Slider; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.util.StringConverter; import org.signalml.app.view.book.wignermap.WignerMapPalette; import org.signalml.plugin.export.NoActiveObjectException; import org.signalml.plugin.export.signal.ChannelSamples; import org.signalml.plugin.export.signal.ExportedSignalSelection; import org.signalml.plugin.export.signal.SvarogAccessSignal; import pl.edu.fuw.fid.signalanalysis.SignalAnalysisTools; import pl.edu.fuw.fid.signalanalysis.SimpleSingleSignal; import pl.edu.fuw.fid.signalanalysis.waveform.ImageChart; import pl.edu.fuw.fid.signalanalysis.SingleSignal; import pl.edu.fuw.fid.signalanalysis.waveform.ImageRefresher; import pl.edu.fuw.fid.signalanalysis.waveform.SignalChart; import pl.edu.fuw.fid.signalanalysis.waveform.TimeFrequency; /** * User interface for interactive Wavelet Transform. * * @author ptr@mimuw.edu.pl */ public class PaneForWavelet { private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(PaneForWavelet.class); final BorderPane root; final ObservableList<MotherWavelet> waveletTypeItems; final ObservableList<WignerMapPalette> paletteTypeItems; final ObservableList<String> frequencyScaleItems; final ImageChart linChart, logChart; final ImageRendererForWavelet renderer; final ImageRefresher refresher; private ImageChart theChart; private MotherWavelet createWavelet(MotherWavelet wavelet, double param) { if (wavelet instanceof ParamWavelet) try { Class<? extends MotherWavelet> cl = wavelet.getClass(); wavelet = cl.getConstructor(Double.class).newInstance(param); } catch (Exception ex) { logger.error("wavelet class does not have a proper constructor", ex); } return wavelet; } private void setWavelet(MotherWavelet wavelet, double param) { wavelet = createWavelet(wavelet, param); renderer.setWavelet(wavelet); refresher.refreshChartImage(theChart); } public PaneForWavelet(SvarogAccessSignal signalAccess, ExportedSignalSelection selection) throws IOException, NoActiveObjectException { root = new BorderPane(); paletteTypeItems = FXCollections.observableArrayList( WignerMapPalette.RAINBOW, WignerMapPalette.GRAYSCALE ); waveletTypeItems = FXCollections.observableArrayList( new GaborWavelet(1.0), new ShannonWavelet(), new HaarWavelet() ); frequencyScaleItems = FXCollections.observableArrayList( "linear", "logarithmic" ); URL url = getClass().getResource("SettingsPanelForWavelet.fxml"); FXMLLoader fxmlLoader = new FXMLLoader(url); VBox settingsPanel = (VBox) fxmlLoader.load(); final ComboBox paletteType = (ComboBox) fxmlLoader.getNamespace().get("paletteTypeComboBox"); paletteType.setItems(paletteTypeItems); final CheckBox paletteInvert = (CheckBox) fxmlLoader.getNamespace().get("paletteInvertCheckBox"); final ComboBox waveletType = (ComboBox) fxmlLoader.getNamespace().get("waveletTypeComboBox"); waveletType.setItems(waveletTypeItems); waveletType.setConverter(new StringConverter() { @Override public String toString(Object object) { MotherWavelet wavelet = (MotherWavelet) object; return wavelet.getLabel(); } @Override public Object fromString(String string) { logger.fatal("fromString called on StringConverter"); return null; } }); final int selectedChannel = Math.max(selection.getChannel(), 0); final ChannelSamples samples = signalAccess.getActiveProcessedSignalSamples(selectedChannel); final double samplingFrequency = samples.getSamplingFrequency(); final double nyquistFrequency = 0.5 * samplingFrequency; final double minFrequency = SignalAnalysisTools.MIN_WAVELET_FREQ; double tMin = selection.getPosition(); double tMax = selection.getEndPosition(); final NumberAxis xAxis = new NumberAxis(tMin, tMax, 1.0); final NumberAxis linAxis = new NumberAxis(minFrequency, nyquistFrequency, 10.0); linAxis.setPrefWidth(50); final LogarithmicAxis logAxis = new LogarithmicAxis(); logAxis.setPrefWidth(50); logAxis.setLowerBound(minFrequency); // Hz logAxis.setUpperBound(nyquistFrequency); final Slider maxFrequency = (Slider) fxmlLoader.getNamespace().get("frequencyMaxSlider"); maxFrequency.setMin(minFrequency); // Hz maxFrequency.setMax(nyquistFrequency); maxFrequency.setValue(nyquistFrequency); maxFrequency.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { double maxFreq = Math.round(newValue.doubleValue()); linAxis.setUpperBound(maxFreq); logAxis.setUpperBound(maxFreq); } }); SingleSignal signal = new SimpleSingleSignal(samples); renderer = new ImageRendererForWavelet(signal); refresher = new ImageRefresher(renderer); final ComboBox freqScale = (ComboBox) fxmlLoader.getNamespace().get("frequencyScaleComboBox"); freqScale.setItems(frequencyScaleItems); freqScale.getSelectionModel().select(0); freqScale.valueProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { boolean logScale = newValue.equals("logarithmic"); if (logScale) { linChart.setVisible(false); linChart.hideImage(); theChart = logChart; } else { logChart.setVisible(false); logChart.hideImage(); theChart = linChart; } theChart.setVisible(true); renderer.setLogScale(logScale); refresher.refreshChartImage(theChart); } }); Runnable onResize = new Runnable() { @Override public void run() { refresher.refreshChartImage(theChart); } }; linChart = new ImageChart(xAxis, linAxis, renderer, onResize); logChart = new ImageChart(xAxis, logAxis, renderer, onResize); linChart.setVisible(true); logChart.setVisible(false); theChart = linChart; waveletType.getSelectionModel().select(renderer.getWavelet()); paletteType.getSelectionModel().select(renderer.getPaletteType()); final NumberAxis xAxisSignal = new NumberAxis(tMin, tMax, 1.0); final NumberAxis yAxisSignal = new NumberAxis(); xAxisSignal.setLabel("time [s]"); yAxisSignal.setLabel("value [µV]"); yAxisSignal.setPrefWidth(50); final SignalChart signalChart = new SignalChart(signal, tMin, tMax, xAxisSignal, yAxisSignal); final Slider waveletParam = (Slider) fxmlLoader.getNamespace().get("waveletParamSlider"); waveletParam.setValue(GaborWavelet.DEFAULT_WIDTH); waveletParam.valueProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { MotherWavelet wavelet = (MotherWavelet) waveletType.getSelectionModel().getSelectedItem(); if (wavelet != null) { setWavelet(wavelet, newValue.doubleValue()); } } }); waveletType.setOnAction(new EventHandler() { @Override public void handle(Event event) { double newValue = waveletParam.getValue(); MotherWavelet wavelet = (MotherWavelet) waveletType.getSelectionModel().getSelectedItem(); if (wavelet != null) { waveletParam.setDisable(!(wavelet instanceof ParamWavelet)); setWavelet(wavelet, newValue); } } }); paletteType.setOnAction(new EventHandler() { @Override public void handle(Event event) { WignerMapPalette pt = (WignerMapPalette) paletteType.getSelectionModel().getSelectedItem(); if (pt != null) { renderer.setPaletteType(pt); refresher.refreshChartImage(theChart); } } }); paletteInvert.setOnAction(new EventHandler() { @Override public void handle(Event event) { boolean inverted = paletteInvert.isSelected(); renderer.setInverted(inverted); refresher.refreshChartImage(theChart); } }); for (final ImageChart chart : new ImageChart[] { linChart, logChart }) { chart.setOnCursorOffChart(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { signalChart.clearWaveform(); } }); chart.setOnCursorOnChart(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent event) { double newValue = waveletParam.getValue(); MotherWavelet mv = (MotherWavelet) waveletType.getSelectionModel().getSelectedItem(); mv = createWavelet(mv, newValue); TimeFrequency tf = chart.getTimeFrequency((int)event.getX(), (int)event.getY()); if (mv != null && tf != null) { signalChart.setWaveform(mv.scale(tf.f), null, tf.t, tf.v); } } }); } StackPane stack = new StackPane(); stack.getChildren().addAll( linChart, logChart, refresher.getProgressIndicator() ); stack.setAlignment(Pos.CENTER); BorderPane main = new BorderPane(); main.setCenter(stack); main.setBottom(signalChart); root.setCenter(main); root.setLeft(settingsPanel); } public Pane getPane() { return root; } }