package mil.nga.giat.geowave.adapter.raster.plugin; import java.awt.Color; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeMap; import javax.imageio.ImageReadParam; import javax.media.jai.Histogram; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverage.grid.io.GridCoverage2DReader; import org.geotools.coverage.grid.io.OverviewPolicy; import org.geotools.data.DataSourceException; import org.geotools.factory.Hints; import org.geotools.geometry.GeneralEnvelope; import org.geotools.parameter.Parameter; import org.geotools.referencing.CRS; import org.geotools.referencing.operation.BufferedCoordinateOperationFactory; import org.geotools.util.Utilities; import org.opengis.coverage.grid.Format; import org.opengis.coverage.grid.GridCoverage; import org.opengis.coverage.grid.GridEnvelope; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterDescriptor; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.cs.AxisDirection; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.CoordinateOperationFactory; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.GeometryFactory; import mil.nga.giat.geowave.adapter.auth.AuthorizationSPI; import mil.nga.giat.geowave.adapter.raster.RasterUtils; import mil.nga.giat.geowave.adapter.raster.Resolution; import mil.nga.giat.geowave.adapter.raster.adapter.CompoundHierarchicalIndexStrategyWrapper; import mil.nga.giat.geowave.adapter.raster.adapter.RasterDataAdapter; import mil.nga.giat.geowave.adapter.raster.stats.HistogramStatistics; import mil.nga.giat.geowave.adapter.raster.stats.OverviewStatistics; import mil.nga.giat.geowave.core.geotime.ingest.SpatialDimensionalityTypeProvider; import mil.nga.giat.geowave.core.geotime.store.query.IndexOnlySpatialQuery; import mil.nga.giat.geowave.core.geotime.store.statistics.BoundingBoxDataStatistics; import mil.nga.giat.geowave.core.index.ByteArrayId; import mil.nga.giat.geowave.core.index.HierarchicalNumericIndexStrategy; import mil.nga.giat.geowave.core.index.HierarchicalNumericIndexStrategy.SubStrategy; import mil.nga.giat.geowave.core.store.AdapterToIndexMapping; import mil.nga.giat.geowave.core.store.CloseableIterator; import mil.nga.giat.geowave.core.store.CloseableIterator.Wrapper; import mil.nga.giat.geowave.core.store.DataStore; import mil.nga.giat.geowave.core.store.adapter.AdapterIndexMappingStore; import mil.nga.giat.geowave.core.store.adapter.AdapterStore; import mil.nga.giat.geowave.core.store.adapter.DataAdapter; import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatistics; import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatisticsStore; import mil.nga.giat.geowave.core.store.index.CustomIdIndex; import mil.nga.giat.geowave.core.store.index.IndexStore; import mil.nga.giat.geowave.core.store.index.PrimaryIndex; import mil.nga.giat.geowave.core.store.query.Query; import mil.nga.giat.geowave.core.store.query.QueryOptions; /** * the reader gets the connection info and returns a grid coverage for every * data adapter */ public class GeoWaveRasterReader extends AbstractGridCoverage2DReader implements GridCoverage2DReader { private final static Logger LOGGER = LoggerFactory.getLogger(GeoWaveRasterReader.class); private GeoWaveRasterConfig config; private AdapterStore geowaveAdapterStore; private DataStatisticsStore geowaveStatisticsStore; private DataStore geowaveDataStore; private IndexStore geowaveIndexStore; private AdapterIndexMappingStore geowaveAdapterIndexMappingStore; private AuthorizationSPI authorizationSPI; protected final static CoordinateOperationFactory OPERATION_FACTORY = new BufferedCoordinateOperationFactory( new Hints( Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE)); private static Set<AxisDirection> UPDirections; private static Set<AxisDirection> LEFTDirections; // class initializer static { LEFTDirections = new HashSet<AxisDirection>(); LEFTDirections.add(AxisDirection.DISPLAY_LEFT); LEFTDirections.add(AxisDirection.EAST); LEFTDirections.add(AxisDirection.GEOCENTRIC_X); LEFTDirections.add(AxisDirection.COLUMN_POSITIVE); UPDirections = new HashSet<AxisDirection>(); UPDirections.add(AxisDirection.DISPLAY_UP); UPDirections.add(AxisDirection.NORTH); UPDirections.add(AxisDirection.GEOCENTRIC_Y); UPDirections.add(AxisDirection.ROW_POSITIVE); } /** * @param source * The source object. * @param uHints * @throws IOException * @throws MalformedURLException * @throws AccumuloSecurityException * @throws AccumuloException */ public GeoWaveRasterReader( final Object source, final Hints uHints ) throws IOException { super( source, uHints); this.source = source; if (GeoWaveGTRasterFormat.isParamList(source)) { try { config = GeoWaveRasterConfig.readFromConfigParams(source.toString()); } catch (final Exception e) { throw new MalformedURLException( source.toString()); } } else { final URL url = GeoWaveGTRasterFormat.getURLFromSource(source); if (url == null) { throw new MalformedURLException( source.toString()); } try { config = GeoWaveRasterConfig.readFromURL(url); } catch (final Exception e) { LOGGER.error( "Cannot read config", e); throw new IOException( e); } } init(config); } public GeoWaveRasterReader( final GeoWaveRasterConfig config ) throws DataSourceException { super( new Object(), new Hints()); this.config = config; init(config); } private void init( final GeoWaveRasterConfig config ) { geowaveDataStore = config.getDataStore(); geowaveAdapterStore = config.getAdapterStore(); geowaveStatisticsStore = config.getDataStatisticsStore(); geowaveIndexStore = config.getIndexStore(); geowaveAdapterIndexMappingStore = config.getAdapterIndexMappingStore(); crs = GeoWaveGTRasterFormat.DEFAULT_CRS; authorizationSPI = config.getAuthorizationFactory().create( config.getAuthorizationURL()); } /** * Constructor. * * @param source * The source object. * @throws IOException * @throws AccumuloSecurityException * @throws AccumuloException * @throws UnsupportedEncodingException * */ public GeoWaveRasterReader( final Object source ) throws IOException { this( source, null); } @Override public Format getFormat() { return new GeoWaveGTRasterFormat(); } @Override public String[] getGridCoverageNames() { try (final CloseableIterator<DataAdapter<?>> it = geowaveAdapterStore.getAdapters()) { final List<String> coverageNames = new ArrayList<String>(); while (it.hasNext()) { final DataAdapter<?> adapter = it.next(); if (adapter instanceof RasterDataAdapter) { coverageNames.add(((RasterDataAdapter) adapter).getCoverageName()); } } return coverageNames.toArray(new String[coverageNames.size()]); } catch (final IOException e) { LOGGER.warn( "unable to close adapter iterator while looking up coverage names", e); } return new String[] {}; } @Override public int getGridCoverageCount() { try (final CloseableIterator<DataAdapter<?>> it = geowaveAdapterStore.getAdapters()) { int coverageCount = 0; while (it.hasNext()) { final DataAdapter<?> adapter = it.next(); if (adapter instanceof RasterDataAdapter) { coverageCount++; } } return coverageCount; } catch (final IOException e) { LOGGER.warn( "unable to close data adapter when looking up coverage count", e); } return 0; } @Override public String[] getMetadataNames() { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public String[] getMetadataNames( final String coverageName ) { if (!checkName(coverageName)) { LOGGER.warn("Unable to find data adapter for '" + coverageName + "'"); return null; } final DataAdapter<?> adapter = geowaveAdapterStore.getAdapter(new ByteArrayId( coverageName)); final Set<String> var = ((RasterDataAdapter) adapter).getMetadata().keySet(); return var.toArray(new String[var.size()]); } @Override public String getMetadataValue( final String name ) { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public String getMetadataValue( final String coverageName, final String name ) { if (!checkName(coverageName)) { LOGGER.warn("Unable to find data adapter for '" + coverageName + "'"); return null; } final DataAdapter<?> adapter = geowaveAdapterStore.getAdapter(new ByteArrayId( coverageName)); return ((RasterDataAdapter) adapter).getMetadata().get( name); } @Override protected boolean checkName( final String coverageName ) { Utilities.ensureNonNull( "coverageName", coverageName); final DataAdapter<?> adapter = geowaveAdapterStore.getAdapter(new ByteArrayId( coverageName)); return (adapter != null) && (adapter instanceof RasterDataAdapter); } @Override public GeneralEnvelope getOriginalEnvelope() { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public GeneralEnvelope getOriginalEnvelope( final String coverageName ) { final DataStatistics<?> statistics = geowaveStatisticsStore.getDataStatistics( new ByteArrayId( coverageName), BoundingBoxDataStatistics.STATS_TYPE, authorizationSPI.getAuthorizations()); // try to use both the bounding box and the overview statistics to // determine the width and height at the highest resolution if (statistics instanceof BoundingBoxDataStatistics) { final BoundingBoxDataStatistics<?> bboxStats = (BoundingBoxDataStatistics<?>) statistics; final GeneralEnvelope env = new GeneralEnvelope( new Rectangle2D.Double( bboxStats.getMinX(), bboxStats.getMinY(), bboxStats.getWidth(), bboxStats.getHeight())); env.setCoordinateReferenceSystem(GeoWaveGTRasterFormat.DEFAULT_CRS); return env; } return null; } @Override public CoordinateReferenceSystem getCoordinateReferenceSystem() { return GeoWaveGTRasterFormat.DEFAULT_CRS; } @Override public CoordinateReferenceSystem getCoordinateReferenceSystem( final String coverageName ) { return GeoWaveGTRasterFormat.DEFAULT_CRS; } @Override public GridEnvelope getOriginalGridRange() { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public GridEnvelope getOriginalGridRange( final String coverageName ) { DataStatistics<?> statistics = geowaveStatisticsStore.getDataStatistics( new ByteArrayId( coverageName), BoundingBoxDataStatistics.STATS_TYPE, authorizationSPI.getAuthorizations()); int width = 0; int height = 0; // try to use both the bounding box and the overview statistics to // determine the width and height at the highest resolution if (statistics instanceof BoundingBoxDataStatistics) { final BoundingBoxDataStatistics<?> bboxStats = (BoundingBoxDataStatistics<?>) statistics; statistics = geowaveStatisticsStore.getDataStatistics( new ByteArrayId( coverageName), OverviewStatistics.STATS_TYPE, authorizationSPI.getAuthorizations()); if (statistics instanceof OverviewStatistics) { final OverviewStatistics overviewStats = (OverviewStatistics) statistics; width = (int) Math .ceil(((bboxStats.getMaxX() - bboxStats.getMinX()) / overviewStats.getResolutions()[0] .getResolution(0))); height = (int) Math .ceil(((bboxStats.getMaxY() - bboxStats.getMinY()) / overviewStats.getResolutions()[0] .getResolution(1))); } } return new GridEnvelope2D( 0, 0, width, height); } @Override public MathTransform getOriginalGridToWorld( final PixelInCell pixInCell ) { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public MathTransform getOriginalGridToWorld( final String coverageName, final PixelInCell pixInCell ) { // just reuse super class implementation but ensure that we do not use a // cached raster2model synchronized (this) { raster2Model = null; return super.getOriginalGridToWorld( coverageName, pixInCell); } } @Override public GridCoverage2D read( final GeneralParameterValue[] parameters ) throws IllegalArgumentException, IOException { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } /* * (non-Javadoc) * * @see * org.opengis.coverage.grid.GridCoverageReader#read(org.opengis.parameter * .GeneralParameterValue []) */ @Override public GridCoverage2D read( final String coverageName, final GeneralParameterValue[] params ) throws IOException { if (!checkName(coverageName)) { LOGGER.warn("Unable to find data adapter for '" + coverageName + "'"); return null; } final Date start = new Date(); // ///////////////////////////////////////////////////////////////////// // // Checking params // // ///////////////////////////////////////////////////////////////////// Color outputTransparentColor = null; Color backgroundColor = null; Interpolation interpolation = null; Rectangle dim = null; GeneralEnvelope requestedEnvelope = null; if (params != null) { for (final GeneralParameterValue generalParameterValue : params) { final Parameter<Object> param = (Parameter<Object>) generalParameterValue; if (param.getDescriptor().getName().getCode().equals( AbstractGridFormat.READ_GRIDGEOMETRY2D.getName().toString())) { final GridGeometry2D gg = (GridGeometry2D) param.getValue(); requestedEnvelope = (GeneralEnvelope) gg.getEnvelope(); dim = gg.getGridRange2D().getBounds(); } else if (param.getDescriptor().getName().getCode().equals( GeoWaveGTRasterFormat.OUTPUT_TRANSPARENT_COLOR.getName().toString())) { outputTransparentColor = (Color) param.getValue(); } else if (param.getDescriptor().getName().getCode().equals( AbstractGridFormat.BACKGROUND_COLOR.getName().toString())) { backgroundColor = (Color) param.getValue(); } else if (param.getDescriptor().getName().getCode().equals( AbstractGridFormat.INTERPOLATION.getName().toString())) { interpolation = (Interpolation) param.getValue(); } } } final GridCoverage2D coverage = renderGridCoverage( coverageName, dim, requestedEnvelope, backgroundColor, outputTransparentColor, interpolation); LOGGER.info("GeoWave Raster Reader needs : " + ((new Date()).getTime() - start.getTime()) + " millisecs"); return coverage; } public GridCoverage2D renderGridCoverage( final String coverageName, final Rectangle dim, final GeneralEnvelope generalEnvelope, Color backgroundColor, Color outputTransparentColor, final Interpolation interpolation ) throws IOException { if (backgroundColor == null) { backgroundColor = AbstractGridFormat.BACKGROUND_COLOR.getDefaultValue(); } if (outputTransparentColor == null) { outputTransparentColor = GeoWaveGTRasterFormat.OUTPUT_TRANSPARENT_COLOR.getDefaultValue(); } final GeoWaveRasterReaderState state = new GeoWaveRasterReaderState( coverageName); state.setRequestedEnvelope(generalEnvelope); // ///////////////////////////////////////////////////////////////////// // // Loading tiles trying to optimize as much as possible // // ///////////////////////////////////////////////////////////////////// final GridCoverage2D coverage = loadTiles( coverageName, backgroundColor, outputTransparentColor, interpolation, dim, state, crs, getOriginalEnvelope(coverageName)); return coverage; } /** * @param backgroundColor * the background color * @param outputTransparentColor * the transparent color * @param pixelDimension * @return the gridcoverage as the final result * @throws IOException */ private GridCoverage2D loadTiles( final String coverageName, final Color backgroundColor, final Color outputTransparentColor, Interpolation interpolation, final Rectangle pixelDimension, final GeoWaveRasterReaderState state, final CoordinateReferenceSystem crs, final GeneralEnvelope originalEnvelope ) throws IOException { transformRequestEnvelope( state, crs); // ///////////////////////////////////////////////////////////////////// // // Check if we have something to load by intersecting the requested // envelope with the bounds of the data set. If not, give warning // // ///////////////////////////////////////////////////////////////////// if (!state.getRequestEnvelopeTransformed().intersects( originalEnvelope, true)) { LOGGER.warn("The requested envelope does not intersect the envelope of this mosaic"); LOGGER.warn(state.getRequestEnvelopeTransformed().toString()); LOGGER.warn(originalEnvelope.toString()); return null; } final ImageReadParam readP = new ImageReadParam(); final Integer imageChoice; final RasterDataAdapter adapter = (RasterDataAdapter) geowaveAdapterStore.getAdapter(new ByteArrayId( coverageName)); if (pixelDimension != null) { try { synchronized (this) { if (!setupResolutions(coverageName)) { LOGGER.warn("Cannot find the overview statistics for the requested coverage name"); return coverageFactory.create( coverageName, RasterUtils.getEmptyImage( (int) pixelDimension.getWidth(), (int) pixelDimension.getHeight(), backgroundColor, outputTransparentColor, adapter.getColorModel()), state.getRequestedEnvelope()); } imageChoice = setReadParams( state.getCoverageName(), OverviewPolicy.getDefaultPolicy(), readP, state.getRequestEnvelopeTransformed(), pixelDimension); } readP.setSourceSubsampling( 1, 1, 0, 0); } catch (final TransformException e) { LOGGER.error( e.getLocalizedMessage(), e); return coverageFactory.create( coverageName, RasterUtils.getEmptyImage( (int) pixelDimension.getWidth(), (int) pixelDimension.getHeight(), backgroundColor, outputTransparentColor, adapter.getColorModel()), state.getRequestedEnvelope()); } } else { imageChoice = Integer.valueOf(0); } final double[][] resolutionLevels = getResolutionLevels(coverageName); final Histogram histogram; boolean equalizeHistogram; if (config.isEqualizeHistogramOverrideSet()) { equalizeHistogram = config.isEqualizeHistogramOverride(); } else { equalizeHistogram = adapter.isEqualizeHistogram(); } if (equalizeHistogram) { histogram = getHistogram( coverageName, resolutionLevels[imageChoice.intValue()][0], resolutionLevels[imageChoice.intValue()][1]); } else { histogram = null; } boolean scaleTo8Bit = true; // default to always scale to 8-bit boolean scaleTo8BitSet = config.isScaleTo8BitSet(); if (scaleTo8BitSet) { scaleTo8Bit = config.isScaleTo8Bit(); } try (final CloseableIterator<GridCoverage> gridCoverageIt = queryForTiles( pixelDimension, state.getRequestEnvelopeTransformed(), resolutionLevels[imageChoice.intValue()][0], resolutionLevels[imageChoice.intValue()][1], adapter)) { // allow the config to override the WMS request if (config.isInterpolationOverrideSet()) { interpolation = config.getInterpolationOverride(); } // but don't allow the default adapter interpolation to override the // WMS request else if (interpolation == null) { interpolation = adapter.getInterpolation(); } final GridCoverage2D result = RasterUtils.mosaicGridCoverages( gridCoverageIt, backgroundColor, outputTransparentColor, pixelDimension, state.getRequestEnvelopeTransformed(), resolutionLevels[imageChoice.intValue()][0], resolutionLevels[imageChoice.intValue()][1], adapter.getNoDataValuesPerBand(), state.isXAxisSwitch(), coverageFactory, state.getCoverageName(), interpolation, histogram, scaleTo8BitSet, scaleTo8Bit, adapter.getColorModel()); return transformResult( result, pixelDimension, state); } } private boolean setupResolutions( final String coverageName ) throws IOException { // this is a bit of a hack to avoid copy and pasting large // portions of the inherited class, which does not handle // multiple coverage names final double[][] resLevels = getResolutionLevels(coverageName); if (resLevels.length == 0) { return false; } numOverviews = resLevels.length - 1; highestRes = resLevels[0]; if (numOverviews > 0) { overViewResolutions = new double[numOverviews][]; System.arraycopy( resLevels, 1, overViewResolutions, 0, numOverviews); } else { overViewResolutions = new double[][] {}; } this.coverageName = coverageName; return true; } private CloseableIterator<GridCoverage> queryForTiles( final Rectangle pixelDimension, final GeneralEnvelope requestEnvelope, final double levelResX, final double levelResY, final RasterDataAdapter adapter ) throws IOException { return queryForTiles( adapter, new IndexOnlySpatialQuery( new GeometryFactory().toGeometry(new Envelope( requestEnvelope.getMinimum(0), requestEnvelope.getMaximum(0), requestEnvelope.getMinimum(1), requestEnvelope.getMaximum(1)))), new double[] { levelResX * adapter.getTileSize(), levelResY * adapter.getTileSize() }); } private CloseableIterator<GridCoverage> queryForTiles( final RasterDataAdapter adapter, final Query query, final double[] targetResolutionPerDimension ) { final AdapterToIndexMapping adapterIndexMapping = geowaveAdapterIndexMappingStore.getIndicesForAdapter(adapter .getAdapterId()); final PrimaryIndex[] indices = adapterIndexMapping.getIndices(geowaveIndexStore); // just work on the first spatial only index that contains this adapter // ID // TODO consider the best strategy for handling temporal queries here for (final PrimaryIndex rasterIndex : indices) { if (SpatialDimensionalityTypeProvider.isSpatial(rasterIndex)) { // determine the correct tier to query for the given resolution final HierarchicalNumericIndexStrategy strategy = CompoundHierarchicalIndexStrategyWrapper .findHierarchicalStrategy(rasterIndex.getIndexStrategy()); if (strategy != null) { final TreeMap<Double, SubStrategy> sortedStrategies = new TreeMap<Double, SubStrategy>(); SubStrategy targetIndexStrategy = null; for (final SubStrategy subStrategy : strategy.getSubStrategies()) { final double[] idRangePerDimension = subStrategy .getIndexStrategy() .getHighestPrecisionIdRangePerDimension(); double rangeSum = 0; for (final double range : idRangePerDimension) { rangeSum += range; } // sort by the sum of the range in each dimension sortedStrategies.put( rangeSum, subStrategy); } for (final SubStrategy subStrategy : sortedStrategies.descendingMap().values()) { final double[] highestPrecisionIdRangePerDimension = subStrategy .getIndexStrategy() .getHighestPrecisionIdRangePerDimension(); // if the id range is less than or equal to the target // resolution in each dimension, use this substrategy boolean withinTargetResolution = true; for (int d = 0; d < highestPrecisionIdRangePerDimension.length; d++) { if (highestPrecisionIdRangePerDimension[d] > targetResolutionPerDimension[d]) { withinTargetResolution = false; break; } } if (withinTargetResolution) { targetIndexStrategy = subStrategy; break; } } if (targetIndexStrategy == null) { // if there is not a substrategy that is within the // target // resolution, use the first substrategy (the lowest // range // per // dimension, which is the highest precision) targetIndexStrategy = sortedStrategies.firstEntry().getValue(); } return geowaveDataStore.query( new QueryOptions( adapter, new CustomIdIndex( // replace the index strategy with a // single // substrategy that fits the target // resolution targetIndexStrategy.getIndexStrategy(), rasterIndex.getIndexModel(), rasterIndex.getId()), // make sure // the // index ID // is // the authorizationSPI.getAuthorizations()), // same as the orginal so that we // are querying the correct table query); } else { return geowaveDataStore.query( new QueryOptions( adapter, rasterIndex, authorizationSPI.getAuthorizations()), query); } } } return new Wrapper( Collections.emptyIterator()); } private GridCoverage2D transformResult( final GridCoverage2D coverage, final Rectangle pixelDimension, final GeoWaveRasterReaderState state ) { if (state.getRequestEnvelopeTransformed() == state.getRequestedEnvelope()) { return coverage; // nothing to do } GridCoverage2D result = null; LOGGER.info("Image reprojection necessary"); result = (GridCoverage2D) RasterUtils.getCoverageOperations().resample( coverage, state.getRequestedEnvelope().getCoordinateReferenceSystem()); return coverageFactory.create( result.getName(), result.getRenderedImage(), result.getEnvelope()); } /** * transforms (if necessary) the requested envelope into the CRS used by * this reader. * * @throws DataSourceException */ public static void transformRequestEnvelope( final GeoWaveRasterReaderState state, final CoordinateReferenceSystem crs ) throws DataSourceException { if (CRS.equalsIgnoreMetadata( state.getRequestedEnvelope().getCoordinateReferenceSystem(), crs)) { state.setRequestEnvelopeTransformed(state.getRequestedEnvelope()); return; // and finish } try { /** Buffered factory for coordinate operations. */ // transforming the envelope back to the dataset crs in final MathTransform transform = OPERATION_FACTORY.createOperation( state.getRequestedEnvelope().getCoordinateReferenceSystem(), crs).getMathTransform(); if (transform.isIdentity()) { // Identity Transform ? state.setRequestEnvelopeTransformed(state.getRequestedEnvelope()); return; // and finish } state.setRequestEnvelopeTransformed(CRS.transform( transform, state.getRequestedEnvelope())); state.getRequestEnvelopeTransformed().setCoordinateReferenceSystem( crs); // if (config.getIgnoreAxisOrder() == false) { // check for axis // order // required final int indexX = indexOfX(crs); final int indexY = indexOfY(crs); final int indexRequestedX = indexOfX(state.getRequestedEnvelope().getCoordinateReferenceSystem()); final int indexRequestedY = indexOfY(state.getRequestedEnvelope().getCoordinateReferenceSystem()); // x Axis problem ??? if ((indexX == indexRequestedY) && (indexY == indexRequestedX)) { state.setXAxisSwitch(true); final Rectangle2D tmp = new Rectangle2D.Double( state.getRequestEnvelopeTransformed().getMinimum( 1), state.getRequestEnvelopeTransformed().getMinimum( 0), state.getRequestEnvelopeTransformed().getSpan( 1), state.getRequestEnvelopeTransformed().getSpan( 0)); state.setRequestEnvelopeTransformed(new GeneralEnvelope( tmp)); state.getRequestEnvelopeTransformed().setCoordinateReferenceSystem( crs); } else if ((indexX == indexRequestedX) && (indexY == indexRequestedY)) { // everything is fine } else { throw new DataSourceException( "Unable to resolve the X Axis problem"); } // } } catch (final Exception e) { throw new DataSourceException( "Unable to create a coverage for this source", e); } } @Override public Set<ParameterDescriptor<List>> getDynamicParameters() throws IOException { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public Set<ParameterDescriptor<List>> getDynamicParameters( final String coverageName ) throws IOException { return Collections.emptySet(); } @Override public double[] getReadingResolutions( final OverviewPolicy policy, final double[] requestedResolution ) throws IOException { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public double[] getReadingResolutions( final String coverageName, final OverviewPolicy policy, final double[] requestedResolution ) throws IOException { synchronized (this) { if (!setupResolutions(coverageName)) { LOGGER.warn("Cannot find the overview statistics for the requested coverage name"); return null; } return super.getReadingResolutions( coverageName, policy, requestedResolution); } } @Override public int getNumOverviews() { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public int getNumOverviews( final String coverageName ) { try { final double[][] resolutionLevels = getResolutionLevels(coverageName); return Math.max( 0, resolutionLevels.length - 1); } catch (final IOException e) { LOGGER.warn( "Unable to read resolution levels", e); } return 0; } @Override public ImageLayout getImageLayout() throws IOException { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public ImageLayout getImageLayout( final String coverageName ) throws IOException { if (!checkName(coverageName)) { LOGGER.warn("Unable to find data adapter for '" + coverageName + "'"); return null; } final RasterDataAdapter adapter = (RasterDataAdapter) geowaveAdapterStore.getAdapter(new ByteArrayId( coverageName)); final GridEnvelope gridEnvelope = getOriginalGridRange(); return new ImageLayout().setMinX( gridEnvelope.getLow(0)).setMinY( gridEnvelope.getLow(1)).setTileWidth( adapter.getTileSize()).setTileHeight( adapter.getTileSize()).setSampleModel( adapter.getSampleModel()).setColorModel( adapter.getColorModel()).setWidth( gridEnvelope.getHigh(0)).setHeight( gridEnvelope.getHigh(1)); } @Override public double[][] getResolutionLevels() throws IOException { throw new UnsupportedOperationException( "A coverage name must be provided, there is no support for a default coverage"); } @Override public double[][] getResolutionLevels( final String coverageName ) throws IOException { final DataStatistics<?> stats = geowaveStatisticsStore.getDataStatistics( new ByteArrayId( coverageName), OverviewStatistics.STATS_TYPE, authorizationSPI.getAuthorizations()); if ((stats != null) && (stats instanceof OverviewStatistics)) { final Resolution[] resolutions = ((OverviewStatistics) stats).getResolutions(); final double[][] retVal = new double[resolutions.length][]; int i = 0; for (final Resolution res : resolutions) { retVal[i++] = res.getResolutionPerDimension(); } return retVal; } return new double[][] {}; } private Histogram getHistogram( final String coverageName, final double resX, final double resY ) throws IOException { final DataStatistics<?> stats = geowaveStatisticsStore.getDataStatistics( new ByteArrayId( coverageName), HistogramStatistics.STATS_TYPE, authorizationSPI.getAuthorizations()); if ((stats != null) && (stats instanceof HistogramStatistics)) { return ((HistogramStatistics) stats).getHistogram(new Resolution( new double[] { resX, resY })); } else { LOGGER.warn("Cannot find histogram for coverage '" + coverageName + "'"); } return null; } /** * @param crs * CoordinateReference System * @return dimension index of y dir in crs */ private static int indexOfY( final CoordinateReferenceSystem crs ) { return indexOf( crs, UPDirections); } /** * @param crs * CoordinateReference System * @return dimension index of X dir in crs */ private static int indexOfX( final CoordinateReferenceSystem crs ) { return indexOf( crs, LEFTDirections); } private static int indexOf( final CoordinateReferenceSystem crs, final Set<AxisDirection> direction ) { final CoordinateSystem cs = crs.getCoordinateSystem(); for (int index = 0; index < cs.getDimension(); index++) { final CoordinateSystemAxis axis = cs.getAxis(index); if (direction.contains(axis.getDirection())) { return index; } } return -1; } }