WorldWind源码剖析系列:窗口定制控件类WorldWindow
在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的更多相关文章
- WorldWind源码剖析系列:星球表面渲染类WorldSurfaceRenderer
星球表面渲染类WorldSurfaceRenderer描述如何渲染星球类(如地球)表面影像纹理.该类的类图如下. 星球类World包含的主要的字段.属性和方法如下: public const int ...
- WorldWind源码剖析系列:插件列表视图类PluginListView和插件列表视图项类PluginListItem
WorldWind中的插件类是个庞大的类,可以说从软件设计层面上统筹可扩展的插件体系的设计思想是WorldWind中的精华,值得学习和借鉴.插件体系中的所用到的类可以分为两大类,一类是插件类Plugi ...
- WorldWind源码剖析系列:经纬度格网类LatLongGrid
经纬度格网类LatLongGrid继承自可渲染对象类RenderableObject,是WorldWind中用来在星球外表绘制经纬度格网的封装类.其类图如下所示. 绘制经纬网格的主体函数为Render ...
- WorldWind源码剖析系列:可渲染对象类RenderableObject
RenderableObject是WorldWind中所有需要渲染的对象的父类,继承了接口IRenderable和Icomparable.其派生类体系如下所示.RenderableObject的成员如 ...
- WorldWind源码剖析系列:视景体类Frustum
PluginSDK中的视景体类Frustum是三维计算机图形学中的概念,主要用来描述透视投影的过程.三维计算机图形学中关于三维物体的渲染,Direct3D和OpenGL都是先通过对现实世界中的场景先进 ...
- WorldWind源码剖析系列:配置载入器类ConfigurationLoader
配置载入器类ConfigurationLoader主要从指定的路径中加载保存星球相关参数的xml文件,从中读取数据来构造星球对象及其所关联的可渲染子对象列表并返回.该类的类图如下所示. 该类所包含的主 ...
- WorldWind源码剖析系列:地形访问器类TerrainAccessor
地形访问器类TerrainAccessor 地形访问器类TerrainAccessor提供了对地形(高程)Terrain (elevation)访问的各种接口interface,是NltTerrain ...
- WorldWind源码剖析系列:二维点类Point2d和三维点类Point3d
PluginSDK中的点主要有二维和三维两种类型,分别用来描述平面和立体点.其类图如下. 这两个类比较简单.其字段成员主要用来描述点对象在各坐标轴上的分量. 属性Length用来返回二维和三维点的距离 ...
- WorldWind源码剖析系列:星球类World
星球类World代表通用的星球类,因为可能需要绘制除地球之外的其它星球,如月球.火星等.该类的类图如下. 需要说明的是,在WorldWind中星球球体的渲染和经纬网格的渲染时分别绘制的.经纬网格的渲染 ...
随机推荐
- Another kind of Fibonacci(矩阵)
Another kind of Fibonacci Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- Alice and Bob(博弈)
Alice and Bob Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:65536KB Total submit users ...
- vue2.0 移动端,下拉刷新,上拉加载更多 插件
本人正在基于 vue2.0 + webpack + es6 搭建前端架构,整理了部分插件,下面这个是下拉更新 上拉更多的,挺好用的,分享给大家. 直接上代码,不懂的多看几遍,下面我换会告诉大家如何使用 ...
- js-权威指南学习笔记21
第二十一章 多媒体和图形编程 1.为了强制让图片缓存起来,首先利用Image()构造函数来创建一个屏幕外的图片对象,之后将该对象的src属性设置成期望的URL. 2.由于各家浏览器制造商未能在对标准音 ...
- WebSerivce与WebAPI的区别
一.什么是Web Service Web Service技术, 能使得运行在不同机器上的不同应用无须借助附加的.专门的第三方软件或硬件, 就可相互交换数据或集成.依据Web Service规范实施的应 ...
- Nginx的站点目录及文件URL的访问控制
1.根据扩展名限制程序和文件访问: web2.0时代,绝大多数网站都是以用户为中心的,这些产品有一些共同点,就是不允许用户发布内容到服务器,还允许用户发图片甚至附件上传到服务器上,给用户开启了上传的功 ...
- CentOS配置yum源(补充)
这是对yum命令的补充 Yum命令 一.用Centos镜像搭建本地yum源 由于安装centos后的默认yum源为centos的官方地址,所以在国内使用很慢甚至无法访问,所以一般的做法都是把默认的yu ...
- springboot 学习之路 14(整合mongodb的Api操作)
springboot整合mongodb: mongodb的安装和权限配置 请点击连接参考 mongodb集成 : 第一步:引如pom文件 第二步:配置文件配置mongodb路径: 第三步:关于mon ...
- CSS 小结笔记之伸缩布局 (flex)
CSS flex 是一种伸缩布局,之前块级元素布局在同一行,可以通过display或position或float来实现,而本篇介绍一个新的方法——flex(弹性布局). flex 为和模型布局提供了极 ...
- CSS实现DIV从隐藏到展示的过渡效果
CSS中有很多功能强大的方法,其中过渡属性transition就很牛叉.你不用写一行JavaScript代码,随便写点css就可以实现一个动画效果.下面结合我在W3C网站上看到的实例,举个栗子说明下( ...