Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[udig-devel] PATCH


diff --git a/plugins/net.refractions.udig.project.ui/src/net/refractions/udig/project/ui/commands/TransformDrawCommand.java b/plugins/net.refractions.udig.project.ui/src/net/refractions/udig/project/ui/commands/TransformDrawCommand.java
index 2068980..eedef9f 100644
--- a/plugins/net.refractions.udig.project.ui/src/net/refractions/udig/project/ui/commands/TransformDrawCommand.java
+++ b/plugins/net.refractions.udig.project.ui/src/net/refractions/udig/project/ui/commands/TransformDrawCommand.java
@@ -14,6 +14,7 @@
  */
 package net.refractions.udig.project.ui.commands;
 
+import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
 
@@ -35,22 +36,30 @@ public class TransformDrawCommand extends AbstractDrawCommand
     private int translateY;
     private int translateX;
     private double rotation;
+    private Point fixedPoint;
 
     public Rectangle getValidArea() {
         return null;
     }
 
     public synchronized void run( IProgressMonitor monitor ) throws Exception {
+        if (fixedPoint == null) {
+            fixedPoint = new Point(display.getWidth() / 2, display.getHeight() / 2);
+        }
         AffineTransform t = new AffineTransform();
-        t.translate((double)display.getWidth()/(double)2, (double)display.getHeight()/(double)2);
+        t.translate(fixedPoint.getX(), fixedPoint.getY());
         t.rotate(rotation);
         t.scale(scaleFactorX, scaleFactorY);
-        t.translate((double)-display.getWidth()/(double)2, (double)-display.getHeight()/(double)2);
+        t.translate(-fixedPoint.getX(), -fixedPoint.getY());
         t.translate(translateX, translateY);
         t.concatenate(graphics.getTransform());
         graphics.setTransform(t);
     }
 
+    public synchronized void fixPoint( Point fixedPoint ) {
+        this.fixedPoint = fixedPoint;
+    }
+
     public synchronized void zoom( double scaleFactorX, double scaleFactorY ) {
         this.scaleFactorX=scaleFactorX;
         this.scaleFactorY=scaleFactorY;
diff --git a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/command/navigation/ZoomCommand.java b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/command/navigation/ZoomCommand.java
index 6879a68..0d00bec 100644
--- a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/command/navigation/ZoomCommand.java
+++ b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/command/navigation/ZoomCommand.java
@@ -13,6 +13,8 @@ import net.refractions.udig.project.internal.Messages;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 
+import com.vividsolutions.jts.geom.Coordinate;
+
 /**
  * Increases or decreases the size of the viewport(in world space) by a constant factor, zoom. The
  * zoom is equal in both directions. The function used is: bbox.height=bbox.height/divisor
@@ -24,6 +26,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
 public class ZoomCommand extends AbstractNavCommand {
 
     private double zoomfactor;
+    private Coordinate fixedPoint;
 
     /**
      * Creates a new instance of ZoomCommand
@@ -39,6 +42,10 @@ public class ZoomCommand extends AbstractNavCommand {
         this.zoomfactor = zoomfactor;
     }
 
+    public void setFixedPoint( Coordinate fixedPoint ) {
+        this.fixedPoint = fixedPoint;
+    }
+
     /**
      * @see net.refractions.udig.project.internal.command.MapCommand#copy()
      */
@@ -50,7 +57,7 @@ public class ZoomCommand extends AbstractNavCommand {
      * @see net.refractions.udig.project.internal.command.navigation.AbstractNavCommand#runImpl()
      */
     protected void runImpl( IProgressMonitor monitor ) {
-        model.zoom(zoomfactor);
+        model.zoom(zoomfactor, fixedPoint);
     }
 
     /**
diff --git a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/ViewportModel.java b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/ViewportModel.java
index f309ec0..ce1a5e7 100644
--- a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/ViewportModel.java
+++ b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/ViewportModel.java
@@ -359,6 +359,25 @@ public interface ViewportModel extends EObject, IMapDisplayListener, IViewportMo
     public ViewportModel zoom( double zoom );
 
     /**
+     * Increases or decreases the size of the viewport(in world space) by a constant factor, zoom.
+     * The zoom is equal in both directions. The function used is: bbox.height=bbox.height/divisor
+     * bbox.width=bbox.width/divisor
+     * <ul>
+     * <li>A zoom must be greater than 1.</li>
+     * <li>A zoom greater than 1 is a zoom towards the map(SimpleFeature appear larger.)</li>
+     * <li>A zoom less than 1 is a zoom away from the map</li>
+     * </ul>
+     * When get not null parameter fixedPoint then keep it fixed after zoom transform. In case of
+     * null parameter center point of map will be fixed
+     * 
+     * @param zoom the zoom factor
+     * @param fixedPoint the point that will remain fixed after zoom, can be null
+     * @return This ViewportModel, allows for command chaining.
+     * @model
+     */
+    public ViewportModel zoom( double zoom, Coordinate fixedPoint );
+
+    /**
      * sets the Viewport bounding box so that it fully contains the visible map extent
      * 
      * @model
diff --git a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ScaleUtils.java b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ScaleUtils.java
index c7e53bc..125e779 100644
--- a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ScaleUtils.java
+++ b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ScaleUtils.java
@@ -469,4 +469,20 @@ public final class ScaleUtils {
                 .getDisplaySize(), mapDisplay.getDPI(), requestedBounds);
     }
 
+    /**
+     * Creates affine transform for zooming that keeps <i>fixedPoint</i> stationary.
+     * 
+     * @param zoom zoom ration
+     * @param fixedPoint point to keep stationary
+     * @return an <i>AffineTransform</i> object containing scale transform that keeps
+     *         <i>fixedPoint</i> stationary
+     */
+    public static AffineTransform createScaleTransformWithFixedPoint( double zoom,
+            Coordinate fixedPoint ) {
+        AffineTransform t = new AffineTransform();
+        t.translate(fixedPoint.x, fixedPoint.y);
+        t.scale(1 / zoom, 1 / zoom);
+        t.translate(-fixedPoint.x, -fixedPoint.y);
+        return t;
+    }
 }
diff --git a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ViewportModelImpl.java b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ViewportModelImpl.java
index 6cd3dc4..f501f2f 100644
--- a/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ViewportModelImpl.java
+++ b/plugins/net.refractions.udig.project/src/net/refractions/udig/project/internal/render/impl/ViewportModelImpl.java
@@ -6,6 +6,7 @@ package net.refractions.udig.project.internal.render.impl;
 import java.awt.Dimension;
 import java.awt.Point;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Collections;
@@ -720,12 +721,33 @@ public class ViewportModelImpl extends EObjectImpl implements ViewportModel {
      */
     public ViewportModel zoom( double zoom ) {
         Coordinate center = getCenter();
-        double height = getHeight() / zoom, width = getWidth() / zoom;
-        double dh = height / 2, dw = width / 2;
-        setBounds(center.x - dw, center.x + dw, center.y - dh, center.y + dh);
+        zoom(zoom, center);
         return this;
     }
 
+    public ViewportModel zoom( double zoom, Coordinate fixedPoint ) {
+        if (fixedPoint == null) {
+            fixedPoint = getCenter();
+        }
+        AffineTransform transformer = ScaleUtils.createScaleTransformWithFixedPoint(zoom,
+                fixedPoint);
+        ReferencedEnvelope srcEnvelope = getBounds();
+        Envelope transformedEnvelope = transformEnvelope(srcEnvelope, transformer);
+        setBounds(transformedEnvelope);
+        return this;
+    }
+
+    private Envelope transformEnvelope( ReferencedEnvelope srcEnvelope, AffineTransform transformer ) {
+        Point2D lowLeft = new Point2D.Double(srcEnvelope.getMinX(), srcEnvelope.getMinY());
+        Point2D transformedLowLeft = new Point2D.Double();
+        transformedLowLeft = transformer.transform(lowLeft, transformedLowLeft);
+        Point2D upRight = new Point2D.Double(srcEnvelope.getMaxX(), srcEnvelope.getMaxY());
+        Point2D transformedUpRight = new Point2D.Double();
+        transformedUpRight = transformer.transform(upRight, transformedUpRight);
+        return new Envelope(transformedLowLeft.getX(), transformedUpRight.getX(),
+                transformedLowLeft.getY(), transformedUpRight.getY());
+    }
+
     /**
      * <!-- begin-user-doc --> <!-- end-user-doc -->
      * 
diff --git a/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/ScrollZoom.java b/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/ScrollZoom.java
index 0c9cb5e..cec20c9 100644
--- a/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/ScrollZoom.java
+++ b/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/ScrollZoom.java
@@ -51,7 +51,8 @@ public class ScrollZoom extends AbstractTool {
     public void mouseWheelMoved(MapMouseWheelEvent e) {
         if( e.modifiersDown() )
             return;
-        UpdateThread.getUpdater().zoom(e.clickCount*3, getContext(), 500);
+        UpdateThread.getUpdater().zoomWithFixedPoint(e.clickCount * 3, getContext(), 500,
+                e.getPoint());
     }
 
     /**
diff --git a/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/UpdateThread.java b/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/UpdateThread.java
index abb9060..bd1c324 100644
--- a/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/UpdateThread.java
+++ b/plugins/net.refractions.udig.tool.default/src/net/refractions/udig/tools/internal/UpdateThread.java
@@ -14,12 +14,16 @@
  */
 package net.refractions.udig.tools.internal;
 
+import java.awt.Point;
 import java.util.ArrayList;
 
+import com.vividsolutions.jts.geom.Coordinate;
+
 import net.refractions.udig.project.command.NavCommand;
 import net.refractions.udig.project.command.factory.NavigationCommandFactory;
 import net.refractions.udig.project.internal.command.navigation.NavComposite;
 import net.refractions.udig.project.internal.command.navigation.PanCommand;
+import net.refractions.udig.project.internal.command.navigation.ZoomCommand;
 import net.refractions.udig.project.ui.commands.TransformDrawCommand;
 import net.refractions.udig.project.ui.tool.IToolContext;
 
@@ -44,6 +48,7 @@ public class UpdateThread implements Runnable {
     private int horizontal=0;
     private IToolContext context;
 	private volatile long updateDelay = 1000;
+    private Coordinate fixedPoint;
     
     private UpdateThread(){}
     
@@ -133,7 +138,15 @@ public class UpdateThread implements Runnable {
         }
         requestStart();
     }
+
     public void zoom( int change, IToolContext context, int updateDelay ) {
+        zoomWithFixedPoint(change, context, updateDelay, null);
+    }
+    /**
+     * Makes zoom and keeps fixedPoint at the same place.
+     */
+    public void zoomWithFixedPoint( int change, IToolContext context, int updateDelay,
+            Point fixedPoint ) {
         amount += change;
         this.updateDelay = updateDelay;
 
@@ -142,16 +155,22 @@ public class UpdateThread implements Runnable {
         synchronized (UpdateThread.class) {
             if (command == null) {
                 TransformDrawCommand transformDrawCommand = new TransformDrawCommand();
-                command=transformDrawCommand;
+                command = transformDrawCommand;
+                if (fixedPoint == null) {
+                    fixedPoint = new Point(context.getViewportPane().getWidth() / 2, context
+                            .getViewportPane().getHeight() / 2);
+                }
+                transformDrawCommand.fixPoint(fixedPoint);
+                this.fixedPoint = context.pixelToWorld(fixedPoint.x, fixedPoint.y);
                 transformDrawCommand.zoom(zoom, zoom);
-                context.sendASyncCommand(transformDrawCommand );
+                context.sendASyncCommand(transformDrawCommand);
             } else {
                 command.zoom(zoom, zoom);
                 context.getViewportPane().repaint();
             }
         }
 
-        this.context=context;
+        this.context = context;
 
         requestStart();
     }
@@ -165,7 +184,9 @@ public class UpdateThread implements Runnable {
                     (NavCommand) new PanCommand((horizontal*-PAN_AMOUNT), (vertical*-PAN_AMOUNT)));
         }
         if( zoom>0.00000001 ){
-            commands.add(factory.createZoomCommand(zoom));
+            ZoomCommand zoomCommand = new ZoomCommand(zoom);
+            zoomCommand.setFixedPoint(fixedPoint);
+            commands.add(zoomCommand);
         }
         if( commands.size()>0 ){
             NavComposite composite = new NavComposite(commands);

Back to the top