World类中包含高程访问器类对象TerrainAccessor _terrainAccessor 来访问本地或网络上的高程数据,通过读取地球配置文件中的TerrainAccessor 字段,构建一个高程访问器类NltTerrainAccessor 对象(列表)。
<TerrainAccessor Name="SRTM">
<TerrainTileService>
<ServerUrl>http://worldwind25.arc.nasa.gov/wwelevation/wwelevation.aspx</ServerUrl>
<DataSetName>srtm30pluszip</DataSetName>
<LevelZeroTileSizeDegrees>20.0</LevelZeroTileSizeDegrees>
<NumberLevels>12</NumberLevels>
<SamplesPerTile>150</SamplesPerTile>
<DataFormat>Int16</DataFormat>
<FileExtension>bil</FileExtension>
<CompressonType>zip</CompressonType>
</TerrainTileService>
<LatLonBoundingBox>
<North>
<Value>90.0</Value>
</North>
<South>
<Value>-90.0</Value>
</South>
<West>
<Value>-180.0</Value>
</West>
<East>
<Value>180.0</Value>
</East>
</LatLonBoundingBox>
</TerrainAccessor>
高程访问器类包含一个高程瓦片服务对象: TerrainTileService tts,用于管理地形瓦片。其中包含访问的网址,瓦片的层级,每个瓦片的高程点数量等信息。0级瓦片的分辨率最低,瓦片跨度20*20度,150*150个点,总共12层,上一层分辨率是下一层的4倍,每个瓦片的点数不变,1级瓦片跨度为5*5°。首先根据需要的分辨率(每度的点数)获得对应的层级,再计算在该层的行和列号,访问具体的瓦片数据。
其类关系图如下:
一、TerrainAccessor 类
TerrainAccessor 类是基类,主要包括四角点经纬度,名字等信息。
主要函数:
float GetElevationAt(double latitude, double longitude, double targetSamplesPerDegree),是一个抽象虚函数,获取给定经纬度,一定采样精度(每度的采样点数量)下的高程值。
virtual TerrainTile GetElevationArray(double north, double south, double west, double east, int samples) 获取给定地理范围和采样精度下的高程数组。首先构造一个给定地理范围和精度的TerrainTile res 对象,samples表示这个瓦片总共samples行,samples列。从西北到东南的顺序设置每个点的高程值(通过GetElevationAt(curLat, curLon, 0)获取)。
二、NltTerrainAccessor类
NltTerrainAccessor访问器访问具体的地形数据,数据采用 BIL 格式。它通过Hash表可缓存100个瓦片数据,包含一个TerrainTileService地形瓦片服务对象和WmsImageStore 图片存储管理对象。还可以包含一个更高精度的地形数据访问器数组。
主要成员变量包括:
public static int CacheSize = 100;
protected TerrainTileService m_terrainTileService;
protected WmsImageStore m_wmsElevationSet;
protected TerrainAccessor[] m_higherResolutionSubsets;
protected Hashtable m_tileCache = new Hashtable();
主要函数:
virtual TerrainTile GetElevationArray(double north, double south, double west, double east, int samples) 重载函数,首先检查定地理范围 是否包含在某个更高精度地形访问器的范围内,如果存在,则递归调用更高精度地形访问器的函数,获取地形瓦片。每度的采样点数量需要大于设定的最小值才能读取高程数据。读取高程数据的主要方法:
double curLat = north - scaleFactor * latrange * x;
double curLon = west + scaleFactor * lonrange * y;
if (ttce == null ||
curLat < ttce.TerrainTile.South ||
curLat > ttce.TerrainTile.North ||
curLon < ttce.TerrainTile.West ||
curLon > ttce.TerrainTile.East)
{
TerrainTile tt = m_terrainTileService.GetTerrainTile(curLat, curLon, samplesPerDegree);
ttce = (TerrainTileCacheEntry)m_tileCache[tt.TerrainTileFilePath];
if (ttce == null)
{
ttce = new TerrainTileCacheEntry(tt);
AddToCache(ttce);
}
if (!ttce.TerrainTile.IsInitialized)
ttce.TerrainTile.Initialize();
ttce.LastAccess = DateTime.Now;
if (!tt.IsValid)
res.IsValid = false;
}
data[x, y] = ttce.TerrainTile.GetElevationAt(curLat, curLon);
ttce是高程瓦片缓存,如果为空,或当前瓦片不在缓存的范围内,通过瓦片服务器的GetTerrainTile方法获取对应的瓦片,如果瓦片没有缓冲过,则创建缓存条目,并添加到缓存区中。对高程瓦片进行初始化。最后,给定经纬度的高程值通过获取瓦片的GetElevationAt函数获取。
float GetElevationAt(double latitude, double longitude, double targetSamplesPerDegree)重载函数, targetSamplesPerDegree为每度拥有的采用点数,为m_terrainTileService.SamplesPerTile / m_terrainTileService.LevelZeroTileSizeDegrees 。瓦片的采样点数除以0级瓦片的经度范围。首先检查定地理范围 是否包含在某个更高精度地形访问器的范围内,如果存在,则递归调用更高精度地形访问器的函数,获取地形瓦片。实际是通过高程瓦片服务获取对应的瓦片TerrainTile ,然后调用瓦片TerrainTile 的TerrainTileGetElevationAt(latitude, longitude);
三、TerrainTileService类
TerrainTileService负责读取和管理高程瓦片数据。主要功能是根据经纬度和每度采样点数,构造一个高程瓦片对象。类图如下所示:
主要变量:
string m_serverUrl;
string m_dataSet;
double m_levelZeroTileSizeDegrees;
int m_samplesPerTile;
int m_numberLevels;
string m_fileExtension;
string m_terrainTileDirectory;
TimeSpan m_terrainTileRetryInterval;
string m_dataType;
主要函数:
public static int GetColFromLongitude(double longitude, double tileSize)
{
return (int)System.Math.Floor((System.Math.Abs(-180.0 - longitude)%360)/tileSize);
}
public static int GetRowFromLatitude(double latitude, double tileSize)
{
return (int)System.Math.Floor((System.Math.Abs(-90.0 - latitude)%180)/tileSize);
}
TerrainTile GetTerrainTile(double latitude, double longitude, double samplesPerDegree): 构造一个新的TerrainTile对象,其中samplesPerDegree决定了瓦片的层级。从最高层级开始往下,直到找到满足精度要求的层级。
四、TerrainTile 类
TerrainTile 对应一个高程瓦片。类图如下所示:
主要属性:
protected TerrainDownloadRequest request; 为一个下载请求,可以从网络上下载高程文件,目前使用的是直接通过http下载,下载路径为:(现在流行的是通过WMS服务提供下载)
download.Url = String.Format(CultureInfo.InvariantCulture,
"{0}?T={1}&L={2}&X={3}&Y={4}",
owner.ServerUrl,
owner.DataSet,
targetLevel, col, row);
public float GetElevationAt(double latitude, double longitude):在瓦片数据中,通过插值计算给定经纬度的高程值。
public void Initialize() :初始化瓦片的高程数据,如果文件不存在,通过request请求下载一个高程文件到缓存目录,然后读取缓存文件到ElevationData二维数组,行为经度,列为纬度。bil高程文件有两个格式,一种Int16 每个高程值2个字节短整形,一种是32位float类型。
for (int y = 0; y < SamplesPerTile; y++)
for (int x = 0; x < SamplesPerTile; x++)
ElevationData[x, y] = reader.ReadInt16();