/*
* Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.s1tbx.io.sentinel1;
import org.esa.s1tbx.io.XMLProductDirectory;
import org.esa.snap.core.datamodel.MetadataAttribute;
import org.esa.snap.core.datamodel.MetadataElement;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductData;
import org.esa.snap.core.util.SystemUtils;
import org.esa.snap.engine_utilities.datamodel.AbstractMetadata;
import org.esa.snap.engine_utilities.gpf.ReaderUtils;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
/**
* This class represents a product directory.
*/
public class Sentinel1Level2Directory extends XMLProductDirectory implements Sentinel1Directory {
private Sentinel1OCNReader OCNReader = null;
public Sentinel1Level2Directory(final File inputFile) {
super(inputFile);
}
protected String getHeaderFileName() {
return Sentinel1Constants.PRODUCT_HEADER_NAME;
}
protected String getRelativePathToImageFolder() {
return getRootFolder() + "measurement" + '/';
}
protected void addImageFile(final String imgPath, final MetadataElement newRoot) throws IOException {
final String name = getBandFileNameFromImage(imgPath);
if (name.endsWith(".nc")) {
if (OCNReader == null) {
OCNReader = new Sentinel1OCNReader(this);
}
File file = new File(getBaseDir(), imgPath);
if(isCompressed()) {
file = getFile(imgPath);
}
OCNReader.addImageFile(file, name);
}
}
@Override
protected void addBands(final Product product) {
OCNReader.addNetCDFBands(product);
}
@Override
protected void addAbstractedMetadataHeader(final MetadataElement root) throws IOException {
final MetadataElement absRoot = AbstractMetadata.addAbstractedMetadataHeader(root);
final MetadataElement origProdRoot = AbstractMetadata.addOriginalProductMetadata(root);
Sentinel1Level1Directory.addManifestMetadata(getProductName(), absRoot, origProdRoot, true);
final String acqMode = absRoot.getAttributeString(AbstractMetadata.ACQUISITION_MODE);
setSLC(absRoot.getAttributeString(AbstractMetadata.SAMPLE_TYPE).equals("COMPLEX"));
// get metadata for each band
addBandAbstractedMetadata(origProdRoot);
}
private void addBandAbstractedMetadata(final MetadataElement origProdRoot) throws IOException {
MetadataElement annotationElement = origProdRoot.getElement("annotation");
if (annotationElement == null) {
annotationElement = new MetadataElement("annotation");
origProdRoot.addElement(annotationElement);
}
if (OCNReader != null) {
// add netcdf metadata for OCN product
OCNReader.addNetCDFMetadata(annotationElement);
}
}
@Override
protected void addTiePointGrids(final Product product) {
// replaced by call to addTiePointGrids(band)
}
@Override
protected String getProductName() {
String name = getBaseName();
if (name.toUpperCase().endsWith(".SAFE"))
return name.substring(0, name.length() - 5);
else if (name.toUpperCase().endsWith(".ZIP"))
return name.substring(0, name.length() - 4);
return name;
}
protected String getProductType() {
return "Level-2 OCN";
}
public Sentinel1OCNReader getOCNReader() {
return OCNReader;
}
public ProductData.UTC getTime(final MetadataElement elem, final String tag) {
String start = elem.getAttributeString(tag, AbstractMetadata.NO_METADATA_STRING);
start = start.replace("T", "_");
return AbstractMetadata.parseUTC(start, sentinelDateFormat);
}
@Override
public Product createProduct() throws IOException {
// If addMetaData() is called before findImages(), the annotation will not show up in the display.
// This is because...
// in addBandAbstractedMetadata() (which is called by addAbstractedMetadataHeader() which is called by
// addMetaData()), for it to add annotations to metadata, OCNReader has to have already been created by
// addImageFile() (which is called by findImages()).
findImages(null);
final MetadataElement newRoot = addMetaData();
final MetadataElement absRoot = newRoot.getElement(AbstractMetadata.ABSTRACT_METADATA_ROOT);
final int sceneWidth = absRoot.getAttributeInt(AbstractMetadata.num_samples_per_line);
final int sceneHeight = absRoot.getAttributeInt(AbstractMetadata.num_output_lines);
final Product product = new Product(getProductName(), getProductType(), sceneWidth, sceneHeight);
updateProduct(product, newRoot);
addBands(product);
addGeoCoding(product);
product.setName(getProductName());
product.setDescription(getProductDescription());
ReaderUtils.addMetadataProductSize(product);
return product;
}
public void addGeoCodingToBands(final Product product) {
OCNReader.addGeoCodingToBands(product);
}
@Override
protected void addGeoCoding(final Product product) {
float minLat = 999F;
float maxLat = -999F;
float minLon = 999F;
float maxLon = -999F;
final MetadataElement elem = getMetadataObject(AbstractMetadata.getOriginalProductMetadata(product), "measurementFrameSet");
if (elem != null) {
final MetadataElement frameSet = elem.getElement("metadataWrap").getElement("xmlData").getElement("frameSet");
final MetadataElement[] frames = frameSet.getElements();
for (MetadataElement frame : frames) {
final MetadataAttribute coordinates = frame.getElement("footPrint").getAttribute("coordinates");
final String coordinatesStr = coordinates.getData().getElemString();
//System.out.println("Sentinel1Level2Directory.addGeoCodingForLevel2Products: coordinates = " + coordinatesStr);
final String[] latLonPairsStr = coordinatesStr.split(" ");
for (String s : latLonPairsStr) {
final String[] latStrLonStr = s.split(",");
final float lat = Float.parseFloat(latStrLonStr[0]);
final float lon = Float.parseFloat(latStrLonStr[1]);
if (lat < minLat) {
minLat = lat;
}
if (lat > maxLat) {
maxLat = lat;
}
if (lon < minLon) {
minLon = lon;
}
if (lon > maxLon) {
maxLon = lon;
}
}
}
//System.out.println("Sentinel1Level2Directory.addGeoCodingForLevel2Products: minLat = " + minLat + " maxLat = " + maxLat + " minLon = " + minLon + " maxLon = " + maxLon);
}
if (minLat > maxLat || minLon > maxLon) {
SystemUtils.LOG.severe("Sentinel1Level2Directory.addGeoCodingForLevel2Products: ERROR failed to get valid footprint");
return;
}
final float[] latCorners = new float[4];
final float[] lonCorners = new float[latCorners.length];
// The footprint
// index 0 index 1
// (maxLat, minLon) (maxLat, maxLon)
// -----------------------------------------------------
// | |
// | |
// | |
// -----------------------------------------------------
// (minLat, minLon) (minLat, maxLon)
// index 2 index 3
// top left corner
latCorners[0] = maxLat;
lonCorners[0] = minLon;
// top right corner
latCorners[1] = maxLat;
lonCorners[1] = maxLon;
// bottom left corner
latCorners[2] = minLat;
lonCorners[2] = minLon;
// bottom right corner
latCorners[3] = minLat;
lonCorners[3] = maxLon;
/*
System.out.println("Sentinel1Level2Directory.addGeoCodingForLevel2Products: corners of footprint (TopL, TopR, bottomL, bottomR):");
for (int i = 0; i < latCorners.length; i++) {
System.out.println(" " + latCorners[i] + ", " + lonCorners[i]);
}
*/
ReaderUtils.addGeoCoding(product, latCorners, lonCorners);
}
}