public static GridCoverage2D normalizeAll()

in common/src/main/java/org/apache/sedona/common/raster/RasterEditors.java [452:541]


  public static GridCoverage2D normalizeAll(
      GridCoverage2D rasterGeom,
      double minLim,
      double maxLim,
      boolean normalizeAcrossBands,
      Double noDataValue,
      Double minValue,
      Double maxValue) {
    if (minLim > maxLim) {
      throw new IllegalArgumentException("minLim cannot be greater than maxLim");
    }

    int numBands = rasterGeom.getNumSampleDimensions();
    RenderedImage renderedImage = rasterGeom.getRenderedImage();
    int rasterDataType = renderedImage.getSampleModel().getDataType();

    double globalMin = minValue != null ? minValue : Double.MAX_VALUE;
    double globalMax = maxValue != null ? maxValue : -Double.MAX_VALUE;

    // Initialize arrays to store band-wise min and max values
    double[] minValues = new double[numBands];
    double[] maxValues = new double[numBands];
    Arrays.fill(minValues, Double.MAX_VALUE);
    Arrays.fill(maxValues, -Double.MAX_VALUE);

    // Trigger safe mode if noDataValue is null - noDataValue is set to maxLim and data values are
    // normalized to range [minLim, maxLim-1].
    // This is done to prevent setting valid data as noDataValue.
    double safetyTrigger = (noDataValue == null) ? 1 : 0;

    // Compute global min and max values across all bands if necessary and not provided
    if (minValue == null || maxValue == null) {
      for (int bandIndex = 0; bandIndex < numBands; bandIndex++) {
        double[] bandValues = bandAsArray(rasterGeom, bandIndex + 1);
        double bandNoDataValue =
            RasterUtils.getNoDataValue(rasterGeom.getSampleDimension(bandIndex));

        if (noDataValue == null) {
          noDataValue = maxLim;
        }

        for (double val : bandValues) {
          if (val != bandNoDataValue) {
            if (normalizeAcrossBands) {
              globalMin = Math.min(globalMin, val);
              globalMax = Math.max(globalMax, val);
            } else {
              minValues[bandIndex] = Math.min(minValues[bandIndex], val);
              maxValues[bandIndex] = Math.max(maxValues[bandIndex], val);
            }
          }
        }
      }
    } else {
      globalMin = minValue;
      globalMax = maxValue;
    }

    // Normalize each band
    for (int bandIndex = 0; bandIndex < numBands; bandIndex++) {
      double[] bandValues = bandAsArray(rasterGeom, bandIndex + 1);
      double bandNoDataValue = RasterUtils.getNoDataValue(rasterGeom.getSampleDimension(bandIndex));
      double currentMin =
          normalizeAcrossBands ? globalMin : (minValue != null ? minValue : minValues[bandIndex]);
      double currentMax =
          normalizeAcrossBands ? globalMax : (maxValue != null ? maxValue : maxValues[bandIndex]);

      if (Double.compare(currentMax, currentMin) == 0) {
        Arrays.fill(bandValues, minLim);
      } else {
        for (int i = 0; i < bandValues.length; i++) {
          if (bandValues[i] != bandNoDataValue) {
            double normalizedValue =
                minLim
                    + ((bandValues[i] - currentMin) * (maxLim - safetyTrigger - minLim))
                        / (currentMax - currentMin);
            bandValues[i] = castRasterDataType(normalizedValue, rasterDataType);
          } else {
            bandValues[i] = noDataValue;
          }
        }
      }

      // Update the raster with the normalized band and noDataValue
      rasterGeom = addBandFromArray(rasterGeom, bandValues, bandIndex + 1);
      rasterGeom = RasterBandEditors.setBandNoDataValue(rasterGeom, bandIndex + 1, noDataValue);
    }

    return rasterGeom;
  }