有两三天没更新博客了,感觉自己又偷懒啦!周五其实主要还是看了研究WorldWind中的Virtual Earth插件功能,我以后准备开发的跟VirtualEarth很类似的,一定得把它攻下。当时Virtual Earth学习没太有大的进展,遇到的难题是:1.图片如何叠加到球体上?(包括投影变换、定位、缩放等)2.Direct 3D开发 。因为Virtual Earth是在Blue Marble插件的基础上开发,所以周六我主要是看了Direct X的基础知识和研究Blue Marble。现在与大家一起分析一下BlueMarble。
Blue Marble插件实现主要是BMNG.cs文件,里面包括两个类BMNG类和BmngLoader类。
BMNG复杂实现BlueMarble功能的控制窗体,BMNG的意思是Blue Marble Next Generation。
BmngLoader类继承自Plugin类,是负责实现插件功能的。它重载了Plugin.cs的Load()和Unload()方法,实现了菜单项点击处理功能menuItemClicked()。这跟一般的实现插件功能的流程是一样的。
下面分别看一下,关键代码的实现。
BMNG类:主要是BMNG构造函数里的处理,这是实现图片叠加到球体上处理的关键,也是分析学习的重点。
BMNG构造函数分析 public BMNG(WorldWind.WorldWindow worldWindow, MenuItem menuItem) { // // Required for Windows Form Designer support // InitializeComponent(); this .m_MenuItem = menuItem; // Plugin menu item ref int lastSelectedDatasetIndex = 1 ; try { //从"Plugins\BlueMarble\settings.txt"读取配置:上次启动时,加载的Blue Marble类型 using (StreamReader reader = new StreamReader(Path.GetDirectoryName(Application.ExecutablePath) + " \\Plugins\\BlueMarble\\settings.txt " )) { lastSelectedDatasetIndex = int .Parse(reader.ReadLine().Trim()); } } catch { } //设置Blue Marble类型 comboBoxBmngVersion.SelectedIndex = lastSelectedDatasetIndex; m_WorldWindow = worldWindow; //设置同时显示的层数 m_RenderableList.ShowOnlyOneLayer = true ; bool foundImagesObject = false ; lock (m_WorldWindow.CurrentWorld.RenderableObjects.ChildObjects.SyncRoot) { foreach (WorldWind.Renderable.RenderableObject ro in m_WorldWindow.CurrentWorld.RenderableObjects.ChildObjects) { //从所有的RenderableObjects数组里,查找是否已经存在名为“Images”的RenderableObjectList对象, //这里把所有的影像的RenderableObject图层,放在该层下面管理(参见下面图片3) if (ro is WorldWind.Renderable.RenderableObjectList && (ro.Name == " Images " )) // SF FIX: don't add to layers called 'xxxx images'! { WorldWind.Renderable.RenderableObjectList imagesList = ro as WorldWind.Renderable.RenderableObjectList; imagesList.ChildObjects.Insert( 0 , m_RenderableList); foundImagesObject = true ; break ; } } } //如果没找到,直接在顶层添加图层列表m_RenderableList if ( ! foundImagesObject) { m_WorldWindow.CurrentWorld.RenderableObjects.ChildObjects.Add(m_RenderableList); } //新建图层ImageLayer m_BlueMarbleBase = new WorldWind.Renderable.ImageLayer( " Blue Marble Base Image " , m_WorldWindow.CurrentWorld, 0 , null , - 90 , 90 , - 180 , 180 , 1.0f , null ); m_BlueMarbleBase.ImageUrl = " http://worldwind.arc.nasa.gov/downloads/land_shallow_topo_2048.dds " ; //新建NltImageStore对象,主要是辅助实现QuadTileSet(瓦片式图层) WorldWind.NltImageStore ia = new WorldWind.NltImageStore( " 106 " , " http://nww.terraserver-usa.com/nwwtile.ashx " ); ia.DataDirectory = null ; ia.LevelZeroTileSizeDegrees = 36.0 ; ia.LevelCount = 4 ; ia.ImageExtension = " jpg " ; ia.CacheDirectory = String.Format( " {0}\\Blue Marble " , m_WorldWindow.Cache.CacheDirectory); WorldWind.ImageStore[] ias = new WorldWind.ImageStore[ 1 ]; ias[ 0 ] = ia; //新建名为"Blue Marble Tiled"的QuadTileSet(瓦片式图层),这是重点 m_BlueMarbleTiled = new WorldWind.Renderable.QuadTileSet( " Blue Marble Tiled " , m_WorldWindow.CurrentWorld, 0 , 90 , - 90 , - 180 , 180 , true , ias); m_BlueMarbleTiled.ServerLogoFilePath = Path.GetDirectoryName(Application.ExecutablePath) + " \\Data\\Icons\\Interface\\meatball.png " ; //BlueMarble图层集合 m_BlueMarbleList = new WorldWind.Renderable.RenderableObjectList( " Blue Marble " ); m_BlueMarbleList.IsOn = false ; m_BlueMarbleList.Add(m_BlueMarbleBase); m_BlueMarbleList.Add(m_BlueMarbleTiled ); //BMNG图层集合 m_ShadedList = new WorldWind.Renderable.RenderableObjectList( " BMNG " ); m_ShadedList.ShowOnlyOneLayer = true ; m_ShadedList.IsOn = false ; //12个月的影像图层 for ( int i = 0 ; i < 12 ; i ++ ) { m_ImageLayers[ 0 , i] = new WorldWind.Renderable.ImageLayer( String.Format( " Base Image - {0}.2004 " , i + 1 ), m_WorldWindow.CurrentWorld, 0 , null , - 90 , 90 , - 180 , 180 , 1.0f , null ); //从http://worldwind28.arc.nasa.gov/public/上加载图片,构建ImageLayer图层 m_ImageLayers[ 0 , i].ImageUrl = String.Format( " {0}world.topo.2004{1:D2}.jpg " , m_BmngBaseImageUrl, i + 1 ); WorldWind.NltImageStore imageStore = new WorldWind.NltImageStore(String.Format( " bmng.topo.2004{0:D2} " , i + 1 ), " http://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; //构建QuadTileSet瓦片图层 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); m_QuadTileLayers[ 0 , i].ServerLogoFilePath = Path.GetDirectoryName(Application.ExecutablePath) + " \\Data\\Icons\\Interface\\meatball.png " ; m_RenderableLayers[ 0 , i] = new WorldWind.Renderable.RenderableObjectList(String.Format( " {0}.2004 " , i + 1 )); m_RenderableLayers[ 0 , i].IsOn = false ; m_RenderableLayers[ 0 , i].Add(m_ImageLayers[ 0 , i]); m_RenderableLayers[ 0 , i].Add(m_QuadTileLayers[ 0 , i]); m_ShadedList.Add(m_RenderableLayers[ 0 , i]); } m_ShadedBathyList = new WorldWind.Renderable.RenderableObjectList( " BMNG (Bathymetry) " ); m_ShadedBathyList.ShowOnlyOneLayer = true ; m_ShadedBathyList.IsOn = false ; for ( int i = 0 ; i < 12 ; i ++ ) { m_ImageLayers[ 1 , i] = new WorldWind.Renderable.ImageLayer( String.Format( " Base Image - {0}.2004 " , i + 1 ), m_WorldWindow.CurrentWorld, 0 , //从文件系统里加载影像图片 String.Format( " {0}\\Data\\Earth\\BmngBathy\\world.topo.bathy.2004{1:D2}.jpg " , Path.GetDirectoryName(Application.ExecutablePath), i + 1 ), - 90 , 90 , - 180 , 180 , 1.0f , null ); // m_ImageLayers[1, i].ImageUrl = String.Format("{0}world.topo.bathy.2004{1:D2}.jpg", m_BmngBaseImageUrl, i+1); //根据http://worldwind25.arc.nasa.gov/tile/tile.aspx构建瓦片式影像的URI地址 WorldWind.NltImageStore imageStore = new WorldWind.NltImageStore(String.Format( " bmng.topo.bathy.2004{0:D2} " , i + 1 ), " http://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 + Bathymetry) Tiled - {0}.2004 " , i + 1 )); ias = new WorldWind.ImageStore[ 1 ]; ias[ 0 ] = imageStore; //构建瓦片式影像 m_QuadTileLayers[ 1 , i] = new WorldWind.Renderable.QuadTileSet( String.Format( " Tiled - {0}.2004 " , i + 1 ), m_WorldWindow.CurrentWorld, 0 , 90 , - 90 , - 180 , 180 , true , ias); m_QuadTileLayers[ 0 , i].ServerLogoFilePath = Path.GetDirectoryName(Application.ExecutablePath) + " \\Data\\Icons\\Interface\\meatball.png " ; m_RenderableLayers[ 1 , i] = new WorldWind.Renderable.RenderableObjectList(String.Format( " {0}.2004 " , i + 1 )); m_RenderableLayers[ 1 , i].IsOn = false ; m_RenderableLayers[ 1 , i].Add(m_ImageLayers[ 1 , i]); m_RenderableLayers[ 1 , i].Add(m_QuadTileLayers[ 1 , i]); m_ShadedBathyList.Add(m_RenderableLayers[ 1 , i]); } m_RenderableList.Add(m_BlueMarbleList); m_RenderableList.Add(m_ShadedList); m_RenderableList.Add(m_ShadedBathyList); // m_RenderableList.Add(m_UnShadedList); this .trackBarMonth.Value = System.DateTime.Now.Month - 1 ; timer = new Timer(); timer.Interval = 1000 ; timer.Tick += new EventHandler(timer_Tick); timer.Start(); }
图3:
原143行 m_ImageLayers[0, i].ImageUrl = String.Format("{0}world.topo.2004{1:D2}.jpg", m_BmngBaseImageUrl, i + 1);从http://worldwind28.arc.nasa.gov/public/上加载图片,构建ImageLayer图层
原183行 String.Format("{0}\\Data\\Earth\\BmngBathy\\world.topo.bathy.2004{1:D2}.jpg", Path.GetDirectoryName(Application.ExecutablePath), i + 1),从文件系统中获取影像图片,构建ImageLayer图层。
另外,构造函数中有个定时器timer,实现每1秒,执行一次timer_Tick(object sender, EventArgs e)。
定时器处理代码 private void timer_Tick( object sender, EventArgs e) { try { // Added TimeKeeper based Modis Month // if (WorldWind.TimeKeeper.CurrentTimeUtc.Month != trackBarMonth.Value) // trackBarMonth.Value = WorldWind.TimeKeeper.CurrentTimeUtc.Month-1; if (m_CurrentMonth != trackBarMonth.Value) { TurnOffLayers(); for ( int i = 0 ; i < 2 ; i ++ ) { m_RenderableLayers[i, trackBarMonth.Value].IsOn = true ; } m_CurrentMonth = trackBarMonth.Value; this .statusBarMonth.Text = GetMonth(trackBarMonth.Value + 1 ) + " - 2004 " ; } if (m_CurrentVersion != comboBoxBmngVersion.SelectedIndex) { m_CurrentVersion = comboBoxBmngVersion.SelectedIndex; if (m_BlueMarbleList.IsOn) m_BlueMarbleList.IsOn = false ; if (m_ShadedList.IsOn) m_ShadedList.IsOn = false ; if (m_ShadedBathyList.IsOn) m_ShadedBathyList.IsOn = false ; if (comboBoxBmngVersion.SelectedIndex == 2 ) // 3) { // show blue marble (original) m_BlueMarbleList.IsOn = true ; this .statusBarMonth.Text = "" ; setMonthLabelsAndSlider( false ); } else { setMonthLabelsAndSlider( true ); switch (comboBoxBmngVersion.SelectedIndex) { case 0 : m_ShadedList.IsOn = true ; break ; case 1 : m_ShadedBathyList.IsOn = true ; break ; // case 2: // m_UnShadedList.IsOn = true; // break; default : break ; } } } } catch { } } }
我个人认为,使用定时器处理,是有些浪费效率,但是主要是为了LayerManager管理里关闭/打开某个图层处理的。如果仅仅为了Blue Marble类型改变球体的底图,完全可以使用Combox的处理事件,就没必要用定时器处理。
BMNGLoader类,按一般插件重载实现Plugin.cs的Load() 、Unload()方法即可。这也是一般套路,无需多说。
BmngLoader代码 public override void Load() { if (ParentApplication.WorldWindow.CurrentWorld.Name.IndexOf( " Earth " ) >= 0 ) { m_MenuItem = new MenuItem( " Blue Marble " ); m_MenuItem.Click += new EventHandler(menuItemClicked); //加到PluginsMenu菜单下 ParentApplication.PluginsMenu.MenuItems.Add(m_MenuItem); m_BmngForm = new BMNG(ParentApplication.WorldWindow, m_MenuItem); m_BmngForm.Owner = ParentApplication; m_ToolbarItem = new WorldWind.WindowsControlMenuButton( " NASA Blue Marble " , Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + " \\Data\\Icons\\Interface\\bmng.png " , m_BmngForm); //加载到WorldWindow.MenuBar菜单里 ParentApplication.WorldWindow.MenuBar.AddToolsMenuButton(m_ToolbarItem); base .Load(); } }
本系列其他部分:
WorldWind学习系列八:Load/Unload Plugins——直捣黄龙篇
WorldWind学习系列七:Load/Unload Plugins——投石问路篇
WorldWind学习系列六:渲染过程解析篇
WorldWind学习系列五:插件加载过程全解析
WorldWind学习系列四:功能分析——Show Planet Axis、Show Position 、Show Cross Hairs功能
WorldWind学习系列三:简单功能分析——主窗体的键盘监听处理及拷贝和粘贴位置坐标功能
WorldWind学习系列三:功能分析——截屏功能和“关于”窗体分析
WorldWind学习系列二:擒贼先擒王篇2
WorldWind学习系列二:擒贼先擒王篇1
WorldWind学习系列一:顺利起航篇
转载于:https://www.cnblogs.com/wuhenke/archive/2009/12/20/1628081.html
相关资源:数据结构—成绩单生成器