File: MapTileManager.java

package info (click to toggle)
gpsprune 10-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 2,220 kB
  • ctags: 3,013
  • sloc: java: 22,662; sh: 23; makefile: 16; python: 15
file content (178 lines) | stat: -rw-r--r-- 4,972 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package tim.prune.gui.map;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.net.MalformedURLException;
import java.net.URL;

import tim.prune.config.Config;

/**
 * Class responsible for managing the map tiles,
 * including invoking the correct memory cacher(s) and/or disk cacher(s)
 */
public class MapTileManager implements ImageObserver
{
	/** Parent object to inform when tiles received */
	private MapCanvas _parent = null;
	/** Current map source */
	private MapSource _mapSource = null;
	/** Array of tile caches, one per layer */
	private MemTileCacher[] _tempCaches = null;
	/** Number of layers */
	private int _numLayers = -1;
	/** Current zoom level */
	private int _zoom = 0;


	/**
	 * Constructor
	 * @param inParent parent canvas to be informed of updates
	 */
	public MapTileManager(MapCanvas inParent)
	{
		_parent = inParent;
		resetConfig();
	}

	/**
	 * Recentre the map
	 * @param inZoom zoom level
	 * @param inTileX x coord of central tile
	 * @param inTileY y coord of central tile
	 */
	public void centreMap(int inZoom, int inTileX, int inTileY)
	{
		_zoom = inZoom;
		// Pass params onto all memory cachers
		if (_tempCaches != null) {
			for (int i=0; i<_tempCaches.length; i++) {
				_tempCaches[i].centreMap(inZoom, inTileX, inTileY);
			}
		}
	}

	/**
	 * @return true if zoom is too high for tiles
	 */
	public boolean isOverzoomed()
	{
		// Ask current map source what maximum zoom is
		int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
		return (_zoom > maxZoom);
	}

	/**
	 * Clear all the memory caches due to changed config / zoom
	 */
	public void clearMemoryCaches()
	{
		int numLayers = _mapSource.getNumLayers();
		if (_tempCaches == null || _tempCaches.length != numLayers) {
			// Ccahers don't match, so need to create the right number of them
			_tempCaches = new MemTileCacher[numLayers];
			for (int i=0; i<numLayers; i++) {
				_tempCaches[i] = new MemTileCacher();
			}
		}
		else {
			// Cachers already there, just need to be cleared
			for (int i=0; i<numLayers; i++) {
				_tempCaches[i].clearAll();
			}
		}
	}

	/**
	 * Reset the map source configuration, apparently it has changed
	 */
	public void resetConfig()
	{
		int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
		_mapSource = MapSourceLibrary.getSource(sourceNum);
		if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
		clearMemoryCaches();
		_numLayers = _mapSource.getNumLayers();
	}

	/**
	 * @return the number of layers in the map
	 */
	public int getNumLayers()
	{
		return _numLayers;
	}

	/**
	 * @param inLayer layer number, starting from 0
	 * @param inX x index of tile
	 * @param inY y index of tile
	 * @return selected tile if already loaded, or null otherwise
	 */
	public Image getTile(int inLayer, int inX, int inY)
	{
		// Check first in memory cache for tile
		MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
		Image tile = tempCache.getTile(inX, inY);
		if (tile != null) {
			return tile;
		}

		// Tile wasn't in memory, but maybe it's in disk cache (if there is one)
		String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
		boolean useDisk = (diskCachePath != null);
		boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
		if (useDisk)
		{
			tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
			if (tile != null) {
				// Pass tile to memory cache
				tempCache.setTile(tile, inX, inY);
				if (tile.getWidth(this) > 0) {return tile;}
				return null;
			}
		}
		// Tile wasn't in memory or on disk, so if online let's get it
		if (onlineMode)
		{
			try
			{
				URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
				if (useDisk) {
					// Copy image directly from URL stream to disk cache
					DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this);
				}
				else {
					// Load image asynchronously, using observer
					tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
					// Pass to memory cache
					_tempCaches[inLayer].setTile(tile, inX, inY);
					if (tile.getWidth(this) > 0) {return tile;}
				}
			}
			catch (MalformedURLException urle) {} // ignore
		}
		return null;
	}

	/**
	 * Method called by image loader to inform of updates to the tiles
	 * @param img the image
	 * @param infoflags flags describing how much of the image is known
	 * @param x ignored
	 * @param y ignored
	 * @param width ignored
	 * @param height ignored
	 * @return false to carry on loading, true to stop
	 */
	public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
	{
		boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
		boolean error = (infoflags & ImageObserver.ERROR) > 0;
		if (loaded || error) {
			_parent.tilesUpdated(loaded);
		}
		return !loaded;
	}
}