Worldwind public release 0.2
[worldwind-tracker.git] / gov / nasa / worldwind / layers / PlaceNameLayer.java
blobf5fe0ede817aa32ca00b8818a1d17b77bb05332d
1 /*
2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
4 All Rights Reserved.
5 */
6 package gov.nasa.worldwind.layers;
8 import com.sun.opengl.util.*;
9 import gov.nasa.worldwind.*;
10 import gov.nasa.worldwind.geom.*;
11 import gov.nasa.worldwind.geom.Point;
13 import java.awt.*;
14 import java.util.*;
15 import java.util.List;
16 import java.util.Queue;
17 import java.util.concurrent.*;
18 import java.util.logging.Level;
20 /**
21 * @author Paul Collins
22 * @version $Id: PlaceNameLayer.java 1788 2007-05-08 17:12:05Z dcollins $
24 public class PlaceNameLayer extends AbstractLayer
26 private final PlaceNameServiceSet placeNameServiceSet;
27 private final List<Tile[]> tiles = new ArrayList<Tile[]>();
29 /**
30 * @param placeNameServiceSet the set of PlaceNameService objects that PlaceNameLayer will render.
31 * @throws IllegalArgumentException if <code>placeNameServiceSet</code> is null
33 public PlaceNameLayer(PlaceNameServiceSet placeNameServiceSet)
35 if (placeNameServiceSet == null)
37 String message = WorldWind.retrieveErrMsg("nullValue.PlaceNameServiceSetIsNull");
38 WorldWind.logger().log(Level.FINE, message);
39 throw new IllegalArgumentException(message);
42 this.placeNameServiceSet = placeNameServiceSet.deepCopy();
43 for (int i = 0; i < this.placeNameServiceSet.getServiceCount(); i++)
45 tiles.add(i, buildTiles(this.placeNameServiceSet.getService(i)));
49 public final PlaceNameServiceSet getPlaceNameServiceSet()
51 return this.placeNameServiceSet;
54 // ============== Tile Assembly ======================= //
55 // ============== Tile Assembly ======================= //
56 // ============== Tile Assembly ======================= //
58 private static class Tile
60 final PlaceNameService placeNameService;
61 final Sector sector;
62 final int row;
63 final int column;
64 final int hash;
65 // Computed data.
66 String fileCachePath = null;
67 Extent extent = null;
68 double extentVerticalExaggeration = Double.MIN_VALUE;
70 static int computeRow(Angle delta, Angle latitude)
72 if (delta == null || latitude == null)
74 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
75 WorldWind.logger().log(Level.FINE, msg);
76 throw new IllegalArgumentException(msg);
78 return (int) ((latitude.getDegrees() + 90d) / delta.getDegrees());
81 static int computeColumn(Angle delta, Angle longitude)
83 if (delta == null || longitude == null)
85 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
86 WorldWind.logger().log(Level.FINE, msg);
87 throw new IllegalArgumentException(msg);
89 return (int) ((longitude.getDegrees() + 180d) / delta.getDegrees());
92 static Angle computeRowLatitude(int row, Angle delta)
94 if (delta == null)
96 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
97 WorldWind.logger().log(Level.FINE, msg);
98 throw new IllegalArgumentException(msg);
100 return Angle.fromDegrees(-90d + delta.getDegrees() * row);
103 static Angle computeColumnLongitude(int column, Angle delta)
105 if (delta == null)
107 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
108 WorldWind.logger().log(Level.FINE, msg);
109 throw new IllegalArgumentException(msg);
111 return Angle.fromDegrees(-180 + delta.getDegrees() * column);
114 Tile(PlaceNameService placeNameService, Sector sector, int row, int column)
116 this.placeNameService = placeNameService;
117 this.sector = sector;
118 this.row = row;
119 this.column = column;
120 this.hash = this.computeHash();
123 int computeHash()
125 return this.getFileCachePath() != null ? this.getFileCachePath().hashCode() : 0;
128 @Override
129 public boolean equals(Object o)
131 if (this == o)
132 return true;
133 if (o == null || this.getClass() != o.getClass())
134 return false;
136 final Tile other = (Tile) o;
138 return this.getFileCachePath() != null ? !this.getFileCachePath().equals(other.getFileCachePath()) :
139 other.getFileCachePath() != null;
142 Extent getExtent(DrawContext dc)
144 if (dc == null)
146 String message = WorldWind.retrieveErrMsg("nullValue.DrawContextIsNull");
147 WorldWind.logger().log(Level.FINE, message);
148 throw new IllegalArgumentException(message);
151 if (this.extent == null || this.extentVerticalExaggeration != dc.getVerticalExaggeration())
153 this.extentVerticalExaggeration = dc.getVerticalExaggeration();
154 this.extent = Sector.computeBoundingCylinder(dc.getGlobe(), this.extentVerticalExaggeration,
155 this.sector);
158 return extent;
161 String getFileCachePath()
163 if (this.fileCachePath == null)
164 this.fileCachePath = this.placeNameService.createFileCachePathFromTile(this.row, this.column);
166 return this.fileCachePath;
169 PlaceNameService getPlaceNameService()
171 return placeNameService;
174 java.net.URL getRequestURL() throws java.net.MalformedURLException
176 return this.placeNameService.createServiceURLFromSector(this.sector);
179 Sector getSector()
181 return sector;
184 public int hashCode()
186 return this.hash;
190 private Tile[] buildTiles(PlaceNameService placeNameService)
192 final Sector sector = placeNameService.getSector();
193 final Angle dLat = placeNameService.getTileDelta().getLatitude();
194 final Angle dLon = placeNameService.getTileDelta().getLongitude();
196 // Determine the row and column offset from the global tiling origin for the southwest tile corner
197 int firstRow = Tile.computeRow(dLat, sector.getMinLatitude());
198 int firstCol = Tile.computeColumn(dLon, sector.getMinLongitude());
199 int lastRow = Tile.computeRow(dLat, sector.getMaxLatitude().subtract(dLat));
200 int lastCol = Tile.computeColumn(dLon, sector.getMaxLongitude().subtract(dLon));
202 int nLatTiles = lastRow - firstRow + 1;
203 int nLonTiles = lastCol - firstCol + 1;
205 Tile[] tiles = new Tile[nLatTiles * nLonTiles];
207 Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
208 for (int row = firstRow; row <= lastRow; row++)
210 Angle p2;
211 p2 = p1.add(dLat);
213 Angle t1 = Tile.computeColumnLongitude(firstCol, dLon);
214 for (int col = firstCol; col <= lastCol; col++)
216 Angle t2;
217 t2 = t1.add(dLon);
219 tiles[col + row * nLonTiles] = new Tile(placeNameService, new Sector(p1, p2, t1, t2), row, col);
220 t1 = t2;
222 p1 = p2;
225 return tiles;
228 // ============== Place Name Data Structures ======================= //
229 // ============== Place Name Data Structures ======================= //
230 // ============== Place Name Data Structures ======================= //
232 private static class PlaceNameChunk implements Cacheable
234 final PlaceNameService placeNameService;
235 final StringBuilder textArray;
236 final int[] textIndexArray;
237 final double[] latlonArray;
238 final int numEntries;
239 final long estimatedMemorySize;
241 PlaceNameChunk(PlaceNameService service, StringBuilder text, int[] textIndices,
242 double[] positions, int numEntries)
244 this.placeNameService = service;
245 this.textArray = text;
246 this.textIndexArray = textIndices;
247 this.latlonArray = positions;
248 this.numEntries = numEntries;
249 this.estimatedMemorySize = this.computeEstimatedMemorySize();
252 long computeEstimatedMemorySize()
254 long result = 0;
255 result += BufferUtil.SIZEOF_SHORT * textArray.capacity();
256 result += BufferUtil.SIZEOF_INT * textIndexArray.length;
257 result += BufferUtil.SIZEOF_DOUBLE * latlonArray.length;
258 return result;
261 Position getPosition(int index)
263 int latlonIndex = 2 * index;
264 return Position.fromDegrees(latlonArray[latlonIndex], latlonArray[latlonIndex + 1], 0);
267 PlaceNameService getPlaceNameService()
269 return this.placeNameService;
272 String getText(int index)
274 int beginIndex = textIndexArray[index];
275 int endIndex = (index + 1 < numEntries) ? textIndexArray[index + 1] : textArray.length();
276 return this.textArray.substring(beginIndex, endIndex);
279 public long getSizeInBytes()
281 return this.estimatedMemorySize;
284 Iterator<PlaceName> createRenderIterator(final DrawContext dc)
286 return new Iterator<PlaceName>()
288 PlaceNameImpl placeNameProxy = new PlaceNameImpl();
289 int index = -1;
291 public boolean hasNext()
293 return index < (PlaceNameChunk.this.numEntries - 1);
296 public PlaceName next()
298 if (!hasNext())
299 throw new NoSuchElementException();
300 this.updateProxy(placeNameProxy, ++index);
301 return placeNameProxy;
304 public void remove()
306 throw new UnsupportedOperationException();
309 void updateProxy(PlaceNameImpl proxy, int index)
311 proxy.text = getText(index);
312 proxy.position = getPosition(index);
313 proxy.font = placeNameService.getFont();
314 proxy.color = placeNameService.getColor();
315 proxy.visible = isNameVisible(dc, placeNameService, proxy.position);
321 private static class PlaceNameImpl implements PlaceName
323 String text;
324 Position position;
325 Font font;
326 Color color;
327 boolean visible;
329 PlaceNameImpl()
333 public String getText()
335 return this.text;
338 public void setText(String text)
340 throw new UnsupportedOperationException();
343 public Position getPosition()
345 return this.position;
348 public void setPosition(Position position)
350 throw new UnsupportedOperationException();
353 public Font getFont()
355 return this.font;
358 public void setFont(Font font)
360 throw new UnsupportedOperationException();
363 public Color getColor()
365 return this.color;
368 public void setColor(Color color)
370 throw new UnsupportedOperationException();
373 public boolean isVisible()
375 return this.visible;
378 public void setVisible(boolean visible)
380 throw new UnsupportedOperationException();
383 public WWIcon getIcon()
385 return null;
388 public void setIcon(WWIcon icon)
390 throw new UnsupportedOperationException();
394 // ============== Rendering ======================= //
395 // ============== Rendering ======================= //
396 // ============== Rendering ======================= //
398 private final PlaceNameRenderer placeNameRenderer = new PlaceNameRenderer();
400 @Override
401 protected void doRender(DrawContext dc)
403 final boolean enableDepthTest = dc.getView().getAltitude()
404 < (dc.getVerticalExaggeration() * dc.getGlobe().getMaxElevation());
406 int serviceCount = this.placeNameServiceSet.getServiceCount();
407 for (int i = 0; i < serviceCount; i++)
409 PlaceNameService placeNameService = this.placeNameServiceSet.getService(i);
410 if (!isServiceVisible(dc, placeNameService))
411 continue;
413 double minDist = placeNameService.getMinDisplayDistance();
414 double maxDist = placeNameService.getMaxDisplayDistance();
415 double minDistSquared = minDist * minDist;
416 double maxDistSquared = maxDist * maxDist;
418 Tile[] tiles = this.tiles.get(i);
419 for (Tile tile : tiles)
423 drawOrRequestTile(dc, tile, minDistSquared, maxDistSquared, enableDepthTest);
425 catch (Exception e)
427 String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionRenderingTile");
428 WorldWind.logger().log(Level.FINE, message, e);
433 this.sendRequests();
436 private void drawOrRequestTile(DrawContext dc, Tile tile, double minDisplayDistanceSquared,
437 double maxDisplayDistanceSquared, boolean enableDepthTest)
439 if (!isTileVisible(dc, tile, minDisplayDistanceSquared, maxDisplayDistanceSquared))
440 return;
442 Object cacheObj = WorldWind.memoryCache().getObject(tile);
443 if (cacheObj == null)
445 this.requestTile(this.readQueue, tile);
446 return;
449 if (!(cacheObj instanceof PlaceNameChunk))
450 return;
452 PlaceNameChunk placeNameChunk = (PlaceNameChunk) cacheObj;
453 Iterator<PlaceName> renderIter = placeNameChunk.createRenderIterator(dc);
454 placeNameRenderer.render(dc, renderIter, enableDepthTest);
457 private static boolean isServiceVisible(DrawContext dc, PlaceNameService placeNameService)
459 if (!placeNameService.isEnabled())
460 return false;
461 //noinspection SimplifiableIfStatement
462 if (dc.getVisibleSector() != null && !placeNameService.getSector().intersects(dc.getVisibleSector()))
463 return false;
465 return placeNameService.getExtent(dc).intersects(dc.getView().getFrustumInModelCoordinates());
468 private static boolean isTileVisible(DrawContext dc, Tile tile, double minDistanceSquared,
469 double maxDistanceSquared)
471 if (!tile.getSector().intersects(dc.getVisibleSector()))
472 return false;
474 Position viewPosition = dc.getView().getPosition();
475 Angle lat = clampAngle(viewPosition.getLatitude(), tile.getSector().getMinLatitude(),
476 tile.getSector().getMaxLatitude());
477 Angle lon = clampAngle(viewPosition.getLongitude(), tile.getSector().getMinLongitude(),
478 tile.getSector().getMaxLongitude());
479 Point p = dc.getGlobe().computePointFromPosition(lat, lon, 0d);
480 double distSquared = dc.getView().getEyePoint().distanceToSquared(p);
481 //noinspection RedundantIfStatement
482 if (minDistanceSquared > distSquared || maxDistanceSquared < distSquared)
483 return false;
485 return true;
488 private static boolean isNameVisible(DrawContext dc, PlaceNameService service, Position namePosition)
490 double elevation = dc.getVerticalExaggeration() * namePosition.getElevation();
491 Point namePoint = dc.getGlobe().computePointFromPosition(namePosition.getLatitude(),
492 namePosition.getLongitude(), elevation);
493 Point eye = dc.getView().getEyePoint();
495 double dist = eye.distanceTo(namePoint);
496 return dist >= service.getMinDisplayDistance() && dist <= service.getMaxDisplayDistance();
499 private static Angle clampAngle(Angle a, Angle min, Angle max)
501 return a.compareTo(min) < 0 ? min : (a.compareTo(max) > 0 ? max : a);
504 // ============== Image Reading and Downloading ======================= //
505 // ============== Image Reading and Downloading ======================= //
506 // ============== Image Reading and Downloading ======================= //
508 private static final int MAX_REQUESTS = 64;
509 private final Queue<Tile> downloadQueue = new LinkedBlockingQueue<Tile>(MAX_REQUESTS);
510 private final Queue<Tile> readQueue = new LinkedBlockingQueue<Tile>(MAX_REQUESTS);
512 private static class RequestTask implements Runnable
514 final PlaceNameLayer layer;
515 final Tile tile;
517 RequestTask(PlaceNameLayer layer, Tile tile)
519 this.layer = layer;
520 this.tile = tile;
523 @Override
524 public boolean equals(Object o)
526 if (this == o)
527 return true;
528 if (o == null || this.getClass() != o.getClass())
529 return false;
531 final RequestTask other = (RequestTask) o;
533 // Don't include layer in comparison so that requests are shared among layers
534 return !(this.tile != null ? !this.tile.equals(other.tile) : other.tile != null);
537 @Override
538 public int hashCode()
540 return (this.tile != null ? this.tile.hashCode() : 0);
543 public void run()
545 synchronized (tile)
547 if (WorldWind.memoryCache().getObject(this.tile) != null)
548 return;
550 final java.net.URL tileURL = WorldWind.dataFileCache().findFile(tile.getFileCachePath(), false);
551 if (tileURL != null)
553 if (this.layer.loadTile(this.tile, tileURL))
555 tile.getPlaceNameService().unmarkResourceAbsent(tile.getPlaceNameService().getTileNumber(
556 tile.row,
557 tile.column));
558 this.layer.firePropertyChange(AVKey.LAYER, null, this);
560 else
562 // Assume that something's wrong with the file and delete it.
563 WorldWind.dataFileCache().removeFile(tileURL);
564 tile.getPlaceNameService().markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row,
565 tile.column));
566 String message = WorldWind.retrieveErrMsg("generic.DeletedCorruptDataFile") + tileURL;
567 WorldWind.logger().log(Level.FINE, message);
569 return;
573 this.layer.requestTile(this.layer.downloadQueue, this.tile);
576 public String toString()
578 return this.tile.toString();
582 private static class DownloadPostProcessor implements RetrievalPostProcessor
584 final PlaceNameLayer layer;
585 final Tile tile;
587 private DownloadPostProcessor(PlaceNameLayer layer, Tile tile)
589 this.layer = layer;
590 this.tile = tile;
593 public java.nio.ByteBuffer run(Retriever retriever)
595 if (retriever == null)
597 String msg = WorldWind.retrieveErrMsg("nullValue.RetrieverIsNull");
598 WorldWind.logger().log(Level.FINE, msg);
599 throw new IllegalArgumentException(msg);
602 if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL))
603 return null;
605 if (!(retriever instanceof URLRetriever))
606 return null;
610 if (retriever instanceof HTTPRetriever)
612 HTTPRetriever httpRetriever = (HTTPRetriever) retriever;
613 if (httpRetriever.getResponseCode() == java.net.HttpURLConnection.HTTP_NO_CONTENT)
615 // Mark tile as missing to avoid further attempts
616 tile.getPlaceNameService().markResourceAbsent(tile.getPlaceNameService().getTileNumber(tile.row,
617 tile.column));
618 return null;
622 URLRetriever urlRetriever = (URLRetriever) retriever;
623 java.nio.ByteBuffer buffer = urlRetriever.getBuffer();
625 synchronized (tile)
627 final java.io.File cacheFile = WorldWind.dataFileCache().newFile(this.tile.getFileCachePath());
628 if (cacheFile == null)
630 String msg = WorldWind.retrieveErrMsg("generic.CantCreateCacheFile")
631 + this.tile.getFileCachePath();
632 WorldWind.logger().log(Level.FINE, msg);
633 return null;
636 if (cacheFile.exists())
637 return buffer; // info is already here; don't need to do anything
639 if (buffer != null)
641 WWIO.saveBuffer(buffer, cacheFile);
642 this.layer.firePropertyChange(AVKey.LAYER, null, this);
643 return buffer;
647 catch (java.io.IOException e)
649 String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionSavingRetrievedFile");
650 WorldWind.logger().log(Level.FINE, message + this.tile.getFileCachePath(), e);
653 return null;
657 private static class GMLPlaceNameSAXHandler extends org.xml.sax.helpers.DefaultHandler
659 static final String GML_FEATURE_MEMBER = "gml:featureMember";
660 static final String TOPP_FULL_NAME_ND = "topp:full_name_nd";
661 static final String TOPP_LATITUDE = "topp:latitude";
662 static final String TOPP_LONGITUDE = "topp:longitude";
663 final LinkedList<String> qNameStack = new LinkedList<String>();
664 boolean inBeginEndPair = false;
665 StringBuilder latBuffer = new StringBuilder();
666 StringBuilder lonBuffer = new StringBuilder();
668 StringBuilder textArray = new StringBuilder();
669 int[] textIndexArray = new int[16];
670 double[] latlonArray = new double[16];
671 int numEntries = 0;
673 GMLPlaceNameSAXHandler()
677 PlaceNameChunk createPlaceNameChunk(PlaceNameService service)
679 return new PlaceNameChunk(service, this.textArray, this.textIndexArray, this.latlonArray, this.numEntries);
682 void beginEntry()
684 int textIndex = this.textArray.length();
685 this.textIndexArray = append(this.textIndexArray, this.numEntries, textIndex);
686 this.inBeginEndPair = true;
689 void endEntry()
691 double lat = this.parseDouble(this.latBuffer);
692 double lon = this.parseDouble(this.lonBuffer);
693 int numLatLon = 2 * this.numEntries;
694 this.latlonArray = this.append(this.latlonArray, numLatLon, lat);
695 numLatLon++;
696 this.latlonArray = this.append(this.latlonArray, numLatLon, lon);
698 this.latBuffer.delete(0, this.latBuffer.length());
699 this.lonBuffer.delete(0, this.lonBuffer.length());
700 this.inBeginEndPair = false;
701 this.numEntries++;
704 double parseDouble(StringBuilder sb)
706 double value = 0;
709 value = Double.parseDouble(sb.toString());
711 catch (NumberFormatException e)
713 String msg = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile");
714 WorldWind.logger().log(Level.FINE, msg, e);
716 return value;
719 int[] append(int[] array, int index, int value)
721 if (index >= array.length)
722 array = this.resizeArray(array);
723 array[index] = value;
724 return array;
727 int[] resizeArray(int[] oldArray)
729 int newSize = 2 * oldArray.length;
730 int[] newArray = new int[newSize];
731 System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
732 return newArray;
735 double[] append(double[] array, int index, double value)
737 if (index >= array.length)
738 array = this.resizeArray(array);
739 array[index] = value;
740 return array;
743 double[] resizeArray(double[] oldArray)
745 int newSize = 2 * oldArray.length;
746 double[] newArray = new double[newSize];
747 System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
748 return newArray;
751 public void characters(char ch[], int start, int length)
753 if (!this.inBeginEndPair)
754 return;
756 String top = this.qNameStack.getFirst();
758 StringBuilder sb = null;
759 if (TOPP_LATITUDE == top)
760 sb = this.latBuffer;
761 else if (TOPP_LONGITUDE == top)
762 sb = this.lonBuffer;
763 else if (TOPP_FULL_NAME_ND == top)
764 sb = this.textArray;
766 if (sb != null)
767 sb.append(ch, start, length);
770 public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes)
772 String internQName = qName.intern();
773 // Don't validate uri, localName or attributes because they aren't used.
774 if (GML_FEATURE_MEMBER == internQName)
775 this.beginEntry();
776 this.qNameStack.addFirst(qName);
779 public void endElement(String uri, String localName, String qName)
781 String internQName = qName.intern();
782 // Don't validate uri or localName because they aren't used.
783 if (GML_FEATURE_MEMBER == internQName)
784 this.endEntry();
785 this.qNameStack.removeFirst();
789 private boolean loadTile(Tile tile, java.net.URL url)
791 PlaceNameChunk placeNameChunk = readTile(tile, url);
792 if (placeNameChunk == null)
793 return false;
795 WorldWind.memoryCache().add(tile, placeNameChunk);
796 return true;
799 private static PlaceNameChunk readTile(Tile tile, java.net.URL url)
801 java.io.InputStream is = null;
805 String path = url.getFile();
806 path = path.replaceAll("%20", " "); // TODO: find a better way to get a path usable by FileInputStream
808 java.io.FileInputStream fis = new java.io.FileInputStream(path);
809 java.io.BufferedInputStream buf = new java.io.BufferedInputStream(fis);
810 is = new java.util.zip.GZIPInputStream(buf);
812 GMLPlaceNameSAXHandler handler = new GMLPlaceNameSAXHandler();
813 javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().parse(is, handler);
814 return handler.createPlaceNameChunk(tile.getPlaceNameService());
816 catch (Exception e)
818 String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile");
819 WorldWind.logger().log(Level.FINE, message, e);
821 finally
825 if (is != null)
826 is.close();
828 catch (java.io.IOException e)
830 String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToReadFile");
831 WorldWind.logger().log(Level.FINE, message, e);
835 return null;
838 private void requestTile(Queue<Tile> queue, Tile tile)
840 if (tile.getPlaceNameService().isResourceAbsent(tile.getPlaceNameService().getTileNumber(
841 tile.row, tile.column)))
842 return;
843 if (!queue.contains(tile))
844 queue.offer(tile);
847 private void sendRequests()
849 Tile tile;
850 // Send threaded read tasks.
851 while (!WorldWind.threadedTaskService().isFull() && (tile = this.readQueue.poll()) != null)
853 WorldWind.threadedTaskService().addTask(new RequestTask(this, tile));
855 // Send retriever tasks.
856 while (!WorldWind.retrievalService().isFull() && (tile = this.downloadQueue.poll()) != null)
858 java.net.URL url;
861 url = tile.getRequestURL();
863 catch (java.net.MalformedURLException e)
865 String message = WorldWind.retrieveErrMsg("layers.PlaceNameLayer.ExceptionAttemptingToDownloadFile");
866 WorldWind.logger().log(Level.FINE, message + tile, e);
867 return;
869 WorldWind.retrievalService().runRetriever(new HTTPRetriever(url, new DownloadPostProcessor(this, tile)));