diff --git a/snap-gpf-ui/src/main/java/org/esa/snap/core/gpf/ui/reproject/ReprojectionForm.java b/snap-gpf-ui/src/main/java/org/esa/snap/core/gpf/ui/reproject/ReprojectionForm.java index 4926b81d9a..622cef3ba2 100644 --- a/snap-gpf-ui/src/main/java/org/esa/snap/core/gpf/ui/reproject/ReprojectionForm.java +++ b/snap-gpf-ui/src/main/java/org/esa/snap/core/gpf/ui/reproject/ReprojectionForm.java @@ -25,11 +25,7 @@ import com.bc.ceres.swing.binding.BindingContext; import com.bc.ceres.swing.selection.AbstractSelectionChangeListener; import com.bc.ceres.swing.selection.SelectionChangeEvent; -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.datamodel.*; import org.esa.snap.core.gpf.ui.CollocationCrsForm; import org.esa.snap.core.gpf.ui.SourceProductSelector; import org.esa.snap.core.gpf.ui.TargetProductSelector; @@ -37,6 +33,7 @@ import org.esa.snap.core.param.ParamParseException; import org.esa.snap.core.param.ParamValidateException; 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; @@ -47,6 +44,7 @@ import org.esa.snap.ui.crs.OutputGeometryForm; import org.esa.snap.ui.crs.OutputGeometryFormModel; import org.esa.snap.ui.crs.PredefinedCrsForm; +import org.esa.snap.ui.product.ProductExpressionPane; import org.geotools.referencing.AbstractReferenceSystem; import org.geotools.referencing.CRS; import org.opengis.parameter.ParameterValueGroup; @@ -57,16 +55,7 @@ import org.opengis.referencing.operation.OperationMethod; import org.opengis.referencing.operation.Projection; -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextArea; -import javax.swing.JTextField; +import javax.swing.*; import java.awt.Insets; import java.awt.Rectangle; import java.awt.Window; @@ -75,6 +64,9 @@ import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; +import java.util.prefs.Preferences; + +import static org.esa.snap.rcp.preferences.general.ReprojectionController.*; /** * @author Marco Zuehlke @@ -104,6 +96,16 @@ class ReprojectionForm extends JTabbedPane { private CollocationCrsForm collocationCrsUI; private CustomCrsForm customCrsUI; + private boolean applyValidPixelExpression; + private JCheckBox applyValidPixelExpressionCheckBox; + + + + private JPanel maskExpressionPanel; + + private JButton editExpressionButton; + private JTextArea expressionArea; + private JTabbedPane t = this; ReprojectionForm(TargetProductSelector targetProductSelector, boolean orthorectify, AppContext appContext) { this.targetProductSelector = targetProductSelector; @@ -122,12 +124,15 @@ class ReprojectionForm extends JTabbedPane { createUI(); } + + void updateParameterMap(Map parameterMap) { parameterMap.clear(); parameterMap.put("resamplingName", reprojectionModel.resamplingName); parameterMap.put("includeTiePointGrids", reprojectionModel.includeTiePointGrids); parameterMap.put("addDeltaBands", reprojectionModel.addDeltaBands); parameterMap.put("noDataValue", reprojectionModel.noDataValue); + parameterMap.put("retainValidPixelExpression", reprojectionModel.retainValidPixelExpression); if (!collocationCrsUI.getRadioButton().isSelected()) { CoordinateReferenceSystem selectedCrs = getSelectedCrs(); if (selectedCrs != null) { @@ -160,6 +165,14 @@ void updateParameterMap(Map parameterMap) { parameterMap.put("width", container.getValue("width")); parameterMap.put("height", container.getValue("height")); } + + applyValidPixelExpression = applyValidPixelExpressionCheckBox.isSelected(); + parameterMap.put("applyValidPixelExpression", applyValidPixelExpression); + + + if (expressionArea.getText() != null) { + parameterMap.put("maskExpression", expressionArea.getText()); + } } public void updateFormModel(Map parameterMap) throws ValidationException, ConversionException { @@ -254,6 +267,8 @@ String getExternalDemName() { private void createUI() { addTab("I/O Parameters", createIOPanel()); addTab("Reprojection Parameters", createParametersPanel()); +// addTab("Validation Masking", createMaskPanel()); + } private JPanel createIOPanel() { @@ -296,15 +311,26 @@ public void selectionChanged(SelectionChangeEvent event) { demSelector = new DemSelector(); parameterPanel.add(demSelector); } - parameterPanel.add(createOuputSettingsPanel()); + + parameterPanel.add(createMaskSettingsPanel()); + + + parameterPanel.add(createOutputSettingsPanel()); + + infoForm = new InfoForm(); parameterPanel.add(infoForm.createUI()); + + crsSelectionPanel.addPropertyChangeListener("crs", evt -> updateCRS()); updateCRS(); return parameterPanel; } + + + private void updateCRS() { final Product sourceProduct = getSourceProduct(); try { @@ -345,9 +371,9 @@ private void updateProductSize() { iGeometry = ImageGeometry.createCollocationTargetGeometry(sourceProduct, collocationProduct); } else { iGeometry = ImageGeometry.createTargetGeometry(sourceProduct, crs, - null, null, null, null, - null, null, null, null, - null); + null, null, null, null, + null, null, null, null, + null); } Rectangle imageRect = iGeometry.getImageRect(); @@ -442,9 +468,9 @@ JPanel createUI() { 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); + "Coordinate reference system as well known text", + scrollPane, + ModalDialog.ID_OK, null); dialog.show(); }); wktButton.setEnabled(false); @@ -453,58 +479,137 @@ JPanel createUI() { } } - private JPanel createOuputSettingsPanel() { - final TableLayout tableLayout = new TableLayout(3); + private JPanel createOutputSettingsPanel() { + + Preferences preferences = SnapApp.getDefault().getPreferences(); + + + final TableLayout tableLayout = new TableLayout(2); 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")); + outputSettingsPanel.setBorder(BorderFactory.createTitledBorder(PROPERTY_OUTPUT_SETTINGS_SECTION_LABEL)); final BindingContext context = new BindingContext(reprojectionContainer); - final JCheckBox preserveResolutionCheckBox = new JCheckBox("Preserve resolution"); + + + final TableLayout resolutionTableLayout = new TableLayout(2); + resolutionTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + resolutionTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + resolutionTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + resolutionTableLayout.setTablePadding(4, 4); + + final JPanel resolutionPanel = new JPanel(resolutionTableLayout); + resolutionPanel.setBorder(BorderFactory.createTitledBorder("Resolution")); + + final JCheckBox preserveResolutionCheckBox = new JCheckBox(PROPERTY_PRESERVE_RESOLUTION_LABEL); + preserveResolutionCheckBox.setToolTipText(PROPERTY_PRESERVE_RESOLUTION_TOOLTIP); context.bind(Model.PRESERVE_RESOLUTION, preserveResolutionCheckBox); collocationCrsUI.getCrsUI().addPropertyChangeListener("collocate", evt -> { final boolean collocate = (Boolean) evt.getNewValue(); reprojectionContainer.setValue(Model.PRESERVE_RESOLUTION, - collocate || reprojectionModel.preserveResolution); + collocate || reprojectionModel.preserveResolution); preserveResolutionCheckBox.setEnabled(!collocate); }); - outputSettingsPanel.add(preserveResolutionCheckBox); + resolutionPanel.add(preserveResolutionCheckBox); - JCheckBox includeTPcheck = new JCheckBox("Reproject tie-point grids", true); - context.bind(Model.REPROJ_TIEPOINTS, includeTPcheck); - outputSettingsPanel.add(includeTPcheck); + preserveResolutionCheckBox.addActionListener(e -> { + if (preserveResolutionCheckBox.isSelected()) { + outputParamButton.setEnabled(false); + } else { + outputParamButton.setEnabled(true); + } - outputParamButton = new JButton("Output Parameters..."); + }); + + outputParamButton = new JButton(PROPERTY_RESOLUTION_PARAMETERS_BUTTON_NAME); outputParamButton.setEnabled(!reprojectionModel.preserveResolution); outputParamButton.addActionListener(new OutputParamActionListener()); - outputSettingsPanel.add(outputParamButton); + resolutionPanel.add(outputParamButton); + - outputSettingsPanel.add(new JLabel("No-data value:")); - final JTextField noDataField = new JTextField(); + outputSettingsPanel.add(resolutionPanel); - outputSettingsPanel.add(noDataField); + + // Resampling Method Component + final TableLayout resamplingTableLayout = new TableLayout(2); + resamplingTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + resamplingTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + resamplingTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + resamplingTableLayout.setTablePadding(4, 4); + final JPanel resamplingPanel = new JPanel(resamplingTableLayout); + + JLabel resamplingMethodLabel = new JLabel(PROPERTY_RESAMPLING_METHOD_LABEL); + String resamplingMethodPreference = preferences.get(PROPERTY_RESAMPLING_METHOD_KEY, PROPERTY_RESAMPLING_METHOD_DEFAULT); + JComboBox resampleComboBox = new JComboBox<>(PROPERTY_RESAMPLING_METHOD_OPTIONS); + resampleComboBox.setPrototypeDisplayValue(resamplingMethodPreference); + resampleComboBox.setSelectedItem(resamplingMethodPreference); + resamplingMethodLabel.setToolTipText(PROPERTY_RESAMPLING_METHOD_TOOLTIP); + resampleComboBox.setToolTipText(PROPERTY_RESAMPLING_METHOD_TOOLTIP); + context.bind(Model.RESAMPLING_NAME, resampleComboBox); + resamplingPanel.add(resamplingMethodLabel); + resamplingPanel.add(resampleComboBox); + + outputSettingsPanel.add(resamplingPanel); + + + + + + // No-Data Component + final TableLayout noDataTableLayout = new TableLayout(2); + noDataTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + noDataTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + noDataTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + noDataTableLayout.setColumnFill(1, TableLayout.Fill.NONE); + noDataTableLayout.setColumnAnchor(0, TableLayout.Anchor.EAST); + noDataTableLayout.setColumnAnchor(1, TableLayout.Anchor.WEST); + noDataTableLayout.setCellWeightX(0,0,0.0); + noDataTableLayout.setCellWeightX(0,1,1.0); + + noDataTableLayout.setTablePadding(4, 4); + final JPanel noDataPanel = new JPanel(noDataTableLayout); + + JLabel noDataLabel = new JLabel(PROPERTY_NO_DATA_VALUE_LABEL); + noDataLabel.setToolTipText(PROPERTY_NO_DATA_VALUE_TOOLTIP); + final JTextField noDataField = new JTextField("12345678"); + noDataField.setMinimumSize(noDataField.getPreferredSize()); + noDataField.setPreferredSize(noDataField.getPreferredSize()); + noDataField.setToolTipText(PROPERTY_NO_DATA_VALUE_TOOLTIP); context.bind(Model.NO_DATA_VALUE, noDataField); + noDataPanel.add(noDataLabel); + noDataPanel.add(noDataField); + + outputSettingsPanel.add(noDataPanel); - JCheckBox addDeltaBandsChecker = new JCheckBox("Add delta lat/lon bands"); + + + JCheckBox retainValidPixelExpressionCheckBox = new JCheckBox(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_LABEL); + retainValidPixelExpressionCheckBox.setToolTipText(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_TOOLTIP); + outputSettingsPanel.add(retainValidPixelExpressionCheckBox); + context.bind(Model.RETAIN_VALID_PIXEL_EXPRESSION, retainValidPixelExpressionCheckBox); + + + + // Tie-Point Grids + JCheckBox includeTPcheck = new JCheckBox(PROPERTY_INCLUDE_TIE_POINT_GRIDS_LABEL); + includeTPcheck.setToolTipText(PROPERTY_INCLUDE_TIE_POINT_GRIDS_TOOLTIP); + context.bind(Model.REPROJ_TIEPOINTS, includeTPcheck); + outputSettingsPanel.add(includeTPcheck); + + + // Add Delta Bands Component + JCheckBox addDeltaBandsChecker = new JCheckBox(PROPERTY_ADD_DELTA_BANDS_LABEL); + addDeltaBandsChecker.setToolTipText(PROPERTY_ADD_DELTA_BANDS_TOOLTIP); outputSettingsPanel.add(addDeltaBandsChecker); context.bind(Model.ADD_DELTA_BANDS, addDeltaBandsChecker); - outputSettingsPanel.add(new JLabel("Resampling method:")); - JComboBox resampleComboBox = new JComboBox<>(RESAMPLING_IDENTIFIER); - resampleComboBox.setPrototypeDisplayValue(RESAMPLING_IDENTIFIER[0]); - context.bind(Model.RESAMPLING_NAME, resampleComboBox); - outputSettingsPanel.add(resampleComboBox); + + reprojectionContainer.addPropertyChangeListener(Model.PRESERVE_RESOLUTION, evt -> updateOutputParameterState()); @@ -516,6 +621,74 @@ private void updateOutputParameterState() { updateProductSize(); } + private JPanel createMaskSettingsPanel() { + Preferences preferences = SnapApp.getDefault().getPreferences(); + + final TableLayout maskExpressionLayout = new TableLayout(2); + maskExpressionLayout.setTablePadding(4, 0); + maskExpressionLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + maskExpressionLayout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + maskExpressionLayout.setTableWeightX(1.0); + + maskExpressionPanel = new JPanel(maskExpressionLayout); + + editExpressionButton = new JButton(PROPERTY_MASK_EXPRESSION_BUTTON_NAME); + editExpressionButton.setPreferredSize(editExpressionButton.getPreferredSize()); + editExpressionButton.setMaximumSize(editExpressionButton.getPreferredSize()); + editExpressionButton.setMinimumSize(editExpressionButton.getPreferredSize()); + final Window parentWindow = SwingUtilities.getWindowAncestor(maskExpressionPanel); + editExpressionButton.addActionListener(new EditExpressionActionListener(parentWindow)); + expressionArea = new JTextArea(3, 40); + expressionArea.setLineWrap(true); + + JLabel maskExpressionLabel = new JLabel(PROPERTY_MASK_EXPRESSION_LABEL); + maskExpressionPanel.add(maskExpressionLabel); + maskExpressionPanel.add(new JScrollPane(expressionArea)); + + maskExpressionPanel.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + maskExpressionLabel.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + editExpressionButton.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + expressionArea.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + + String maskExpressionText = preferences.get(PROPERTY_MASK_EXPRESSION_KEY, PROPERTY_MASK_EXPRESSION_DEFAULT); + expressionArea.setText(maskExpressionText); + + boolean applyValidPixelExpressionPreference = preferences.getBoolean(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT); + applyValidPixelExpressionCheckBox = new JCheckBox(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_LABEL); + applyValidPixelExpressionCheckBox.setToolTipText(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_TOOLTIP); + applyValidPixelExpressionCheckBox.setSelected(applyValidPixelExpressionPreference); + + final TableLayout secondRowLayout = new TableLayout(3); + secondRowLayout.setTablePadding(4, 0); + secondRowLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + secondRowLayout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + secondRowLayout.setTableWeightX(1.0); + + final JPanel secondRowPanel = new JPanel(secondRowLayout); + secondRowPanel.add(applyValidPixelExpressionCheckBox); + + secondRowPanel.add(secondRowLayout.createHorizontalSpacer()); + + secondRowLayout.setTableAnchor(TableLayout.Anchor.NORTHEAST); + secondRowPanel.setLayout(secondRowLayout); + secondRowPanel.add(editExpressionButton); + + final TableLayout layout = new TableLayout(1); + layout.setTablePadding(4, 4); + layout.setTableFill(TableLayout.Fill.HORIZONTAL); + layout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + layout.setTableWeightX(1.0); + + final JPanel panel = new JPanel(layout); + panel.setBorder(BorderFactory.createTitledBorder(PROPERTY_MASKING_SECTION_LABEL)); + panel.add(maskExpressionPanel); + panel.add(secondRowPanel); + + return panel; + } + + + private JPanel createSourceProductPanel() { final JPanel panel = sourceProductSelector.createDefaultPanel(); sourceProductSelector.getProductNameLabel().setText("Name:"); @@ -577,7 +750,7 @@ public void actionPerformed(ActionEvent event) { } final OutputGeometryForm form = new OutputGeometryForm(workCopy); final ModalDialog outputParametersDialog = new OutputParametersDialog(appContext.getApplicationWindow(), - sourceProduct, workCopy); + sourceProduct, workCopy); outputParametersDialog.setContent(form); if (outputParametersDialog.show() == ModalDialog.ID_OK) { outputGeometryModel = workCopy; @@ -585,7 +758,7 @@ public void actionPerformed(ActionEvent event) { } } catch (Exception e) { appContext.handleError("Could not create a 'Coordinate Reference System'.\n" + - e.getMessage(), e); + e.getMessage(), e); } } @@ -617,8 +790,8 @@ protected void onReset() { imageGeometry = ImageGeometry.createCollocationTargetGeometry(sourceProduct, collocationProduct); } else { imageGeometry = ImageGeometry.createTargetGeometry(sourceProduct, crs, - null, null, null, null, - null, null, null, null, null); + null, null, null, null, + null, null, null, null, null); } outputGeometryFormModel.resetToDefaults(imageGeometry); } @@ -631,14 +804,20 @@ private static class Model { private static final String ADD_DELTA_BANDS = "addDeltaBands"; private static final String NO_DATA_VALUE = "noDataValue"; private static final String RESAMPLING_NAME = "resamplingName"; + private static final String RETAIN_VALID_PIXEL_EXPRESSION = "retainValidPixelExpression"; + + + Preferences preferences = SnapApp.getDefault().getPreferences(); - private boolean preserveResolution = true; - private boolean includeTiePointGrids = true; - private boolean addDeltaBands = false; - private double noDataValue = Double.NaN; - private String resamplingName = RESAMPLING_IDENTIFIER[0]; + private boolean preserveResolution = preferences.getBoolean(PROPERTY_PRESERVE_RESOLUTION_KEY, PROPERTY_PRESERVE_RESOLUTION_DEFAULT); + private boolean retainValidPixelExpression = preferences.getBoolean(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_DEFAULT); + private boolean includeTiePointGrids = preferences.getBoolean(PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY, PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT); + private boolean addDeltaBands = preferences.getBoolean(PROPERTY_ADD_DELTA_BANDS_KEY, PROPERTY_ADD_DELTA_BANDS_DEFAULT); + private double noDataValue = preferences.getDouble(PROPERTY_NO_DATA_VALUE_KEY, PROPERTY_NO_DATA_VALUE_DEFAULT); + private String resamplingName = preferences.get(PROPERTY_RESAMPLING_METHOD_KEY, PROPERTY_RESAMPLING_METHOD_DEFAULT);; } + private static class OrthorectifyProductFilter implements ProductFilter { @Override @@ -655,4 +834,27 @@ public boolean accept(Product product) { return geoCoding != null && geoCoding.canGetGeoPos() && geoCoding.canGetPixelPos(); } } -} + + public class EditExpressionActionListener implements ActionListener { + + private final Window parentWindow; + + private EditExpressionActionListener(Window parentWindow) { + this.parentWindow = parentWindow; + } + + @Override + public void actionPerformed(ActionEvent e) { + ProductExpressionPane pep = ProductExpressionPane.createBooleanExpressionPane(new Product[]{getSourceProduct()}, + getSourceProduct(), + appContext.getPreferences()); + pep.setCode(expressionArea.getText()); + final int i = pep.showModalDialog(parentWindow, "Mask Expression Editor"); + if (i == ModalDialog.ID_OK) { + expressionArea.setText(pep.getCode()); + } + + } + } + +} \ No newline at end of file diff --git a/snap-gpf-ui/src/main/resources/org/esa/snap/core/gpf/docs/gpf/org_esa_snap_core_gpf_common_reproject_ReprojectionOp.html b/snap-gpf-ui/src/main/resources/org/esa/snap/core/gpf/docs/gpf/org_esa_snap_core_gpf_common_reproject_ReprojectionOp.html index 385f89fcfe..bcfe43a30e 100644 --- a/snap-gpf-ui/src/main/resources/org/esa/snap/core/gpf/docs/gpf/org_esa_snap_core_gpf_common_reproject_ReprojectionOp.html +++ b/snap-gpf-ui/src/main/resources/org/esa/snap/core/gpf/docs/gpf/org_esa_snap_core_gpf_common_reproject_ReprojectionOp.html @@ -17,20 +17,20 @@

Reproject Operator Description

Overview

- - - - + + + +
Name:Reproject
Full name:org.esa.snap.core.gpf.common.reproject.ReprojectionOp
Purpose:Reprojection of a source product to a target Coordinate Reference System.
Version:1.0
Name:Reproject
Full name:org.esa.snap.core.gpf.common.reproject.ReprojectionOp
Purpose:Reprojection of a source product to a target Coordinate Reference System.
Version:1.0

Description

- The reprojection operator is used to geo-reference data products. - Beside plain reprojection it is able to use a Digital Elevation Model (DEM) to orthorectify a data product and - to collocate one product with another. -

- The following XML sample shows how to integrate the {@code Reproject} operator in a processing graph (an - Lambert_Azimuthal_Equal_Area projection using the WGS-84 datum): -

+    The reprojection operator is used to geo-reference data products.
+    Beside plain reprojection it is able to use a Digital Elevation Model (DEM) to orthorectify a data product and
+    to collocate one product with another.
+

+ The following XML sample shows how to integrate the {@code Reproject} operator in a processing graph (an + Lambert_Azimuthal_Equal_Area projection using the WGS-84 datum): +

     <node id="reprojectNode">
         <operator>Reproject</operator>
         <sources>
@@ -72,166 +72,196 @@ 

Description

<noDataValue>NaN</noDataValue> <includeTiePointGrids>true</includeTiePointGrids> <addDeltaBands>false</addDeltaBands> + <applyValidPixelExpression>false</applyValidPixelExpression> + <retainValidPixelExpression>false</retainValidPixelExpression> + <maskExpression>false</maskExpression> </parameters> </node>
+

Sources

- - - - - - - - - - - - + + + + + + + + + + + +
NameDescription
sourceProductThe product which will be reprojected.
collocationProductThe source product will be collocated with this product.
NameDescription
sourceProductThe product which will be reprojected.
collocationProductThe source product will be collocated with this product.

Parameters

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameData TypeDefaultDescriptionConstraints
wktFileFileA file which contains the target Coordinate Reference System in WKT format.
crsStringA text specifying the target Coordinate Reference System, either in WKT or as an authority code. For appropriate EPSG authority codes see (www.epsg-registry.org). AUTO authority can be used with code 42001 (UTM), and 42002 (Transverse Mercator) where the scene center is used as reference. Examples: EPSG:4326, AUTO:42001
resamplingStringNearestThe method used for resampling of floating-point raster data.value set: [Nearest, Bilinear, Bicubic]
referencePixelXDoubleThe X-position of the reference pixel.
referencePixelYDoubleThe Y-position of the reference pixel.
eastingDoubleThe easting of the reference pixel.
northingDoubleThe northing of the reference pixel.
orientationDouble0The orientation of the output product (in degree).interval: [-360,360]
pixelSizeXDoubleThe pixel size in X direction given in CRS units.
pixelSizeYDoubleThe pixel size in Y direction given in CRS units.
widthIntegerThe width of the target product.
heightIntegerThe height of the target product.
tileSizeXIntegerThe tile size in X direction.
tileSizeYIntegerThe tile size in Y direction.
orthorectifybooleanfalseWhether the source product should be orthorectified. (Not applicable to all products)
elevationModelNameStringThe name of the elevation model for the orthorectification. If not given tie-point data is used.
noDataValueDoubleThe value used to indicate no-data.
includeTiePointGridsbooleantrueWhether tie-point grids should be included in the output product.
addDeltaBandsbooleanfalseWhether to add delta longitude and latitude bands.
NameData TypeDefaultDescriptionConstraints
wktFileFileA file which contains the target Coordinate Reference System in WKT format.
crsStringA text specifying the target Coordinate Reference System, either in WKT or as an authority code. For appropriate EPSG authority codes see (www.epsg-registry.org). AUTO authority can be used with code 42001 (UTM), and 42002 (Transverse Mercator) where the scene center is used as reference. Examples: EPSG:4326, AUTO:42001
resamplingStringNearestThe method used for resampling of floating-point raster data.value set: [Nearest, Bilinear, Bicubic]
referencePixelXDoubleThe X-position of the reference pixel.
referencePixelYDoubleThe Y-position of the reference pixel.
eastingDoubleThe easting of the reference pixel.
northingDoubleThe northing of the reference pixel.
orientationDouble0The orientation of the output product (in degree).interval: [-360,360]
pixelSizeXDoubleThe pixel size in X direction given in CRS units.
pixelSizeYDoubleThe pixel size in Y direction given in CRS units.
widthIntegerThe width of the target product.
heightIntegerThe height of the target product.
tileSizeXIntegerThe tile size in X direction.
tileSizeYIntegerThe tile size in Y direction.
orthorectifybooleanfalseWhether the source product should be orthorectified. (Not applicable to all products)
elevationModelNameStringThe name of the elevation model for the orthorectification. If not given tie-point data is used.
noDataValueDoubleThe value used to indicate no-data.
includeTiePointGridsbooleantrueWhether tie-point grids should be included in the output product.
addDeltaBandsbooleanfalseWhether to add delta longitude and latitude bands.
applyValidPixelExpressionbooleantrueConstrain which pixels get used based on the valid expression of the source file bands.
retainValidPixelExpressionbooleantrueThe valid pixel expression of each of the source file bands will be retained and stored in the corresponding + bands of the reprojected file.
maskExpressionbooleanfalseCustom logical expression to constrain which pixels of the source band get used.

diff --git a/snap-graph-builder/src/main/java/org/esa/snap/graphbuilder/gpf/ui/ReprojectionUI.java b/snap-graph-builder/src/main/java/org/esa/snap/graphbuilder/gpf/ui/ReprojectionUI.java index c75abed416..35eedb35b0 100644 --- a/snap-graph-builder/src/main/java/org/esa/snap/graphbuilder/gpf/ui/ReprojectionUI.java +++ b/snap-graph-builder/src/main/java/org/esa/snap/graphbuilder/gpf/ui/ReprojectionUI.java @@ -1,15 +1,27 @@ package org.esa.snap.graphbuilder.gpf.ui; +import com.bc.ceres.binding.ConversionException; +import com.bc.ceres.binding.PropertyContainer; import com.bc.ceres.binding.PropertySet; +import com.bc.ceres.binding.PropertySetDescriptor; 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.gpf.GPF; +import org.esa.snap.core.gpf.OperatorSpi; +import org.esa.snap.core.gpf.annotations.ParameterDescriptorFactory; +import org.esa.snap.core.gpf.common.BandMathsOp; +import org.esa.snap.core.gpf.descriptor.OperatorDescriptor; +import org.esa.snap.core.gpf.descriptor.PropertySetDescriptorFactory; +import org.esa.snap.core.param.ParamChangeEvent; +import org.esa.snap.core.param.ParamChangeListener; +import org.esa.snap.core.param.ParamProperties; +import org.esa.snap.core.param.Parameter; +import org.esa.snap.core.util.Debug; import org.esa.snap.core.util.ProductUtils; +import org.esa.snap.core.util.SystemUtils; import org.esa.snap.rcp.SnapApp; import org.esa.snap.ui.AbstractDialog; import org.esa.snap.ui.AppContext; @@ -21,6 +33,7 @@ import org.esa.snap.ui.crs.OutputGeometryForm; import org.esa.snap.ui.crs.OutputGeometryFormModel; import org.esa.snap.ui.crs.PredefinedCrsForm; +import org.esa.snap.ui.product.ProductExpressionPane; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; @@ -28,8 +41,11 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.HashMap; import java.util.Map; +import java.util.prefs.Preferences; + +import static org.esa.snap.rcp.preferences.general.ReprojectionController.*; + /** * User interface for Reprojection @@ -38,6 +54,14 @@ public class ReprojectionUI extends BaseOperatorUI { private static final String[] RESAMPLING_IDENTIFIER = {"Nearest", "Bilinear", "Bicubic"}; + private static final String _PARAM_NAME_REPROJECT = "reproject"; + private Parameter paramResamplingName = null; + private Parameter paramIncludeTiePointGrids = null; + private Parameter paramAddDeltaBands = null; + private Parameter paramNoDataValue = null; + private Parameter paramMaskExpression = null; + private Parameter paramApplyValidPixelExpression = null; + private Parameter paramRetainValidPixelExpression = null; private JScrollPane scrollPane; private boolean orthoMode = false; @@ -52,18 +76,30 @@ public class ReprojectionUI extends BaseOperatorUI { private ReprojectionUI.InfoForm infoForm; private CoordinateReferenceSystem crs; + private JPanel maskExpressionPanel; + //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 resampleComboBox = new JComboBox<>(RESAMPLING_IDENTIFIER); + JCheckBox preserveResolutionCheckBox; + JCheckBox includeTPcheck; + JTextField noDataField; + JCheckBox addDeltaBandsCheckBox; + JComboBox resampleComboBox; + + + // Components of Masking + private boolean applyValidPixelExpression = PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT; + private JCheckBox applyValidPixelExpressionCheckBox; + private boolean retainValidPixelExpression; + private JCheckBox retainValidPixelExpressionCheckBox; + private JButton editExpressionButton; + private JTextArea expressionArea; //Create panel @Override @@ -71,6 +107,7 @@ public JComponent CreateOpTab(String operatorName, Map parameter initializeOperatorUI(operatorName, parameterMap); + initVariables(); final JComponent panel = createPanel(); initParameters(); @@ -82,16 +119,31 @@ public JComponent CreateOpTab(String operatorName, Map parameter //called when sourceProduct is set @Override public void initParameters() { + if (!propertySet.getValue("orientation").equals(0.0) || + propertySet.getValue("easting") != null || + propertySet.getValue("northing") != null || + propertySet.getValue("pixelSizeX") != null || + propertySet.getValue("pixelSizeY") != null || + propertySet.getValue("referencePixelX") != null || + propertySet.getValue("referencePixelY") != null || + propertySet.getValue("width") != null || + propertySet.getValue("height") != null) { + preserveResolutionCheckBox.setSelected(false); + } + + 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); + addDeltaBandsCheckBox.setEnabled(true); } else { - addDeltaBandsChecker.setEnabled(false); + addDeltaBandsCheckBox.setEnabled(false); } } updateCRS(); - updateParameters(); + +// updateUIState(_PARAM_NAME_REPROJECT); +// updateParameters(); } @@ -103,29 +155,40 @@ public UIValidation validateParameters() { @Override public void updateParameters() { - - paramMap.clear(); - paramMap.put("resamplingName", resampleComboBox.getSelectedItem().toString()); + if (!propertySet.getValue("orientation").equals(0.0) || + propertySet.getValue("easting") != null || + propertySet.getValue("northing") != null || + propertySet.getValue("pixelSizeX") != null || + propertySet.getValue("pixelSizeY") != null || + propertySet.getValue("referencePixelX") != null || + propertySet.getValue("referencePixelY") != null || + propertySet.getValue("width") != null || + propertySet.getValue("height") != null) { + preserveResolutionCheckBox.setSelected(false); + } +// paramMap.clear(); + paramMap.put("resampling", resampleComboBox.getSelectedItem().toString()); paramMap.put("includeTiePointGrids", includeTPcheck.isSelected()); - paramMap.put("addDeltaBands", addDeltaBandsChecker.isSelected()); + paramMap.put("addDeltaBands", addDeltaBandsCheckBox.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 productMap = new HashMap<>(5); - // productMap.put("source", getSourceProduct()); - // if (collocationCrsUI.getRadioButton().isSelected()) { - // collocationCrsUI.prepareShow(); - // productMap.put("collocateWith", collocationCrsUI.getCollocationProduct()); - // } - // } + + // 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 productMap = new HashMap<>(5); + // productMap.put("source", getSourceProduct()); + // if (collocationCrsUI.getRadioButton().isSelected()) { + // collocationCrsUI.prepareShow(); + // productMap.put("collocateWith", collocationCrsUI.getCollocationProduct()); + // } + // } if (orthoMode) { @@ -149,8 +212,56 @@ public void updateParameters() { paramMap.put("width", container.getValue("width")); paramMap.put("height", container.getValue("height")); } + + paramMap.put("applyValidPixelExpression", applyValidPixelExpressionCheckBox.isSelected()); + paramMap.put("retainValidPixelExpression", retainValidPixelExpressionCheckBox.isSelected()); + if (expressionArea.getText() != null) { + paramMap.put("maskExpression", expressionArea.getText()); + } } + private void initVariables() { + final ParamChangeListener paramChangeListener = createParamChangeListener(); + + paramResamplingName = new Parameter("resampling", paramMap.get("resampling")); + paramResamplingName.getProperties().setValueSetBound(false); + paramResamplingName.getProperties().setLabel("ResamplingName"); /*I18N*/ + paramResamplingName.addParamChangeListener(paramChangeListener); + + paramIncludeTiePointGrids = new Parameter("includeTiePointGrids", paramMap.get("includeTiePointGrids")); + paramIncludeTiePointGrids.getProperties().setValueSetBound(false); + paramIncludeTiePointGrids.getProperties().setLabel("IncludeTiePointGrids"); /*I18N*/ + paramIncludeTiePointGrids.addParamChangeListener(paramChangeListener); + + paramAddDeltaBands = new Parameter("addDeltaBands", paramMap.get("addDeltaBands")); + paramAddDeltaBands.getProperties().setValueSetBound(false); + paramAddDeltaBands.getProperties().setLabel("AddDeltaBands"); /*I18N*/ + paramAddDeltaBands.addParamChangeListener(paramChangeListener); + + paramApplyValidPixelExpression = new Parameter("applyValidPixelExpression", paramMap.get("applyValidPixelExpression")); + paramApplyValidPixelExpression.getProperties().setValueSetBound(false); + paramApplyValidPixelExpression.getProperties().setLabel("ApplyValidPixelExpression"); /*I18N*/ + paramApplyValidPixelExpression.addParamChangeListener(paramChangeListener); + + paramRetainValidPixelExpression = new Parameter("retainValidPixelExpression", paramMap.get("retainValidPixelExpression")); + paramRetainValidPixelExpression.getProperties().setValueSetBound(false); + paramRetainValidPixelExpression.getProperties().setLabel("RetainValidPixelExpression"); /*I18N*/ + paramRetainValidPixelExpression.addParamChangeListener(paramChangeListener); + + paramNoDataValue = new Parameter("noDataValue", paramMap.get("noDataValue")); + paramNoDataValue.getProperties().setValueSetBound(false); + paramNoDataValue.getProperties().setLabel("No-Data Value"); /*I18N*/ + paramNoDataValue.addParamChangeListener(paramChangeListener); + + paramMaskExpression = new Parameter("maskExpressiong", paramMap.get("maskExpression")); + paramMaskExpression.getProperties().setLabel("Mask Expression"); /*I18N*/ + paramMaskExpression.getProperties().setDescription("Mask expression"); /*I18N*/ + paramMaskExpression.getProperties().setNumRows(5); +// paramExpression.getProperties().setEditorClass(ArithmetikExpressionEditor.class); +// paramExpression.getProperties().setValidatorClass(BandArithmeticExprValidator.class); + +// setArithmetikValues(); + } private JComponent createPanel() { final JPanel parameterPanel = new JPanel(); @@ -178,13 +289,19 @@ private JComponent createPanel() { parameterPanel.add(demSelector); } + parameterPanel.add(createMaskSettingsPanel()); + + //create and add the output setting panel - parameterPanel.add(createOuputSettingsPanel()); + parameterPanel.add(createOutputSettingsPanel()); + //create and add the info panel infoForm = new ReprojectionUI.InfoForm(); parameterPanel.add(infoForm.createUI()); + + //add change listener crsSelectionPanel.addPropertyChangeListener("crs", evt -> updateCRS()); updateCRS(); @@ -192,6 +309,7 @@ private JComponent createPanel() { } + Product getSourceProduct() { if(!hasSourceProducts()) { return null; @@ -242,16 +360,16 @@ private void updateProductSize() { 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); - - // } + // 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; @@ -344,9 +462,9 @@ JPanel createUI() { 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); + "Coordinate reference system as well known text", + scrollPane, + ModalDialog.ID_OK, null); dialog.show(); }); wktButton.setEnabled(false); @@ -355,23 +473,37 @@ JPanel createUI() { } } - private JPanel createOuputSettingsPanel() { - final TableLayout tableLayout = new TableLayout(3); + private JPanel createOutputSettingsPanel() { + + Preferences preferences = SnapApp.getDefault().getPreferences(); + + + final TableLayout tableLayout = new TableLayout(2); 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")); + outputSettingsPanel.setBorder(BorderFactory.createTitledBorder(PROPERTY_OUTPUT_SETTINGS_SECTION_LABEL)); + + + final TableLayout resolutionTableLayout = new TableLayout(2); + resolutionTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + resolutionTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + resolutionTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + resolutionTableLayout.setTablePadding(4, 4); + + final JPanel resolutionPanel = new JPanel(resolutionTableLayout); + resolutionPanel.setBorder(BorderFactory.createTitledBorder("Resolution")); + + + // Preserve resolution + preserveResolutionCheckBox = new JCheckBox(PROPERTY_PRESERVE_RESOLUTION_LABEL); + preserveResolutionCheckBox.setSelected(preferences.getBoolean(PROPERTY_PRESERVE_RESOLUTION_KEY, PROPERTY_PRESERVE_RESOLUTION_DEFAULT)); + preserveResolutionCheckBox.setToolTipText(PROPERTY_PRESERVE_RESOLUTION_TOOLTIP); preserveResolutionCheckBox.addActionListener(e -> { if (preserveResolutionCheckBox.isSelected()) { outputParamButton.setEnabled(false); @@ -380,29 +512,223 @@ private JPanel createOuputSettingsPanel() { } }); - outputSettingsPanel.add(preserveResolutionCheckBox); + resolutionPanel.add(preserveResolutionCheckBox); - outputSettingsPanel.add(includeTPcheck); - outputParamButton = new JButton("Output Parameters..."); + outputParamButton = new JButton(PROPERTY_RESOLUTION_PARAMETERS_BUTTON_NAME); outputParamButton.setEnabled(!preserveResolutionCheckBox.isSelected()); outputParamButton.addActionListener(new OutputParamActionListener()); - outputSettingsPanel.add(outputParamButton); + resolutionPanel.add(outputParamButton); + + + outputSettingsPanel.add(resolutionPanel); + + + // Resampling method + final TableLayout resamplingTableLayout = new TableLayout(2); + resamplingTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + resamplingTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + resamplingTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + resamplingTableLayout.setTablePadding(4, 4); + final JPanel resamplingPanel = new JPanel(resamplingTableLayout); + + JLabel resamplingMethodLabel = new JLabel(PROPERTY_RESAMPLING_METHOD_LABEL); + resamplingMethodLabel.setToolTipText(PROPERTY_RESAMPLING_METHOD_TOOLTIP); + resampleComboBox = new JComboBox<>(PROPERTY_RESAMPLING_METHOD_OPTIONS); + String resamplingMethodPreference = preferences.get(PROPERTY_RESAMPLING_METHOD_KEY, PROPERTY_RESAMPLING_METHOD_DEFAULT); + if (paramResamplingName.getValueAsText() != null) { + resamplingMethodPreference = paramResamplingName.getValueAsText(); + } + resampleComboBox.setPrototypeDisplayValue(resamplingMethodPreference); + resampleComboBox.setSelectedItem(resamplingMethodPreference); + resampleComboBox.setToolTipText(PROPERTY_RESAMPLING_METHOD_TOOLTIP); + resamplingPanel.add(resamplingMethodLabel); + resamplingPanel.add(resampleComboBox); + + outputSettingsPanel.add(resamplingPanel); + + - outputSettingsPanel.add(new JLabel("No-data value:")); - outputSettingsPanel.add(noDataField); + // No-data Value Components + final TableLayout noDataTableLayout = new TableLayout(2); + noDataTableLayout.setTableAnchor(TableLayout.Anchor.WEST); + noDataTableLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + noDataTableLayout.setColumnFill(0, TableLayout.Fill.NONE); + noDataTableLayout.setColumnFill(1, TableLayout.Fill.NONE); + noDataTableLayout.setColumnAnchor(0, TableLayout.Anchor.EAST); + noDataTableLayout.setColumnAnchor(1, TableLayout.Anchor.WEST); + noDataTableLayout.setCellWeightX(0,0,0.0); + noDataTableLayout.setCellWeightX(0,1,1.0); + + noDataTableLayout.setTablePadding(4, 4); + final JPanel noDataPanel = new JPanel(noDataTableLayout); + + JLabel noDataLabel = new JLabel(PROPERTY_NO_DATA_VALUE_LABEL); + noDataLabel.setToolTipText(PROPERTY_NO_DATA_VALUE_TOOLTIP); + String noDataPreference = Double.toString(preferences.getDouble(PROPERTY_NO_DATA_VALUE_KEY, PROPERTY_NO_DATA_VALUE_DEFAULT)); + if (paramNoDataValue.getValue() != null) { + noDataPreference = paramNoDataValue.getValueAsText(); + } +// noDataField = new JTextField(Double.toString(noDataPreference), 8); + noDataField = new JTextField(noDataPreference, 8); + noDataField.setToolTipText(PROPERTY_NO_DATA_VALUE_TOOLTIP); + noDataPanel.add(noDataLabel); + noDataPanel.add(noDataField); + + outputSettingsPanel.add(noDataPanel); + + + + //Retain valid pixel expression + retainValidPixelExpressionCheckBox = new JCheckBox(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_LABEL); + boolean retainValidPixelExpressionPreference = preferences.getBoolean(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_DEFAULT); + if (paramRetainValidPixelExpression.getValue() != null) { + retainValidPixelExpressionPreference = (Boolean) paramRetainValidPixelExpression.getValue(); + } + retainValidPixelExpressionCheckBox.setSelected(retainValidPixelExpressionPreference); + retainValidPixelExpressionCheckBox.setToolTipText(PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_TOOLTIP); + outputSettingsPanel.add(retainValidPixelExpressionCheckBox); + + // Tie-point grids + includeTPcheck = new JCheckBox(PROPERTY_INCLUDE_TIE_POINT_GRIDS_LABEL); + boolean includeTPcheckPreference = preferences.getBoolean(PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY, PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT); + if (paramIncludeTiePointGrids.getValue() != null) { + includeTPcheckPreference = (Boolean) paramIncludeTiePointGrids.getValue(); + } +// includeTPcheck.setSelected(preferences.getBoolean(PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY, PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT)); + includeTPcheck.setSelected(includeTPcheckPreference); + includeTPcheck.setToolTipText(PROPERTY_INCLUDE_TIE_POINT_GRIDS_TOOLTIP); + outputSettingsPanel.add(includeTPcheck); + + + + + + // Add delta bands component + addDeltaBandsCheckBox = new JCheckBox(PROPERTY_ADD_DELTA_BANDS_LABEL); + boolean addDeltaBandsPreference = preferences.getBoolean(PROPERTY_ADD_DELTA_BANDS_KEY, PROPERTY_ADD_DELTA_BANDS_DEFAULT); + if (paramAddDeltaBands.getValue() != null) { + addDeltaBandsPreference = (Boolean) paramAddDeltaBands.getValue(); + } + addDeltaBandsCheckBox.setSelected(addDeltaBandsPreference); + addDeltaBandsCheckBox.setToolTipText(PROPERTY_ADD_DELTA_BANDS_TOOLTIP); + outputSettingsPanel.add(addDeltaBandsCheckBox); + - outputSettingsPanel.add(addDeltaBandsChecker); - outputSettingsPanel.add(new JLabel("Resampling method:")); - resampleComboBox.setPrototypeDisplayValue(RESAMPLING_IDENTIFIER[0]); - outputSettingsPanel.add(resampleComboBox); return outputSettingsPanel; } + + + + + + + + private JPanel createMaskSettingsPanel() { + Preferences preferences = SnapApp.getDefault().getPreferences(); + + final TableLayout maskExpressionLayout = new TableLayout(2); + maskExpressionLayout.setTablePadding(4, 0); + maskExpressionLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + maskExpressionLayout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + maskExpressionLayout.setTableWeightX(1.0); + + maskExpressionPanel = new JPanel(maskExpressionLayout); + + editExpressionButton = new JButton(PROPERTY_MASK_EXPRESSION_BUTTON_NAME); + editExpressionButton.setPreferredSize(editExpressionButton.getPreferredSize()); + editExpressionButton.setMaximumSize(editExpressionButton.getPreferredSize()); + editExpressionButton.setMinimumSize(editExpressionButton.getPreferredSize()); + final Window parentWindow = SwingUtilities.getWindowAncestor(maskExpressionPanel); + editExpressionButton.addActionListener(new EditExpressionActionListener(parentWindow)); + expressionArea = new JTextArea(3, 40); + expressionArea.setLineWrap(true); + + JLabel maskExpressionLabel = new JLabel(PROPERTY_MASK_EXPRESSION_LABEL); + maskExpressionPanel.add(maskExpressionLabel); + maskExpressionPanel.add(new JScrollPane(expressionArea)); + + maskExpressionPanel.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + maskExpressionLabel.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + editExpressionButton.setToolTipText(PROPERTY_MASK_EXPRESSION_TOOLTIP); + expressionArea.setToolTipText( PROPERTY_MASK_EXPRESSION_TOOLTIP); + + String maskExpressionText = preferences.get(PROPERTY_MASK_EXPRESSION_KEY, PROPERTY_MASK_EXPRESSION_DEFAULT); + if (paramMaskExpression.getValueAsText() != null) { + maskExpressionText = paramMaskExpression.getValueAsText(); + } + expressionArea.setText(maskExpressionText); + + boolean applyValidPixelExpression = preferences.getBoolean(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT); + if (paramApplyValidPixelExpression.getValue() != null) { + applyValidPixelExpression = (Boolean) paramApplyValidPixelExpression.getValue(); + } + applyValidPixelExpressionCheckBox = new JCheckBox(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_LABEL); + applyValidPixelExpressionCheckBox.setToolTipText(PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_TOOLTIP); + applyValidPixelExpressionCheckBox.setSelected(applyValidPixelExpression); + + final TableLayout secondRowLayout = new TableLayout(3); + secondRowLayout.setTablePadding(4, 0); + secondRowLayout.setTableFill(TableLayout.Fill.HORIZONTAL); + secondRowLayout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + secondRowLayout.setTableWeightX(1.0); + + final JPanel secondRowPanel = new JPanel(secondRowLayout); + secondRowPanel.add(applyValidPixelExpressionCheckBox); + + secondRowPanel.add(secondRowLayout.createHorizontalSpacer()); + + secondRowLayout.setTableAnchor(TableLayout.Anchor.NORTHEAST); + secondRowPanel.setLayout(secondRowLayout); + secondRowPanel.add(editExpressionButton); + + final TableLayout layout = new TableLayout(1); + layout.setTablePadding(4, 4); + layout.setTableFill(TableLayout.Fill.HORIZONTAL); + layout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + layout.setTableWeightX(1.0); + + final JPanel panel = new JPanel(layout); + panel.setBorder(BorderFactory.createTitledBorder(PROPERTY_MASKING_SECTION_LABEL)); + panel.add(maskExpressionPanel); + panel.add(secondRowPanel); + + return panel; + } + + + private class EditExpressionActionListener implements ActionListener { + + private final Window parentWindow; + + private EditExpressionActionListener(Window parentWindow) { + this.parentWindow = parentWindow; + } + + @Override + public void actionPerformed(ActionEvent e) { + ProductExpressionPane pep = ProductExpressionPane.createBooleanExpressionPane(new Product[]{getSourceProduct()}, + getSourceProduct(), + appContext.getPreferences()); +// pep.setCode(expressionArea.getText()); + pep.setCode(paramMaskExpression.getValueAsText()); + final int i = pep.showModalDialog(parentWindow, "Mask Expression Editor"); + if (i == ModalDialog.ID_OK) { + expressionArea.setText(pep.getCode()); + paramMaskExpression.setValue(pep.getCode(), null); + Debug.trace("MaskExpressionDialog: expression is: " + pep.getCode()); + +// maskExpression = paramMaskExpression.getValueAsText(); + } + + } + } + private void updateOutputParameterState() { outputParamButton.setEnabled(!preserveResolutionCheckBox.isSelected() && (crs != null)); updateProductSize(); @@ -429,17 +755,27 @@ public void actionPerformed(ActionEvent event) { OutputGeometryFormModel workCopy; if (outputGeometryModel != null) { workCopy = new OutputGeometryFormModel(outputGeometryModel); - } else { - // final Product collocationProduct = collocationCrsUI.getCollocationProduct(); - // if (collocationCrsUI.getRadioButton().isSelected() && collocationProduct != null) { + } else if (!propertySet.getValue("orientation").equals(0.0) || + propertySet.getValue("easting") != null || + propertySet.getValue("northing") != null || + propertySet.getValue("pixelSizeX") != null || + propertySet.getValue("pixelSizeY") != null || + propertySet.getValue("referencePixelX") != null || + propertySet.getValue("referencePixelY") != null || + propertySet.getValue("width") != null || + propertySet.getValue("height") != null) { + // final Product collocationProduct = collocationCrsUI.getCollocationProduct(); + // if (collocationCrsUI.getRadioButton().isSelected() && collocationProduct != null) { // workCopy = new OutputGeometryFormModel(sourceProduct, collocationProduct); - // } else { - workCopy = new OutputGeometryFormModel(sourceProduct, crs); - // } + // } else { + workCopy = new OutputGeometryFormModel(sourceProduct, crs, propertySet); + // } + } else { + workCopy = new OutputGeometryFormModel(sourceProduct, crs); } final OutputGeometryForm form = new OutputGeometryForm(workCopy); final ModalDialog outputParametersDialog = new OutputParametersDialog(appContext.getApplicationWindow(), - sourceProduct, workCopy); + sourceProduct, workCopy); outputParametersDialog.setContent(form); if (outputParametersDialog.show() == ModalDialog.ID_OK) { outputGeometryModel = workCopy; @@ -447,7 +783,7 @@ public void actionPerformed(ActionEvent event) { } } catch (Exception e) { appContext.handleError("Could not create a 'Coordinate Reference System'.\n" + - e.getMessage(), e); + e.getMessage(), e); } } @@ -470,16 +806,56 @@ public OutputParametersDialog(Window parent, Product sourceProduct, @Override protected void onReset() { - // final Product collocationProduct = collocationCrsUI.getCollocationProduct(); + // 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); + // } else { + imageGeometry = ImageGeometry.createTargetGeometry(sourceProduct, crs, + null, null, null, null, + null, null, null, null, null); //} outputGeometryFormModel.resetToDefaults(imageGeometry); } } + + private ParamChangeListener createParamChangeListener() { + return new ParamChangeListener() { + + public void parameterValueChanged(ParamChangeEvent event) { + updateUIState(event.getParameter().getName()); + } + }; + } + + private void updateUIState(String parameterName) { + + if (parameterName == null) { + return; + } + + if (parameterName.equals(_PARAM_NAME_REPROJECT)) { +// final boolean b = targetProduct != null; + paramResamplingName.setUIEnabled(true); + editExpressionButton.setEnabled(true); + paramIncludeTiePointGrids.setUIEnabled(true); + paramAddDeltaBands.setUIEnabled(true); + paramNoDataValue.setUIEnabled(true); + paramMaskExpression.setUIEnabled(true); + paramApplyValidPixelExpression.setUIEnabled(true); + paramRetainValidPixelExpression.setUIEnabled(true); +// if (b) { +// setArithmetikValues(); +// } +// +// final String selectedBandName = paramBand.getValueAsText(); +// if (b) { +// if (selectedBandName != null && selectedBandName.length() > 0) { +// targetBand = targetProduct.getBand(selectedBandName); +// } +// } + } + } } + + diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/Reprojection.html b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/Reprojection.html index f525842323..ad34407a8e 100644 --- a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/Reprojection.html +++ b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/Reprojection.html @@ -1,18 +1,3 @@ - @@ -31,133 +16,560 @@ + -

Reprojection Dialog

+ +

Overview

+ +

+ The Reprojection tool enables you to take any file (one which contains geo-coding) and resample it into a new file + of a specified map projection. Some key parameters which you can specify are: coordinate reference system (CRS), + resolution, masking, interpolation method, and geographic location. +

+ +

+ The Reproject tool can be accessed in the menu system (Raster -> Geometric -> Reprojection) and at the gpf command line. +

+ +

+ Figures 1a and 1b illustrate the results of applying the Reproject tool to a level-2 file using an oblique stereographic + projection. Figure 1a is the original unmapped level-2 image (of a rhos_s band) and figure 1b is the reprojected image. + Note: since all pixels in the reprojected file contain geocoding, the LandMask tool was + subsequently used on the reprojected file to add Land (in brown) and water (in aqua) masks which span beyond the + actual level-2 scene boundaries. +

+ +
+ + + + + +
+
+
+ Figure 1a. Unmapped scene of a level-2 file
+
+
+
+
+ Figure 1b. Projected scene of a level-2 file
(Oblique Sterographic)
+
+
+
+ + + + +

I/O Parameters

+ +
+

+ Figure 1. I/O Parameters +
+ + + +

- Source Product -

+ +

+ Name
This is the file to be reprojected and serves as the input file to the Reprojection Tool. You + may conveniently select one of the files currently loaded in SeaDAS using the drop down selector. In this case, a file + reference index appears to the left of the file name indicating that it is a loaded file and not a direct system + file. To select a file directly from your computer system, use the selector button to the right and navigate to the + desired file. A file selected this way directly from your system will not have a file reference number displayed next to it. +

+ Note: a loaded file can differ from a system file (even though they may bear the same name) in that you may have + made changes to the loaded file in SeaDAS and not saved them. +

+ + + +

- Target Product -

+ +

+ Name
This is the name of the reprojected file which will be generated. The default behavior appends + "_reprojected" to the original filename. +

+ +

+ Save file as
Used to specify whether the file should be physically saved to the file system. The + combo box presents a list of file formats, currently BEAM-DIMAP, GeoTIFF, and HDF5. +

+ Note: if deselected this tool will run much faster as the reprojection + does not actually occur at the time of run. Subsequently when the user opens a band in the reprojected file the + reprojection occurs for that band only. +

+ +

+ Directory
Location in which to save the reprojected file. +

+ Note: the default is the last directory saved to by any standard GUI tool in SeaDAS +

+ +

+ Open in SNAP (SeaDAS)
Used to specify whether the file should be automatically opened in SNAP (SeaDAS). +

+ + +

+
+ + + + +

Reprojection Parameters

+ + +
+

+ Figure 2. Map Projection & Settings Tab + +
+ + +

Coordinate Reference System (CRS)

+

+ There are 3 options for selecting a CRS: create one yourself - "Custom CRS"; select one - "Predefined CRS"; or use + one + from an existing file - "Use CRS of file". +

+ + +

+ Custom CRS
+ With this option you will manually select the map projection (along with it's parameters) and the datum to use. +

+ +

+ Geodetic datum
+ The coordinate system for locating positions on the Earth. In general, these are based on reference ellipsoids used + to represent the shape of the Earth. You can select from a variety of datums. The most common (and default) + is "WGS 84" (WGS 1984, EPSG:4326). + +

+ +

+ Projection
+ The map projection (or how the 3 dimensional Earth's surface will be transformed onto a 2 dimensional surface). + Select from a list of map projections. If a projection requires parameters then the "Projection Parameters" button will + become selectable. +

+ + +

+ Projection Parameters
+ This opens a window of selectable parameters needed by the selected map projection. These contain default values, + but likely + you will want to modify these values based on your scene location or region of interest. + (See CRS Parameters for a more on these + parameters) +

+ + +

+ + +

+ Predefined CRS
+ SeaDAS contains a multitude of pre-defined coordinate reference systems including the EPSG (European Petroleum + Survey Group) Geodetic Parameter + Dataset. Use the selector to the right to choose one + of these projections. ( + See Predefined CRS for more on this). +

+ +

+ Use CRS of file
+ Select a file from your system (one with geo-coding) and use the identical map projection criteria and geographic + boundaries of that file. This will have the effect that both files are collocated (same raster grid size and grid + geocoding) but separate files. See the Collocation Tool if you wish to actually merge the files together. +

+
+ + + + + + +

+ Masking +

+ +

+ Expression
+ You can create a custom logical expression to constrain which pixels of the source band get used. +

+ + +

+ Edit Expression
+ This accesses the Expression Editor to help you construct a logical expression. Note that the mask expression + you create here is applied to all of the bands so avoid band specific expressions. +

+ + +

+ Apply source valid pixel expression
+ Each band of the source file has a valid pixel expression which designates whether a pixel is valid for display + or some other operation. These expressions are unique to each band. When reprojecting a source file you want to + consider whether or not to allow the "invalid" pixels to be used or ignored. + When this is selected only the pixels which are "valid" based on the valid pixel expression contraints, + will be used in the creation of the reproject file. +

+ + +
+ + + + +

+ Output Settings +

+ + +

+ Preserve resolution
+ Use the SeaDAS defaults which will automatically determine a "best-fit" resolution, output file size, and easting + and westing. You can deselect this and manually set these parameters by clicking "Output Parameters". + (see details) +

+ +

+ Resampling method
+ This is the interpolation method. Choose between Nearest, Bilinear, and Bicubic. (See details) +

+ +

+ No-data value
+ The default no-data value is used for output pixels in the projected band which have either no corresponding pixel + in the source product or the source pixel is invalid. +

+ + +

+ Retain valid pixel expression
+ The valid pixel expression of each of the source file bands will be retained and stored in the corresponding + bands of the reprojected file. +

+ + +

+ Reproject tie-point grids
+ Specifies whether or not the tie-point grids shall be included. If they are reprojected they will appear as bands in + the target product and not any more as tie-point grids. +

+ + +

+ Add delta lat/lon bands
+ Specifies whether or not delta latitude and longitude bands will be added to the target product. These are virtual + bands, which can be used to assess the accuracy of the new geo-coding given by the Coordinate Reference System (CRS) + with respect to the old geo-coding. +

+ + + + + + +
+ + +Output Information + +

+ Scene width
+ This will be the width in pixels of the output file. +

+ +

+ Scene height
+ This will be the height in pixels of the output file. +

+ +

+ Center longitude
+ This is the longitude of the center of the source file. +

+ +

+ Center latitude
+ This is the latitude of the center of the source file. +

+ +

+ CRS
+ This is name of the chosen projection and datum +

+ +

+ Show WKT
+ This is the CRS WKT (well-known text) +

+ +

+
+ + + +

GUI: CRS Parameters

- Here you can create a new product with a projected Coordinate Reference System (CRS). - If you want that the created product is also orthorectified use the - Orthorectification command. - If it is your intention to create one product from multiple input products use the - Mosaic Processor. + This is a sub window of options launched from the Custom CRS Projection Parameters button +

+ +
+ +
+
+ Figure 3. +
+ +

+ +

+ Semi-Major
+ The semi-major axis of the planet's shape treated as an ellipsoid, which in the case of the Earth, is the equatorial + radius. + This value is automatically filled based on the datum (reference ellipsoid) which you selected. +

+ + +

+ Semi-Minor
+ The semi-minor axis of the planet's shape treated as an ellipsoid, which in the case of the Earth, is the polar + radius. + This value is automatically filled based on the datum (reference ellipsoid) which you selected. +

+ + +

+ False Easting
+ This is the distance away from the origin (x component) to place the reference pixel. This essentially has the + effect of + shifting the geographic boundaries of your output file sideways. +

+ + +

+ False Northing
+ This is the distance away from the origin (y component) to place the reference pixel. This essentially has the + effect of + shifting the geographic boundaries of your output file up and down. +

+ + +

+ Map Projection dependent fields
+ Each map projection may have additional fields dependent on the particular projection. Some of these parameters are: +

+ Latitude of center
+ Longitude of center
+ Central meridian
+ Latitude of origin
+ Scale factor
+ Azimuth
+ Standard parallel 1
+ ...

+

+

+ +
+ + + +

GUI: Predefined CRS

- After the new product has been created, you can change to the - Product Explorer in order to open - an Image View for a band of the new product. + This is a sub window of options launched from the Map Projection & Settings window +

+ +
+
+ +
+ Figure 4. +
+ + +

+ +

+ Select a CRS in the left window of this GUI + and an XML text representation of the selected projection will be displayed and loaded in the right side of this GUI + . If you look at the XML, you can see + all the individual parameters which go into the particular projection. You could replicate or deviate from these + parameters + if you wish by instead using the "Custom CRS" option of the parent window and manually setting these parameters. +

+ +

+ Note 1: as of SeaDAS 7.5, the EPSG dataset being used is version 7.9.0 +

+

+ Note 2: you can + use this XML or the authority code when running Reproject in the command line mode. +

+ +

+ +
+ + +

GUI: Output Parameters

+

+ This is a sub window of options launched from the Resolution Output Parameters button. +

+ +
+ +
+
+ Figure 5. +
+ +

+ +

+ Reference Pixel
+ This is the pixel of your output file to use for setting the easting and northing. +

+ +

+ Reference pixel is at scene upper left
+ In this case the upper left pixel of the output file will be used as the reference. +

+ +

+ Reference pixel is at scene center
+ In this case the center pixel of the output file will be used as the reference. +

+ +

+ Other reference pixel position
+ In this case you custom specify which pixel of the output file will be used as the reference. +

+ -

I/O Parameters

- +

+ Easting
+ This is the distance away from the origin (x component) to place the reference pixel. This essentially has the + effect of + shifting the geographic boundaries of your output file sideways. +

+ + +

+ Northing
+ This is the distance away from the origin (y component) to place the reference pixel. This essentially has the + effect of + shifting the geographic boundaries of your output file up and down. +

+ + +

+ Orientation
+ This is the angular rotation of the output image. It is the angle between geographic north and map grid north (in degrees), + in other words, the convergence angle of the projection's vertical axis from true north. +

+ +

+ Pixel sizeX
+ This is the resolution in the x direction of the output image. The units are dependent on which CRS you have + defined. +

+ +

+ Pixel sizeY
+ This is the resolution in the y direction of the output image. The units are dependent on which CRS you have + defined. +

+ +

+ Fit product size
+ This is used to define the width and height in pixels of the output file such that all data from the input file + will be "best fit" and fully included in the output file. + Of note and caution is that SeaDAS (as of version 7.5) uses the width and height setting and ignores this checkbox + when Reproject runs. + Really the wording on this should be "Edit sizing". We will have to look into this. Regardless, clicking "Reset" + will set + these values for the width and height to "best fit". +

+ +

+ Width
+ This is the desired width in pixels of the output file. +

+ +

+ Height
+ This is the desired height in pixels of the output file. +

+ + + + +

+ +
+ + + + + + +

Metadata

+ +

The following meta data is added to the output file by the Reproject tool. All the rest of the original meta data from the + input file is retained and included in the output file
+ +

- - + + -
-
Source Product
- -

- Name: - Here the user specifies the name of the source product. The combo box presents - a list of all products opened in the Sentinel Toolbox. The user may select one of these - or, by clicking on the button next to the combo box, choose a product - from the file system. - -

Target Product
- -

- Name: - Used to specify the name of the target product. -

- -

- Save as: - Used to specify whether the target product should be saved to the file system. The - combo box presents a list of file formats. - The text field allows to specify a target directory. -

- -

- Open in SNAP: - Used to specify whether the target product should be opened in the Sentinel Toolbox. - When the target product is not saved, it is opened in the Sentinel Toolbox automatically. -

NameDescription
- -

Projection Parameters

- - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-
Coordinate Reference System (CRS)
- -

- Custom CRS: - The transformation used by the projection can be selected. Also the geodetic datum and - projection parameters can be set, if possible for the selected transformation. -

- -

- Predefined CRS: - By clicking on the Select... button a new Select Coordinate Reference System dialog is shown - where a predefined CRS can be selected. -

- -

- Use CRS of: - A product can be selected to use its projected Coordinate Reference System. This will have the effect - that source product will cover the same geographic region on the same CRS. Which means that both - products are collocated. -

- -
Output Settings
- -

- Preserve resolution: - If unchecked the Output Parameters... is enabled and the upcoming - Output Parameters dialog lets you edit the output parameters like - easting and northing of the reference pixel, the pixel size and the scene height and width. -

- -

- Reproject tie-point grids: - Specifies whether or not the tie-point grids shall be included. If they are reprojected they will appear - as bands in the target product and not any more as tie-point grids. -

- -

- Add delta lat/lon bands: - Specifies whether or not delta latitude and longitude bands will be added to the target product. - These are virtual bands, which can be used to assess the accuracy of the new geo-coding given - by the Coordinate Reference System (CRS) with respect to the old geo-coding. -

- - -

- No-data value: - The default no-data value is used for output pixels in the projected band which have either no - corresponding pixel in the source product or the source pixel is invalid. -

- -

- Resampling Method: - You can select one resampling method for the projection.
- For a brief description have a look at Resampling - Methods. -

- -
Output Information
- -

- Displays some information about the output, like scene width and height, the geographic coordinate of - the scene center and short description of the selected CRS.
- When clicking the Show WKT... button the corresponding Well-Known Text of the currently defined - CRS is shown. -

-
- Reproject_gpt_parametersThe full GPT operator parameter xml string used in the creation the output file
crsThe coordinate reference system (WKT) used in the creation of the output file
map_projectionThe map projection name used in the creation of the output file
history"Reproject" is prepended to original history value
spatial_resolutionIf exists in original file, "Derived from" is prepended to original value
processing_levelIf exists in original file, "Derived from" is prepended to original value
product_nameIf exists in original file, "Derived from" is prepended to original value
titleIf exists in original file, "Derived from" is prepended to original value
-
+ - + \ No newline at end of file diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1a.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1a.png new file mode 100644 index 0000000000..e359254fed Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1a.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1b.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1b.png new file mode 100644 index 0000000000..58095f8a16 Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_1b.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_01.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_01.png new file mode 100644 index 0000000000..f3c6e70c41 Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_01.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_02.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_02.png new file mode 100644 index 0000000000..907dd421bf Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_02.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_03.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_03.png new file mode 100644 index 0000000000..ec830bc84d Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_03.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_04.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_04.png new file mode 100644 index 0000000000..f999a716b4 Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_04.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_05.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_05.png new file mode 100644 index 0000000000..f5e4efb49f Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_05.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_06.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_06.png new file mode 100644 index 0000000000..1c3ce9118c Binary files /dev/null and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/Reproject_GUI_06.png differ diff --git a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/ReprojectionProjectionParameters.png b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/ReprojectionProjectionParameters.png index 10ea28ab6a..45b53b9eeb 100644 Binary files a/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/ReprojectionProjectionParameters.png and b/snap-help/src/main/resources/org/esa/snap/snap/help/docs/desktop/images/ReprojectionProjectionParameters.png differ diff --git a/snap-rcp/src/main/java/org/esa/snap/rcp/preferences/general/ReprojectionController.java b/snap-rcp/src/main/java/org/esa/snap/rcp/preferences/general/ReprojectionController.java new file mode 100644 index 0000000000..126ee6eae4 --- /dev/null +++ b/snap-rcp/src/main/java/org/esa/snap/rcp/preferences/general/ReprojectionController.java @@ -0,0 +1,470 @@ + + +/* + * Copyright (C) 2011 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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.snap.rcp.preferences.general; + + import com.bc.ceres.binding.Property; + import com.bc.ceres.binding.PropertyDescriptor; + import com.bc.ceres.binding.PropertySet; + import com.bc.ceres.binding.ValidationException; + import com.bc.ceres.swing.TableLayout; + import com.bc.ceres.swing.binding.BindingContext; + import com.bc.ceres.swing.binding.Enablement; + import com.bc.ceres.swing.binding.PropertyEditorRegistry; + import com.bc.ceres.swing.binding.PropertyPane; + import org.esa.snap.rcp.preferences.DefaultConfigController; + import org.esa.snap.rcp.preferences.Preference; + import org.netbeans.spi.options.OptionsPanelController; + import org.openide.util.HelpCtx; + + import javax.swing.*; + import java.awt.*; + +/** + * Panel handling general layer preferences. Sub-panel of the "Layer"-panel. + * + * @author Daniel Knowles (NASA) + */ +@org.openide.util.NbBundle.Messages({ + "Options_DisplayName_Reprojection=" + "Reprojection", + "Options_Keywords_Reprojection=layer, general" +}) +@OptionsPanelController.SubRegistration(location = "GeneralPreferences", + displayName = "#Options_DisplayName_Reprojection", + keywords = "#Options_Keywords_Reprojection", + keywordsCategory = "reprojection, layer", + id = "reprojectionController", + position = 3) + + +public final class ReprojectionController extends DefaultConfigController { + + + // Preferences property prefix + private static final String PROPERTY_ROOT_KEY = "reprojection"; + + // Output Settings + private static final String PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX = PROPERTY_ROOT_KEY + ".output.settings"; + + public static final String PROPERTY_OUTPUT_SETTINGS_SECTION_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".section"; + public static final String PROPERTY_OUTPUT_SETTINGS_SECTION_LABEL = "Output Settings"; + public static final String PROPERTY_OUTPUT_SETTINGS_SECTION_TOOLTIP = "Output settings"; + + public static final String PROPERTY_PRESERVE_RESOLUTION_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".preserve.resolution"; + public static final String PROPERTY_PRESERVE_RESOLUTION_LABEL = "Preserve resolution"; + public static final String PROPERTY_PRESERVE_RESOLUTION_TOOLTIP = "Preserve resolution"; + public static final String PROPERTY_RESOLUTION_PARAMETERS_BUTTON_NAME = "Output Parameters..."; + public static boolean PROPERTY_PRESERVE_RESOLUTION_DEFAULT = true; + + public static final String PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".include.tie.point.grids"; + public static final String PROPERTY_INCLUDE_TIE_POINT_GRIDS_LABEL = "Reproject tie-point grids"; + public static final String PROPERTY_INCLUDE_TIE_POINT_GRIDS_TOOLTIP = "Reproject tie-point grids"; + public static boolean PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT = true; + + public static final String PROPERTY_ADD_DELTA_BANDS_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".add.delta.bands"; + public static final String PROPERTY_ADD_DELTA_BANDS_LABEL = "Add delta lat/lon bands"; + public static final String PROPERTY_ADD_DELTA_BANDS_TOOLTIP = "Add delta lat/lon bands"; + public static boolean PROPERTY_ADD_DELTA_BANDS_DEFAULT = false; + + public static final String PROPERTY_NO_DATA_VALUE_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".no.data.value"; + public static final String PROPERTY_NO_DATA_VALUE_LABEL = "No-data value"; + public static final String PROPERTY_NO_DATA_VALUE_TOOLTIP = "No-data value to set in target file"; + public static double PROPERTY_NO_DATA_VALUE_DEFAULT = Double.NaN; + + public static final String PROPERTY_RESAMPLING_METHOD_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".resampling.method"; + public static final String PROPERTY_RESAMPLING_METHOD_LABEL = "Resampling method"; + public static final String PROPERTY_RESAMPLING_METHOD_TOOLTIP = "Resampling method"; + public static final String PROPERTY_RESAMPLING_METHOD_OPTION_NEAREST = "Nearest"; + public static final String PROPERTY_RESAMPLING_METHOD_OPTION_BILINEAR = "Bilinear"; + public static final String PROPERTY_RESAMPLING_METHOD_OPTION_BICUBIC = "Bicubic"; + public static final String[] PROPERTY_RESAMPLING_METHOD_OPTIONS = { + PROPERTY_RESAMPLING_METHOD_OPTION_NEAREST, + PROPERTY_RESAMPLING_METHOD_OPTION_BILINEAR, + PROPERTY_RESAMPLING_METHOD_OPTION_BICUBIC}; + public static String PROPERTY_RESAMPLING_METHOD_DEFAULT = PROPERTY_RESAMPLING_METHOD_OPTION_NEAREST; + + public static final String PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_KEY = PROPERTY_OUTPUT_SETTINGS_KEY_SUFFIX + ".retain.valid.pixel.expression"; + public static final String PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_LABEL = "Retain valid pixel expression"; + public static final String PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_TOOLTIP = "Retain valid pixel expressions"; + public static boolean PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_DEFAULT = false; + + + // Masking + + private static final String PROPERTY_MASKING_KEY_SUFFIX = PROPERTY_ROOT_KEY + ".masking"; + + public static final String PROPERTY_MASKING_SECTION_KEY = PROPERTY_MASKING_KEY_SUFFIX + ".section"; + public static final String PROPERTY_MASKING_SECTION_LABEL = "Masking"; + public static final String PROPERTY_MASKING_SECTION_TOOLTIP = "Masking options"; + + public static final String PROPERTY_MASK_EXPRESSION_KEY = PROPERTY_MASKING_KEY_SUFFIX + ".mask.expression"; + public static final String PROPERTY_MASK_EXPRESSION_LABEL = "Expression"; + public static final String PROPERTY_MASK_EXPRESSION_TOOLTIP = "Mask expression to apply to the source file(s)"; + public static String PROPERTY_MASK_EXPRESSION_DEFAULT = ""; + public static final String PROPERTY_MASK_EXPRESSION_BUTTON_NAME = "Edit Expression"; + + + public static final String PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_KEY = PROPERTY_MASKING_KEY_SUFFIX + ".apply.valid.pixel.expression"; + public static final String PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_LABEL = "Apply source valid pixel expression"; + public static final String PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_TOOLTIP = "Applies source file valid pixel expression to masking criteria"; + public static boolean PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT = true; + + + + // Restore to defaults + + private static final String PROPERTY_RESTORE_KEY_SUFFIX = PROPERTY_ROOT_KEY + ".restore.defaults"; + + public static final String PROPERTY_RESTORE_SECTION_KEY = PROPERTY_RESTORE_KEY_SUFFIX + ".section"; + public static final String PROPERTY_RESTORE_SECTION_LABEL = "Restore"; + public static final String PROPERTY_RESTORE_SECTION_TOOLTIP = "Restores preferences to the package defaults"; + + public static final String PROPERTY_RESTORE_DEFAULTS_NAME = PROPERTY_RESTORE_KEY_SUFFIX + ".apply"; + public static final String PROPERTY_RESTORE_DEFAULTS_LABEL = "Default (" + "Reprojection" + " Preferences)"; + public static final String PROPERTY_RESTORE_DEFAULTS_TOOLTIP = "Restore all " + " Reprojection preferences to the original default"; + public static final boolean PROPERTY_RESTORE_DEFAULTS_DEFAULT = false; + + + + + + Property restoreDefaults; + + boolean propertyValueChangeEventsEnabled = true; + + + Enablement enablementGeneralPalette; + Enablement enablementGeneralRange; + Enablement enablementGeneralLog; + + + + + protected PropertySet createPropertySet() { + return createPropertySet(new GeneralLayerBean()); + } + + + @Override + public HelpCtx getHelpCtx() { + return new HelpCtx("colorManipulationPreferences"); + } + + @Override + protected JPanel createPanel(BindingContext context) { + + initPropertyDefaults(context, PROPERTY_OUTPUT_SETTINGS_SECTION_KEY, true); + initPropertyDefaults(context, PROPERTY_PRESERVE_RESOLUTION_KEY, PROPERTY_PRESERVE_RESOLUTION_DEFAULT); + initPropertyDefaults(context, PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY, PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT); + initPropertyDefaults(context, PROPERTY_ADD_DELTA_BANDS_KEY, PROPERTY_ADD_DELTA_BANDS_DEFAULT); + initPropertyDefaults(context, PROPERTY_NO_DATA_VALUE_KEY, PROPERTY_NO_DATA_VALUE_DEFAULT); + initPropertyDefaults(context, PROPERTY_RESAMPLING_METHOD_KEY, PROPERTY_RESAMPLING_METHOD_DEFAULT); + initPropertyDefaults(context, PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_DEFAULT); + + initPropertyDefaults(context, PROPERTY_MASKING_SECTION_KEY, true); + initPropertyDefaults(context, PROPERTY_MASK_EXPRESSION_KEY, PROPERTY_MASK_EXPRESSION_DEFAULT); + initPropertyDefaults(context, PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_KEY, PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT); + + restoreDefaults = initPropertyDefaults(context, PROPERTY_RESTORE_DEFAULTS_NAME, PROPERTY_RESTORE_DEFAULTS_DEFAULT); + + + + // + // Create UI + // + + TableLayout tableLayout = new TableLayout(2); + tableLayout.setTableAnchor(TableLayout.Anchor.NORTHWEST); + tableLayout.setTablePadding(new Insets(4, 10, 0, 0)); + tableLayout.setTableFill(TableLayout.Fill.BOTH); + tableLayout.setColumnWeightX(1, 1.0); + + JPanel pageUI = new JPanel(tableLayout); + + PropertyEditorRegistry registry = PropertyEditorRegistry.getInstance(); + + PropertySet propertyContainer = context.getPropertySet(); + Property[] properties = propertyContainer.getProperties(); + + int currRow = 0; + for (Property property : properties) { + PropertyDescriptor descriptor = property.getDescriptor(); + PropertyPane.addComponent(currRow, tableLayout, pageUI, context, registry, descriptor); + currRow++; + } + + pageUI.add(tableLayout.createVerticalSpacer()); + + JPanel parent = new JPanel(new BorderLayout()); + parent.add(pageUI, BorderLayout.CENTER); + parent.add(Box.createHorizontalStrut(50), BorderLayout.EAST); + return parent; + } + + + + @Override + protected void configure(BindingContext context) { + + configureGeneralCustomEnablement(context); + + // Handle resetDefaults events - set all other components to defaults + restoreDefaults.addPropertyChangeListener(evt -> { + handleRestoreDefaults(context); + }); + + + // Add listeners to all components in order to uncheck restoreDefaults checkbox accordingly + + PropertySet propertyContainer = context.getPropertySet(); + Property[] properties = propertyContainer.getProperties(); + + for (Property property : properties) { + if (property != restoreDefaults) { + property.addPropertyChangeListener(evt -> { + handlePreferencesPropertyValueChange(context); + }); + } + } + } + + + + + + + /** + * Test all properties to determine whether the current value is the default value + * + * @param context + * @return + * @author Daniel Knowles + */ + private boolean isDefaults(BindingContext context) { + + PropertySet propertyContainer = context.getPropertySet(); + Property[] properties = propertyContainer.getProperties(); + + for (Property property : properties) { + if (property != restoreDefaults && property.getDescriptor().getDefaultValue() != null) + if (!property.getValue().equals(property.getDescriptor().getDefaultValue())) { + return false; + } + } + + return true; + } + + + /** + * Handles the restore defaults action + * + * @param context + * @author Daniel Knowles + */ + private void handleRestoreDefaults(BindingContext context) { + if (propertyValueChangeEventsEnabled) { + propertyValueChangeEventsEnabled = false; + try { + if (restoreDefaults.getValue()) { + + PropertySet propertyContainer = context.getPropertySet(); + Property[] properties = propertyContainer.getProperties(); + + for (Property property : properties) { + if (property != restoreDefaults && property.getDescriptor().getDefaultValue() != null) + property.setValue(property.getDescriptor().getDefaultValue()); + } + } + } catch (ValidationException e) { + e.printStackTrace(); + } + propertyValueChangeEventsEnabled = true; + + context.setComponentsEnabled(PROPERTY_RESTORE_DEFAULTS_NAME, false); + } + } + + + /** + * Set restoreDefault component because a property has changed + * @param context + * @author Daniel Knowles + */ + private void handlePreferencesPropertyValueChange(BindingContext context) { + if (propertyValueChangeEventsEnabled) { + propertyValueChangeEventsEnabled = false; + try { + restoreDefaults.setValue(isDefaults(context)); + context.setComponentsEnabled(PROPERTY_RESTORE_DEFAULTS_NAME, !isDefaults(context)); + } catch (ValidationException e) { + e.printStackTrace(); + } + propertyValueChangeEventsEnabled = true; + } + } + + + /** + * Initialize the property descriptor default value + * + * @param context + * @param propertyName + * @param propertyDefault + * @return + * @author Daniel Knowles + */ + private Property initPropertyDefaults(BindingContext context, String propertyName, Object propertyDefault) { + + Property property = context.getPropertySet().getProperty(propertyName); + + property.getDescriptor().setDefaultValue(propertyDefault); + + return property; + } + + + + /** + * Configure enablement of the components tied to PROPERTY_GENERAL_CUSTOM_KEY + * + * @param context + * @author Daniel Knowles + */ + private void configureGeneralCustomEnablement(BindingContext context) { +// +// +// enablementGeneralPalette = context.bindEnabledState(ColorManipulationDefaults.PROPERTY_GENERAL_PALETTE_KEY, true, +// ColorManipulationDefaults.PROPERTY_GENERAL_CUSTOM_KEY, true); +// +// enablementGeneralRange = context.bindEnabledState(ColorManipulationDefaults.PROPERTY_GENERAL_RANGE_KEY, true, +// ColorManipulationDefaults.PROPERTY_GENERAL_CUSTOM_KEY, true); +// +// enablementGeneralLog = context.bindEnabledState(ColorManipulationDefaults.PROPERTY_GENERAL_LOG_KEY, true, +// ColorManipulationDefaults.PROPERTY_GENERAL_CUSTOM_KEY, true); +// +// +// +// // handle it the first time so bound properties get properly enabled +//// handleGeneralCustom(); +// enablementGeneralPalette.apply(); +// enablementGeneralRange.apply(); +// enablementGeneralLog.apply(); + } +// +// /** +// * Handles enablement of the components +// * +// * @author Daniel Knowles +// */ +// private void handleGeneralCustom() { +// enablementGeneralPalette.apply(); +// enablementGeneralRange.apply(); +// enablementGeneralLog.apply(); +// } +// + + + + + + + @SuppressWarnings("UnusedDeclaration") + static class GeneralLayerBean { + + + // Output Settings + + @Preference(label = PROPERTY_OUTPUT_SETTINGS_SECTION_LABEL, + key = PROPERTY_OUTPUT_SETTINGS_SECTION_KEY, + description = PROPERTY_OUTPUT_SETTINGS_SECTION_TOOLTIP) + boolean outputSettingsSection = true; + + @Preference(label = PROPERTY_PRESERVE_RESOLUTION_LABEL, + key = PROPERTY_PRESERVE_RESOLUTION_KEY, + description = PROPERTY_PRESERVE_RESOLUTION_TOOLTIP) + boolean preserveResolution = PROPERTY_PRESERVE_RESOLUTION_DEFAULT; + + @Preference(label = PROPERTY_INCLUDE_TIE_POINT_GRIDS_LABEL, + key = PROPERTY_INCLUDE_TIE_POINT_GRIDS_KEY, + description = PROPERTY_INCLUDE_TIE_POINT_GRIDS_TOOLTIP) + boolean includeTiePointGrids = PROPERTY_INCLUDE_TIE_POINT_GRIDS_DEFAULT; + + @Preference(label = PROPERTY_ADD_DELTA_BANDS_LABEL, + key = PROPERTY_ADD_DELTA_BANDS_KEY, + description = PROPERTY_ADD_DELTA_BANDS_TOOLTIP) + boolean addDeltaBands = PROPERTY_ADD_DELTA_BANDS_DEFAULT; + + @Preference(label = PROPERTY_NO_DATA_VALUE_LABEL, + key = PROPERTY_NO_DATA_VALUE_KEY, + description = PROPERTY_NO_DATA_VALUE_TOOLTIP) + double noDataValue = PROPERTY_NO_DATA_VALUE_DEFAULT; + + @Preference(label = PROPERTY_RESAMPLING_METHOD_LABEL, + key = PROPERTY_RESAMPLING_METHOD_KEY, + description = PROPERTY_RESAMPLING_METHOD_TOOLTIP, + valueSet = {PROPERTY_RESAMPLING_METHOD_OPTION_NEAREST, + PROPERTY_RESAMPLING_METHOD_OPTION_BILINEAR, + PROPERTY_RESAMPLING_METHOD_OPTION_BICUBIC}) + String resamplingMethod = PROPERTY_RESAMPLING_METHOD_DEFAULT; + + @Preference(label = PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_LABEL, + key = PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_KEY, + description = PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_TOOLTIP) + boolean retainValidPixelExpression = PROPERTY_RETAIN_VALID_PIXEL_EXPRESSION_DEFAULT; + + + + + // Masking + + @Preference(label = PROPERTY_MASKING_SECTION_LABEL, + key = PROPERTY_MASKING_SECTION_KEY, + description = PROPERTY_MASKING_SECTION_TOOLTIP) + boolean defaultPaletteSection = true; + + @Preference(label = PROPERTY_MASK_EXPRESSION_LABEL, + key = PROPERTY_MASK_EXPRESSION_KEY, + description = PROPERTY_MASK_EXPRESSION_TOOLTIP) + String maskExpression = PROPERTY_MASK_EXPRESSION_DEFAULT; + + @Preference(label = PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_LABEL, + key = PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_KEY, + description = PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_TOOLTIP) + boolean grayScaleCpd = PROPERTY_APPLY_VALID_PIXEL_EXPRESSION_DEFAULT; + + + + + + + // Restore Defaults + + @Preference(label = PROPERTY_RESTORE_SECTION_LABEL, + key = PROPERTY_RESTORE_SECTION_KEY, + description = PROPERTY_RESTORE_SECTION_TOOLTIP) + boolean restoreDefaultsSection = true; + + @Preference(label = PROPERTY_RESTORE_DEFAULTS_LABEL, + key = PROPERTY_RESTORE_DEFAULTS_NAME, + description = PROPERTY_RESTORE_DEFAULTS_TOOLTIP) + boolean restoreDefaults = PROPERTY_RESTORE_DEFAULTS_DEFAULT; + } + +} + diff --git a/snap-ui/src/main/java/org/esa/snap/ui/crs/OutputGeometryFormModel.java b/snap-ui/src/main/java/org/esa/snap/ui/crs/OutputGeometryFormModel.java index f58107f213..65a503dc7b 100644 --- a/snap-ui/src/main/java/org/esa/snap/ui/crs/OutputGeometryFormModel.java +++ b/snap-ui/src/main/java/org/esa/snap/ui/crs/OutputGeometryFormModel.java @@ -146,12 +146,14 @@ private void setAxisUnits(PropertySet pc) { } private void updateProductSize() { - if (targetCrs != null && sourceProduct != null) { - Double pixelSizeX = propertyContainer.getValue("pixelSizeX"); - Double pixelSizeY = propertyContainer.getValue("pixelSizeY"); - Rectangle productSize = ImageGeometry.calculateProductSize(sourceProduct, targetCrs, pixelSizeX, pixelSizeY); - propertyContainer.setValue("width", productSize.width); - propertyContainer.setValue("height", productSize.height); + if (isFitProductSize()) { + if (targetCrs != null && sourceProduct != null) { + Double pixelSizeX = propertyContainer.getValue("pixelSizeX"); + Double pixelSizeY = propertyContainer.getValue("pixelSizeY"); + Rectangle productSize = ImageGeometry.calculateProductSize(sourceProduct, targetCrs, pixelSizeX, pixelSizeY); + propertyContainer.setValue("width", productSize.width); + propertyContainer.setValue("height", productSize.height); + } } }