]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/map/MapPosition.java
Version 14, October 2012
[GpsPrune.git] / tim / prune / gui / map / MapPosition.java
1 package tim.prune.gui.map;
2
3 /**
4  * Class to hold the current position of the map
5  */
6 public class MapPosition
7 {
8         /** Width and height of each tile of map */
9         private static final int MAP_TILE_SIZE = 256;
10
11         /** x position (scale depends on zoom) */
12         private int _xPosition = 0;
13         /** y position (scale depends on zoom) */
14         private int _yPosition = 0;
15
16         /** Zoom level, from 2 to max */
17         private int _zoom = 12;
18         /** Factor to zoom by, 2 to the power of zoom */
19         private int _zoomFactor = 1 << _zoom;
20         /** Maximum zoom level */
21         private static final int MAX_ZOOM = 21;
22
23
24         /**
25          * Zoom and pan to show the selected area
26          * @param inMinX minimum transformed X
27          * @param inMaxX maximum transformed X
28          * @param inMinY minimum transformed Y
29          * @param inMaxY maximum transformed Y
30          * @param inWidth width of display
31          * @param inHeight height of display
32          */
33         public void zoomToXY(double inMinX, double inMaxX, double inMinY, double inMaxY, int inWidth, int inHeight)
34         {
35                 // System.out.println("Zooming to " + inMinX + ", " + inMaxX + ", " + inMinY + ", " + inMaxY + "; width=" + inWidth + ", height=" + inHeight);
36                 double diffX = Math.abs(inMaxX - inMinX);
37                 double diffY = Math.abs(inMaxY - inMinY);
38                 // Find out what zoom level to go to
39                 int requiredZoom = -1;
40                 for (int currZoom = MAX_ZOOM; currZoom >= 2; currZoom--)
41                 {
42                         if (transformToPixels(diffX, currZoom) < inWidth
43                                 && transformToPixels(diffY, currZoom) < inHeight)
44                         {
45                                 requiredZoom = currZoom;
46                                 break;
47                         }
48                 }
49                 if (requiredZoom < 2) requiredZoom = 2;
50                 // Set position
51                 setZoom(requiredZoom);
52                 _xPosition = transformToPixels((inMinX + inMaxX) / 2.0);
53                 _yPosition = transformToPixels((inMinY + inMaxY) / 2.0);
54         }
55
56         /**
57          * Ensure that zoom and zoomFactor remain in sync
58          * @param inZoom zoom level to set
59          */
60         private void setZoom(int inZoom)
61         {
62                 _zoom = inZoom;
63                 _zoomFactor = 1 << _zoom;
64         }
65
66         /**
67          * Zoom and pan to show the selected area
68          * @param inMinX minimum pixels X
69          * @param inMaxX maximum pixels X
70          * @param inMinY minimum pixels Y
71          * @param inMaxY maximum pixels Y
72          * @param inWidth width of display
73          * @param inHeight height of display
74          */
75         public void zoomToPixels(int inMinX, int inMaxX, int inMinY, int inMaxY, int inWidth, int inHeight)
76         {
77                 // System.out.println("Current position is " + _xPosition + ", " + _yPosition);
78                 int diffX = Math.abs(inMaxX - inMinX);
79                 int diffY = Math.abs(inMaxY - inMinY);
80                 // Find out what zoom level to go to
81                 int requiredZoom = -1;
82                 int multFactor = 0;
83                 for (int currZoom = MAX_ZOOM; currZoom >= _zoom; currZoom--)
84                 {
85                         multFactor = 1 << (currZoom - _zoom);
86                         if ((diffX * multFactor) < inWidth && (diffY * multFactor) < inHeight)
87                         {
88                                 requiredZoom = currZoom;
89                                 break;
90                         }
91                 }
92                 setZoom(requiredZoom);
93                 // Set position
94                 _xPosition = (_xPosition - inWidth/2 + (inMinX + inMaxX) / 2) * multFactor;
95                 _yPosition = (_yPosition - inHeight/2 + (inMinY + inMaxY) / 2) * multFactor;
96         }
97
98         /**
99          * Transform a given coordinate into pixels using the current zoom value
100          * @param inValue value to transform
101          * @return pixels
102          */
103         private int transformToPixels(double inValue)
104         {
105                 return transformToPixels(inValue, _zoom);
106         }
107
108         /**
109          * Transform a given coordinate into pixels using the specified zoom value
110          * @param inValue value to transform
111          * @param inZoom zoom value to use
112          * @return pixels
113          */
114         private static int transformToPixels(double inValue, int inZoom)
115         {
116                 return (int) (inValue * MAP_TILE_SIZE * (1 << inZoom));
117         }
118
119         /**
120          * Convert pixels back into x coordinates
121          * @param inPixelX x coordinate on screen
122          * @param inWidth current width of window
123          * @return x coordinate
124          */
125         public double getXFromPixels(int inPixelX, int inWidth)
126         {
127                 return ((inPixelX - inWidth/2) + _xPosition) * 1.0 / MAP_TILE_SIZE / _zoomFactor;
128         }
129
130         /**
131          * Convert pixels back into y coordinates
132          * @param inPixelY y coordinate on screen
133          * @param inHeight current height of window
134          * @return y coordinate
135          */
136         public double getYFromPixels(int inPixelY, int inHeight)
137         {
138                 return ((inPixelY - inHeight/2) + _yPosition) * 1.0 / MAP_TILE_SIZE / _zoomFactor;
139         }
140
141         /**
142          * Get the horizontal offset from the centre
143          * @param inValue value to transform
144          * @return number of pixels right (+ve) or left (-ve) from the centre
145          */
146         public int getXFromCentre(double inValue)
147         {
148                 return transformToPixels(inValue) - _xPosition;
149         }
150
151         /**
152          * Get the vertical offset from the centre
153          * @param inValue value to transform
154          * @return number of pixels up (+ve) or down (-ve) from the centre
155          */
156         public int getYFromCentre(double inValue)
157         {
158                 return transformToPixels(inValue) - _yPosition;
159         }
160
161         /**
162          * Convert a pixel value into a bounds value for sensitivity
163          * @param inPixels number of pixels
164          * @return bounds value to use for x,y checking
165          */
166         public double getBoundsFromPixels(int inPixels) {
167                 return (inPixels * 1.0 / MAP_TILE_SIZE / _zoomFactor);
168         }
169
170         /**
171          * Get the leftmost, rightmost, upper and lower index boundaries for the tiles to display
172          * @param inWidth width of window
173          * @param inHeight height of window
174          * @return tile indices as array left, right, up, down
175          */
176         public int[] getTileIndices(int inWidth, int inHeight)
177         {
178                 int[] result = new int[4];
179                 result[0] = getTileIndex(_xPosition - inWidth/2);
180                 result[1] = getTileIndex(_xPosition + inWidth/2);
181                 result[2] = getTileIndex(_yPosition - inHeight/2);
182                 result[3] = getTileIndex(_yPosition + inHeight/2);
183                 return result;
184         }
185
186         /**
187          * Get the pixel offsets for the display
188          * @param inWidth width of window
189          * @param inHeight height of window
190          * @return offsets as x, y
191          */
192         public int[] getDisplayOffsets(int inWidth, int inHeight)
193         {
194                 int[] result = new int[2];
195                 result[0] = getDisplayOffset(_xPosition - inWidth/2);
196                 result[1] = getDisplayOffset(_yPosition - inHeight/2);
197                 return result;
198         }
199
200         /**
201          * @return x index of the centre tile
202          */
203         public int getCentreTileX()
204         {
205                 return getTileIndex(_xPosition);
206         }
207
208         /**
209          * @return y index of the centre tile
210          */
211         public int getCentreTileY()
212         {
213                 return getTileIndex(_yPosition);
214         }
215
216         /**
217          * @param inPosition position of point
218          * @return tile index for that point
219          */
220         private int getTileIndex(int inPosition)
221         {
222                 return inPosition / MAP_TILE_SIZE;
223         }
224
225         /**
226          * @param inPosition position of point
227          * @return pixel offset for that point
228          */
229         private int getDisplayOffset(int inPosition)
230         {
231                 return inPosition % MAP_TILE_SIZE;
232                 // I thought that &255 would be slightly faster, but it gives the wrong result
233         }
234
235         /**
236          * Zoom in one level
237          */
238         public void zoomIn()
239         {
240                 if (_zoom < MAX_ZOOM)
241                 {
242                         setZoom(_zoom + 1);
243                         _xPosition *= 2;
244                         _yPosition *= 2;
245                 }
246         }
247
248         /**
249          * Zoom out one level
250          */
251         public void zoomOut()
252         {
253                 if (_zoom >= 3)
254                 {
255                         setZoom(_zoom - 1);
256                         _xPosition /= 2;
257                         _yPosition /= 2;
258                 }
259         }
260
261         /**
262          * @return current zoom level
263          */
264         public int getZoom()
265         {
266                 return _zoom;
267         }
268
269         /**
270          * Pan map by the specified amount
271          * @param inDeltaX amount to pan right
272          * @param inDeltaY amount to pan down
273          */
274         public void pan(int inDeltaX, int inDeltaY)
275         {
276                 // TODO: Check bounds?
277                 _xPosition += inDeltaX;
278                 _yPosition += inDeltaY;
279         }
280 }