Package org.locationtech.udig.tutorials.rcp

Source Code of org.locationtech.udig.tutorials.rcp.OverviewMapViewer$LocationBoxMoveTool

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, 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.tutorials.rcp;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.List;

import org.locationtech.udig.catalog.wmsc.server.WMSTileSet;
import org.locationtech.udig.project.internal.ContextModelListenerAdapter;
import org.locationtech.udig.project.internal.Layer;
import org.locationtech.udig.project.internal.Map;
import org.locationtech.udig.project.internal.ProjectPackage;
import org.locationtech.udig.project.render.IViewportModelListener;
import org.locationtech.udig.project.render.ViewportModelEvent;
import org.locationtech.udig.project.render.ViewportModelEvent.EventType;
import org.locationtech.udig.project.render.displayAdapter.IMapDisplay;
import org.locationtech.udig.project.render.displayAdapter.IMapDisplayListener;
import org.locationtech.udig.project.render.displayAdapter.MapDisplayEvent;
import org.locationtech.udig.project.ui.commands.AbstractDrawCommand;
import org.locationtech.udig.project.ui.commands.IDrawCommand;
import org.locationtech.udig.project.ui.render.displayAdapter.MapMouseEvent;
import org.locationtech.udig.project.ui.render.displayAdapter.ViewportPane;
import org.locationtech.udig.project.ui.tool.AbstractModalTool;
import org.locationtech.udig.project.ui.viewers.MapViewer;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

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


/**
* An overview map viewer.
*
<p> This viewer will track the the main map and add/remove layers.
*  It also displays a blue box around the current area that is being
*  viewed.
</p>
*
* @author Emily Gouge
* @since 1.2.0
*/
public class OverviewMapViewer {
   
    private MapViewer mapviewer = null;
    private Map mainmap = null;

    private IViewportModelListener viewportListener = null;
    private ContextModelListenerAdapter contextListener = null;
    private IMapDisplayListener mapDisplayListener = null;
   
    private IDrawCommand rectDrawCommand = null;
   
   
    public OverviewMapViewer( Composite parent, int style, Map mainMap) {
        mapviewer = new MapViewer(parent, style);
        this.mainmap = mainMap;       
    }
   
    /**
     * Sets the map to use for the overview map.  Note that this should
     * only be done once the main map has a viewport model so
     * that the correct listeners can be created an added.
     *
     * @param map
     */
    public void setMap(Map map){
        if (mainmap.getViewportModel() == null){
            throw new IllegalStateException("Cannot set the map until the main map has a viewport model."); //$NON-NLS-1$
        }
        mapviewer.setMap(map);
        addContextListener();
        addViewportModelListener();
        addMapDisplayListener();
    }
   
    public Control getControl(){
        return mapviewer.getControl();
    }
    public void removeLocationBox(){
        if (rectDrawCommand != null){
            rectDrawCommand.setValid(false);
            rectDrawCommand = null;
        }
    }
   
    /**
     * Creates a location box - which tracks the viewport of the main map
     * in the overview window.
     */
    public void createLocationBox(ViewportPane mainMapViewportPane){
        final Map overviewMap = this.mapviewer.getMap();
        rectDrawCommand = new AbstractDrawCommand(){

            public Rectangle getValidArea() {
                return null;
            }

            public void run( IProgressMonitor monitor ) throws Exception {
                //draw a bounding box around the area that is associated
                //with the main map
                ReferencedEnvelope bounds = mainmap.getViewportModel().getBounds();
               
                double xmin = bounds.getMinX();
                double xmax = bounds.getMaxX();
                double ymin = bounds.getMinY();
                double ymax = bounds.getMaxY();
               
                 Point ll = overviewMap.getViewportModel().worldToPixel(new Coordinate(xmin, ymin));
                 Point ur = overviewMap.getViewportModel().worldToPixel(new Coordinate(xmax, ymax));
                
                
                 int width = ur.x - ll.x;
                 int height = ur.y - ll.y;
                 if (width < 2) width = 2;
                 if (height > -2) height = -2;
                
                 graphics.setLineWidth(1);
                 graphics.setColor(new Color(255,255,255,120));
                 graphics.drawRect(ll.x-1, ll.y+1, width+2, height-2);
                 graphics.drawRect(ll.x+1, ll.y-1, width-2, height+2);
                
                 graphics.setColor(Color.BLUE);
                 graphics.setLineWidth(1);
                 graphics.drawRect(ll.x, ll.y, width, height);
            }
           
        };
        mapviewer.getViewport().addDrawCommand(rectDrawCommand);
        //add tool to the location box
        //mapviewer.setModalTool(new LocationBoxMoveTool( mainMapViewportPane ));
    }
   
    /**
     * Add a context listener that listens to when layers are added/removed
     * from the map.
     */
    private void addContextListener(){
        final Map overviewmap = this.mapviewer.getMap();
        contextListener = new ContextModelListenerAdapter(){
            protected void layerAdded( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void manyLayersAdded( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void layerRemoved( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void manyLayersRemoved( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void zorderChanged( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void glyphChanged( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void styleChanged( Notification msg ) {
                updateMapAndRefresh(msg);
            }

            protected void visibilityChanged( Notification msg ) {
                updateMapAndRefresh(msg);
            }
          
            private void updateMapAndRefresh(Notification msg){
                overviewmap.getContextModel().eNotify(msg);
                ReferencedEnvelope bnds = findNewOverviewZoom(mainmap.getViewportModel().getBounds(), mainmap.getRenderManager().getMapDisplay(), mapviewer.getMap().getViewportModel().getBounds());
                mapviewer.getMap().getViewportModelInternal().setBounds(bnds);               
            }
        };
        mainmap.getContextModel().eAdapters().add(contextListener);
       
        //add a deep listener to listen to layer hide/show events
        Adapter layerVisibilityAdapter = new AdapterImpl(){
            @SuppressWarnings("unchecked")
            public void notifyChanged( final Notification msg ) {
                if (msg.getNotifier() instanceof Layer && msg.getFeatureID(Layer.class) == ProjectPackage.LAYER__VISIBLE) {
                    if (msg.getNewBooleanValue() != msg.getOldBooleanValue()){
                        // mapviewer needs refreshing
                        overviewmap.getRenderManager().refresh((Layer)msg.getNotifier(), null);
                    }
                }
            }
        };
        mainmap.addDeepAdapter(layerVisibilityAdapter);
    }
   
    /**
     * Adds a viewport model listener to call repaint when the viewport
     * is changed.
     */
    private void addViewportModelListener() {
        viewportListener = new IViewportModelListener(){
            public void changed( ViewportModelEvent event ) {
                if (event.getType() == EventType.CRS){
                    //need to update the overview map crs
                    CoordinateReferenceSystem newcrs = (CoordinateReferenceSystem)event.getNewValue();
                    mapviewer.getMap().getViewportModelInternal().setCRS(newcrs);
                }else if (event.getType() == EventType.BOUNDS){
                    //bounds have changed change the overview box correspondingly
                    if (!mainmap.getViewportModel().isBoundsChanging()) {
                        ReferencedEnvelope bnds = findNewOverviewZoom(mainmap.getViewportModel().getBounds(), mainmap.getRenderManager().getMapDisplay(), mapviewer.getMap().getViewportModel().getBounds());
                        mapviewer.getMap().getViewportModelInternal().setBounds(bnds);

                    }
                    mapviewer.getViewport().repaint();
                }else{
                    // repaint to update the box representing the location
                    mapviewer.getViewport().repaint();
                }
            }

        };
        mainmap.getViewportModelInternal().addViewportModelListener(viewportListener);
       
        mapviewer.getViewport().addPaneListener(new IMapDisplayListener(){

            public void sizeChanged( MapDisplayEvent event ) {
                //update the bounds
                ReferencedEnvelope bnds = findNewOverviewZoom(mainmap.getViewportModel().getBounds(), mainmap.getRenderManager().getMapDisplay(), mapviewer.getMap().getViewportModel().getBounds());
                mapviewer.getMap().getViewportModelInternal().setBounds(bnds);
            }});
    }
   
    /**
     * Adds a map display listener that listens to map resize events.
     */
    private void addMapDisplayListener() {
        mapDisplayListener = new IMapDisplayListener(){
            public void sizeChanged( MapDisplayEvent event ) {
                // update the bounds
                mapviewer.getMap().getViewportModelInternal().setBounds(
                        mainmap.getBounds(new NullProgressMonitor()));
            }
        };

        mapviewer.getViewport().addPaneListener(mapDisplayListener);
    }
   
   
    public void dispose(){
        if(viewportListener != null){
            mainmap.getViewportModelInternal().removeViewportModelListener(viewportListener);
        }
        if (contextListener != null){
            mainmap.getContextModel().eAdapters().remove(contextListener);
        }
        if (mapDisplayListener != null){
            mapviewer.getViewport().removePaneListener(mapDisplayListener);
        }
        removeLocationBox();
        mapviewer.dispose();
    }
   
   
    /**
     * This function is called with the viewport bounds are changed or
     * the pane size is changed.  It computes new bounds for the overview map
     * based on the bounds (center point).  If one of the layers on the map can resolve to a
     * WMSTileSet it uses the resolutions associated with the tile set and finds the resolution that
     * is two larger than the current resolution to use for the overview.
     *
     * @param mainMapEnvelope
     * @param mainMapDisplay
     * @param overviewMapEnvelope
     * @return
     */
    private ReferencedEnvelope findNewOverviewZoom(ReferencedEnvelope mainMapEnvelope, IMapDisplay  mainMapDisplay, ReferencedEnvelope overviewMapEnvelope) {
       
        //go through all the layers looking for a tiled resource
        List<Layer> layers = mainmap.getLayersInternal();
        for( Layer layer : layers ) {
            if (layer.getGeoResource().canResolve(WMSTileSet.class)){
                try {
                    WMSTileSet tiles = layer.getGeoResource().resolve(WMSTileSet.class,new NullProgressMonitor());
                   
                    double currres = mainMapEnvelope.getWidth() / mainMapDisplay.getWidth();
                   
                    double[] res = tiles.getResolutions();
                    //find the closest matching resolution
                    double diff = Math.abs(currres - res[0]);
                    int index = 0;
                    for( int i = 0; i < res.length; i++ ) {
                        if (Math.abs(currres - res[i]) < diff) {
                            index = i;
                            diff = Math.abs(currres - res[i]);
                        }
                    }
                    //find the fourth lower resolution  (anything less than 3 and the
                    //overview window usually isn't big enough to actually be useful)
                    index = index - 4;
                    if (index < 0) index = 0;

                    double newres = res[index];

                    // find the center of the screen
                    double centerx = mainMapEnvelope.getMedian(0);
                    double centery = mainMapEnvelope.getMedian(1);

                    // using the next resolution, screen size, and center of the screen
                    // compute a new bounding box
                    double pixelwidth = mapviewer.getViewport().getWidth();
                    double newunitwidth = newres * pixelwidth;
                    double xmin = centerx - (newunitwidth / 2.0);
                    double xmax = centerx + (newunitwidth / 2.0);

                    double newunitheight = newres * mapviewer.getViewport().getHeight();
                    double ymin = centery - (newunitheight / 2.0);
                    double ymax = centery + (newunitheight / 2.0);

                    // new bounding box
                    ReferencedEnvelope re = new ReferencedEnvelope(xmin, xmax, ymin, ymax,overviewMapEnvelope.getCoordinateReferenceSystem());
                    if (!mainMapEnvelope.contains((Envelope)re)){
                        return re;
                    }
                } catch (Exception ex) {
                }
            }
        }

        ReferencedEnvelope bnds = new ReferencedEnvelope(mainMapEnvelope);                                   
        bnds.expandBy(Math.max(bnds.getWidth() * 3, bnds.getHeight() * 3));
        //this may be too slow and may need to done in a job ??
        ReferencedEnvelope maximumExtent = mainmap.getBounds(new NullProgressMonitor());
        ReferencedEnvelope ret = new ReferencedEnvelope(maximumExtent.intersection(bnds), bnds.getCoordinateReferenceSystem());
        return ret;
    }
   
    /**
     * Tool to apply to the overview map viewer to
     * allow the viewbox to be moved around and
     * move the main box as well.
     *   
     *
     * @author Emily Gouge
     * @since 1.2.0
     */
    class LocationBoxMoveTool extends AbstractModalTool{
        ViewportPane mainMapVP;

        public LocationBoxMoveTool( ViewportPane mainMapVP){
            super(MOUSE | MOTION);
            this.mainMapVP = mainMapVP;

        }
       
        private boolean dragging = false;
        private org.eclipse.swt.graphics.Point startp = null;
       
        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseDragged(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseDragged( MapMouseEvent e ) {
            if (dragging){
                //determining the number of pixels moved in the overview
                org.eclipse.swt.graphics.Point p = Display.getCurrent().map((Canvas)mapviewer.getViewport(), null, e.x, e.y);
                int xdiff = p.x - startp.x;
                int ydiff = p.y - startp.y;
                //determine the coordinate difference
                Coordinate oldc = context.pixelToWorld(startp.x, startp.y);
                Coordinate newc = context.pixelToWorld(p.x, p.y);
                double xoffset = newc.x - oldc.x;
                double yoffset = newc.y - oldc.y;
               
                //determine the number of pixels on the main map
                Point p1 = mainmap.getViewportModel().worldToPixel(newc);
                Point p2 = mainmap.getViewportModel().worldToPixel(oldc);
                xdiff = p2.x - p1.x;
                ydiff = p2.y - p1.y;
               
                //compute and update bounds
                final ReferencedEnvelope bounds = mainmap.getViewportModel().getBounds();

                ReferencedEnvelope newbounds = new ReferencedEnvelope(bounds.getMinX() + xoffset,
                        bounds.getMaxX() + xoffset, bounds.getMinY() + yoffset, bounds.getMaxY()
                                + yoffset, bounds.getCoordinateReferenceSystem());



                //scroll
                ((Canvas) mainMapVP).scroll(xdiff, ydiff, 0, 0, mainMapVP.getWidth(), mainMapVP.getHeight(), true);
                startp = p;
                mainmap.getViewportModelInternal().setBounds(newbounds);
                mainMapVP.repaint();
            }
              
        }

        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mousePressed(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mousePressed( MapMouseEvent e ) {
            Coordinate start = getContext().pixelToWorld(e.x, e.y);
            if (mainmap.getViewportModelInternal().getBounds().contains(start)){
                dragging = true;
                startp = Display.getCurrent().map((Canvas) mapviewer.getViewport(), null, e.x, e.y);
                mainmap.getViewportModelInternal().setIsBoundsChanging(true);
            }
      
        }
        /**
         * @see org.locationtech.udig.project.ui.tool.AbstractTool#mouseReleased(org.locationtech.udig.project.render.displayAdapter.MapMouseEvent)
         */
        public void mouseReleased( MapMouseEvent e ) {
            if (dragging) {
                mainmap.getViewportModelInternal().setIsBoundsChanging(false);
                org.eclipse.swt.graphics.Point p = Display.getCurrent().map((Canvas)mapviewer.getViewport(), null, e.x, e.y);
                //determine the coordinate difference
                Coordinate oldc = context.pixelToWorld(startp.x, startp.y);
                Coordinate newc = context.pixelToWorld(p.x, p.y);
                double xoffset = newc.x - oldc.x;
                double yoffset = newc.y - oldc.y;
                               
                //compute and update bounds
                final ReferencedEnvelope bounds = mainmap.getViewportModel().getBounds();
                ReferencedEnvelope newbounds = new ReferencedEnvelope(bounds.getMinX() + xoffset,
                        bounds.getMaxX() + xoffset, bounds.getMinY() + yoffset, bounds.getMaxY()
                                + yoffset, bounds.getCoordinateReferenceSystem());
                mainmap.getViewportModelInternal().setBounds(newbounds);
                dragging = false;
            }
        }
    }
}
TOP

Related Classes of org.locationtech.udig.tutorials.rcp.OverviewMapViewer$LocationBoxMoveTool

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.