[WorldWind学习]23.TerrainAccessor

QuadTile的CreateElevatedMesh()方法中:

1  //获取地形瓦片
2 TerrainTile tile = QuadTileSet.World.TerrainAccessor.GetElevationArray(North + degreePerSample, South - degreePerSample, West - degreePerSample, East + degreePerSample, vertexCountElevated + 3);
3 float[,] heightData = tile.ElevationData;

调用了World的TerrainAccessor属性的GetElevationArray()方法。

实际调用的是TerrainAccessor子类NltTerrainAccessor的GetElevationArray方法。

GetElevationArray对高清影像进行递归调用。如下是NltTerrainAccessor的GetElevationArray方法。

  1                                 /// <summary>
  2         /// Builds a terrain array with specified boundaries
  3         /// </summary>
  4         /// <param name="north">North edge in decimal degrees.</param>
  5         /// <param name="south">South edge in decimal degrees.</param>
  6         /// <param name="west">West edge in decimal degrees.</param>
  7         /// <param name="east">East edge in decimal degrees.</param>
  8         /// <param name="samples"></param>
  9         public override TerrainTile GetElevationArray(double north, double south, double west, double east,
 10             int samples)
 11         {
 12             TerrainTile res = null;
 13             
 14             if (m_higherResolutionSubsets != null)
 15             {
 16                 // TODO: Support more than 1 level of higher resolution sets and allow user selections
 17                 foreach (TerrainAccessor higherResSub in m_higherResolutionSubsets)
 18                 {
 19                     if (north <= higherResSub.North && south >= higherResSub.South &&
 20                         west >= higherResSub.West && east <= higherResSub.East)
 21                     {
 22                         res = higherResSub.GetElevationArray(north, south, west, east, samples);
 23                         return res;
 24                     }
 25                 }
 26             }
 27 
 28             res = new TerrainTile(m_terrainTileService);
 29             res.North = north;
 30             res.South = south;
 31             res.West = west;
 32             res.East = east;
 33             res.SamplesPerTile = samples;
 34             res.IsInitialized = true;
 35             res.IsValid = true;
 36 
 37             double samplesPerDegree = (double)samples / (double)(north - south);
 38             double latrange = Math.Abs(north - south);
 39             double lonrange = Math.Abs(east - west);
 40             TerrainTileCacheEntry ttce = null;
 41 
 42             float[,] data = new float[samples, samples];
 43 
 44             if(samplesPerDegree < World.Settings.MinSamplesPerDegree)
 45             {
 46                 res.ElevationData = data;
 47                 return res;
 48             }
 49 
 50             double scaleFactor = (double)1 / (samples - 1);
 51             for (int x = 0; x < samples; x++)
 52             {
 53                 for (int y = 0; y < samples; y++)
 54                 {
 55                     double curLat = north - scaleFactor * latrange * x;
 56                     double curLon = west + scaleFactor * lonrange * y;
 57 
 58                     // Wrap lat/lon to fit range 90/-90 and -180/180 (PM 2006-11-17)
 59                     if (curLat > 90)
 60                     {
 61                         curLat = 90 - (curLat - 90);
 62                         curLon += 180;
 63                     }
 64                     if (curLat < -90)
 65                     {
 66                         curLat = -90 - (curLat + 90);
 67                         curLon += 180;
 68                     }
 69                     if (curLon > 180)
 70                     {
 71                         curLon -= 360;
 72                     }
 73                     if (curLon < -180)
 74                     {
 75                         curLon += 360;
 76                     }
 77 
 78                     if (ttce == null ||
 79                         curLat < ttce.TerrainTile.South ||
 80                         curLat > ttce.TerrainTile.North ||
 81                         curLon < ttce.TerrainTile.West ||
 82                         curLon > ttce.TerrainTile.East)
 83                     {
 84                         TerrainTile tt = m_terrainTileService.GetTerrainTile(curLat, curLon, samplesPerDegree);
 85                         ttce = (TerrainTileCacheEntry)m_tileCache[tt.TerrainTileFilePath];
 86                         if (ttce == null)
 87                         {
 88                             ttce = new TerrainTileCacheEntry(tt);
 89                             AddToCache(ttce);
 90                         }
 91                         if (!ttce.TerrainTile.IsInitialized)
 92                             ttce.TerrainTile.Initialize();
 93                         ttce.LastAccess = DateTime.Now;
 94                         if (!tt.IsValid)
 95                             res.IsValid = false;
 96                     }
 97 
 98                     data[x, y] = ttce.TerrainTile.GetElevationAt(curLat, curLon);
 99                 }
100             }
101             res.ElevationData = data;
102 
103             return res;
104         }
GetElevationArray

最后查看TerrainTile类的GetElevationAt方法获取了高程数据。

  1 public class TerrainTile : IDisposable
  2     {
  3         public string TerrainTileFilePath;
  4         public double TileSizeDegrees;
  5         public int SamplesPerTile;
  6         public double South;
  7         public double North;
  8         public double West;
  9         public double East;
 10         public int Row;
 11         public int Col;
 12         public int TargetLevel;
 13         public TerrainTileService m_owner;
 14         public bool IsInitialized;
 15         public bool IsValid;
 16 
 17         public float[,] ElevationData;
 18         protected TerrainDownloadRequest request;
 19 
 20         public TerrainTile( TerrainTileService owner )
 21         {
 22             m_owner = owner;
 23         }
 24         /// <summary>
 25         /// This method initializes the terrain tile add switches to
 26         /// Initialize floating point/int 16 tiles
 27         /// </summary>
 28         public void Initialize()
 29         {
 30             if(IsInitialized)
 31                 return;
 32 
 33             if(!File.Exists(TerrainTileFilePath))
 34             {
 35                 // Download elevation
 36                 if(request==null)
 37                 {
 38                     using( request = new TerrainDownloadRequest(this, m_owner, Row, Col, TargetLevel) )
 39                     {
 40                         request.SaveFilePath = TerrainTileFilePath;
 41                         request.DownloadInForeground();
 42                     }
 43                 }
 44             }
 45 
 46             if(ElevationData==null)
 47                 ElevationData = new float[SamplesPerTile, SamplesPerTile];
 48 
 49             if(File.Exists(TerrainTileFilePath))
 50             {
 51                 // Load elevation file
 52                 try
 53                 {
 54                     // TerrainDownloadRequest's FlagBadTile() creates empty files
 55                     // as a way to flag "bad" terrain tiles.
 56                     // Remove the empty 'flag' files after preset time.
 57                     try
 58                     {
 59                         FileInfo tileInfo = new FileInfo(TerrainTileFilePath);
 60                         if(tileInfo.Length == 0)
 61                         {
 62                             TimeSpan age = DateTime.Now.Subtract( tileInfo.LastWriteTime );
 63                             if(age < m_owner.TerrainTileRetryInterval)
 64                             {
 65                                 // This tile is still flagged bad
 66                                 IsInitialized = true;
 67                             }
 68                             else
 69                             {
 70                                 // remove the empty 'flag' file
 71                                 File.Delete(TerrainTileFilePath);
 72                             }
 73                             return;
 74                         }
 75                     }
 76                     catch
 77                     {
 78                         // Ignore any errors in the above block, and continue.
 79                         // For example, if someone had the empty 'flag' file
 80                         // open, the delete would fail.
 81                     }
 82     
 83                     using( Stream s = File.OpenRead(TerrainTileFilePath))
 84                     {
 85                         BinaryReader reader = new BinaryReader(s);
 86                         if(m_owner.DataType=="Int16")
 87                         {
 88                             /*
 89                             byte[] tfBuffer = new byte[SamplesPerTile*SamplesPerTile*2];
 90                             if (s.Read(tfBuffer,0,tfBuffer.Length) < tfBuffer.Length)
 91                                 throw new IOException(string.Format("End of file error while reading terrain file '{0}'.", TerrainTileFilePath) );
 92 
 93                             int offset = 0;
 94                             for(int y = 0; y < SamplesPerTile; y++)
 95                                 for(int x = 0; x < SamplesPerTile; x++)
 96                                     ElevationData[x,y] = tfBuffer[offset++] + (short)(tfBuffer[offset++]<<8);
 97                             */
 98                             for(int y = 0; y < SamplesPerTile; y++)
 99                                 for(int x = 0; x < SamplesPerTile; x++)
100                                     ElevationData[x,y] = reader.ReadInt16();
101                         }
102                         if(m_owner.DataType=="Float32")
103                         {
104                             /*
105                             byte[] tfBuffer = new byte[SamplesPerTile*SamplesPerTile*4];
106                             if (s.Read(tfBuffer,0,tfBuffer.Length) < tfBuffer.Length)
107                                     throw new IOException(string.Format("End of file error while reading terrain file '{0}'.", TerrainTileFilePath) );
108                             */
109                             for(int y = 0; y < SamplesPerTile; y++)
110                                 for(int x = 0; x < SamplesPerTile; x++)
111                                 {
112                                     ElevationData[x,y] = reader.ReadSingle();
113                                 }
114                         }
115                         IsInitialized = true;
116                         IsValid = true;
117                     }
118                     return;
119                 }
120                 catch(IOException)
121                 {
122                     // If there is an IO exception when reading the terrain tile,
123                     // then either something is wrong with the file, or with
124                     // access to the file, so try and remove it.
125                     try
126                     {
127                         File.Delete(TerrainTileFilePath);
128                     }
129                     catch(Exception ex)
130                     {
131                         throw new ApplicationException(String.Format("Error while trying to delete corrupt terrain tile {0}", TerrainTileFilePath), ex);
132                     }
133                 }
134                 catch(Exception ex)
135                 {
136                     // Some other type of error when reading the terrain tile.
137                     throw new ApplicationException(String.Format("Error while trying to read terrain tile {0}", TerrainTileFilePath), ex);
138                 }
139             }
140         }
141         //根据经纬度从DEM瓦片中获取高程
142         public float GetElevationAt(double latitude, double longitude)
143         {
144             try
145             {
146                 double deltaLat = North - latitude;
147                 double deltaLon = longitude - West;
148 
149                 double df2 = (SamplesPerTile-1) / TileSizeDegrees;
150                 float lat_pixel = (float)(deltaLat * df2);
151                 float lon_pixel = (float)(deltaLon * df2);
152 
153                 int lat_min = (int)lat_pixel;
154                 int lat_max = (int)Math.Ceiling(lat_pixel);
155                 int lon_min = (int)lon_pixel;
156                 int lon_max = (int)Math.Ceiling(lon_pixel);
157 
158                 if(lat_min >= SamplesPerTile)
159                     lat_min = SamplesPerTile - 1;
160                 if(lat_max >= SamplesPerTile)
161                     lat_max = SamplesPerTile - 1;
162                 if(lon_min >= SamplesPerTile)
163                     lon_min = SamplesPerTile - 1;
164                 if(lon_max >= SamplesPerTile)
165                     lon_max = SamplesPerTile - 1;
166 
167                 if(lat_min < 0)
168                     lat_min = 0;
169                 if(lat_max < 0)
170                     lat_max = 0;
171                 if(lon_min < 0)
172                     lon_min = 0;
173                 if(lon_max < 0)
174                     lon_max = 0;
175 
176                 float delta = lat_pixel - lat_min;
177                 float westElevation = 
178                     ElevationData[lon_min, lat_min]*(1-delta) + 
179                     ElevationData[lon_min, lat_max]*delta;
180             
181                 float eastElevation = 
182                     ElevationData[lon_max, lat_min]*(1-delta) + 
183                     ElevationData[lon_max, lat_max]*delta;
184             
185                 delta = lon_pixel - lon_min;
186                 float interpolatedElevation = 
187                     westElevation*(1-delta) + 
188                     eastElevation*delta;
189 
190                 return interpolatedElevation;
191             }
192             catch
193             {
194             }
195             return 0;
196         }
197         #region IDisposable Members
198 
199         public void Dispose()
200         {
201             if(request != null)
202             {
203                 request.Dispose();
204                 request = null;
205             }
206             
207             GC.SuppressFinalize(this);
208         }
209 
210         #endregion
211     }
TerrainTile

TerrainAccessor在ConfigLoader中构建,赋值给World。

原文地址:https://www.cnblogs.com/yhlx125/p/3557425.html