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