zoukankan      html  css  js  c++  java
  • WorldWind源码剖析系列:星球球体的加载与渲染

    WorldWind源码剖析系列:星球球体的加载与渲染

    WorldWind中主函数Main()的分析

    在文件WorldWind.cs中主函数Main()阐明了WorldWind的初始化运行机制(如图1所示 ):

    图1 WorldWind的初始化运行机制

    1.  使用System.Version在内部,读取软件版本信息,并格式化输出。我们在外面配置软件版本,关于部分中版本自动更改。

    获取格式化版本号

        // Establish the version number string used for user display,

        // such as the Splash and Help->About screens.

        // To change the Application.ProductVersion make the

        // changes in WorldWindAssemblyInfo.cs

        // For alpha/beta versions, include " alphaN" or " betaN"

        // at the end of the format string.

     

        Version ver = new System.Version(Application.ProductVersion);

        Release = string.Format("{0}.{1}.{2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision);

    2.判断该软件是否已经有个实例启动,如果有,则不启动。

    判断是否已启动实例

         // If World Wind is already running, pass any commandline

        // arguments from this instance, and quit.

        IntPtr handle = GetWWHandle();  //此处通过获取线程指针

     

        if (!System.IntPtr.Zero.Equals(handle))

        {

         if(args.Length>0)

          NativeMethods.SendArgs( handle, string.Join(" ",args) );

         return;

    }

    3.判断计算机中已经存在的协议数目,并给当前主线程命名。主要是针对.Net FrameWork 1.1版的bug(不允许多于50个协议)。因为该软件要启用自己的新协议"worldwind://"。现在2.0以后不存在该问题啦。

    //abort if 50 bindings problem present and user opts to go to the download page

    if(BindingsCheck.FiftyBindingsWarning())

    return;

    // Name the main thread

    System.Threading.Thread.CurrentThread.Name = "Main Thread";

    4.解析Main(string[] args)中参数args主要是在控制台中启动程序时同时赋予了参数的形式。

       // ParseArgs may set values that are used elsewhere,

        // such as startFullScreen and CurrentSettingsDirectory.

        ParseArgs(args);

          args中参数可能是:

          "worldwind://":加载定位显示球体某处。

          “/f” :全屏启动。

           “/s=……”:指定加载“配置”的文件夹路径。

           这里要注意的是,Main函数一般是没有参数的,如果我们以后要写可以在控制台下给启动程序传入参数,可以借鉴一下。

    5.加载上次使用的配置信息,包括上次使用的WorldWind主窗体使用信息和上次使用的World球体显示信息。

    加载配置

    if(CurrentSettingsDirectory == null)

    {

    // load program settings from default directory

    LoadSettings();

    World.LoadSettings();

    }

    else

    {

    LoadSettings(CurrentSettingsDirectory);

    World.LoadSettings(CurrentSettingsDirectory);

    }

    6.启动主程序,还有对线程异常事件处理和程序空闲处理(防止过度休眠)。

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

     

    MainApplication app = new MainApplication();//该构造函数中完成星球球体的加载与渲染

    Application.Idle += new EventHandler(app.WorldWindow.OnApplicationIdle);

    Application.Run(app);

    7.程序启动后,将状态配置保存起来。

    // Save World settings

          World.Settings.Save();

          其中用到了,将World的配置对象WorldSettings(注意:不是其父类SettingsBase,只是调用其父类的Save方法)序列化为XML文件,并保存,以备下次启动前读取World(即球体)上次状态配置。

    将WorldSettings序列化

            public virtual void Save(string fileName) 

            {

                XmlSerializer ser = null;

     

                try 

                {

                    ser = new XmlSerializer(this.GetType());

                    using(TextWriter tw = new StreamWriter(fileName)) 

                    {

                        ser.Serialize(tw, this);

                    }

                }

                catch(Exception ex) 

                {

                    throw new System.Exception(String.Format("Saving settings class '{0}' to {1} failed", this.GetType().ToString(), fileName), ex);

                }

            }

    8.保存程序整体的该次状态配置。(此处类似7,不详讲,只是这次序列化的对象是WorldWindSettings)。

         // Save program settings

          Settings.Save();

    总结:主函数内容分析学习到此完成。我们之后会针对各功能分别分析,个个突破。

    WorldWindMainApplication类构造函数的分析

    上面提到的第6步中,MainApplication类构造函数真正完成星球球体的加载与渲染。该构造函数依次作以下几个事情:

    1、通过变量Settings.ConfigurationWizardAtStartup来判断是否在程序第一次启动时加载配置助手窗体,该配置助手完成一些一些与欢迎界面Welcome、大气层渲染Atmosphere、缓冲区配置Cache、网络代理Proxy、配置参数最后汇总核查FinalPage等相关信息的配置。

    if(Settings.ConfigurationWizardAtStartup)

    {

        // If the settings file doesn't exist, then we are using the

        // default settings, and the default is to show the Configuration

        // Wizard at startup. We only want that to happen the first time

        // World Wind is started, so change the setting to false(the user

        // can change it to true if they want).

        if(!File.Exists(Settings.FileName))

        {

           Settings.ConfigurationWizardAtStartup = false;

        }

        ConfigurationWizard.Wizard wizard = new ConfigurationWizard.Wizard( Settings );

        wizard.TopMost = true;

        wizard.ShowInTaskbar = true;

        wizard.ShowDialog();

        // TODO: should settings be saved now, in case of program crashes,

        // and so that XML file on disk matches in-memory settings?

    }

    2、加载闪屏

    using( this.splashScreen = new Splash() )

    {

        this.splashScreen.Owner = this;

        this.splashScreen.Show();

        this.splashScreen.SetText("Initializing...");

     

        Application.DoEvents();

        InitializeComponent();

     

        // ParseArgs may have set the "startFullScreen" flag

        if(startFullScreen && !FullScreen)

        {

           FullScreen = true;

        }

    3、设置缓冲区大小和网络下载错误

    // set Upper and Lower limits for Cache size control, in bytes

    long CacheUpperLimit = (long)Settings.CacheSizeMegaBytes * 1024L * 1024L;

    long CacheLowerLimit = (long)Settings.CacheSizeMegaBytes * 768L * 1024L;   //75% of upper limit

    //Set up the cache

    worldWindow.Cache = new Cache(

                Settings.CachePath,

                CacheLowerLimit,

                CacheUpperLimit,

                Settings.CacheCleanupInterval,

                Settings.TotalRunTime );

     

    WorldWind.Net.WebDownload.Log404Errors = World.Settings.Log404Errors;

    4、获取XML配置文件所在的路径,获取该路径下所有星球的XML配置文件,请这些星球的名称作为“File”菜单下的菜单项,以便在各个星球之间切换。并利用这些星球的参数构造每一个星球对象,将其注意加载到哈希表对象availableWorldList中(哈希表对象是在文件WorldWind.cs中定义的,专门用来保存各类星球球体对象,利用哈希表的直接索引定位特性)。

    DirectoryInfo worldsXmlDir = new DirectoryInfo( Settings.ConfigPath );

    if (!worldsXmlDir.Exists)

        throw new ApplicationException(

           string.Format(CultureInfo.CurrentCulture,

           "World Wind configuration directory '{0}' could not be found.", worldsXmlDir.FullName));

     

    FileInfo[] worldXmlDescriptorFiles = worldsXmlDir.GetFiles("*.xml");

    int worldIndex = 0;

    menuItemFile.MenuItems.Add(0, new System.Windows.Forms.MenuItem("-"));

    foreach (FileInfo worldXmlDescriptorFile in worldXmlDescriptorFiles)

    {

        try

        {

            Log.Write(Log.Levels.Debug+1, "CONF", "checking world " + worldXmlDescriptorFile.FullName + " ...");

            World w = WorldWind.ConfigurationLoader.Load(worldXmlDescriptorFile.FullName, worldWindow.Cache);

           if(!availableWorldList.Contains(w.Name))

           this.availableWorldList.Add(w.Name, worldXmlDescriptorFile.FullName);

     

           w.Dispose();

           System.Windows.Forms.MenuItem mi = new System.Windows.Forms.MenuItem(w.Name, new System.EventHandler(OnWorldChange));

           menuItemFile.MenuItems.Add(worldIndex, mi);

           worldIndex++;

        }

        catch( Exception caught )

        {

           splashScreen.SetError( worldXmlDescriptorFile + ": " + caught.Message );

           Log.Write(caught);

        }

    }

     

    Log.Write(Log.Levels.Debug, "CONF", "loading startup world...");

    OpenStartupWorld();

    此步骤中,第一处加红标注的World w = WorldWind.ConfigurationLoader.Load(worldXmlDescriptorFile.FullName, worldWindow.Cache); 代码根据每个星球所对应的保存在XML中的参数逐个构造星球对象。此处将仅仅调用ConfigurationLoader.Load()函数构造好的各个星球对象加入到哈希表对象availableWorldList中,然后调用第二处加红标注的OpenStartupWorld()函数来加载渲染默认启动时的星球。而OpenStartupWorld()则通过调用OpenWorld(curWorldFile)函数,OpenWorld(curWorldFile)函数内部再根据Settings.DefaultWorld(其默认值为“Earth”)参数调用ConfigurationLoader.Load()函数构造、加载和渲染指定的星球,否则加载渲染默认启动时的星球。OpenWorld( curWorldFile )函数还将在点击“File”菜单下的各个星球名称菜单项激活星球之间切换事件时被调用。

    5、设置“View”菜单下的"vertical exaggeration"菜单项的竖直放大倍数子菜单项。如下图所示。

    // Set up vertical exaggeration sub-menu

    float[] verticalExaggerationMultipliers = { 0.0f, 1.0f, 1.5f, 2.0f, 3.0f, 5.0f, 7.0f, 10.0f };

    foreach (float multiplier in verticalExaggerationMultipliers)

    {

        MenuItem curItem = new MenuItem(multiplier.ToString("f1",CultureInfo.CurrentCulture) + "x", new EventHandler(this.menuItemVerticalExaggerationChange));

        curItem.RadioCheck = true;

        this.menuItemVerticalExaggeration.MenuItems.Add(curItem);

        if(Math.Abs(multiplier-World.Settings.VerticalExaggeration)<0.1f)

           curItem.Checked = true;

    }

     

    图2 竖直放大倍数菜单项

       所要加载的星球的XML文件内容如下(以Earth.xml为例):

    <?xml version="1.0" encoding="UTF-8"?>
    <World Name="Earth" EquatorialRadius="6378137.0" LayerDirectory="Earth" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="WorldXmlDescriptor.xsd">
    <TerrainAccessor Name="SRTM">
      <TerrainTileService>
        <ServerUrl>http://worldwind25.arc.nasa.gov/wwelevation/wwelevation.aspx</ServerUrl>
        <DataSetName>srtm30pluszip</DataSetName>
        <LevelZeroTileSizeDegrees>20.0</LevelZeroTileSizeDegrees>
        <NumberLevels>12</NumberLevels>
        <SamplesPerTile>150</SamplesPerTile>
        <DataFormat>Int16</DataFormat>
        <FileExtension>bil</FileExtension>
        <CompressonType>zip</CompressonType>
      </TerrainTileService>
      <LatLonBoundingBox>
        <North>
          <Value>90.0</Value>
        </North>
        <South>
          <Value>-90.0</Value>
        </South>
        <West>
          <Value>-180.0</Value>
        </West>
        <East>
          <Value>180.0</Value>
        </East>
      </LatLonBoundingBox>
    </TerrainAccessor>
    </World>

      本篇博文在本人调试源代码的基础上,梳理了WorldWind主函数的处理和加载流程,在博文成文的过程中较多的参考和借鉴了无痕客的博文《WorldWind学习系列二:擒贼先擒王篇1》和《WorldWind学习系列二:擒贼先擒王篇2》,在此,向无痕客表示感谢。

         其他参考链接:WORLD WIND界面结构探究,WorldWindcs代码分析

  • 相关阅读:
    uva 10099(最大生成树+搜索)
    Codeforces Round #218 (Div. 2) 解题报告
    CodeChef December Challenge 2013 解题报告
    Codeforces Round #217 (Div. 2) 解题报告
    uva 1423 (拓扑排序)
    UESTC 1307 windy数(数位DP)
    Codeforces Round #216 (Div. 2) 解题报告
    Codeforces Round #215 (Div. 2) 解题报告
    uva 10047(BFS)
    uva 10369(最小生成树)
  • 原文地址:https://www.cnblogs.com/rainbow70626/p/4558651.html
Copyright © 2011-2022 走看看