[WorldWind学习]23.TerrainAccessor
QuadTile的CreateElevatedMesh()方法中:
//获取地形瓦片
TerrainTile tile = QuadTileSet.World.TerrainAccessor.GetElevationArray(North + degreePerSample, South - degreePerSample, West - degreePerSample, East + degreePerSample, vertexCountElevated + );
float[,] heightData = tile.ElevationData;
调用了World的TerrainAccessor属性的GetElevationArray()方法。
实际调用的是TerrainAccessor子类NltTerrainAccessor的GetElevationArray方法。
GetElevationArray对高清影像进行递归调用。如下是NltTerrainAccessor的GetElevationArray方法。
/// <summary>
/// Builds a terrain array with specified boundaries
/// </summary>
/// <param name="north">North edge in decimal degrees.</param>
/// <param name="south">South edge in decimal degrees.</param>
/// <param name="west">West edge in decimal degrees.</param>
/// <param name="east">East edge in decimal degrees.</param>
/// <param name="samples"></param>
public override TerrainTile GetElevationArray(double north, double south, double west, double east,
int samples)
{
TerrainTile res = null; if (m_higherResolutionSubsets != null)
{
// TODO: Support more than 1 level of higher resolution sets and allow user selections
foreach (TerrainAccessor higherResSub in m_higherResolutionSubsets)
{
if (north <= higherResSub.North && south >= higherResSub.South &&
west >= higherResSub.West && east <= higherResSub.East)
{
res = higherResSub.GetElevationArray(north, south, west, east, samples);
return res;
}
}
} res = new TerrainTile(m_terrainTileService);
res.North = north;
res.South = south;
res.West = west;
res.East = east;
res.SamplesPerTile = samples;
res.IsInitialized = true;
res.IsValid = true; double samplesPerDegree = (double)samples / (double)(north - south);
double latrange = Math.Abs(north - south);
double lonrange = Math.Abs(east - west);
TerrainTileCacheEntry ttce = null; float[,] data = new float[samples, samples]; if(samplesPerDegree < World.Settings.MinSamplesPerDegree)
{
res.ElevationData = data;
return res;
} double scaleFactor = (double) / (samples - );
for (int x = ; x < samples; x++)
{
for (int y = ; y < samples; y++)
{
double curLat = north - scaleFactor * latrange * x;
double curLon = west + scaleFactor * lonrange * y; // Wrap lat/lon to fit range 90/-90 and -180/180 (PM 2006-11-17)
if (curLat > )
{
curLat = - (curLat - );
curLon += ;
}
if (curLat < -)
{
curLat = - - (curLat + );
curLon += ;
}
if (curLon > )
{
curLon -= ;
}
if (curLon < -)
{
curLon += ;
} 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);
}
}
res.ElevationData = data; return res;
}
GetElevationArray
最后查看TerrainTile类的GetElevationAt方法获取了高程数据。
public class TerrainTile : IDisposable
{
public string TerrainTileFilePath;
public double TileSizeDegrees;
public int SamplesPerTile;
public double South;
public double North;
public double West;
public double East;
public int Row;
public int Col;
public int TargetLevel;
public TerrainTileService m_owner;
public bool IsInitialized;
public bool IsValid; public float[,] ElevationData;
protected TerrainDownloadRequest request; public TerrainTile( TerrainTileService owner )
{
m_owner = owner;
}
/// <summary>
/// This method initializes the terrain tile add switches to
/// Initialize floating point/int 16 tiles
/// </summary>
public void Initialize()
{
if(IsInitialized)
return; if(!File.Exists(TerrainTileFilePath))
{
// Download elevation
if(request==null)
{
using( request = new TerrainDownloadRequest(this, m_owner, Row, Col, TargetLevel) )
{
request.SaveFilePath = TerrainTileFilePath;
request.DownloadInForeground();
}
}
} if(ElevationData==null)
ElevationData = new float[SamplesPerTile, SamplesPerTile]; if(File.Exists(TerrainTileFilePath))
{
// Load elevation file
try
{
// TerrainDownloadRequest's FlagBadTile() creates empty files
// as a way to flag "bad" terrain tiles.
// Remove the empty 'flag' files after preset time.
try
{
FileInfo tileInfo = new FileInfo(TerrainTileFilePath);
if(tileInfo.Length == )
{
TimeSpan age = DateTime.Now.Subtract( tileInfo.LastWriteTime );
if(age < m_owner.TerrainTileRetryInterval)
{
// This tile is still flagged bad
IsInitialized = true;
}
else
{
// remove the empty 'flag' file
File.Delete(TerrainTileFilePath);
}
return;
}
}
catch
{
// Ignore any errors in the above block, and continue.
// For example, if someone had the empty 'flag' file
// open, the delete would fail.
} using( Stream s = File.OpenRead(TerrainTileFilePath))
{
BinaryReader reader = new BinaryReader(s);
if(m_owner.DataType=="Int16")
{
/*
byte[] tfBuffer = new byte[SamplesPerTile*SamplesPerTile*2];
if (s.Read(tfBuffer,0,tfBuffer.Length) < tfBuffer.Length)
throw new IOException(string.Format("End of file error while reading terrain file '{0}'.", TerrainTileFilePath) ); int offset = 0;
for(int y = 0; y < SamplesPerTile; y++)
for(int x = 0; x < SamplesPerTile; x++)
ElevationData[x,y] = tfBuffer[offset++] + (short)(tfBuffer[offset++]<<8);
*/
for(int y = ; y < SamplesPerTile; y++)
for(int x = ; x < SamplesPerTile; x++)
ElevationData[x,y] = reader.ReadInt16();
}
if(m_owner.DataType=="Float32")
{
/*
byte[] tfBuffer = new byte[SamplesPerTile*SamplesPerTile*4];
if (s.Read(tfBuffer,0,tfBuffer.Length) < tfBuffer.Length)
throw new IOException(string.Format("End of file error while reading terrain file '{0}'.", TerrainTileFilePath) );
*/
for(int y = ; y < SamplesPerTile; y++)
for(int x = ; x < SamplesPerTile; x++)
{
ElevationData[x,y] = reader.ReadSingle();
}
}
IsInitialized = true;
IsValid = true;
}
return;
}
catch(IOException)
{
// If there is an IO exception when reading the terrain tile,
// then either something is wrong with the file, or with
// access to the file, so try and remove it.
try
{
File.Delete(TerrainTileFilePath);
}
catch(Exception ex)
{
throw new ApplicationException(String.Format("Error while trying to delete corrupt terrain tile {0}", TerrainTileFilePath), ex);
}
}
catch(Exception ex)
{
// Some other type of error when reading the terrain tile.
throw new ApplicationException(String.Format("Error while trying to read terrain tile {0}", TerrainTileFilePath), ex);
}
}
}
//根据经纬度从DEM瓦片中获取高程
public float GetElevationAt(double latitude, double longitude)
{
try
{
double deltaLat = North - latitude;
double deltaLon = longitude - West; double df2 = (SamplesPerTile-) / TileSizeDegrees;
float lat_pixel = (float)(deltaLat * df2);
float lon_pixel = (float)(deltaLon * df2); int lat_min = (int)lat_pixel;
int lat_max = (int)Math.Ceiling(lat_pixel);
int lon_min = (int)lon_pixel;
int lon_max = (int)Math.Ceiling(lon_pixel); if(lat_min >= SamplesPerTile)
lat_min = SamplesPerTile - ;
if(lat_max >= SamplesPerTile)
lat_max = SamplesPerTile - ;
if(lon_min >= SamplesPerTile)
lon_min = SamplesPerTile - ;
if(lon_max >= SamplesPerTile)
lon_max = SamplesPerTile - ; if(lat_min < )
lat_min = ;
if(lat_max < )
lat_max = ;
if(lon_min < )
lon_min = ;
if(lon_max < )
lon_max = ; float delta = lat_pixel - lat_min;
float westElevation =
ElevationData[lon_min, lat_min]*(-delta) +
ElevationData[lon_min, lat_max]*delta; float eastElevation =
ElevationData[lon_max, lat_min]*(-delta) +
ElevationData[lon_max, lat_max]*delta; delta = lon_pixel - lon_min;
float interpolatedElevation =
westElevation*(-delta) +
eastElevation*delta; return interpolatedElevation;
}
catch
{
}
return ;
}
#region IDisposable Members public void Dispose()
{
if(request != null)
{
request.Dispose();
request = null;
} GC.SuppressFinalize(this);
} #endregion
}
TerrainTile
TerrainAccessor在ConfigLoader中构建,赋值给World。
[WorldWind学习]23.TerrainAccessor的更多相关文章
- Python学习--23 第三方库
本文将介绍python里常用的模块.如未特殊说明,所有示例均以python3.4为例: $ python -V Python 3.4.3 网络请求 urllib urllib提供了一系列用于操作URL ...
- Python学习--23 内建模块及第三方库
本文将介绍python里常用的模块.如未特殊说明,所有示例均以python3.4为例: $ python -V Python 3.4.3 网络请求 urllib urllib提供了一系列用于操作URL ...
- [WorldWind学习]19.WebDownload
using System; using System.Diagnostics; using System.Globalization; using System.Net; using System.I ...
- [WorldWind学习]18.High-Performance Timer in C#
In some applications exact time measurement methods are very important. 一些应用程序中精确的时间测量是非常重要的. The of ...
- msp430入门学习23
msp430的ADC(模数转换) msp430入门学习
- iOS 学习 - 23 加载本地 txt 文件, NSMutableParagraphStyle 段落格式,缩放动画,字体间距
思路: 1.new 一个 Empty 后缀为 .txt 文件,内容随笔拷贝一段 2.用 NSString 接收本地文件,再用一个标题拼接字符串 3.创建一个 NSMutableParagraphSty ...
- 【Java EE 学习 23】【log4j的使用】【ant的使用】【内省】
一.ant下载地址:http://ant.apache.org/bindownload.cgi 二.log4j下载地址:http://logging.apache.org/log4j/2.x/dow ...
- iOS学习23之事件处理
1. 事件的基本概念 1> 概述 事件是当用户手指触击屏幕及在屏幕上移动时,系统不断发送给应用程序的对象. 系统将事件按照特定的路径传递给可以对其进行处理的对象 在iOS中,一个UITouch对 ...
- [游戏学习23] MFC 画尺子
>_<:这是个简单的MFC程序,有利于了解MFC的框架结构 >_<:Ruler.h #include<afxwin.h> class CMyApp:public C ...
随机推荐
- 最全Java学习路线图——Java学习指南
准备篇 适用/适合人群:适合基础小白 目标:掌握JavaSE. ●技术点小节: 1.开发工具的安装配置的介绍 2.JDK安装 3.DOS环境编程 4.Eclipse的安装使用 ●JAVA基础 1.基本 ...
- PureMVC--一款多平台MVC框架
官网:http://puremvc.org/ 下载:https://github.com/PureMVC/puremvc-csharp-multicore-framework/tree/1.1.0 A ...
- 删除C盘垃圾文件bat
@ECHO OFF@echo 此批处理由59互联(http://www.59.cn)整理发布@echo @echo 清理几个比较多垃圾文件的地方DEL /F /S /Q "C:\WINDOW ...
- 我学cocos2d-x (三) Node:一切可视化对象的祖先
在cocos2d-x中一切可视化的对象都继承自Node(如文字(label).精灵(sprite).场景(scene).布局(layer)).这是一个纯虚类.主要负责决定元素显示的位置. 由导演(Di ...
- PVS 7.6 部署教程
PVS 7.6 部署教程 1 PVS介绍 Citrix Provisioning Services採用流技术通过网络将单一标准桌面镜像,包含操作系统和软件按需交付给物理虚拟桌面.一方面实现同型号机器单 ...
- 添加app第一次启动页面
一.添加几个成员变量 @interface hDisplayView ()<UIScrollViewDelegate> { UIScrollView *_bigScrollView; NS ...
- 关于直播学习笔记-003-nginx-rtmp、srs、vlc、obs
服务器 1.nginx-rtmp:https://github.com/illuspas/nginx-rtmp-win32 2.srs:https://github.com/illuspas/srs- ...
- bootstrap里面的popover组件如何使鼠标移入可以对弹出框进行一系列的操作
在bootstrap里面,有一个组件很可爱,它就是popover,它是对标签title属性的优化,奉上连接一枚:http://docs.demo.mschool.cn/components/popov ...
- poj_2739 尺取法
题目大意 给定一个数字N,N可能由1个或多个连续的素数求和得到,比如41 = 2+3+5+7+11+13, 41 = 11+13+17, 41 = 41.求出对于N,所有可能的组合形式. 题目分析 先 ...
- poj_1390 动态规划
题目大意 将一些连续的序列根据颜色分为N段,每段有颜色 为 Ci, 长度为 Li.每次点击其中的一段 i ,则可以将该段i消除,该段相邻的两段自动连接到一起,如果连接到一起的两段之前的颜色相同,则更新 ...