Package mil.nga.giat.geowave.raster.adapter.merge.nodata

Source Code of mil.nga.giat.geowave.raster.adapter.merge.nodata.NoDataMetadataFactory$MultiRaster

package mil.nga.giat.geowave.raster.adapter.merge.nodata;

import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import mil.nga.giat.geowave.raster.adapter.merge.nodata.NoDataMetadata.SampleIndex;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;

public class NoDataMetadataFactory
{
  private static class NoDataSummary
  {
    private final Set<SampleIndex> indices;
    private final double[][] usedNoDataValues;

    public NoDataSummary(
        final Set<SampleIndex> indices,
        final double[][] usedNoDataValues ) {
      this.indices = indices;
      this.usedNoDataValues = usedNoDataValues;
    }
  }

  private static final int MAX_LIST_NO_DATA = 20;

  public static NoDataMetadata createMetadata(
      final double[][] allNoDataValues,
      final Geometry shape,
      final Raster data ) {
    final NoDataSummary noDataSummary = getNoDataSummary(
        allNoDataValues,
        shape,
        data);
    return createMetadata(
        noDataSummary,
        new Geometry[] {
          shape
        });
  }

  public static NoDataMetadata mergeMetadata(
      final NoDataMetadata noDataMetadata1,
      final WritableRaster raster1,
      final NoDataMetadata noDataMetadata2,
      final WritableRaster raster2 ) {
    final Set<SampleIndex> noDataIndices1 = noDataMetadata1.getNoDataIndices();
    final Set<SampleIndex> noDataIndices2 = noDataMetadata2.getNoDataIndices();
    if ((noDataIndices1 != null) && (noDataIndices2 != null)) {
      // simple case, just take the intersection of the sets
      noDataIndices2.retainAll(noDataIndices1);
      return new NoDataBySampleIndex(
          noDataIndices2);
    }
    else if (noDataIndices1 != null) {
      // just determine which of the no data indices are covered by the
      // second set of metadata and remove them
      return mergeMetadataBySummary(
          noDataIndices1,
          noDataMetadata2,
          raster2);
    }
    else if (noDataIndices2 != null) {
      // just determine which of the no data indices are covered by the
      // first set of metadata and remove them
      return mergeMetadataBySummary(
          noDataIndices2,
          noDataMetadata1,
          raster1);
    }
    else if ((noDataMetadata1 instanceof NoDataByFilter) && (noDataMetadata2 instanceof NoDataByFilter)) {
      final NoDataByFilter noDataByFilter1 = ((NoDataByFilter) noDataMetadata1);
      final NoDataByFilter noDataByFilter2 = ((NoDataByFilter) noDataMetadata2);

      final double[][] noDataPerBand1 = noDataByFilter1.getNoDataPerBand();
      final double[][] noDataPerBand2 = noDataByFilter1.getNoDataPerBand();
      // union the no data values from each filter
      final int numBands = Math.min(
          noDataPerBand1.length,
          noDataPerBand2.length);
      final double[][] allNoDataValues = new double[numBands][];
      for (int b = 0; b < numBands; b++) {
        final Set<Double> noDataValuesInBand = new HashSet<Double>();
        if (noDataPerBand1[b] != null) {
          for (final double noDataValue : noDataPerBand1[b]) {
            noDataValuesInBand.add(noDataValue);
          }
        }
        if (noDataPerBand2[b] != null) {
          for (final double noDataValue : noDataPerBand2[b]) {
            noDataValuesInBand.add(noDataValue);
          }
        }
        allNoDataValues[b] = new double[noDataValuesInBand.size()];
        int i = 0;
        final Iterator<Double> it = noDataValuesInBand.iterator();
        while (it.hasNext()) {
          allNoDataValues[b][i++] = it.next();
        }
      }
      return mergeMetadataBySummary(
          allNoDataValues,
          noDataByFilter1,
          raster1,
          noDataByFilter2,
          raster2);
    }
    else {
      // this should never happen because the only implementations of
      // metadata are by index or by filter but just in case iteratively
      // go through every sample, determine if its covered by the first or
      // the second set of metadata and use the indices
      return exhaustiveMergeMetadata(
          noDataMetadata1,
          raster1,
          noDataMetadata2,
          raster2);
    }
  }

  private static NoDataMetadata createMetadata(
      final NoDataSummary noDataSummary,
      final Geometry[] shapes ) {
    if (noDataSummary.indices.size() > MAX_LIST_NO_DATA) {
      Geometry finalShape = shapes[0];
      if (shapes.length > 1) {
        for (int i = 1; i < shapes.length; i++) {
          finalShape = finalShape.intersection(shapes[i]);
        }
      }
      return new NoDataByFilter(
          finalShape,
          noDataSummary.usedNoDataValues);
    }
    else if (!noDataSummary.indices.isEmpty()) {
      // just go through every raster sample and determine whether it
      // qualifies as null data
      return new NoDataBySampleIndex(
          noDataSummary.indices);
    }
    else {
      // the "no data" samples in the dataset must be 0, so just return
      // null for the metadata
      return null;
    }
  }

  private static NoDataMetadata mergeMetadataBySummary(
      final Set<SampleIndex> noDataIndices,
      final NoDataMetadata noDataMetadata,
      final WritableRaster raster ) {
    final Iterator<SampleIndex> indices = noDataIndices.iterator();
    while (indices.hasNext()) {
      final SampleIndex index = indices.next();
      if (!noDataMetadata.isNoData(
          index,
          raster.getSampleDouble(
              index.getX(),
              index.getY(),
              index.getBand()))) {
        indices.remove();
      }
    }
    return new NoDataBySampleIndex(
        noDataIndices);
  }

  private static NoDataMetadata exhaustiveMergeMetadata(
      final NoDataMetadata noDataMetadata1,
      final WritableRaster raster1,
      final NoDataMetadata noDataMetadata2,
      final WritableRaster raster2 ) {
    final int width = Math.min(
        raster1.getWidth(),
        raster2.getWidth());
    final int height = Math.min(
        raster1.getHeight(),
        raster2.getHeight());
    final int numBands = Math.min(
        raster1.getNumBands(),
        raster2.getNumBands());
    final Set<SampleIndex> indices = new HashSet<SampleIndex>();
    for (int b = 0; b < numBands; b++) {
      for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
          final SampleIndex index = new SampleIndex(
              x,
              y,
              b);
          if (noDataMetadata1.isNoData(
              index,
              raster1.getSampleDouble(
                  x,
                  y,
                  b)) && noDataMetadata2.isNoData(
              index,
              raster2.getSampleDouble(
                  x,
                  y,
                  b))) {
            indices.add(index);
          }
        }
      }
    }
    return new NoDataBySampleIndex(
        indices);
  }

  private static NoDataMetadata mergeMetadataBySummary(
      final double[][] allNoDataValues,
      final NoDataByFilter noDataMetadata1,
      final WritableRaster raster1,
      final NoDataByFilter noDataMetadata2,
      final WritableRaster raster2 ) {
    final NoDataSummary noDataSummary = getNoDataSummary(
        allNoDataValues,
        noDataMetadata1,
        raster1,
        noDataMetadata2,
        raster2);
    return createMetadata(
        noDataSummary,
        new Geometry[] {
          noDataMetadata1.getShape(),
          noDataMetadata2.getShape()
        });
  }

  private static NoDataSummary getNoDataSummary(
      final double[][] allNoDataValues,
      final NoDataByFilter noDataMetadata1,
      final WritableRaster raster1,
      final NoDataByFilter noDataMetadata2,
      final WritableRaster raster2 ) {
    final int width = Math.min(
        raster1.getWidth(),
        raster2.getWidth());
    final int height = Math.min(
        raster1.getHeight(),
        raster2.getHeight());
    final int numBands = Math.min(
        raster1.getNumBands(),
        raster2.getNumBands());
    return getNoDataSummary(
        allNoDataValues,
        new MultiShape(
            new Geometry[] {
              noDataMetadata1.getShape(),
              noDataMetadata2.getShape()
            }),
        new MultiRaster(
            new Raster[] {
              raster1,
              raster2
            }),
        width,
        height,
        numBands);
  }

  private static NoDataSummary getNoDataSummary(
      final double[][] allNoDataValues,
      final Geometry shape,
      final Raster data ) {
    return getNoDataSummary(
        allNoDataValues,
        new SingleShape(
            shape),
        new SingleRaster(
            data),
        data.getWidth(),
        data.getHeight(),
        data.getNumBands());
  }

  private static NoDataSummary getNoDataSummary(
      final double[][] allNoDataValues,
      final NoDataByCoordinate shape,
      final NoDataBySample data,
      final int width,
      final int height,
      final int numBands ) {

    final Set<Double>[] noDataValuesPerBand;
    boolean skipNoData;

    final Set<SampleIndex> indices = new HashSet<SampleIndex>();
    if (allNoDataValues == null) {
      skipNoData = true;
      noDataValuesPerBand = null;
      if (shape == null) {
        return new NoDataSummary(
            indices,
            new double[][] {});
      }
    }
    else {
      noDataValuesPerBand = new Set[numBands];
      for (int b = 0; b < numBands; b++) {
        noDataValuesPerBand[b] = new HashSet<Double>();
      }
      skipNoData = false;
    }

    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        if (shape.accept(
            x,
            y)) {
          for (int b = 0; b < numBands; b++) {
            indices.add(new SampleIndex(
                x,
                y,
                b));
          }
          // this will ignore the no data values for this x,y
          // which should be fine because the shape will
          // always classify this x,y as "no data"
          continue;
        }
        else if (!skipNoData) {
          for (int b = 0; b < numBands; b++) {
            if (allNoDataValues[b] == null) {
              continue;
            }
            else {
              final double[] samples = data.getSampleValues(
                  x,
                  y,
                  b);
              for (int i = 0; i < allNoDataValues[b].length; i++) {
                // if a single sample is not a "no data" value
                // then it is valid
                boolean noData = true;
                for (final double sample : samples) {
                  if (sample != allNoDataValues[b][i]) {
                    noData = false;
                    break;
                  }
                }
                if (noData) {
                  indices.add(new SampleIndex(
                      x,
                      y,
                      b));
                  noDataValuesPerBand[b].add(allNoDataValues[b][i]);
                }
              }
            }
          }
        }
      }
    }
    final double[][] usedNoDataValues;
    if (!skipNoData) {
      usedNoDataValues = new double[noDataValuesPerBand.length][];
      for (int b = 0; b < noDataValuesPerBand.length; b++) {
        usedNoDataValues[b] = new double[noDataValuesPerBand[b].size()];
        int i = 0;
        final Iterator<Double> noDataValues = noDataValuesPerBand[b].iterator();
        while (noDataValues.hasNext()) {
          usedNoDataValues[b][i++] = noDataValues.next();
        }
      }
    }
    else {
      usedNoDataValues = new double[][] {};
    }
    return new NoDataSummary(
        indices,
        usedNoDataValues);
  }

  private static interface NoDataByCoordinate
  {
    public boolean accept(
        int x,
        int y );
  }

  private static interface NoDataBySample
  {
    public double[] getSampleValues(
        int x,
        int y,
        int b );
  }

  private static class SingleShape implements
      NoDataByCoordinate
  {
    private final Geometry shape;

    public SingleShape(
        final Geometry shape ) {
      this.shape = shape;
    }

    @Override
    public boolean accept(
        final int x,
        final int y ) {
      return ((shape != null) && !shape.contains(new GeometryFactory().createPoint(new Coordinate(
          x,
          y))));
    }
  }

  private static class MultiShape implements
      NoDataByCoordinate
  {
    private final Geometry[] shapes;
    private boolean acceptNone = false;

    public MultiShape(
        final Geometry[] shapes ) {
      this.shapes = shapes;
      for (final Geometry shape : shapes) {
        if (shape == null) {
          acceptNone = true;
        }
      }
    }

    @Override
    public boolean accept(
        final int x,
        final int y ) {
      if (!acceptNone) {
        for (final Geometry shape : shapes) {
          // if any one contains the point than it is not "no data"
          // based on shape
          if (shape.contains(new GeometryFactory().createPoint(new Coordinate(
              x,
              y)))) {
            return true;
          }
        }
      }
      return true;
    }
  }

  private static class SingleRaster implements
      NoDataBySample
  {
    private final Raster raster;

    public SingleRaster(
        final Raster raster ) {
      this.raster = raster;
    }

    @Override
    public double[] getSampleValues(
        final int x,
        final int y,
        final int b ) {
      return new double[] {
        raster.getSampleDouble(
            x,
            y,
            b)
      };
    }
  }

  private static class MultiRaster implements
      NoDataBySample
  {
    private final Raster[] rasters;

    public MultiRaster(
        final Raster[] rasters ) {
      this.rasters = rasters;
    }

    @Override
    public double[] getSampleValues(
        final int x,
        final int y,
        final int b ) {
      final double[] samples = new double[rasters.length];
      for (int i = 0; i < rasters.length; i++) {
        samples[i] = rasters[i].getSampleDouble(
            x,
            y,
            b);
      }
      return samples;
    }
  }
}
TOP

Related Classes of mil.nga.giat.geowave.raster.adapter.merge.nodata.NoDataMetadataFactory$MultiRaster

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.