Package org.locationtech.udig.tools.jgrass.profile

Source Code of org.locationtech.udig.tools.jgrass.profile.ProfileTool

/*
* uDig - User Friendly Desktop Internet GIS client
* (C) HydroloGIS - www.hydrologis.com
*
* 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 HydroloGIS BSD
* License v1.0 (http://udig.refractions.net/files/hsd3-v10.html).
*/
package org.locationtech.udig.tools.jgrass.profile;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.locationtech.udig.catalog.IGeoResource;
import org.locationtech.udig.project.EditManagerEvent;
import org.locationtech.udig.project.IEditManager;
import org.locationtech.udig.project.IEditManagerListener;
import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.ui.ApplicationGIS;
import org.locationtech.udig.project.ui.commands.AbstractDrawCommand;
import org.locationtech.udig.project.ui.render.displayAdapter.MapMouseEvent;
import org.locationtech.udig.project.ui.tool.SimpleTool;
import org.locationtech.udig.ui.ExceptionDetailsDialog;
import org.locationtech.udig.ui.PlatformGIS;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.ViewType;
import org.geotools.geometry.jts.JTS;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Coordinate;

import org.locationtech.udig.tools.jgrass.JGrassToolsPlugin;
import org.locationtech.udig.tools.jgrass.profile.borrowedfromjgrasstools.CoverageUtilities;
import org.locationtech.udig.tools.jgrass.profile.borrowedfromjgrasstools.ProfilePoint;
import org.locationtech.udig.tools.jgrass.profile.borrowedfromjgrasstools.RegionMap;

/**
* <p>
* Tool to draw raster map profiles.
* </p>
* <p>
* NOTE: this is an extention of the DistanceTool
* </p>
*
* @author Andrea Antonello - www.hydrologis.com
*/
public class ProfileTool extends SimpleTool implements IEditManagerListener {

    private int currentPointNumber = 0;

    private List<Point> points = new ArrayList<Point>();
    private ProfileFeedbackCommand command;
    private Point now;
    private double latestProgessiveDistance = 0;
    private boolean doubleClicked = false;

    private GridCoverage2D rasterMapResource;
    private ProfileView chartView;
    private Coordinate begin;
    private double step;

    private ILayer selectedLayer;

    public ProfileTool() {
        super(MOUSE | MOTION);

        IEditManager editManager = ApplicationGIS.getActiveMap().getEditManager();
        editManager.addListener(this);
        selectedLayer = editManager.getSelectedLayer();
    }

    @Override
    protected void onMousePressed( MapMouseEvent e ) {
        super.onMousePressed(e);
        checkFirstActivation();
    }

    protected void onMouseMoved( MapMouseEvent e ) {
        if (!doubleClicked) {
            // saving value to display the distance
            now = e.getPoint();
            if (command == null || points.isEmpty())
                return;
            Rectangle area = command.getValidArea();
            if (area != null)
                getContext().getViewportPane().repaint(area.x, area.y, area.width, area.height);
            else {
                getContext().getViewportPane().repaint();
            }
        }
    }

    public void onMouseReleased( MapMouseEvent e ) {
        // necessary to restart from begin, having an empty view
        if (now == null) {
            return;
        }
        if (currentPointNumber == 0) {
            chartView.clearSeries();
            latestProgessiveDistance = 0;
            points.clear();
            disposeCommand();
            doubleClicked = false;
            chartView.clearMarkers();
        }

        Point current = e.getPoint();
        // if enough points are there, create the profile
        if (points.isEmpty() || !current.equals(points.get(points.size() - 1))) {
            points.add(current);
        }

        /*
         * run with backgroundable progress monitoring
         */
        if (command == null || !command.isValid()) {
            command = new ProfileFeedbackCommand();
            getContext().sendASyncCommand(command);
        }

        try {
            profile(null);
        } catch (Exception ex) {
            ex.printStackTrace();

            String message = "An error occurred while extracting the profile from the map.";
            ExceptionDetailsDialog.openError(null, message, IStatus.ERROR, JGrassToolsPlugin.PLUGIN_ID, ex);
        }
    }

    protected void onMouseDoubleClicked( MapMouseEvent e ) {
        currentPointNumber = 0;
        doubleClicked = true;
    }

    /**
     * Removes all the line in the map
     */
    private void disposeCommand() {
        if (command != null) {
            command.setValid(false);
            Rectangle area = command.getValidArea();
            if (area != null)
                getContext().getViewportPane().repaint(area.x, area.y, area.width, area.height);
            else {
                getContext().getViewportPane().repaint();
            }
            command = null;
        }
    }

    /**
     * Creates the profile of the raster map.
     *
     * @param monitor the progress monitor.
     * @throws IOException
     */
    private void profile( IProgressMonitor monitor ) throws Exception {
        if (points.size() == currentPointNumber && points.size() > 1) {
            // no point added, do not read
            return;
        } else {
            if (!doubleClicked) {
                currentPointNumber = points.size();
            }
        }

        /*
         * need to get the profile of the last two clicked points
         */
        if (points.size() == 1) {
            Point beforeLastPoint = points.get(0);
            begin = getContext().pixelToWorld(beforeLastPoint.x, beforeLastPoint.y);
        } else if (points.size() > 1) {
            // monitor.beginTask("Extracting profile...", IProgressMonitor.UNKNOWN);

            Point lastPoint = points.get(points.size() - 1);
            Coordinate end = getContext().pixelToWorld(lastPoint.x, lastPoint.y);

            final List<ProfilePoint> profile = CoverageUtilities.doProfile(rasterMapResource, step, begin, end);
            begin = end;

            Display.getDefault().syncExec(new Runnable(){
                public void run() {
                    for( ProfilePoint profilePoint : profile ) {
                        double elevation = profilePoint.getElevation();
                        // if (!Double.isNaN(elevation)) {
                        chartView.addToSeries(latestProgessiveDistance + profilePoint.getProgressive(), elevation);
                        // } else {
                        // // chartView.addToSeries(latestProgessiveDistance +
                        // // profilePoint.getProgressive(), Double.NaN);
                        // }
                    }
                    ProfilePoint last = profile.get(profile.size() - 1);
                    chartView.addStopLine(latestProgessiveDistance + last.getProgressive());
                    chartView.setRangeToDataBounds();
                    latestProgessiveDistance = latestProgessiveDistance + last.getProgressive();
                }
            });

            // monitor.done();
        }

    }

    public void setActive( boolean active ) {

        if (!active) {
            cleanupOnDeactivation();
            IEditManager editManager = ApplicationGIS.getActiveMap().getEditManager();
            editManager.removeListener(this);
        }
        super.setActive(active);
    }

    private void cleanupOnDeactivation() {
        // on tool deactivation
        rasterMapResource = null;
        now = null;
        points.clear();
        doubleClicked = false;
        disposeCommand();
    }

    private void checkFirstActivation() {
        if (rasterMapResource == null) {
            final IGeoResource geoResource = selectedLayer.getGeoResource();
            if (geoResource.canResolve(GridCoverage.class)) {
                IRunnableWithProgress operation = new IRunnableWithProgress(){

                    public void run( IProgressMonitor pm ) throws InvocationTargetException, InterruptedException {
                        try {
                            rasterMapResource = (GridCoverage2D) geoResource.resolve(GridCoverage.class,
                                    new NullProgressMonitor());
                            rasterMapResource = rasterMapResource.view(ViewType.GEOPHYSICS);

                            RegionMap regionMap = CoverageUtilities.getRegionParamsFromGridCoverage(rasterMapResource);
                            double xres = regionMap.getXres();
                            double yres = regionMap.getYres();
                            step = Math.min(xres, yres);

                            Display.getDefault().syncExec(new Runnable(){
                                public void run() {
                                    final IStatusLineManager statusBar = getContext().getActionBars().getStatusLineManager();
                                    disposeCommand();
                                    if (statusBar == null)
                                        return; // shouldn't happen if the tool is being used.
                                    statusBar.setErrorMessage(null);
                                    statusBar.setMessage(null);
                                    try {
                                        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
                                                .showView(ProfileView.ID);
                                    } catch (PartInitException e) {
                                        e.printStackTrace();
                                    }
                                    chartView = ((ProfileView) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
                                            .getActivePage().findView(ProfileView.ID));
                                }
                            });
                        } catch (Exception e) {
                            e.printStackTrace();

                            String message = "Profile tool error";
                            ExceptionDetailsDialog.openError(null, message, IStatus.ERROR, JGrassToolsPlugin.PLUGIN_ID, e);
                        }
                    }
                };
                PlatformGIS.runInProgressDialog("Reading map for profile...", false, operation, false);

            } else {
                getContext().updateUI(new Runnable(){
                    public void run() {
                        Shell shell = PlatformUI.getWorkbench().getDisplay().getActiveShell();
                        MessageBox msgBox = new MessageBox(shell, SWT.ICON_ERROR);
                        msgBox.setMessage("The selected layer can't be read by the available datastores. Unable to create a profile on it.");
                        msgBox.open();
                    }
                });
                super.setActive(false);
                return;
            }

        }
    }

    private double distance() throws TransformException {
        if (points.isEmpty())
            return 0;
        Iterator<Point> iter = points.iterator();
        Point start = iter.next();
        double distance = 0;
        while( iter.hasNext() ) {
            Point current = iter.next();
            Coordinate begin = getContext().pixelToWorld(start.x, start.y);
            Coordinate end = getContext().pixelToWorld(current.x, current.y);
            distance += JTS.orthodromicDistance(begin, end, getContext().getCRS());
            start = current;
        }

        if (now != null) {
            Point current = now;
            Coordinate begin = getContext().pixelToWorld(start.x, start.y);
            Coordinate end = getContext().pixelToWorld(current.x, current.y);
            distance += JTS.orthodromicDistance(begin, end, getContext().getCRS());
        }
        return distance;
    }

    private void displayOnStatusBar( double distance ) {
        final IStatusLineManager statusBar = getContext().getActionBars().getStatusLineManager();

        if (statusBar == null)
            return; // shouldn't happen if the tool is being used.
        final String message = createMessage(distance);
        getContext().updateUI(new Runnable(){
            public void run() {
                statusBar.setErrorMessage(null);
                statusBar.setMessage(message);
            }
        });
    }

    /**
     * @param distance
     * @return
     */
    private String createMessage( double distance ) {
        String message = "";

        if (distance > 100000.0) {
            message = message.concat((int) (distance / 1000.0) + " km"); //$NON-NLS-1$
        } else if (distance > 10000.0) { // km + m
            message = message.concat(round(distance / 1000.0, 1) + " km"); //$NON-NLS-1$
        } else if (distance > 1000.0) { // km + m
            message = message.concat(round(distance / 1000.0, 2) + " km"); //$NON-NLS-1$
        } else if (distance > 100.0) { // m
            message = message.concat(round(distance, 1) + " m"); //$NON-NLS-1$
        } else if (distance > 1.0) { // m
            message = message.concat(round(distance, 2) + " m"); //$NON-NLS-1$
        } else { // mm
            message = message.concat(round(distance * 1000.0, 1) + " mm"); //$NON-NLS-1$
        }

        return message;
    }

    /**
     * Truncates a double to the given number of decimal places. Note: truncation at zero decimal
     * places will still show up as x.0, since we're using the double type.
     *
     * @param value number to round-off
     * @param decimalPlaces number of decimal places to leave
     * @return the rounded value
     */
    private double round( double value, int decimalPlaces ) {
        double divisor = Math.pow(10, decimalPlaces);
        double newVal = value * divisor;
        newVal = (Long.valueOf(Math.round(newVal)).intValue()) / divisor;
        return newVal;
    }

    /**
     */
    class ProfileFeedbackCommand extends AbstractDrawCommand {

        public Rectangle getValidArea() {
            return null;
        }

        public void run( IProgressMonitor monitor ) throws Exception {
            if (points.isEmpty())
                return;
            graphics.setColor(Color.BLACK);
            Iterator<Point> iter = points.iterator();
            Point start = iter.next();
            while( iter.hasNext() ) {
                Point current = iter.next();
                graphics.drawLine(start.x, start.y, current.x, current.y);
                start = current;
            }
            if (start == null || now == null)
                return;
            graphics.drawLine(start.x, start.y, now.x, now.y);
            double distance = distance();
            displayOnStatusBar(distance);

        }
    }

    @Override
    public void changed( EditManagerEvent event ) {
        if (event.getType() == EditManagerEvent.SELECTED_LAYER) {
            cleanupOnDeactivation();
            selectedLayer = (ILayer) event.getNewValue();
        }
    }
}
TOP

Related Classes of org.locationtech.udig.tools.jgrass.profile.ProfileTool

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.