org.eumetsat.metop.visat.SounderInfoView.java Source code

Java tutorial

Introduction

Here is the source code for org.eumetsat.metop.visat.SounderInfoView.java

Source

/* 
 * Copyright (C) 2002-2008 by Brockmann Consult
 *
 * 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. This program is distributed in the hope 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.eumetsat.metop.visat;

import com.bc.ceres.binio.CompoundData;
import com.bc.ceres.binio.CompoundMember;
import com.bc.ceres.binio.CompoundType;
import com.bc.ceres.binio.SequenceData;
import com.bc.ceres.glayer.Layer;
import com.bc.ceres.glayer.LayerListener;
import com.bc.ceres.glayer.support.AbstractLayerListener;
import org.esa.beam.framework.datamodel.GeoPos;
import org.esa.beam.framework.datamodel.ImageInfo;
import org.esa.beam.framework.datamodel.Scaling;
import org.esa.beam.framework.datamodel.Stx;
import org.esa.beam.framework.help.HelpSys;
import org.esa.beam.framework.ui.*;
import org.esa.beam.framework.ui.tool.ToolButtonFactory;
import org.esa.beam.framework.ui.application.support.AbstractToolView;
import org.esa.beam.framework.ui.product.ProductSceneView;
import org.esa.beam.visat.VisatApp;
import org.eumetsat.metop.eps.EpsFile;
import org.eumetsat.metop.eps.EpsMetaData;
import org.eumetsat.metop.sounder.Ifov;
import org.eumetsat.metop.sounder.SounderLayer;
import org.eumetsat.metop.sounder.SounderOverlay;
import org.eumetsat.metop.sounder.SounderOverlayListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.event.ChartProgressEvent;
import org.jfree.chart.event.ChartProgressListener;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

abstract class SounderInfoView extends AbstractToolView {
    private static final String NO_IFOV_SELECTED = "No IFOV selected";
    private static final String IO_ERROR = "IO error";

    private SounderOverlayListener overlayListener;
    private InternalFrameListener internalFrameListener;
    private XYSeriesCollection spectrumDataset;
    private JTextField latTextField;
    private JTextField lonTextField;
    private JTextField mdrIndexTextField;
    private JTextField ifovInMdrIndexTextField;
    private JTextField szaTextField;
    private JTextField saaTextField;
    private JTextField vzaTextField;
    private JTextField vaaTextField;
    private ImageInfoEditor editor;
    private XYPlot spectrumPlot;

    @Override
    protected JComponent createControl() {
        overlayListener = new SounderOverlayListener() {
            @Override
            public void selectionChanged(SounderOverlay overlay) {
                updateUI(overlay);
            }

            @Override
            public void dataChanged(SounderOverlay overlay) {
                updateUI(overlay);
            }
        };
        internalFrameListener = new InternalFrameAdapter() {
            @Override
            public void internalFrameActivated(final InternalFrameEvent e) {
                final Container contentPane = e.getInternalFrame().getContentPane();
                if (contentPane instanceof ProductSceneView) {
                    final ProductSceneView view = (ProductSceneView) contentPane;
                    final SounderLayer layer = getSounderLayer(view);

                    if (layer != null) {
                        layerChanged(layer);
                    } else {
                        final LayerListener layerListener = new AbstractLayerListener() {
                            @Override
                            public void handleLayersAdded(Layer parentLayer, Layer[] childLayers) {
                                final SounderLayer layer = getSounderLayer(view);
                                if (layer != null) {
                                    layerChanged(layer);
                                    view.getRootLayer().removeListener(this);
                                }
                            }
                        };
                        view.getRootLayer().addListener(layerListener);
                    }
                }
            }

            @Override
            public void internalFrameDeactivated(final InternalFrameEvent e) {
                final Container contentPane = e.getInternalFrame().getContentPane();
                if (contentPane instanceof ProductSceneView) {
                    final ProductSceneView view = (ProductSceneView) contentPane;
                    final SounderLayer layer = getSounderLayer(view);
                    if (layer != null) {
                        layer.getOverlay().removeListener(overlayListener);
                    }
                }
            }

            @Override
            public void internalFrameClosed(InternalFrameEvent e) {
                if (getSounderLayer() == null) {
                    clearUI();
                    editor.setModel(null);
                }
            }
        };
        VisatApp.getApp().addInternalFrameListener(internalFrameListener);

        final JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.add("Sounder Info", createInfoComponent());
        tabbedPane.add("Sounder Spectrum", createSpectrumChartComponent());
        tabbedPane.add("Sounder Layer", createSounderLayerComponent());

        final SounderLayer layer = getSounderLayer();
        if (layer != null) {
            layerChanged(layer);
        }

        final AbstractButton helpButton = ToolButtonFactory.createButton(UIUtils.loadImageIcon("icons/Help24.gif"),
                false);
        helpButton.setToolTipText("Help."); /*I18N*/
        helpButton.setName("helpButton");

        if (getDescriptor().getHelpId() != null) {
            HelpSys.enableHelpOnButton(helpButton, getDescriptor().getHelpId());
            HelpSys.enableHelpKey(tabbedPane, getDescriptor().getHelpId());
        }

        final JPanel containerPanel = new JPanel(new BorderLayout());
        containerPanel.add(tabbedPane, BorderLayout.CENTER);
        final JPanel buttonPanel = new JPanel(new BorderLayout());
        buttonPanel.add(helpButton, BorderLayout.EAST);
        containerPanel.add(buttonPanel, BorderLayout.SOUTH);

        return containerPanel;
    }

    private void layerChanged(SounderLayer layer) {
        layer.getOverlay().addListener(overlayListener);

        spectrumPlot.setDomainCrosshairValue(channelToCrosshairValue(layer.getSelectedChannel()));
        editor.setModel(createImageInfoEditorModel(layer));
        updateUI(layer.getOverlay());
    }

    @Override
    public void componentFocusGained() {
        final ProductSceneView view = VisatApp.getApp().getSelectedProductSceneView();
        if (MetopSounderVPI.isValidAvhrrProductSceneView(view)) {
            final SounderLayer layer = getSounderLayer();
            if (layer != null) {
                view.setSelectedLayer(layer);
            }
        }
    }

    @Override
    public void dispose() {
        VisatApp.getApp().removeInternalFrameListener(internalFrameListener);

        internalFrameListener = null;
        overlayListener = null;
        spectrumDataset = null;
        spectrumPlot = null;

        latTextField = null;
        lonTextField = null;

        mdrIndexTextField = null;
        ifovInMdrIndexTextField = null;

        szaTextField = null;
        saaTextField = null;
        vzaTextField = null;
        vaaTextField = null;
        editor = null;

        super.dispose();
    }

    protected abstract SounderLayer getSounderLayer(ProductSceneView view);

    private SounderLayer getSounderLayer() {
        final ProductSceneView view = VisatApp.getApp().getSelectedProductSceneView();

        if (view == null) {
            return null;
        }

        return getSounderLayer(view);
    }

    protected abstract XYSeries createSpectrumPlotXYSeries(double[] radiances);

    protected abstract int crosshairValueToChannel(double value);

    protected abstract double channelToCrosshairValue(int channel);

    protected void configureSpectrumChart(JFreeChart chart) {
        chart.setBackgroundPaint(Color.white);
    }

    protected void configureSpectrumPlot(XYPlot plot) {
        plot.setBackgroundPaint(Color.lightGray);
        plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);

        plot.setDomainCrosshairVisible(true);
        plot.setDomainCrosshairLockedOnData(true);
        plot.setRangeCrosshairVisible(false);
        plot.setNoDataMessage(NO_IFOV_SELECTED);
    }

    protected void configureSpectrumPlotRenderer(XYLineAndShapeRenderer renderer) {
        renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());

        renderer.setSeriesShape(0, new Ellipse2D.Double(-3.0, -3.0, 6.0, 6.0));
        renderer.setSeriesShapesVisible(0, true);
        renderer.setSeriesShapesFilled(0, true);
    }

    protected void configureSpectrumPlotXAxis(NumberAxis axis) {
        axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
    }

    protected void configureSpectrumPlotYAxis(NumberAxis axis) {
        axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
    }

    protected void configureSpectrumChartPanel(ChartPanel chartPanel) {
        chartPanel.setMinimumDrawHeight(0);
        chartPanel.setMaximumDrawHeight(20000);
        chartPanel.setMinimumDrawWidth(0);
        chartPanel.setMaximumDrawWidth(20000);
        chartPanel.setPreferredSize(new Dimension(400, 200));
    }

    private Component createInfoComponent() {
        latTextField = new JTextField();
        latTextField.setEditable(false);
        lonTextField = new JTextField();
        lonTextField.setEditable(false);
        mdrIndexTextField = new JTextField();
        mdrIndexTextField.setEditable(false);
        ifovInMdrIndexTextField = new JTextField();
        ifovInMdrIndexTextField.setEditable(false);
        szaTextField = new JTextField();
        szaTextField.setEditable(false);
        saaTextField = new JTextField();
        saaTextField.setEditable(false);
        vzaTextField = new JTextField();
        vzaTextField.setEditable(false);
        vaaTextField = new JTextField();
        vaaTextField.setEditable(false);

        final TableLayout layout = new TableLayout(3);
        layout.setTableAnchor(TableLayout.Anchor.NORTHWEST);
        layout.setTableFill(TableLayout.Fill.BOTH);
        layout.setColumnWeightX(0, 0.0);
        layout.setColumnWeightX(1, 0.8);
        layout.setColumnWeightX(2, 1.0);
        layout.setTablePadding(3, 3);

        final JPanel panel = new JPanel(layout);
        panel.add(new JLabel("Latitude:"));
        panel.add(latTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("Longitude:"));
        panel.add(lonTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("MDR index:"));
        panel.add(mdrIndexTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("Ifov index:"));
        panel.add(ifovInMdrIndexTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("Sun zenith:"));
        panel.add(szaTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("Sun azimuth:"));
        panel.add(saaTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("View zenith:"));
        panel.add(vzaTextField);
        panel.add(new JLabel(""));

        panel.add(new JLabel("View azimuth:"));
        panel.add(vaaTextField);
        panel.add(new JLabel(""));

        final JPanel containerPanel = new JPanel(new BorderLayout(4, 4));
        containerPanel.add(panel, BorderLayout.NORTH);

        clearEarthLocationFields(NO_IFOV_SELECTED);
        clearIndexFields(NO_IFOV_SELECTED);
        clearAngularRelationFields(NO_IFOV_SELECTED);

        return containerPanel;
    }

    private JComponent createSpectrumChartComponent() {
        spectrumDataset = new XYSeriesCollection();

        final JFreeChart chart = ChartFactory.createXYLineChart("Sounder IFOV Spectrum", // chart title
                "Channel", // x axis label
                "Brightness Temperature (K)", // y axis label
                spectrumDataset, PlotOrientation.VERTICAL, false, // include legend
                true, // tooltips
                false // urls
        );
        chart.addProgressListener(new DomainCrosshairListener());
        configureSpectrumChart(chart);

        spectrumPlot = chart.getXYPlot();
        configureSpectrumPlot(spectrumPlot);
        configureSpectrumPlotRenderer((XYLineAndShapeRenderer) spectrumPlot.getRenderer());
        configureSpectrumPlotYAxis((NumberAxis) spectrumPlot.getRangeAxis());
        configureSpectrumPlotXAxis((NumberAxis) spectrumPlot.getDomainAxis());

        final ChartPanel chartPanel = new ChartPanel(chart);
        configureSpectrumChartPanel(chartPanel);

        final JPanel containerPanel = new JPanel(new BorderLayout(4, 4));
        containerPanel.add(chartPanel);

        return containerPanel;
    }

    private class DomainCrosshairListener implements ChartProgressListener {
        @Override
        public void chartProgress(ChartProgressEvent event) {
            if (event.getType() != ChartProgressEvent.DRAWING_FINISHED) {
                return;
            }
            final double value = event.getChart().getXYPlot().getDomainCrosshairValue();
            if (value > 0.0) {
                final SounderLayer layer = getSounderLayer();
                if (layer != null) {
                    final int channel = crosshairValueToChannel(value);
                    if (channel != layer.getSelectedChannel()) {
                        final SwingWorker<Object, Object> worker = new SwingWorker<Object, Object>() {
                            @Override
                            protected Object doInBackground() throws Exception {
                                layer.setSelectedChannel(channel);
                                return null;
                            }

                            @Override
                            protected void done() {
                                layer.regenerate();
                                editor.setModel(createImageInfoEditorModel(layer));
                            }
                        };
                        worker.execute();
                    } else {
                        if (editor.getModel() == null) {
                            editor.setModel(createImageInfoEditorModel(layer));
                        }
                    }
                }
            }
        }
    }

    private Component createSounderLayerComponent() {
        editor = new ImageInfoEditor();

        final JPanel containerPanel = new JPanel(new BorderLayout(4, 4));
        containerPanel.add(editor, BorderLayout.NORTH);

        final SounderLayer layer = getSounderLayer();
        if (layer != null) {
            editor.setModel(createImageInfoEditorModel(layer));
        }

        return containerPanel;
    }

    private ImageInfoEditorModel createImageInfoEditorModel(final SounderLayer layer) {
        final ImageInfo imageInfo = layer.getImageInfo();
        final ImageInfoEditorModel editorModel = new DefaultImageInfoEditorModel(imageInfo);

        final Stx stx = layer.getStx();
        final Scaling scaling = layer.getScaling();

        editorModel.setDisplayProperties("", "", stx, scaling);
        editorModel.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                layer.regenerate();
            }
        });

        return editorModel;
    }

    protected void updateUI(final SounderOverlay overlay) {
        if (overlay.getSelectedIfov() != null) {
            final Ifov selectedIfov = overlay.getSelectedIfov();
            updateEarthLocationFields(selectedIfov, overlay.getEpsFile());
            updateIndexFields(selectedIfov);
            updateAngularRelationFields(selectedIfov, overlay.getEpsFile());
            updateSpectrumDataset(overlay.getSelectedIfov(), overlay.getEpsFile());
        } else {
            clearUI();
        }
    }

    private void updateIndexFields(Ifov selectedIfov) {
        mdrIndexTextField.setText(Integer.toString(selectedIfov.getMdrIndex()));
        ifovInMdrIndexTextField.setText(Integer.toString(selectedIfov.getIfovInMdrIndex()));
    }

    private void updateEarthLocationFields(final Ifov selectedIfov, final EpsFile epsFile) {
        final SwingWorker<GeoPos, Object> worker = new SwingWorker<GeoPos, Object>() {
            @Override
            protected GeoPos doInBackground() throws Exception {
                return readEarthLocation(epsFile, selectedIfov);
            }

            @Override
            protected void done() {
                try {
                    final GeoPos geoPos = get();
                    lonTextField.setText(geoPos.getLonString());
                    latTextField.setText(geoPos.getLatString());
                } catch (InterruptedException e) {
                    clearEarthLocationFields(IO_ERROR);
                } catch (ExecutionException e) {
                    clearEarthLocationFields(IO_ERROR);
                }
            }
        };
        worker.execute();
    }

    private void updateAngularRelationFields(final Ifov selectedIfov, final EpsFile epsFile) {
        final SwingWorker<AngularRelation, Object> worker = new SwingWorker<AngularRelation, Object>() {
            @Override
            protected AngularRelation doInBackground() throws Exception {
                return readAngularRelation(epsFile, selectedIfov);
            }

            @Override
            protected void done() {
                try {
                    final AngularRelation angularRelation = get();
                    vzaTextField.setText(Double.toString(angularRelation.vza));
                    vaaTextField.setText(Double.toString(angularRelation.vaa));
                    szaTextField.setText(Double.toString(angularRelation.sza));
                    saaTextField.setText(Double.toString(angularRelation.saa));
                } catch (InterruptedException e) {
                    clearAngularRelationFields(IO_ERROR);
                } catch (ExecutionException e) {
                    clearAngularRelationFields(IO_ERROR);
                }
            }
        };
        worker.execute();
    }

    private void clearIndexFields(String text) {
        mdrIndexTextField.setText(text);
        ifovInMdrIndexTextField.setText(text);
    }

    private void clearEarthLocationFields(String text) {
        lonTextField.setText(text);
        latTextField.setText(text);
    }

    private void clearAngularRelationFields(String text) {
        saaTextField.setText(text);
        vaaTextField.setText(text);
        szaTextField.setText(text);
        vzaTextField.setText(text);
    }

    private void clearUI() {
        clearEarthLocationFields(NO_IFOV_SELECTED);
        clearIndexFields(NO_IFOV_SELECTED);
        clearAngularRelationFields(NO_IFOV_SELECTED);
        spectrumDataset.removeAllSeries();
        spectrumPlot.setNoDataMessage(NO_IFOV_SELECTED);
    }

    private void updateSpectrumDataset(final Ifov selectedIfov, final EpsFile epsFile) {
        final SwingWorker<XYSeries, Object> worker = new SwingWorker<XYSeries, Object>() {
            @Override
            protected XYSeries doInBackground() throws Exception {
                return createSpectrumPlotXYSeries(readSceneRadiances(epsFile, selectedIfov));
            }

            @Override
            protected void done() {
                try {
                    spectrumDataset.removeAllSeries();
                    final XYSeries series = get();
                    spectrumDataset.addSeries(series);
                } catch (InterruptedException e) {
                    spectrumPlot.setNoDataMessage(IO_ERROR);
                } catch (ExecutionException e) {
                    spectrumPlot.setNoDataMessage(IO_ERROR);
                }
            }
        };
        worker.execute();
    }

    protected abstract GeoPos readEarthLocation(EpsFile sounderFile, Ifov ifov) throws IOException;

    protected abstract AngularRelation readAngularRelation(EpsFile sounderFile, Ifov ifov) throws IOException;

    protected abstract double[] readSceneRadiances(EpsFile sounderFile, Ifov ifov) throws IOException;

    protected static GeoPos readEarthLocation(EpsFile sounderFile, String sequenceName, Ifov ifov)
            throws IOException {
        final NumberData numberData = getNumberData(sounderFile, sequenceName, ifov);

        final float factor = getScalingFactor(sounderFile, sequenceName).floatValue();
        final float lat = numberData.getNumber(0).floatValue() / factor;
        final float lon = numberData.getNumber(1).floatValue() / factor;

        return new GeoPos(lat, lon);
    }

    protected static AngularRelation readAngularRelation(EpsFile sounderFile, String sequenceName, Ifov ifov)
            throws IOException {
        final NumberData numberData = getNumberData(sounderFile, sequenceName, ifov);

        final double factor = getScalingFactor(sounderFile, sequenceName).doubleValue();
        final double sza = numberData.getNumber(0).doubleValue() / factor;
        final double vza = numberData.getNumber(1).doubleValue() / factor;
        final double saa = numberData.getNumber(2).doubleValue() / factor;
        final double vaa = numberData.getNumber(3).doubleValue() / factor;

        return new AngularRelation(sza, vza, saa, vaa);
    }

    protected static double[] readSceneRadiances(EpsFile sounderFile, String sequenceName, Ifov ifov)
            throws IOException {
        final NumberData numberData = getNumberData(sounderFile, sequenceName, ifov);

        final double factor = getScalingFactor(sounderFile, sequenceName).doubleValue();
        final double[] radiances = new double[numberData.getElementCount()];
        for (int i = 0; i < radiances.length; i++) {
            radiances[i] = numberData.getNumber(i).doubleValue() / factor;
        }

        return radiances;
    }

    protected static EpsMetaData getMetaData(EpsFile sounderFile, String sequenceName) throws IOException {
        final CompoundData compoundData = getCompoundData(sounderFile, 0);
        final CompoundType compoundType = compoundData.getCompoundType();
        final CompoundMember compoundMember = compoundType.getMember(compoundType.getMemberIndex(sequenceName));

        return (EpsMetaData) compoundMember.getMetadata();
    }

    protected static Number getScalingFactor(EpsFile sounderFile, String sequenceName) throws IOException {
        try {
            return Double.valueOf(getMetaData(sounderFile, sequenceName).getScalingFactor().replace("10^", "1.0E"));
        } catch (NumberFormatException e) {
            throw new IOException(e.getMessage(), e);
        }
    }

    protected static NumberData getNumberData(EpsFile sounderFile, String sequenceName, Ifov ifov)
            throws IOException {
        return NumberData.of(getSequenceData(sounderFile, sequenceName, ifov));
    }

    protected static SequenceData getSequenceData(EpsFile sounderFile, String sequenceName, Ifov ifov)
            throws IOException {
        return getCompoundData(sounderFile, ifov.getMdrIndex()).getSequence(sequenceName)
                .getSequence(ifov.getIfovInMdrIndex());
    }

    protected static CompoundData getCompoundData(EpsFile sounderFile, int mdrIndex) throws IOException {
        final SequenceData data = sounderFile.getMdrData();
        if (data != null) {
            return data.getCompound(mdrIndex).getCompound(1);
        }

        throw new IOException("No MDR.");
    }

    protected static class AngularRelation {
        // solar-zenith
        public final double vza;
        // sat-zenith
        public final double saa;
        // solar-azimuth
        public final double vaa;
        // sat-azimuth
        public final double sza;

        private AngularRelation(double sza, double vza, double saa, double vaa) {
            this.sza = sza;
            this.vza = vza;
            this.saa = saa;
            this.vaa = vaa;
        }
    }
}