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