private void initGeoCodings(Document dom) {
   final GeoCoding[] geoCodings = DimapProductHelpers.createGeoCoding(dom, product);
   if (geoCodings != null) {
     if (geoCodings.length == 1) {
       product.setGeoCoding(geoCodings[0]);
     } else if (geoCodings.length == product.getNumBands()) {
       for (int i = 0; i < geoCodings.length; i++) {
         final Band band = product.getBandAt(i);
         if (product.getSceneRasterWidth() == band.getRasterWidth()
             && product.getSceneRasterHeight() == band.getRasterHeight()) {
           product.setGeoCoding(geoCodings[i]);
         }
         band.setGeoCoding(geoCodings[i]);
       }
     }
   } else {
     final Band lonBand = product.getBand("longitude");
     final Band latBand = product.getBand("latitude");
     if (latBand != null && lonBand != null) {
       final GeoCoding geoCoding =
           GeoCodingFactory.createPixelGeoCoding(latBand, lonBand, null, 6);
       product.setGeoCoding(geoCoding);
     }
   }
 }
 private static void configureBand(
     Band band05X, ImageInfo imageInfo, String unit, String description) {
   band05X.setUnit(unit);
   band05X.setDescription(description);
   band05X.setImageInfo(imageInfo);
   band05X.setNoDataValue(Double.NaN);
   band05X.setNoDataValueUsed(true);
 }
 @Override
 public void undo() throws CannotUndoException {
   super.undo();
   for (Band displacementBand : displacementBands) {
     if (product.containsBand(displacementBand.getName())) {
       product.removeBand(displacementBand);
     }
   }
 }
  /**
   * The template method which is called by the {@link
   * org.esa.snap.framework.dataio.AbstractProductReader#readBandRasterDataImpl(int, int, int, int,
   * int, int, org.esa.snap.framework.datamodel.Band, int, int, int, int,
   * org.esa.snap.framework.datamodel.ProductData, com.bc.ceres.core.ProgressMonitor)} } method
   * after an optional spatial subset has been applied to the input parameters.
   *
   * <p>The destination band, buffer and region parameters are exactly the ones passed to the
   * original {@link org.esa.snap.framework.dataio.AbstractProductReader#readBandRasterDataImpl}
   * call. Since the <code>destOffsetX</code> and <code>destOffsetY</code> parameters are already
   * taken into acount in the <code>sourceOffsetX</code> and <code>sourceOffsetY</code> parameters,
   * an implementor of this method is free to ignore them.
   *
   * @param sourceOffsetX the absolute X-offset in source raster co-ordinates
   * @param sourceOffsetY the absolute Y-offset in source raster co-ordinates
   * @param sourceWidth the width of region providing samples to be read given in source raster
   *     co-ordinates
   * @param sourceHeight the height of region providing samples to be read given in source raster
   *     co-ordinates
   * @param sourceStepX the sub-sampling in X direction within the region providing samples to be
   *     read
   * @param sourceStepY the sub-sampling in Y direction within the region providing samples to be
   *     read
   * @param destBand the destination band which identifies the data source from which to read the
   *     sample values
   * @param destBuffer the destination buffer which receives the sample values to be read
   * @param destOffsetX the X-offset in the band's raster co-ordinates
   * @param destOffsetY the Y-offset in the band's raster co-ordinates
   * @param destWidth the width of region to be read given in the band's raster co-ordinates
   * @param destHeight the height of region to be read given in the band's raster co-ordinates
   * @param pm a monitor to inform the user about progress
   * @throws java.io.IOException if an I/O error occurs
   * @see #getSubsetDef
   */
  @Override
  protected void readBandRasterDataImpl(
      int sourceOffsetX,
      int sourceOffsetY,
      int sourceWidth,
      int sourceHeight,
      int sourceStepX,
      int sourceStepY,
      Band destBand,
      int destOffsetX,
      int destOffsetY,
      int destWidth,
      int destHeight,
      ProductData destBuffer,
      ProgressMonitor pm)
      throws IOException {
    final int sourceMinX = sourceOffsetX;
    final int sourceMinY = sourceOffsetY;
    final int sourceMaxX = sourceOffsetX + sourceWidth - 1;
    final int sourceMaxY = sourceOffsetY + sourceHeight - 1;

    final File dataFile = bandDataFiles.get(destBand);
    final ImageInputStream inputStream = getOrCreateImageInputStream(destBand, dataFile);
    if (inputStream == null) {
      return;
    }

    int destPos = 0;

    pm.beginTask("Reading band '" + destBand.getName() + "'...", sourceMaxY - sourceMinY);
    // For each scan in the data source
    try {
      synchronized (inputStream) {
        for (int sourceY = sourceMinY; sourceY <= sourceMaxY; sourceY += sourceStepY) {
          if (pm.isCanceled()) {
            break;
          }
          final long sourcePosY = (long) sourceY * destBand.getRasterWidth();
          if (sourceStepX == 1) {
            long inputPos = sourcePosY + sourceMinX;
            destBuffer.readFrom(destPos, destWidth, inputStream, inputPos);
            destPos += destWidth;
          } else {
            for (int sourceX = sourceMinX; sourceX <= sourceMaxX; sourceX += sourceStepX) {
              long inputPos = sourcePosY + sourceX;
              destBuffer.readFrom(destPos, 1, inputStream, inputPos);
              destPos++;
            }
          }
        }
        pm.worked(1);
      }
    } finally {
      pm.done();
    }
  }
 @Override
 public void redo() throws CannotRedoException {
   super.redo();
   for (Band displacementBand : displacementBands) {
     if (!product.containsBand(displacementBand.getName())) {
       product.addBand(displacementBand);
       product.fireProductNodeChanged(displacementBand.getName());
     }
   }
 }
 @Override
 public void preEncode(ProfileWriteContext ctx, Product p) throws IOException {
   NFileWriteable writeable = ctx.getNetcdfFileWriteable();
   for (Band band : p.getBands()) {
     IndexCoding indexCoding = band.getIndexCoding();
     if (indexCoding != null) {
       String variableName = ReaderUtils.getVariableName(band);
       NVariable variable = writeable.findVariable(variableName);
       writeIndexCoding(indexCoding, variable);
     }
   }
 }
 @Override
 public void decode(ProfileReadContext ctx, Product p) throws IOException {
   final Band[] bands = p.getBands();
   for (Band band : bands) {
     String variableName = ReaderUtils.getVariableName(band);
     final Variable variable = ctx.getNetcdfFile().getRootGroup().findVariable(variableName);
     final IndexCoding indexCoding = readIndexCoding(variable, band.getName() + "_index_coding");
     if (indexCoding != null) {
       p.getIndexCodingGroup().add(indexCoding);
       band.setSampleCoding(indexCoding);
     }
   }
 }
  public void removeFactorsForCurrentTile(Band targetBand, Tile targetTile, String srcBandName)
      throws OperatorException {

    Band sourceBand = sourceProduct.getBand(targetBand.getName());
    Tile sourceTile = calibrationOp.getSourceTile(sourceBand, targetTile.getRectangle());
    targetTile.setRawSamples(sourceTile.getRawSamples());
  }
 private ImageInputStream getOrCreateImageInputStream(Band band, File file) throws IOException {
   ImageInputStream inputStream = getImageInputStream(band);
   if (inputStream == null) {
     try {
       inputStream = new FileImageInputStream(file);
     } catch (IOException e) {
       SystemUtils.LOG.log(
           Level.WARNING,
           "DimapProductReader: Unable to read file '"
               + file
               + "' referenced by '"
               + band.getName()
               + "'.",
           e);
     }
     if (inputStream == null) {
       return null;
     }
     if (bandInputStreams == null) {
       bandInputStreams = new Hashtable<Band, ImageInputStream>();
     }
     bandInputStreams.put(band, inputStream);
   }
   return inputStream;
 }
Beispiel #10
0
 public ProductNodeGroup<Placemark> getGcpGroup(final Band band) {
   ProductNodeGroup<Placemark> gcpGroup = bandGCPGroup.get(createKey(band));
   if (gcpGroup == null) {
     gcpGroup = new ProductNodeGroup<>(band.getProduct(), "ground_control_points", true);
     bandGCPGroup.put(createKey(band), gcpGroup);
   }
   return gcpGroup;
 }
 private void addBandsToProduct(TiffFileInfo tiffInfo, Product product) throws IOException {
   final ImageReadParam readParam = imageReader.getDefaultReadParam();
   TIFFRenderedImage baseImage =
       (TIFFRenderedImage) imageReader.readAsRenderedImage(FIRST_IMAGE, readParam);
   SampleModel sampleModel = baseImage.getSampleModel();
   final int numBands = sampleModel.getNumBands();
   final int productDataType = ImageManager.getProductDataType(sampleModel.getDataType());
   bandMap = new HashMap<>(numBands);
   for (int i = 0; i < numBands; i++) {
     final String bandName = String.format("band_%d", i + 1);
     final Band band = product.addBand(bandName, productDataType);
     if (tiffInfo.containsField(BaselineTIFFTagSet.TAG_COLOR_MAP)
         && baseImage.getColorModel() instanceof IndexColorModel) {
       band.setImageInfo(createIndexedImageInfo(product, baseImage, band));
     }
     bandMap.put(band, i);
   }
 }
 private static Product copyProduct(Product writtenProduct) {
   Product targetProduct =
       new Product(
           writtenProduct.getName(),
           writtenProduct.getProductType(),
           writtenProduct.getSceneRasterWidth(),
           writtenProduct.getSceneRasterHeight());
   targetProduct.setStartTime(writtenProduct.getStartTime());
   targetProduct.setEndTime(writtenProduct.getEndTime());
   ProductUtils.copyMetadata(writtenProduct, targetProduct);
   ProductUtils.copyGeoCoding(writtenProduct, targetProduct);
   ProductUtils.copyTiePointGrids(writtenProduct, targetProduct);
   ProductUtils.copyMasks(writtenProduct, targetProduct);
   ProductUtils.copyVectorData(writtenProduct, targetProduct);
   for (Band band : writtenProduct.getBands()) {
     // Force setting source image, otherwise GPF will set an OperatorImage and invoke
     // computeTile()!!
     ProductUtils.copyBand(band.getName(), writtenProduct, targetProduct, true);
   }
   return targetProduct;
 }
 private void bindBandsToFiles(Document dom) {
   bandDataFiles = DimapProductHelpers.getBandDataFiles(dom, product, getInputDir());
   final Band[] bands = product.getBands();
   for (final Band band : bands) {
     if (band instanceof VirtualBand || band instanceof FilterBand) {
       continue;
     }
     final File dataFile = bandDataFiles.get(band);
     if (dataFile == null || !dataFile.canRead()) {
       SystemUtils.LOG.warning(
           "DimapProductReader: Unable to read file '"
               + dataFile
               + "' referenced by '"
               + band.getName()
               + "'.");
       SystemUtils.LOG.warning(
           "DimapProductReader: Removed band '"
               + band.getName()
               + "' from product '"
               + product.getFileLocation()
               + "'.");
     }
   }
 }
  private static ImageInfo createIndexedImageInfo(
      Product product, TIFFRenderedImage baseImage, Band band) {
    final IndexColorModel colorModel = (IndexColorModel) baseImage.getColorModel();
    final IndexCoding indexCoding = new IndexCoding("color_map");
    final int colorCount = colorModel.getMapSize();
    final ColorPaletteDef.Point[] points = new ColorPaletteDef.Point[colorCount];
    for (int j = 0; j < colorCount; j++) {
      final String name = String.format("I%3d", j);
      indexCoding.addIndex(name, j, "");
      points[j] = new ColorPaletteDef.Point(j, new Color(colorModel.getRGB(j)), name);
    }
    product.getIndexCodingGroup().add(indexCoding);
    band.setSampleCoding(indexCoding);

    return new ImageInfo(new ColorPaletteDef(points, points.length));
  }
  @Override
  protected void addBands(final Product product) {

    String bandName;
    boolean real = true;
    Band lastRealBand = null;
    String unit;

    final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product);
    for (Map.Entry<String, ImageIOFile> stringImageIOFileEntry : bandImageFileMap.entrySet()) {
      final ImageIOFile img = stringImageIOFileEntry.getValue();
      final String imgName = img.getName().toLowerCase();
      final MetadataElement bandMetadata = absRoot.getElement(imgBandMetadataMap.get(imgName));
      final String swath = bandMetadata.getAttributeString(AbstractMetadata.swath);
      final String pol = bandMetadata.getAttributeString(AbstractMetadata.polarization);
      final int width = bandMetadata.getAttributeInt(AbstractMetadata.num_samples_per_line);
      final int height = bandMetadata.getAttributeInt(AbstractMetadata.num_output_lines);

      String tpgPrefix = "";
      String suffix = pol;
      if (isSLC() && isTOPSAR()) {
        suffix = swath + '_' + pol;
        tpgPrefix = swath;
      }

      int numImages = img.getNumImages();
      if (isSLC()) {
        numImages *= 2; // real + imaginary
      }
      for (int i = 0; i < numImages; ++i) {

        if (isSLC()) {
          for (int b = 0; b < img.getNumBands(); ++b) {
            if (real) {
              bandName = "i" + '_' + suffix;
              unit = Unit.REAL;
            } else {
              bandName = "q" + '_' + suffix;
              unit = Unit.IMAGINARY;
            }

            final Band band = new Band(bandName, ProductData.TYPE_INT16, width, height);
            band.setUnit(unit);

            product.addBand(band);
            bandMap.put(band, new ImageIOFile.BandInfo(band, img, i, b));
            AbstractMetadata.addBandToBandMap(bandMetadata, bandName);

            if (real) {
              lastRealBand = band;
            } else {
              ReaderUtils.createVirtualIntensityBand(product, lastRealBand, band, '_' + suffix);
            }
            real = !real;

            // add tiepointgrids and geocoding for band
            addTiePointGrids(band, imgName, tpgPrefix);

            // reset to null so it doesn't adopt a geocoding from the bands
            product.setGeoCoding(null);
          }
        } else {
          for (int b = 0; b < img.getNumBands(); ++b) {
            bandName = "Amplitude" + '_' + suffix;
            final Band band = new Band(bandName, ProductData.TYPE_INT32, width, height);
            band.setUnit(Unit.AMPLITUDE);

            product.addBand(band);
            bandMap.put(band, new ImageIOFile.BandInfo(band, img, i, b));
            AbstractMetadata.addBandToBandMap(bandMetadata, bandName);

            SARReader.createVirtualIntensityBand(product, band, '_' + suffix);

            // add tiepointgrids and geocoding for band
            addTiePointGrids(band, imgName, tpgPrefix);
          }
        }
      }
    }
  }
Beispiel #16
0
 private String createKey(final Band band) {
   return band.getProduct().getName() + '_' + band.getName();
 }
Beispiel #17
0
  /**
   * Called by the framework in order to compute a tile for the given target band.
   *
   * <p>The default implementation throws a runtime exception with the message "not implemented".
   *
   * @param targetBand The target band.
   * @param targetTile The current tile associated with the target band to be computed.
   * @param pm A progress monitor which should be used to determine computation cancelation
   *     requests.
   * @throws org.esa.snap.framework.gpf.OperatorException If an error occurs during computation of
   *     the target raster.
   */
  public void computeTile(Band targetBand, Tile targetTile, ProgressMonitor pm)
      throws OperatorException {

    final Rectangle targetTileRectangle = targetTile.getRectangle();
    final int x0 = targetTileRectangle.x;
    final int y0 = targetTileRectangle.y;
    final int w = targetTileRectangle.width;
    final int h = targetTileRectangle.height;

    Tile sourceRaster1 = null;
    ProductData srcData1 = null;
    ProductData srcData2 = null;
    Band sourceBand1 = null;

    final String[] srcBandNames = targetBandNameToSourceBandName.get(targetBand.getName());
    if (srcBandNames.length == 1) {
      sourceBand1 = sourceProduct.getBand(srcBandNames[0]);
      sourceRaster1 = calibrationOp.getSourceTile(sourceBand1, targetTileRectangle);
      srcData1 = sourceRaster1.getDataBuffer();
    } else {
      sourceBand1 = sourceProduct.getBand(srcBandNames[0]);
      final Band sourceBand2 = sourceProduct.getBand(srcBandNames[1]);
      sourceRaster1 = calibrationOp.getSourceTile(sourceBand1, targetTileRectangle);
      final Tile sourceRaster2 = calibrationOp.getSourceTile(sourceBand2, targetTileRectangle);
      srcData1 = sourceRaster1.getDataBuffer();
      srcData2 = sourceRaster2.getDataBuffer();
    }

    final Unit.UnitType bandUnit = Unit.getUnitType(sourceBand1);

    // copy band if unit is phase
    if (bandUnit == Unit.UnitType.PHASE) {
      targetTile.setRawSamples(sourceRaster1.getRawSamples());
      return;
    }

    final ProductData trgData = targetTile.getDataBuffer();
    final TileIndex srcIndex = new TileIndex(sourceRaster1);
    final TileIndex tgtIndex = new TileIndex(targetTile);

    final int maxY = y0 + h;
    final int maxX = x0 + w;

    double dn = 0, dn2 = 0, sigma, i, q;
    int srcIdx, tgtIdx;

    for (int y = y0; y < maxY; ++y) {
      srcIndex.calculateStride(y);
      tgtIndex.calculateStride(y);

      for (int x = x0; x < maxX; ++x) {
        srcIdx = srcIndex.getIndex(x);
        tgtIdx = tgtIndex.getIndex(x);

        if (bandUnit == Unit.UnitType.AMPLITUDE) {
          dn = srcData1.getElemDoubleAt(srcIdx);
          dn2 = dn * dn;
        } else if (bandUnit == Unit.UnitType.INTENSITY) {
          dn2 = srcData1.getElemDoubleAt(srcIdx);
        } else if (bandUnit == Unit.UnitType.REAL || bandUnit == Unit.UnitType.IMAGINARY) {
          if (outputImageInComplex) {
            dn = srcData1.getElemDoubleAt(srcIdx);
          } else {
            i = srcData1.getElemDoubleAt(srcIdx);
            q = srcData2.getElemDoubleAt(srcIdx);
            dn2 = i * i + q * q;
          }
        } else {
          throw new OperatorException("ALOS Calibration: unhandled unit");
        }

        if (isComplex && outputImageInComplex) {
          sigma = dn * Math.sqrt(calibrationFactor);
        } else {
          sigma = dn2 * calibrationFactor;
        }

        if (outputImageScaleInDb) { // convert calibration result to dB
          if (sigma < underFlowFloat) {
            sigma = -underFlowFloat;
          } else {
            sigma = 10.0 * Math.log10(sigma);
          }
        }

        trgData.setElemDoubleAt(tgtIdx, sigma);
      }
    }
  }
  @Override
  protected void addGeoCoding(final Product product) {

    TiePointGrid latGrid = product.getTiePointGrid(OperatorUtils.TPG_LATITUDE);
    TiePointGrid lonGrid = product.getTiePointGrid(OperatorUtils.TPG_LONGITUDE);
    if (latGrid != null && lonGrid != null) {
      setLatLongMetadata(product, latGrid, lonGrid);

      final TiePointGeoCoding tpGeoCoding = new TiePointGeoCoding(latGrid, lonGrid, Datum.WGS_84);
      product.setGeoCoding(tpGeoCoding);
      return;
    }

    final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product);
    final String acquisitionMode = absRoot.getAttributeString(AbstractMetadata.ACQUISITION_MODE);
    int numOfSubSwath;
    switch (acquisitionMode) {
      case "IW":
        numOfSubSwath = 3;
        break;
      case "EW":
        numOfSubSwath = 5;
        break;
      default:
        return;
    }

    String[] bandNames = product.getBandNames();
    Band firstSWBand = null, lastSWBand = null;
    boolean firstSWBandFound = false, lastSWBandFound = false;
    for (String bandName : bandNames) {
      if (!firstSWBandFound && bandName.contains(acquisitionMode + 1)) {
        firstSWBand = product.getBand(bandName);
        firstSWBandFound = true;
      }

      if (!lastSWBandFound && bandName.contains(acquisitionMode + numOfSubSwath)) {
        lastSWBand = product.getBand(bandName);
        lastSWBandFound = true;
      }
    }
    if (firstSWBand == null && lastSWBand == null) return;

    final GeoCoding firstSWBandGeoCoding = bandGeocodingMap.get(firstSWBand);
    final int firstSWBandHeight = firstSWBand.getRasterHeight();

    final GeoCoding lastSWBandGeoCoding = bandGeocodingMap.get(lastSWBand);
    final int lastSWBandWidth = lastSWBand.getRasterWidth();
    final int lastSWBandHeight = lastSWBand.getRasterHeight();

    final PixelPos ulPix = new PixelPos(0, 0);
    final PixelPos llPix = new PixelPos(0, firstSWBandHeight - 1);
    final GeoPos ulGeo = new GeoPos();
    final GeoPos llGeo = new GeoPos();
    firstSWBandGeoCoding.getGeoPos(ulPix, ulGeo);
    firstSWBandGeoCoding.getGeoPos(llPix, llGeo);

    final PixelPos urPix = new PixelPos(lastSWBandWidth - 1, 0);
    final PixelPos lrPix = new PixelPos(lastSWBandWidth - 1, lastSWBandHeight - 1);
    final GeoPos urGeo = new GeoPos();
    final GeoPos lrGeo = new GeoPos();
    lastSWBandGeoCoding.getGeoPos(urPix, urGeo);
    lastSWBandGeoCoding.getGeoPos(lrPix, lrGeo);

    final float[] latCorners = {
      (float) ulGeo.getLat(), (float) urGeo.getLat(), (float) llGeo.getLat(), (float) lrGeo.getLat()
    };
    final float[] lonCorners = {
      (float) ulGeo.getLon(), (float) urGeo.getLon(), (float) llGeo.getLon(), (float) lrGeo.getLon()
    };

    ReaderUtils.addGeoCoding(product, latCorners, lonCorners);

    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_near_lat, ulGeo.getLat());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_near_long, ulGeo.getLon());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_far_lat, urGeo.getLat());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_far_long, urGeo.getLon());

    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_near_lat, llGeo.getLat());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_near_long, llGeo.getLon());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_far_lat, lrGeo.getLat());
    AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_far_long, lrGeo.getLon());

    // add band geocoding
    final Band[] bands = product.getBands();
    for (Band band : bands) {
      band.setGeoCoding(bandGeocodingMap.get(band));
    }
  }
  private void addTiePointGrids(final Band band, final String imgXMLName, final String tpgPrefix) {

    // System.out.println("S1L1Dir.addTiePointGrids: band = " + band.getName() + " imgXMLName = " +
    // imgXMLName + " tpgPrefix = " + tpgPrefix);

    final Product product = band.getProduct();
    String pre = "";
    if (!tpgPrefix.isEmpty()) pre = tpgPrefix + '_';

    final TiePointGrid existingLatTPG = product.getTiePointGrid(pre + OperatorUtils.TPG_LATITUDE);
    final TiePointGrid existingLonTPG = product.getTiePointGrid(pre + OperatorUtils.TPG_LONGITUDE);
    if (existingLatTPG != null && existingLonTPG != null) {
      // System.out.println("for band = " + band.getName() + ", use existing TPG");
      // reuse geocoding
      final TiePointGeoCoding tpGeoCoding =
          new TiePointGeoCoding(existingLatTPG, existingLonTPG, Datum.WGS_84);
      band.setGeoCoding(tpGeoCoding);
      return;
    }
    // System.out.println("add new TPG for band = " + band.getName());
    final String annotation = FileUtils.exchangeExtension(imgXMLName, ".xml");
    final MetadataElement origProdRoot = AbstractMetadata.getOriginalProductMetadata(product);
    final MetadataElement annotationElem = origProdRoot.getElement("annotation");
    final MetadataElement imgElem = annotationElem.getElement(annotation);
    final MetadataElement productElem = imgElem.getElement("product");
    final MetadataElement geolocationGrid = productElem.getElement("geolocationGrid");
    final MetadataElement geolocationGridPointList =
        geolocationGrid.getElement("geolocationGridPointList");

    final MetadataElement[] geoGrid = geolocationGridPointList.getElements();

    // System.out.println("geoGrid.length = " + geoGrid.length);

    final double[] latList = new double[geoGrid.length];
    final double[] lngList = new double[geoGrid.length];
    final double[] incidenceAngleList = new double[geoGrid.length];
    final double[] elevAngleList = new double[geoGrid.length];
    final double[] rangeTimeList = new double[geoGrid.length];
    final int[] x = new int[geoGrid.length];
    final int[] y = new int[geoGrid.length];

    // Loop through the list of geolocation grid points, assuming that it represents a row-major
    // rectangular grid.
    int gridWidth = 0, gridHeight = 0;
    int i = 0;
    for (MetadataElement ggPoint : geoGrid) {
      latList[i] = ggPoint.getAttributeDouble("latitude", 0);
      lngList[i] = ggPoint.getAttributeDouble("longitude", 0);
      incidenceAngleList[i] = ggPoint.getAttributeDouble("incidenceAngle", 0);
      elevAngleList[i] = ggPoint.getAttributeDouble("elevationAngle", 0);
      rangeTimeList[i] =
          ggPoint.getAttributeDouble("slantRangeTime", 0) * Constants.oneBillion; // s to ns

      x[i] = (int) ggPoint.getAttributeDouble("pixel", 0);
      y[i] = (int) ggPoint.getAttributeDouble("line", 0);
      if (x[i] == 0) {
        // This means we are at the start of a new line
        if (gridWidth
            == 0) // Here we are implicitly assuming that the pixel horizontal spacing is assumed to
                  // be the same from line to line.
        gridWidth = i;
        ++gridHeight;
      }
      ++i;
    }

    // System.out.println("geoGrid w = " + gridWidth + "; h = " + gridHeight);

    final int newGridWidth = gridWidth;
    final int newGridHeight = gridHeight;
    final float[] newLatList = new float[newGridWidth * newGridHeight];
    final float[] newLonList = new float[newGridWidth * newGridHeight];
    final float[] newIncList = new float[newGridWidth * newGridHeight];
    final float[] newElevList = new float[newGridWidth * newGridHeight];
    final float[] newslrtList = new float[newGridWidth * newGridHeight];
    final int sceneRasterWidth = band.getSceneRasterWidth();
    final int sceneRasterHeight = band.getSceneRasterHeight();
    final double subSamplingX = (double) sceneRasterWidth / (newGridWidth - 1);
    final double subSamplingY = (double) sceneRasterHeight / (newGridHeight - 1);

    getListInEvenlySpacedGrid(
        sceneRasterWidth,
        sceneRasterHeight,
        gridWidth,
        gridHeight,
        x,
        y,
        latList,
        newGridWidth,
        newGridHeight,
        subSamplingX,
        subSamplingY,
        newLatList);

    getListInEvenlySpacedGrid(
        sceneRasterWidth,
        sceneRasterHeight,
        gridWidth,
        gridHeight,
        x,
        y,
        lngList,
        newGridWidth,
        newGridHeight,
        subSamplingX,
        subSamplingY,
        newLonList);

    getListInEvenlySpacedGrid(
        sceneRasterWidth,
        sceneRasterHeight,
        gridWidth,
        gridHeight,
        x,
        y,
        incidenceAngleList,
        newGridWidth,
        newGridHeight,
        subSamplingX,
        subSamplingY,
        newIncList);

    getListInEvenlySpacedGrid(
        sceneRasterWidth,
        sceneRasterHeight,
        gridWidth,
        gridHeight,
        x,
        y,
        elevAngleList,
        newGridWidth,
        newGridHeight,
        subSamplingX,
        subSamplingY,
        newElevList);

    getListInEvenlySpacedGrid(
        sceneRasterWidth,
        sceneRasterHeight,
        gridWidth,
        gridHeight,
        x,
        y,
        rangeTimeList,
        newGridWidth,
        newGridHeight,
        subSamplingX,
        subSamplingY,
        newslrtList);

    TiePointGrid latGrid = product.getTiePointGrid(pre + OperatorUtils.TPG_LATITUDE);
    if (latGrid == null) {
      latGrid =
          new TiePointGrid(
              pre + OperatorUtils.TPG_LATITUDE,
              newGridWidth,
              newGridHeight,
              0.5f,
              0.5f,
              subSamplingX,
              subSamplingY,
              newLatList);
      latGrid.setUnit(Unit.DEGREES);
      product.addTiePointGrid(latGrid);
    }

    TiePointGrid lonGrid = product.getTiePointGrid(pre + OperatorUtils.TPG_LONGITUDE);
    if (lonGrid == null) {
      lonGrid =
          new TiePointGrid(
              pre + OperatorUtils.TPG_LONGITUDE,
              newGridWidth,
              newGridHeight,
              0.5f,
              0.5f,
              subSamplingX,
              subSamplingY,
              newLonList,
              TiePointGrid.DISCONT_AT_180);
      lonGrid.setUnit(Unit.DEGREES);
      product.addTiePointGrid(lonGrid);
    }

    if (product.getTiePointGrid(pre + OperatorUtils.TPG_INCIDENT_ANGLE) == null) {
      final TiePointGrid incidentAngleGrid =
          new TiePointGrid(
              pre + OperatorUtils.TPG_INCIDENT_ANGLE,
              newGridWidth,
              newGridHeight,
              0.5f,
              0.5f,
              subSamplingX,
              subSamplingY,
              newIncList);
      incidentAngleGrid.setUnit(Unit.DEGREES);
      product.addTiePointGrid(incidentAngleGrid);
    }

    if (product.getTiePointGrid(pre + OperatorUtils.TPG_ELEVATION_ANGLE) == null) {
      final TiePointGrid elevAngleGrid =
          new TiePointGrid(
              pre + OperatorUtils.TPG_ELEVATION_ANGLE,
              newGridWidth,
              newGridHeight,
              0.5f,
              0.5f,
              subSamplingX,
              subSamplingY,
              newElevList);
      elevAngleGrid.setUnit(Unit.DEGREES);
      product.addTiePointGrid(elevAngleGrid);
    }

    if (product.getTiePointGrid(pre + OperatorUtils.TPG_SLANT_RANGE_TIME) == null) {
      final TiePointGrid slantRangeGrid =
          new TiePointGrid(
              pre + OperatorUtils.TPG_SLANT_RANGE_TIME,
              newGridWidth,
              newGridHeight,
              0.5f,
              0.5f,
              subSamplingX,
              subSamplingY,
              newslrtList);
      slantRangeGrid.setUnit(Unit.NANOSECONDS);
      product.addTiePointGrid(slantRangeGrid);
    }

    final TiePointGeoCoding tpGeoCoding = new TiePointGeoCoding(latGrid, lonGrid, Datum.WGS_84);
    bandGeocodingMap.put(band, tpGeoCoding);
  }
  private static Band[] createXYDisplacementBands(final Product product, ProgressMonitor pm) {
    final int width = product.getSceneRasterWidth();
    final int height = product.getSceneRasterHeight();

    ImageInfo blueToRedGrad =
        new ImageInfo(
            new ColorPaletteDef(
                new ColorPaletteDef.Point[] {
                  new ColorPaletteDef.Point(-1.0, Color.BLUE),
                  new ColorPaletteDef.Point(0.0, Color.WHITE),
                  new ColorPaletteDef.Point(1.0, Color.RED),
                }));
    ImageInfo amplGrad =
        new ImageInfo(
            new ColorPaletteDef(
                new ColorPaletteDef.Point[] {
                  new ColorPaletteDef.Point(0.0, Color.WHITE),
                  new ColorPaletteDef.Point(1.0, Color.RED),
                }));
    ImageInfo phaseGrad =
        new ImageInfo(
            new ColorPaletteDef(
                new ColorPaletteDef.Point[] {
                  new ColorPaletteDef.Point(-Math.PI, Color.WHITE),
                  new ColorPaletteDef.Point(0.0, Color.BLUE),
                  new ColorPaletteDef.Point(+Math.PI, Color.WHITE),
                }));

    final Band bandX = new Band("gc_displ_x", ProductData.TYPE_FLOAT64, width, height);
    configureBand(bandX, blueToRedGrad.clone(), "pixels", "Geo-coding X-displacement");

    final Band bandY = new Band("gc_displ_y", ProductData.TYPE_FLOAT64, width, height);
    configureBand(bandY, blueToRedGrad.clone(), "pixels", "Geo-coding Y-displacement");

    final Band bandAmpl =
        new VirtualBand(
            "gc_displ_ampl",
            ProductData.TYPE_FLOAT64,
            width,
            height,
            "ampl(gc_displ_x, gc_displ_y)");
    configureBand(bandAmpl, amplGrad.clone(), "pixels", "Geo-coding displacement amplitude");

    final Band bandPhase =
        new VirtualBand(
            "gc_displ_phase",
            ProductData.TYPE_FLOAT64,
            width,
            height,
            "phase(gc_displ_x, gc_displ_y)");
    configureBand(bandPhase, phaseGrad.clone(), "radians", "Geo-coding displacement phase");

    final double[] dataX = new double[width * height];
    final double[] dataY = new double[width * height];

    bandX.setRasterData(ProductData.createInstance(dataX));
    bandY.setRasterData(ProductData.createInstance(dataY));

    pm.beginTask(
        "Computing geo-coding displacements for product '" + product.getName() + "'...", height);
    try {
      final GeoPos geoPos = new GeoPos();
      final PixelPos pixelPos1 = new PixelPos();
      final PixelPos pixelPos2 = new PixelPos();
      for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
          double maxX = 0;
          double maxY = 0;
          double valueX = 0;
          double valueY = 0;
          for (float[] offset : OFFSETS) {
            pixelPos1.setLocation(x + offset[0], y + offset[1]);
            product.getGeoCoding().getGeoPos(pixelPos1, geoPos);
            product.getGeoCoding().getPixelPos(geoPos, pixelPos2);
            double dx = pixelPos2.x - pixelPos1.x;
            double dy = pixelPos2.y - pixelPos1.y;
            if (Math.abs(dx) > maxX) {
              maxX = Math.abs(dx);
              valueX = dx;
            }
            if (Math.abs(dy) > maxY) {
              maxY = Math.abs(dy);
              valueY = dy;
            }
          }
          dataX[y * width + x] = valueX;
          dataY[y * width + x] = valueY;
        }
        if (pm.isCanceled()) {
          return null;
        }
        pm.worked(1);
      }
    } finally {
      pm.done();
    }

    return new Band[] {bandX, bandY, bandAmpl, bandPhase};
  }