]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - src/tim/prune/gui/map/MapPosition.java
Moved source into separate src directory due to popular request
[GpsPrune.git] / src / tim / prune / gui / map / MapPosition.java
diff --git a/src/tim/prune/gui/map/MapPosition.java b/src/tim/prune/gui/map/MapPosition.java
new file mode 100644 (file)
index 0000000..25f05fc
--- /dev/null
@@ -0,0 +1,280 @@
+package tim.prune.gui.map;
+
+/**
+ * Class to hold the current position of the map
+ */
+public class MapPosition
+{
+       /** Width and height of each tile of map */
+       private static final int MAP_TILE_SIZE = 256;
+
+       /** x position (scale depends on zoom) */
+       private int _xPosition = 0;
+       /** y position (scale depends on zoom) */
+       private int _yPosition = 0;
+
+       /** Zoom level, from 2 to max */
+       private int _zoom = 12;
+       /** Factor to zoom by, 2 to the power of zoom */
+       private int _zoomFactor = 1 << _zoom;
+       /** Maximum zoom level */
+       private static final int MAX_ZOOM = 21;
+
+
+       /**
+        * Zoom and pan to show the selected area
+        * @param inMinX minimum transformed X
+        * @param inMaxX maximum transformed X
+        * @param inMinY minimum transformed Y
+        * @param inMaxY maximum transformed Y
+        * @param inWidth width of display
+        * @param inHeight height of display
+        */
+       public void zoomToXY(double inMinX, double inMaxX, double inMinY, double inMaxY, int inWidth, int inHeight)
+       {
+               // System.out.println("Zooming to " + inMinX + ", " + inMaxX + ", " + inMinY + ", " + inMaxY + "; width=" + inWidth + ", height=" + inHeight);
+               double diffX = Math.abs(inMaxX - inMinX);
+               double diffY = Math.abs(inMaxY - inMinY);
+               // Find out what zoom level to go to
+               int requiredZoom = -1;
+               for (int currZoom = MAX_ZOOM; currZoom >= 2; currZoom--)
+               {
+                       if (transformToPixels(diffX, currZoom) < inWidth
+                               && transformToPixels(diffY, currZoom) < inHeight)
+                       {
+                               requiredZoom = currZoom;
+                               break;
+                       }
+               }
+               if (requiredZoom < 2) requiredZoom = 2;
+               // Set position
+               setZoom(requiredZoom);
+               _xPosition = transformToPixels((inMinX + inMaxX) / 2.0);
+               _yPosition = transformToPixels((inMinY + inMaxY) / 2.0);
+       }
+
+       /**
+        * Ensure that zoom and zoomFactor remain in sync
+        * @param inZoom zoom level to set
+        */
+       private void setZoom(int inZoom)
+       {
+               _zoom = inZoom;
+               _zoomFactor = 1 << _zoom;
+       }
+
+       /**
+        * Zoom and pan to show the selected area
+        * @param inMinX minimum pixels X
+        * @param inMaxX maximum pixels X
+        * @param inMinY minimum pixels Y
+        * @param inMaxY maximum pixels Y
+        * @param inWidth width of display
+        * @param inHeight height of display
+        */
+       public void zoomToPixels(int inMinX, int inMaxX, int inMinY, int inMaxY, int inWidth, int inHeight)
+       {
+               // System.out.println("Current position is " + _xPosition + ", " + _yPosition);
+               int diffX = Math.abs(inMaxX - inMinX);
+               int diffY = Math.abs(inMaxY - inMinY);
+               // Find out what zoom level to go to
+               int requiredZoom = -1;
+               int multFactor = 0;
+               for (int currZoom = MAX_ZOOM; currZoom >= _zoom; currZoom--)
+               {
+                       multFactor = 1 << (currZoom - _zoom);
+                       if ((diffX * multFactor) < inWidth && (diffY * multFactor) < inHeight)
+                       {
+                               requiredZoom = currZoom;
+                               break;
+                       }
+               }
+               setZoom(requiredZoom);
+               // Set position
+               _xPosition = (_xPosition - inWidth/2 + (inMinX + inMaxX) / 2) * multFactor;
+               _yPosition = (_yPosition - inHeight/2 + (inMinY + inMaxY) / 2) * multFactor;
+       }
+
+       /**
+        * Transform a given coordinate into pixels using the current zoom value
+        * @param inValue value to transform
+        * @return pixels
+        */
+       private int transformToPixels(double inValue)
+       {
+               return transformToPixels(inValue, _zoom);
+       }
+
+       /**
+        * Transform a given coordinate into pixels using the specified zoom value
+        * @param inValue value to transform
+        * @param inZoom zoom value to use
+        * @return pixels
+        */
+       private static int transformToPixels(double inValue, int inZoom)
+       {
+               return (int) (inValue * MAP_TILE_SIZE * (1 << inZoom));
+       }
+
+       /**
+        * Convert pixels back into x coordinates
+        * @param inPixelX x coordinate on screen
+        * @param inWidth current width of window
+        * @return x coordinate
+        */
+       public double getXFromPixels(int inPixelX, int inWidth)
+       {
+               return ((inPixelX - inWidth/2) + _xPosition) * 1.0 / MAP_TILE_SIZE / _zoomFactor;
+       }
+
+       /**
+        * Convert pixels back into y coordinates
+        * @param inPixelY y coordinate on screen
+        * @param inHeight current height of window
+        * @return y coordinate
+        */
+       public double getYFromPixels(int inPixelY, int inHeight)
+       {
+               return ((inPixelY - inHeight/2) + _yPosition) * 1.0 / MAP_TILE_SIZE / _zoomFactor;
+       }
+
+       /**
+        * Get the horizontal offset from the centre
+        * @param inValue value to transform
+        * @return number of pixels right (+ve) or left (-ve) from the centre
+        */
+       public int getXFromCentre(double inValue)
+       {
+               return transformToPixels(inValue) - _xPosition;
+       }
+
+       /**
+        * Get the vertical offset from the centre
+        * @param inValue value to transform
+        * @return number of pixels up (+ve) or down (-ve) from the centre
+        */
+       public int getYFromCentre(double inValue)
+       {
+               return transformToPixels(inValue) - _yPosition;
+       }
+
+       /**
+        * Convert a pixel value into a bounds value for sensitivity
+        * @param inPixels number of pixels
+        * @return bounds value to use for x,y checking
+        */
+       public double getBoundsFromPixels(int inPixels) {
+               return (inPixels * 1.0 / MAP_TILE_SIZE / _zoomFactor);
+       }
+
+       /**
+        * Get the leftmost, rightmost, upper and lower index boundaries for the tiles to display
+        * @param inWidth width of window
+        * @param inHeight height of window
+        * @return tile indices as array left, right, up, down
+        */
+       public int[] getTileIndices(int inWidth, int inHeight)
+       {
+               int[] result = new int[4];
+               result[0] = getTileIndex(_xPosition - inWidth/2);
+               result[1] = getTileIndex(_xPosition + inWidth/2);
+               result[2] = getTileIndex(_yPosition - inHeight/2);
+               result[3] = getTileIndex(_yPosition + inHeight/2);
+               return result;
+       }
+
+       /**
+        * Get the pixel offsets for the display
+        * @param inWidth width of window
+        * @param inHeight height of window
+        * @return offsets as x, y
+        */
+       public int[] getDisplayOffsets(int inWidth, int inHeight)
+       {
+               int[] result = new int[2];
+               result[0] = getDisplayOffset(_xPosition - inWidth/2);
+               result[1] = getDisplayOffset(_yPosition - inHeight/2);
+               return result;
+       }
+
+       /**
+        * @return x index of the centre tile
+        */
+       public int getCentreTileX()
+       {
+               return getTileIndex(_xPosition);
+       }
+
+       /**
+        * @return y index of the centre tile
+        */
+       public int getCentreTileY()
+       {
+               return getTileIndex(_yPosition);
+       }
+
+       /**
+        * @param inPosition position of point
+        * @return tile index for that point
+        */
+       private int getTileIndex(int inPosition)
+       {
+               return inPosition / MAP_TILE_SIZE;
+       }
+
+       /**
+        * @param inPosition position of point
+        * @return pixel offset for that point
+        */
+       private int getDisplayOffset(int inPosition)
+       {
+               return inPosition % MAP_TILE_SIZE;
+               // I thought that &255 would be slightly faster, but it gives the wrong result
+       }
+
+       /**
+        * Zoom in one level
+        */
+       public void zoomIn()
+       {
+               if (_zoom < MAX_ZOOM)
+               {
+                       setZoom(_zoom + 1);
+                       _xPosition *= 2;
+                       _yPosition *= 2;
+               }
+       }
+
+       /**
+        * Zoom out one level
+        */
+       public void zoomOut()
+       {
+               if (_zoom >= 3)
+               {
+                       setZoom(_zoom - 1);
+                       _xPosition /= 2;
+                       _yPosition /= 2;
+               }
+       }
+
+       /**
+        * @return current zoom level
+        */
+       public int getZoom()
+       {
+               return _zoom;
+       }
+
+       /**
+        * Pan map by the specified amount
+        * @param inDeltaX amount to pan right
+        * @param inDeltaY amount to pan down
+        */
+       public void pan(int inDeltaX, int inDeltaY)
+       {
+               // TODO: Check bounds?
+               _xPosition += inDeltaX;
+               _yPosition += inDeltaY;
+       }
+}