/*
* 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.insar.gpf.ui;
import org.esa.snap.core.datamodel.MetadataElement;
import org.esa.snap.core.dataop.resamp.ResamplingFactory;
import org.esa.snap.engine_utilities.datamodel.AbstractMetadata;
import org.esa.snap.engine_utilities.gpf.InputProductValidator;
import org.esa.snap.graphbuilder.gpf.ui.BaseOperatorUI;
import org.esa.snap.graphbuilder.gpf.ui.UIValidation;
import org.esa.snap.graphbuilder.rcp.utils.DialogUtils;
import org.esa.snap.ui.AppContext;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Map;
/**
* User interface for OffsetTrackingOp
*/
public class OffsetTrackingOpUI extends BaseOperatorUI {
// Output grid parameters
private final JTextField gridAzimuthSpacing = new JTextField("");
private final JTextField gridRangeSpacing = new JTextField("");
private final JTextField gridAzimuthSpacingInMeters = new JTextField("");
private final JTextField gridRangeSpacingInMeters = new JTextField("");
private final JTextField gridAzimuthDimension = new JTextField("");
private final JTextField gridRangeDimension = new JTextField("");
private final JTextField totalGridPoints = new JTextField("");
// Registration parameters
private final JComboBox<String> registrationWindowWidth = new JComboBox(
new String[]{"32", "64", "128", "256", "512", "1024", "2048"});
private final JComboBox<String> registrationWindowHeight = new JComboBox(
new String[]{"32", "64", "128", "256", "512", "1024", "2048"});
private final JTextField xCorrThreshold = new JTextField("");
// Post processing parameters
private final JComboBox<String> averageBoxSize = new JComboBox(new String[]{"3", "5", "7", "9"});
private final JTextField maxVelocity = new JTextField("");
private final JTextField radius = new JTextField("");
// Other options
private final JComboBox resamplingType = new JComboBox(ResamplingFactory.resamplingNames);
final JCheckBox spatialAverageCheckBox = new JCheckBox("Spatial Average");
final JCheckBox fillHoleCheckBox = new JCheckBox("Fill Holes");
private Boolean spatialAverage = true;
private Boolean fillHoles = true;
private final JComboBox vectorsCombo = new JComboBox();
@Override
public JComponent CreateOpTab(String operatorName, Map<String, Object> parameterMap, AppContext appContext) {
initializeOperatorUI(operatorName, parameterMap);
final JComponent panel = createPanel();
initParameters();
spatialAverageCheckBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
spatialAverage = (e.getStateChange() == ItemEvent.SELECTED);
}
});
fillHoleCheckBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
fillHoles = (e.getStateChange() == ItemEvent.SELECTED);
}
});
return new JScrollPane(panel);
}
@Override
public void initParameters() {
gridAzimuthSpacing.setText(String.valueOf(paramMap.get("gridAzimuthSpacing")));
gridRangeSpacing.setText(String.valueOf(paramMap.get("gridRangeSpacing")));
registrationWindowWidth.setSelectedItem(paramMap.get("registrationWindowWidth"));
registrationWindowHeight.setSelectedItem(paramMap.get("registrationWindowHeight"));
xCorrThreshold.setText(String.valueOf(paramMap.get("xCorrThreshold")));
averageBoxSize.setSelectedItem(paramMap.get("averageBoxSize"));
maxVelocity.setText(String.valueOf(paramMap.get("maxVelocity")));
radius.setText(String.valueOf(paramMap.get("radius")));
resamplingType.setSelectedItem(paramMap.get("resamplingType"));
gridAzimuthSpacingInMeters.setText("");
gridAzimuthSpacingInMeters.setColumns(7);
gridAzimuthSpacingInMeters.setEditable(false);
gridRangeSpacingInMeters.setText("");
gridRangeSpacingInMeters.setEditable(false);
gridAzimuthDimension.setText("");
gridAzimuthDimension.setEditable(false);
gridRangeDimension.setText("");
gridRangeDimension.setEditable(false);
totalGridPoints.setText("");
totalGridPoints.setEditable(false);
if (sourceProducts != null && sourceProducts.length > 0) {
setDerivedAzimuthParameters();
setDerivedRangeParameters();
}
spatialAverage = (Boolean)paramMap.get("spatialAverage");
if(spatialAverage != null) {
spatialAverageCheckBox.setSelected(spatialAverage);
}
fillHoles = (Boolean)paramMap.get("fillHoles");
if(fillHoles != null) {
fillHoleCheckBox.setSelected(fillHoles);
}
vectorsCombo.removeAllItems();
final String[] geometryNames = getGeometries();
for (String g : geometryNames) {
vectorsCombo.addItem(g);
}
final String selectedGeometry = (String) paramMap.get("roiVector");
if (selectedGeometry != null) {
vectorsCombo.setSelectedItem(selectedGeometry);
}
}
@Override
public UIValidation validateParameters() {
return new UIValidation(UIValidation.State.OK, "");
}
@Override
public void updateParameters() {
paramMap.put("gridAzimuthSpacing", Integer.parseInt(gridAzimuthSpacing.getText()));
paramMap.put("gridRangeSpacing", Integer.parseInt(gridRangeSpacing.getText()));
paramMap.put("registrationWindowWidth", registrationWindowWidth.getSelectedItem());
paramMap.put("registrationWindowHeight", registrationWindowHeight.getSelectedItem());
paramMap.put("xCorrThreshold", Double.parseDouble(xCorrThreshold.getText()));
paramMap.put("averageBoxSize", averageBoxSize.getSelectedItem());
paramMap.put("maxVelocity", Double.parseDouble(maxVelocity.getText()));
paramMap.put("radius", Integer.parseInt(radius.getText()));
paramMap.put("resamplingType", resamplingType.getSelectedItem());
setDerivedAzimuthParameters();
setDerivedRangeParameters();
paramMap.put("spatialAverage", spatialAverage);
paramMap.put("fillHoles", fillHoles);
paramMap.put("roiVector", vectorsCombo.getSelectedItem());
}
private JComponent createPanel() {
final JPanel contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
final GridBagConstraints gbc = DialogUtils.createGridBagConstraints();
contentPane.add(new JLabel(" "), gbc);
gbc.gridy++;
final JPanel gridPanel = new JPanel(new GridBagLayout());
final GridBagConstraints gbc2 = DialogUtils.createGridBagConstraints();
gridPanel.setBorder(BorderFactory.createTitledBorder("Output Grid"));
gridAzimuthSpacing.setColumns(3);
DialogUtils.addComponent(gridPanel, gbc2, "Grid Azimuth Spacing (in pixels):", gridAzimuthSpacing);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Grid Range Spacing (in pixels):", gridRangeSpacing);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Grid Azimuth Spacing (in meters):", gridAzimuthSpacingInMeters);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Grid Range Spacing (in meters):", gridRangeSpacingInMeters);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Grid Azimuth Dimension:", gridAzimuthDimension);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Grid Range Dimension:", gridRangeDimension);
gbc2.gridy++;
DialogUtils.addComponent(gridPanel, gbc2, "Total Grid Points:", totalGridPoints);
gridAzimuthSpacing.setDocument(new gridAzimuthSpacingDocument());
gridRangeSpacing.setDocument(new gridRangeSpacingDocument());
final JPanel registrationPanel = new JPanel(new GridBagLayout());
final GridBagConstraints gbc3 = DialogUtils.createGridBagConstraints();
registrationPanel.setBorder(BorderFactory.createTitledBorder("Registration"));
DialogUtils.addComponent(registrationPanel, gbc3, "Registration Window Width:", registrationWindowWidth);
gbc3.gridy++;
DialogUtils.addComponent(registrationPanel, gbc3, "Registration Window Height:", registrationWindowHeight);
gbc3.gridy++;
DialogUtils.addComponent(registrationPanel, gbc3, "Cross-Correlation Threshold:", xCorrThreshold);
gbc3.gridy++;
DialogUtils.addComponent(registrationPanel, gbc3, "Average Box Size:", averageBoxSize);
gbc3.gridy++;
DialogUtils.addComponent(registrationPanel, gbc3, "Max Velocity (m/day):", maxVelocity);
gbc3.gridy++;
DialogUtils.addComponent(registrationPanel, gbc3, "Radius for Hole Filling:", radius);
gbc3.gridy++;
contentPane.add(gridPanel, gbc);
gbc.gridx = 1;
contentPane.add(registrationPanel, gbc);
gbc.gridx = 0;
gbc.gridy++;
DialogUtils.addComponent(contentPane, gbc, "Resampling Type:", resamplingType);
gbc.gridy++;
gbc.gridx = 1;
contentPane.add(spatialAverageCheckBox, gbc);
gbc.gridy++;
contentPane.add(fillHoleCheckBox, gbc);
gbc.gridx = 0;
gbc.gridy++;
DialogUtils.addComponent(contentPane, gbc, "ROI Vector Mask:", vectorsCombo);
gbc.gridy++;
DialogUtils.fillPanel(contentPane, gbc);
return contentPane;
}
private synchronized void setDerivedAzimuthParameters() {
if (sourceProducts != null && sourceProducts.length > 0) {
try {
final int sourceImageWidth = sourceProducts[0].getSceneRasterWidth();
final int sourceImageHeight = sourceProducts[0].getSceneRasterHeight();
final int gridRgSpacingInPixel = Integer.parseInt(gridRangeSpacing.getText());
final int gridAzSpacingInPixel = Integer.parseInt(gridAzimuthSpacing.getText());
final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(sourceProducts[0]);
double azPixelSpacing = 0.0;
if (absRoot != null) {
azPixelSpacing = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.azimuth_spacing);
}
if (azPixelSpacing != 0.0) {
final double azSpacingInM = azPixelSpacing * gridAzSpacingInPixel;
gridAzimuthSpacingInMeters.setText(String.valueOf(azSpacingInM));
}
final int azimuthDimension = sourceImageHeight / gridAzSpacingInPixel;
gridAzimuthDimension.setText(String.valueOf(azimuthDimension));
final int rangeDimension = sourceImageWidth / gridRgSpacingInPixel;
final int totalPoints = rangeDimension * azimuthDimension;
totalGridPoints.setText(String.valueOf(totalPoints));
} catch (Exception e) {
gridAzimuthSpacingInMeters.setText("");
gridAzimuthDimension.setText("");
}
}
}
private synchronized void setDerivedRangeParameters() {
if (sourceProducts != null && sourceProducts.length > 0) {
try {
final int sourceImageWidth = sourceProducts[0].getSceneRasterWidth();
final int sourceImageHeight = sourceProducts[0].getSceneRasterHeight();
final int gridRgSpacingInPixel = Integer.parseInt(gridRangeSpacing.getText());
final int gridAzSpacingInPixel = Integer.parseInt(gridAzimuthSpacing.getText());
final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(sourceProducts[0]);
double rgPixelSpacing = 0.0;
if (absRoot != null) {
rgPixelSpacing = AbstractMetadata.getAttributeDouble(absRoot, AbstractMetadata.range_spacing);
}
if (rgPixelSpacing != 0.0) {
final double rgSpacingInM = rgPixelSpacing * gridRgSpacingInPixel;
gridRangeSpacingInMeters.setText(String.valueOf(rgSpacingInM));
}
final int rangeDimension = sourceImageWidth / gridRgSpacingInPixel;
gridRangeDimension.setText(String.valueOf(rangeDimension));
final int azimuthDimension = sourceImageHeight / gridAzSpacingInPixel;
final int totalPoints = rangeDimension * azimuthDimension;
totalGridPoints.setText(String.valueOf(totalPoints));
} catch (Exception e) {
gridRangeSpacingInMeters.setText("");
gridRangeDimension.setText("");
}
}
}
private class gridAzimuthSpacingDocument extends PlainDocument {
@Override
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
super.replace(offset, length, text, attrs);
setDerivedAzimuthParameters();
}
}
private class gridRangeSpacingDocument extends PlainDocument {
@Override
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
super.replace(offset, length, text, attrs);
setDerivedRangeParameters();
}
}
}