You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2021/08/31 17:25:22 UTC
[sis] 07/07: Parse some more metadata from Landsat.
This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
commit bd56303e6be910ab67a19c06b35fa18e57633f9e
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Tue Aug 31 19:15:42 2021 +0200
Parse some more metadata from Landsat.
---
.../storage/earthobservation/LandsatReader.java | 135 ++++++++++++++-------
.../sis/storage/earthobservation/LandsatStore.java | 2 +-
.../earthobservation/LandsatStoreProvider.java | 8 +-
.../sis/storage/earthobservation/package-info.java | 3 +-
.../sis/internal/storage/wkt/FirstKeywordPeek.java | 6 +-
5 files changed, 106 insertions(+), 48 deletions(-)
diff --git a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
index 4fe53b6..479696e 100644
--- a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
+++ b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatReader.java
@@ -147,6 +147,11 @@ final class LandsatReader extends MetadataBuilder {
static final int DIM = 2;
/**
+ * Suffix of groups that describe the processing done on the data instead of the data themselves.
+ */
+ private static final String LINEAGE_SUFFIX = "_RECORD";
+
+ /**
* The {@value} suffix added to attribute names that are followed by a band number.
* This band suffix is itself followed by the {@code '_'} character, then the band number.
* Example: {@code "REFLECTANCE_ADD_BAND_1"}.
@@ -220,6 +225,14 @@ final class LandsatReader extends MetadataBuilder {
private String group;
/**
+ * The last group where we fetched lineage (history) information.
+ * The same file may contain many lineage group.
+ *
+ * @see #parseLineage(String, int, String)
+ */
+ private String lineageGroup;
+
+ /**
* The acquisition time, or {@code null} if not yet known. This needs to be parsed in two steps:
* first by parsing the {@code "DATE_ACQUIRED"} attribute, then {@code "SCENE_CENTER_TIME"}.
*
@@ -365,8 +378,17 @@ final class LandsatReader extends MetadataBuilder {
start = CharSequences.skipLeadingWhitespaces(line, start + 1, --end);
end = CharSequences.skipTrailingWhitespaces(line, start, end);
}
+ final String value = line.substring(start, end);
try {
- parseKeyValuePair(key, band, line.substring(start, end));
+ if (group == null || !group.endsWith(LINEAGE_SUFFIX)) {
+ parseKeyValuePair(key, band, value);
+ } else {
+ if (!group.equals(lineageGroup)) {
+ lineageGroup = group;
+ newLineage();
+ }
+ parseLineage(key, band, value);
+ }
} catch (IllegalArgumentException | DateTimeException e) {
warning(key, reader, e);
}
@@ -407,8 +429,9 @@ final class LandsatReader extends MetadataBuilder {
}
/**
- * Invoked for every key-value pairs found in the file.
- * Leading and trailing spaces, if any, have been removed.
+ * Invoked for every key-value pairs found in the file for the main groups.
+ * A mean group is any group other than {@linkplain #parseLineage lineage}.
+ * Leading and trailing spaces, if any, have been removed from given argument.
*
* @param key the key in upper cases.
* @param band the band number, or 0 if none.
@@ -430,12 +453,10 @@ final class LandsatReader extends MetadataBuilder {
group = null;
break;
}
-
- ////
- //// GROUP = METADATA_FILE_INFO
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = METADATA_FILE_INFO (L1)│
+ * │ PRODUCT_CONTENTS (L2)│
+ * └────────────────────────────────────┘
* Origin of the product.
* Value is "Image courtesy of the U.S. Geological Survey".
*/
@@ -449,6 +470,10 @@ final class LandsatReader extends MetadataBuilder {
break;
}
/*
+ * Example: "https://doi.org/10.5066/P9OGBGM6"
+ */
+// case "DIGITAL_OBJECT_IDENTIFIER":
+ /*
* Product Request ID. NNNNNNNNNNNNN_UUUUU, where NNNNNNNNNNNNN = 13-digit Tracking,
* Routing, and Metrics (TRAM) order number and UUUUU = 5-digit TRAM unit number.
* Example: "0501403126384_00011"
@@ -458,10 +483,11 @@ final class LandsatReader extends MetadataBuilder {
break;
}
/*
- * The unique Landsat scene identifier.
- * Format is {@code Ls8ppprrrYYYYDDDGGGVV}.
- * Example: "LC81230522014071LGN00".
+ * Product: the filename prefix. Example: "LC08_L2SP_197030_20210812_20210819_02_T1"
+ * Scene: the unique Landsat scene identifier. Example: "LC81230522014071LGN00".
+ * Format: Ls8ppprrrYYYYDDDGGGVV
*/
+ case "LANDSAT_PRODUCT_ID":
case "LANDSAT_SCENE_ID": {
addTitleOrIdentifier(value, MetadataBuilder.Scope.ALL);
break;
@@ -488,15 +514,14 @@ final class LandsatReader extends MetadataBuilder {
* Example: "LPGS_2.3.0".
*/
// TODO case "PROCESSING_SOFTWARE_VERSION":
-
- ////
- //// GROUP = PRODUCT_METADATA
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = PRODUCT_METADATA (L1)│
+ * │ PRODUCT_CONTENTS (L2)│
+ * └────────────────────────────────────┘
* The identifier to inform the user of the product type.
* Value can be "L1T" or "L1GT".
*/
+ case "PROCESSING_LEVEL":
case "DATA_TYPE": {
setProcessingLevelCode("Landsat", value);
break;
@@ -628,6 +653,22 @@ final class LandsatReader extends MetadataBuilder {
break;
}
/*
+ * Examples: UINT8, UINT16, INT16.
+ */
+ case "DATA_TYPE_BAND_": {
+ final int s = value.lastIndexOf("INT");
+ if (s >= 0) try {
+ final Integer n = Integer.valueOf(value.substring(s + 3));
+ final DefaultBand db = band(key, band);
+ if (db != null) {
+ db.setBitsPerValue(n);
+ }
+ } catch (NumberFormatException e) {
+ warning(key, null, e);
+ }
+ break;
+ }
+ /*
* The file name for L1 metadata.
* Exemple: "LC81230522014071LGN00_MTL.txt".
*/
@@ -637,12 +678,9 @@ final class LandsatReader extends MetadataBuilder {
}
break;
}
-
- ////
- //// GROUP = IMAGE_ATTRIBUTES
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = IMAGE_ATTRIBUTES │
+ * └────────────────────────────────────┘
* The overall cloud coverage (percent) of the WRS-2 scene as a value between 0 and 100 inclusive.
* -1 indicates that the score was not calculated.
*/
@@ -671,12 +709,9 @@ final class LandsatReader extends MetadataBuilder {
setIlluminationElevationAngle(Double.parseDouble(value));
break;
}
-
- ////
- //// GROUP = MIN_MAX_PIXEL_VALUE
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = MIN_MAX_PIXEL_VALUE │
+ * └────────────────────────────────────┘
* Minimum achievable spectral radiance value for a band 1.
* This parameter is only present if this band is included in the product.
*/
@@ -700,12 +735,9 @@ final class LandsatReader extends MetadataBuilder {
}
break;
}
-
- ////
- //// GROUP = RADIOMETRIC_RESCALING
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = RADIOMETRIC_RESCALING │
+ * └────────────────────────────────────┘
* The multiplicative rescaling factor used to convert calibrated DN to Radiance units for a band.
* Unit is W/(m² sr um)/DN.
*/
@@ -721,12 +753,9 @@ final class LandsatReader extends MetadataBuilder {
setTransferFunction(key, band, false, value);
break;
}
-
- ////
- //// GROUP = PROJECTION_PARAMETERS
- ////
-
- /*
+ /* ┌────────────────────────────────────┐
+ * │ GROUP = PROJECTION_PARAMETERS │
+ * └────────────────────────────────────┘
* The map projection used in creating the image.
* Universal Transverse Mercator (UTM) or Polar Stereographic (PS).
*/
@@ -775,6 +804,28 @@ final class LandsatReader extends MetadataBuilder {
}
/**
+ * Invoked for every key-value pairs found in a lineage group. This method does a work similar to
+ * {@link #parseKeyValuePair(String, int, String)} except that the result is stored in a section
+ * about data history. Note that the file can contains many distinct lineage sections.
+ */
+ private void parseLineage(final String key, final int band, String value) {
+ switch (key) {
+ case "LANDSAT_PRODUCT_ID": {
+ addSource(value, null, null);
+ break;
+ }
+ case "PROCESSING_LEVEL": {
+ addProcessing(null, value);
+ break;
+ }
+ case "PROCESSING_SOFTWARE_VERSION": {
+ addSoftwareReference(value);
+ break;
+ }
+ }
+ }
+
+ /**
* Sets a component of the linear transfer function.
*
* @param key the key without its band number. Used only for formatting warning messages.
diff --git a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
index 770b330..6932a16 100644
--- a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
+++ b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
@@ -69,7 +69,7 @@ import org.apache.sis.setup.OptionKey;
*
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.8
* @module
*/
diff --git a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStoreProvider.java b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStoreProvider.java
index b54e628..6db3495 100644
--- a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStoreProvider.java
+++ b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStoreProvider.java
@@ -37,7 +37,7 @@ import org.apache.sis.internal.storage.wkt.FirstKeywordPeek;
* the part of the caller. However the {@link LandsatStore} instances created by this factory are not thread-safe.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.8
* @module
*/
@@ -62,7 +62,8 @@ public class LandsatStoreProvider extends DataStoreProvider {
/**
* The expected keyword after spaces removal.
*/
- private static final String KEYWORD = "GROUP=L1_METADATA_FILE";
+ private static final String KEYWORD = "GROUP=LANDSAT_METADATA_FILE",
+ L1_KEYWORD = "GROUP=L1_METADATA_FILE";
/**
* The part in process of being parsed:
@@ -126,7 +127,8 @@ public class LandsatStoreProvider extends DataStoreProvider {
*/
@Override
protected ProbeResult forKeyword(final char[] keyword, final int length) {
- if (length == maxLength && KEYWORD.equalsIgnoreCase(new String(keyword))) {
+ final String ks = new String(keyword, 0, length);
+ if (KEYWORD.equalsIgnoreCase(ks) || L1_KEYWORD.equalsIgnoreCase(ks)) {
return ProbeResult.SUPPORTED;
}
return ProbeResult.UNSUPPORTED_STORAGE;
diff --git a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/package-info.java b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/package-info.java
index a7278a9..b84a034 100644
--- a/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/package-info.java
+++ b/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/package-info.java
@@ -34,7 +34,8 @@
*
* @author Thi Phuong Hao Nguyen (VNSC)
* @author Minh Chinh Vu (VNSC)
- * @version 0.8
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
* @since 0.8
* @module
*/
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/FirstKeywordPeek.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/FirstKeywordPeek.java
index 8387c7f..d83319d 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/FirstKeywordPeek.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/FirstKeywordPeek.java
@@ -161,7 +161,11 @@ public abstract class FirstKeywordPeek {
}
keyword[pos++] = (char) c;
}
- c = (buffer == null) ? IOUtilities.readCodePoint(reader) : buffer.hasRemaining() ? (char) buffer.get() : -1;
+ if (buffer != null) {
+ c = buffer.hasRemaining() ? (char) buffer.get() : -1;
+ } else {
+ c = IOUtilities.readCodePoint(reader);
+ }
} while ((s = isKeywordChar(c)) >= ACCEPT);
/*
* At this point we finished to read and store the keyword.