Updated to worldwind release 20070817
[worldwind-tracker.git] / gov / nasa / worldwind / util / LevelSet.java
blob74e42a404036e04e8df3270036f2d9cdc183e6e1
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
7 package gov.nasa.worldwind.util;
9 import gov.nasa.worldwind.WWObjectImpl;
10 import gov.nasa.worldwind.avlist.*;
11 import gov.nasa.worldwind.geom.*;
13 import java.net.*;
14 import java.util.*;
16 /**
17 * @author tag
18 * @version $Id: LevelSet.java 2593 2007-08-18 00:03:31Z tgaskins $
20 public class LevelSet extends WWObjectImpl
22 public static final class SectorResolution
24 private final int levelNumber;
25 private final Sector sector;
27 public SectorResolution(Sector sector, int levelNumber)
29 this.levelNumber = levelNumber;
30 this.sector = sector;
34 private final Sector sector;
35 private final LatLon levelZeroTileDelta;
36 private final int numLevelZeroColumns;
37 private final java.util.ArrayList<Level> levels = new java.util.ArrayList<Level>();
38 private final SectorResolution[] sectorLevelLimits;
40 public LevelSet(AVList params)
42 StringBuffer sb = new StringBuffer();
44 Object o = params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA);
45 if (o == null || !(o instanceof LatLon))
46 sb.append(Logging.getMessage("term.tileDelta"));
48 o = params.getValue(AVKey.SECTOR);
49 if (o == null || !(o instanceof Sector))
50 sb.append(Logging.getMessage("term.sector"));
52 int numLevels = 0;
53 o = params.getValue(AVKey.NUM_LEVELS);
54 if (o == null || !(o instanceof Integer) || (numLevels = (Integer) o) < 1)
55 sb.append(Logging.getMessage("term.numLevels"));
57 int numEmptyLevels = 0;
58 o = params.getValue(AVKey.NUM_EMPTY_LEVELS);
59 if (o == null || !(o instanceof Integer) || (numEmptyLevels = (Integer) o) < 0)
60 sb.append(Logging.getMessage("term.numEMptyLevels"));
62 SectorResolution[] sectorLimits = null;
63 o = params.getValue(AVKey.SECTOR_RESOLUTION_LIMITS);
64 if (o != null && !(o instanceof SectorResolution[]))
66 sb.append(Logging.getMessage("term.sectorResolutionLimits"));
68 else if (o != null)
70 sectorLimits = (SectorResolution[]) o;
71 for (SectorResolution sr : sectorLimits)
73 if (sr.levelNumber > numLevels - 1)
75 String message =
76 Logging.getMessage("LevelSet.sectorResolutionLimitsTooHigh", sr.levelNumber, numLevels - 1);
77 Logging.logger().warning(message);
78 break;
82 this.sectorLevelLimits = sectorLimits;
84 if (sb.length() > 0)
86 String message = Logging.getMessage("layers.LevelSet.InvalidLevelDescriptorFields", sb.toString());
87 Logging.logger().severe(message);
88 throw new IllegalArgumentException(message);
91 this.levelZeroTileDelta = (LatLon) params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA);
92 this.sector = (Sector) params.getValue(AVKey.SECTOR);
94 params = params.copy(); // copy so as not to modify the user's params
96 TileUrlBuilder tub = (TileUrlBuilder) params.getValue(AVKey.TILE_URL_BUILDER);
97 if (tub == null)
99 params.setValue(AVKey.TILE_URL_BUILDER, new TileUrlBuilder()
101 public URL getURL(Tile tile) throws MalformedURLException
103 StringBuffer sb = new StringBuffer(tile.getLevel().getService());
104 if (sb.lastIndexOf("?") != sb.length() - 1)
105 sb.append("?");
106 sb.append("T=");
107 sb.append(tile.getLevel().getDataset());
108 sb.append("&L=");
109 sb.append(tile.getLevel().getLevelName());
110 sb.append("&X=");
111 sb.append(tile.getColumn());
112 sb.append("&Y=");
113 sb.append(tile.getRow());
115 return new URL(sb.toString());
120 for (int i = 0; i < numLevels; i++)
122 params.setValue(AVKey.LEVEL_NAME, i < numEmptyLevels ? "" : Integer.toString(i - numEmptyLevels));
123 params.setValue(AVKey.LEVEL_NUMBER, i);
125 Angle latDelta = this.levelZeroTileDelta.getLatitude().divide(Math.pow(2, i));
126 Angle lonDelta = this.levelZeroTileDelta.getLongitude().divide(Math.pow(2, i));
127 params.setValue(AVKey.TILE_DELTA, new LatLon(latDelta, lonDelta));
129 this.levels.add(new Level(params));
132 if (this.sectorLevelLimits != null)
134 Arrays.sort(this.sectorLevelLimits, new Comparator<SectorResolution>()
136 public int compare(SectorResolution sra, SectorResolution srb)
138 // sort order is deliberately backwards in order to list higher-resolution sectors first
139 return sra.levelNumber < srb.levelNumber ? 1 : sra.levelNumber == srb.levelNumber ? 0 : -1;
144 this.numLevelZeroColumns =
145 (int) Math.round(this.sector.getDeltaLon().divide(this.levelZeroTileDelta.getLongitude()));
148 public LevelSet(LevelSet source)
150 if (source == null)
152 String msg = Logging.getMessage("nullValue.LevelSetIsNull");
153 Logging.logger().severe(msg);
154 throw new IllegalArgumentException(msg);
157 this.levelZeroTileDelta = source.levelZeroTileDelta;
158 this.sector = source.sector;
159 this.numLevelZeroColumns = source.numLevelZeroColumns;
160 this.sectorLevelLimits = source.sectorLevelLimits;
162 for (Level level : source.levels)
164 this.levels.add(level); // Levels are final, so it's safe to copy references.
168 public final Sector getSector()
170 return this.sector;
173 public final LatLon getLevelZeroTileDelta()
175 return this.levelZeroTileDelta;
178 public final ArrayList<Level> getLevels()
180 return this.levels;
183 public final Level getLevel(int levelNumber)
185 return (levelNumber >= 0 && levelNumber < this.levels.size()) ? this.levels.get(levelNumber) : null;
188 public final int getNumLevels()
190 return this.levels.size();
193 public final Level getFirstLevel()
195 return this.getLevel(0);
198 public final Level getLastLevel()
200 return this.getLevel(this.getNumLevels() - 1);
203 public final Level getLastLevel(Sector sector)
205 Level level = this.getLevel(this.getNumLevels() - 1);
207 if (this.sectorLevelLimits != null)
208 for (SectorResolution sr : this.sectorLevelLimits)
210 if (sr.sector.intersects(sector) && sr.levelNumber <= level.getLevelNumber())
212 level = this.getLevel(sr.levelNumber);
213 break;
217 return level;
220 public final Level getLastLevel(Angle latitude, Angle longitude)
222 Level level = this.getLevel(this.getNumLevels() - 1);
224 if (this.sectorLevelLimits != null)
225 for (SectorResolution sr : this.sectorLevelLimits)
227 if (sr.sector.contains(latitude, longitude) && sr.levelNumber <= level.getLevelNumber())
229 level = this.getLevel(sr.levelNumber);
230 break;
234 return level;
237 public final boolean isFinalLevel(int levelNum)
239 return levelNum == this.getNumLevels() - 1;
242 public final boolean isLevelEmpty(int levelNumber)
244 return this.levels.get(levelNumber).isEmpty();
247 private int numColumnsInLevel(Level level)
249 int levelDelta = level.getLevelNumber() - this.getFirstLevel().getLevelNumber();
250 double twoToTheN = Math.pow(2, levelDelta);
251 return (int) (twoToTheN * this.numLevelZeroColumns);
254 private long getTileNumber(Tile tile)
256 return tile.getRow() * this.numColumnsInLevel(tile.getLevel()) + tile.getColumn();
260 * Instructs the level set that a tile is likely to be absent.
262 * @param tile The tile to mark as having an absent resource.
263 * @throws IllegalArgumentException if <code>tile</code> is null
265 public final void markResourceAbsent(Tile tile)
267 if (tile == null)
269 String msg = Logging.getMessage("nullValue.TileIsNull");
270 Logging.logger().severe(msg);
271 throw new IllegalArgumentException(msg);
274 tile.getLevel().markResourceAbsent(this.getTileNumber(tile));
278 * Indicates whether a tile has been marked as absent.
280 * @param tile The tile in question.
281 * @return <code>true</code> if the tile is marked absent, otherwise <code>false</code>.
282 * @throws IllegalArgumentException if <code>tile</code> is null
284 public final boolean isResourceAbsent(Tile tile)
286 if (tile == null)
288 String msg = Logging.getMessage("nullValue.TileIsNull");
289 Logging.logger().severe(msg);
290 throw new IllegalArgumentException(msg);
293 if (tile.getLevel().isEmpty())
294 return true;
296 int tileNumber = tile.getRow() * this.numColumnsInLevel(tile.getLevel()) + tile.getColumn();
297 return tile.getLevel().isResourceAbsent(tileNumber);
301 * Removes the absent-tile mark associated with a tile, if one is associatied.
303 * @param tile The tile to unmark.
304 * @throws IllegalArgumentException if <code>tile</code> is null
306 public final void unmarkResourceAbsent(Tile tile)
308 if (tile == null)
310 String msg = Logging.getMessage("nullValue.TileIsNull");
311 Logging.logger().severe(msg);
312 throw new IllegalArgumentException(msg);
315 tile.getLevel().unmarkResourceAbsent(this.getTileNumber(tile));