2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
.util
;
9 import gov
.nasa
.worldwind
.WWObjectImpl
;
10 import gov
.nasa
.worldwind
.avlist
.*;
11 import gov
.nasa
.worldwind
.geom
.*;
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
;
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"));
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"));
70 sectorLimits
= (SectorResolution
[]) o
;
71 for (SectorResolution sr
: sectorLimits
)
73 if (sr
.levelNumber
> numLevels
- 1)
76 Logging
.getMessage("LevelSet.sectorResolutionLimitsTooHigh", sr
.levelNumber
, numLevels
- 1);
77 Logging
.logger().warning(message
);
82 this.sectorLevelLimits
= sectorLimits
;
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
);
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)
107 sb
.append(tile
.getLevel().getDataset());
109 sb
.append(tile
.getLevel().getLevelName());
111 sb
.append(tile
.getColumn());
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
)
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()
173 public final LatLon
getLevelZeroTileDelta()
175 return this.levelZeroTileDelta
;
178 public final ArrayList
<Level
> getLevels()
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
);
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
);
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
)
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
)
288 String msg
= Logging
.getMessage("nullValue.TileIsNull");
289 Logging
.logger().severe(msg
);
290 throw new IllegalArgumentException(msg
);
293 if (tile
.getLevel().isEmpty())
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
)
310 String msg
= Logging
.getMessage("nullValue.TileIsNull");
311 Logging
.logger().severe(msg
);
312 throw new IllegalArgumentException(msg
);
315 tile
.getLevel().unmarkResourceAbsent(this.getTileNumber(tile
));