gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster.2.4 / org.gvsig.raster / org.gvsig.raster.googlemaps / org.gvsig.raster.googlemaps.provider / src / main / java / org / gvsig / raster / googlemaps / provider / GoogleMapsImage.java @ 6514
History | View | Annotate | Download (11.2 KB)
1 |
package org.gvsig.raster.googlemaps.provider; |
---|---|
2 |
|
3 |
import java.awt.image.BufferedImage; |
4 |
import java.util.HashMap; |
5 |
import java.util.Iterator; |
6 |
import java.util.Map; |
7 |
import java.util.Map.Entry; |
8 |
import java.util.Set; |
9 |
|
10 |
import org.slf4j.Logger; |
11 |
import org.slf4j.LoggerFactory; |
12 |
|
13 |
import org.gvsig.fmap.dal.DataStoreParameters; |
14 |
import org.gvsig.fmap.dal.exception.DataException; |
15 |
import org.gvsig.fmap.dal.exception.ValidateDataParametersException; |
16 |
import org.gvsig.fmap.geom.Geometry.DIMENSIONS; |
17 |
import org.gvsig.fmap.geom.Geometry.SUBTYPES; |
18 |
import org.gvsig.fmap.geom.GeometryLocator; |
19 |
import org.gvsig.fmap.geom.GeometryManager; |
20 |
import org.gvsig.fmap.geom.exception.CreateEnvelopeException; |
21 |
import org.gvsig.fmap.geom.exception.CreateGeometryException; |
22 |
import org.gvsig.fmap.geom.primitive.Envelope; |
23 |
import org.gvsig.fmap.geom.primitive.Point; |
24 |
import org.gvsig.googlemaps.lib.api.GoogleMapsLocator; |
25 |
import org.gvsig.googlemaps.lib.api.GoogleMapsManager; |
26 |
import org.gvsig.googlemaps.lib.api.GoogleMapsRequest; |
27 |
import org.gvsig.googlemaps.lib.api.GoogleMapsRequestParams; |
28 |
import org.gvsig.googlemaps.lib.api.exceptions.DownloadingException; |
29 |
import org.gvsig.googlemaps.lib.api.exceptions.URLFormatException; |
30 |
import org.gvsig.raster.lib.buffer.api.Band; |
31 |
import org.gvsig.raster.lib.buffer.api.Buffer; |
32 |
import org.gvsig.raster.lib.buffer.api.BufferLocator; |
33 |
import org.gvsig.raster.lib.buffer.api.TileStruct; |
34 |
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException; |
35 |
import org.gvsig.tools.ToolsLocator; |
36 |
import org.gvsig.tools.dispose.Disposable; |
37 |
import org.gvsig.tools.dispose.DisposeUtils; |
38 |
import org.gvsig.tools.dispose.impl.AbstractDisposable; |
39 |
import org.gvsig.tools.exception.BaseException; |
40 |
import org.gvsig.tools.locator.LocatorException; |
41 |
|
42 |
|
43 |
/**
|
44 |
* @author fdiaz
|
45 |
*
|
46 |
*/
|
47 |
public class GoogleMapsImage extends AbstractDisposable { |
48 |
|
49 |
private static final Logger logger = LoggerFactory.getLogger(GoogleMapsImage.class); |
50 |
private static final int MAX_RECENT_ACCEDED_TILES_NUMBER = 50; |
51 |
|
52 |
private Map<String, DownloadedTile> recentAccededTiles; |
53 |
|
54 |
private TileStruct tileStruct;
|
55 |
private GoogleMapsRasterProvider provider;
|
56 |
|
57 |
/**
|
58 |
* @param provider
|
59 |
* @param query
|
60 |
* @param tileStruct
|
61 |
*/
|
62 |
public GoogleMapsImage(TileStruct tileStruct, GoogleMapsRasterProvider provider) {
|
63 |
this.tileStruct = tileStruct;
|
64 |
this.provider = provider;
|
65 |
|
66 |
recentAccededTiles = new HashMap<String, DownloadedTile>(); |
67 |
} |
68 |
|
69 |
/**
|
70 |
* @param bandNumber
|
71 |
* @param zoomLevel
|
72 |
* @param structRow
|
73 |
* @param structCol
|
74 |
* @return Band
|
75 |
* @throws CreateEnvelopeException
|
76 |
* @throws CloneNotSupportedException
|
77 |
* @throws ValidateDataParametersException
|
78 |
*/
|
79 |
public Band fetchTile(int bandNumber, int zoomLevel, int structRow, int structCol) throws CreateEnvelopeException, |
80 |
ValidateDataParametersException, CloneNotSupportedException {
|
81 |
|
82 |
// BufferManager bufferManager = BufferLocator.getBufferManager();
|
83 |
|
84 |
String keyTile = composeKeyForRecentTiles(zoomLevel, structRow, structCol);
|
85 |
DownloadedTile tile = recentAccededTiles.get(keyTile); |
86 |
|
87 |
Buffer buffer = null; |
88 |
if (tile != null && tile.isDownloaded()) { |
89 |
// Devolver la banda del buffer del tile
|
90 |
logger.info("Devolviendo la banda "+bandNumber+" del buffer del tile "+tile.getKey()); |
91 |
try {
|
92 |
buffer = tile.getBuffer(); |
93 |
Band band = buffer.getBand(bandNumber); |
94 |
ToolsLocator.getDisposableManager().bind(band); |
95 |
return band;
|
96 |
} catch (InterruptedException e) { |
97 |
logger.warn("Can't fetch tile: zoomLevel = " + zoomLevel + ", tileRow = " + structRow |
98 |
+ ", tileColumn = " + structCol + ", band = " + bandNumber + ".", e); |
99 |
return null; |
100 |
} |
101 |
} else {
|
102 |
// Cargar un tile nuevo
|
103 |
Band band = null;
|
104 |
try {
|
105 |
while(tile==null || !tile.isDownloaded()) { |
106 |
tile = requestTile(zoomLevel, structRow, structCol, keyTile); |
107 |
} |
108 |
|
109 |
buffer = tile.getBuffer(); |
110 |
|
111 |
if (recentAccededTiles.size() >= MAX_RECENT_ACCEDED_TILES_NUMBER) {
|
112 |
removeOlderTile(); |
113 |
} |
114 |
recentAccededTiles.put(keyTile, tile); |
115 |
|
116 |
band = buffer.getBand(bandNumber); |
117 |
ToolsLocator.getDisposableManager().bind(band); |
118 |
return band;
|
119 |
} catch (DataException | BufferException | CreateGeometryException | InterruptedException | URLFormatException | DownloadingException e) { |
120 |
logger.warn("Can't fetch tile: zoomLevel = " + zoomLevel + ", tileRow = " + structRow |
121 |
+ ", tileColumn = " + structCol + ", band = " + bandNumber + ".", e); |
122 |
return null; |
123 |
} |
124 |
} |
125 |
} |
126 |
|
127 |
private DownloadedTile requestTile(int zoomLevel, int structRow, int structCol, String key) throws CreateEnvelopeException, |
128 |
CloneNotSupportedException, BufferException, ValidateDataParametersException, DataException, CreateGeometryException, URLFormatException, DownloadingException {
|
129 |
|
130 |
Double pixelSize = this.tileStruct.getPixelSizePerZoomLevel().get(zoomLevel); |
131 |
|
132 |
GeometryManager geomManager = GeometryLocator.getGeometryManager(); |
133 |
|
134 |
Envelope structExtent = this.tileStruct.getEnvelope();
|
135 |
int rowsPerTile = this.tileStruct.getRowsPerTile(); |
136 |
int columnsPerTile = this.tileStruct.getColumnsPerTile(); |
137 |
|
138 |
double minX = Math.max(structExtent.getMinimum(DIMENSIONS.X) + (structCol * (pixelSize * columnsPerTile)),structExtent.getMinimum(DIMENSIONS.X)); |
139 |
double minY = Math.max(structExtent.getMaximum(DIMENSIONS.Y) - ((structRow + 1) * (pixelSize * rowsPerTile)),structExtent.getMinimum(DIMENSIONS.Y)); |
140 |
double maxX = Math.min(structExtent.getMinimum(DIMENSIONS.X) + ((structCol + 1) * (pixelSize * columnsPerTile)),structExtent.getMaximum(DIMENSIONS.X)); |
141 |
double maxY = Math.min(structExtent.getMaximum(DIMENSIONS.Y) - (structRow * (pixelSize * rowsPerTile)),structExtent.getMaximum(DIMENSIONS.Y)); |
142 |
Envelope envelope = geomManager.createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D); |
143 |
Point center;
|
144 |
|
145 |
center = geomManager.createPoint(envelope.getCenter(DIMENSIONS.X), envelope.getCenter(DIMENSIONS.Y), SUBTYPES.GEOM2D); |
146 |
|
147 |
GoogleMapsManager googleMapsManager = GoogleMapsLocator.getManager(); |
148 |
GoogleMapsRequestParams requestParams = googleMapsManager.createRequestParams(); |
149 |
|
150 |
DataStoreParameters storeParameters = provider.getParameters(); |
151 |
requestParams.setHasApiKey((Boolean) storeParameters.getDynValue("hasApiKey")); |
152 |
requestParams.setApiKey((String) storeParameters.getDynValue("apiKey")); |
153 |
requestParams.setLanguage((String) storeParameters.getDynValue("language")); |
154 |
requestParams.setRegion((String) storeParameters.getDynValue("region")); |
155 |
requestParams.setURL("http://maps.google.com/maps/api/staticmap?");
|
156 |
requestParams.setMapType((String) storeParameters.getDynValue("mapType")); |
157 |
requestParams.setFormat((String) storeParameters.getDynValue("format")); |
158 |
|
159 |
GoogleMapsRequest googleRequest=googleMapsManager.createRequest(requestParams); |
160 |
DownloadedTile downloadedTile = new DownloadedTile(key, envelope);
|
161 |
downloadedTile.setImage(googleRequest.getTile(center, zoomLevel, (int)Math.round(envelope.getLength(DIMENSIONS.X)/pixelSize), (int)Math.round(envelope.getLength(DIMENSIONS.Y)/pixelSize))); |
162 |
|
163 |
return downloadedTile;
|
164 |
} |
165 |
|
166 |
private String composeKeyForRecentTiles(int zoomLevel, int structRow, int structCol) { |
167 |
StringBuilder builder = new StringBuilder(); |
168 |
builder.append(zoomLevel); |
169 |
builder.append(":");
|
170 |
builder.append(structCol); |
171 |
builder.append(":");
|
172 |
builder.append(structRow); |
173 |
return builder.toString();
|
174 |
} |
175 |
|
176 |
private void removeOlderTile() { |
177 |
DownloadedTile olderTile = null;
|
178 |
for (Iterator<DownloadedTile> iterator = recentAccededTiles.values().iterator(); iterator.hasNext();) { |
179 |
DownloadedTile tile = (DownloadedTile) iterator.next(); |
180 |
if (olderTile == null || tile.getLastAccess() < olderTile.getLastAccess()) { |
181 |
olderTile = tile; |
182 |
} |
183 |
} |
184 |
if (olderTile != null) { |
185 |
recentAccededTiles.remove(olderTile.getKey()); |
186 |
DisposeUtils.dispose(olderTile); |
187 |
} |
188 |
} |
189 |
|
190 |
|
191 |
private class DownloadedTile extends AbstractDisposable { //implements GoogleMapsRequestListener { |
192 |
|
193 |
private org.gvsig.raster.lib.buffer.api.Buffer buffer;
|
194 |
long lastAccess;
|
195 |
private String key; |
196 |
private Envelope envelope;
|
197 |
private boolean downloaded; |
198 |
|
199 |
public DownloadedTile(String key, Envelope envelope) { |
200 |
logger |
201 |
.info("CONSTRUCTOR hashCode = " + this.hashCode() + " className = " + this.getClass().getSimpleName()); |
202 |
this.key = key;
|
203 |
this.envelope = envelope;
|
204 |
lastAccess = System.currentTimeMillis();
|
205 |
this.downloaded = false; |
206 |
} |
207 |
|
208 |
public String getKey() { |
209 |
return key;
|
210 |
} |
211 |
|
212 |
public synchronized org.gvsig.raster.lib.buffer.api.Buffer getBuffer() throws InterruptedException { |
213 |
lastAccess = System.currentTimeMillis();
|
214 |
while(!isDownloaded()){
|
215 |
logger.info("Esperando al tile: "+this.key); |
216 |
this.wait();
|
217 |
} |
218 |
logger.info("Sirviendo el tile: "+this.key); |
219 |
return buffer;
|
220 |
} |
221 |
|
222 |
public long getLastAccess() { |
223 |
return lastAccess;
|
224 |
} |
225 |
|
226 |
@Override
|
227 |
protected void finalize() throws Throwable { |
228 |
super.finalize();
|
229 |
logger.info("CLEANED key " + this.key + " hashCode = " + this.hashCode()); |
230 |
} |
231 |
|
232 |
public synchronized void setImage(BufferedImage img) { |
233 |
|
234 |
downloaded = false;
|
235 |
|
236 |
try {
|
237 |
|
238 |
this.buffer =
|
239 |
BufferLocator.getBufferManager().createBuffer(img, GoogleMapsRasterProvider.GOOGLE_MAPS_PROJECTION, |
240 |
this.envelope);
|
241 |
|
242 |
} catch (LocatorException | BufferException e) {
|
243 |
logger.warn("Can't create buffer to load downloaded image.", e);
|
244 |
} |
245 |
|
246 |
this.downloaded = true; |
247 |
logger.info("Tile listo : " + this.key); |
248 |
this.notify();
|
249 |
} |
250 |
|
251 |
@Override
|
252 |
protected void doDispose() throws BaseException { |
253 |
logger.info("DO DISPOSE key " + this.key + " hashCode = " + this.hashCode()); |
254 |
DisposeUtils.dispose(buffer); |
255 |
buffer = null;
|
256 |
} |
257 |
|
258 |
|
259 |
public boolean isDownloaded(){ |
260 |
return this.downloaded; |
261 |
} |
262 |
} |
263 |
|
264 |
@Override
|
265 |
protected void doDispose() throws BaseException { |
266 |
if (recentAccededTiles != null) { |
267 |
Set<Entry<String, DownloadedTile>> entrySet = recentAccededTiles.entrySet(); |
268 |
for (Iterator<Entry<String, DownloadedTile>> iterator = entrySet.iterator(); iterator.hasNext();) { |
269 |
Entry<String, DownloadedTile> entry = (Entry<String, DownloadedTile>) iterator.next(); |
270 |
DisposeUtils.dispose(entry.getValue()); |
271 |
} |
272 |
recentAccededTiles.clear(); |
273 |
} |
274 |
DisposeUtils.dispose((Disposable) tileStruct); |
275 |
tileStruct = null;
|
276 |
} |
277 |
|
278 |
|
279 |
|
280 |
} |