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 }
最后查看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 }
TerrainAccessor在ConfigLoader中构建,赋值给World。