Package org.locationtech.udig.project.ui.internal.commands.draw

Source Code of org.locationtech.udig.project.ui.internal.commands.draw.DrawFeatureCommand

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2004, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*
*/
package org.locationtech.udig.project.ui.internal.commands.draw;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.render.displayAdapter.IMapDisplay;
import org.locationtech.udig.project.ui.commands.AbstractDrawCommand;
import org.locationtech.udig.project.ui.internal.ProjectUIPlugin;
import org.locationtech.udig.ui.Drawing;
import org.locationtech.udig.ui.PlatformGIS;
import org.locationtech.udig.ui.graphics.AWTGraphics;
import org.locationtech.udig.ui.graphics.AWTSWTImageUtils;
import org.locationtech.udig.ui.graphics.SWTGraphics;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.Symbolizer;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;

/**
* Draws a feature on the screen.
*
* @author jeichar
* @since 0.9
*/
public class DrawFeatureCommand extends AbstractDrawCommand {

    private SimpleFeature feature;
    private static final Map<MathTransformKey, MathTransform> mtCache=new ConcurrentHashMap<MathTransformKey, MathTransform>();

    private Drawing drawing = Drawing.create();
    private CoordinateReferenceSystem featureCRS;

    Symbolizer[] syms;

    private Color color=Color.ORANGE;

    private MathTransform mt;
    /**
     * The location that the image should be drawn at.
     */
//    private Point imageLocation;
    /**
     * The image of the drawn feature. 
     * @see #preRender()
     */
    private Image image;
    private boolean errorReported;
   
    /**
     * @param feature
     * @param layer layer that feature is from
     * @throws IOException
     */
    public DrawFeatureCommand( SimpleFeature feature, ILayer layer ) throws IOException {
        this(feature, layer.getCRS());
    }

    /**
     * @param feature
     * @param crs
     */
    public DrawFeatureCommand( SimpleFeature feature, CoordinateReferenceSystem crs ) {
        this.feature = feature;
        if (crs == null)
            this.featureCRS = DefaultGeographicCRS.WGS84;
        else
            this.featureCRS = crs;
    }

    /**
     * @param feature
     */
    public DrawFeatureCommand( SimpleFeature feature ) {
        this(feature, feature.getFeatureType().getCoordinateReferenceSystem());
    }
   
    /**
     * Renders the feature to a image buffer so that drawing command will be fast.
     * If feature is large you should call this so that there isn't a big delay in the display
     * thread.
     * <p>
     * setMap() must be called before calling this method.
     * </p>
     * <p>
     * If this method is called then this object must be sent to the ViewportPane or be disposed
     * because a Image object is created that needs to be disposed.
     * </p>
     *
     */
    public void preRender(){
       
        if( BUFFER_READY ){
       
            PlatformGIS.syncInDisplayThread(new Runnable(){
                public void run() {
                    renderInternal();
                }
            });
        }
    }
   
    private void renderInternal(){
        if( syms==null ) {
            syms = Drawing.getSymbolizers(((Geometry)feature.getDefaultGeometry()).getClass(), color,false);
        }
        MathTransform mt = getMathTransform(featureCRS);
        AffineTransform toScreen=getMap().getViewportModel().worldToScreenTransform();

        // calculate the size of the image and where it will be in the display
        Envelope envelope;
        try{
            ReferencedEnvelope bounds = new ReferencedEnvelope(feature.getBounds());
            envelope = bounds.transform(getMap().getViewportModel().getCRS(), true);
        }catch (Exception e) {
            envelope=new ReferencedEnvelope(feature.getBounds());
        }
        double[] screenbounds=new double[]{
                envelope.getMinX(), envelope.getMinY(),
                envelope.getMaxX(), envelope.getMaxY(),
                };
        toScreen.transform(screenbounds, 0, screenbounds, 0, 2);
       
//        imageLocation=new Point((int)(Math.min(screenbounds[0], screenbounds[2])), (int)(Math.min(screenbounds[1], screenbounds[3])) );
       
        int width = (int) Math.abs(screenbounds[2]-screenbounds[0]);
        int height = (int) Math.abs(screenbounds[3]-screenbounds[1]);
        //create transparent image
        image=AWTSWTImageUtils.createDefaultImage(Display.getDefault(), width, height);
       
        // draw feature
        SWTGraphics graphics=new SWTGraphics(image, Display.getDefault());
       
        drawing.drawFeature(graphics, feature,
                getMap().getViewportModel().worldToScreenTransform(envelope, new Dimension(width,height)), false, syms, mt);
        graphics.dispose();
    }
   
    /** I haven't been able to get the SWT image buffer going yet
     * So this flag is so I can quickly enable the unstable code for
     * development and disable it for committing my changes.
     */
    private static final boolean BUFFER_READY=false;

    /**
     * @see org.locationtech.udig.project.command.MapCommand#run()
     */
    public void run( IProgressMonitor monitor ) throws Exception {
        if( !BUFFER_READY || graphics instanceof AWTGraphics ){
            if( syms==null )
                syms = Drawing.getSymbolizers(((Geometry)feature.getDefaultGeometry()).getClass(), color, false);
            MathTransform mt = getMathTransform(featureCRS);
            drawing.drawFeature(graphics, feature,
                    getMap().getViewportModel().worldToScreenTransform(), false, syms, mt);
        }else{
            if( image==null ){
                preRender();
            }
//            graphics.drawImage(image, imageLocation.x, imageLocation.y);
        }
    }

    /**
     *
     * @return
     */
    private MathTransform getMathTransform(CoordinateReferenceSystem featureCRS) {
        MathTransformKey key=new MathTransformKey(featureCRS, getMap().getViewportModel().getCRS());
        mt=mtCache.get(key);
        if( mt==null ){
            try {
                mt = CRS.findMathTransform(featureCRS, getMap().getViewportModel().getCRS(), true);
            } catch (Exception e) {
                mt = null;
            }
            mtCache.put(key,mt);
        }
        return mt;
    }

    /**
     * @return Returns the color.
     */
    public Color getColor() {
        return color;
    }

    /**
     * @param color The color to set.
     */
    public void setColor( Color color ) {
        this.color = color;
    }
    /**
     * Allows the symbolizers to be set
     *
     * @param syms symbolizers to use to draw features. 
     */
    public void setSymbolizers( Symbolizer[] syms){
        if( syms==null )
            this.syms=new Symbolizer[0];
        else{

            this.syms=new Symbolizer[syms.length];
            System.arraycopy(syms, 0, this.syms, 0, this.syms.length);
        }
    }

    public Rectangle getValidArea() {
        if( feature!=null ){
            try {
                Envelope bounds = new ReferencedEnvelope(feature.getBounds()).transform(getMap().getViewportModel().getCRS(), true);
                double[] points=new double[]{bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY()};
                getMap().getViewportModel().worldToScreenTransform().transform(points, 0, points, 0, 2);
                return new Rectangle((int)points[0], (int)points[1], (int)Math.abs(points[2]-points[0]), (int)Math.abs(points[3]-points[1]));
            } catch (TransformException e) {
                if( !errorReported ){
                    errorReported = true;
                    ProjectUIPlugin.log("error calculating valid area, this will not be reported again", e);
                }
                return null;
            } catch (MismatchedDimensionException e) {
                if( !errorReported ){
                    errorReported = true;
                    ProjectUIPlugin.log("error calculating valid area, this will not be reported again", e);
                }
                return null;
            } catch (FactoryException e) {
                if( !errorReported ){
                    errorReported = true;
                    ProjectUIPlugin.log("error calculating valid area, this will not be reported again", e);
                }
                return null;
            }
        }
        return null;

    }

    public void setValid(boolean valid){
        super.setValid(valid);
        if( !valid )
            dispose();
    }
   
    protected void finalize(){
        dispose();
    }
    /**
     * Diposes of the image if it has been created.  Only needs to be called if the
     * command has not been sent to the {@link IMapDisplay}.
     */
    public void dispose(){
        if( image!=null && !image.isDisposed()){
            image.dispose();
            image=null;
        }
    }
   
    private static class MathTransformKey{
        final CoordinateReferenceSystem from, to;

        protected MathTransformKey(CoordinateReferenceSystem from, CoordinateReferenceSystem to){
            this.from=from;
            this.to=to;
        }
        @Override
        public int hashCode() {
            final int PRIME = 31;
            int result = 1;
            result = PRIME * result + ((from == null) ? 0 : from.hashCode());
            result = PRIME * result + ((to == null) ? 0 : to.hashCode());
            return result;
        }

        @Override
        public boolean equals( Object obj ) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            final MathTransformKey other = (MathTransformKey) obj;
            if (from == null) {
                if (other.from != null)
                    return false;
            } else if (!from.equals(other.from))
                return false;
            if (to == null) {
                if (other.to != null)
                    return false;
            } else if (!to.equals(other.to))
                return false;
            return true;
        }
       
    }
}
TOP

Related Classes of org.locationtech.udig.project.ui.internal.commands.draw.DrawFeatureCommand

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.