/* * PenTool.java * * Created on April 21, 2005, 6:10 PM */ package ika.map.tools; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import java.util.*; import ika.geo.*; import ika.utils.*; import ika.gui.MapComponent; /** * MeasureTool - a tool to measure distances between two points. * @author Bernhard Jenny, Institute of Cartography, ETH Zurich. */ public class MeasureTool extends DoubleBufferedTool { /** * The location to start measuring. */ private Point2D.Double dragStartPos; /** * The current position to measur to. */ private Point2D.Double dragCurrentPos; /** * A set of MeasurToolListeners that will be informed when a new distance has * been computed. */ private Set listeners = new HashSet(); /** * Create a new instance. * @param mapComponent The MapComponent for which this MapTool provides its services. */ public MeasureTool(MapComponent mapComponent) { super(mapComponent); } public void deactivate() { reportClearDistance(); mapComponent.repaint(); } /** * Adds a MeasureToolListener. * @param listener The MeasureToolListener to add. */ public void addMeasureToolListener(MeasureToolListener listener) { if (listener == null) throw new IllegalArgumentException(); this.listeners.add(listener); } /** * Removes a MeasureToolListener. * @param listener The MeasureToolListener to remove. */ public void removeMeasureToolListener(MeasureToolListener listener) { this.listeners.remove(listener); } /** * Inform all registered MeasureToolListeners of a new distance. */ private void reportDistance(boolean finalDistance) { if (dragStartPos == null || dragCurrentPos == null) return; final double dx = dragCurrentPos.x - dragStartPos.x; final double dy = dragCurrentPos.y - dragStartPos.y; final double d = Math.sqrt(dx*dx+dy*dy); final double angle = Math.atan2(dy, dx); Iterator iterator = this.listeners.iterator(); while (iterator.hasNext()) { MeasureToolListener listener = (MeasureToolListener)iterator.next(); if (finalDistance) listener.newDistance(d, angle, this.mapComponent); else listener.distanceChanged(d, angle, this.mapComponent); } } /** * Inform all registered MeasureToolListeners that the distance is not valid anymore. */ private void reportClearDistance() { Iterator iterator = this.listeners.iterator(); while (iterator.hasNext()) { MeasureToolListener listener = (MeasureToolListener)iterator.next(); listener.clearDistance(); } } /** * The mouse was pressed down, while this MapTool was the active one. * @param point The location of the mouse in world coordinates. * @param evt The original event. */ public void mouseDown(Point2D.Double point, MouseEvent evt) { setMeasureCursor(); captureBackground(); } /** * The mouse starts a drag, while this MapTool was the active one. * @param point The location of the mouse in world coordinates. * @param evt The original event. */ public void startDrag(Point2D.Double point, MouseEvent evt) { setMeasureCursor(); this.dragStartPos = (Point2D.Double)point.clone(); } /** * The mouse location changed during a drag, while this MapTool was the active one. * @param point The location of the mouse in world coordinates. * @param evt The original event. */ public void updateDrag(Point2D.Double point, MouseEvent evt) { // just in case we didn't get a mousePressed-Event if (dragStartPos == null) { dragStartPos = (Point2D.Double)point.clone(); setMeasureCursor(); return; } // if this is the first time mouseDragged is called, capture the screen. if (dragCurrentPos == null) captureBackground(); dragCurrentPos = (Point2D.Double)point.clone(); mapComponent.repaint(); reportDistance(false); } /** * A drag ends, while this MapTool was the active one. * @param point The location of the mouse in world coordinates. * @param evt The original event. */ public void endDrag(Point2D.Double point, MouseEvent evt) { /* dragStartPos = null; dragCurrentPos = null; */ reportDistance(true); releaseBackground(); mapComponent.repaint(); setDefaultCursor(); } /** * Treat escape key events. Stop drawing the rectangle and revert to the * previous state, without doing anything. * The event can be consumed (return true) or be delegated to other * listeners (return false). * @param keyEvent The new key event. * @return True if the key event has been consumed, false otherwise. */ public boolean keyEvent(KeyEvent keyEvent) { final boolean keyReleased = keyEvent.getID() == KeyEvent.KEY_RELEASED; final boolean isEscapeKey = keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE; if (keyReleased && isEscapeKey) { dragStartPos = null; dragCurrentPos = null; releaseBackground(); mapComponent.repaint(); setDefaultCursor(); reportClearDistance(); } return false; } /** * Draw the interface elements of this MapTool. * @param rp The destination to draw to. */ public void draw(RenderParams rp) { if (dragStartPos == null || dragCurrentPos == null) return; this.mapComponent.shiftGraphics2DByBorderWidth(rp.g2d); // this.mapComponent.setupGraphics2DForDrawingInWorldCoordinates(rp.g2d); FIXME rp.g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rp.g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); final float scale = (float)this.mapComponent.getScaleFactor(); rp.g2d.setColor(Color.black); final double strokeWidth = 1. / mapComponent.getScaleFactor(); final BasicStroke stroke = new BasicStroke((float)strokeWidth); rp.g2d.setStroke(stroke); final Line2D line = new Line2D.Double(dragStartPos, dragCurrentPos); rp.g2d.draw(line); } /** * Utility method to change the cursor to a cross-hair cursor. */ private void setMeasureCursor() { mapComponent.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); } }