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