package org.esa.snap.graphbuilder.gpf.ui;
import com.bc.ceres.binding.PropertySet;
import com.bc.ceres.swing.TableLayout;
import org.esa.snap.core.datamodel.GeoCoding;
import org.esa.snap.core.datamodel.GeoPos;
import org.esa.snap.core.datamodel.ImageGeometry;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductFilter;
import org.esa.snap.core.gpf.ui.CollocationCrsForm;
import org.esa.snap.core.util.ProductUtils;
import org.esa.snap.rcp.SnapApp;
import org.esa.snap.ui.AbstractDialog;
import org.esa.snap.ui.AppContext;
import org.esa.snap.ui.DemSelector;
import org.esa.snap.ui.ModalDialog;
import org.esa.snap.ui.crs.CrsForm;
import org.esa.snap.ui.crs.CrsSelectionPanel;
import org.esa.snap.ui.crs.CustomCrsForm;
import org.esa.snap.ui.crs.OutputGeometryForm;
import org.esa.snap.ui.crs.OutputGeometryFormModel;
import org.esa.snap.ui.crs.PredefinedCrsForm;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
/**
* User interface for Reprojection
*/
public class ReprojectionUI extends BaseOperatorUI {
private static final String[] RESAMPLING_IDENTIFIER = {"Nearest", "Bilinear", "Bicubic"};
private JScrollPane scrollPane;
private boolean orthoMode = false;
private AppContext appContext = SnapApp.getDefault().getAppContext();
private DemSelector demSelector;
private CrsSelectionPanel crsSelectionPanel;
private OutputGeometryFormModel outputGeometryModel;
private JButton outputParamButton;
private ReprojectionUI.InfoForm infoForm;
private CoordinateReferenceSystem crs;
//TODO add collocationCRSForm
//private CollocationCrsForm collocationCrsUI;
private CustomCrsForm customCrsUI;
//Components of output setting panel
final JCheckBox preserveResolutionCheckBox = new JCheckBox("Preserve resolution",true);
JCheckBox includeTPcheck = new JCheckBox("Reproject tie-point grids", true);
final JTextField noDataField = new JTextField(Double.toString(Double.NaN));
JCheckBox addDeltaBandsChecker = new JCheckBox("Add delta lat/lon bands");
JComboBox<String> resampleComboBox = new JComboBox<>(RESAMPLING_IDENTIFIER);
//Create panel
@Override
public JComponent CreateOpTab(String operatorName, Map<String, Object> parameterMap, AppContext appContext) {
initializeOperatorUI(operatorName, parameterMap);
final JComponent panel = createPanel();
initParameters();
scrollPane = new JScrollPane(panel);
return scrollPane;
}
//called when sourceProduct is set
@Override
public void initParameters() {
if(hasSourceProducts() && sourceProducts[0] != null) {
crsSelectionPanel.setReferenceProduct(sourceProducts[0]);
if((sourceProducts[0].getBand("longitude") != null && sourceProducts[0].getBand("latitude") != null) || (sourceProducts[0].getTiePointGrid("longitude") != null && sourceProducts[0].getTiePointGrid("latitude") != null)) {
addDeltaBandsChecker.setEnabled(true);
} else {
addDeltaBandsChecker.setEnabled(false);
}
}
updateCRS();
updateParameters();
}
@Override
public UIValidation validateParameters() {
return new UIValidation(UIValidation.State.OK, "");
}
@Override
public void updateParameters() {
paramMap.clear();
paramMap.put("resamplingName", resampleComboBox.getSelectedItem().toString());
paramMap.put("includeTiePointGrids", includeTPcheck.isSelected());
paramMap.put("addDeltaBands", addDeltaBandsChecker.isSelected());
paramMap.put("noDataValue", Double.parseDouble(noDataField.getText()));
// if (!collocationCrsUI.getRadioButton().isSelected()) {
CoordinateReferenceSystem selectedCrs = getSelectedCrs();
if (selectedCrs != null) {
paramMap.put("crs", selectedCrs.toWKT());
} else {
paramMap.put("crs", "EPSG:4326");
}
// collocationCrsUI.prepareHide();
// } else {
// //TODO
// final Map<String, Product> productMap = new HashMap<>(5);
// productMap.put("source", getSourceProduct());
// if (collocationCrsUI.getRadioButton().isSelected()) {
// collocationCrsUI.prepareShow();
// productMap.put("collocateWith", collocationCrsUI.getCollocationProduct());
// }
// }
if (orthoMode) {
paramMap.put("orthorectify", orthoMode);
if (demSelector.isUsingExternalDem()) {
paramMap.put("elevationModelName", demSelector.getDemName());
} else {
paramMap.put("elevationModelName", null);
}
}
if (!preserveResolutionCheckBox.isSelected() && outputGeometryModel != null) {
PropertySet container = outputGeometryModel.getPropertySet();
paramMap.put("referencePixelX", container.getValue("referencePixelX"));
paramMap.put("referencePixelY", container.getValue("referencePixelY"));
paramMap.put("easting", container.getValue("easting"));
paramMap.put("northing", container.getValue("northing"));
paramMap.put("orientation", container.getValue("orientation"));
paramMap.put("pixelSizeX", container.getValue("pixelSizeX"));
paramMap.put("pixelSizeY", container.getValue("pixelSizeY"));
paramMap.put("width", container.getValue("width"));
paramMap.put("height", container.getValue("height"));
}
}
private JComponent createPanel() {
final JPanel parameterPanel = new JPanel();
final TableLayout layout = new TableLayout(1);
layout.setTablePadding(4, 4);
layout.setTableFill(TableLayout.Fill.HORIZONTAL);
layout.setTableAnchor(TableLayout.Anchor.WEST);
layout.setTableWeightX(1.0);
parameterPanel.setLayout(layout);
//Create panel with CrsForms
customCrsUI = new CustomCrsForm(appContext);
CrsForm predefinedCrsUI = new PredefinedCrsForm(appContext);
//collocationCrsUI = new CollocationCrsForm(appContext);
CrsForm[] crsForms = new CrsForm[]{customCrsUI, predefinedCrsUI/*, collocationCrsUI*/};
crsSelectionPanel = new CrsSelectionPanel(crsForms);
crsSelectionPanel.prepareShow();
//add CrsPanel to parameter panel
parameterPanel.add(crsSelectionPanel);
//if orthoMode, create and add demSelector
if (orthoMode) {
demSelector = new DemSelector();
parameterPanel.add(demSelector);
}
//create and add the output setting panel
parameterPanel.add(createOuputSettingsPanel());
//create and add the info panel
infoForm = new ReprojectionUI.InfoForm();
parameterPanel.add(infoForm.createUI());
//add change listener
crsSelectionPanel.addPropertyChangeListener("crs", evt -> updateCRS());
updateCRS();
return parameterPanel;
}
Product getSourceProduct() {
if(!hasSourceProducts()) {
return null;
}
return sourceProducts[0];
}
CoordinateReferenceSystem getSelectedCrs() {
return crs;
}
private void updateCRS() {
final Product sourceProduct = getSourceProduct();
try {
if (sourceProduct != null) {
crs = crsSelectionPanel.getCrs(ProductUtils.getCenterGeoPos(sourceProduct));
infoForm.setCenterPos(ProductUtils.getCenterGeoPos(sourceProduct));
if (outputGeometryModel != null) {
outputGeometryModel.setSourceProduct(sourceProduct);
}
if (crs != null) {
infoForm.setCrsInfoText(crs.getName().getCode(), crs.toString());
} else {
infoForm.setCrsErrorText("No valid 'Coordinate Reference System' selected.");
}
} else {
infoForm.setCrsErrorText("No source product selected.");
crs = null;
}
} catch (FactoryException e) {
infoForm.setCrsErrorText(e.getMessage());
crs = null;
}
if (outputGeometryModel != null) {
outputGeometryModel.setTargetCrs(crs);
}
updateOutputParameterState();
}
private void updateProductSize() {
int width = 0;
int height = 0;
final Product sourceProduct = getSourceProduct();
if (sourceProduct != null && crs != null) {
if (!preserveResolutionCheckBox.isSelected() && outputGeometryModel != null) {
PropertySet container = outputGeometryModel.getPropertySet();
width = container.getValue("width");
height = container.getValue("height");
} else {
ImageGeometry iGeometry;
// final Product collocationProduct = collocationCrsUI.getCollocationProduct();
// if (collocationCrsUI.getRadioButton().isSelected() && collocationProduct != null) {
// iGeometry = ImageGeometry.createCollocationTargetGeometry(sourceProduct, collocationProduct);
// } else {
iGeometry = ImageGeometry.createTargetGeometry(sourceProduct, crs,
null, null, null, null,
null, null, null, null,
null);
// }
Rectangle imageRect = iGeometry.getImageRect();
width = imageRect.width;
height = imageRect.height;
}
}
infoForm.setWidth(width);
infoForm.setHeight(height);
}
private class InfoForm {
private JLabel widthLabel;
private JLabel heightLabel;
private JLabel centerLatLabel;
private JLabel centerLonLabel;
private JLabel crsLabel;
private String wkt;
private JButton wktButton;
void setWidth(int width) {
widthLabel.setText(Integer.toString(width));
}
void setHeight(int height) {
heightLabel.setText(Integer.toString(height));
}
void setCenterPos(GeoPos geoPos) {
if (geoPos != null) {
centerLatLabel.setText(geoPos.getLatString());
centerLonLabel.setText(geoPos.getLonString());
} else {
centerLatLabel.setText("");
centerLonLabel.setText("");
}
}
void setCrsErrorText(String infoText) {
setCrsInfoText("<html><b>" + infoText + "</b>", null);
}
void setCrsInfoText(String infoText, String wkt) {
this.wkt = wkt;
crsLabel.setText(infoText);
boolean hasWKT = (wkt != null);
wktButton.setEnabled(hasWKT);
}
JPanel createUI() {
widthLabel = new JLabel();
heightLabel = new JLabel();
centerLatLabel = new JLabel();
centerLonLabel = new JLabel();
crsLabel = new JLabel();
final TableLayout tableLayout = new TableLayout(5);
tableLayout.setTableAnchor(TableLayout.Anchor.WEST);
tableLayout.setTableFill(TableLayout.Fill.HORIZONTAL);
tableLayout.setTablePadding(4, 4);
tableLayout.setColumnWeightX(0, 0.0);
tableLayout.setColumnWeightX(1, 0.0);
tableLayout.setColumnWeightX(2, 1.0);
tableLayout.setColumnWeightX(3, 0.0);
tableLayout.setColumnWeightX(4, 1.0);
tableLayout.setCellColspan(2, 1, 3);
tableLayout.setCellPadding(0, 3, new Insets(4, 24, 4, 20));
tableLayout.setCellPadding(1, 3, new Insets(4, 24, 4, 20));
final JPanel panel = new JPanel(tableLayout);
panel.setBorder(BorderFactory.createTitledBorder("Output Information"));
panel.add(new JLabel("Scene width:"));
panel.add(widthLabel);
panel.add(new JLabel("pixel"));
panel.add(new JLabel("Center longitude:"));
panel.add(centerLonLabel);
panel.add(new JLabel("Scene height:"));
panel.add(heightLabel);
panel.add(new JLabel("pixel"));
panel.add(new JLabel("Center latitude:"));
panel.add(centerLatLabel);
panel.add(new JLabel("CRS:"));
panel.add(crsLabel);
wktButton = new JButton("Show WKT");
wktButton.addActionListener(e -> {
JTextArea wktArea = new JTextArea(30, 40);
wktArea.setEditable(false);
wktArea.setText(wkt);
final JScrollPane scrollPane = new JScrollPane(wktArea);
final ModalDialog dialog = new ModalDialog(appContext.getApplicationWindow(),
"Coordinate reference system as well known text",
scrollPane,
ModalDialog.ID_OK, null);
dialog.show();
});
wktButton.setEnabled(false);
panel.add(wktButton);
return panel;
}
}
private JPanel createOuputSettingsPanel() {
final TableLayout tableLayout = new TableLayout(3);
tableLayout.setTableAnchor(TableLayout.Anchor.WEST);
tableLayout.setTableFill(TableLayout.Fill.HORIZONTAL);
tableLayout.setColumnFill(0, TableLayout.Fill.NONE);
tableLayout.setTablePadding(4, 4);
tableLayout.setColumnPadding(0, new Insets(4, 4, 4, 20));
tableLayout.setColumnWeightX(0, 0.0);
tableLayout.setColumnWeightX(1, 0.0);
tableLayout.setColumnWeightX(2, 1.0);
tableLayout.setCellColspan(0, 1, 2);
tableLayout.setCellPadding(1, 0, new Insets(4, 24, 4, 20));
final JPanel outputSettingsPanel = new JPanel(tableLayout);
outputSettingsPanel.setBorder(BorderFactory.createTitledBorder("Output Settings"));
preserveResolutionCheckBox.addActionListener(e -> {
if (preserveResolutionCheckBox.isSelected()) {
outputParamButton.setEnabled(false);
} else {
outputParamButton.setEnabled(true);
}
});
outputSettingsPanel.add(preserveResolutionCheckBox);
outputSettingsPanel.add(includeTPcheck);
outputParamButton = new JButton("Output Parameters...");
outputParamButton.setEnabled(!preserveResolutionCheckBox.isSelected());
outputParamButton.addActionListener(new OutputParamActionListener());
outputSettingsPanel.add(outputParamButton);
outputSettingsPanel.add(new JLabel("No-data value:"));
outputSettingsPanel.add(noDataField);
outputSettingsPanel.add(addDeltaBandsChecker);
outputSettingsPanel.add(new JLabel("Resampling method:"));
resampleComboBox.setPrototypeDisplayValue(RESAMPLING_IDENTIFIER[0]);
outputSettingsPanel.add(resampleComboBox);
return outputSettingsPanel;
}
private void updateOutputParameterState() {
outputParamButton.setEnabled(!preserveResolutionCheckBox.isSelected() && (crs != null));
updateProductSize();
}
private void showWarningMessage(String message) {
AbstractDialog.showWarningDialog(scrollPane, message, "Reprojection");
}
private class OutputParamActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
try {
final Product sourceProduct = getSourceProduct();
if (sourceProduct == null) {
showWarningMessage("Please select a product to reproject.\n");
return;
}
if (crs == null) {
showWarningMessage("Please specify a 'Coordinate Reference System' first.\n");
return;
}
OutputGeometryFormModel workCopy;
if (outputGeometryModel != null) {
workCopy = new OutputGeometryFormModel(outputGeometryModel);
} else {
// final Product collocationProduct = collocationCrsUI.getCollocationProduct();
// if (collocationCrsUI.getRadioButton().isSelected() && collocationProduct != null) {
// workCopy = new OutputGeometryFormModel(sourceProduct, collocationProduct);
// } else {
workCopy = new OutputGeometryFormModel(sourceProduct, crs);
// }
}
final OutputGeometryForm form = new OutputGeometryForm(workCopy);
final ModalDialog outputParametersDialog = new OutputParametersDialog(appContext.getApplicationWindow(),
sourceProduct, workCopy);
outputParametersDialog.setContent(form);
if (outputParametersDialog.show() == ModalDialog.ID_OK) {
outputGeometryModel = workCopy;
updateProductSize();
}
} catch (Exception e) {
appContext.handleError("Could not create a 'Coordinate Reference System'.\n" +
e.getMessage(), e);
}
}
}
private class OutputParametersDialog extends ModalDialog {
private static final String TITLE = "Output Parameters";
private final Product sourceProduct;
private final OutputGeometryFormModel outputGeometryFormModel;
public OutputParametersDialog(Window parent, Product sourceProduct,
OutputGeometryFormModel outputGeometryFormModel) {
super(parent, TITLE, ModalDialog.ID_OK_CANCEL | ModalDialog.ID_RESET, null);
this.sourceProduct = sourceProduct;
this.outputGeometryFormModel = outputGeometryFormModel;
}
@Override
protected void onReset() {
// final Product collocationProduct = collocationCrsUI.getCollocationProduct();
ImageGeometry imageGeometry;
//if (collocationCrsUI.getRadioButton().isSelected() && collocationProduct != null) {
// imageGeometry = ImageGeometry.createCollocationTargetGeometry(sourceProduct, collocationProduct);
// } else {
imageGeometry = ImageGeometry.createTargetGeometry(sourceProduct, crs,
null, null, null, null,
null, null, null, null, null);
//}
outputGeometryFormModel.resetToDefaults(imageGeometry);
}
}
}