在WorldWindow定制控件是从Control类派生出来的,需要自己操纵GDI+绘制所需要的界面效果,这种自定义控件比较耗费精力,需要比较深厚的GDI+和DirectX 3D开发功底。(区别于用户控件UserControl,也叫组合控件,大多是对.NET工具箱提供的默认基础控件进行的组合和轻量级的改变,实现起来比较简单)。为了明确定制控件Control和用户控件UserControl之间的体系关系,此处给出了Control类继承层次结构(源自MSDN)以及WorldWindow类的类图:在WorldWindow中成员较多,此处仅就比较重要的成员作详细分析:

     

  需要特别说明的是:在WorldWindow中星球球体的渲染和经纬网格的渲染时分别绘制的,星球由类World表示,经纬网格由类LatLongGrid表示。

WorldWindow定制控件的主要字段、方法和属性有:

private Device m_Device3d;//定制窗口绑定的绘制设备

private PresentParameters m_presentParams;//Direct3D绘制呈现参数

private DrawArgs drawArgs; //绘制参数

private World m_World; //定制窗口中需要绘制的星球

private Cache m_Cache;// //定制窗口中需要绘制的星球的缓冲区

private Thread m_WorkerThread;//后台工作线程

private bool showDiagnosticInfo; //是否显示诊断信息

private string _caption = "";//标题

private long lastFpsUpdateTime; //最后一次Fps的更新时间

private int frameCounter; //帧数

private float fps;//每秒渲染的帧速率

private string saveScreenShotFilePath; //保存截屏文件路径

private ImageFileFormat saveScreenShotImageFileFormat = ImageFileFormat.Bmp; //保存截屏文件格式

private bool m_WorkerThreadRunning;//判断工作线程是否正在运行

private LayerManagerButton layerManagerButton; //图层管理器按钮

private MenuBar _menuBar = new MenuBar(MenuAnchor.Top, 90);

private bool m_isRenderDisabled; // True when WW isn't active - CPU saver

private bool isMouseDragging; //是否正在用鼠标拖拽场景

private Point mouseDownStartPosition = Point.Empty; //鼠标按下时的起始位置

private bool renderWireFrame; //是否以线框模式渲染

private System.Timers.Timer m_FpsTimer = new System.Timers.Timer(250);

public void Goto( WorldWind.Net.WorldWindUri uri )转到URI连接。

public void GotoLatLon(double latitude, double longitude, double heading, double altitude, double perpendicularViewRange, double tilt)移动到指定的经纬度位置,内部实际是通过调用this.drawArgs.WorldCamera.SetPosition(latitude, longitude, heading, altitude, tilt);函数实现具体功能。

public void SaveScreenshot(string filePath)对当前场景截屏保存为图片文件。

public void OnApplicationIdle(object sender, EventArgs e)星球的消息循环,在WorldWind.cs文件的主函数static void Main(string[] args)中被调用。其内部调用了WorldWindow类的Render()函数。

private static bool IsAppStillIdle判断程序是否空闲,如果控件返回真。

protected override void OnPaint(PaintEventArgs e),任何继承自Control类的定制控件均需要重载Control类的函数,当窗口需要重新绘制时被调用。

private Device m_Device3d;//绘制场景所需要的DirectX 3D设备对象

private DrawArgs drawArgs;//场景绘制时指定的绘制参数

private World m_World;// WorldWindow定制控件中表示星球球体的对象。星球球体的渲染和经纬网格的渲染时分别绘制的,星球由类World表示,经纬网格由类LatLongGrid表示

private Cache m_Cache;//用于缓存高程数据和纹理数据的本地缓存对象

private Thread m_WorkerThread; //后台工作线程,使用多线程的方式实现高程数据和纹理数据的远程下载,并及时更新应用程序的图形界面(GUI)

public World CurrentWorld;//公开的属性CurrentWorld的Set属性除了完成将星球对象的引用保存在m_World成员中外,还实例化了运动相机MomentumCamera和星球球体的经纬网格LatLongGrid,并且将经纬网格对象添加到星球对象的可渲染对象列表中

public void Render();//该方法首先判断星球对象m_World是否为空、后台工作线程WorkerThread是否为空,并依次作相应的处理;其次,在开始绘制之前调用绘制参数对象drawArgs的相机对象WorldCamera所保留的Update ()方法this.drawArgs.WorldCamera.Update(m_Device3d)更新DirectX 3D设备对象m_Device3d,然后开启绘制标识,设置绘制模式、调用星球对象m_World的渲染函数m_World.Render(this.drawArgs)完成星球主体的渲染、绘制十字光标his.DrawCrossHairs();、统计绘制帧速率、渲染各个自定义的窗体挂件m_RootWidget.Render(drawArgs)和m_NewRootWidget.Render(drawArgs)、实时响应用户的截屏操作SaveScreenShot()、在渲染窗口的右上角绘制位置信息RenderPositionInfo()、完成菜单条的渲染_menuBar.Render(drawArgs)、线型图形的渲染m_FpsGraph.Render(drawArgs)、输出星球对象m_World的屏幕消息字符串

重载鼠标滑轮滚动消息protected override void OnMouseWheel(MouseEventArgs e)

重载键盘按键按下消息protected override void OnKeyDown(KeyEventArgs e)

重载键盘按键弹起消息protected override void OnKeyUp(KeyEventArgs e)

重载键盘按键消息protected override void OnKeyPress(KeyPressEventArgs e)

重载预处理消息方法,在消息循环过程中在消息被丢弃之前事先处理键盘和输入信息public override bool PreProcessMessage(ref Message msg)

紧接着,定义两个比较重要的方法体public bool HandleKeyDown(KeyEventArgs e)和public bool HandleKeyUp(KeyEventArgs e)分别用来处理按键按下和弹起时的消息,其中按键按下的处理方法HandleKeyDown里面基本上包含了WorldWind的全部按键操作控制实现代码

重载了鼠标按下、弹起、双击、移动和离开等五个消息的处理方法:

protected override void OnMouseDown(MouseEventArgs e)

protected override void OnMouseDoubleClick(MouseEventArgs e)

protected override void OnMouseUp(MouseEventArgs e)

protected override void OnMouseMove(MouseEventArgs e)

protected override void OnMouseLeave(EventArgs e)

其中,鼠标按下的消息处理方法中,先记录下当前按下鼠标的位置,然后先让各个自定义的窗体挂件m_RootWidget.OnMouseDown(e)和m_NewRootWidget.OnMouseDown(e)处理,再让菜单条this._menuBar.OnMouseDown(e)作出处理,以便对用户的操作作出实时响应,最后标识用户是左键按下还是右键按下。

鼠标按下的消息处理方法比较重要,里面除了实现先让自定义的窗体挂件和菜单条处理鼠标按下的消息外,还实简单地现了通过光线追踪(Ray Tracing)技术进行拾取检测等操作

this.drawArgs.WorldCamera.PickingRayIntersection(DrawArgs.LastMousePosition.X,DrawArgs.LastMousePosition.Y,out targetLatitude,out targetLongitude),最后在调用方法his.drawArgs.WorldCamera.PointGoto(targetLatitude, targetLongitude)使星球飞行到用户通过右键单击所想要去的地方去漫游(左键双击表示放大,右键双击表示放大)。

接下来的定义了方法private void InitializeGraphics()和private void OnDeviceReset(object sender, EventArgs e),分别初始化使用DirectX 3D用来渲染图形时的设备状态和当DirectX 3D设备对象m_Device3d需要重置时调用的方法,用户切换渲染窗口和调整渲染窗口都会使设备对象失效,当再次使用时需要重置。不熟悉这一部分内容的读者可以查阅DirectX 3D三维图形绘制的基础知识,此处不再赘述。

最后一个重要的方法是private void WorkerThreadFunc(),即前面提到的后台工作线程的绑定方法体。其内部调用了查询性能计数器方法和星球对象的更新函数:

PerformanceTimer.QueryPerformanceCounter(ref startTicks);

m_World.Update(this.drawArgs);

其中,后者使用多线程的方式实现高程数据和纹理数据的本地调用或远程下载,完成用户所请求的区域的地形数据的绘制和纹理映射,并及时更新应用程序的图形界面(GUI)。详细过程请参照m_World.Update(this.drawArgs)内部实现。

WorldWind源码剖析系列:窗口定制控件类WorldWindow的更多相关文章

  1. WorldWind源码剖析系列:星球表面渲染类WorldSurfaceRenderer

    星球表面渲染类WorldSurfaceRenderer描述如何渲染星球类(如地球)表面影像纹理.该类的类图如下. 星球类World包含的主要的字段.属性和方法如下: public const int ...

  2. WorldWind源码剖析系列:插件列表视图类PluginListView和插件列表视图项类PluginListItem

    WorldWind中的插件类是个庞大的类,可以说从软件设计层面上统筹可扩展的插件体系的设计思想是WorldWind中的精华,值得学习和借鉴.插件体系中的所用到的类可以分为两大类,一类是插件类Plugi ...

  3. WorldWind源码剖析系列:经纬度格网类LatLongGrid

    经纬度格网类LatLongGrid继承自可渲染对象类RenderableObject,是WorldWind中用来在星球外表绘制经纬度格网的封装类.其类图如下所示. 绘制经纬网格的主体函数为Render ...

  4. WorldWind源码剖析系列:可渲染对象类RenderableObject

    RenderableObject是WorldWind中所有需要渲染的对象的父类,继承了接口IRenderable和Icomparable.其派生类体系如下所示.RenderableObject的成员如 ...

  5. WorldWind源码剖析系列:视景体类Frustum

    PluginSDK中的视景体类Frustum是三维计算机图形学中的概念,主要用来描述透视投影的过程.三维计算机图形学中关于三维物体的渲染,Direct3D和OpenGL都是先通过对现实世界中的场景先进 ...

  6. WorldWind源码剖析系列:配置载入器类ConfigurationLoader

    配置载入器类ConfigurationLoader主要从指定的路径中加载保存星球相关参数的xml文件,从中读取数据来构造星球对象及其所关联的可渲染子对象列表并返回.该类的类图如下所示. 该类所包含的主 ...

  7. WorldWind源码剖析系列:地形访问器类TerrainAccessor

    地形访问器类TerrainAccessor 地形访问器类TerrainAccessor提供了对地形(高程)Terrain (elevation)访问的各种接口interface,是NltTerrain ...

  8. WorldWind源码剖析系列:二维点类Point2d和三维点类Point3d

    PluginSDK中的点主要有二维和三维两种类型,分别用来描述平面和立体点.其类图如下. 这两个类比较简单.其字段成员主要用来描述点对象在各坐标轴上的分量. 属性Length用来返回二维和三维点的距离 ...

  9. WorldWind源码剖析系列:星球类World

    星球类World代表通用的星球类,因为可能需要绘制除地球之外的其它星球,如月球.火星等.该类的类图如下. 需要说明的是,在WorldWind中星球球体的渲染和经纬网格的渲染时分别绘制的.经纬网格的渲染 ...

随机推荐

  1. Java虚拟机 - Class类文件结构

    [深入Java虚拟机]之二:Class类文件结构 平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现.不仅使用Jav ...

  2. 脚本执行错误---/bin/sh^M:损坏的解释器 没有那个文件或目录

    在执行脚本时,弹出错误提示: 这是由于脚本文件在保存时使用了DOS文件格式造成的,可以用vim打开文件,然后执行下列操作:

  3. call,apply,bind

    var student={ name:"马云", say:function(){ console.log(this.name); } } var f=student.say; f. ...

  4. 【 js 基础 】【读书笔记】Javascript “继承”

    是时候写一写 “继承”了,为什么加引号,因为当你阅读完这篇文章,你会知道,说是 继承 其实是不准确的. 一.类1.传统的面向类的语言中的类:类/继承 描述了一种代码的组织结构形式.举个例子:“汽车”可 ...

  5. css3之transform属性实现div不定宽高垂直水平居中

    transform的作用 transform 属性向元素应用 2D 或 3D 转换.该属性允许我们对元素进行旋转.缩放.移动或倾斜.(w3cschool) transform的兼容性 transfor ...

  6. art-template辅助函数和子模板

    art-template 前端使用 用途:主要用来处理数据和优化性能,与其他的一些模块化处理数据的插件相比,art-template处理性能好 不废话,上代码 1.art-template基本语法使用 ...

  7. Dynamics 365Online 通过插件中的retrievemultiple消息来过滤产品视图

    本篇中要讲的是对产品视图基于某个条件进行过滤显示,而手段就是通过插件中的retrievemultiple消息,可能很多人都写过对它都不陌生. 先来看张插件注册的截图,插件的message是retrie ...

  8. ie8 透明背景不能点击问题

    最近开发网站,需求是三个一屏,1和3只能看见一半,2显示在中间,无箭头按钮. 因为之前写过一个有前后按钮的插件,想着怎么就在这上面改造,故把前后按钮去掉背景,定位在了1和3的位置上来实现点击前后, 发 ...

  9. 2016年,谁是最受欢迎的 Java EE 服务器?

    [编者按]本文作者为性能监控工具 Plumbr 创始人 Nikita Salnikov-tarnovski,主要介绍2016年度最广为使用的 Java EE 容器及其排名变化情况.本文系国内 ITOM ...

  10. python之绘制图形库turtle

    关于绘制图形库turtle# 画布上,默认有一个坐标原点为画布中心的坐标轴(0,0),默认"standard"模式坐标原点上有一只面朝x轴正方向小乌龟 一:海龟箭头Turtle相关 ...