“土耳其冰淇淋”通过精心收集,向本站投稿了6篇WorldWind系列十三:地形数据(DEM)加载和应用(入门篇),下面是小编为大家整理后的WorldWind系列十三:地形数据(DEM)加载和应用(入门篇),欢迎大家借鉴与参考,希望对大家有所帮助。

篇1:WorldWind系列十三:地形数据(DEM)加载和应用(入门篇)
学习WW中DEM的加载和应用对于基于WW搞三维GIS插件开发很重要,我一直也想关注和搜集相关学习资料,之前没有开始研究它,主要是自己没能在 WW看到高程应用功能,感觉没法切入。我昨天下午和今天上午的时间就花在找研究切入点啦!实质上就是找如何在WW查看高程的功能。(现在回想一下,感觉浪费时间了,还是因为我对WW的功能没能完全知道)
我在开始学习DEM加载和应用前,我主要参看了CSDN上的博文——《庆贺,绘制出World Wind的LOD地形网格》(blog.csdn.net/paul_xj/archive//08/29/1763585.aspx),相信研究WW的人都应该看过这篇和他的三篇学习总结。我也看过研究过好多遍,结合自己的学习,每遍拜读都有些收获。他的文章关注度很高,绝对是WW初学者的起航灯塔。但是,我对上面提到的《绘制出World Wind的LOD地形网格》几乎要全文否定。我不希望网友以该文为标准来学习WW的地形网格(即DEM加载应用),因为我原本也是很相信他说的,按他说的去做的,事实不是那样的,相信他也是刚入门时写下的,很多DirectX的东西理解也不是很深刻的。
所谓的绘制出LOD地形网格有问题!怎么能将DirectX三维渲染与GIS中DEM混为一团?!地形图包括地物和地貌。而地貌主要体现在等高线上,在三维中体现为DEM应用(数字高程模型)!上面博客中讲到的构建地形网格只是将DirectX的面渲染改为线渲染,这还是平面级别的,根本没有体现高程,怎么就是地形网格啦?!从DirectX三维技术角度讲,也是有问题的:DX中面渲染和线渲染存储点的方式是不同的,因为WW中使用LOD模型各层要渲染的面很多且相邻,所以简单更改渲染方式没能看出影响。但如果你绘制单个面然后更改为线性渲染,就会看出问题啦!这还是平面级别上面,面渲染改为线渲染会出现问题,如果是三维物体(立方体)如果简单改为线渲染,问题更明显!(你学过DirectX后,试一下就知道啦!)
至于博客中说到的:“按下‘Ctrl+W’出来的网格,是什么空中网格”,只是简单地操作,放大后看到后面是“天空”,就认为是什么空中网格,这真是典型的形而上学啦!真正学习过三维开发的人都会知道:为了提高效率,三维渲染只是渲染可视的前一面,不被看到的面统统隐去(不渲染)。大家放大操作后看到“天空”而不是又一层网格,就是因为后面的网格不可视。‘Ctrl+W’出来的网格,是个空心球体框架。只是更改DX三维球体渲染时 FillMode而已。
WorldWindow.cs中响应“CRL+W”的处理代码:
1351行:
// Control key downelse if (e.Control){switch (e.KeyCode){case Keys.D:this.showDiagnosticInfo = !this.showDiagnosticInfo;return true;case Keys.W:renderWireFrame. = !renderWireFrame;return true;}}然后,看Render方法,代码行号776
// Set fill modeif (renderWireFrame)m_Device3d.RenderState.FillMode = FillMode.WireFrame;elsem_Device3d.RenderState.FillMode = FillMode.Solid;所以看到的是球体框架而不是实心球,
压根没有空中网格一说!
这是文章中最后的截图,貌似很像他所说的地形网格,可能有网友会据此驳斥我。首先,在上面我已经从DirectX渲染技术角度上,我已经说明了这不是地形格网。其次,图中能表现出地形的高低起伏,是因为有地表面渲染中有DEM数据的加载和应用(这是关键)。我认为地形网格其实很简单,将地表面的渲染FillMode = FillMode.WireFrame;(注意:不是球面渲染的FillMode)。
我一向主张学习WW要从功能入手,DEM学习也应该从功能入手,现在看看WW中体现DEM功能:(参看www.help2go.com/Tutorials/Software_Applications/View_the_world_with_NASA_Worldwind.html)
Zoom in further,and Worldwind will download higher resolution images,giving you greater and greater detail. Now,hold down the right-mouse button and move your mouse down a bit -- your view will rotate a bit,so rather than looking head-on at the city from above,you'll be looking at it from an angle.
按住鼠标右键,移动鼠标一点,你就可以从一个角度看地貌了,而不是垂直向下看啦。
可能很多网友已经知道如何看到上面的效果啦!可是我之前不知道,所以一直困惑没找到切入点。我的WW学习很强调从功能入手分析代码学习代码。
上面的分析,算是DEM加载和应用入门篇吧!因为我自己就是走过这个阶段的,希望你也有所收获。然后下一篇,我们从代码基本分析DEM数据的加载和使用。
另附:(需要了解的两个知识点)
LOD是Level of Detail的缩写,意为层次细节度,技术指根据物体模型的节点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
DDS(DirectDraw Surface)文件格式是微软为DirectX开发的一种图片格式,它是可以使用类似S3TC标准提供的一种压缩纹理格式. DDS文件可以有很多不同的格式,可以含有 Mipmap 或不保存 Mipmap 信息,可以使用压缩或非压缩的像素格式,常见的压缩数据方式有 DXTn(DXT1~DXT5),DDS文件的结构见MSDN: DDS File Reference. 参看:www.csinx.org/IBLog/article.asp?id=8
篇2:WorldWind系列十四:DEM数据加载和应用――以SRTM为例(上)
DEM应用在WW的三维表现中占有很重要的位置,跟影像数据同等重要!幸好影像和DEM的加载和处理原理上几乎一致,对基于WW搞GIS三维开发来说是件好事,理解好任何一种,另一种触类旁通!前一篇,主要从功能上做了简单入门介绍,该篇将从代码级别分析WW内置的SRTM的DEM数据加载和应用,下一篇讲从二次开发角度上讲解如何处理、配置自己的影像和DEM数据,呵呵,因为DEM部分很重要,且是放假期间我也有时间,争取篇篇精彩!
两个缩写词介绍:因为这两个缩写词常出现,知道是什么缩写,就不觉得神秘啦!
SRTM:The Shuttle Radar Topography Mission (SRTM) obtained elevation data on a near-global scale to generate the most complete high-resolution digital topographic database of Earth. SRTM consisted of a specially modified radar system that flew onboard the Space Shuttle Endeavour during an 11-day mission in February of .
NLT:NASA Learning Technologies.
我从BMNG.cs为例入手研究DEM的使用,当然研究瓦片影像也该从此入手,但,今天影像不是我们关注的重点。现在正式步入主题,跟我一起分析和学习代码吧!
BMNG.cs类144行构造函数中代码,
WorldWind.NltImageStore imageStore = new WorldWind.NltImageStore(String.Format(“bmng.topo.{0:D2}”, i + 1), “worldwind25.arc.nasa.gov/tile/tile.aspx”);imageStore.DataDirectory = null;imageStore.LevelZeroTileSizeDegrees = 36.0;imageStore.LevelCount = 5;imageStore.ImageExtension = “jpg”;imageStore.CacheDirectory = String.Format(“{0}BMNG{1}”, m_WorldWindow.Cache.CacheDirectory, String.Format(“BMNG (Shaded) Tiled - {0}.2004”, i + 1));ias = new WorldWind.ImageStore[1];ias[0] = imageStore;m_QuadTileLayers[0, i] = new WorldWind.Renderable.QuadTileSet(String.Format(“Tiled - {0}.2004”, i + 1),m_WorldWindow.CurrentWorld,0,90, -90, -180, 180,true,ias);BMNG中的NltImageStore.cs、QuadTileSet类。这是我们关注的对象。
QuadTileSet继承自RenderableObject,是要绘制渲染的对象类。
关注它的562行Update方法、517行Initialize()方法、 701行Render()方法。
Update()方法
QuadTileSet的Update()方法
public override void Update(DrawArgs drawArgs){if (!isInitialized)Initialize(drawArgs);if (m_effectPath != null && m_effect == null){string errs = string.Empty;m_effect = Effect.FromFile(DrawArgs.Device, m_effectPath, null, “”, ShaderFlags.None, m_effectPool, out errs);if (errs != null && errs != string.Empty){Log.Write(Log.Levels.Warning, “Could not load effect ” + m_effectPath + “: ” + errs);Log.Write(Log.Levels.Warning, “Effect has been disabled.”);m_effectPath = null;m_effect = null;}}if (ImageStores[0].LevelZeroTileSizeDegrees < 180){// Check for layer outside viewdouble vrd = DrawArgs.Camera.ViewRange.Degrees;double latitudeMax = DrawArgs.Camera.Latitude.Degrees + vrd;double latitudeMin = DrawArgs.Camera.Latitude.Degrees - vrd;double longitudeMax = DrawArgs.Camera.Longitude.Degrees + vrd;double longitudeMin = DrawArgs.Camera.Longitude.Degrees - vrd;if (latitudeMax < m_south || latitudeMin > m_north || longitudeMax < m_west || longitudeMin > m_east)return;}if (DrawArgs.Camera.ViewRange * 0.5f >Angle.FromDegrees(TileDrawDistance * ImageStores[0].LevelZeroTileSizeDegrees)){lock (m_topmostTiles.SyncRoot){foreach (QuadTile qt in m_topmostTiles.Values)qt.Dispose();m_topmostTiles.Clear();ClearDownloadRequests();}return;}//知识点,可以看看,如何计算不可见瓦片的算法。RemoveInvisibleTiles(DrawArgs.Camera);下面主要是如何计算和加载瓦片式影像的,是重点,但不是这次的重点。
try{//根据Camera所对的中心经纬度,计算中心点的行列号int middleRow = MathEngine.GetRowFromLatitude(DrawArgs.Camera.Latitude, ImageStores[0].LevelZeroTileSizeDegrees);int middleCol = MathEngine.GetColFromLongitude(DrawArgs.Camera.Longitude, ImageStores[0].LevelZeroTileSizeDegrees);//根据行列号,反推瓦片的四点对应的经度或纬度double middleSouth = -90.0f + middleRow * ImageStores[0].LevelZeroTileSizeDegrees;double middleNorth = -90.0f + middleRow * ImageStores[0].LevelZeroTileSizeDegrees + ImageStores[0].LevelZeroTileSizeDegrees;double middleWest = -180.0f + middleCol * ImageStores[0].LevelZeroTileSizeDegrees;double middleEast = -180.0f + middleCol * ImageStores[0].LevelZeroTileSizeDegrees + ImageStores[0].LevelZeroTileSizeDegrees;double middleCenterLat = 0.5f * (middleNorth + middleSouth);double middleCenterLon = 0.5f * (middleWest + middleEast);//这里存在一个算法,由中心瓦片框,向四周扩散地找相邻的瓦片矩形框。//有兴趣的网友可以看一下,根据算法画出图来就好理解啦。(我感觉该算法对以后开发会有用的)int tileSpread = 4;for (int i = 0; i < tileSpread; i++){for (double j = middleCenterLat - i * ImageStores[0].LevelZeroTileSizeDegrees; j < middleCenterLat + i * ImageStores[0].LevelZeroTileSizeDegrees; j += ImageStores[0].LevelZeroTileSizeDegrees){for (double k = middleCenterLon - i * ImageStores[0].LevelZeroTileSizeDegrees; k < middleCenterLon + i * ImageStores[0].LevelZeroTileSizeDegrees; k += ImageStores[0].LevelZeroTileSizeDegrees){//根据经纬度和tileSize来计算行列号,这里LevelZeroTileSizeDegrees为第0层的瓦片大小为36度,瓦片总个数为50片int curRow = MathEngine.GetRowFromLatitude(Angle.FromDegrees(j), ImageStores[0].LevelZeroTileSizeDegrees);int curCol = MathEngine.GetColFromLongitude(Angle.FromDegrees(k), ImageStores[0].LevelZeroTileSizeDegrees);long key = ((long)curRow << 32) + curCol;//如果集合m_topmostTiles已经存在QuadTile,则更新QuadTileQuadTile qt = (QuadTile)m_topmostTiles[key];if (qt != null){qt.Update(drawArgs);continue;}// Check for tile outside layer boundaries,获取外边框四点经度或纬度坐标double west = -180.0f + curCol * ImageStores[0].LevelZeroTileSizeDegrees;if (west > m_east)continue;double east = west + ImageStores[0].LevelZeroTileSizeDegrees;if (east < m_west)continue;double south = -90.0f + curRow * ImageStores[0].LevelZeroTileSizeDegrees;if (south > m_north)continue;double north = south + ImageStores[0].LevelZeroTileSizeDegrees;if (north < m_south)continue;//结合中不存在,创建新的QuadTileqt = new QuadTile(south, north, west, east, 0, this);//判断新的QuadTile是否在可视区域中。(可以关注一下:Intersects()方法判断矩形框相交)if (DrawArgs.Camera.ViewFrustum.Intersects(qt.BoundingBox)){lock (m_topmostTiles.SyncRoot)m_topmostTiles.Add(key, qt);//调用QuadTile的Update()方法qt.Update(drawArgs);}}}}}catch (System.Threading.ThreadAbortException){}catch (Exception caught){Log.Write(caught);}}Render()方法的关键代码为:
device.VertexFormat = CustomVertex.PositionNormalTextured.Format;foreach (QuadTile qt in m_topmostTiles.Values)qt.Render(drawArgs);从上面可以看出,QuadTileSet可看作是QuadTile的集合,真正实现更新和渲染的是QuadTile对象。里面有影像的加载和渲染绘制,也有DEM的渲染绘制。
我们先看看QuadTile.cs 中Update()方法:
QuadTile的Update()代码
public virtual void Update(DrawArgs drawArgs){if (m_isResetingCache)return;try{double tileSize = North - South;if (!isInitialized){if (DrawArgs.Camera.ViewRange * 0.5f < Angle.FromDegrees(QuadTileSet.TileDrawDistance * tileSize)&& MathEngine.SphericalDistance(CenterLatitude, CenterLongitude,DrawArgs.Camera.Latitude, DrawArgs.Camera.Longitude) < Angle.FromDegrees(QuadTileSet.TileDrawSpread * tileSize * 1.25f)&& DrawArgs.Camera.ViewFrustum.Intersects(BoundingBox))Initialize();}if (isInitialized && World.Settings.VerticalExaggeration != verticalExaggeration || m_CurrentOpacity != QuadTileSet.Opacity ||QuadTileSet.RenderStruts != renderStruts){//创建瓦片网格(重点)CreateTileMesh();}if (isInitialized){//判断进入下一层的条件(ViewRange角度、球面距离、可视区域)if (DrawArgs.Camera.ViewRange < Angle.FromDegrees(QuadTileSet.TileDrawDistance * tileSize)&& MathEngine.SphericalDistance(CenterLatitude, CenterLongitude,DrawArgs.Camera.Latitude, DrawArgs.Camera.Longitude) < Angle.FromDegrees(QuadTileSet.TileDrawSpread * tileSize)&& DrawArgs.Camera.ViewFrustum.Intersects(BoundingBox)){if (northEastChild == null || northWestChild == null || southEastChild == null || southWestChild == null){//计算下一级别的四个子瓦片(重点,稍后一起看看)ComputeChildren(drawArgs);}if (northEastChild != null){northEastChild.Update(drawArgs);}if (northWestChild != null){northWestChild.Update(drawArgs);}if (southEastChild != null){southEastChild.Update(drawArgs);}if (southWestChild != null){southWestChild.Update(drawArgs);}}else{if (northWestChild != null){northWestChild.Dispose();northWestChild = null;}if (northEastChild != null){northEastChild.Dispose();northEastChild = null;}if (southEastChild != null){southEastChild.Dispose();southEastChild = null;}if (southWestChild != null){southWestChild.Dispose();southWestChild = null;}}}if (isInitialized){if (DrawArgs.Camera.ViewRange / 2 > Angle.FromDegrees(QuadTileSet.TileDrawDistance * tileSize * 1.5f)|| MathEngine.SphericalDistance(CenterLatitude, CenterLongitude, DrawArgs.Camera.Latitude, DrawArgs.Camera.Longitude) > Angle.FromDegrees(QuadTileSet.TileDrawSpread * tileSize * 1.5f)){if (Level != 0 || (Level == 0 && !QuadTileSet.AlwaysRenderBaseTiles))this.Dispose();}}}catch{}}创建下一级的四个瓦片的方法:(可以被我们重用)
ComputeChildren(DrawArgs drawArgs)public virtual void ComputeChildren(DrawArgs drawArgs){//判断是否是最高级别if (Level + 1 >= QuadTileSet.ImageStores[0].LevelCount)return;//计算瓦片的中点经纬度double CenterLat = 0.5f * (South + North);double CenterLon = 0.5f * (East + West);if (northWestChild == null)northWestChild = ComputeChild(CenterLat, North, West, CenterLon);if (northEastChild == null)northEastChild = ComputeChild(CenterLat, North, CenterLon, East);if (southWestChild == null)southWestChild = ComputeChild(South, CenterLat, West, CenterLon);if (southEastChild == null)southEastChild = ComputeChild(South, CenterLat, CenterLon, East);}ComputeChild(double childSouth, double childNorth, double childWest, double childEast)///
/// Returns the QuadTile for specified location if available.
/// Tries to queue a download if not available.
///
/// private QuadTile ComputeChild(double childSouth, double childNorth, double childWest, double childEast)
{
QuadTile child = new QuadTile(
childSouth,
childNorth,
childWest,
childEast,
this.Level + 1,
QuadTileSet);
return child;
}
QuadTile.cs 中的CreateTileMesh()方法用来创建瓦片格网的,分别在Initialize() 、Update()方法中调用,
410行 这里调用的CreateElevatedMesh();是添加DEM数据创建高程格网的。
////// Builds flat or terrain mesh for current tile
///
public virtual void CreateTileMesh()
{
verticalExaggeration = World.Settings.VerticalExaggeration;
m_CurrentOpacity = QuadTileSet.Opacity;
renderStruts = QuadTileSet.RenderStruts;
if (QuadTileSet.TerrainMapped && Math.Abs(verticalExaggeration) > 1e-3)
//创建具有高程值的格网(今天要关注的)
CreateElevatedMesh();
else
//创建没有高程值的平面格网
CreateFlatMesh();
}
591行CreateElevatedMesh()创建具有高程值的格网
////// Build the elevated terrain mesh
///
protected virtual void CreateElevatedMesh()
{
isDownloadingTerrain = true;
//vertexCountElevated值为40;向四周分别扩充一个样本点
// Get height data with one extra sample around the tile
double degreePerSample = LatitudeSpan / vertexCountElevated;
//获取具有高程值的TerrainTile对象(这是最关键部分,深入分析)
TerrainTile tile = QuadTileSet.World.TerrainAccessor.GetElevationArray(North + degreePerSample, South - degreePerSample, West - degreePerSample, East + degreePerSample, vertexCountElevated + 3);
float[,] heightData = tile.ElevationData;
int vertexCountElevatedPlus3 = vertexCountElevated / 2 + 3;
int totalVertexCount = vertexCountElevatedPlus3 * vertexCountElevatedPlus3;
northWestVertices = new CustomVertex.PositionNormalTextured[totalVertexCount];
southWestVertices = new CustomVertex.PositionNormalTextured[totalVertexCount];
northEastVertices = new CustomVertex.PositionNormalTextured[totalVertexCount];
southEastVertices = new CustomVertex.PositionNormalTextured[totalVertexCount];
double layerRadius = (double)QuadTileSet.LayerRadius;
// Calculate mesh base radius (bottom vertices)
// Find minimum elevation to account for possible bathymetry
float minimumElevation = float.MaxValue;
float maximumElevation = float.MinValue;
foreach (float height in heightData)
{
if (height < minimumElevation)
minimumElevation = height;
if (height > maximumElevation)
maximumElevation = height;
}
minimumElevation *= verticalExaggeration;
maximumElevation *= verticalExaggeration;
if (minimumElevation > maximumElevation)
{
// Compensate for negative vertical exaggeration
minimumElevation = maximumElevation;
maximumElevation = minimumElevation;
}
double verlap = 500 * verticalExaggeration; // 500m high tiles
// Radius of mesh bottom grid
meshBaseRadius = layerRadius + minimumElevation - overlap;
CreateElevatedMesh(ChildLocation.NorthWest, northWestVertices, meshBaseRadius, heightData);
CreateElevatedMesh(ChildLocation.SouthWest, southWestVertices, meshBaseRadius, heightData);
CreateElevatedMesh(ChildLocation.NorthEast, northEastVertices, meshBaseRadius, heightData);
CreateElevatedMesh(ChildLocation.SouthEast, southEastVertices, meshBaseRadius, heightData);
BoundingBox = new BoundingBox((float)South, (float)North, (float)West, (float)East,
(float)layerRadius, (float)layerRadius + 10000 * this.verticalExaggeration);
QuadTileSet.IsDownloadingElevation = false;
// Build common set of indexes for the 4 child meshes
int vertexCountElevatedPlus2 = vertexCountElevated / 2 + 2;
vertexIndexes = new short[2 * vertexCountElevatedPlus2 * vertexCountElevatedPlus2 * 3];
int elevated_idx = 0;
for (int i = 0; i < vertexCountElevatedPlus2; i++)
{
for (int j = 0; j < vertexCountElevatedPlus2; j++)
{
vertexIndexes[elevated_idx++] = (short)(i * vertexCountElevatedPlus3 + j);
vertexIndexes[elevated_idx++] = (short)((i + 1) * vertexCountElevatedPlus3 + j);
vertexIndexes[elevated_idx++] = (short)(i * vertexCountElevatedPlus3 + j + 1);
vertexIndexes[elevated_idx++] = (short)(i * vertexCountElevatedPlus3 + j + 1);
vertexIndexes[elevated_idx++] = (short)((i + 1) * vertexCountElevatedPlus3 + j);
vertexIndexes[elevated_idx++] = (short)((i + 1) * vertexCountElevatedPlus3 + j + 1);
}
}
calculate_normals(ref northWestVertices, vertexIndexes);
calculate_normals(ref southWestVertices, vertexIndexes);
calculate_normals(ref northEastVertices, vertexIndexes);
calculate_normals(ref southEastVertices, vertexIndexes);
isDownloadingTerrain = false;
}
596行TerrainTile tile = QuadTileSet.World.TerrainAccessor.GetElevationArray(North + degreePerSample, South - degreePerSample, West - degreePerSample, East + degreePerSample, vertexCountElevated + 3);获取样本点的高程值数组。

篇3:WorldWind系列十四:DEM数据加载和应用――以SRTM为例(下)
使用了TerrainAccessor.cs类120行代码
public virtual TerrainTile GetElevationArray(double north, double south, double west, double east, int samples){TerrainTile res = null;res = new TerrainTile(null);res.North = north;res.South = south;res.West = west;res.East = east;res.SamplesPerTile = samples;res.IsInitialized = true;res.IsValid = true;double latrange = Math.Abs(north - south);double lonrange = Math.Abs(east - west);float[,] data = new float[samples,samples];float scaleFactor = (float)1/(samples - 1);for(int x = 0; x < samples; x++){for(int y = 0; y < samples; y++){double curLat = north - scaleFactor * latrange * x;double curLon = west + scaleFactor * lonrange * y;//关键,获取瓦片所有样本点的高程值data[x,y] = GetElevationAt(curLat, curLon, 0);}}res.ElevationData = data;return res;}关键代码:data[x,y] = GetElevationAt(curLat, curLon, 0);
GetElevationAt;在TerrainAccessor.cs是抽象方法,真正实现是在TerrainAccessor的子类NltTerrainAccessor中重载实现的。
120行 public override float GetElevationAt(double latitude, double longitude){return GetElevationAt(latitude, longitude, m_terrainTileService.SamplesPerTile / m_terrainTileService.LevelZeroTileSizeDegrees);}TerrainAccessor对象哪里来的(即:在哪完成初始化和传入的?)
ConfigurationLoader.cs的Load()方法的97行代码:
TerrainAccessor[] terrainAccessor = getTerrainAccessorsFromXPathNodeIterator(worldIter.Current.Select(“TerrainAccessor”),System.IO.Path.Combine(cache.CacheDirectory, worldName));World newWorld = new World(worldName,new Microsoft.DirectX.Vector3(0, 0, 0),new Microsoft.DirectX.Quaternion(0, 0, 0, 0),equatorialRadius,cache.CacheDirectory,(terrainAccessor != null ? terrainAccessor[0] : null)//TODO: Oops, World should be able to handle an array of terrainAccessors);然后通过World对象传入到QuadTileSet类中的。
我们看看getTerrainAccessorsFromXPathNodeIterator方法如何完成完成TerrainAccessor对象。
注意:该方法返回值为TerrainAccessor[],是个数组,为什么呢??(请关注我下一篇文章)
2078行
getTerrainAccessorsFromXPathNodeIterator(XPathNodeIterator iter, string cacheDirectory)代码
private static TerrainAccessor[] getTerrainAccessorsFromXPathNodeIterator(XPathNodeIterator iter, string cacheDirectory){System.Collections.ArrayList terrainAccessorList = new System.Collections.ArrayList();//下面是读取DEM配置XML,并根据配置信息创建TerrainTileService对象和TerrainAccessor对象while(iter.MoveNext()){string terrainAccessorName = iter.Current.GetAttribute(“Name”, “”);if(terrainAccessorName == null){// TODO: Throw exception?continue;}XPathNodeIterator latLonBoxIter = iter.Current.Select(“LatLonBoundingBox”);if(latLonBoxIter.Count != 1){// TODO: Throw exception?continue;}double north = 0;double south = 0;double west = 0;double east = 0;latLonBoxIter.MoveNext();north = ParseDouble(getInnerTextFromFirstChild(latLonBoxIter.Current.Select(“North”)));south = ParseDouble(getInnerTextFromFirstChild(latLonBoxIter.Current.Select(“South”)));west = ParseDouble(getInnerTextFromFirstChild(latLonBoxIter.Current.Select(“West”)));east = ParseDouble(getInnerTextFromFirstChild(latLonBoxIter.Current.Select(“East”)));TerrainAccessor[] higerResolutionSubsets = getTerrainAccessorsFromXPathNodeIterator(iter.Current.Select(“HigherResolutionSubsets”),Path.Combine(cacheDirectory, terrainAccessorName));XPathNodeIterator tileServiceIter = iter.Current.Select(“TerrainTileService”);if(tileServiceIter.Count == 1){string serverUrl = null;string dataSetName = null;double levelZeroTileSizeDegrees = double.NaN;uint numberLevels = 0;uint samplesPerTile = 0;string dataFormat = null;string fileExtension = null;string compressionType = null;tileServiceIter.MoveNext();serverUrl = getInnerTextFromFirstChild(tileServiceIter.Current.Select(“ServerUrl”));dataSetName = getInnerTextFromFirstChild(tileServiceIter.Current.Select(“DataSetName”));levelZeroTileSizeDegrees = ParseDouble(getInnerTextFromFirstChild(tileServiceIter.Current.Select(“LevelZeroTileSizeDegrees”)));numberLevels = uint.Parse(getInnerTextFromFirstChild(tileServiceIter.Current.Select(“NumberLevels”)));samplesPerTile = uint.Parse(getInnerTextFromFirstChild(tileServiceIter.Current.Select(“SamplesPerTile”)));dataFormat = getInnerTextFromFirstChild(tileServiceIter.Current.Select(“DataFormat”));fileExtension = getInnerTextFromFirstChild(tileServiceIter.Current.Select(“FileExtension”));compressionType = getInnerTextFromFirstChild(tileServiceIter.Current.Select(“CompressonType”));//根据配置信息创建TerrainTileService对象和TerrainAccessor对象TerrainTileService tts = new TerrainTileService(serverUrl,dataSetName,levelZeroTileSizeDegrees,(int)samplesPerTile,fileExtension,(int)numberLevels,Path.Combine(cacheDirectory, terrainAccessorName),World.Settings.TerrainTileRetryInterval,dataFormat);TerrainAccessor newTerrainAccessor = new NltTerrainAccessor(terrainAccessorName,west,south,east,north,tts,higerResolutionSubsets);terrainAccessorList.Add(newTerrainAccessor);}//TODO: Add Floating point terrain Accessor code//TODO: Add WMSAccessor code and make it work in TerrainAccessor (which it currently doesn't)}if(terrainAccessorList.Count > 0){return (TerrainAccessor[])terrainAccessorList.ToArray(typeof(TerrainAccessor));}else{return null;}}再来看看DEM的配置在哪里和XML内容吧
路径:
C:Program FilesNASAWorld Wind 1.4ConfigEarth.xml
配置内容:
?xml version=“1.0” encoding=“UTF-8”?>接着上面的讲NltTerrainAccessor类76行代码GetElevationAt(double latitude, double longitude, double targetSamplesPerDegree)方法。
获取特定点的高程值
////// Get terrain elevation at specified location.
///
/// Latitude in decimal degrees.
/// Longitude in decimal degrees.
///
/// public override float GetElevationAt(double latitude, double longitude, double targetSamplesPerDegree)
{
try
{
if (m_terrainTileService == null || targetSamplesPerDegree < World.Settings.MinSamplesPerDegree)
return 0;
if (m_higherResolutionSubsets != null)
{
foreach (TerrainAccessor higherResSub in m_higherResolutionSubsets)
{
if (latitude > higherResSub.South && latitude < higherResSub.North &&
longitude > higherResSub.West && longitude < higherResSub.East)
{
return higherResSub.GetElevationAt(latitude, longitude, targetSamplesPerDegree);
}
}
}
//自己可以看看如何完成TerrainTile的初始化构建的
TerrainTile tt = m_terrainTileService.GetTerrainTile(latitude, longitude, targetSamplesPerDegree);
TerrainTileCacheEntry 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;
//获取高程值
return ttce.TerrainTile.GetElevationAt(latitude, longitude);
}
catch (Exception)
{
}
return 0;
}
上面获取高程值的关键:TerrainTile类的330行的GetElevationAt(double latitude, double longitude)方法
public float GetElevationAt(double latitude, double longitude){try{double deltaLat = North - latitude;double deltaLon = longitude - West;//TileSizeDegrees为当前级别下瓦片的度数大小//计算方法:158行tile.TileSizeDegrees = m_levelZeroTileSizeDegrees * Math.Pow(0.5, tile.TargetLevel);//注意思考:SamplesPerTile-1为什么是减去1?传进来的SamplesPerTile=43而不是44?//如果传入的是44,这里应该减2double df2 = (SamplesPerTile-1) / 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 - 1;if(lat_max >= SamplesPerTile)lat_max = SamplesPerTile - 1;if(lon_min >= SamplesPerTile)lon_min = SamplesPerTile - 1;if(lon_max >= SamplesPerTile)lon_max = SamplesPerTile - 1;if(lat_min < 0)lat_min = 0;if(lat_max < 0)lat_max = 0;if(lon_min < 0)lon_min = 0;if(lon_max < 0)lon_max = 0;float delta = lat_pixel - lat_min;//根据外矩形四顶点的经纬度分别插值计算中间线的高程float westElevation =ElevationData[lon_min, lat_min]*(1-delta) +ElevationData[lon_min, lat_max]*delta;float eastElevation =ElevationData[lon_max, lat_min]*(1-delta) +ElevationData[lon_max, lat_max]*delta;//利用插值计算点的高程值delta = lon_pixel - lon_min;float interpolatedElevation =westElevation*(1-delta) +eastElevation*delta;return interpolatedElevation;}catch{}return 0;}public float[,] ElevationData就是存放当前瓦片所有样本点高程值的数值,
这是通过Initialize()中读取DEM(.bil)文件来获取的。
读取BIL文件高程数据
////// This method initializes the terrain tile add switches to
/// Initialize floating point/int 16 tiles
///
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 == 0)
{
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.
}
//读取BIL文件数据的关键代码,可以被我们借鉴使用
using( Stream s = File.OpenRead(TerrainTileFilePath))
{
BinaryReader reader = new BinaryReader(s);
if(m_owner.DataType==“Int16”)
{
for(int y = 0; y < SamplesPerTile; y++)
for(int x = 0; x < SamplesPerTile; x++)
ElevationData[x,y] = reader.ReadInt16();
}
if(m_owner.DataType==“Float32”)
{
for(int y = 0; y < SamplesPerTile; y++)
for(int x = 0; 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);
}
}
}另注:SRTM的高程数据存放路径如下图:(DEM跟影像也是分级存放的,存放方式一致)
至此,如何加载DEM数据创建网格的过程已经分析完了。
接下来,继续分析QuadTile.cs中CreateElevatedMesh()和Render方法,内容主要是DirectX编程,稍后添加……
篇4:WorldWind系列五:插件加载过程全解析
不得不承认World Wind的代码真的很庞大,没有太多帮助文档的前提下,一头钻进代码里肯定令你头疼的,甚至研究代码间关联仿佛是在走迷宫,我最近一直想弄明白如何在 MenuBar中加载那些插件的,WorldWind学习系列四中研究的只是特殊的三个功能加载的,那三个没有继承Plugin类,不算是插件功能加载。所以WorldWind学习系列四加载的三个是特殊情况,不是一般的插件加载。今天下午终于柳暗花明,如果你真正关注World Wind分析,那么就好好看看下面的插件加载过程全解析。
我们先看看Plugin类的继承图,看看到底都有些什么插件,然后在分析一般性的插件加载全过程。
哦,原来这么多插件,我们要基于WW开发自己的应用,只需继承Plugin类写出自己的插件功能即可的。
我们现在分析插件加载过程,请确保你看过WorldWind学习系列二:擒贼先擒王篇2 中的(5.加载上次使用的配置信息)。加载的插件入口就是WorldWind.cs的Main()中调用的LoadSettings()静态方法。
1.读取WorldWind的配置中插件信息
加载WorldWind配置
private static void LoadSettings(){try{//先读取上次使用时保存的“使用插件配置文件”,如果存在,则从文件中读取配置实例化WorldWindSettingsSettings = (WorldWindSettings) SettingsBase.Load(Settings, SettingsBase.LocationType.User);if(!File.Exists(Settings.FileName)){//我们假定是配置文件不存在,这就是一个个地加载插件,保存到ArrayList中Settings.PluginsLoadedOnStartup.Add(“ShapeFileInfoTool”);//Settings.PluginsLoadedOnStartup.Add(“OverviewFormLoader”);//Settings.PluginsLoadedOnStartup.Add(“Atmosphere”);Settings.PluginsLoadedOnStartup.Add(“SkyGradient”);Settings.PluginsLoadedOnStartup.Add(“BmngLoader”);//Settings.PluginsLoadedOnStartup.Add(“Compass”);//Settings.PluginsLoadedOnStartup.Add(“ExternalLayerManagerLoader”);Settings.PluginsLoadedOnStartup.Add(“MeasureTool”);//Settings.PluginsLoadedOnStartup.Add(“MovieRecorder”);Settings.PluginsLoadedOnStartup.Add(“NRLWeatherLoader”);Settings.PluginsLoadedOnStartup.Add(“ShapeFileLoader”);Settings.PluginsLoadedOnStartup.Add(“Stars3D”);Settings.PluginsLoadedOnStartup.Add(“GlobalClouds”);Settings.PluginsLoadedOnStartup.Add(“PlaceFinderLoader”);Settings.PluginsLoadedOnStartup.Add(“LightController”);Settings.PluginsLoadedOnStartup.Add(“Earthquake_2.0.2.1”);Settings.PluginsLoadedOnStartup.Add(“Historical_Earthquake_2.0.2.2”);Settings.PluginsLoadedOnStartup.Add(“KMLImporter”);//Settings.PluginsLoadedOnStartup.Add(“doublezoom”);//Settings.PluginsLoadedOnStartup.Add(“PlanetaryRings”);Settings.PluginsLoadedOnStartup.Add(“TimeController”);//Settings.PluginsLoadedOnStartup.Add(“WavingFlags”);Settings.PluginsLoadedOnStartup.Add(“ScaleBarLegend”);Settings.PluginsLoadedOnStartup.Add(“Compass3D”);Settings.PluginsLoadedOnStartup.Add(“AnaglyphStereo”);Settings.PluginsLoadedOnStartup.Add(“GlobeIcon”);}// decrypt encoded user credentialsDataProtector dp = new DataProtector(DataProtector.Store.USE_USER_STORE);if(Settings.ProxyUsername.Length > 0) Settings.ProxyUsername = dp.TransparentDecrypt(Settings.ProxyUsername);if(Settings.ProxyPassword.Length > 0) Settings.ProxyPassword = dp.TransparentDecrypt(Settings.ProxyPassword);}catch(Exception caught){Log.Write(caught);}}2.Main()中后面调用MainApplication()方法,该MainApplication()调用 OpenStartupWorld(),用来初始化启动World对象。OpenStartupWorld()方法首先确定加载的是Earth/Moon 等,然后开始加载一个星球。
加载一个星球代码
////// Loads a new planet
///
private void OpenWorld(string worldXmlFile)
{
if(this.worldWindow.CurrentWorld != null)
{
try
{
this.worldWindow.ResetToolbar();
}
catch
{}
try
{
foreach(PluginInfo p in this.compiler.Plugins)
{
try
{
if(p.Plugin.IsLoaded)
p.Plugin.Unload();
}
catch
{}
}
}
catch
{}
try
{
this.worldWindow.CurrentWorld.Dispose();
}
catch
{}
}
if(this.gotoDialog != null)
{
this.gotoDialog.Dispose();
this.gotoDialog = null;
}
if(this.rapidFireModisManager != null)
{
this.rapidFireModisManager.Dispose();
this.rapidFireModisManager = null;
}
if(this.animatedEarthMananger != null)
{
this.animatedEarthMananger.Dispose();
this.animatedEarthMananger = null;
}
if(this.wmsBrowser != null)
{
this.wmsBrowser.Dispose();
this.wmsBrowser = null;
}
worldWindow.CurrentWorld = WorldWind.ConfigurationLoader.Load(worldXmlFile, worldWindow.Cache);
this.splashScreen.SetText(“Initializing menus...”);
// InitializePluginCompiler()是我们要关注的初始化插件编辑器PluginCompiler(真正管理加载插件的类)
InitializePluginCompiler();
//RenderableObject系统很复杂,我们稍后准备专门分析一下
foreach(RenderableObject worldRootObject in this.worldWindow.CurrentWorld.RenderableObjects.ChildObjects)
{
this.AddLayerMenuButtons(this.worldWindow, worldRootObject);
}
//加载Earth专有的MenuButton( AnimatedEarthManager和RapidFireModisManager)的配置,
//这里主要不关注
this.AddInternalPluginMenuButtons();
this.menuItemModisHotSpots.Enabled = worldWindow.CurrentWorld.IsEarth;
this.menuItemAnimatedEarth.Enabled = worldWindow.CurrentWorld.IsEarth;
}3.我们看看InitializePluginCompiler()如何加载插件的?
初始化PluginCompiler
////// Compile and run plug-in “scripts”
///
private void InitializePluginCompiler()
{
Log.Write(Log.Levels.Debug, “CONF”, “initializing plugin compiler...”);
this.splashScreen.SetText(“Initializing plugins...”);
string pluginRoot = Path.Combine(DirectoryPath, “Plugins”);
compiler = new PluginCompiler(this, pluginRoot);
//#if DEBUG
// Search for plugins in worldwind.exe (plugin development/debugging aid)
compiler.FindPlugins(Assembly.GetExecutingAssembly());
//#endif
//从启动文件夹下Plugins文件夹,加载插件
compiler.FindPlugins();
//加载启动插件插件
compiler.LoadStartupPlugins();
}4.加载启动插件函数的代码
加载启动插件
/// Loads the plugins that are set for load on world wind startup.///public void LoadStartupPlugins(){foreach(PluginInfo pi in m_plugins){if(pi.IsLoadedAtStartup){try{// CompileLog.Write(Log.Levels.Debug, LogCategory, “loading ”+pi.Name+“ ...”);worldWind.SplashScreen.SetText(“Initializing plugin ” + pi.Name);//Load方法加载插件,Plugin类的Load()为虚方法,实质上调用的是各个插件重载后的Load()方法Load(pi);}catch(Exception caught){// Plugin failed to loadstring message = “Plugin ” + pi.Name + “ failed: ” + caught.Message;Log.Write(Log.Levels.Error, LogCategory, message);Log.Write(caught);// Disable automatic load of this plugin on startuppi.IsLoadedAtStartup = false;worldWind.SplashScreen.SetError(message);}}}}5.现在看两个插件类重载的Load()方法的实例。例如:Compass3D.cs和TimeController.cs。
Compass3D.cs的Load()方法
重载后的Load方法
public override void Load(){m_menuItem = new System.Windows.Forms.MenuItem(“Compass”);m_menuItem.Click += new EventHandler(m_menuItem_Click);m_menuItem.Checked = World.Settings.ShowCompass;ParentApplication.ToolsMenu.MenuItems.Add(m_menuItem);m_form. = new FormWidget(“Compass”);m_form.ClientSize = new System.Drawing.Size(200, 200);m_form.Location = new System.Drawing.Point(0, 400);m_form.BackgroundColor = World.Settings.WidgetBackgroundColor;m_form.AutoHideHeader = true;m_form.VerticalScrollbarEnabled = false;m_form.HorizontalScrollbarEnabled = false;m_form.BorderEnabled = false;//注册两个窗体事件m_form.OnResizeEvent += new FormWidget.ResizeHandler(m_form_OnResizeEvent);m_form.OnVisibleChanged += new VisibleChangedHandler(m_form_OnVisibleChanged);//实例化Compass3DWidgetm_compass = new Compass3DWidget();m_compass.Location = new System.Drawing.Point(5, 0);m_compass.Font = new System.Drawing.Font(“Ariel”, 10.0f, System.Drawing.FontStyle.Bold);m_compass.ParentWidget = m_form;m_form_OnResizeEvent(m_form, m_form.WidgetSize);m_form.ChildWidgets.Add(m_compass);m_form.Visible = World.Settings.ShowCompass;//将要绘制的Widget加载到DrawArgs.NewRootWidget.ChildWidgets,为了在WorldWindow.cs的Render()方法里渲染DrawArgs.NewRootWidget.ChildWidgets.Add(m_form);//Compass 3D工具菜单按钮m_toolbarItem = new WorldWind.NewWidgets.WidgetMenuButton(“Compass 3D”,basePath + “DataIconsInterfacecompass2.png”,m_form);//向MenuBar中添加Compass 3D菜单按钮ParentApplication.WorldWindow.MenuBar.AddToolsMenuButton(m_toolbarItem);base.Load();}TimeController.cs的Load方法,如下:
时间控制
public override void Load(){try{m_window = new WorldWind.NewWidgets.FormWidget(“Time Control”);m_window.Name = “Time Control”;m_window.ClientSize = new System.Drawing.Size(300, 183);// Bug in FormWidget required anchor to be set before Location and parent widgetm_window.Anchor = WorldWind.NewWidgets.WidgetEnums.AnchorStyles.Left | WorldWind.NewWidgets.WidgetEnums.AnchorStyles.Bottom;m_window.ParentWidget = DrawArgs.NewRootWidget;m_window.Location = new System.Drawing.Point(0, DrawArgs.NewRootWidget.ClientSize.Height - 183);m_window.Text = “Double Click to Re-Open”;m_window.BorderEnabled = false;m_window.AutoHideHeader = true;m_window.BackgroundColor = System.Drawing.Color.FromArgb(0, 0, 0, 0);m_window.HeaderEnabled = true;m_window.Visible = false;time = new WorldWind.NewWidgets.PictureBox();time.Name = “Time”;time.ImageUri = basePath + “DataIconsTimetime off.png”;time.ClientLocation = new System.Drawing.Point(12, 59);time.ClientSize = new System.Drawing.Size(42, 42);time.Visible = true;time.ParentWidget = m_window;time.OnMouseEnterEvent += new EventHandler(time_OnMouseEnterEvent);time.OnMouseLeaveEvent += new EventHandler(time_OnMouseLeaveEvent);time.OnMouseUpEvent += new MouseEventHandler(time_OnMouseUpEvent);time.CountHeight = false;time.CountWidth = true;m_window.ChildWidgets.Add(time);play = new WorldWind.NewWidgets.PictureBox();play.Name = “Play”;if (TimeKeeper.Enabled){play.ImageUri = basePath + “DataIconsTimeplay on.png”;}else{play.ImageUri = basePath + “DataIconsTimeplay off.png”;}play.ClientLocation = new System.Drawing.Point(50, 1);play.ClientSize = new System.Drawing.Size(82, 82);play.Visible = true;play.ParentWidget = m_window;play.OnMouseEnterEvent += new EventHandler(play_OnMouseEnterEvent);play.OnMouseLeaveEvent += new EventHandler(play_OnMouseLeaveEvent);play.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(play_OnMouseUpEvent);play.CountHeight = true;play.CountWidth = true;m_window.ChildWidgets.Add(play);close = new WorldWind.NewWidgets.PictureBox();close.Name = “Close”;close.ImageUri = basePath + “DataIconsTimeclose off.png”;close.ClientLocation = new System.Drawing.Point(29, 3);close.ClientSize = new System.Drawing.Size(22, 22);close.Visible = true;close.ParentWidget = m_window;close.OnMouseEnterEvent += new EventHandler(close_OnMouseEnterEvent);close.OnMouseLeaveEvent += new EventHandler(close_OnMouseLeaveEvent);close.OnMouseUpEvent += new MouseEventHandler(close_OnMouseUpEvent);close.CountHeight = false;close.CountWidth = false;m_window.ChildWidgets.Add(close);rewind = new WorldWind.NewWidgets.PictureBox();rewind.Name = “Rewind”;rewind.ImageUri = basePath + “DataIconsTimerepeat off.png”;rewind.ClientLocation = new System.Drawing.Point(16, 26);rewind.ClientSize = new System.Drawing.Size(32, 32);rewind.Visible = true;rewind.ParentWidget = m_window;rewind.OnMouseEnterEvent += new EventHandler(rewind_OnMouseEnterEvent);rewind.OnMouseLeaveEvent += new EventHandler(rewind_OnMouseLeaveEvent);rewind.OnMouseUpEvent += new MouseEventHandler(rewind_OnMouseUpEvent);rewind.CountHeight = false;rewind.CountWidth = false;m_window.ChildWidgets.Add(rewind);pause = new WorldWind.NewWidgets.PictureBox();pause.Name = “Pause”;if (TimeKeeper.Enabled){pause.ImageUri = basePath + “DataIconsTimepause off.png”;}else{pause.ImageUri = basePath + “DataIconsTimepause on.png”;}pause.ClientLocation = new System.Drawing.Point(35, 88);pause.ClientSize = new System.Drawing.Size(64, 64);pause.Visible = true;pause.ParentWidget = m_window;pause.OnMouseEnterEvent += new EventHandler(pause_OnMouseEnterEvent);pause.OnMouseLeaveEvent += new EventHandler(pause_OnMouseLeaveEvent);pause.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(pause_OnMouseUpEvent);pause.CountHeight = true;pause.CountWidth = false;m_window.ChildWidgets.Add(pause);slow = new WorldWind.NewWidgets.PictureBox();slow.Name = “Slow”;slow.ImageUri = basePath + “DataIconsTimeslow off.png”;slow.ClientLocation = new System.Drawing.Point(97, 88);slow.ClientSize = new System.Drawing.Size(64, 64);slow.Visible = true;slow.ParentWidget = m_window;slow.OnMouseEnterEvent += new EventHandler(slow_OnMouseEnterEvent);slow.OnMouseLeaveEvent += new EventHandler(slow_OnMouseLeaveEvent);slow.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(slow_OnMouseUpEvent);slow.CountHeight = false;slow.CountWidth = false;m_window.ChildWidgets.Add(slow);fast = new WorldWind.NewWidgets.PictureBox();fast.Name = “Fast”;fast.ImageUri = basePath + “DataIconsTimefast off.png”;fast.ClientLocation = new System.Drawing.Point(158, 88);fast.ClientSize = new System.Drawing.Size(64, 64);fast.Visible = true;fast.ParentWidget = m_window;fast.OnMouseEnterEvent += new EventHandler(fast_OnMouseEnterEvent);fast.OnMouseLeaveEvent += new EventHandler(fast_OnMouseLeaveEvent);fast.OnMouseUpEvent += new System.Windows.Forms.MouseEventHandler(fast_OnMouseUpEvent);fast.CountHeight = false;fast.CountWidth = false;m_window.ChildWidgets.Add(fast);timeLabel = new WorldWind.NewWidgets.TextLabel();timeLabel.Name = “Current Time”;timeLabel.ClientLocation = new System.Drawing.Point(134, 65);timeLabel.ClientSize = new System.Drawing.Size(140, 60);timeLabel.Visible = true;timeLabel.ParentWidget = m_window;timeLabel.Text = GetCurrentTimeString();TimeKeeper.Elapsed += new System.Timers.ElapsedEventHandler(TimeKeeper_Elapsed);timeLabel.CountHeight = false;timeLabel.CountWidth = true;timeLabel.WordBreak = true;m_window.ChildWidgets.Add(timeLabel);DrawArgs.NewRootWidget.ChildWidgets.Add(m_window);m_toolbarItem = new WorldWind.NewWidgets.WidgetMenuButton(“Time Controller”,basePath + “DataIconsTimetime off.png”,m_window);//向MenuBar中添加菜单按钮ParentApplication.WorldWindow.MenuBar.AddToolsMenuButton(m_toolbarItem);}catch (Exception ex){Log.Write(ex);}base.Load();}其他插件的重载后的Load()方法也是类似的,不再赘述,
希望能帮研究WW的朋友理清插件加载过程的思路,少走弯路。
篇5:ArcSDE在数据连库接加载中的应用
ArcSDE在数据连库接加载中的应用
ArcSDE是ArcGIS与关系数据库之间的GIS通道.它允许用户在多种数据管理系统中管理地理信息,并使所有的ArcGIS应用程序都能够使用这些数据.ArcSDE是多用户ArcGIS系统的一个关键部件.它为DBMS提供了一个开放的接口,允许ArcGIS在多种数据库平台上管理地理信息.这些平台包括如果你的ArcGIS需要使用一个可以被大量用户同步访问并编辑的大型数据库,ArcSDE为你提供必要的.功能.通过ArcSDE你的ArcGIS可以在DBMS中轻而易举地管理一个共享的、多用户的空间数据库.
作 者:王重阳 张韶华 WANG Chong-yang ZHANG Shao-hua 作者单位:王重阳,WANG Chong-yang(北京北大方正软件技术学院,廊坊,065001)张韶华,ZHANG Shao-hua(北京市测绘设计研究院,北京,100038)
刊 名:北京测绘 英文刊名:BEIJING SURVEYING AND MAPPING 年,卷(期): “”(2) 分类号:P208 关键词:ArcSDE ArcGIS 安装 数据连接 数据加载篇6:DEM地形分析在山区地质灾害研究中的应用-以云南省漾濞县为例
DEM地形分析在山区地质灾害研究中的应用-以云南省漾濞县为例
摘要:云南省漾濞县具有典型的山地特点,每年其境内发生的地质灾害都给人民生命和财产造成了极大的损失.在漾濞县的地质灾害调查中,通过“3S”技术的应用,建立了漾濞县的数字高程模型,进行了基于ArcGIS的.地形分析,提取出了坡度和坡向等重要的地形因子.通过研究发现:坡度是漾濞县地质灾害频发的最主要控制因素,漾濞江及其支流上游的滑坡和崩塌为泥石流的发生提供了物源基础;同时阳坡是地质灾害发生的主要坡向,滑坡和崩塌等灾害发生频繁.最后,制作了漾濞县坡度、坡向分析图,指出了漾濞县较易发生地质灾害的地区,为其他山地地区地质灾害研究提供了一种借鉴模式.作 者:郑著彬 任静丽 ZHENG Zhu-bin REN Jing-li 作者单位:郑著彬,ZHENG Zhu-bin(赣南师范学院,历史文化与旅游学院,江西,赣州,341000)任静丽,REN Jing-li(赣南师范学院教育科学学院,江西,赣州,341000)
期 刊:云南地理环境研究 Journal:YUNNAN GEOGRAPHIC ENVIRONMENT RESEARCH 年,卷(期):2010, 22(2) 分类号:X87 关键词:DEM 地形分析 地质灾害 漾濞县











