org.esa.s1tbx.dat.views.polarview.PolarView.java Source code

Java tutorial

Introduction

Here is the source code for org.esa.s1tbx.dat.views.polarview.PolarView.java

Source

/*
 * Copyright (C) 2014 by Array Systems Computing Inc. http://www.array.ca
 *
 * 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 3 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, see http://www.gnu.org/licenses/
 */
package org.esa.s1tbx.dat.views.polarview;

import org.apache.commons.math3.util.FastMath;
import org.esa.snap.datamodel.AbstractMetadata;
import org.esa.snap.framework.datamodel.MetadataElement;
import org.esa.snap.framework.datamodel.Product;
import org.esa.snap.framework.datamodel.ProductData;
import org.esa.snap.framework.datamodel.ProductNode;
import org.esa.snap.framework.datamodel.RasterDataNode;
import org.esa.snap.framework.ui.BasicView;
import org.esa.snap.framework.ui.product.ProductNodeView;
import org.esa.snap.framework.ui.product.ProductSceneImage;
import org.esa.snap.rcp.SnapDialogs;
import org.esa.snap.util.FileFolderUtils;

import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.border.BevelBorder;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * NEST
 * User: lveci
 * Date: Dec 1, 2008
 */
public final class PolarView extends BasicView
        implements ProductNodeView, ActionListener, PopupMenuListener, MouseListener, MouseMotionListener {

    private final Product product;
    private ProductSceneImage sceneImage;
    private MetadataElement spectraMetadataRoot = null;

    private final int numRecords;
    private final int recordLength;
    private int numDirBins;
    private int numWLBins;

    private float firstDirBins = 0;
    private float dirBinStep = 0;
    private float firstWLBin = 0;
    private float lastWLBin = 0;
    private final double minRadius = -10;

    private ProductData.UTC zeroDopplerTime = null;
    private double minSpectrum = 0;
    private double maxSpectrum = 255;
    private double maxSpecDir = 0;
    private double maxSpecWL = 0;

    private double minReal = 0;
    private double maxReal = 0;
    private double minImaginary = 0;
    private double maxImaginary = 0;

    private double windSpeed = 0;
    private double windDirection = 0;
    private double sarWaveHeight = 0;
    private double sarAzShiftVar = 0;
    private double backscatter = 0;

    private int currentRecord = 0;

    private enum Unit {
        REAL, IMAGINARY, AMPLITUDE, INTENSITY
    }

    private final String[] unitTypes = new String[] { "Real", "Imaginary", "Amplitude", "Intensity" };

    private enum WaveProductType {
        CROSS_SPECTRA, WAVE_SPECTRA
    }

    private final ControlPanel controlPanel;
    private final PolarPanel polarPanel;
    private Unit graphUnit = Unit.REAL;
    private WaveProductType waveProductType = WaveProductType.WAVE_SPECTRA;
    private float spectrum[][] = null;

    public static final Color colourTable[] = (new Color[] { new Color(255, 255, 255), new Color(0, 0, 255),
            new Color(0, 255, 255), new Color(0, 255, 0), new Color(255, 255, 0), new Color(255, 0, 0) });
    private static final double rings[] = { 50.0, 100.0, 200.0 };
    private static final String ringTextStrings[] = { "200 m", "100 m", "50 m" };

    public PolarView(Product prod, ProductSceneImage image) {
        product = prod;
        sceneImage = image;

        if (prod.getProductType().equals("ASA_WVW_2P")) {
            waveProductType = WaveProductType.WAVE_SPECTRA;
            graphUnit = Unit.AMPLITUDE;
        } else {
            waveProductType = WaveProductType.CROSS_SPECTRA;
            graphUnit = Unit.INTENSITY;
        }

        getMetadata();

        final RasterDataNode[] rasters = sceneImage.getRasters();
        final RasterDataNode rasterNode = rasters[0];
        numRecords = rasterNode.getRasterHeight() - 1;
        recordLength = rasterNode.getRasterWidth();

        addMouseListener(this);
        addMouseMotionListener(this);

        this.setLayout(new BorderLayout());

        polarPanel = new PolarPanel();
        this.add(polarPanel, BorderLayout.CENTER);
        controlPanel = new ControlPanel(this);
        this.add(controlPanel, BorderLayout.SOUTH);

        createPlot(currentRecord);
    }

    /**
     * Returns the currently visible product node.
     */
    @Override
    public ProductNode getVisibleProductNode() {
        return sceneImage.getRasters()[0];
    }

    /**
     * Releases all of the resources used by this view, its subcomponents, and all of its owned children.
     */
    @Override
    public void dispose() {
        sceneImage = null;
        super.dispose();
    }

    public Product getProduct() {
        return product;
    }

    private void getMetadata() {
        final MetadataElement root = AbstractMetadata.getOriginalProductMetadata(product);
        final MetadataElement sph = root.getElement("SPH");
        numDirBins = sph.getAttributeInt("NUM_DIR_BINS", 0);
        numWLBins = sph.getAttributeInt("NUM_WL_BINS", 0);
        firstDirBins = (float) sph.getAttributeDouble("FIRST_DIR_BIN", 0);
        dirBinStep = (float) sph.getAttributeDouble("DIR_BIN_STEP", 0);
        firstWLBin = (float) sph.getAttributeDouble("FIRST_WL_BIN", 0);
        lastWLBin = (float) sph.getAttributeDouble("LAST_WL_BIN", 0);

        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            spectraMetadataRoot = root.getElement("OCEAN_WAVE_SPECTRA_MDS");
        } else {
            spectraMetadataRoot = root.getElement("CROSS_SPECTRA_MDS");
        }
    }

    private void getSpectraMetadata(int rec) {
        try {
            final String elemName = spectraMetadataRoot.getName() + '.' + (rec + 1);
            final MetadataElement spectraMetadata = spectraMetadataRoot.getElement(elemName);

            zeroDopplerTime = spectraMetadata.getAttributeUTC("zero_doppler_time");
            maxSpecDir = spectraMetadata.getAttributeDouble("spec_max_dir", 0);
            maxSpecWL = spectraMetadata.getAttributeDouble("spec_max_wl", 0);

            if (waveProductType == WaveProductType.WAVE_SPECTRA) {
                minSpectrum = spectraMetadata.getAttributeDouble("min_spectrum", 0);
                maxSpectrum = spectraMetadata.getAttributeDouble("max_spectrum", 255);
                windSpeed = spectraMetadata.getAttributeDouble("wind_speed", 0);
                windDirection = spectraMetadata.getAttributeDouble("wind_direction", 0);
                sarWaveHeight = spectraMetadata.getAttributeDouble("SAR_wave_height", 0);
                sarAzShiftVar = spectraMetadata.getAttributeDouble("SAR_az_shift_var", 0);
                backscatter = spectraMetadata.getAttributeDouble("backscatter", 0);
            } else {
                minReal = spectraMetadata.getAttributeDouble("min_real", 0);
                maxReal = spectraMetadata.getAttributeDouble("max_real", 255);
                minImaginary = spectraMetadata.getAttributeDouble("min_imag", 0);
                maxImaginary = spectraMetadata.getAttributeDouble("max_imag", 255);
            }
        } catch (Exception e) {
            System.out.println("Unable to get metadata for " + spectraMetadataRoot.getName());
        }

        final DecimalFormat frmt = new DecimalFormat("0.0000");

        final List<String> metadataList = new ArrayList<String>(10);
        metadataList.add("Time: " + zeroDopplerTime.toString());
        metadataList.add("Peak Direction: " + maxSpecDir + " deg");
        metadataList.add("Peak Wavelength: " + frmt.format(maxSpecWL) + " m");

        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            metadataList.add("Min Spectrum: " + frmt.format(minSpectrum));
            metadataList.add("Max Spectrum: " + frmt.format(maxSpectrum));

            metadataList.add("Wind Speed: " + windSpeed + " m/s");
            metadataList.add("Wind Direction: " + windDirection + " deg");
            metadataList.add("SAR Swell Wave Height: " + frmt.format(sarWaveHeight) + " m");
            metadataList.add("SAR Azimuth Shift Var: " + frmt.format(sarAzShiftVar) + " m^2");
            metadataList.add("Backscatter: " + frmt.format(backscatter) + " dB");
        }

        polarPanel.setMetadata(metadataList.toArray(new String[metadataList.size()]));
    }

    private float getMinValue(boolean real) {
        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            return (float) minSpectrum;
        } else {
            return real ? (float) minReal : (float) minImaginary;
        }
    }

    private float getMaxValue(boolean real) {
        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            return (float) maxSpectrum;
        } else {
            return real ? (float) maxReal : (float) maxImaginary;
        }
    }

    private void createPlot(int rec) {

        getSpectraMetadata(rec);
        spectrum = getSpectrum(0, rec, graphUnit != Unit.IMAGINARY);

        float minValue = getMinValue(graphUnit != Unit.IMAGINARY);
        float maxValue = getMaxValue(graphUnit != Unit.IMAGINARY);

        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            if (graphUnit == Unit.INTENSITY) {
                minValue = Float.MAX_VALUE;
                maxValue = Float.MIN_VALUE;
                for (int i = 0; i < spectrum.length; i++) {
                    for (int j = 0; j < spectrum[0].length; j++) {
                        final float realVal = spectrum[i][j];
                        final float val = realVal * realVal;
                        spectrum[i][j] = val;
                        minValue = Math.min(minValue, val);
                        maxValue = Math.max(maxValue, val);
                    }
                }
            }
        } else if (graphUnit == Unit.AMPLITUDE || graphUnit == Unit.INTENSITY) {
            // complex data
            final float imagSpectrum[][] = getSpectrum(1, rec, false);
            minValue = Float.MAX_VALUE;
            maxValue = Float.MIN_VALUE;
            for (int i = 0; i < spectrum.length; i++) {
                for (int j = 0; j < spectrum[0].length; j++) {
                    final float realVal = spectrum[i][j];
                    final float imagVal = imagSpectrum[i][j];
                    float val;
                    if (sign(realVal) == sign(imagVal))
                        val = realVal * realVal + imagVal * imagVal;
                    else
                        val = 0.0F;
                    if (graphUnit == Unit.AMPLITUDE)
                        val = (float) Math.sqrt(val);
                    spectrum[i][j] = val;
                    minValue = Math.min(minValue, val);
                    maxValue = Math.max(maxValue, val);
                }
            }
        }

        final float rStep = (float) (Math.log(lastWLBin) - Math.log(firstWLBin)) / (float) (numWLBins - 1);
        double logr = Math.log(firstWLBin) - (rStep / 2.0);
        final double colourRange[] = { (double) minValue, (double) maxValue };
        final double radialRange[] = { minRadius, 333.33333333333 };

        final float thFirst;
        final float thStep;
        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            thFirst = firstDirBins + 5f;
            thStep = -dirBinStep;
        } else {
            thFirst = firstDirBins - 5f;
            thStep = dirBinStep;
        }

        final int nWl = spectrum[0].length;
        final float radii[] = new float[nWl + 1];
        for (int j = 0; j <= nWl; j++) {
            radii[j] = (float) (10000.0 / FastMath.exp(logr));
            logr += rStep;
        }

        final PolarData data = new PolarData(spectrum, 90f + thFirst, thStep, radii);

        final PolarCanvas polarCanvas = polarPanel.getPolarCanvas();
        polarCanvas.setAxisNames("Azimuth", "Range");

        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            polarCanvas.setWindDirection(windDirection);
            polarCanvas.showWindDirection(true);
            polarCanvas.setAxisNames("North", "East");
        }

        final Axis colourAxis = polarCanvas.getColourAxis();
        final Axis radialAxis = polarCanvas.getRadialAxis();
        colourAxis.setDataRange(colourRange);
        colourAxis.setUnit(unitTypes[graphUnit.ordinal()]);
        radialAxis.setAutoRange(false);
        radialAxis.setDataRange(radialRange);
        radialAxis.setRange(radialRange[0], radialRange[1], 4);
        radialAxis.setTitle("Wavelength (m)");
        polarCanvas.setRings(rings, ringTextStrings);
        data.setColorScale(ColourScale.newCustomScale(colourRange));
        polarCanvas.setData(data);

        repaint();
        controlPanel.updateControls();
    }

    private float[][] getSpectrum(int imageNum, int rec, boolean getReal) {

        float[] dataset;
        try {
            final RasterDataNode rasterNode = product.getBandAt(imageNum);
            rasterNode.loadRasterData();
            dataset = new float[recordLength];
            rasterNode.getPixels(0, rec, recordLength, 1, dataset);

        } catch (IOException e) {
            System.out.println(e.getMessage());
            return null;
        }

        final float minValue = getMinValue(getReal);
        final float maxValue = getMaxValue(getReal);
        final float scale = (maxValue - minValue) / 255f;
        final float spectrum[][] = new float[numDirBins][numWLBins];

        int index = 0;
        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            for (int i = 0; i < numDirBins; i++) {
                for (int j = 0; j < numWLBins; j++) {
                    spectrum[i][j] = dataset[index++] * scale + minValue;
                }
            }
        } else {
            final int Nd2 = numDirBins / 2;
            for (int i = 0; i < Nd2; i++) {
                for (int j = 0; j < numWLBins; j++) {
                    spectrum[i][j] = dataset[index++] * scale + minValue;
                }
            }

            if (getReal) {
                for (int i = 0; i < Nd2; i++) {
                    System.arraycopy(spectrum[i], 0, spectrum[i + Nd2], 0, numWLBins);
                }
            } else {
                for (int i = 0; i < Nd2; i++) {
                    for (int j = 0; j < numWLBins; j++) {
                        spectrum[i + Nd2][j] = -spectrum[i][j];
                    }
                }
            }
        }
        return spectrum;
    }

    private static int sign(float f) {
        return f < 0.0F ? -1 : 1;
    }

    @Override
    public JPopupMenu createPopupMenu(Component component) {
        return null;
    }

    @Override
    public JPopupMenu createPopupMenu(MouseEvent event) {
        final JPopupMenu popup = new JPopupMenu();

        final JMenuItem itemNext = createMenuItem("Next");
        popup.add(itemNext);
        itemNext.setEnabled(currentRecord < numRecords);

        final JMenuItem itemPrev = createMenuItem("Previous");
        popup.add(itemPrev);
        itemPrev.setEnabled(currentRecord > 0);

        final JMenuItem itemColourScale = createMenuItem("Colour Scale");
        popup.add(itemColourScale);

        final JMenu unitMenu = new JMenu("Unit");
        popup.add(unitMenu);

        if (waveProductType == WaveProductType.WAVE_SPECTRA) {
            createCheckedMenuItem(unitTypes[Unit.AMPLITUDE.ordinal()], unitMenu, graphUnit == Unit.AMPLITUDE);
            createCheckedMenuItem(unitTypes[Unit.INTENSITY.ordinal()], unitMenu, graphUnit == Unit.INTENSITY);
        } else {
            createCheckedMenuItem(unitTypes[Unit.REAL.ordinal()], unitMenu, graphUnit == Unit.REAL);
            createCheckedMenuItem(unitTypes[Unit.IMAGINARY.ordinal()], unitMenu, graphUnit == Unit.IMAGINARY);
            createCheckedMenuItem(unitTypes[Unit.AMPLITUDE.ordinal()], unitMenu, graphUnit == Unit.AMPLITUDE);
            createCheckedMenuItem(unitTypes[Unit.INTENSITY.ordinal()], unitMenu, graphUnit == Unit.INTENSITY);
        }

        final JMenuItem itemExportReadout = createMenuItem("Export Readouts");
        popup.add(itemExportReadout);

        popup.setLabel("Justification");
        popup.setBorder(new BevelBorder(BevelBorder.RAISED));
        popup.addPopupMenuListener(this);
        popup.show(this, event.getX(), event.getY());

        return popup;
    }

    private JMenuItem createMenuItem(String name) {
        final JMenuItem item = new JMenuItem(name);
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(this);
        return item;
    }

    private JCheckBoxMenuItem createCheckedMenuItem(String name, JMenu parent, boolean state) {
        final JCheckBoxMenuItem item = new JCheckBoxMenuItem(name);
        item.setHorizontalTextPosition(JMenuItem.RIGHT);
        item.addActionListener(this);
        parent.add(item);
        return item;
    }

    /**
     * Handles menu item pressed events
     *
     * @param event the action event
     */
    public void actionPerformed(ActionEvent event) {

        if (event.getActionCommand().equals("Next")) {
            showNextPlot();
        } else if (event.getActionCommand().equals("Previous")) {
            showPreviousPlot();
        } else if (event.getActionCommand().equals("Colour Scale")) {
            callColourScaleDlg();
        } else if (event.getActionCommand().equals("Export Readouts")) {
            exportReadouts();
        } else if (event.getActionCommand().equals("Real")) {
            graphUnit = Unit.REAL;
            createPlot(currentRecord);
        } else if (event.getActionCommand().equals("Imaginary")) {
            graphUnit = Unit.IMAGINARY;
            createPlot(currentRecord);
        } else if (event.getActionCommand().equals("Amplitude")) {
            graphUnit = Unit.AMPLITUDE;
            createPlot(currentRecord);
        } else if (event.getActionCommand().equals("Intensity")) {
            graphUnit = Unit.INTENSITY;
            createPlot(currentRecord);
        }
    }

    int getCurrentRecord() {
        return currentRecord;
    }

    int getNumRecords() {
        return numRecords;
    }

    void showNextPlot() {
        createPlot(++currentRecord);
    }

    void showPreviousPlot() {
        createPlot(--currentRecord);
    }

    void showPlot(int record) {
        currentRecord = record;
        createPlot(currentRecord);
    }

    void zoomOut() {

        createPlot(currentRecord);
    }

    void zoomIn() {

        createPlot(currentRecord);
    }

    private void callColourScaleDlg() {
        final PolarCanvas polarCanvas = polarPanel.getPolarCanvas();
        final ColourScaleDialog dlg = new ColourScaleDialog(polarCanvas.getColourAxis());
        dlg.show();
    }

    private void exportReadouts() {
        final File file = FileFolderUtils.GetFilePath("Export Wave Mode Readout", "txt", "txt",
                product.getName() + "_rec" + currentRecord, "Wave mode readout", true);
        try {
            polarPanel.exportReadout(file);
        } catch (Exception e) {
            SnapDialogs.showError("Unable to export file " + file.toString() + ": " + e.getMessage());
        }
    }

    private void checkPopup(MouseEvent e) {
        if (e.isPopupTrigger()) {
            createPopupMenu(e);
        }
    }

    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    }

    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    }

    public void popupMenuCanceled(PopupMenuEvent e) {
    }

    /**
     * Handle mouse pressed event
     *
     * @param e the mouse event
     */
    public void mousePressed(MouseEvent e) {
        checkPopup(e);
    }

    /**
     * Handle mouse clicked event
     *
     * @param e the mouse event
     */
    public void mouseClicked(MouseEvent e) {
        checkPopup(e);

        final Object src = e.getSource();
        final PolarCanvas polarCanvas = polarPanel.getPolarCanvas();
        if (src == polarCanvas) {
            final Axis axis = polarCanvas.selectAxis(e.getPoint());
            if (axis != null && axis == polarCanvas.getColourAxis()) {
                callColourScaleDlg();
            }
        }
    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
        checkPopup(e);
    }

    public void mouseDragged(MouseEvent e) {
    }

    /**
     * Handle mouse moved event
     *
     * @param e the mouse event
     */
    public void mouseMoved(MouseEvent e) {
        updateReadout(e);
    }

    private void updateReadout(MouseEvent evt) {
        if (spectrum == null)
            return;

        final double rTh[] = polarPanel.getPolarCanvas().getRTheta(evt.getPoint());
        if (rTh != null) {
            final float thFirst;
            final int thBin;
            final float thStep;
            final int element;
            final int direction;

            final float rStep = (float) (Math.log(lastWLBin) - Math.log(firstWLBin)) / (float) (numWLBins - 1);
            int wvBin = (int) (((rStep / 2.0 + Math.log(10000.0 / rTh[0])) - Math.log(firstWLBin)) / rStep);
            wvBin = Math.min(wvBin, spectrum[0].length - 1);
            final int wl = (int) Math.round(FastMath.exp((double) wvBin * rStep + Math.log(firstWLBin)));

            if (waveProductType == WaveProductType.CROSS_SPECTRA) {
                thFirst = firstDirBins - 5f;
                thStep = dirBinStep;
                thBin = (int) (((rTh[1] - (double) thFirst) % 360.0) / (double) thStep);
                element = (thBin % (spectrum.length / 2)) * spectrum[0].length + wvBin;
                direction = (int) ((float) thBin * thStep + thStep / 2.0f + thFirst);
            } else {
                thFirst = firstDirBins + 5f;
                thStep = -dirBinStep;
                thBin = (int) ((((360.0 - rTh[1]) + (double) thFirst) % 360.0) / (double) (-thStep));
                element = thBin * spectrum[0].length + wvBin;
                direction = (int) (-((float) thBin * thStep + thStep / 2.0f + thFirst));
            }

            final List<String> readoutList = new ArrayList<String>(5);
            readoutList.add("Record: " + (currentRecord + 1) + " of " + (numRecords + 1));
            readoutList.add("Wavelength: " + wl + " m");
            readoutList.add("Direction: " + direction + " deg");
            readoutList.add("Bin: " + (thBin + 1) + "," + (wvBin + 1) + " Element: " + element);
            readoutList.add("Value: " + spectrum[thBin][wvBin]);

            polarPanel.setReadout(readoutList.toArray(new String[readoutList.size()]));

        } else {
            polarPanel.setReadout(null);
        }
        repaint();
    }

}