package mil.nga.giat.geowave.adapter.raster.adapter.merge.nodata;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import mil.nga.giat.geowave.adapter.raster.FitToIndexGridCoverage;
import mil.nga.giat.geowave.adapter.raster.adapter.MergeableRasterTile;
import mil.nga.giat.geowave.adapter.raster.adapter.RasterDataAdapter;
import mil.nga.giat.geowave.adapter.raster.adapter.RasterTile;
import mil.nga.giat.geowave.adapter.raster.adapter.merge.RasterTileMergeStrategy;
import mil.nga.giat.geowave.adapter.raster.adapter.merge.nodata.NoDataMetadata.SampleIndex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opengis.coverage.grid.GridCoverage;
public class NoDataMergeStrategy implements
RasterTileMergeStrategy<NoDataMetadata>
{
public NoDataMergeStrategy() {}
private static final long serialVersionUID = 38473874l;
private static final Logger LOGGER = LoggerFactory.getLogger(NoDataMergeStrategy.class);
@Override
public void merge(
final RasterTile<NoDataMetadata> thisTile,
final RasterTile<NoDataMetadata> nextTile,
final SampleModel sampleModel ) {
// this strategy aims for latest tile with data values, but where there
// is no data in the latest and there is data in the earlier tile, it
// fills the data from the earlier tile
// if next tile is null or if this tile does not have metadata, just
// keep this tile as is
if ((nextTile != null) && (thisTile.getMetadata() != null)) {
if (nextTile instanceof MergeableRasterTile) {
final NoDataMetadata thisTileMetadata = thisTile.getMetadata();
final NoDataMetadata nextTileMetadata = nextTile.getMetadata();
final WritableRaster thisRaster = Raster.createWritableRaster(
sampleModel,
thisTile.getDataBuffer(),
null);
final WritableRaster nextRaster = Raster.createWritableRaster(
sampleModel,
nextTile.getDataBuffer(),
null);
final int maxX = thisRaster.getMinX() + thisRaster.getWidth();
final int maxY = thisRaster.getMinY() + thisRaster.getHeight();
boolean recalculateMetadata = false;
for (int b = 0; b < thisRaster.getNumBands(); b++) {
for (int x = thisRaster.getMinX(); x < maxX; x++) {
for (int y = thisRaster.getMinY(); y < maxY; y++) {
if (thisTileMetadata.isNoData(
new SampleIndex(
x,
y,
b),
thisRaster.getSampleDouble(
x,
y,
b))) {
final double sample = nextRaster.getSampleDouble(
x,
y,
b);
if ((nextTileMetadata == null) || !nextTileMetadata.isNoData(
new SampleIndex(
x,
y,
b),
sample)) {
// we only need to recalculate metadata if
// the raster is overwritten,
// otherwise just use this raster's
// metadata
recalculateMetadata = true;
thisRaster.setSample(
x,
y,
b,
sample);
}
}
}
}
}
if (recalculateMetadata) {
thisTile.setMetadata(NoDataMetadataFactory.mergeMetadata(
thisTileMetadata,
thisRaster,
nextTileMetadata,
nextRaster));
}
}
}
}
@Override
public boolean equals(
final Object obj ) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
return true;
}
@Override
public int hashCode() {
return (int) serialVersionUID;
// this looks correct based on behaviour of equals?!? should return the
// same hash code for all instances
}
@Override
public byte[] toBinary() {
return new byte[] {};
}
@Override
public void fromBinary(
final byte[] bytes ) {}
@Override
public NoDataMetadata getMetadata(
final GridCoverage tileGridCoverage,
final RasterDataAdapter dataAdapter ) {
if (tileGridCoverage instanceof FitToIndexGridCoverage) {
return NoDataMetadataFactory.createMetadata(
dataAdapter.getNoDataValuesPerBand(),
((FitToIndexGridCoverage) tileGridCoverage).getFootprintScreenGeometry(),
tileGridCoverage.getRenderedImage().getData());
}
return NoDataMetadataFactory.createMetadata(
dataAdapter.getNoDataValuesPerBand(),
null,
tileGridCoverage.getRenderedImage().getData());
}
}