/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2012, 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.processing.coverage.reducetodomain; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import org.apache.sis.geometry.DirectPosition2D; import org.geotoolkit.coverage.grid.GridCoverage2D; import org.geotoolkit.coverage.grid.GridCoverageBuilder; import org.geotoolkit.coverage.grid.GridEnvelope2D; import org.geotoolkit.coverage.grid.GridGeometry2D; import org.geotoolkit.internal.referencing.CRSUtilities; import org.geotoolkit.parameter.Parameters; import static org.geotoolkit.parameter.Parameters.*; import org.geotoolkit.processing.AbstractProcess; import org.geotoolkit.process.ProcessException; import org.geotoolkit.processing.coverage.straighten.StraightenDescriptor; import org.apache.sis.internal.referencing.j2d.AffineTransform2D; import org.geotoolkit.utility.parameter.ParametersExt; import org.opengis.coverage.Coverage; import org.opengis.metadata.spatial.PixelOrientation; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.RangeMeaning; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; /** * Fix possible coverage crossing the antimeridan. * * @author Johann Sorel (Geomatys) * @module */ public class ReduceToDomainProcess extends AbstractProcess { /** * Default constructor */ public ReduceToDomainProcess(final ParameterValueGroup input) { super(ReduceToDomainDescriptor.INSTANCE,input); } /** * * @param coverage coverage to process */ public ReduceToDomainProcess(Coverage coverage){ super(ReduceToDomainDescriptor.INSTANCE, asParameters(coverage)); } private static ParameterValueGroup asParameters(Coverage coverage){ final ParameterValueGroup params = ReduceToDomainDescriptor.INPUT_DESC.createValue(); ParametersExt.getOrCreateValue(params, ReduceToDomainDescriptor.COVERAGE_IN.getName().getCode()).setValue(coverage); return params; } /** * Execute process now. * * @return reduced coverage * @throws ProcessException */ public Coverage executeNow() throws ProcessException { execute(); return (Coverage) outputParameters.parameter(ReduceToDomainDescriptor.COVERAGE_OUT.getName().getCode()).getValue(); } /** * {@inheritDoc} */ @Override protected void execute() throws ProcessException { GridCoverage2D candidate = (GridCoverage2D) value(StraightenDescriptor.COVERAGE_IN, inputParameters); final CoordinateReferenceSystem crs = candidate.getCoordinateReferenceSystem2D(); final CoordinateReferenceSystem crs2d; try { crs2d = CRSUtilities.getCRS2D(crs); } catch (TransformException ex) { throw new ProcessException(ex.getMessage(), this, ex); } final boolean hack = true; final boolean[] wrapAround = new boolean[2]; final CoordinateSystem cs = crs2d.getCoordinateSystem(); for(int i=0;i<cs.getDimension();i++){ wrapAround[i] = crs instanceof GeographicCRS || (cs.getAxis(i).getRangeMeaning() == RangeMeaning.WRAPAROUND); } if (!(crs instanceof ProjectedCRS)) { if(!wrapAround[0] && !wrapAround[1]){ //no wrap around axis, can't fix anything. getOrCreate(StraightenDescriptor.COVERAGE_OUT, outputParameters).setValue(candidate); return; } } //straighten coverage--------------------------------------------------- final ParameterValueGroup subParams = StraightenDescriptor.INPUT_DESC.createValue(); Parameters.getOrCreate(StraightenDescriptor.COVERAGE_IN, subParams).setValue(candidate); final org.geotoolkit.process.Process subprocess = StraightenDescriptor.INSTANCE.createProcess(subParams); final ParameterValueGroup result; try{ result = subprocess.call(); }catch(ProcessException ex){ throw new ProcessException(ex.getMessage(), this, ex); } candidate = (GridCoverage2D) Parameters.getOrCreate(StraightenDescriptor.COVERAGE_OUT, result).getValue(); //resample coverage, we want it to be 'straight', no rotation or different axe scale. final GridGeometry2D gridgeom = candidate.getGridGeometry(); final GridEnvelope2D gridenv = gridgeom.getExtent2D(); final MathTransform gridToCRS = gridgeom.getGridToCRS2D(PixelOrientation.UPPER_LEFT); try{ final double[] coords = new double[2 * 2]; coords[0] = gridenv.getMinX(); coords[1] = gridenv.getMinY(); coords[2] = gridenv.getMaxX(); coords[3] = gridenv.getMaxY(); gridToCRS.transform(coords, 0, coords, 0, 2); double minX = coords[0]; double maxX = coords[2]; double minY = coords[3]; double maxY = coords[1]; double spanX = maxX-minX; double spanY = maxY-minY; double scaleX = spanX / gridenv.getWidth(); double scaleY = spanY / gridenv.getHeight(); double scale = Math.min(scaleX, scaleY); final double axiXMinValue; final double axiXMaxValue; final double axiYMinValue; final double axiYMaxValue; if(hack && crs2d instanceof GeographicCRS){ axiXMinValue = -180; axiXMaxValue = +180; axiYMinValue = -90; axiYMaxValue = +90; } else if (crs2d instanceof ProjectedCRS) { /* * Hack : we did not verified if base CRS is long/lat * this hack work only for Mercator and Plate Carré */ final MathTransform mt = ((ProjectedCRS)crs2d).getConversionFromBase().getMathTransform(); DirectPosition2D pt1 = new DirectPosition2D(-180, 0); pt1 = (DirectPosition2D) mt.transform(pt1, pt1); axiXMinValue = pt1.getX(); DirectPosition2D pt2 = new DirectPosition2D(180, 0); pt2 = (DirectPosition2D) mt.transform(pt2, pt2); axiXMaxValue = pt2.getX(); axiYMinValue = Double.NEGATIVE_INFINITY; axiYMaxValue = Double.POSITIVE_INFINITY; } else { axiXMinValue = cs.getAxis(0).getMinimumValue(); axiXMaxValue = cs.getAxis(0).getMinimumValue(); axiYMinValue = cs.getAxis(1).getMaximumValue(); axiYMaxValue = cs.getAxis(1).getMaximumValue(); } final boolean xWrap = (minX < axiXMinValue || maxX > axiXMaxValue); final boolean yWrap = (minY < axiYMinValue || maxY > axiYMaxValue); if( !xWrap && !yWrap ){ //nothing to fix getOrCreate(StraightenDescriptor.COVERAGE_OUT, outputParameters).setValue(candidate); return; } //calculate the fixed result image final AffineTransform2D baseTrs = (AffineTransform2D) candidate.getGridGeometry().getGridToCRS2D(PixelOrientation.UPPER_LEFT); final RenderedImage img = candidate.getRenderedImage(); final ColorModel cm = img.getColorModel(); final Raster baseRaster = img.getData(); final BufferedImage resimg; final AffineTransform2D gtc; final WritableRaster raster; if(xWrap && yWrap){ //wrap both axes raster = baseRaster.createCompatibleWritableRaster((int)(spanX/scale), (int)(spanY/scale)); resimg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); gtc = new AffineTransform2D( scale, 0, 0, -scale, axiXMinValue, axiYMaxValue); }else if(xWrap){ //wrap x axes raster = baseRaster.createCompatibleWritableRaster((int)(spanX/scale), img.getHeight()); resimg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); gtc = new AffineTransform2D( scale, 0, 0, -scale, axiXMinValue, baseTrs.getTranslateY()); }else{ //wrap y axes raster = baseRaster.createCompatibleWritableRaster(img.getWidth(), (int)(spanY/scale)); resimg = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); gtc = new AffineTransform2D( scale, 0, 0, -scale, baseTrs.getTranslateX(), axiYMaxValue); } final AffineTransform2D baseInv = baseTrs.inverse(); final AffineTransform2D resInv = gtc.inverse(); //draw base image final Point2D pt = new Point2D.Double(); AffineTransform tmp = new AffineTransform(resInv); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); final double crsSpanX = axiXMaxValue - axiXMinValue; final double crsSpanY = axiYMaxValue - axiYMinValue; if(xWrap){ pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(-crsSpanX, 0); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(+crsSpanX, 0); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); } if(yWrap){ pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(0,-crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(0,+crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); } if(xWrap && yWrap){ pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(-crsSpanX,-crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(-crsSpanX,+crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(+crsSpanX,-crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); pt.setLocation(0, 0); tmp = new AffineTransform(resInv); tmp.translate(+crsSpanX,+crsSpanY); tmp.concatenate(baseTrs); tmp.transform(pt, pt); raster.setRect((int)pt.getX(), (int)pt.getY(), baseRaster); } final GridCoverageBuilder gcb = new GridCoverageBuilder(); final GridGeometry2D gg = new GridGeometry2D(null, PixelOrientation.UPPER_LEFT, gtc,crs,null); gcb.setGridCoverage(candidate); gcb.setGridGeometry(gg); gcb.setRenderedImage(resimg); final GridCoverage2D outgc = gcb.getGridCoverage2D(); getOrCreate(StraightenDescriptor.COVERAGE_OUT, outputParameters).setValue(outgc); }catch(TransformException ex){ throw new ProcessException(ex.getMessage(), this, ex); } } }