Java tutorial
/* * 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.terrasarx; import Jama.Matrix; import org.esa.s1tbx.io.FileImageInputStreamExtImpl; import org.esa.s1tbx.io.SARReader; import org.esa.s1tbx.io.XMLProductDirectory; import org.esa.s1tbx.io.imageio.ImageIOFile; import org.esa.snap.core.datamodel.Band; 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.datamodel.TiePointGeoCoding; import org.esa.snap.core.datamodel.TiePointGrid; import org.esa.snap.core.dataop.downloadable.XMLSupport; import org.esa.snap.core.util.ProductUtils; import org.esa.snap.core.util.math.MathUtils; import org.esa.snap.engine_utilities.datamodel.AbstractMetadata; import org.esa.snap.engine_utilities.datamodel.Unit; import org.esa.snap.engine_utilities.datamodel.metadata.AbstractMetadataIO; import org.esa.snap.engine_utilities.eo.Constants; import org.esa.snap.engine_utilities.gpf.OperatorUtils; import org.esa.snap.engine_utilities.gpf.ReaderUtils; import org.esa.snap.engine_utilities.gpf.StackUtils; import org.esa.snap.engine_utilities.util.Maths; import org.esa.snap.engine_utilities.util.ZipUtils; import org.jdom2.Document; import org.jdom2.Element; import javax.imageio.stream.ImageInputStream; import java.awt.*; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.DateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * This class represents a product directory. */ public class TerraSarXProductDirectory extends XMLProductDirectory { private static String TERRA_SAR_X = "TerraSAR-X"; private static String TAN_DEM_X = "TanDEM-X"; private final File headerFile; private String productName = null; private String productType = null; private String productDescription = ""; private final double[] latCorners = new double[4]; private final double[] lonCorners = new double[4]; private final double[] slantRangeCorners = new double[4]; private final double[] incidenceCorners = new double[4]; private final List<File> cosarFileList = new ArrayList<>(1); private final Map<String, ImageInputStream> cosarBandMap = new HashMap<>(1); private static final DateFormat standardDateFormat = ProductData.UTC.createDateFormat("yyyy-MM-dd HH:mm:ss"); // For TDM CoSSC products only private String masterSatellite = null; private String slaveSatellite = null; private String masterProductName = null; private String slaveProductName = null; int numMasterBands = 0; public TerraSarXProductDirectory(final File inputFile) { super(inputFile); headerFile = inputFile; } protected String getHeaderFileName() { if (ZipUtils.isZip(headerFile)) { return ""; //todo } else { return headerFile.getName(); } } protected String getRelativePathToImageFolder() { return getRootFolder() + "IMAGEDATA" + '/'; } private void replaceAbstractedMetadataField(final MetadataElement abstractedMetadata, final String attrName, final String newValue) { final ProductData productData = abstractedMetadata.getAttribute(attrName).getData(); productData.setElems(newValue); } private MetadataElement addMetaDataForTanDemX() throws IOException { // xmlDoc is the "main" annotation (i.e., the file with name "TDM... .xml") final Element mainRootElement = xmlDoc.getRootElement(); final String inSARmasterID = mainRootElement.getChild("commonAcquisitionInfo").getChild("inSARmasterID") .getText().toLowerCase(); final String inSARslaveID = inSARmasterID.endsWith("1") ? "sat2" : "sat1"; masterSatellite = mainRootElement.getChild("commonAcquisitionInfo").getChild("satelliteID" + inSARmasterID) .getText(); slaveSatellite = mainRootElement.getChild("commonAcquisitionInfo").getChild("satelliteID" + inSARslaveID) .getText(); final List<Element> componentList = mainRootElement.getChild("productComponents").getChildren("component"); Element masterAnnotationComponent = null; Element slaveAnnotationComponent = null; for (Element component : componentList) { final String satId = component.getChild("instrument").getChildText("satIDs"); if (component.getChildText("name").startsWith("cossc_annotation")) { if (satId.equals(masterSatellite)) { masterAnnotationComponent = component; } if (satId.equals(slaveSatellite)) { slaveAnnotationComponent = component; } } if (masterAnnotationComponent != null && slaveAnnotationComponent != null) { break; } } if (masterAnnotationComponent == null) { throw new IOException( "Cannot locate primary annotation component (master product) in main annotation of TDM product"); } if (slaveAnnotationComponent == null) { throw new IOException( "Cannot locate secondary annotation component (slave product) in main annotation of TDM product"); } final String masterHeader = masterAnnotationComponent.getChild("file").getChild("location") .getChildText("name"); masterProductName = masterHeader.substring(0, masterHeader.indexOf("/")); // Build the slave metadata final String slaveHeader = slaveAnnotationComponent.getChild("file").getChild("location") .getChildText("name"); slaveProductName = slaveHeader.substring(0, slaveHeader.indexOf("/")); final Document slaveDoc = XMLSupport.LoadXML(getInputStream(slaveHeader)); final Element slaveRootElement = slaveDoc.getRootElement(); final MetadataElement slaveRoot = new MetadataElement("Slave_Metadata"); AbstractMetadataIO.AddXMLMetadata(slaveRootElement, AbstractMetadata.addOriginalProductMetadata(slaveRoot)); addAbstractedMetadataHeader(slaveRoot); final MetadataElement slaveAbstractedMetadataElem = slaveRoot.getElement("Abstracted_Metadata"); // Add Product_Information to slave Abstracted_Metadata final MetadataElement productInfo = new MetadataElement("Product_Information"); final MetadataElement inputProd = new MetadataElement("InputProducts"); productInfo.addElement(inputProd); inputProd.setAttributeString("InputProduct", slaveProductName); slaveAbstractedMetadataElem.addElement(productInfo); // Change the name from Abstracted_Metadata to the slave product name slaveAbstractedMetadataElem.setName(slaveProductName); // Remove Original_Product_Data from Slave_Metadata slaveRoot.removeElement(slaveRoot.getElement("Original_Product_Metadata")); // Use the master's annotation to build the Abstracted_Metadata and Original_Product_Metadata. final MetadataElement metadataRoot = new MetadataElement(Product.METADATA_ROOT_NAME); final Document masterDoc = XMLSupport.LoadXML(getInputStream(masterHeader)); final Element masterRootElement = masterDoc.getRootElement(); AbstractMetadataIO.AddXMLMetadata(masterRootElement, AbstractMetadata.addOriginalProductMetadata(metadataRoot)); addAbstractedMetadataHeader(metadataRoot); // Replace the product name (which right now is the master product) with the TDM product. // Replace data in Abstracted_Metadata with TDM values. MetadataElement abstractedMetadata = metadataRoot.getElement("Abstracted_Metadata"); // Turn on the coregistration flag abstractedMetadata.setAttributeInt("coregistered_stack", 1); // Replace PRODUCT productName = getHeaderFileName().substring(0, getHeaderFileName().length() - 4); replaceAbstractedMetadataField(abstractedMetadata, "PRODUCT", productName); // Replace PRODUCT_TYPE productType = mainRootElement.getChild("productInfo").getChildText("productType"); replaceAbstractedMetadataField(abstractedMetadata, "PRODUCT_TYPE", productType); // Replace SPH_DESCRIPTOR replaceAbstractedMetadataField(abstractedMetadata, "SPH_DESCRIPTOR", mainRootElement.getChild("generalHeader").getChildText("itemName")); // Replace mission replaceAbstractedMetadataField(abstractedMetadata, "MISSION", "TDM"); // Add the CoSSC metadata, i.e., the "main" annotation from the file with name "TDM... .xml" final MetadataElement cosscMetadataElem = new MetadataElement("CoSSC_Metadata"); AbstractMetadataIO.AddXMLMetadata(mainRootElement, cosscMetadataElem); metadataRoot.addElement(cosscMetadataElem); // Turn on the bi-static flag abstractedMetadata.setAttributeInt("bistatic_stack", 1); // Add the slave metadata metadataRoot.addElement(slaveRoot); return metadataRoot; } @Override protected MetadataElement addMetaData() throws IOException { if (getHeaderFileName().startsWith("TSX") || getHeaderFileName().startsWith("TDX")) { productName = TERRA_SAR_X; productType = TERRA_SAR_X; return super.addMetaData(); } else if (getHeaderFileName().startsWith("TDM")) { productName = TAN_DEM_X; productType = TAN_DEM_X; return addMetaDataForTanDemX(); } else { throw new IOException("Invalid header file: " + getHeaderFileName()); } } @Override protected void addAbstractedMetadataHeader(final MetadataElement root) throws IOException { final MetadataElement absRoot = AbstractMetadata.addAbstractedMetadataHeader(root); final MetadataElement origProdRoot = AbstractMetadata.addOriginalProductMetadata(root); final String defStr = AbstractMetadata.NO_METADATA_STRING; final int defInt = AbstractMetadata.NO_METADATA; final MetadataElement level1Elem = origProdRoot.getElementAt(0); final MetadataElement generalHeader = level1Elem.getElement("generalHeader"); final MetadataElement productInfo = level1Elem.getElement("productInfo"); final MetadataElement productSpecific = level1Elem.getElement("productSpecific"); final MetadataElement missionInfo = productInfo.getElement("missionInfo"); final MetadataElement productVariantInfo = productInfo.getElement("productVariantInfo"); final MetadataElement imageDataInfo = productInfo.getElement("imageDataInfo"); final MetadataElement sceneInfo = productInfo.getElement("sceneInfo"); final MetadataElement processing = level1Elem.getElement("processing"); final MetadataElement instrument = level1Elem.getElement("instrument"); final MetadataElement platform = level1Elem.getElement("platform"); final MetadataElement complexImageInfo = productSpecific.getElement("complexImageInfo"); final MetadataElement geocodedImageInfo = productSpecific.getElement("geocodedImageInfo"); MetadataAttribute attrib = generalHeader.getAttribute("fileName"); if (attrib != null) productName = attrib.getData().getElemString().replace("_____", "_").replace("__", "_"); if (productName.endsWith(".xml")) productName = productName.substring(0, productName.length() - 4); //mph AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PRODUCT, productName); productType = productVariantInfo.getAttributeString("productType", defStr).replace("_____", "_") .replace("__", "_"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PRODUCT_TYPE, productType); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.SPH_DESCRIPTOR, generalHeader.getAttributeString("itemName", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.MISSION, "TSX"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PROC_TIME, ReaderUtils.getTime(generalHeader, "generationTime", standardDateFormat)); MetadataElement elem = generalHeader.getElement("generationSystem"); if (elem != null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ProcessingSystemIdentifier, elem.getAttributeString("generationSystem", defStr)); } if (missionInfo != null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.CYCLE, missionInfo.getAttributeInt("orbitCycle", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.REL_ORBIT, missionInfo.getAttributeInt("relOrbit", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ABS_ORBIT, missionInfo.getAttributeInt("absOrbit", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PASS, missionInfo.getAttributeString("orbitDirection", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.SAMPLE_TYPE, imageDataInfo.getAttributeString("imageDataType", defStr)); } final MetadataElement acquisitionInfo = productInfo.getElement("acquisitionInfo"); if (acquisitionInfo != null) { final String imagingMode = getAcquisitionMode( acquisitionInfo.getAttributeString("imagingMode", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ACQUISITION_MODE, imagingMode); final String lookDirection = acquisitionInfo.getAttributeString("lookDirection", defStr); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.antenna_pointing, lookDirection); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.BEAMS, acquisitionInfo.getAttributeString("elevationBeamConfiguration", defStr)); productDescription = productType + ' ' + imagingMode; if (missionInfo == null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PASS, acquisitionInfo.getAttributeString("orbitDirection", defStr)); } } final MetadataElement polarisationList = acquisitionInfo.getElement("polarisationList"); final MetadataAttribute[] polList = polarisationList.getAttributes(); for (int i = 0; i < polList.length; ++i) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.polarTags[i], polList[i].getData().getElemString()); } final MetadataElement imageRaster = imageDataInfo.getElement("imageRaster"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_looks, imageRaster.getAttributeDouble("azimuthLooks", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_looks, imageRaster.getAttributeDouble("rangeLooks", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.num_samples_per_line, imageRaster.getAttributeInt("numberOfColumns", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.num_output_lines, imageRaster.getAttributeInt("numberOfRows", defInt)); if (sceneInfo != null) { setStartStopTime(absRoot, sceneInfo, imageRaster.getAttributeInt("numberOfRows", defInt)); getCornerCoords(sceneInfo, geocodedImageInfo); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.avg_scene_height, sceneInfo.getAttributeDouble("sceneAverageHeight", defInt)); } else if (acquisitionInfo != null) { setStartStopTime(absRoot, acquisitionInfo, imageRaster.getAttributeInt("numberOfRows", defInt)); } AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_near_lat, latCorners[0]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_near_long, lonCorners[0]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_far_lat, latCorners[1]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_far_long, lonCorners[1]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_near_lat, latCorners[2]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_near_long, lonCorners[2]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_far_lat, latCorners[3]); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_far_long, lonCorners[3]); // See Andrea's email dated Sept. 30, 2010 final String sampleType = absRoot.getAttributeString(AbstractMetadata.SAMPLE_TYPE); if (sampleType.contains("COMPLEX") && complexImageInfo != null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_spacing, complexImageInfo.getAttributeDouble("projectedSpacingAzimuth", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_spacing, complexImageInfo.getElement("projectedSpacingRange").getAttributeDouble("slantRange", defInt)); } else { final MetadataElement rowSpacing = imageDataInfo.getElement("imageRaster").getElement("rowSpacing"); final MetadataElement colSpacing = imageDataInfo.getElement("imageRaster").getElement("columnSpacing"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_spacing, rowSpacing.getAttributeDouble("rowSpacing", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_spacing, colSpacing.getAttributeDouble("columnSpacing", defInt)); } if (instrument != null) { final MetadataElement settings = instrument.getElement("settings"); final MetadataElement settingRecord = settings.getElement("settingRecord"); final MetadataElement PRF = settingRecord.getElement("PRF"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.pulse_repetition_frequency, PRF.getAttributeDouble("PRF", defInt)); final MetadataElement RSF = settings.getElement("RSF"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_sampling_rate, RSF.getAttributeDouble("RSF", defInt) / Constants.oneMillion); final MetadataElement radarParameters = instrument.getElement("radarParameters"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.radar_frequency, radarParameters.getAttributeDouble("centerFrequency", defInt) / Constants.oneMillion); } int srgr = 1; if (productVariantInfo.getAttributeString("projection", " ").equalsIgnoreCase("SLANTRANGE")) srgr = 0; AbstractMetadata.setAttribute(absRoot, AbstractMetadata.srgr_flag, srgr); final String mapProjection = productVariantInfo.getAttributeString("mapProjection", " ").trim(); if (!mapProjection.isEmpty()) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.map_projection, mapProjection); } AbstractMetadata.setAttribute(absRoot, AbstractMetadata.abs_calibration_flag, 0); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.coregistered_stack, 0); final MetadataElement processingFlags = processing.getElement("processingFlags"); if (processingFlags != null) { setFlag(processingFlags, "rangeSpreadingLossCorrectedFlag", "true", absRoot, AbstractMetadata.range_spread_comp_flag); setFlag(processingFlags, "elevationPatternCorrectedFlag", "true", absRoot, AbstractMetadata.ant_elev_corr_flag); } // add Range and Azimuth bandwidth final MetadataElement processingParameter = processing.getElement("processingParameter"); if (processingParameter != null) { final double rangeBW = processingParameter.getAttributeDouble("totalProcessedRangeBandwidth"); // Hz final double azimuthBW = processingParameter.getAttributeDouble("totalProcessedAzimuthBandwidth"); // Hz AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_bandwidth, rangeBW / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_bandwidth, azimuthBW); } AbstractMetadata.setAttribute(absRoot, AbstractMetadata.slant_range_to_first_pixel, (Math.min(slantRangeCorners[0], slantRangeCorners[2]) / Constants.oneBillion) * Constants.halfLightSpeed); // Note: Here we use the minimum of the slant range times of two corners because the original way cause // problem for stripmap product when the two slant range times are different. final MetadataElement calibration = level1Elem.getElement("calibration"); if (calibration != null) { final MetadataElement calibrationConstant = calibration.getElement("calibrationConstant"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.calibration_factor, calibrationConstant.getAttributeDouble("calFactor", defInt)); } if (platform != null) { final MetadataElement orbit = platform.getElement("orbit"); addOrbitStateVectors(absRoot, orbit); addSRGRCoefficients(absRoot, productSpecific, productInfo); } final MetadataElement doppler = processing.getElement("doppler"); if (doppler != null) { final MetadataElement dopplerCentroid = doppler.getElement("dopplerCentroid"); addDopplerCentroidCoefficients(absRoot, dopplerCentroid); } // handle ATI products by copying abs metadata to slv metadata final String antennaReceiveConfiguration = acquisitionInfo.getAttributeString("antennaReceiveConfiguration", ""); if (antennaReceiveConfiguration.equals("DRA")) { final MetadataElement targetSlaveMetadataRoot = AbstractMetadata.getSlaveMetadata(root); // copy Abstracted Metadata for (File cosFile : cosarFileList) { final String fileName = cosFile.getName().toUpperCase(); if (fileName.contains("_SRA_")) continue; AbstractMetadata.setAttribute(absRoot, AbstractMetadata.coregistered_stack, 1); final MetadataElement targetSlaveMetadata = new MetadataElement(fileName); targetSlaveMetadataRoot.addElement(targetSlaveMetadata); ProductUtils.copyMetadata(absRoot, targetSlaveMetadata); } // modify abstracted metadata } } private void findImagedForTanDemX(final MetadataElement newRoot) throws IOException { String parentPath = masterProductName + "/" + getRelativePathToImageFolder(); findImages(parentPath, newRoot); numMasterBands = cosarFileList.size(); parentPath = slaveProductName + "/" + getRelativePathToImageFolder(); findImages(parentPath, newRoot); } @Override protected void findImages(final MetadataElement newRoot) throws IOException { if (getHeaderFileName().startsWith("TSX") || getHeaderFileName().startsWith("TDX")) { super.findImages(newRoot); } else if (getHeaderFileName().startsWith("TDM")) { findImagedForTanDemX(newRoot); } else { throw new IOException("Invalid header file: " + getHeaderFileName()); } } private static void setStartStopTime(final MetadataElement absRoot, final MetadataElement elem, final int height) { final ProductData.UTC startTime = ReaderUtils.getTime(elem.getElement("start"), "timeUTC", standardDateFormat); final ProductData.UTC stopTime = ReaderUtils.getTime(elem.getElement("stop"), "timeUTC", standardDateFormat); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_line_time, startTime); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_line_time, stopTime); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.line_time_interval, ReaderUtils.getLineTimeInterval(startTime, stopTime, height)); } private static String getAcquisitionMode(final String mode) { if (mode.equalsIgnoreCase("SM")) return "Stripmap"; else if (mode.equalsIgnoreCase("SL") || mode.equalsIgnoreCase("HS")) return "Spotlight"; else if (mode.equalsIgnoreCase("SC")) return "ScanSAR"; return " "; } private static void setFlag(MetadataElement elem, String attribTag, String trueValue, MetadataElement absRoot, String absTag) { int val = 0; if (elem.getAttributeString(attribTag, " ").equalsIgnoreCase(trueValue)) val = 1; AbstractMetadata.setAttribute(absRoot, absTag, val); } private void getCornerCoords(MetadataElement sceneInfo, MetadataElement geocodedImageInfo) { int maxRow = 0, maxCol = 0; int minRow = Integer.MAX_VALUE, minCol = Integer.MAX_VALUE; final List<CornerCoord> coordList = new ArrayList<>(); final MetadataElement[] children = sceneInfo.getElements(); for (MetadataElement child : children) { if (child.getName().equals("sceneCornerCoord")) { final int refRow = child.getAttributeInt("refRow", 0); final int refCol = child.getAttributeInt("refColumn", 0); coordList.add(new CornerCoord(refRow, refCol, child.getAttributeDouble("lat", 0), child.getAttributeDouble("lon", 0), child.getAttributeDouble("rangeTime", 0) * Constants.oneBillion, child.getAttributeDouble("incidenceAngle", 0))); if (refRow > maxRow) maxRow = refRow; if (refCol > maxCol) maxCol = refCol; if (refRow < minRow) minRow = refRow; if (refCol < minCol) minCol = refCol; } } final int[] indexArray = { 0, 1, 2, 3 }; if (minRow == maxRow && minCol == maxCol && geocodedImageInfo != null) { final MetadataElement geoParameter = geocodedImageInfo.getElement("geoParameter"); final MetadataElement sceneCoordsGeographic = geoParameter.getElement("sceneCoordsGeographic"); final double latUL = sceneCoordsGeographic.getAttributeDouble("upperLeftLatitude", 0); final double latUR = sceneCoordsGeographic.getAttributeDouble("upperRightLatitude", 0); final double latLL = sceneCoordsGeographic.getAttributeDouble("lowerLeftLatitude", 0); final double latLR = sceneCoordsGeographic.getAttributeDouble("lowerRightLatitude", 0); final double lonUL = sceneCoordsGeographic.getAttributeDouble("upperLeftLongitude", 0); final double lonUR = sceneCoordsGeographic.getAttributeDouble("upperRightLongitude", 0); final double lonLL = sceneCoordsGeographic.getAttributeDouble("lowerLeftLongitude", 0); final double lonLR = sceneCoordsGeographic.getAttributeDouble("lowerRightLongitude", 0); int k = 0; double d0, d1, d2, d3; for (CornerCoord coord : coordList) { d0 = Math.abs(coord.lat - latUL) + Math.abs(coord.lon - lonUL); d1 = Math.abs(coord.lat - latUR) + Math.abs(coord.lon - lonUR); d2 = Math.abs(coord.lat - latLL) + Math.abs(coord.lon - lonLL); d3 = Math.abs(coord.lat - latLR) + Math.abs(coord.lon - lonLR); if (d0 <= d1 && d0 <= d2 && d0 <= d3) { indexArray[k] = 0; } else if (d1 <= d0 && d1 <= d2 && d1 <= d3) { indexArray[k] = 1; } else if (d2 <= d0 && d2 <= d1 && d2 <= d3) { indexArray[k] = 2; } else if (d3 <= d0 && d3 <= d1 && d3 <= d2) { indexArray[k] = 3; } k++; } } int index = 0; for (CornerCoord coord : coordList) { if (minRow == maxRow && minCol == maxCol) { latCorners[indexArray[index]] = coord.lat; lonCorners[indexArray[index]] = coord.lon; slantRangeCorners[indexArray[index]] = coord.rangeTime; incidenceCorners[indexArray[index]] = coord.incidenceAngle; ++index; } else { index = -1; if (coord.refRow == minRow) { if (Math.abs(coord.refCol - minCol) < Math.abs(coord.refCol - maxCol)) { // UL index = 0; } else { // UR index = 1; } } else if (coord.refRow == maxRow) { if (Math.abs(coord.refCol - minCol) < Math.abs(coord.refCol - maxCol)) { // LL index = 2; } else { // LR index = 3; } } if (index >= 0) { latCorners[index] = coord.lat; lonCorners[index] = coord.lon; slantRangeCorners[index] = coord.rangeTime; incidenceCorners[index] = coord.incidenceAngle; } } } } protected void addImageFile(final String imgPath, final MetadataElement newRoot) throws IOException { if (imgPath.toUpperCase().endsWith("COS")) { final File file = new File(getBaseDir(), imgPath); cosarFileList.add(file); setSLC(true); } else { final String name = getBandFileNameFromImage(imgPath); if ((name.endsWith("tif") || name.endsWith("tiff")) && name.startsWith("image")) { final Dimension bandDimensions = getBandDimensions(newRoot, name); final InputStream inStream = getInputStream(imgPath); final ImageInputStream imgStream = ImageIOFile.createImageInputStream(inStream, bandDimensions); if (imgStream == null) throw new IOException("Unable to open " + imgPath); final ImageIOFile img = new ImageIOFile(name, imgStream, ImageIOFile.getTiffIIOReader(imgStream), 1, 1, ProductData.TYPE_UINT16); bandImageFileMap.put(img.getName(), img); } } } @Override protected void addGeoCoding(final Product product) { File level1ProductDir = getBaseDir(); if (getHeaderFileName().startsWith("TDM")) { // Using the master product is important here. // The slave product is coregistered to the master without its geocoding being updated afterwards. // Its geocoding is unusable because of this. level1ProductDir = new File(getBaseDir(), masterProductName); } File georefFile = new File(level1ProductDir, "ANNOTATION" + File.separator + "GEOREF.xml"); if (georefFile.exists()) { try { readGeoRef(product, georefFile); return; } catch (Exception e) { // } } MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final String sampleType = absRoot.getAttributeString(AbstractMetadata.SAMPLE_TYPE); if (OperatorUtils.isMapProjected(product) || sampleType.contains("COMPLEX")) { ReaderUtils.addGeoCoding(product, latCorners, lonCorners); } else { final boolean isAscending = absRoot.getAttributeString(AbstractMetadata.PASS).equals("ASCENDING"); final double[] flippedLatCorners = new double[4]; final double[] flippedLonCorners = new double[4]; if (isAscending) { // flip up and down flippedLatCorners[0] = latCorners[2]; flippedLatCorners[1] = latCorners[3]; flippedLatCorners[2] = latCorners[0]; flippedLatCorners[3] = latCorners[1]; flippedLonCorners[0] = lonCorners[2]; flippedLonCorners[1] = lonCorners[3]; flippedLonCorners[2] = lonCorners[0]; flippedLonCorners[3] = lonCorners[1]; } else { // flip left and right flippedLatCorners[0] = latCorners[1]; flippedLatCorners[1] = latCorners[0]; flippedLatCorners[2] = latCorners[3]; flippedLatCorners[3] = latCorners[2]; flippedLonCorners[0] = lonCorners[1]; flippedLonCorners[1] = lonCorners[0]; flippedLonCorners[2] = lonCorners[3]; flippedLonCorners[3] = lonCorners[2]; } ReaderUtils.addGeoCoding(product, flippedLatCorners, flippedLonCorners); } } private static void readGeoRef(final Product product, final File georefFile) throws IOException { final Document xmlDoc = XMLSupport.LoadXML(georefFile.getAbsolutePath()); final Element root = xmlDoc.getRootElement(); final Element geoGrid = root.getChild("geolocationGrid"); final Element numGridPnt = geoGrid.getChild("numberOfGridPoints"); final Element numAzimuth = numGridPnt.getChild("azimuth"); final int numAz = Integer.parseInt(numAzimuth.getValue()); final Element numRange = numGridPnt.getChild("range"); final int numRg = Integer.parseInt(numRange.getValue()); final Element gridReferenceTime = geoGrid.getChild("gridReferenceTime"); final Element tReferenceTimeUTC = gridReferenceTime.getChild("tReferenceTimeUTC"); final int size = numAz * numRg; final double[] latList = new double[size]; final double[] lonList = new double[size]; final double[] incList = new double[size]; final double[] timeList = new double[size]; final int[] row = new int[size]; final int[] col = new int[size]; //final boolean flip = !isSLC(); int i = 0; int r = numRg - 1; int c = 0; boolean regridNeeded = false; final List<Element> grdPntList = geoGrid.getChildren("gridPoint"); for (Element pnt : grdPntList) { int index = i; /* if(flip) { index = (numRg * c) + r; --r; if(r < 0) { r = numRg-1; ++c; } } */ final Element tElem = pnt.getChild("tau"); timeList[index] = Double.parseDouble(tElem.getValue()); final Element latElem = pnt.getChild("lat"); latList[index] = Double.parseDouble(latElem.getValue()); final Element lonElem = pnt.getChild("lon"); lonList[index] = Double.parseDouble(lonElem.getValue()); final Element rowElem = pnt.getChild("row"); if (rowElem != null) { row[index] = Integer.parseInt(rowElem.getValue()) - 1; regridNeeded = true; } final Element colElem = pnt.getChild("col"); if (colElem != null) { col[index] = Integer.parseInt(colElem.getValue()) - 1; } final Element incElem = pnt.getChild("inc"); incList[index] = Double.parseDouble(incElem.getValue()); ++i; } final int gridWidth = numRg; final int gridHeight = numAz; final int newGridWidth = gridWidth; final int newGridHeight = gridHeight; float[] newLatList = new float[newGridWidth * newGridHeight]; float[] newLonList = new float[newGridWidth * newGridHeight]; float[] newIncList = new float[newGridWidth * newGridHeight]; final int sceneRasterWidth = product.getSceneRasterWidth(); final int sceneRasterHeight = product.getSceneRasterHeight(); final double subSamplingX = sceneRasterWidth / (double) (newGridWidth - 1); final double subSamplingY = sceneRasterHeight / (double) (newGridHeight - 1); if (regridNeeded) { getListInEvenlySpacedGrid(sceneRasterWidth, sceneRasterHeight, gridWidth, gridHeight, col, row, latList, newGridWidth, newGridHeight, subSamplingX, subSamplingY, newLatList); getListInEvenlySpacedGrid(sceneRasterWidth, sceneRasterHeight, gridWidth, gridHeight, col, row, lonList, newGridWidth, newGridHeight, subSamplingX, subSamplingY, newLonList); getListInEvenlySpacedGrid(sceneRasterWidth, sceneRasterHeight, gridWidth, gridHeight, col, row, incList, newGridWidth, newGridHeight, subSamplingX, subSamplingY, newIncList); } else { for (int m = 0; m < newLatList.length; ++m) { newLatList[m] = (float) latList[m]; newLonList[m] = (float) lonList[m]; newIncList[m] = (float) incList[m]; } } final TiePointGrid latGrid = new TiePointGrid(OperatorUtils.TPG_LATITUDE, newGridWidth, newGridHeight, 0.5f, 0.5f, subSamplingX, subSamplingY, newLatList); latGrid.setUnit(Unit.DEGREES); product.addTiePointGrid(latGrid); final TiePointGrid lonGrid = new TiePointGrid(OperatorUtils.TPG_LONGITUDE, newGridWidth, newGridHeight, 0.5f, 0.5f, subSamplingX, subSamplingY, newLonList, TiePointGrid.DISCONT_AT_180); lonGrid.setUnit(Unit.DEGREES); product.addTiePointGrid(lonGrid); final TiePointGrid incidentAngleGrid = new TiePointGrid(OperatorUtils.TPG_INCIDENT_ANGLE, newGridWidth, newGridHeight, 0.5f, 0.5f, subSamplingX, subSamplingY, newIncList); incidentAngleGrid.setUnit(Unit.DEGREES); product.addTiePointGrid(incidentAngleGrid); final TiePointGeoCoding tpGeoCoding = new TiePointGeoCoding(latGrid, lonGrid); product.setSceneGeoCoding(tpGeoCoding); // final TiePointGrid timeGrid = new TiePointGrid("Time", gridWidth, gridHeight, 0, 0, // subSamplingX, subSamplingY, timeList); // timeGrid.setUnit(Unit.NANOSECONDS); // product.addTiePointGrid(timeGrid); } private static void getListInEvenlySpacedGrid(final int sceneRasterWidth, final int sceneRasterHeight, final int sourceGridWidth, final int sourceGridHeight, final int[] x, final int[] y, final double[] sourcePointList, final int targetGridWidth, final int targetGridHeight, final double subSamplingX, final double subSamplingY, final float[] targetPointList) { if (sourcePointList.length != sourceGridWidth * sourceGridHeight) { throw new IllegalArgumentException( "Original tie point array size does not match 'sourceGridWidth' x 'sourceGridHeight'"); } if (targetPointList.length != targetGridWidth * targetGridHeight) { throw new IllegalArgumentException( "Target tie point array size does not match 'targetGridWidth' x 'targetGridHeight'"); } int k = 0; for (int r = 0; r < targetGridHeight; r++) { double newY = r * subSamplingY; if (newY > sceneRasterHeight - 1) { newY = sceneRasterHeight - 1; } double oldY0 = 0, oldY1 = 0; int j0 = 0, j1 = 0; for (int rr = 1; rr < sourceGridHeight; rr++) { j0 = rr - 1; j1 = rr; oldY0 = y[j0 * sourceGridWidth]; oldY1 = y[j1 * sourceGridWidth]; if (oldY1 > newY) { break; } } final double wj = (newY - oldY0) / (oldY1 - oldY0); for (int c = 0; c < targetGridWidth; c++) { double newX = c * subSamplingX; if (newX > sceneRasterWidth - 1) { newX = sceneRasterWidth - 1; } double oldX0 = 0, oldX1 = 0; int i0 = 0, i1 = 0; for (int cc = 1; cc < sourceGridWidth; cc++) { i0 = cc - 1; i1 = cc; oldX0 = x[i0]; oldX1 = x[i1]; if (oldX1 > newX) { break; } } final double wi = (newX - oldX0) / (oldX1 - oldX0); targetPointList[k++] = (float) MathUtils.interpolate2D(wi, wj, sourcePointList[i0 + j0 * sourceGridWidth], sourcePointList[i1 + j0 * sourceGridWidth], sourcePointList[i0 + j1 * sourceGridWidth], sourcePointList[i1 + j1 * sourceGridWidth]); } } } @Override protected void addTiePointGrids(final Product product) { final int gridWidth = 4; final int gridHeight = 4; final double subSamplingX = (double) product.getSceneRasterWidth() / (gridWidth - 1); final double subSamplingY = (double) product.getSceneRasterHeight() / (gridHeight - 1); if (subSamplingX == 0 || subSamplingY == 0) return; final float[] flippedSlantRangeCorners = new float[4]; final float[] flippedIncidenceCorners = new float[4]; getFlippedCorners(product, flippedSlantRangeCorners, flippedIncidenceCorners); if (product.getTiePointGrid(OperatorUtils.TPG_INCIDENT_ANGLE) == null) { final float[] fineAngles = new float[gridWidth * gridHeight]; ReaderUtils.createFineTiePointGrid(2, 2, gridWidth, gridHeight, flippedIncidenceCorners, fineAngles); final TiePointGrid incidentAngleGrid = new TiePointGrid(OperatorUtils.TPG_INCIDENT_ANGLE, gridWidth, gridHeight, 0, 0, subSamplingX, subSamplingY, fineAngles); incidentAngleGrid.setUnit(Unit.DEGREES); product.addTiePointGrid(incidentAngleGrid); } final float[] fineSlantRange = new float[gridWidth * gridHeight]; ReaderUtils.createFineTiePointGrid(2, 2, gridWidth, gridHeight, flippedSlantRangeCorners, fineSlantRange); final TiePointGrid slantRangeGrid = new TiePointGrid(OperatorUtils.TPG_SLANT_RANGE_TIME, gridWidth, gridHeight, 0, 0, subSamplingX, subSamplingY, fineSlantRange); slantRangeGrid.setUnit(Unit.NANOSECONDS); product.addTiePointGrid(slantRangeGrid); } private void getFlippedCorners(Product product, final float[] flippedSlantRangeCorners, final float[] flippedIncidenceCorners) { MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final String sampleType = absRoot.getAttributeString(AbstractMetadata.SAMPLE_TYPE); if (OperatorUtils.isMapProjected(product) || sampleType.contains("COMPLEX")) { flippedSlantRangeCorners[0] = (float) slantRangeCorners[0]; flippedSlantRangeCorners[1] = (float) slantRangeCorners[1]; flippedSlantRangeCorners[2] = (float) slantRangeCorners[2]; flippedSlantRangeCorners[3] = (float) slantRangeCorners[3]; flippedIncidenceCorners[0] = (float) incidenceCorners[0]; flippedIncidenceCorners[1] = (float) incidenceCorners[1]; flippedIncidenceCorners[2] = (float) incidenceCorners[2]; flippedIncidenceCorners[3] = (float) incidenceCorners[3]; } else { final boolean isAscending = absRoot.getAttributeString(AbstractMetadata.PASS).equals("ASCENDING"); if (isAscending) { // flip up and down flippedSlantRangeCorners[0] = (float) slantRangeCorners[2]; flippedSlantRangeCorners[1] = (float) slantRangeCorners[3]; flippedSlantRangeCorners[2] = (float) slantRangeCorners[0]; flippedSlantRangeCorners[3] = (float) slantRangeCorners[1]; flippedIncidenceCorners[0] = (float) incidenceCorners[2]; flippedIncidenceCorners[1] = (float) incidenceCorners[3]; flippedIncidenceCorners[2] = (float) incidenceCorners[0]; flippedIncidenceCorners[3] = (float) incidenceCorners[1]; } else { // flip left and right flippedSlantRangeCorners[0] = (float) slantRangeCorners[1]; flippedSlantRangeCorners[1] = (float) slantRangeCorners[0]; flippedSlantRangeCorners[2] = (float) slantRangeCorners[3]; flippedSlantRangeCorners[3] = (float) slantRangeCorners[2]; flippedIncidenceCorners[0] = (float) incidenceCorners[1]; flippedIncidenceCorners[1] = (float) incidenceCorners[0]; flippedIncidenceCorners[2] = (float) incidenceCorners[3]; flippedIncidenceCorners[3] = (float) incidenceCorners[2]; } } } private boolean isBelongToCoSSC() { // This checks if the product is in fact part of a CoSSC product by checking if the parent // directory contains a file that starts with "TDM" and ends in "xml". // This handles the case where the user just opens one of the two SSC products inside a CoSSC // product. final String[] fileList = getBaseDir().getParentFile().list(); for (String s : fileList) { if (s.startsWith("TDM") && s.endsWith("xml")) { return true; } } return false; } private String appendIfMatch(final Band band, final String key, String bands) { if (band.getName().contains(key)) { bands = bands + band.getName() + " "; } return bands; } @Override protected void addBands(final Product product) { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final int width = absRoot.getAttributeInt(AbstractMetadata.num_samples_per_line); final int height = absRoot.getAttributeInt(AbstractMetadata.num_output_lines); final Set<String> ImageKeys = bandImageFileMap.keySet(); // The set of keys in the map. for (String key : ImageKeys) { final ImageIOFile img = bandImageFileMap.get(key); for (int i = 0; i < img.getNumImages(); ++i) { for (int b = 0; b < img.getNumBands(); ++b) { final String pol = SARReader.findPolarizationInBandName(img.getName()); final Band band = new Band("Amplitude_" + pol, img.getDataType(), width, height); band.setUnit(Unit.AMPLITUDE); product.addBand(band); SARReader.createVirtualIntensityBand(product, band, '_' + pol); bandMap.put(band, new ImageIOFile.BandInfo(band, img, i, b)); } } } if (!cosarFileList.isEmpty()) { String masterBands = ""; String slaveBands = ""; final boolean polsUnique = arePolarizationsUnique(); String extraInfo = ""; // if pols not unique add the extra info final String mission = absRoot.getAttributeString("MISSION"); for (int i = 0; i < cosarFileList.size(); i++) { final File file = cosarFileList.get(i); final String fileName = file.getName().toUpperCase(); final String pol = SARReader.findPolarizationInBandName(fileName); if (mission.contains("TDM")) { final String level1ProductDirName = file.getParentFile().getParentFile().getName(); if (level1ProductDirName.equals(masterProductName)) { extraInfo = "_mst"; } else if (level1ProductDirName.equals(slaveProductName)) { extraInfo = "_slv1"; } extraInfo += StackUtils.createBandTimeStamp(product); } else if (!polsUnique) { final int polIndex = fileName.indexOf(pol); extraInfo = fileName.substring(polIndex + 2, fileName.indexOf(".", polIndex + 3)); } final int bandDataType = (mission.contains("TDM") || isBelongToCoSSC()) ? ProductData.TYPE_FLOAT32 : ProductData.TYPE_INT16; //System.out.println("TerraSarXProductDirectory.addBands: band data type = " + ProductData.getTypeString(bandDataType)); final Band realBand = new Band("i_" + pol + extraInfo, bandDataType, width, height); realBand.setUnit(Unit.REAL); product.addBand(realBand); masterBands = appendIfMatch(realBand, "mst", masterBands); slaveBands = appendIfMatch(realBand, "slv", slaveBands); final Band imaginaryBand = new Band("q_" + pol + extraInfo, bandDataType, width, height); imaginaryBand.setUnit(Unit.IMAGINARY); product.addBand(imaginaryBand); masterBands = appendIfMatch(imaginaryBand, "mst", masterBands); slaveBands = appendIfMatch(imaginaryBand, "slv", slaveBands); ReaderUtils.createVirtualIntensityBand(product, realBand, imaginaryBand, ""); try { cosarBandMap.put(realBand.getName(), FileImageInputStreamExtImpl.createInputStream(file)); cosarBandMap.put(imaginaryBand.getName(), FileImageInputStreamExtImpl.createInputStream(file)); } catch (Exception e) { // } } if (mission.contains("TDM")) { final MetadataElement slaveMetadata = absRoot.getParentElement().getElement("Slave_Metadata"); slaveMetadata.setAttributeString("Master_bands", masterBands); final MetadataElement slaveProduct = slaveMetadata.getElement(slaveProductName); final MetadataAttribute slaveBandsAttr = new MetadataAttribute("Slave_bands", ProductData.TYPE_ASCII); slaveProduct.addAttribute(slaveBandsAttr); slaveProduct.setAttributeString(slaveBandsAttr.getName(), slaveBands); } } absRoot.setAttributeInt(AbstractMetadata.num_samples_per_line, width); absRoot.setAttributeInt(AbstractMetadata.num_output_lines, height); } private boolean arePolarizationsUnique() { final List<String> pols = new ArrayList<>(); for (final File file : cosarFileList) { pols.add(SARReader.findPolarizationInBandName(file.getName())); } for (int i = 0; i < pols.size(); ++i) { for (int j = i + 1; j < pols.size(); ++j) { if (pols.get(i).equals(pols.get(j))) return false; } } return true; } private static void addOrbitStateVectors(MetadataElement absRoot, MetadataElement orbitInformation) { final MetadataElement orbitVectorListElem = absRoot.getElement(AbstractMetadata.orbit_state_vectors); final MetadataElement[] stateVectorElems = orbitInformation.getElements(); for (int i = 1; i < stateVectorElems.length; ++i) { // first stateVectorElem is orbitHeader therefore skip it addVector(AbstractMetadata.orbit_vector, orbitVectorListElem, stateVectorElems[i], i); } // set state vector time if (absRoot.getAttributeUTC(AbstractMetadata.STATE_VECTOR_TIME, AbstractMetadata.NO_METADATA_UTC) .equalElems(AbstractMetadata.NO_METADATA_UTC)) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.STATE_VECTOR_TIME, ReaderUtils.getTime(stateVectorElems[1], "timeUTC", standardDateFormat)); } } private static void addVector(String name, MetadataElement orbitVectorListElem, MetadataElement srcElem, int num) { final MetadataElement orbitVectorElem = new MetadataElement(name + num); orbitVectorElem.setAttributeUTC(AbstractMetadata.orbit_vector_time, ReaderUtils.getTime(srcElem, "timeUTC", standardDateFormat)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_x_pos, srcElem.getAttributeDouble("posX", 0)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_y_pos, srcElem.getAttributeDouble("posY", 0)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_z_pos, srcElem.getAttributeDouble("posZ", 0)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_x_vel, srcElem.getAttributeDouble("velX", 0)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_y_vel, srcElem.getAttributeDouble("velY", 0)); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_z_vel, srcElem.getAttributeDouble("velZ", 0)); orbitVectorListElem.addElement(orbitVectorElem); } private static void addSRGRCoefficients(final MetadataElement absRoot, final MetadataElement productSpecific, final MetadataElement productInfo) { // get swath begin time and swath end time final MetadataElement sceneInfo = productInfo.getElement("sceneInfo"); if (sceneInfo == null) { return; } final MetadataElement rangeTime = sceneInfo.getElement("rangeTime"); if (rangeTime == null) { return; } final double firstPixelTime = rangeTime.getAttributeDouble("firstPixel"); final double lastPixelTime = rangeTime.getAttributeDouble("lastPixel"); // get slant range time to ground rang conversion coefficients final MetadataElement projectedImageInfo = productSpecific.getElement("projectedImageInfo"); if (projectedImageInfo == null) { return; } final MetadataElement slantToGroundRangeProjection = projectedImageInfo .getElement("slantToGroundRangeProjection"); if (slantToGroundRangeProjection == null) { return; } // final double validityRangeMin = slantToGroundRangeProjection.getAttributeDouble("validityRangeMin"); // final double validityRangeMax = slantToGroundRangeProjection.getAttributeDouble("validityRangeMax"); final double referencePoint = slantToGroundRangeProjection.getAttributeDouble("referencePoint"); final int polynomialDegree = slantToGroundRangeProjection.getAttributeInt("polynomialDegree"); final double[] s2gCoef = new double[polynomialDegree + 1]; int cnt = 0; for (MetadataElement elem : slantToGroundRangeProjection.getElements()) { s2gCoef[cnt++] = elem.getAttributeDouble("coefficient", 0); } // compute ground range to slant range conversion coefficients final int m = 11; // order of ground to slant polynomial double[] sltRgTime = new double[m + 1]; double[] groundRange = new double[m + 1]; for (int i = 0; i <= m; i++) { sltRgTime[i] = firstPixelTime + (lastPixelTime - firstPixelTime) * i / m; groundRange[i] = Maths.computePolynomialValue(sltRgTime[i] - referencePoint, s2gCoef); } // final double groundRangeRef = (groundRange[0] + groundRange[m]) / 2; final double groundRangeRef = 0.0; // set ground range ref to 0 because when g2sCoef are used in computing // slant range from ground range, the ground range origin is assumed to be 0 final double[] deltaGroundRange = new double[m + 1]; final double deltaMax = groundRange[m] - groundRangeRef; for (int i = 0; i <= m; i++) { deltaGroundRange[i] = (groundRange[i] - groundRangeRef) / deltaMax; } final Matrix G = Maths.createVandermondeMatrix(deltaGroundRange, m); final Matrix tau = new Matrix(sltRgTime, m + 1); final Matrix s = G.solve(tau); final double[] g2sCoef = s.getColumnPackedCopy(); double tmp = 1; for (int i = 0; i <= m; i++) { g2sCoef[i] *= Constants.halfLightSpeed / tmp; tmp *= deltaMax; } // save ground range to slant range conversion coefficients in abstract metadata final MetadataElement srgrCoefficientsElem = absRoot.getElement(AbstractMetadata.srgr_coefficients); final MetadataElement srgrListElem = new MetadataElement(AbstractMetadata.srgr_coef_list); srgrCoefficientsElem.addElement(srgrListElem); final ProductData.UTC utcTime = absRoot.getAttributeUTC(AbstractMetadata.first_line_time, AbstractMetadata.NO_METADATA_UTC); srgrListElem.setAttributeUTC(AbstractMetadata.srgr_coef_time, utcTime); AbstractMetadata.addAbstractedAttribute(srgrListElem, AbstractMetadata.ground_range_origin, ProductData.TYPE_FLOAT64, "m", "Ground Range Origin"); AbstractMetadata.setAttribute(srgrListElem, AbstractMetadata.ground_range_origin, 0.0); for (int i = 0; i <= m; i++) { final MetadataElement coefElem = new MetadataElement(AbstractMetadata.coefficient + '.' + (i + 1)); srgrListElem.addElement(coefElem); AbstractMetadata.addAbstractedAttribute(coefElem, AbstractMetadata.srgr_coef, ProductData.TYPE_FLOAT64, "", "SRGR Coefficient"); AbstractMetadata.setAttribute(coefElem, AbstractMetadata.srgr_coef, g2sCoef[i]); } } private static void addDopplerCentroidCoefficients(final MetadataElement absRoot, final MetadataElement dopplerCentroid) { final MetadataElement[] dopplerElems = dopplerCentroid.getElements(); final MetadataElement dopplerCentroidCoefficientsElem = absRoot .getElement(AbstractMetadata.dop_coefficients); int listCnt = 1; for (MetadataElement dopplerEstimate : dopplerElems) { if (dopplerEstimate.getName().equalsIgnoreCase("dopplerEstimate")) { final MetadataElement dopplerListElem = new MetadataElement( AbstractMetadata.dop_coef_list + '.' + listCnt); dopplerCentroidCoefficientsElem.addElement(dopplerListElem); ++listCnt; final ProductData.UTC utcTime = ReaderUtils.getTime(dopplerEstimate, "timeUTC", standardDateFormat); dopplerListElem.setAttributeUTC(AbstractMetadata.dop_coef_time, utcTime); final MetadataElement combinedDoppler = dopplerEstimate.getElement("combinedDoppler"); final MetadataElement[] coefficients = combinedDoppler.getElements(); /*final double refTime = elem.getElement("dopplerCentroidReferenceTime"). getAttributeDouble("dopplerCentroidReferenceTime", 0)*1e9; // s to ns AbstractMetadata.addAbstractedAttribute(dopplerListElem, AbstractMetadata.slant_range_time, ProductData.TYPE_FLOAT64, "ns", "Slant Range Time"); AbstractMetadata.setAttribute(dopplerListElem, AbstractMetadata.slant_range_time, refTime); */ int cnt = 1; for (MetadataElement coefficient : coefficients) { final double coefValue = coefficient.getAttributeDouble("coefficient", 0); final MetadataElement coefElem = new MetadataElement(AbstractMetadata.coefficient + '.' + cnt); dopplerListElem.addElement(coefElem); ++cnt; AbstractMetadata.addAbstractedAttribute(coefElem, AbstractMetadata.dop_coef, ProductData.TYPE_FLOAT64, "", "Doppler Centroid Coefficient"); AbstractMetadata.setAttribute(coefElem, AbstractMetadata.dop_coef, coefValue); } } } } ImageInputStream getCosarImageInputStream(final Band band) { return cosarBandMap.get(band.getName()); } @Override public void close() throws IOException { super.close(); final Set<String> keys = cosarBandMap.keySet(); // The set of keys in the map. for (String key : keys) { final ImageInputStream img = cosarBandMap.get(key); img.close(); } } @Override protected String getProductName() { return productName; } @Override protected String getProductDescription() { return productDescription; } @Override protected String getProductType() { return productType; } private static class CornerCoord { final int refRow, refCol; final double lat, lon; final double rangeTime, incidenceAngle; CornerCoord(int row, int col, double lt, double ln, double range, double angle) { refRow = row; refCol = col; lat = lt; lon = ln; rangeTime = range; incidenceAngle = angle; } } }