X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=src%2Ftim%2Fprune%2Fgui%2Fmap%2FMapPosition.java;fp=src%2Ftim%2Fprune%2Fgui%2Fmap%2FMapPosition.java;h=25f05fc1a2a238370d8888ea4b807b7d3f5f8adb;hp=0000000000000000000000000000000000000000;hb=ce6f2161b8596f7018d6a76bff79bc9e571f35fd;hpb=2d8cb72e84d5cc1089ce77baf1e34ea3ea2f8465 diff --git a/src/tim/prune/gui/map/MapPosition.java b/src/tim/prune/gui/map/MapPosition.java new file mode 100644 index 0000000..25f05fc --- /dev/null +++ b/src/tim/prune/gui/map/MapPosition.java @@ -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; + } +}