[WorldWind学习]23.TerrainAccessor

时间:2023-03-09 15:44:49
[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