source: osm/applications/editors/josm/plugins/slippy_map_chooser/src/TileDB.java@ 9534

Last change on this file since 9534 was 7199, checked in by tim, 17 years ago

Initial import of slippy_map_chooser source version 1.1

File size: 6.9 KB
Line 
1// License: GPL. Copyright 2007 by Tim Haussmann
2
3
4import java.io.IOException;
5import java.io.InputStream;
6import java.net.MalformedURLException;
7import java.net.URL;
8import java.util.Enumeration;
9import java.util.Hashtable;
10import java.util.Vector;
11
12import javax.imageio.ImageIO;
13import javax.swing.JComponent;
14
15
16
17/**
18 * The TileDB is responsible for fetching and storing all needed map tiles. The tiles
19 * are stored in memory and are fetched one by one in background.
20 * Tiles are stored in a HashTable. The path of the tile on the tile server (i.e. '/12/3/5.png')
21 * acts as key and the OsmTile as value.
22 * @author Tim Haussmann
23 *
24 */
25public class TileDB{
26
27 public static final int PRIO_HIGH = 1;
28 public static final int PRIO_LOW = 2;
29
30 //Osm tile server address
31 private static final String OSM_TILE_SERVER = "http://tile.openstreetmap.org";
32
33 //Queue for loading tiles
34 private Vector<OsmTile> iTileQueue = new Vector<OsmTile>();
35
36 //DB for holding the downloaded tiles
37 private Hashtable<String,OsmTile> iHashTable = new Hashtable<String,OsmTile>(SlippyMapChooserPlugin.MAX_TILES_IN_DB + 50);
38
39 //the order in that the tiles have been downloaded, needed to delete old ones
40 private Vector<String> iTileOrder = new Vector<String>(SlippyMapChooserPlugin.MAX_TILES_IN_DB + 50);
41
42 //to update the map after a tile has been loaded
43 private JComponent iSlippyMapChooser;
44
45 private int[] iMaxLatValues;
46 private int[] iMaxLonValues;
47
48 /**
49 * Creates the TileDB.
50 * @param aWorldChooser
51 */
52 public TileDB(JComponent aWorldChooser){
53 iSlippyMapChooser = aWorldChooser;
54
55 iMaxLatValues = new int[20];
56 iMaxLonValues = new int[20];
57 for(int i=0; i<20; i++){
58 iMaxLatValues[i] = OsmMercator.LatToY(OsmMercator.MIN_LAT, i)/OsmTile.HEIGHT;
59 iMaxLonValues[i] = OsmMercator.LonToX(180, i)/OsmTile.WIDTH;
60 }
61
62 new TileFetcherThread(this);
63 new TileFetcherThread(this);
64 new TileFetcherThread(this);
65 new TileFetcherThread(this);
66 }
67
68 /**
69 * Creates a OsmTile if it's not in the Hashtable. New created tiles are added to the
70 * end of the download queue (Vector) and the DB (Hashtable). After that the fetching thread is
71 * notified.
72 * @param aZoomLevel the zoomlevel for the tile to create
73 * @param aIndexX the X-index of the tile to create. Must be within [0..2^zoomlevel[
74 * @param aIndexY the Y-index of the tile to create. Must be within [0..2^zoomlevel[
75 * @param aPriority PRIO_HIGH adds this tile at the waiting queue start PRIO_LOW at the end
76 */
77 public synchronized void loadTile(int aZoomLevel, int aIndexX, int aIndexY, int aPriority)
78 {
79
80 if(aZoomLevel <0 || aIndexX <0 || aIndexY <0){
81 return;
82 }else if(iMaxLonValues[aZoomLevel] <= aIndexX ||
83 iMaxLatValues[aZoomLevel] <= aIndexY ){
84 return;
85 }
86 String key = OsmTile.key(aZoomLevel, aIndexX, aIndexY);
87 OsmTile t = iHashTable.get(key);
88 if(t != null){
89 //if a tile is already in the DB and still in the laoding queue
90 //move it to the beginning of the queue in order to make the currently
91 //visible tiles load first
92 if(iTileQueue.remove(t)){
93 iTileQueue.add(0,t);
94 }
95 return;
96 }
97
98 t = new OsmTile(aZoomLevel, aIndexX, aIndexY);
99 iHashTable.put(t.toString(),t);
100 iTileOrder.add(0,key);
101
102 if(aPriority == PRIO_LOW){
103 iTileQueue.addElement(t);
104 }else if(aPriority == PRIO_HIGH){
105 iTileQueue.add(0,t);
106 }else{
107 iTileQueue.addElement(t);
108 }
109
110 //check if old tiles need to be deleted
111 if(iTileOrder.size() > SlippyMapChooserPlugin.MAX_TILES_IN_DB){
112 for(int i=0; i<SlippyMapChooserPlugin.MAX_TILES_REDUCE_BY; i++){
113 String removedKey = iTileOrder.remove(iTileOrder.size()-1);
114 iHashTable.remove(removedKey);
115 }
116 }
117
118 //Wake up the fetching threads
119 synchronized (this) {
120 notifyAll();
121 }
122 }
123
124 /**
125 * Returns the next tile that needs to be loaded. This method is called by the threads
126 * that fetch the tiles. If the download queue is empty the calling threads are waiting.
127 * @return the first tile in the download queue with the same zoom level that is currently displayed or just the first.
128 */
129 private OsmTile getNextTile(){
130 if(iTileQueue.size() > 0){
131 OsmTile t;
132 Enumeration<OsmTile> e = iTileQueue.elements();
133 while(e.hasMoreElements()){
134 t = e.nextElement();
135 if(t.getZoomlevel() == SlippyMapChooser.iZoomlevel){
136 return t;
137 }
138 }
139 return iTileQueue.firstElement();
140 }
141 else{
142 synchronized (this) {
143 try {
144 wait();
145 } catch (InterruptedException e) {
146 e.printStackTrace();
147 }
148 }
149 return iTileQueue.firstElement();
150 }
151 }
152
153 /**
154 * Access tiles in the TileDB.
155 * @return an Enumeration that holds all OsmTiles currently stored in the TileDB (Hashtable)
156 */
157 public Enumeration<OsmTile> elements() {
158 return iHashTable.elements();
159 }
160
161 /**
162 * Returns a OsmTile by key
163 * @param aKey
164 * @return
165 */
166 public OsmTile get(String aKey){
167 return iHashTable.get(aKey);
168 }
169
170 /**
171 * Delete OsmTiles from the TileDB.
172 * @param aTile that is to be deleted.
173 */
174 public void remove(OsmTile aTile){
175 iHashTable.remove(aTile.toString());
176 iTileQueue.removeElement(aTile);
177 }
178
179 /**
180 * Returns the number of OsmTiles waiting to be fetched from the server.
181 * @return
182 */
183 public int getLoadingQueueSize() {
184 return iTileQueue.size();
185 }
186
187 /**
188 * Returns the number of tiles stored in the TileDB
189 * @return
190 */
191 public int getCachedTilesSize() {
192 return iHashTable.size();
193 }
194
195
196 /***************************************************
197 * Private inner class to fetch the tiles over http
198 * *************************************************
199 */
200
201 class TileFetcherThread implements Runnable{
202
203 private TileDB iTileDB;
204 private Thread iThread;
205
206 public TileFetcherThread(TileDB aTileDB){
207 iTileDB = aTileDB;
208 iThread = new Thread(this);
209 iThread.start();
210 }
211
212 public void run(){
213
214 while(true){
215
216 //get the next tile to load
217 OsmTile t = iTileDB.getNextTile();
218
219 URL tileUrl = null;
220 try {
221
222 //build the url to the tile
223 tileUrl = new URL(OSM_TILE_SERVER + t.getRemotePath());
224
225 //get the tile
226 InputStream in = tileUrl.openStream();
227
228 //the tile needs the image...
229 t.setImage(ImageIO.read(in));
230
231 } catch (MalformedURLException e) {
232// System.out.println("Catched: " + e.getMessage());
233// e.printStackTrace();
234 t.setImage(null);
235 } catch (IOException e) {
236// System.out.println("Catched: " + e.getMessage());
237// e.printStackTrace();
238 t.setImage(null);
239 } catch (Exception e){
240// System.out.println("Catched: " + e.getMessage());
241// e.printStackTrace();
242 t.setImage(null);
243 }
244
245 iTileQueue.removeElement(t);
246 iSlippyMapChooser.repaint();
247 }
248 }
249 }
250}
Note: See TracBrowser for help on using the repository browser.