From 12839d825462fe879a3180a621ec6058604e12ac Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Wed, 11 May 2022 14:21:20 -0400 Subject: [PATCH 01/12] Reproject Tool: added new features of masking and use of the valid-pixel-expression, added metadata to output product --- .../org/esa/snap/core/util/ProductUtils.java | 309 ++++++++++++++++++ .../org/esa/snap/core/util/StringUtils.java | 160 ++++++++- .../reproject/OperatorParameterSupport.java | 184 +++++++++++ .../common/reproject/ParameterUpdater.java | 47 +++ .../gpf/common/reproject/ReprojectionOp.java | 109 +++++- 5 files changed, 804 insertions(+), 5 deletions(-) create mode 100644 snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/OperatorParameterSupport.java create mode 100644 snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ParameterUpdater.java diff --git a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java index bcb058a01eb..1010bbc08d8 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java @@ -57,6 +57,20 @@ */ public class ProductUtils { + private static String GLOBAL_ATTRIBUTES_KEY = "Global_Attributes"; + public static String METADATA_PROJECTION_KEY = "map_projection"; + public static String[] METADATA_POSSIBLE_PROJECTION_KEYS = {METADATA_PROJECTION_KEY, "projection", "crs"}; + public static String[] METADATA_POSSIBLE_SENSOR_KEYS = {"sensor_name", "instrument", "sensor"}; + public static String[] METADATA_POSSIBLE_PLATFORM_KEYS = {"platform"}; + public static String[] METADATA_POSSIBLE_PROCESSING_VERSION_KEYS = {"processing_version"}; + public static String[] METADATA_POSSIBLE_DAY_NIGHT_KEYS = {"day_night_flag", "day_night"}; + public static String[] METADATA_POSSIBLE_ORBIT_KEYS = {"orbit_number", "orbit"}; + public static String[] METADATA_POSSIBLE_START_ORBIT_KEYS = {"start_orbit_number", "end_orbit"}; + public static String[] METADATA_POSSIBLE_END_ORBIT_KEYS = {"end_orbit_number", "end_orbit"}; + + public static String METADATA_RESOLUTION_KEY = "spatial_resolution"; + public static String[] METADATA_POSSIBLE_RESOLUTION_KEYS = {METADATA_RESOLUTION_KEY, "resolution"}; + private static final int[] RGB_BAND_OFFSETS = new int[]{ 2, 1, 0 }; @@ -1076,6 +1090,301 @@ public static void copyTiePointGrids(Product sourceProduct, Product targetProduc } } + public static void markAsDerivedFromMetaDataField(Product product, String attribute) { + // Created by Daniel Knowles + + String tag = "Derived from ("; + + if (attribute != null && attribute.length() > 0 && product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + String value = ""; + + MetadataAttribute metadataAttribute = metadataElement.getAttribute(attribute); + + if (metadataAttribute != null) { + value = metadataAttribute.getData().toString(); + + if (value != null && value.length() > 0 && !value.startsWith(tag)) { + value = tag + value + ")"; + setMetaDataField(product, attribute, value); + } + } + } + + } + + + public static void markProductMetaDataFieldAsDerivedFrom(Product product) { + // Created by Daniel Knowles + + markAsDerivedFromMetaDataField(product, "product_name"); + markAsDerivedFromMetaDataField(product, "title"); + markAsDerivedFromMetaDataField(product, "processing_level"); + + String tag = "Derived from ("; + + if (product != null) { + String productType = product.getProductType(); + + if (productType != null && productType.length() > 0 && !productType.startsWith(tag)) { + productType = tag + productType + ")"; + product.setProductType(productType); + } + } + + } + + + public static void prependHistoryMetaDataField(Product product, String latestHistoryEvent) { + // Created by Daniel Knowles + + String HISTORY_KEY = "history"; + String history = latestHistoryEvent; + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + if (metadataElement.getAttribute(HISTORY_KEY) != null) { + String previousHistory = metadataElement.getAttribute(HISTORY_KEY).getData().toString(); + + if (previousHistory.length() > 0) { + history = latestHistoryEvent + " :: " + previousHistory; + } + } + + setMetaDataField(product, HISTORY_KEY, history); + } + } + + + public static void setResolutionMetaDataField(Product product, boolean markAsDerivedFrom) { + // Created by Daniel Knowles + + setMetaDataFieldFromPossible(product, METADATA_RESOLUTION_KEY, METADATA_POSSIBLE_RESOLUTION_KEYS); + + if (markAsDerivedFrom) { + markAsDerivedFromMetaDataField(product, METADATA_RESOLUTION_KEY); + } + } + + + public static void setMetaDataFieldFromPossible(Product product, String attribute, String[] possibleAttributes) { + // Created by Daniel Knowles + // if attribute does not exist then set to first value found from the possibleAttributes + + if (product != null && product.getMetadataRoot() != null) { + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + if (metadataElement != null) { + MetadataAttribute metadataAttribute = metadataElement.getAttribute(attribute); + + if (metadataAttribute == null) { + for (String key : possibleAttributes) { + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + if (metadataElement.getAttribute(keyVariation) != null) { + String value = metadataElement.getAttribute(keyVariation).getData().toString(); + setMetaDataField(product, attribute, value); + break; + } + } + } + + for (String key : possibleAttributes) { + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + if (keyVariation != null && !keyVariation.toLowerCase().equals(attribute.toLowerCase())) { + deleteMetaDataField(product, keyVariation); + } + } + } + } + } + } + } + + + public static void setMapProjectionMetaDataFields(Product product) { + // Created by Daniel Knowles + + String MAP_PROJECTION_KEY = "map_projection"; + String CRS_KEY = "crs"; + String UNDEFINED_VALUE = "undefined"; + String[] keysToDelete = {"projection", "mapprojection", "coordinatesystem", "coordinatereferencesystem", "coordinate_system", "geocoding", "geo_coding"}; + + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + deleteMetaDataFields(product, keysToDelete); + + String mapProjectionString = UNDEFINED_VALUE; + String crsString = UNDEFINED_VALUE; + + if (product.getSceneGeoCoding() != null && product.getSceneGeoCoding().getMapCRS() != null) { + if (product.getSceneGeoCoding().getMapCRS().getName() != null) { + mapProjectionString = product.getSceneGeoCoding().getMapCRS().getName().toString(); + } + if (product.getSceneGeoCoding().getMapCRS().toString() != null) { + crsString = product.getSceneGeoCoding().getMapCRS().toString().replaceAll("\n", "").replaceAll(" ", ""); + } + } + + setMetaDataField(product, MAP_PROJECTION_KEY, mapProjectionString); + setMetaDataField(product, CRS_KEY, crsString); + } + } + + + public static void deleteMetaDataFields(Product product, String[] fields) { + // Created by Daniel Knowles + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + for (String key : fields) { + MetadataAttribute metadataAttribute = metadataElement.getAttribute(key); + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(false); + metadataElement.removeAttribute(metadataAttribute); + } + } + } + + + public static void deleteMetaDataField(Product product, String field) { + // Created by Daniel Knowles + + String[] fields = {field}; + deleteMetaDataFields(product, fields); + } + + + public static void setMetaDataField(Product product, String field, String value) { + // Created by Daniel Knowles + + String UNDEFINED_VALUE = "undefined"; + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + MetadataAttribute metadataAttribute = metadataElement.getAttribute(field); + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(false); + metadataAttribute.setModified(true); + } + + // this wont do anything if attribute is not a String type + try { + if (value != null) { + metadataElement.setAttributeString(field, value); + } else { + metadataElement.setAttributeString(field, UNDEFINED_VALUE); + } + } catch (Exception e) { + + } + + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(true); + } + } + } + + + + + public static String getMetaData(Product product, String[] keys) { + // Created by Daniel Knowles + String metaData = ""; + + for (String key : keys) { + metaData = getMetaData(product, key, false); + + if (metaData.length() > 0) { + return metaData; + } + } + + return metaData; + } + + public static String getMetaData(Product product, String key) { + // Created by Daniel Knowles + String metaData = ""; + + if (key != null && key.length() > 0) { + try { + metaData = product.getMetadataRoot().getElement("Global_Attributes").getAttribute(key).getData().getElemString(); + } catch (Exception ignore) { + } + } + + return metaData; + } + + + + + public static String getMetaData(Product product, String key, boolean exact) { + // Created by Daniel Knowles + if (key == null) { + return null; + } + + if (exact) { + return getMetaData(product, key); + } else { + String metaData = ""; + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + metaData = getMetaData(product, keyVariation); + if (metaData != null && metaData.length() > 0) { + return metaData; + } + } + + return metaData; + } + } + + + + + + + + + + + public static String getMetaDataOrbit(Product product) { + // Created by Daniel Knowles + // Note this tries to retrieve an orbit or orbit range name + String metaData = getMetaData(product, METADATA_POSSIBLE_ORBIT_KEYS); + + if (metaData != null && metaData.length() > 0) { + return metaData; + } + + try { + String startOrbit = getMetaData(product, METADATA_POSSIBLE_START_ORBIT_KEYS); + String endOrbit = getMetaData(product, METADATA_POSSIBLE_END_ORBIT_KEYS); + if (startOrbit != null && startOrbit.length() > 0 && endOrbit != null && endOrbit.length() > 0) { + metaData = startOrbit + "-" + endOrbit; + } else if (endOrbit == null && startOrbit != null && startOrbit.length() > 0) { + metaData = startOrbit; + } else if (startOrbit == null && endOrbit != null && endOrbit.length() > 0) { + metaData = endOrbit; + } + } catch (Exception ignored) { + } + + + return metaData; + } + + public static void copyVectorData(Product sourceProduct, Product targetProduct) { ProductNodeGroup vectorDataGroup = sourceProduct.getVectorDataGroup(); diff --git a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java index ed24c66e655..20dff82306c 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java @@ -23,10 +23,7 @@ import java.awt.Color; import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.StringTokenizer; +import java.util.*; /** * The StringUtils class provides frequently used utility methods dealing with String values @@ -55,6 +52,22 @@ public class StringUtils { * @throws IllegalArgumentException if one of the arguments was null * @see java.util.StringTokenizer */ + + public enum CaseType { + TITLE, + TITLE_UNDERSCORE, + LOWER_UNDERSCORE, + UPPER_UNDERSCORE, + CAMEL_LOWER_FIRST, + CAMEL_UPPER + } + + + public static String DELIMITOR_SPACE = " "; + public static String DELIMITOR_UNDERSCORE = "_"; + + + public static List split(String text, char[] separators, boolean trimTokens, List tokens) { Guardian.assertNotNull("text", text); @@ -885,4 +898,143 @@ private static Format getFormat() { prettyFormat.setTextMode(Format.TextMode.NORMALIZE); return prettyFormat; } + + + public static String[] getStringCaseVariations(String s) { + // Created by Daniel Knowles + if (s == null || s.length() == 0) { + return null; + } + + if (s.length() == 1) { + String[] stringArray = {s.toLowerCase(), s.toUpperCase()}; + return stringArray; + } + + LinkedHashSet linkedHashSet = new LinkedHashSet(); + linkedHashSet.add(s); + linkedHashSet.add(getStringCaseVariation(s, CaseType.LOWER_UNDERSCORE)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.UPPER_UNDERSCORE)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.CAMEL_LOWER_FIRST)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.CAMEL_UPPER)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.TITLE_UNDERSCORE)); + + String[] stringArray = new String[linkedHashSet.size()]; + linkedHashSet.toArray(stringArray); + return stringArray; + } + + + + public static String getStringCaseVariation(String s, CaseType caseType) { + // Created by Daniel Knowles + if (s == null || s.length() == 0) { + return null; + } + + String tmpString; + switch (caseType) { + case TITLE: + return toTitleCase(s, true); + case TITLE_UNDERSCORE: + return toTitleCase(s, false); + case LOWER_UNDERSCORE: + tmpString = toTitleCase(s, true); + if (tmpString != null) { + return tmpString.toLowerCase(); + } else { + return null; + } + case UPPER_UNDERSCORE: + tmpString = toTitleCase(s, true); + if (tmpString != null) { + return tmpString.toUpperCase(); + } else { + return null; + } + case CAMEL_LOWER_FIRST: + return toCamelCase(s, false); + case CAMEL_UPPER: + return toCamelCase(s, true); + default: + return null; + } + + + } + + + static String toCamelCase(String s, boolean upper) { + // Created by Daniel Knowles + + if (s == null || s.length() == 0) { + return s; + } + + String sourceDelimitor; + + if (s.contains(DELIMITOR_SPACE)) { + sourceDelimitor = DELIMITOR_SPACE; + } else if (s.contains(DELIMITOR_UNDERSCORE)) { + sourceDelimitor = DELIMITOR_UNDERSCORE; + } else { + return s; + } + + String[] parts = s.split(sourceDelimitor); + StringBuilder camelCaseString = new StringBuilder(""); + boolean firstWordSet = false; + for (String part : parts) { + if (part != null && part.length() > 0) { + if (!firstWordSet && !upper) { + camelCaseString.append(part.toLowerCase()); + firstWordSet = true; + } else { + camelCaseString.append(toProperCase(part)); + } + } + } + + return camelCaseString.toString(); + } + + + static String toTitleCase(String s, boolean spaceDelimitor) { + // Created by Daniel Knowles + // Source string is either space or underscore delimited + // Returned string is of format "This Is My Title" or "This_Is_My_Title" + + String delimitor = (spaceDelimitor) ? DELIMITOR_SPACE : DELIMITOR_UNDERSCORE; + if (s == null || s.length() == 0) { + return s; + } + + String sourceDelimitor; + + if (s.contains(DELIMITOR_SPACE)) { + sourceDelimitor = DELIMITOR_SPACE; + } else if (s.contains(DELIMITOR_UNDERSCORE)) { + sourceDelimitor = DELIMITOR_UNDERSCORE; + } else { + return s; + } + + String[] parts = s.split(sourceDelimitor); + for (int i = 0; i < parts.length; i++) { + parts[i] = toProperCase(parts[i]); + } + + return StringUtils.join(parts, delimitor); + } + + + static String toProperCase(String s) { + // Created by Daniel Knowles + + if (s == null || s.length() < 2) { + return s; } + + return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); + } +} \ No newline at end of file diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/OperatorParameterSupport.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/OperatorParameterSupport.java new file mode 100644 index 00000000000..a98046c6363 --- /dev/null +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/OperatorParameterSupport.java @@ -0,0 +1,184 @@ +/* + * 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.core.gpf.common.reproject; + +import com.bc.ceres.binding.*; +import com.bc.ceres.binding.dom.DefaultDomConverter; +import com.bc.ceres.binding.dom.DefaultDomElement; +import com.bc.ceres.binding.dom.DomElement; +import com.bc.ceres.core.Assert; +import org.esa.snap.core.gpf.Operator; +import org.esa.snap.core.gpf.annotations.ParameterDescriptorFactory; +import org.esa.snap.core.gpf.descriptor.OperatorDescriptor; +import org.esa.snap.core.gpf.descriptor.PropertySetDescriptorFactory; + +import java.util.HashMap; +import java.util.Map; + +/** + * WARNING: This class belongs to a preliminary API and may change in future releases. + *

+ * Support for operator parameters input/output. + * + * @author Norman Fomferra + * @author Marco Zühlke + */ +public class OperatorParameterSupport { + + private static final ParameterUpdater DEFAULT = new ParameterUpdater() { + @Override + public void handleParameterSaveRequest(Map parameterMap) { + } + + @Override + public void handleParameterLoadRequest(Map parameterMap) { + } + }; + + private ParameterDescriptorFactory descriptorFactory; + private Map parameterMap; + private PropertySet propertySet; + private ParameterUpdater parameterUpdater; + private PropertySetDescriptor propertySetDescriptor; + private Class operatorType; + + /** + * Creates a parameter support for the operator described by the given {@link OperatorDescriptor}. + * + * @param operatorDescriptor The operator descriptor. + */ + public OperatorParameterSupport(OperatorDescriptor operatorDescriptor) { + this(operatorDescriptor, null, null, null); + } + + /** + * Creates a parameter support for the operator described by the given {@link OperatorDescriptor}. + *

+ * If a property set and a parameter map are given the client as to keep them in sync. + * The {@code parameterUpdater} will be called before each save and after each load request to + * enable custom updating. + * + * @param operatorDescriptor The operator descriptor. + * @param propertySet The property set (can be null). If supplied a parameter map is required as well. + * @param parameterMap the parameter map (can be null) + * @param parameterUpdater The parameter updater (can be null) + * + */ + public OperatorParameterSupport(OperatorDescriptor operatorDescriptor, + PropertySet propertySet, + Map parameterMap, + ParameterUpdater parameterUpdater) { + Assert.notNull(operatorDescriptor, "operatorDescriptor"); + init(null, operatorDescriptor, propertySet, parameterMap, parameterUpdater); + } + + /** + * @deprecated since BEAM 5, use {@link #OperatorParameterSupport(OperatorDescriptor)} instead + */ + @Deprecated + public OperatorParameterSupport(Class opType) { + this(opType, null, null, null); + } + + /** + * @deprecated since BEAM 5, use {@link #OperatorParameterSupport(OperatorDescriptor, PropertySet, Map, ParameterUpdater)} + */ + @Deprecated + public OperatorParameterSupport(Class opType, + PropertySet propertySet, + Map parameterMap, + ParameterUpdater parameterUpdater) { + Assert.notNull(opType, "opType"); + init(opType, null, propertySet, parameterMap, parameterUpdater); + } + + private void init(Class opType, + OperatorDescriptor operatorDescriptor, + PropertySet propertySet, + Map parameterMap, + ParameterUpdater parameterUpdater) { + Assert.argument(parameterMap != null || propertySet == null, "parameterMap != null || propertySet == null"); + + this.descriptorFactory = new ParameterDescriptorFactory(); + + if (parameterMap == null) { + parameterMap = new HashMap<>(); + } + this.parameterMap = parameterMap; + + this.operatorType = opType != null ? opType : operatorDescriptor.getOperatorClass(); + + if (propertySet == null) { + if (operatorDescriptor != null) { + try { + propertySetDescriptor = PropertySetDescriptorFactory.createForOperator(operatorDescriptor, descriptorFactory.getSourceProductMap()); + } catch (ConversionException e) { + throw new IllegalStateException("Not able to init OperatorParameterSupport.", e); + } + propertySet = PropertyContainer.createMapBacked(this.parameterMap, propertySetDescriptor); + propertySet.setDefaultValues(); + } else { + propertySetDescriptor = DefaultPropertySetDescriptor.createFromClass(operatorType, descriptorFactory); + propertySet = PropertyContainer.createMapBacked(this.parameterMap, propertySetDescriptor); + propertySet.setDefaultValues(); + } + } + this.propertySet = propertySet; + + if (parameterUpdater == null) { + parameterUpdater = DEFAULT; + } + this.parameterUpdater = parameterUpdater; + + } + + public PropertySet getPropertySet() { + return propertySet; + } + + /** + * @deprecated since BEAM 5, use {@link #getPropertySet()} + */ + @Deprecated + public PropertySet getPopertySet() { + return propertySet; + } + + public Map getParameterMap() { + return parameterMap; + } + + public void fromDomElement(DomElement parametersElement) throws ValidationException, ConversionException { + parameterMap.clear(); + propertySet.setDefaultValues(); + DefaultDomConverter domConverter = createDomConverter(); + domConverter.convertDomToValue(parametersElement, propertySet); + parameterUpdater.handleParameterLoadRequest(parameterMap); + } + + public DomElement toDomElement() throws ValidationException, ConversionException { + parameterUpdater.handleParameterSaveRequest(parameterMap); + DefaultDomConverter domConverter = createDomConverter(); + DefaultDomElement parametersElement = new DefaultDomElement("parameters"); + domConverter.convertValueToDom(propertySet, parametersElement); + return parametersElement; + } + + private DefaultDomConverter createDomConverter() { + return new DefaultDomConverter(operatorType, descriptorFactory, propertySetDescriptor); + } +} \ No newline at end of file diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ParameterUpdater.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ParameterUpdater.java new file mode 100644 index 00000000000..9d6cab460c1 --- /dev/null +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ParameterUpdater.java @@ -0,0 +1,47 @@ +/* + * 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.core.gpf.common.reproject; + +import com.bc.ceres.binding.ConversionException; +import com.bc.ceres.binding.ValidationException; + +import java.util.Map; + +/** + * WARNING: This class belongs to a preliminary API and may change in future releases. + * + * Enables reaction to parameter save and load request. + * + * @author Marco Zühlke + */ +public interface ParameterUpdater { + + /** + * Called before the parameter map is saved. The implementer should update the given map. + * + * @param parameterMap The parameter map + */ + void handleParameterSaveRequest(Map parameterMap) throws ValidationException, ConversionException; + + /** + * Called after the parameter map has been loaded. Implementers + * should update internal model from the given map. + * + * @param parameterMap The parameter map + */ + void handleParameterLoadRequest(Map parameterMap) throws ValidationException, ConversionException; +} \ No newline at end of file diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java index 0ae20563315..598b5986a29 100644 --- a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java @@ -15,6 +15,7 @@ */ package org.esa.snap.core.gpf.common.reproject; +import com.bc.ceres.binding.dom.DomElement; import com.bc.ceres.glevel.MultiLevelImage; import com.bc.ceres.glevel.MultiLevelModel; import com.bc.ceres.glevel.support.AbstractMultiLevelSource; @@ -48,6 +49,7 @@ import org.esa.snap.core.gpf.annotations.Parameter; import org.esa.snap.core.gpf.annotations.SourceProduct; import org.esa.snap.core.gpf.annotations.TargetProduct; +import org.esa.snap.core.gpf.descriptor.OperatorDescriptor; import org.esa.snap.core.image.ImageManager; import org.esa.snap.core.image.ResolutionLevel; import org.esa.snap.core.util.Debug; @@ -72,6 +74,7 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.HashMap; +import java.util.Map; /** *

@@ -210,6 +213,19 @@ public class ReprojectionOp extends Operator { defaultValue = "false") private boolean addDeltaBands; + @Parameter(description = "Apply the valid pixel expression to determine whether a source pixel gets used", + defaultValue = "true") + private boolean applyValidPixelExpression; + + @Parameter(description = "Copy source valid pixel expression(s) to the corresponding bands of the reprojected file", + defaultValue = "true") + private boolean retainValidPixelExpression; + + + @Parameter(description = "Logical expression of masks and/or bands to apply to determine whether a source pixel gets used", + defaultValue = "") + private String maskExpression; + private ReprojectionSettingsProvider reprojectionSettingsProvider; private ElevationModel elevationModel; @@ -301,6 +317,36 @@ public void initialize() throws OperatorException { ProductUtils.copyOverlayMasks(sourceProduct, targetProduct); targetProduct.setAutoGrouping(sourceProduct.getAutoGrouping()); + // todo Danny added these metadata lines + String operatorName = "Reproject"; + + OperatorDescriptor operatorDescriptor = null; + OperatorParameterSupport parameterSupport = null; + + ProductUtils.setMapProjectionMetaDataFields(targetProduct); + ProductUtils.setResolutionMetaDataField(targetProduct, true); + ProductUtils.prependHistoryMetaDataField(targetProduct, operatorName); + ProductUtils.markProductMetaDataFieldAsDerivedFrom(targetProduct); + + final Map parameterMap = new HashMap<>(); + updateParameterMap(parameterMap); + + operatorDescriptor = getSpi().getOperatorDescriptor(); + parameterSupport = new OperatorParameterSupport(operatorDescriptor, null, parameterMap, null); + + String parameterXml = ""; + try { + DomElement domElement = parameterSupport.toDomElement(); + parameterXml = domElement.toXml(); + } catch (Exception e) { + } + + if (parameterXml != null) { + ProductUtils.setMetaDataField(targetProduct, operatorName + "_gpt_parameters", parameterXml.toString().replaceAll("\n", "").replaceAll(" ", "")); + } + + // todo end Danny additions + if (addDeltaBands) { addDeltaBands(); } @@ -346,6 +392,37 @@ private void reprojectRasterDataNodes(RasterDataNode[] rasterDataNodes) { } private void reprojectSourceRaster(RasterDataNode sourceRaster) { + boolean validPixelExpressionSet = false; + + String validPixelExpressionOriginal = sourceRaster.getValidPixelExpression(); + String validPixelExpression = (applyValidPixelExpression) ? validPixelExpressionOriginal: ""; + + String bandDescriptionOriginal = sourceRaster.getDescription(); + String bandDescription = bandDescriptionOriginal; + + if (maskExpression != null && maskExpression.length() > 0) { + if (validPixelExpression != null && validPixelExpression.length() > 0) { + validPixelExpression = "(" + validPixelExpression + ") && " + maskExpression; + } else { + validPixelExpression = maskExpression; + } + } + + if (validPixelExpression != null && validPixelExpression.length() > 0) { + if (validPixelExpression.equals(validPixelExpressionOriginal)) { + bandDescription = bandDescription + "\n[Reprojected with source validPixelExpression applied:\nexpression=" + validPixelExpressionOriginal +"]"; + } else { + bandDescription = bandDescription + "\n[Reprojected with source masking criteria:\nexpression=" + validPixelExpression +"]"; + sourceRaster.setValidPixelExpression(validPixelExpression); + validPixelExpressionSet = true; + } + + } else { + bandDescription = bandDescription + " [Reprojected with no source masking criteria]"; + sourceRaster.setValidPixelExpression(""); + validPixelExpressionSet = true; + } + final ReprojectionSettings reprojectionSettings = reprojectionSettingsProvider.getReprojectionSettings(sourceRaster); final int targetDataType; MultiLevelImage sourceImage; @@ -376,6 +453,16 @@ private void reprojectSourceRaster(RasterDataNode sourceRaster) { sourceImage = createNoDataReplacedImage(sourceRaster, targetNoDataValue); } + if (retainValidPixelExpression && validPixelExpressionOriginal != null && validPixelExpressionOriginal.length() > 0) { + targetBand.setValidPixelExpression(validPixelExpressionOriginal); + } + + if (validPixelExpressionSet) { + sourceRaster.setValidPixelExpression(validPixelExpressionOriginal); + } + + + final Interpolation resampling = getResampling(targetBand); MultiLevelModel targetModel = reprojectionSettings.getTargetModel(); if (targetModel == null) { @@ -918,5 +1005,25 @@ public Reproject getReprojection() { } } - + void updateParameterMap(Map parameterMap) { + parameterMap.clear(); + parameterMap.put("resamplingName", resamplingName); + parameterMap.put("includeTiePointGrids", includeTiePointGrids); + parameterMap.put("addDeltaBands", addDeltaBands); + parameterMap.put("noDataValue", noDataValue); + parameterMap.put("crs", crs); + parameterMap.put("orthorectify", orthorectify); + parameterMap.put("elevationModelName", elevationModelName); + parameterMap.put("referencePixelX", referencePixelX); + parameterMap.put("referencePixelY", referencePixelY); + parameterMap.put("easting", easting); + parameterMap.put("northing", northing); + parameterMap.put("orientation", orientation); + parameterMap.put("pixelSizeX", pixelSizeX); + parameterMap.put("pixelSizeY", pixelSizeY); + parameterMap.put("width", width); + parameterMap.put("height", height); + parameterMap.put("tileSizeX", tileSizeX); + parameterMap.put("tileSizeY", tileSizeY); } +} \ No newline at end of file From cc5b3a6efd4e80ac46c0cf563edd5b8864d8b65e Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Thu, 18 Aug 2022 11:10:40 -0400 Subject: [PATCH 02/12] Reproject: fixed xml load/save for GraphBuilder tool --- .../gpf/common/reproject/ReprojectionOp.java | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java index 598b5986a29..2ca8ddde4be 100644 --- a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/reproject/ReprojectionOp.java @@ -168,7 +168,7 @@ public class ReprojectionOp extends Operator { description = "The method used for resampling of floating-point raster data.", valueSet = {"Nearest", "Bilinear", "Bicubic"}, defaultValue = "Nearest") - private String resamplingName; + private String resampling; @Parameter(description = "The X-position of the reference pixel.") private Double referencePixelX; @@ -239,7 +239,7 @@ public void initialize() throws OperatorException { } catch (OperatorException e) { //Catch exception in order to clarify the error message throw new OperatorException("The product selected as reference (Collocation product) contains rasters of different sizes and cannot be used as input.\n" + - "Please consider resampling it so that all rasters have the same size."); + "Please consider resampling it so that all rasters have the same size."); } } validateSourceProduct(); @@ -250,25 +250,25 @@ public void initialize() throws OperatorException { validateSARProduct(); /* - * 1. Compute the target CRS - */ + * 1. Compute the target CRS + */ GeoCoding sceneGeoCoding = sourceProduct.getSceneGeoCoding(); final GeoPos centerGeoPos = getCenterGeoPos(sceneGeoCoding, sourceProduct.getSceneRasterWidth(), sourceProduct.getSceneRasterHeight()); CoordinateReferenceSystem targetCrs = createTargetCRS(centerGeoPos); /* - * 2. Compute the target geometry - */ + * 2. Compute the target geometry + */ ImageGeometry targetImageGeometry = createImageGeometry(targetCrs); // determineDefaultSourceModel(); /* - * 3. Create the target product - */ + * 3. Create the target product + */ Rectangle targetRect = targetImageGeometry.getImageRect(); targetProduct = new Product("projected_" + sourceProduct.getName(), - sourceProduct.getProductType(), - targetRect.width, - targetRect.height); + sourceProduct.getProductType(), + targetRect.width, + targetRect.height); targetProduct.setDescription(sourceProduct.getDescription()); Dimension tileSize; if (tileSizeX != null && tileSizeY != null) { @@ -280,14 +280,14 @@ public void initialize() throws OperatorException { if (sourceProductPreferredTileSize.width == sourceProduct.getSceneRasterWidth()) { tileSize.width = targetProduct.getSceneRasterWidth(); tileSize.height = Math.min(sourceProductPreferredTileSize.height, - targetProduct.getSceneRasterHeight()); + targetProduct.getSceneRasterHeight()); } } } targetProduct.setPreferredTileSize(tileSize); /* - * 4. Define some target properties - */ + * 4. Define some target properties + */ if (orthorectify) { elevationModel = createElevationModel(); } @@ -296,8 +296,8 @@ public void initialize() throws OperatorException { copyIndexCoding(); try { targetProduct.setSceneGeoCoding(new CrsGeoCoding(targetImageGeometry.getMapCrs(), - targetRect, - targetImageGeometry.getImage2MapTransform())); + targetRect, + targetImageGeometry.getImage2MapTransform())); } catch (Exception e) { throw new OperatorException(e); } @@ -379,9 +379,9 @@ private GeoCoding getSourceGeoCoding(final RasterDataNode sourceBand) { private Orthorectifier createOrthorectifier(final RasterDataNode sourceBand) { return new Orthorectifier2(sourceBand.getRasterWidth(), - sourceBand.getRasterHeight(), - sourceBand.getPointing(), - elevationModel, 25); + sourceBand.getRasterHeight(), + sourceBand.getPointing(), + elevationModel, 25); } @@ -475,7 +475,7 @@ private void reprojectSourceRaster(RasterDataNode sourceRaster) { reprojectionSettings.setReprojection(reprojection); } MultiLevelImage projectedImage = createProjectedImage(sourceGeoCoding, sourceImage, reprojectionSettings.getSourceModel(), - targetBand, resampling, targetModel, reprojection); + targetBand, resampling, targetModel, reprojection); if (mustReplaceNaN(sourceRaster, targetDataType, targetNoDataValue.doubleValue())) { projectedImage = createNaNReplacedImage(projectedImage, targetModel, targetNoDataValue.doubleValue()); } @@ -485,8 +485,8 @@ private void reprojectSourceRaster(RasterDataNode sourceRaster) { targetBand.setSourceImage(projectedImage); /* - * Flag and index codings - */ + * Flag and index codings + */ if (sourceRaster instanceof Band) { final Band sourceBand = (Band) sourceRaster; ProductUtils.copySpectralBandProperties(sourceBand, targetBand); @@ -583,9 +583,9 @@ public RenderedImage createImage(int targetLevel) { RenderedImage leveledSourceImage = sourceImage.getImage(sourceLevel); final Rectangle sourceBounds = new Rectangle(leveledSourceImage.getMinX(), - leveledSourceImage.getMinY(), - leveledSourceImage.getWidth(), - leveledSourceImage.getHeight()); + leveledSourceImage.getMinY(), + leveledSourceImage.getWidth(), + leveledSourceImage.getHeight()); // the following transformation maps the source level image to level zero and then to the model, // which either is a map or an image CRS @@ -594,8 +594,8 @@ public RenderedImage createImage(int targetLevel) { i2mSource.concatenate(sourceImageToMapTransform); ImageGeometry sourceGeometry = new ImageGeometry(sourceBounds, - sourceModelCrs, - i2mSource); + sourceModelCrs, + i2mSource); ImageLayout imageLayout = ImageManager.createSingleBandedImageLayout( ImageManager.getDataBufferType(targetBand.getDataType()), @@ -604,7 +604,7 @@ public RenderedImage createImage(int targetLevel) { targetProduct.getPreferredTileSize(), ResolutionLevel.create(getModel(), targetLevel)); Rectangle targetBounds = new Rectangle(imageLayout.getMinX(null), imageLayout.getMinY(null), - imageLayout.getWidth(null), imageLayout.getHeight(null)); + imageLayout.getWidth(null), imageLayout.getHeight(null)); // the following transformation maps the target level image to level zero and then to the model, // which always is a map @@ -613,16 +613,16 @@ public RenderedImage createImage(int targetLevel) { i2mTarget.concatenate(targetImageToMapTransform); ImageGeometry targetGeometry = new ImageGeometry(targetBounds, - targetModelCrs, - i2mTarget); + targetModelCrs, + i2mTarget); Hints hints = new Hints(JAI.KEY_IMAGE_LAYOUT, imageLayout); hints.put(Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE); Dimension tileSize = ImageManager.getPreferredTileSize(targetProduct); try { return reprojection.reproject(leveledSourceImage, sourceGeometry, targetGeometry, - targetBand.getNoDataValue(), resampling, hints, targetLevel, - tileSize); + targetBand.getNoDataValue(), resampling, hints, targetLevel, + tileSize); } catch (FactoryException | TransformException e) { Debug.trace(e); throw new RuntimeException(e); @@ -669,7 +669,7 @@ public Spi() { private GeoPos getCenterGeoPos(GeoCoding geoCoding, int width, int height) { final PixelPos centerPixelPos = new PixelPos(0.5 * width + 0.5, - 0.5 * height + 0.5); + 0.5 * height + 0.5); return geoCoding.getGeoPos(centerPixelPos, null); } @@ -751,11 +751,11 @@ private Interpolation getResampling(Band band) { private int getResampleType() { final int resamplingType; - if ("Nearest".equalsIgnoreCase(resamplingName)) { + if ("Nearest".equalsIgnoreCase(resampling)) { resamplingType = Interpolation.INTERP_NEAREST; - } else if ("Bilinear".equalsIgnoreCase(resamplingName)) { + } else if ("Bilinear".equalsIgnoreCase(resampling)) { resamplingType = Interpolation.INTERP_BILINEAR; - } else if ("Bicubic".equalsIgnoreCase(resamplingName)) { + } else if ("Bicubic".equalsIgnoreCase(resampling)) { resamplingType = Interpolation.INTERP_BICUBIC; } else { resamplingType = -1; @@ -765,7 +765,7 @@ private int getResampleType() { void validateResamplingParameter() { if (getResampleType() == -1) { - throw new OperatorException("Invalid resampling method: " + resamplingName); + throw new OperatorException("Invalid resampling method: " + resampling); } } @@ -773,7 +773,7 @@ void validateReferencingParameters() { if (!((referencePixelX == null && referencePixelY == null && easting == null && northing == null) || (referencePixelX != null && referencePixelY != null && easting != null && northing != null))) { throw new OperatorException("Invalid referencing parameters: \n" + - "'referencePixelX', 'referencePixelY', 'easting' and 'northing' have to be specified either all or not at all."); + "'referencePixelX', 'referencePixelY', 'easting' and 'northing' have to be specified either all or not at all."); } } @@ -807,10 +807,10 @@ private ImageGeometry createImageGeometry(CoordinateReferenceSystem targetCrs) { imageGeometry = ImageGeometry.createCollocationTargetGeometry(sourceProduct, collocationProduct); } else { imageGeometry = ImageGeometry.createTargetGeometry(sourceProduct, targetCrs, - pixelSizeX, pixelSizeY, - width, height, orientation, - easting, northing, - referencePixelX, referencePixelY); + pixelSizeX, pixelSizeY, + width, height, orientation, + easting, northing, + referencePixelX, referencePixelY); final AxisDirection targetAxisDirection = targetCrs.getCoordinateSystem().getAxis(1).getDirection(); if (!AxisDirection.DISPLAY_DOWN.equals(targetAxisDirection)) { imageGeometry.changeYAxisDirection(); @@ -836,7 +836,7 @@ private void addDeltaBands() { deltaLatBand.setImageInfo(createDeltaBandImageInfo(-0.01, +0.01)); final Band deltaLonMetBand = targetProduct.addBand("delta_lon_metric", - "cos(rad(LAT)) * 6378137 * rad(longitude - LON)"); + "cos(rad(LAT)) * 6378137 * rad(longitude - LON)"); deltaLonMetBand.setUnit("m"); deltaLonMetBand.setDescription("Delta between old longitude and new longitude in meters"); deltaLonMetBand.setNoDataValueUsed(true); @@ -928,15 +928,15 @@ private void addReprojectionSettingsIfNecessary(RasterDataNode rasterDataNode) { if (!reprojectionSettingsMap.containsKey(key)) { GeoPos centerGeoPos = getCenterGeoPos(rasterDataNode.getGeoCoding(), - rasterDataNode.getRasterWidth(), - rasterDataNode.getRasterHeight()); + rasterDataNode.getRasterWidth(), + rasterDataNode.getRasterHeight()); CoordinateReferenceSystem targetCrs = createTargetCRS(centerGeoPos); ImageGeometry targetImageGeometry = ImageGeometry.createTargetGeometry(rasterDataNode, targetCrs, - pixelSizeX, pixelSizeY, - width, height, - orientation, easting, - northing, referencePixelX, - referencePixelY); + pixelSizeX, pixelSizeY, + width, height, + orientation, easting, + northing, referencePixelX, + referencePixelY); AxisDirection targetAxisDirection = targetCrs.getCoordinateSystem().getAxis(1).getDirection(); if (!AxisDirection.DISPLAY_DOWN.equals(targetAxisDirection)) { targetImageGeometry.changeYAxisDirection(); @@ -944,8 +944,8 @@ private void addReprojectionSettingsIfNecessary(RasterDataNode rasterDataNode) { Rectangle targetRect = targetImageGeometry.getImageRect(); try { CrsGeoCoding geoCoding = new CrsGeoCoding(targetImageGeometry.getMapCrs(), - targetRect, - targetImageGeometry.getImage2MapTransform()); + targetRect, + targetImageGeometry.getImage2MapTransform()); MultiLevelModel sourceModel = rasterDataNode.getMultiLevelModel(); reprojectionSettingsMap.put(key, new ReprojectionSettings(geoCoding, sourceModel, targetImageGeometry)); } catch (FactoryException | TransformException e) { @@ -1007,7 +1007,7 @@ public Reproject getReprojection() { } void updateParameterMap(Map parameterMap) { parameterMap.clear(); - parameterMap.put("resamplingName", resamplingName); + parameterMap.put("resampling", resampling); parameterMap.put("includeTiePointGrids", includeTiePointGrids); parameterMap.put("addDeltaBands", addDeltaBands); parameterMap.put("noDataValue", noDataValue); @@ -1025,5 +1025,5 @@ void updateParameterMap(Map parameterMap) { parameterMap.put("height", height); parameterMap.put("tileSizeX", tileSizeX); parameterMap.put("tileSizeY", tileSizeY); -} + } } \ No newline at end of file From 9a227ac9763fb440ed9fff81fd38544a2ae82dae Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Mon, 22 Aug 2022 15:32:07 -0400 Subject: [PATCH 03/12] Added NSIDC reader functionality ... commit to s3tbx, snap-desktop, and snap-engine --- .../org/esa/snap/core/datamodel/Band.java | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java index 87db4ad57f2..b272dcf6a82 100644 --- a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java +++ b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java @@ -64,6 +64,8 @@ public class Band extends AbstractBand { public static final String PROPERTY_NAME_SPECTRAL_BAND_INDEX = "spectralBandIndex"; public static final String PROPERTY_NAME_SPECTRAL_BANDWIDTH = "spectralBandwidth"; public static final String PROPERTY_NAME_SPECTRAL_WAVELENGTH = "spectralWavelength"; + public static final String PROPERTY_NAME_DATE_BAND_INDEX = "dateBandIndex"; + public static final String PROPERTY_NAME_DATE = "date"; /** * If this band contains flag data, this is the flag coding. @@ -73,6 +75,9 @@ public class Band extends AbstractBand { private int spectralBandIndex; private float spectralWavelength; private float spectralBandwidth; + private int dateBandIndex; + private String date; + // private float spectralBandwidth; private float solarFlux; /** @@ -89,6 +94,7 @@ public Band(String name, int dataType, int width, int height) { // By default a band is not a spectral band, // so spectral band index must be -1 setSpectralBandIndex(-1); + setDateBandIndex(-1); setModified(false); } @@ -202,6 +208,52 @@ public void setSpectralWavelength(float spectralWavelength) { } } + /** + * Gets the (zero-based) date band index. + * + * @return the (zero-based) date band index or -1 if it is unknown + */ + public int getDateBandIndex() { + return dateBandIndex; + } + + /** + * Sets the (zero-based) date band index. + * + * @param dateBandIndex the (zero-based) spectral band index or -1 if it is unknown + */ + public void setDateBandIndex(int dateBandIndex) { + if (this.dateBandIndex != dateBandIndex) { + this.dateBandIndex = dateBandIndex; + fireProductNodeChanged(PROPERTY_NAME_DATE_BAND_INDEX); + setModified(true); + } + } + + /** + * Gets the date. + * + * @return the date for this band, or zero if this is not a date band or the date is + * not known. + */ + public String getDate() { + return date; + } + + /** + * Sets the date. + * + * @param date YYYY-MM-DD of this band, or 1601-01-01 if this is not a date band or + * the date is not known. + */ + public void setDate(String date) { + if (this.date != date) { + this.date = date; + fireProductNodeChanged(PROPERTY_NAME_DATE); + setModified(true); + } + } + /** * Gets the spectral bandwidth in nm (nanomater) units. * @@ -259,8 +311,8 @@ protected RenderedImage createSourceImage() { if (hasRasterData()) { // This code is for backward compatibility only final RenderedImage image = ImageUtils.createRenderedImage(getRasterWidth(), - getRasterHeight(), - getRasterData()); + getRasterHeight(), + getRasterData()); return new DefaultMultiLevelImage(new DefaultMultiLevelSource(image, model)); } else { return new DefaultMultiLevelImage(new AbstractMultiLevelSource(model) { @@ -297,9 +349,9 @@ public void readRasterData(final int offsetX, final int offsetY, if (isProductReaderDirectlyUsable()) { // Don't go the long way round the source image. getProductReader().readBandRasterData(this, offsetX, offsetY, - width, height, - rasterData, - pm); + width, height, + rasterData, + pm); } else { try { pm.beginTask("Reading raster data...", 100); @@ -479,8 +531,8 @@ public ImageInfo createDefaultImageInfo(double[] histoSkipAreas, ProgressMonitor String name = indexCoding.getSampleName(i); int value = indexCoding.getSampleValue(i); final Color color = new Color(random.nextFloat(), - random.nextFloat(), - random.nextFloat()); + random.nextFloat(), + random.nextFloat()); points[i] = new ColorPaletteDef.Point(value, color, name); } return new ImageInfo(new ColorPaletteDef(points, points.length)); From 5982a54e320a451950f27166131982e8d66f588d Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Thu, 2 Feb 2023 11:12:32 -0500 Subject: [PATCH 04/12] Added changes to support the new Angular View tool --- .../org/esa/snap/core/datamodel/Band.java | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java index 87db4ad57f2..a1822498a11 100644 --- a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java +++ b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java @@ -64,12 +64,16 @@ public class Band extends AbstractBand { public static final String PROPERTY_NAME_SPECTRAL_BAND_INDEX = "spectralBandIndex"; public static final String PROPERTY_NAME_SPECTRAL_BANDWIDTH = "spectralBandwidth"; public static final String PROPERTY_NAME_SPECTRAL_WAVELENGTH = "spectralWavelength"; + public static final String PROPERTY_NAME_ANGULAR_BAND_INDEX = "angularBandIndex"; + public static final String PROPERTY_NAME_ANGULAR_VALUE = "angularValue"; /** * If this band contains flag data, this is the flag coding. */ private SampleCoding sampleCoding; + private int angularBandIndex; + private float angularValue; private int spectralBandIndex; private float spectralWavelength; private float spectralBandwidth; @@ -88,6 +92,7 @@ public Band(String name, int dataType, int width, int height) { super(name, dataType, width, height); // By default a band is not a spectral band, // so spectral band index must be -1 + setAngularBandIndex(-1); setSpectralBandIndex(-1); setModified(false); } @@ -156,6 +161,30 @@ public void setSampleCoding(SampleCoding sampleCoding) { } } + public float getAngularValue() { + return angularValue; + } + + public void setAngularValue(float angularValue) { + if (this.angularValue != angularValue) { + this.angularValue = angularValue; + fireProductNodeChanged(PROPERTY_NAME_ANGULAR_VALUE); + setModified(true); + } + } + + public int getAngularBandIndex() { + return angularBandIndex; + } + + public void setAngularBandIndex(int angularBandIndex) { + if (this.angularBandIndex != angularBandIndex) { + this.angularBandIndex = angularBandIndex; + fireProductNodeChanged(PROPERTY_NAME_ANGULAR_BAND_INDEX); + setModified(true); + } + } + /** * Gets the (zero-based) spectral band index. * @@ -259,8 +288,8 @@ protected RenderedImage createSourceImage() { if (hasRasterData()) { // This code is for backward compatibility only final RenderedImage image = ImageUtils.createRenderedImage(getRasterWidth(), - getRasterHeight(), - getRasterData()); + getRasterHeight(), + getRasterData()); return new DefaultMultiLevelImage(new DefaultMultiLevelSource(image, model)); } else { return new DefaultMultiLevelImage(new AbstractMultiLevelSource(model) { @@ -297,9 +326,9 @@ public void readRasterData(final int offsetX, final int offsetY, if (isProductReaderDirectlyUsable()) { // Don't go the long way round the source image. getProductReader().readBandRasterData(this, offsetX, offsetY, - width, height, - rasterData, - pm); + width, height, + rasterData, + pm); } else { try { pm.beginTask("Reading raster data...", 100); @@ -454,6 +483,8 @@ public String toString() { + ProductData.getTypeString(getDataType()) + "," + +getRasterWidth() + "," + +getRasterHeight() + "," + + +getAngularBandIndex() + "," + + +getAngularValue() + "," + +getSpectralBandIndex() + "," + +getSpectralWavelength() + "," + +getSpectralBandwidth() + "," + @@ -479,8 +510,8 @@ public ImageInfo createDefaultImageInfo(double[] histoSkipAreas, ProgressMonitor String name = indexCoding.getSampleName(i); int value = indexCoding.getSampleValue(i); final Color color = new Color(random.nextFloat(), - random.nextFloat(), - random.nextFloat()); + random.nextFloat(), + random.nextFloat()); points[i] = new ColorPaletteDef.Point(value, color, name); } return new ImageInfo(new ColorPaletteDef(points, points.length)); From 0761a0ac945c4586e6b413ba4b0020f50ff6ce26 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Wed, 1 Mar 2023 08:42:05 -0500 Subject: [PATCH 05/12] Removed formatting changes which caused merged conflicts --- .../java/org/esa/snap/core/datamodel/Band.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java index b272dcf6a82..984395bea85 100644 --- a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java +++ b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java @@ -311,8 +311,8 @@ protected RenderedImage createSourceImage() { if (hasRasterData()) { // This code is for backward compatibility only final RenderedImage image = ImageUtils.createRenderedImage(getRasterWidth(), - getRasterHeight(), - getRasterData()); + getRasterHeight(), + getRasterData()); return new DefaultMultiLevelImage(new DefaultMultiLevelSource(image, model)); } else { return new DefaultMultiLevelImage(new AbstractMultiLevelSource(model) { @@ -349,9 +349,9 @@ public void readRasterData(final int offsetX, final int offsetY, if (isProductReaderDirectlyUsable()) { // Don't go the long way round the source image. getProductReader().readBandRasterData(this, offsetX, offsetY, - width, height, - rasterData, - pm); + width, height, + rasterData, + pm); } else { try { pm.beginTask("Reading raster data...", 100); @@ -531,8 +531,8 @@ public ImageInfo createDefaultImageInfo(double[] histoSkipAreas, ProgressMonitor String name = indexCoding.getSampleName(i); int value = indexCoding.getSampleValue(i); final Color color = new Color(random.nextFloat(), - random.nextFloat(), - random.nextFloat()); + random.nextFloat(), + random.nextFloat()); points[i] = new ColorPaletteDef.Point(value, color, name); } return new ImageInfo(new ColorPaletteDef(points, points.length)); From 3231de2e2c46fe926ee09e49f00707b058f69b69 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Wed, 1 Mar 2023 08:43:48 -0500 Subject: [PATCH 06/12] Removed formatting changes which caused merged conflicts --- .../java/org/esa/snap/core/datamodel/Band.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java index a1822498a11..6ad4e0abd84 100644 --- a/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java +++ b/snap-core/src/main/java/org/esa/snap/core/datamodel/Band.java @@ -288,8 +288,8 @@ protected RenderedImage createSourceImage() { if (hasRasterData()) { // This code is for backward compatibility only final RenderedImage image = ImageUtils.createRenderedImage(getRasterWidth(), - getRasterHeight(), - getRasterData()); + getRasterHeight(), + getRasterData()); return new DefaultMultiLevelImage(new DefaultMultiLevelSource(image, model)); } else { return new DefaultMultiLevelImage(new AbstractMultiLevelSource(model) { @@ -326,9 +326,9 @@ public void readRasterData(final int offsetX, final int offsetY, if (isProductReaderDirectlyUsable()) { // Don't go the long way round the source image. getProductReader().readBandRasterData(this, offsetX, offsetY, - width, height, - rasterData, - pm); + width, height, + rasterData, + pm); } else { try { pm.beginTask("Reading raster data...", 100); @@ -510,8 +510,8 @@ public ImageInfo createDefaultImageInfo(double[] histoSkipAreas, ProgressMonitor String name = indexCoding.getSampleName(i); int value = indexCoding.getSampleValue(i); final Color color = new Color(random.nextFloat(), - random.nextFloat(), - random.nextFloat()); + random.nextFloat(), + random.nextFloat()); points[i] = new ColorPaletteDef.Point(value, color, name); } return new ImageInfo(new ColorPaletteDef(points, points.length)); From 673cc9baf24602a56299a0dc45250d70b4389e6f Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Sat, 9 Sep 2023 21:10:59 -0400 Subject: [PATCH 07/12] Added angularValue and angularBandIndex property copy to various tools --- .../esa/snap/core/dataio/ProductFlipper.java | 2 ++ .../core/dataio/ProductSubsetBuilder.java | 2 ++ .../core/dataio/dimap/DimapHeaderWriter.java | 5 ++++ .../dataio/dimap/DimapProductConstants.java | 2 ++ .../dataio/dimap/DimapProductHelpers.java | 19 ++++++++++++++ .../org/esa/snap/core/util/ProductUtils.java | 2 ++ .../esa/snap/core/gpf/common/BandMathsOp.java | 13 ++++++++++ .../support/BandDescriptorDomConverter.java | 26 +++++++++++++++++++ 8 files changed, 71 insertions(+) diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java index 37275344887..708b4dffc1e 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java @@ -323,6 +323,8 @@ private void addBandsToProduct(Product product) { } destBand.setSpectralBandIndex(sourceBand.getSpectralBandIndex()); destBand.setSpectralWavelength(sourceBand.getSpectralWavelength()); + destBand.setAngularValue(sourceBand.getAngularValue()); + destBand.setAngularBandIndex(sourceBand.getAngularBandIndex()); destBand.setSpectralBandwidth(sourceBand.getSpectralBandwidth()); destBand.setSolarFlux(sourceBand.getSolarFlux()); FlagCoding sourceFlagCoding = sourceBand.getFlagCoding(); diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java index 0b3d695c4d6..12fd9e2f76a 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java @@ -668,6 +668,8 @@ protected void addBandsToProduct(Product product) { destBand.setSpectralBandIndex(sourceBand.getSpectralBandIndex()); destBand.setSpectralWavelength(sourceBand.getSpectralWavelength()); destBand.setSpectralBandwidth(sourceBand.getSpectralBandwidth()); + destBand.setAngularValue(sourceBand.getAngularValue()); + destBand.setAngularBandIndex(sourceBand.getAngularBandIndex()); destBand.setSolarFlux(sourceBand.getSolarFlux()); if (sourceBand.isNoDataValueSet()) { destBand.setNoDataValue(sourceBand.getNoDataValue()); diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapHeaderWriter.java b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapHeaderWriter.java index b9e75dd29f2..f3c52a1243a 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapHeaderWriter.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapHeaderWriter.java @@ -219,7 +219,12 @@ protected void writeImageInterpretationElements(int indent) { printLine(indent + 2, DimapProductConstants.TAG_SPECTRAL_BAND_INDEX, band.getSpectralBandIndex()); } + if (band.getAngularBandIndex() > -1) { + printLine(indent + 2, DimapProductConstants.TAG_ANGULAR_BAND_INDEX, + band.getAngularBandIndex()); + } printLine(indent + 2, DimapProductConstants.TAG_BAND_WAVELEN, band.getSpectralWavelength()); + printLine(indent + 2, DimapProductConstants.TAG_BAND_ANGULAR_VALUE, band.getAngularValue()); printLine(indent + 2, DimapProductConstants.TAG_BANDWIDTH, band.getSpectralBandwidth()); final FlagCoding flagCoding = band.getFlagCoding(); if (flagCoding != null) { diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductConstants.java b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductConstants.java index 02dd05c094f..1870e04737b 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductConstants.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductConstants.java @@ -279,9 +279,11 @@ public final class DimapProductConstants { public static final String TAG_DATA_TYPE = "DATA_TYPE"; public static final String TAG_SOLAR_FLUX = "SOLAR_FLUX"; public static final String TAG_SPECTRAL_BAND_INDEX = "SPECTRAL_BAND_INDEX"; + public static final String TAG_ANGULAR_BAND_INDEX = "ANGULAR_BAND_INDEX"; public static final String TAG_SOLAR_FLUX_UNIT = "SOLAR_FLUX_UNIT"; public static final String TAG_BANDWIDTH = "BANDWIDTH"; public static final String TAG_BAND_WAVELEN = "BAND_WAVELEN"; + public static final String TAG_BAND_ANGULAR_VALUE = "BAND_ANGULAR_VALUE"; public static final String TAG_WAVELEN_UNIT = "WAVELEN_UNIT"; public static final String TAG_FLAG_CODING_NAME = "FLAG_CODING_NAME"; public static final String TAG_INDEX_CODING_NAME = "INDEX_CODING_NAME"; diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductHelpers.java b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductHelpers.java index ce192d46c95..bcab2fb34d8 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductHelpers.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/dimap/DimapProductHelpers.java @@ -1643,8 +1643,10 @@ private static void setGeneralBandProperties(Band band, Element element, Product setUnit(element, band); setSpectralWaveLength(element, band); setSpectralBandWidth(element, band); + setAngularValue(element, band); setSolarFlux(element, band); setSpectralBandIndex(element, band); + setAngularBandIndex(element, band); setScaling(element, band); setFlagCoding(element, band, product); setIndexCoding(element, band, product); @@ -1695,6 +1697,15 @@ private static void setSpectralBandIndex(final Element element, final Band band) } } + private static void setAngularBandIndex(final Element element, final Band band) { + final String angularBandIndex = element.getChildTextTrim(DimapProductConstants.TAG_ANGULAR_BAND_INDEX); + if (angularBandIndex != null) { + band.setAngularBandIndex(Integer.parseInt(angularBandIndex)); + } else { + band.setAngularBandIndex(-1); + } + } + private static void setScaling(final Element element, final Band band) { final String scalingFactorString = element.getChildTextTrim(DimapProductConstants.TAG_SCALING_FACTOR); if (scalingFactorString != null) { @@ -1827,6 +1838,14 @@ private static void setSpectralBandWidth(final Element element, final Band band) } } + private static void setAngularValue(final Element element, final Band band) { + final String angularValue = element.getChildTextTrim(DimapProductConstants.TAG_BAND_ANGULAR_VALUE); + if (angularValue != null) { + band.setAngularValue(Float.parseFloat(angularValue)); + } + } + + private void addCollectedAncillaryVariables() { Set>> entries = ancillaryVariables.entrySet(); for (Map.Entry> entry : entries) { diff --git a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java index 37ac397fb20..534feafb667 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java @@ -1020,6 +1020,8 @@ public static void copySpectralBandProperties(Band sourceBand, Band targetBand) targetBand.setSpectralBandIndex(sourceBand.getSpectralBandIndex()); targetBand.setSpectralWavelength(sourceBand.getSpectralWavelength()); targetBand.setSpectralBandwidth(sourceBand.getSpectralBandwidth()); + targetBand.setAngularValue(sourceBand.getAngularValue()); + targetBand.setAngularBandIndex(sourceBand.getAngularBandIndex()); targetBand.setSolarFlux(sourceBand.getSolarFlux()); } diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/BandMathsOp.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/BandMathsOp.java index 671c4a4600d..c9675f6a2f7 100644 --- a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/BandMathsOp.java +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/BandMathsOp.java @@ -183,6 +183,13 @@ public static class BandDescriptor { * Target band's spectral wavelength in nm. */ public Float spectralWavelength; + + + public Float angularValue; + + + public Integer angularBandIndex; + /** * Target band's spectral bandwidth in nm. */ @@ -413,6 +420,12 @@ private Band createBand(BandDescriptor bandDescriptor, Dimension targetBandDimen if (bandDescriptor.spectralWavelength != null) { targetBand.setSpectralWavelength(bandDescriptor.spectralWavelength); } + if (bandDescriptor.angularValue != null) { + targetBand.setAngularValue(bandDescriptor.angularValue); + } + if (bandDescriptor.angularBandIndex != null) { + targetBand.setAngularBandIndex(bandDescriptor.angularBandIndex); + } if (bandDescriptor.spectralBandwidth != null) { targetBand.setSpectralBandwidth(bandDescriptor.spectralBandwidth); } diff --git a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/support/BandDescriptorDomConverter.java b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/support/BandDescriptorDomConverter.java index 69af33d0acc..e3dff928eea 100644 --- a/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/support/BandDescriptorDomConverter.java +++ b/snap-gpf/src/main/java/org/esa/snap/core/gpf/common/support/BandDescriptorDomConverter.java @@ -83,6 +83,22 @@ public BandMathsOp.BandDescriptor[] convertDomToValue(DomElement parentElement, desc.spectralBandwidth = Float.parseFloat(spectralBandwidth.getValue()); } + DomElement angularValue = targetBand.getChild("angularValue"); + if (angularValue != null) { + if(angularValue.getValue().equals("null")) + desc.angularValue = null; + else + desc.angularValue = Float.parseFloat(angularValue.getValue()); + } + + DomElement angularBandIndex = targetBand.getChild("angularBandIndex"); + if (angularBandIndex != null) { + if(angularBandIndex.getValue().equals("null")) + desc.angularBandIndex = null; + else + desc.angularBandIndex = Integer.parseInt(angularBandIndex.getValue()); + } + DomElement scalingOffset = targetBand.getChild("scalingOffset"); if (scalingOffset != null) { if(scalingOffset.getValue().equals("null")) @@ -151,6 +167,16 @@ public void convertValueToDom(Object value, DomElement parentElement) throws Con spectralBandwidth.setValue(String.valueOf(bandDescriptor.spectralBandwidth)); } + if(bandDescriptor.angularValue != null) { + DomElement angularValue = targetBand.createChild("angularValue"); + angularValue.setValue(String.valueOf(bandDescriptor.angularValue)); + } + + if(bandDescriptor.angularBandIndex != null) { + DomElement angularBandIndex = targetBand.createChild("angularBandIndex"); + angularBandIndex.setValue(String.valueOf(bandDescriptor.angularBandIndex)); + } + if(bandDescriptor.scalingOffset != null) { DomElement scalingOffset = targetBand.createChild("scalingOffset"); scalingOffset.setValue(String.valueOf(bandDescriptor.scalingOffset)); From 8e9218cab8b6583d1b82976af65ecc42d56f04b6 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Wed, 11 Oct 2023 16:37:11 -0400 Subject: [PATCH 08/12] Update subset tool to include 'derived from' in some of the metadata fields' --- .../org/esa/snap/core/dataio/ProductSubsetBuilder.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java index 12fd9e2f76a..d365dc3127e 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductSubsetBuilder.java @@ -146,6 +146,10 @@ private static void updateMetadata( totalSize.getData().setElemUInt(targetProduct.getRawStorageSize()); } + +// ProductUtils.markProductMetaDataFieldAsDerivedFrom(targetProduct); + + if (nearRangeOnLeft) { setLatLongMetadata(targetProduct, trgAbsRoot, "first_near_lat", "first_near_long", 0.5f, 0.5f); setLatLongMetadata(targetProduct, trgAbsRoot, "first_far_lat", "first_far_long", @@ -534,6 +538,9 @@ private Product createProduct() { if (!isMetadataIgnored()) { ProductUtils.copyMetadata(sourceProduct, product); } + + ProductUtils.markProductMetaDataFieldAsDerivedFrom(product); + addTiePointGridsToProduct(product); addBandsToProduct(product); ProductUtils.copyMasks(sourceProduct, product); From 055f943e6fee3bb367b5dadbccab005bf934966b Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Mon, 20 Nov 2023 11:16:28 -0500 Subject: [PATCH 09/12] Updated ProductUtils.java and StringUtils.java to match other branches --- .../org/esa/snap/core/util/ProductUtils.java | 77 +++++++++++++++++-- .../org/esa/snap/core/util/StringUtils.java | 5 -- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java index 0418570cfcd..68b9e956750 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java @@ -49,10 +49,9 @@ import java.awt.image.*; import java.io.IOException; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.text.ParseException; +import java.util.*; +import java.util.List; /** * This class provides many static factory methods to be used in conjunction with data products. @@ -64,6 +63,8 @@ public class ProductUtils { private static String GLOBAL_ATTRIBUTES_KEY = "Global_Attributes"; public static String METADATA_PROJECTION_KEY = "map_projection"; public static String[] METADATA_POSSIBLE_PROJECTION_KEYS = {METADATA_PROJECTION_KEY, "projection", "crs"}; + public static String[] METADATA_POSSIBLE_START_TIME_KEYS = {"time_coverage_start"}; + public static String[] METADATA_POSSIBLE_END_TIME_KEYS = {"time_coverage_end"}; public static String[] METADATA_POSSIBLE_SENSOR_KEYS = {"sensor_name", "instrument", "sensor"}; public static String[] METADATA_POSSIBLE_PLATFORM_KEYS = {"platform"}; public static String[] METADATA_POSSIBLE_PROCESSING_VERSION_KEYS = {"processing_version"}; @@ -74,7 +75,6 @@ public class ProductUtils { public static String METADATA_RESOLUTION_KEY = "spatial_resolution"; public static String[] METADATA_POSSIBLE_RESOLUTION_KEYS = {METADATA_RESOLUTION_KEY, "resolution"}; - private static final int[] RGB_BAND_OFFSETS = new int[]{ 2, 1, 0 }; @@ -1396,6 +1396,71 @@ public static String getMetaData(Product product, String key) { + static ProductData.UTC parseUtcDate(String timeString) { + try { + if (timeString.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z")) { + // ISO + return ProductData.UTC.parse(timeString, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + } else if (timeString.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z")) { + // ISO with micros + timeString = timeString.substring(0, timeString.length() - 1); + return ProductData.UTC.parse(timeString, "yyyy-MM-dd'T'HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{2}\\d{2}T\\d{6}Z")) { + // ISO no-punctation + return ProductData.UTC.parse(timeString, "yyyyMMdd'T'HHmmss'Z'"); + } else if (timeString.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}")) { + // MODIS + return ProductData.UTC.parse(timeString, "yyyy-MM-dd HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{2}\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}")) { + // OCTS + return ProductData.UTC.parse(timeString, "yyyyMMdd HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{3}\\d{2}\\d{2}\\d{2}\\d{3}")) { + Date date = ProductData.UTC.createDateFormat("yyyyDDDHHmmssSSS").parse(timeString); + String milliSeconds = timeString.substring(timeString.length() - 3); + return ProductData.UTC.create(date, Long.parseLong(milliSeconds) * 1000); + } + } catch (ParseException ignored) { + } + return null; + } + + + + public static boolean isMetadataKeyExists(Product product, String key) { + // Created by Daniel Knowles + boolean keyExists = false; + + MetadataAttribute metadataAttribute; + + if (key != null && key.length() > 0) { + try { + metadataAttribute = product.getMetadataRoot().getElement("Global_Attributes").getAttribute(key); + if (metadataAttribute != null) { + keyExists = true; + } + } catch (Exception ignore) { + } + } + + return keyExists; + } + + public static String getBandMetaData(Product product, String key, String band) { + // Created by Daniel Knowles + String metaData = ""; + + if (key != null && key.length() > 0 && band != null && band.length() > 0) { + try { + metaData = product.getMetadataRoot().getElement("Band_Attributes").getElement(band).getAttribute(key).getData().getElemString(); + } catch (Exception ignore) { + } + } + + return metaData; + } + + + public static String getMetaData(Product product, String key, boolean exact) { // Created by Daniel Knowles @@ -1453,8 +1518,6 @@ public static String getMetaDataOrbit(Product product) { return metaData; } - - public static void copyVectorData(Product sourceProduct, Product targetProduct) { ProductNodeGroup vectorDataGroup = sourceProduct.getVectorDataGroup(); diff --git a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java index 79886a3320b..107d6428a8a 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java @@ -51,9 +51,6 @@ public enum CaseType { public static String DELIMITOR_SPACE = " "; public static String DELIMITOR_UNDERSCORE = "_"; - - - /** * Splits the given text into a list of tokens by using the supplied separators. Empty tokens are created for * successive separators, or if the supplied text starts with or ends with a separator. If the given text string @@ -940,7 +937,6 @@ private static Format getFormat() { prettyFormat.setTextMode(Format.TextMode.NORMALIZE); return prettyFormat; } - public static String[] getStringCaseVariations(String s) { // Created by Daniel Knowles if (s == null || s.length() == 0) { @@ -1077,5 +1073,4 @@ static String toProperCase(String s) { return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); } - } From 151861e5d807ac5c9c052a0cbf56288f81823ab7 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Thu, 25 Jan 2024 19:25:23 -0500 Subject: [PATCH 10/12] temp edits to fix conflicts --- .../org/esa/snap/core/util/ProductUtils.java | 380 +++++++++++++++++- .../org/esa/snap/core/util/StringUtils.java | 148 +++++++ 2 files changed, 524 insertions(+), 4 deletions(-) diff --git a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java index 855f3e0c0f3..9017ef36a1e 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/ProductUtils.java @@ -49,10 +49,9 @@ import java.awt.image.*; import java.io.IOException; import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.text.ParseException; +import java.util.*; +import java.util.List; /** * This class provides many static factory methods to be used in conjunction with data products. @@ -61,6 +60,21 @@ */ public class ProductUtils { + private static String GLOBAL_ATTRIBUTES_KEY = "Global_Attributes"; + public static String METADATA_PROJECTION_KEY = "map_projection"; + public static String[] METADATA_POSSIBLE_PROJECTION_KEYS = {METADATA_PROJECTION_KEY, "projection", "crs"}; + public static String[] METADATA_POSSIBLE_START_TIME_KEYS = {"time_coverage_start"}; + public static String[] METADATA_POSSIBLE_END_TIME_KEYS = {"time_coverage_end"}; + public static String[] METADATA_POSSIBLE_SENSOR_KEYS = {"sensor_name", "instrument", "sensor"}; + public static String[] METADATA_POSSIBLE_PLATFORM_KEYS = {"platform"}; + public static String[] METADATA_POSSIBLE_PROCESSING_VERSION_KEYS = {"processing_version"}; + public static String[] METADATA_POSSIBLE_DAY_NIGHT_KEYS = {"day_night_flag", "day_night"}; + public static String[] METADATA_POSSIBLE_ORBIT_KEYS = {"orbit_number", "orbit"}; + public static String[] METADATA_POSSIBLE_START_ORBIT_KEYS = {"start_orbit_number", "end_orbit"}; + public static String[] METADATA_POSSIBLE_END_ORBIT_KEYS = {"end_orbit_number", "end_orbit"}; + + public static String METADATA_RESOLUTION_KEY = "spatial_resolution"; + public static String[] METADATA_POSSIBLE_RESOLUTION_KEYS = {METADATA_RESOLUTION_KEY, "resolution"}; private static final int[] RGB_BAND_OFFSETS = new int[]{ 2, 1, 0 }; @@ -1009,6 +1023,364 @@ public static void copyTiePointGrids(Product sourceProduct, Product targetProduc } } + public static void markAsDerivedFromMetaDataField(Product product, String attribute) { + // Created by Daniel Knowles + + String tag = "Derived from ("; + + if (attribute != null && attribute.length() > 0 && product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + String value = ""; + + MetadataAttribute metadataAttribute = metadataElement.getAttribute(attribute); + + if (metadataAttribute != null) { + value = metadataAttribute.getData().toString(); + + if (value != null && value.length() > 0 && !value.startsWith(tag)) { + value = tag + value + ")"; + setMetaDataField(product, attribute, value); + } + } + } + + } + + + public static void markProductMetaDataFieldAsDerivedFrom(Product product) { + // Created by Daniel Knowles + + markAsDerivedFromMetaDataField(product, "product_name"); + markAsDerivedFromMetaDataField(product, "title"); + markAsDerivedFromMetaDataField(product, "processing_level"); + + String tag = "Derived from ("; + + if (product != null) { + String productType = product.getProductType(); + + if (productType != null && productType.length() > 0 && !productType.startsWith(tag)) { + productType = tag + productType + ")"; + product.setProductType(productType); + } + } + + } + + + public static void prependHistoryMetaDataField(Product product, String latestHistoryEvent) { + // Created by Daniel Knowles + + String HISTORY_KEY = "history"; + String history = latestHistoryEvent; + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + if (metadataElement.getAttribute(HISTORY_KEY) != null) { + String previousHistory = metadataElement.getAttribute(HISTORY_KEY).getData().toString(); + + if (previousHistory.length() > 0) { + history = latestHistoryEvent + " :: " + previousHistory; + } + } + + setMetaDataField(product, HISTORY_KEY, history); + } + } + + + public static void setResolutionMetaDataField(Product product, boolean markAsDerivedFrom) { + // Created by Daniel Knowles + + setMetaDataFieldFromPossible(product, METADATA_RESOLUTION_KEY, METADATA_POSSIBLE_RESOLUTION_KEYS); + + if (markAsDerivedFrom) { + markAsDerivedFromMetaDataField(product, METADATA_RESOLUTION_KEY); + } + } + + + public static void setMetaDataFieldFromPossible(Product product, String attribute, String[] possibleAttributes) { + // Created by Daniel Knowles + // if attribute does not exist then set to first value found from the possibleAttributes + + if (product != null && product.getMetadataRoot() != null) { + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + if (metadataElement != null) { + MetadataAttribute metadataAttribute = metadataElement.getAttribute(attribute); + + if (metadataAttribute == null) { + for (String key : possibleAttributes) { + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + if (metadataElement.getAttribute(keyVariation) != null) { + String value = metadataElement.getAttribute(keyVariation).getData().toString(); + setMetaDataField(product, attribute, value); + break; + } + } + } + + for (String key : possibleAttributes) { + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + if (keyVariation != null && !keyVariation.toLowerCase().equals(attribute.toLowerCase())) { + deleteMetaDataField(product, keyVariation); + } + } + } + } + } + } + } + + + public static void setMapProjectionMetaDataFields(Product product) { + // Created by Daniel Knowles + + String MAP_PROJECTION_KEY = "map_projection"; + String CRS_KEY = "crs"; + String UNDEFINED_VALUE = "undefined"; + String[] keysToDelete = {"projection", "mapprojection", "coordinatesystem", "coordinatereferencesystem", "coordinate_system", "geocoding", "geo_coding"}; + + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + deleteMetaDataFields(product, keysToDelete); + + String mapProjectionString = UNDEFINED_VALUE; + String crsString = UNDEFINED_VALUE; + + if (product.getSceneGeoCoding() != null && product.getSceneGeoCoding().getMapCRS() != null) { + if (product.getSceneGeoCoding().getMapCRS().getName() != null) { + mapProjectionString = product.getSceneGeoCoding().getMapCRS().getName().toString(); + } + if (product.getSceneGeoCoding().getMapCRS().toString() != null) { + crsString = product.getSceneGeoCoding().getMapCRS().toString().replaceAll("\n", "").replaceAll(" ", ""); + } + } + + setMetaDataField(product, MAP_PROJECTION_KEY, mapProjectionString); + setMetaDataField(product, CRS_KEY, crsString); + } + } + + + public static void deleteMetaDataFields(Product product, String[] fields) { + // Created by Daniel Knowles + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + for (String key : fields) { + MetadataAttribute metadataAttribute = metadataElement.getAttribute(key); + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(false); + metadataElement.removeAttribute(metadataAttribute); + } + } + } + + + public static void deleteMetaDataField(Product product, String field) { + // Created by Daniel Knowles + + String[] fields = {field}; + deleteMetaDataFields(product, fields); + } + + + public static void setMetaDataField(Product product, String field, String value) { + // Created by Daniel Knowles + + String UNDEFINED_VALUE = "undefined"; + + if (product != null && product.getMetadataRoot() != null && product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY) != null) { + + MetadataElement metadataElement = product.getMetadataRoot().getElement(GLOBAL_ATTRIBUTES_KEY); + + MetadataAttribute metadataAttribute = metadataElement.getAttribute(field); + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(false); + metadataAttribute.setModified(true); + } + + // this wont do anything if attribute is not a String type + try { + if (value != null) { + metadataElement.setAttributeString(field, value); + } else { + metadataElement.setAttributeString(field, UNDEFINED_VALUE); + } + } catch (Exception e) { + + } + + if (metadataAttribute != null) { + metadataAttribute.setReadOnly(true); + } + } + } + + + + + public static String getMetaData(Product product, String[] keys) { + // Created by Daniel Knowles + String metaData = ""; + + for (String key : keys) { + metaData = getMetaData(product, key, false); + + if (metaData.length() > 0) { + return metaData; + } + } + + return metaData; + } + + public static String getMetaData(Product product, String key) { + // Created by Daniel Knowles + String metaData = ""; + + if (key != null && key.length() > 0) { + try { + metaData = product.getMetadataRoot().getElement("Global_Attributes").getAttribute(key).getData().getElemString(); + } catch (Exception ignore) { + } + } + + return metaData; + } + + + + static ProductData.UTC parseUtcDate(String timeString) { + try { + if (timeString.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z")) { + // ISO + return ProductData.UTC.parse(timeString, "yyyy-MM-dd'T'HH:mm:ss'Z'"); + } else if (timeString.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z")) { + // ISO with micros + timeString = timeString.substring(0, timeString.length() - 1); + return ProductData.UTC.parse(timeString, "yyyy-MM-dd'T'HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{2}\\d{2}T\\d{6}Z")) { + // ISO no-punctation + return ProductData.UTC.parse(timeString, "yyyyMMdd'T'HHmmss'Z'"); + } else if (timeString.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}")) { + // MODIS + return ProductData.UTC.parse(timeString, "yyyy-MM-dd HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{2}\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}")) { + // OCTS + return ProductData.UTC.parse(timeString, "yyyyMMdd HH:mm:ss"); + } else if (timeString.matches("\\d{4}\\d{3}\\d{2}\\d{2}\\d{2}\\d{3}")) { + Date date = ProductData.UTC.createDateFormat("yyyyDDDHHmmssSSS").parse(timeString); + String milliSeconds = timeString.substring(timeString.length() - 3); + return ProductData.UTC.create(date, Long.parseLong(milliSeconds) * 1000); + } + } catch (ParseException ignored) { + } + return null; + } + + + + public static boolean isMetadataKeyExists(Product product, String key) { + // Created by Daniel Knowles + boolean keyExists = false; + + MetadataAttribute metadataAttribute; + + if (key != null && key.length() > 0) { + try { + metadataAttribute = product.getMetadataRoot().getElement("Global_Attributes").getAttribute(key); + if (metadataAttribute != null) { + keyExists = true; + } + } catch (Exception ignore) { + } + } + + return keyExists; + } + + public static String getBandMetaData(Product product, String key, String band) { + // Created by Daniel Knowles + String metaData = ""; + + if (key != null && key.length() > 0 && band != null && band.length() > 0) { + try { + metaData = product.getMetadataRoot().getElement("Band_Attributes").getElement(band).getAttribute(key).getData().getElemString(); + } catch (Exception ignore) { + } + } + + return metaData; + } + + + + + public static String getMetaData(Product product, String key, boolean exact) { + // Created by Daniel Knowles + if (key == null) { + return null; + } + + if (exact) { + return getMetaData(product, key); + } else { + String metaData = ""; + String[] keyVariations = StringUtils.getStringCaseVariations(key); + for (String keyVariation : keyVariations) { + metaData = getMetaData(product, keyVariation); + if (metaData != null && metaData.length() > 0) { + return metaData; + } + } + + return metaData; + } + } + + + + + + + + + + + public static String getMetaDataOrbit(Product product) { + // Created by Daniel Knowles + // Note this tries to retrieve an orbit or orbit range name + String metaData = getMetaData(product, METADATA_POSSIBLE_ORBIT_KEYS); + + if (metaData != null && metaData.length() > 0) { + return metaData; + } + + try { + String startOrbit = getMetaData(product, METADATA_POSSIBLE_START_ORBIT_KEYS); + String endOrbit = getMetaData(product, METADATA_POSSIBLE_END_ORBIT_KEYS); + if (startOrbit != null && startOrbit.length() > 0 && endOrbit != null && endOrbit.length() > 0) { + metaData = startOrbit + "-" + endOrbit; + } else if (endOrbit == null && startOrbit != null && startOrbit.length() > 0) { + metaData = startOrbit; + } else if (startOrbit == null && endOrbit != null && endOrbit.length() > 0) { + metaData = endOrbit; + } + } catch (Exception ignored) { + } + + + return metaData; + } public static void copyVectorData(Product sourceProduct, Product targetProduct) { ProductNodeGroup vectorDataGroup = sourceProduct.getVectorDataGroup(); diff --git a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java index 7c53215d42c..107d6428a8a 100644 --- a/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java +++ b/snap-core/src/main/java/org/esa/snap/core/util/StringUtils.java @@ -39,6 +39,18 @@ */ public class StringUtils { + public enum CaseType { + TITLE, + TITLE_UNDERSCORE, + LOWER_UNDERSCORE, + UPPER_UNDERSCORE, + CAMEL_LOWER_FIRST, + CAMEL_UPPER + } + + + public static String DELIMITOR_SPACE = " "; + public static String DELIMITOR_UNDERSCORE = "_"; /** * Splits the given text into a list of tokens by using the supplied separators. Empty tokens are created for * successive separators, or if the supplied text starts with or ends with a separator. If the given text string @@ -925,4 +937,140 @@ private static Format getFormat() { prettyFormat.setTextMode(Format.TextMode.NORMALIZE); return prettyFormat; } + public static String[] getStringCaseVariations(String s) { + // Created by Daniel Knowles + if (s == null || s.length() == 0) { + return null; + } + + if (s.length() == 1) { + String[] stringArray = {s.toLowerCase(), s.toUpperCase()}; + return stringArray; + } + + LinkedHashSet linkedHashSet = new LinkedHashSet(); + linkedHashSet.add(s); + linkedHashSet.add(getStringCaseVariation(s, CaseType.LOWER_UNDERSCORE)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.UPPER_UNDERSCORE)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.CAMEL_LOWER_FIRST)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.CAMEL_UPPER)); + linkedHashSet.add(getStringCaseVariation(s, CaseType.TITLE_UNDERSCORE)); + + String[] stringArray = new String[linkedHashSet.size()]; + linkedHashSet.toArray(stringArray); + return stringArray; + } + + + + public static String getStringCaseVariation(String s, CaseType caseType) { + // Created by Daniel Knowles + if (s == null || s.length() == 0) { + return null; + } + + String tmpString; + switch (caseType) { + case TITLE: + return toTitleCase(s, true); + case TITLE_UNDERSCORE: + return toTitleCase(s, false); + case LOWER_UNDERSCORE: + tmpString = toTitleCase(s, true); + if (tmpString != null) { + return tmpString.toLowerCase(); + } else { + return null; + } + case UPPER_UNDERSCORE: + tmpString = toTitleCase(s, true); + if (tmpString != null) { + return tmpString.toUpperCase(); + } else { + return null; + } + case CAMEL_LOWER_FIRST: + return toCamelCase(s, false); + case CAMEL_UPPER: + return toCamelCase(s, true); + default: + return null; + } + + + } + + + static String toCamelCase(String s, boolean upper) { + // Created by Daniel Knowles + + if (s == null || s.length() == 0) { + return s; + } + + String sourceDelimitor; + + if (s.contains(DELIMITOR_SPACE)) { + sourceDelimitor = DELIMITOR_SPACE; + } else if (s.contains(DELIMITOR_UNDERSCORE)) { + sourceDelimitor = DELIMITOR_UNDERSCORE; + } else { + return s; + } + + String[] parts = s.split(sourceDelimitor); + StringBuilder camelCaseString = new StringBuilder(""); + boolean firstWordSet = false; + for (String part : parts) { + if (part != null && part.length() > 0) { + if (!firstWordSet && !upper) { + camelCaseString.append(part.toLowerCase()); + firstWordSet = true; + } else { + camelCaseString.append(toProperCase(part)); + } + } + } + + return camelCaseString.toString(); + } + + + static String toTitleCase(String s, boolean spaceDelimitor) { + // Created by Daniel Knowles + // Source string is either space or underscore delimited + // Returned string is of format "This Is My Title" or "This_Is_My_Title" + + String delimitor = (spaceDelimitor) ? DELIMITOR_SPACE : DELIMITOR_UNDERSCORE; + if (s == null || s.length() == 0) { + return s; + } + + String sourceDelimitor; + + if (s.contains(DELIMITOR_SPACE)) { + sourceDelimitor = DELIMITOR_SPACE; + } else if (s.contains(DELIMITOR_UNDERSCORE)) { + sourceDelimitor = DELIMITOR_UNDERSCORE; + } else { + return s; + } + + String[] parts = s.split(sourceDelimitor); + for (int i = 0; i < parts.length; i++) { + parts[i] = toProperCase(parts[i]); + } + + return StringUtils.join(parts, delimitor); + } + + static String toProperCase(String s) { + // Created by Daniel Knowles + + if (s == null || s.length() < 2) { + return s; + } + + return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); + } } From 9b3ed562407471a46a377024efc5f91980bb4589 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Sat, 27 Jan 2024 10:06:31 -0500 Subject: [PATCH 11/12] Updated to support bindingContext used in seadas_reader --- .../bc/ceres/swing/binding/BindingContext.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ceres-ui/src/main/java/com/bc/ceres/swing/binding/BindingContext.java b/ceres-ui/src/main/java/com/bc/ceres/swing/binding/BindingContext.java index 9d972e1787a..cc7c13ea718 100644 --- a/ceres-ui/src/main/java/com/bc/ceres/swing/binding/BindingContext.java +++ b/ceres-ui/src/main/java/com/bc/ceres/swing/binding/BindingContext.java @@ -58,6 +58,8 @@ * @version $Revision$ $Date$ * @since Ceres 0.6 */ +// MAR2020 - Daniel Knowles - Added setEnabled so that some properties can be initially enabled/disabled + public class BindingContext { private final PropertySet propertySet; @@ -478,6 +480,22 @@ private static void configureComponent(JComponent component, String name, String component.setEnabled(enabled); } + + /** + * Sets the enabled state of the components associated with {@code targetProperty}. + * Enablement of the target property matches that of the source property. + * + * @param targetPropertyName The name of the target property. + * @param sourcePropertyName The name of the source property. + */ + public Enablement bindEnabledState(final String targetPropertyName, + final String sourcePropertyName) { + return bindEnabledState(targetPropertyName, true, + new EqualValuesCondition(sourcePropertyName, true)); + } + + + /** * Sets the enabled state of the components associated with {@code targetProperty}. * If the current value of {@code sourceProperty} equals {@code sourcePropertyValue} then From 6b410dd8ae70903c0bcf179734fc14266d9d5b31 Mon Sep 17 00:00:00 2001 From: Daniel Knowles Date: Fri, 15 Mar 2024 13:59:30 -0400 Subject: [PATCH 12/12] Add transfer of valid pixel expression and no-data value to ProductFlipper. This was done in this branch to avoid meerge conflicts --- .../src/main/java/org/esa/snap/core/dataio/ProductFlipper.java | 3 +++ snap-raster/src/main/java/org/esa/snap/raster/gpf/FlipOp.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java index 708b4dffc1e..4a6aa34a625 100644 --- a/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java +++ b/snap-core/src/main/java/org/esa/snap/core/dataio/ProductFlipper.java @@ -326,6 +326,9 @@ private void addBandsToProduct(Product product) { destBand.setAngularValue(sourceBand.getAngularValue()); destBand.setAngularBandIndex(sourceBand.getAngularBandIndex()); destBand.setSpectralBandwidth(sourceBand.getSpectralBandwidth()); + destBand.setValidPixelExpression(sourceBand.getValidPixelExpression()); + destBand.setNoDataValueUsed(sourceBand.isNoDataValueUsed()); + destBand.setNoDataValue(sourceBand.getNoDataValue()); destBand.setSolarFlux(sourceBand.getSolarFlux()); FlagCoding sourceFlagCoding = sourceBand.getFlagCoding(); IndexCoding sourceIndexCoding = sourceBand.getIndexCoding(); diff --git a/snap-raster/src/main/java/org/esa/snap/raster/gpf/FlipOp.java b/snap-raster/src/main/java/org/esa/snap/raster/gpf/FlipOp.java index 0eff243ecf4..5a6140b904f 100644 --- a/snap-raster/src/main/java/org/esa/snap/raster/gpf/FlipOp.java +++ b/snap-raster/src/main/java/org/esa/snap/raster/gpf/FlipOp.java @@ -105,6 +105,9 @@ private void addSelectedBands() throws OperatorException { for (Band srcBand : sourceBands) { final Band targetBand = ProductUtils.copyBand(srcBand.getName(), sourceProduct, targetProduct, false); targetBand.setSourceImage(srcBand.getSourceImage()); + targetBand.setValidPixelExpression(srcBand.getValidPixelExpression()); + targetBand.setNoDataValue(srcBand.getNoDataValue()); + targetBand.setNoDataValueUsed(srcBand.isNoDataValueUsed()); } }