/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.display3d.scene.loader; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.util.Collection; import javax.measure.IncommensurableException; import org.apache.sis.util.ArgumentChecks; import org.geotoolkit.image.interpolation.Interpolation; import org.geotoolkit.image.interpolation.InterpolationCase; import org.geotoolkit.image.interpolation.Resample; import org.geotoolkit.image.iterator.PixelIterator; import org.geotoolkit.image.iterator.PixelIteratorFactory; import org.apache.sis.referencing.CRS; import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.internal.referencing.j2d.AffineTransform2D; import org.geotoolkit.storage.coverage.AbstractGridMosaic; import org.geotoolkit.storage.coverage.GridMosaic; import org.geotoolkit.storage.coverage.GridMosaicRenderedImage; import org.geotoolkit.storage.coverage.Pyramid; import org.geotoolkit.storage.coverage.PyramidalCoverageReference; import org.geotoolkit.display.PortrayalException; import org.geotoolkit.display3d.utils.TextureUtils; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.NoninvertibleTransformException; import org.opengis.referencing.operation.TransformException; import org.opengis.util.FactoryException; import org.apache.sis.geometry.Envelopes; /** * Generate tile images for terrain. * * @author Thomas Rouby (Geomatys) * @author Johann Sorel (Geomatys) */ public class PyramidImageLoader implements ImageLoader{ private final PyramidalCoverageReference ref; private final Pyramid dataSource; private GridMosaicRenderedImage dataRenderedImage = null; private CoordinateReferenceSystem outputCrs; private MathTransform transformToOutput, transformFromOutput; public PyramidImageLoader(final PyramidalCoverageReference ref, final Pyramid dataSource) throws FactoryException, IncommensurableException { ArgumentChecks.ensureNonNull("pyramid", dataSource); this.ref = ref; this.dataSource = dataSource; } public PyramidalCoverageReference getCoverageReference() { return ref; } public void setOutputCRS(CoordinateReferenceSystem outputCrs) throws PortrayalException { this.outputCrs = outputCrs; try { createTransformOutput(); } catch (FactoryException | IncommensurableException ex) { throw new PortrayalException(ex); } } /** * Internal only, use setOutputCRS to recalculate output transform */ private void createTransformOutput() throws FactoryException, IncommensurableException { if (outputCrs != null){ final CoordinateReferenceSystem crsImg = this.dataSource.getCoordinateReferenceSystem(); transformToOutput = CRS.findOperation(crsImg, outputCrs, null).getMathTransform(); try { transformFromOutput = transformToOutput.inverse(); } catch (NoninvertibleTransformException ex) { transformFromOutput = CRS.findOperation(outputCrs, crsImg, null).getMathTransform(); } } } @Override public BufferedImage getBufferedImageOf(Envelope outputEnv, Dimension outputDimension) throws PortrayalException { if(outputCrs == null){ throw new PortrayalException("Output crs has not been set"); } if (!org.geotoolkit.referencing.CRS.equalsApproximatively(outputEnv.getCoordinateReferenceSystem(), outputCrs)){ this.setOutputCRS(outputEnv.getCoordinateReferenceSystem()); } final Envelope env; try { env = Envelopes.transform(transformFromOutput, outputEnv); } catch (TransformException ex) { throw new PortrayalException(ex); } final double scale = env.getSpan(0)/outputDimension.width; final int indexImg = TextureUtils.getNearestScaleIndex(dataSource.getScales(), scale); if (dataRenderedImage != null) { final GridMosaic gridMosaic = dataRenderedImage.getGridMosaic(); final double mosaicScale = gridMosaic.getScale(); final double mosaicIndex = TextureUtils.getNearestScaleIndex(dataSource.getScales(), mosaicScale); if (gridMosaic.getPyramid() != dataSource || mosaicIndex != indexImg) { final Collection<GridMosaic> mosaics = dataSource.getMosaics(indexImg); if (!mosaics.isEmpty()) { dataRenderedImage = new GridMosaicRenderedImage(mosaics.iterator().next()); } else { dataRenderedImage = null; return null; } } } else { final Collection<GridMosaic> mosaics = dataSource.getMosaics(indexImg); if (!mosaics.isEmpty()) { dataRenderedImage = new GridMosaicRenderedImage(mosaics.iterator().next()); } else { dataRenderedImage = null; return null; } } try { return extractTileImage(outputEnv, dataRenderedImage, transformFromOutput, outputDimension); } catch (TransformException ex) { throw new PortrayalException(ex); } } private static BufferedImage extractTileImage(final Envelope tileEnvelope, final GridMosaicRenderedImage dataRenderedImage, final MathTransform transformFromOutput, final Dimension tileSize) throws TransformException { if (dataRenderedImage == null) { return null; } final double targetTileWidth = tileSize.width; final double targetTileHeight = tileSize.height; final GridMosaic gridmosaic = dataRenderedImage.getGridMosaic(); final MathTransform mosaicCrsToMosaicGrid = AbstractGridMosaic.getTileGridToCRS(gridmosaic, new Point(0, 0)).inverse(); final AffineTransform2D targetGridToTargetCrs = new AffineTransform2D( tileEnvelope.getSpan(0)/targetTileWidth, 0, 0, -tileEnvelope.getSpan(1)/targetTileHeight, tileEnvelope.getMinimum(0), tileEnvelope.getMaximum(1)); final ColorModel sourceColorModel = dataRenderedImage.getColorModel(); final Raster prototype = dataRenderedImage.getData(new Rectangle(1, 1)); //prepare the output image final WritableRaster targetRaster = prototype.createCompatibleWritableRaster(tileSize.width, tileSize.height); final BufferedImage targetImage = new BufferedImage(sourceColorModel, targetRaster, sourceColorModel.isAlphaPremultiplied(), null); final MathTransform sourceToTarget = MathTransforms.concatenate( targetGridToTargetCrs, transformFromOutput, mosaicCrsToMosaicGrid); //resample image final double[] fillValue = new double[targetImage.getData().getNumBands()]; final PixelIterator it = PixelIteratorFactory.createRowMajorIterator(dataRenderedImage); final Interpolation interpol = Interpolation.create(it, InterpolationCase.NEIGHBOR, 2); final Resample resampler = new Resample(sourceToTarget, targetImage, interpol, fillValue); resampler.fillImage(); return targetImage; } }