/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.workbench.ui.zoom; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseWheelEvent; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import javax.swing.Icon; import javax.swing.Timer; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jump.workbench.ui.Viewport; import com.vividsolutions.jump.workbench.ui.cursortool.DragTool; import com.vividsolutions.jump.workbench.ui.images.IconLoader; import com.vividsolutions.jump.workbench.ui.renderer.RenderingManager; public abstract class AbstractZoomTool extends DragTool { static final double WHEEL_ZOOM_IN_FACTOR = 1.15; static final int BOX_TOLERANCE = 4; static final double ZOOM_IN_FACTOR = 2; protected Image origImage; protected Image auxImage = null; protected double scale = 1d; protected int mouseWheelCount = 0; protected Point2D.Double zoomTo = new Point2D.Double(0,0); private boolean isAnimatingZoom = false; //deafult to no zoom animation private Timer mouseWheelUpdateTimer = null; public boolean setAnimatingZoom(boolean animating) { boolean previousValue = isAnimatingZoom; isAnimatingZoom = animating; return previousValue; } public boolean getAnimatingZoom(){ return isAnimatingZoom; } public Icon getIcon() { return IconLoader.icon("Magnify.gif"); } public Cursor getCursor() { return createCursor(IconLoader.icon("MagnifyCursor.gif").getImage()); } protected void gestureFinished() throws NoninvertibleTransformException { } private Point2D cursor = null; public void mouseWheelMoved(MouseWheelEvent e) { int nclicks = e.getWheelRotation(); //negative is up/away mouseWheelCount = mouseWheelCount + nclicks; if (mouseWheelCount == 0) scale = 1d; else if (mouseWheelCount < 0) scale = Math.abs(mouseWheelCount)*WHEEL_ZOOM_IN_FACTOR; else scale = 1 / (mouseWheelCount*WHEEL_ZOOM_IN_FACTOR); try { cursor = e.getPoint(); if (mouseWheelUpdateTimer == null) { RenderingManager renderManager = getPanel().getRenderingManager(); renderManager.setPaintingEnabled(false); mouseWheelUpdateTimer = new Timer(700, new ActionListener() { public void actionPerformed(ActionEvent e) { try { //zoomAt(getCentre(), scale, false); zoomAt(cursor, scale, false); mouseWheelUpdateTimer.stop(); mouseWheelUpdateTimer = null; mouseWheelCount = 0; origImage = null; RenderingManager renderManager = getPanel().getRenderingManager(); renderManager.setPaintingEnabled(true); renderManager.repaintPanel(); } catch (NoninvertibleTransformException e1) { } } }); mouseWheelUpdateTimer.start(); mouseWheelUpdateTimer.setRepeats(false); cacheImage(); //scaleImageAtCentre(scale); scaleImageAtPoint(cursor, scale); } else { mouseWheelUpdateTimer.restart(); //scaleImageAtCentre(scale); scaleImageAtPoint(cursor, scale); } } catch (Throwable t) { getPanel().getContext().handleThrowable(t); } } protected void scaleImageAtCentre(double zoomFactor) { double w = getPanel().getWidth(); double h = getPanel().getHeight(); double dx = (w - (w * zoomFactor)) / 2; double dy = (h - (h * zoomFactor)) / 2; drawImage((int) dx, (int) dy, zoomFactor); } protected void scaleImageAtPoint(Point2D p, double zoomFactor) { double w = getPanel().getWidth(); double h = getPanel().getHeight(); double dx = (w - (w * zoomFactor)) / 2; double dy = (h - (h * zoomFactor)) / 2; double cx = w/2; double cy = h/2; double x1 = p.getX() - cx; double y1 = p.getY() - cy; double x2 = x1 - (x1 * zoomFactor); double y2 = y1 - (y1 * zoomFactor); dx += x2; dy += y2; drawImage((int) dx, (int) dy, zoomFactor); } /** * Creates a new Image if currImage doesn't exist * or is the wrong size for the panel. * @param currImage an image buffer * @return a new image, or the existing one if it's compatible */ public Image createImageIfNeeded(Image currImage) { if (currImage == null || currImage.getHeight(null) != getPanel().getHeight() || currImage.getWidth(null) != getPanel().getWidth()) { Graphics2D g = (Graphics2D) getPanel().getGraphics(); Image img = g.getDeviceConfiguration().createCompatibleImage( getPanel().getWidth(), getPanel().getHeight(), Transparency.OPAQUE); return img; } //return getPanel().createBlankPanelImage(); return currImage; } public void cacheImage() { origImage = createImageIfNeeded(origImage); getPanel().paint(origImage.getGraphics()); } protected Point2D getCentre() throws NoninvertibleTransformException { //zoom while keeping cursor over same model point double x = getPanel().getWidth() / 2; double y = getPanel().getHeight() / 2; return new Point2D.Double(x,y); } protected void zoomAt(Point2D p, double zoomFactor, boolean animatingZoom) throws NoninvertibleTransformException { //zoom while keeping cursor over same model point Viewport vp = getPanel().getViewport(); Point2D zoomPoint = vp.toModelPoint(p); Envelope modelEnvelope = vp.getEnvelopeInModelCoordinates(); Coordinate centre = modelEnvelope.centre(); double width = modelEnvelope.getWidth(); double height = modelEnvelope.getHeight(); double dx = (zoomPoint.getX() - centre.x) / zoomFactor; double dy = (zoomPoint.getY() - centre.y) / zoomFactor; Envelope zoomModelEnvelope = new Envelope( zoomPoint.getX() - (0.5 * (width / zoomFactor)) - dx, zoomPoint.getX() + (0.5 * (width / zoomFactor)) - dx, zoomPoint.getY() - (0.5 * (height / zoomFactor)) - dy, zoomPoint.getY() + (0.5 * (height / zoomFactor)) - dy); vp.zoom(zoomModelEnvelope); //getPanel().getViewport().zoomToViewPoint(p, zoomFactor); } public void drawImage(int dx, int dy, double scale) { double w = origImage.getWidth(getPanel()); double h = origImage.getHeight(getPanel()); double w2 = w * scale; double h2 = h * scale; auxImage = createImageIfNeeded(auxImage); Graphics2D g = (Graphics2D)auxImage.getGraphics(); RenderingHints rh = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHints(rh); g.setComposite(AlphaComposite.Src); g.setColor(Color.WHITE); g.fillRect(0, 0, auxImage.getWidth(getPanel()), auxImage.getHeight(getPanel())); g.drawImage(origImage,(int) dx,(int) dy,(int) w2,(int) h2, getPanel()); getPanel().getGraphics().drawImage(auxImage, 0, 0, getPanel()); } }