placenamelayer.java
来自「world wind java sdk 源码」· Java 代码 · 共 1,493 行 · 第 1/4 页
JAVA
1,493 行
/*
Copyright (C) 2001, 2006 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.placename;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.cache.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.retrieve.*;
import gov.nasa.worldwind.util.*;
import java.net.URL;
import java.nio.*;
import java.nio.channels.ClosedByInterruptException;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.logging.Level;
/**
* @author Paul Collins
* @version $Id: PlaceNameLayer.java 10925 2009-05-06 22:22:50Z dcollins $
*/
public class PlaceNameLayer extends AbstractLayer implements BulkRetrievable
{
private final PlaceNameServiceSet placeNameServiceSet;
private PriorityBlockingQueue<Runnable> requestQ = new PriorityBlockingQueue<Runnable>(64);
private Vec4 referencePoint;
private final Object fileLock = new Object();
private boolean cullNames = false;
protected static final double LEVEL_A = 0x1 << 25;
protected static final double LEVEL_B = 0x1 << 24;
protected static final double LEVEL_C = 0x1 << 23;
protected static final double LEVEL_D = 0x1 << 22;
protected static final double LEVEL_E = 0x1 << 21;
protected static final double LEVEL_F = 0x1 << 20;
protected static final double LEVEL_G = 0x1 << 19;
protected static final double LEVEL_H = 0x1 << 18;
protected static final double LEVEL_I = 0x1 << 17;
protected static final double LEVEL_J = 0x1 << 16;
protected static final double LEVEL_K = 0x1 << 15;
protected static final double LEVEL_L = 0x1 << 14;
protected static final double LEVEL_M = 0x1 << 13;
protected static final double LEVEL_N = 0x1 << 12;
protected static final double LEVEL_O = 0x1 << 11;
protected static final double LEVEL_P = 0x1 << 10;
protected static final LatLon GRID_1x1 = new LatLon(Angle.fromDegrees(180d), Angle.fromDegrees(360d));
protected static final LatLon GRID_4x8 = new LatLon(Angle.fromDegrees(45d), Angle.fromDegrees(45d));
protected static final LatLon GRID_8x16 = new LatLon(Angle.fromDegrees(22.5d), Angle.fromDegrees(22.5d));
protected static final LatLon GRID_16x32 = new LatLon(Angle.fromDegrees(11.25d), Angle.fromDegrees(11.25d));
protected static final LatLon GRID_36x72 = new LatLon(Angle.fromDegrees(5d), Angle.fromDegrees(5d));
protected static final LatLon GRID_72x144 = new LatLon(Angle.fromDegrees(2.5d), Angle.fromDegrees(2.5d));
protected static final LatLon GRID_144x288 = new LatLon(Angle.fromDegrees(1.25d), Angle.fromDegrees(1.25d));
protected static final LatLon GRID_288x576 = new LatLon(Angle.fromDegrees(0.625d), Angle.fromDegrees(0.625d));
private List<NavigationTile> navTiles = new ArrayList<NavigationTile>(); //top navigation tiles for each service
/**
* @param placeNameServiceSet the set of PlaceNameService objects that PlaceNameLayer will render.
* @throws IllegalArgumentException if {@link gov.nasa.worldwind.layers.placename.PlaceNameServiceSet} is null
*/
public PlaceNameLayer(PlaceNameServiceSet placeNameServiceSet)
{
if (placeNameServiceSet == null)
{
String message = Logging.getMessage("nullValue.PlaceNameServiceSetIsNull");
Logging.logger().fine(message);
throw new IllegalArgumentException(message);
}
//
this.placeNameServiceSet = placeNameServiceSet.deepCopy();
for (int i = 0; i < this.placeNameServiceSet.getServiceCount(); i++)
{
//todo do this for long as well and pick min
int calc1 = (int) (PlaceNameService.TILING_SECTOR.getDeltaLatDegrees()/this.placeNameServiceSet.getService(i).getTileDelta().getLatitude().getDegrees());
int numLevels=(int)Math.log(calc1);
navTiles.add(new NavigationTile(this.placeNameServiceSet.getService(i), PlaceNameService.TILING_SECTOR, numLevels, "top"));
}
if (!WorldWind.getMemoryCacheSet().containsCache(Tile.class.getName()))
{
long size = Configuration.getLongValue(AVKey.PLACENAME_LAYER_CACHE_SIZE, 2000000L);
MemoryCache cache = new BasicMemoryCache((long) (0.85 * size), size);
cache.setName("Placename Tiles");
WorldWind.getMemoryCacheSet().addCache(Tile.class.getName(), cache);
}
}
public boolean isCullNames()
{
return cullNames;
}
public void setCullNames(boolean cullNames)
{
this.cullNames = cullNames;
placeNameRenderer.setCullTextEnabled(cullNames);
}
public final PlaceNameServiceSet getPlaceNameServiceSet()
{
return this.placeNameServiceSet;
}
private PriorityBlockingQueue<Runnable> getRequestQ()
{
return this.requestQ;
}
// ============== Tile Assembly ======================= //
// ============== Tile Assembly ======================= //
// ============== Tile Assembly ======================= //
private class NavigationTile
{
String id;
private PlaceNameService placeNameService;
public Sector navSector;
private List<NavigationTile> subNavTiles= new ArrayList<NavigationTile>();
private List<Integer> tileKeys = new ArrayList<Integer>();
private int level;
NavigationTile(PlaceNameService placeNameService, Sector sector, int levels, String id)
{
this.placeNameService = placeNameService;
this.id=id;
this.navSector = sector;
level=levels;
}
private void buildSubNavTiles()
{
if (level > 0)
{
//split sector, create a navTile for each quad
Sector[] subSectors=this.navSector.subdivide();
for( int j=0; j<subSectors.length; j++)
{
subNavTiles.add(new NavigationTile(placeNameService, subSectors[j], level-1, this.id+"."+j));
}
}
}
public List<NavigationTile> navTilesVisible(DrawContext dc, double minDistSquared, double maxDistSquared)
{
ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
if (this.isNavSectorVisible(dc, minDistSquared, maxDistSquared))
{
if ( this.level > 0 && !this.hasSubTiles())
this.buildSubNavTiles();
if (this.hasSubTiles())
{
for(NavigationTile nav: subNavTiles)
{
navList.addAll(nav.navTilesVisible(dc, minDistSquared, maxDistSquared));
}
}else //at bottom level navigation tile
{
navList.add(this);
}
}
return navList;
}
//Added for bulk download, does not use eye position to determine visibility
//todo validate sector
public List<NavigationTile> navTilesVisible(Sector sector)
{
ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
if (navSector.intersects(sector))
{
if ( this.level > 0 && !this.hasSubTiles())
this.buildSubNavTiles();
if (this.hasSubTiles())
{
for(NavigationTile nav: subNavTiles)
{
navList.addAll(nav.navTilesVisible(sector));
}
}else //at bottom level navigation tile
{
navList.add(this);
}
}
return navList;
}
private int estimateNumberTilesinSector(Sector searchSector)
{
final Angle dLat = placeNameService.getTileDelta().getLatitude();
final Angle dLon = placeNameService.getTileDelta().getLongitude();
// Determine the row and column offset from the global tiling origin for the southwest tile corner
int firstRow = Tile.computeRow(dLat, this.navSector.getMinLatitude());
int firstCol = Tile.computeColumn(dLon, this.navSector.getMinLongitude());
int lastRow = Tile.computeRow(dLat, this.navSector.getMaxLatitude().subtract(dLat));
int lastCol = Tile.computeColumn(dLon, this.navSector.getMaxLongitude().subtract(dLon));
int tileCount=0;
Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
boolean needToCheckDisk = true;
for (int row = 0; row <= lastRow-firstRow; row++)
{
Angle p2;
p2 = p1.add(dLat);
Angle t1 = Tile.computeColumnLongitude(firstCol, dLon);
for (int col = 0; col <= lastCol-firstCol; col++)
{
Angle t2;
t2 = t1.add(dLon);
Sector tileSector = new Sector(p1, p2, t1, t2);
if (tileSector.intersects(searchSector))
{
if (needToCheckDisk)
{
//now check if on disk
String filePath = this.placeNameService.createFileCachePathFromTile(row+firstRow, col+firstCol);
final java.net.URL tileURL = WorldWind.getDataFileStore().findFile(filePath, false);
if (tileURL == null)
needToCheckDisk=false; //looked and found nothing
else
return 0; //found one, assume rest are there
}
tileCount++;
}
t1 = t2;
}
p1 = p2;
}
return tileCount;
}
//end added for bulk download
public List<NavigationTile> getSubNavTiles()
{
ArrayList<NavigationTile> navList=new ArrayList<NavigationTile>();
for(NavigationTile nav: subNavTiles)
{
navList.add(nav);
}
return navList;
}
public boolean hasSubTiles()
{
return !subNavTiles.isEmpty();
}
private boolean isNavSectorVisible(DrawContext dc, double minDistanceSquared, double maxDistanceSquared)
{
if (!navSector.intersects(dc.getVisibleSector()))
return false;
View view = dc.getView();
Position eyePos = view.getEyePosition();
if (eyePos == null)
return false;
//check for eyePos over globe
if (Double.isNaN(eyePos.getLatitude().getDegrees()) || Double.isNaN(eyePos.getLongitude().getDegrees()))
return false;
Angle lat = clampAngle(eyePos.getLatitude(), navSector.getMinLatitude(),
navSector.getMaxLatitude());
Angle lon = clampAngle(eyePos.getLongitude(), navSector.getMinLongitude(),
navSector.getMaxLongitude());
Vec4 p = dc.getGlobe().computePointFromPosition(lat, lon, 0d);
double distSquared = dc.getView().getEyePoint().distanceToSquared3(p);
//noinspection RedundantIfStatement
if (minDistanceSquared > distSquared || maxDistanceSquared < distSquared)
return false;
return true;
}
public List<Tile> getTiles()
{
if (tileKeys.isEmpty())
{
Tile[] tiles=buildTiles(this.placeNameService, this);
//load tileKeys
for (Tile t: tiles)
{
tileKeys.add(t.getHashInt());
WorldWind.getMemoryCache(Tile.class.getName()).add(t.getHashInt(), t);
}
return Arrays.asList(tiles);
}
else
{
List<Tile> dataTiles=new ArrayList<Tile>();
for ( Integer s : tileKeys )
{
Tile t = (Tile) WorldWind.getMemoryCache(Tile.class.getName()).getObject(s);
if (t != null)
{
dataTiles.add(t);
}
}
return dataTiles;
}
}
}
private static class Tile implements Cacheable
{
final PlaceNameService placeNameService;
final Sector sector;
final int row;
final int column;
private Integer hashInt=null;
// Computed data.
String fileCachePath = null;
double extentVerticalExaggeration = Double.MIN_VALUE;
private Vec4 centroid; // Cartesian coordinate of lat/lon center
private double priority = Double.MAX_VALUE; // Default is minimum priority
private PlaceNameChunk dataChunk=null;
Tile(PlaceNameService placeNameService, Sector sector, int row, int column)
{
this.placeNameService = placeNameService;
this.sector = sector;
this.row = row;
this.column = column;
this.fileCachePath = this.placeNameService.createFileCachePathFromTile(this.row, this.column);
this.hashInt = this.computeHash();
}
public void setDataChunk(PlaceNameChunk chunk)
{
dataChunk = chunk;
}
public PlaceNameChunk getDataChunk()
{
return dataChunk;
}
public long getSizeInBytes()
{
long result = 32; //references
result += this.getSector().getSizeInBytes();
if (this.getFileCachePath() != null)
result += this.getFileCachePath().length();
if (dataChunk != null)
{
result += dataChunk.estimatedMemorySize;
}
return result;
}
static int computeRow(Angle delta, Angle latitude)
{
if (delta == null || latitude == null)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?