Package org.geotools.renderer.lite

Source Code of org.geotools.renderer.lite.RenderingTransformationHelper

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
*    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.geotools.renderer.lite;

import static org.geotools.resources.coverage.FeatureUtilities.*;

import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.jai.Interpolation;
import javax.media.jai.JAI;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.processing.CoverageProcessor;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.crs.ForceCoordinateSystemFeatureResults;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.SchemaException;
import org.geotools.filter.function.RenderingTransformation;
import org.geotools.filter.visitor.ExtractBoundsFilterVisitor;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.matrix.XAffineTransform;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.resources.coverage.FeatureUtilities;
import org.opengis.coverage.processing.Operation;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.FeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.expression.Expression;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransform2D;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Envelope;

/**
* Helper class that transforms the input data via rendering transformations. Rolled out
* so that it can be shared among {@link StreamingRenderer} and grid coverage direct rendering
* to {@link RenderedImage}
*/
public abstract class RenderingTransformationHelper {
   
    /** The logger for the rendering module. */
    private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.rendering");
   
    private final static FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(null);
   
   
    private static final CoverageProcessor PROCESSOR = CoverageProcessor.getInstance();
   
    // the crop and scale operations
    private static final Operation CROP = PROCESSOR.getOperation("CoverageCrop");
    private static final Operation SCALE = PROCESSOR.getOperation("Scale");

   
    public Object applyRenderingTransformation(Expression transformation,
            FeatureSource featureSource, Query layerQuery, Query renderingQuery,
            GridGeometry2D gridGeometry, CoordinateReferenceSystem sourceCrs, RenderingHints hints) throws IOException, SchemaException, TransformException, FactoryException  {
        Object result = null;
       
        // check if it's a wrapper coverage or a wrapped reader
        FeatureType schema = featureSource.getSchema();
        boolean isRasterData = false;
        if(schema instanceof SimpleFeatureType) {
            SimpleFeatureType simpleSchema = (SimpleFeatureType) schema;
            GridCoverage2D coverage = null;
            if(FeatureUtilities.isWrappedCoverage(simpleSchema) || FeatureUtilities.isWrappedCoverageReader(simpleSchema)) {
                isRasterData = true;

                // get the desired grid geometry
                GridGeometry2D readGG = gridGeometry;
                if(transformation instanceof RenderingTransformation) {
                    RenderingTransformation tx = (RenderingTransformation) transformation;
                    readGG = (GridGeometry2D) tx.invertGridGeometry(renderingQuery, gridGeometry);
                    // TODO: override the read params and force this grid geometry, or something
                    // similar to this (like passing it as a param to readCoverage
                }
               
                FeatureCollection<?,?> sample = featureSource.getFeatures();
                Feature gridWrapper = DataUtilities.first( sample );
               
                if(FeatureUtilities.isWrappedCoverageReader(simpleSchema)) {
                    final Object params = PARAMS_PROPERTY_NAME.evaluate(gridWrapper);
                    final GridCoverage2DReader reader = (GridCoverage2DReader) GRID_PROPERTY_NAME.evaluate(gridWrapper);
                    // don't read more than the native resolution (in case we are oversampling)
                    if(CRS.equalsIgnoreMetadata(reader.getCoordinateReferenceSystem(), gridGeometry.getCoordinateReferenceSystem())) {
                         MathTransform g2w = reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER);
                         if(g2w instanceof AffineTransform2D && readGG.getGridToCRS2D() instanceof AffineTransform2D) {
                             AffineTransform2D atOriginal = (AffineTransform2D) g2w;
                             AffineTransform2D atMap = (AffineTransform2D) readGG.getGridToCRS2D();
                             if(XAffineTransform.getScale(atMap) < XAffineTransform.getScale(atOriginal)) {
                                 // we need to go trough some convoluted code to make sure the new grid geometry
                                 // has at least one pixel
                                
                                 org.opengis.geometry.Envelope worldEnvelope = gridGeometry.getEnvelope();
                                 GeneralEnvelope transformed = org.geotools.referencing.CRS.transform(atOriginal.inverse(), worldEnvelope);
                                 int minx = (int) Math.floor(transformed.getMinimum(0));
                                 int miny = (int) Math.floor(transformed.getMinimum(1));
                                 int maxx = (int) Math.ceil(transformed.getMaximum(0));
                                 int maxy = (int) Math.ceil(transformed.getMaximum(1));
                                 Rectangle rect = new Rectangle(minx, miny, (maxx - minx), (maxy - miny));
                                 GridEnvelope2D gridEnvelope = new GridEnvelope2D(rect);
                                 readGG = new GridGeometry2D(gridEnvelope, atOriginal, worldEnvelope.getCoordinateReferenceSystem());
                             }
                         }
                    }
                    coverage = readCoverage(reader, params, readGG);
                } else {
                    coverage = (GridCoverage2D) GRID_PROPERTY_NAME.evaluate(gridWrapper);
                }
               
                // readers will return null if there is no coverage in the area
                if(coverage != null) {
                    if(readGG != null) {
                        // Crop will fail if we try to crop outside of the coverage area
                        ReferencedEnvelope renderingEnvelope = new ReferencedEnvelope(readGG.getEnvelope());
                        CoordinateReferenceSystem coverageCRS = coverage.getCoordinateReferenceSystem2D();
                        if(!CRS.equalsIgnoreMetadata(renderingEnvelope.getCoordinateReferenceSystem(), coverageCRS)) {
                            renderingEnvelope = renderingEnvelope.transform(coverageCRS, true);
                        }
                        if(coverage.getEnvelope2D().intersects(renderingEnvelope)) {
                            // the resulting coverage might be larger than the readGG envelope, shall we crop it?
                            final ParameterValueGroup param = CROP.getParameters();
                            param.parameter("Source").setValue(coverage);
                            param.parameter("Envelope").setValue(renderingEnvelope);
                            coverage = (GridCoverage2D) PROCESSOR.doOperation(param);
                        } else {
                            coverage = null;
                        }
                       
                        if(coverage != null) {
                            // we might also need to scale the coverage to the desired resolution
                            MathTransform2D coverageTx = readGG.getGridToCRS2D();
                            if(coverageTx instanceof AffineTransform) {
                                AffineTransform coverageAt = (AffineTransform) coverageTx;
                                AffineTransform renderingAt = (AffineTransform) gridGeometry.getGridToCRS2D();
                                // we adjust the scale only if we have many more pixels than required (30% or more)
                                final double ratioX = coverageAt.getScaleX() / renderingAt.getScaleX();
                                final double ratioY = coverageAt.getScaleY() / renderingAt.getScaleY();
                                if(ratioX < 0.7 && ratioY < 0.7) {
                                    // resolution is too different
                                    final ParameterValueGroup param = SCALE.getParameters();
                                    param.parameter("Source").setValue(coverage);
                                    param.parameter("xScale").setValue(ratioX);
                                    param.parameter("yScale").setValue(ratioY);
                                    final Interpolation interpolation = (Interpolation) hints.get(JAI.KEY_INTERPOLATION);
                                    if(interpolation != null) {
                                        param.parameter("Interpolation").setValue(interpolation);
                                    }
   
                                    coverage = (GridCoverage2D) PROCESSOR.doOperation(param);
                                }
                            }
                        }
                    }
                   
                    if(coverage != null) {
                        // apply the transformation
                        result = transformation.evaluate(coverage);
                    } else {
                        result = null;
                    }
                }
            }
        }
       
        if(result == null && !isRasterData) {
            // it's a transformation starting from vector data, let's see if we can optimize the query
            FeatureCollection originalFeatures;
            Query optimizedQuery = null;
            if(transformation instanceof RenderingTransformation) {
                RenderingTransformation tx = (RenderingTransformation) transformation;
                optimizedQuery = tx.invertQuery(renderingQuery, gridGeometry);
            }
            // if we could not find an optimized query no other choice but to just limit
            // ourselves to the bbox, we don't know if the transformation alters/adds attributes :-(
            if(optimizedQuery == null) {
                 Envelope bounds = (Envelope) renderingQuery.getFilter().accept(ExtractBoundsFilterVisitor.BOUNDS_VISITOR, null);
                 Filter bbox = new FastBBOX(filterFactory.property(""), bounds, filterFactory);
                 optimizedQuery = new Query(null, bbox);
                 optimizedQuery.setHints(layerQuery.getHints());
            }
           
            // grab the original features
            Query mixedQuery = DataUtilities.mixQueries(layerQuery, optimizedQuery, null);
            originalFeatures = featureSource.getFeatures(mixedQuery);
            originalFeatures = RendererUtilities.fixFeatureCollectionReferencing(originalFeatures, sourceCrs);
           
            // transform them
            result = transformation.evaluate(originalFeatures);
        }
       
        return result;
    }
   
    /**
     * Subclasses will override and provide means to read the coverage
     * @param reader
     * @param params
     * @param readGG
     * @return
     * @throws IOException
     */
    protected abstract GridCoverage2D readCoverage(GridCoverage2DReader reader, Object params,
            GridGeometry2D readGG) throws IOException;

   

}
TOP

Related Classes of org.geotools.renderer.lite.RenderingTransformationHelper

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.