




已阅读5页,还剩15页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
WorldWind系列十二:Measure插件学习(上)来源:博客园 作者:无痕客我在写自己的WorldWind插件时,遇到很大挫折,上周六本来想写个简单的画线的插件,费了九牛二虎之力终于画出了,如何以动画效果画出线的问题没解决。Direct3D中画线本来是个简单的事,画到球面上也不难,但是实践告诉我:我前期学习WW,又犯了眼高手低的毛病!改动人家写好的插件代码容易,但要把插件的整个流程都自己写,就没想象的简单啦,写代码不严谨的小问题就不说了,我周六画线的主要问题是Direct3D编程都浮在表面,连PrimitiveType中各类型的基元数和顶点的关系没搞清楚。(如想了解请参看:/wuhenke/archive/2009/12/27/1633411.html红色部分)自己在画线上体验,让我决定先学习Measure插件。另外,我一直想做个类似VE插件,支持加载ArcGIS切图方式的影像,自己想了很久,有几个主要困惑没解决:投影方式不同如何处理、只要部分影像(如何计算行列数)、切图的中心问题(VE影像是全球的,切图中心经纬度为(0,0)等等。所以,前段WW实践,让我很受打击,博客就没心情更新啦!虽然理论和实践还有很大的距离,但是总结还是很重要的!上面都是题外话了,开始说说Measure插件吧!总体感觉Measure插件很强大,如果能搞清楚,在球面上画点、线、面都不是难事啦。(前提:要有点DirectX编程基础)MeasureTool.cs中有两个大类:MeasureTool(插件类)和MeasureToolLayer(渲染对象类)。MeasureToolLayer类中又包含五个内部类:MeasureLine、MeasureMultiLine 、MeasurePropertiesDialog、 MeasureState 、SaveMultiLine(如下图)MeasureTool作为插件类,需要实现Load() 和Unload()方法,不详说。Load()中注册了一些事件。加载代码publicoverridevoidLoad()/构造渲染对象layer=newMeasureToolLayer(this,ParentApplication.WorldWindow.DrawArgs);/设置纹理路径layer.TexturePath=Path.Combine(PluginDirectory,PluginsMeasure);ParentApplication.WorldWindow.CurrentWorld.RenderableObjects.Add(layer);menuItem=newMenuItem(MeasuretM);menuItem.Click+=newEventHandler(menuItemClicked);ParentApplication.ToolsMenu.MenuItems.Add(menuItem);/Subscribeevents 注册了事件ParentApplication.WorldWindow.MouseMove+=newMouseEventHandler(layer.MouseMove);ParentApplication.WorldWindow.MouseDown+=newMouseEventHandler(layer.MouseDown);ParentApplication.WorldWindow.MouseUp+=newMouseEventHandler(layer.MouseUp);ParentApplication.WorldWindow.KeyUp+=newKeyEventHandler(layer.KeyUp);MeasureToolLayer作为渲染对象类,是WW插件实现的重点。必须重载的方法Initialize()、Update()、Render()和PerformSelectionAction(DrawArgs drawArgs)。我们先分别看看MeasureToolLayer的五个内部类。public enum MeasureStateIdle,Measuring,CompleteMeasureState是个枚举类型,存放Measure的当前状态的(空闲、测量中、完成)。从上图中,我们可看到MeasurePropertiesDialog和 SaveMultiLine类。MeasurePropertiesDialog继承自Form,主要是设置画线的类型:单线、多条线。设置MeasureMode代码privatevoidokButton_Click(objectsender,EventArgse)if(lineModeButton.Checked=true)World.Settings.MeasureMode=MeasureMode.Single;elseWorld.Settings.MeasureMode=MeasureMode.Multi;this.Close();SaveMultiLine类基础自Form。主要实现将画出的多线,保存为KML或Shp格式。保存代码privatevoidsaveButton_Click(objectsender,System.EventArgse)/Heh.SaveFileDialogchooser=newSaveFileDialog();chooser.DefaultExt=*.csv;chooser.Filter=kmlfiles(*.kml)|*.kml|Shapefiles(*.shp)|*.shp;chooser.Title=SaveMultiline;chooser.ShowDialog(MainApplication.ActiveForm);Stringfilename=chooser.FileName;Console.WriteLine(filename);tryif(filename.EndsWith(.kml)StreamWriterwriter=newStreamWriter(filename);stringkml=writeKML();writer.WriteLine(kml);writer.Close();/needtobeabletosavetoanetworkashapefileaccessibleif(filename.EndsWith(.shp)writeShape(filename);catch(Exceptionex)MessageBox.Show(ex.Message);输出KML文件代码;KML代码privatestringwriteKML()/constructXMLtosendXmlDocumentdoc=newXmlDocument();XmlNodekmlnode=doc.CreateElement(kml);XmlNodenode=doc.CreateElement(Placemark);XmlNodename=doc.CreateElement(name);name.InnerText=NewMeasurement;node.AppendChild(name);XmlNodedesc=doc.CreateElement(description);stringdescription=NewMeasurement;desc.InnerXml=description;node.AppendChild(desc);XmlNodepolygon=doc.CreateElement(Polygon);stringrequest=;foreach(MeasureLinelineinm_multiline)Doublelat=line.StartLatitude.Degrees;Doublelon=line.StartLongitude.Degrees;request+=lon+,+lat+,100n;request+=;polygon.InnerXml=request;node.AppendChild(polygon);kmlnode.AppendChild(node);doc.AppendChild(kmlnode);returndoc.OuterXml;保存为SHP格式文件代码保存为Shap代码privatevoidwriteShape(stringfilename)IntPtrshphandle=ShapeLib.SHPCreate(filename,ShapeLib.ShapeType.PolyLine);doublelat=newdoublem_multiline.Count;doublelon=newdoublem_multiline.Count;inti=0;foreach(MeasureLinelineinm_multiline)lati=line.StartLatitude.Degrees;loni=line.StartLongitude.Degrees;i+;ShapeLib.SHPObjectpoly=ShapeLib.SHPCreateSimpleObject(ShapeLib.ShapeType.Polygon,m_multiline.Count,lon,lat,null);ShapeLib.SHPWriteObject(shphandle,0,poly);ShapeLib.SHPDestroyObject(poly);ShapeLib.SHPClose(shphandle);上面是右键菜单的两个功能,如果实现添加右键菜单呢?很简单,MeasureToolLayer类只要重载RenderObject类的BuildContextMenu(ContextMenu menu)方法。示例代码如下:添加右键菜单代码/Fillsthecontextmenuwithmenuitemsspecifictothelayer./publicoverridevoidBuildContextMenu(ContextMenumenu)menu.MenuItems.Add(Properties,newSystem.EventHandler(OnPropertiesClick);menu.MenuItems.Add(SaveMulti-PointLine,newSystem.EventHandler(saveLine);OnPropertiesClick和saveLine就是用来调用两个窗体类的。MeasureMultiLine继承自ArrayList,主要是存放MeasureLine的集合。internalclassMeasureMultiLine:ArrayList/添加线publicvoidaddLine(MeasureLineline)Add(line);/删除最后一条线publicvoiddeleteLine()RemoveAt(Count-1);/计算集合中线的总长度,我们关注如何计算单条线的长度。publicdoublegetLength()doublesum=0.0;foreach(MeasureLinelineinthis)sum+=line.Linear;returnsum;/线集合的渲染方法。publicvoidRender(DrawArgsdrawArgs)foreach(MeasureLinelineinthis)try/调用线的渲染方法line.Render(drawArgs);catchMeasureLine继承自ListViewItem,是该Measure插件的关键部分,主要是对线对象的计算和部分渲染。这里面知识点比较重要,很多可以被我们借鉴重用。其中用到的重要方法Calculate() 和Render(),还有一些没用到的方法(这里暂不分析)。publicvoidCalculate(Worldworld,booluseTerrain)/计算球面上两点间圆弧(对应的角度)AngleangularDistance=World.ApproxAngularDistance(startLatitude,startLongitude,endLatitude,endLongitude);/计算圆弧长度=弧度值*半径Linear=angularDistance.Radians*world.EquatorialRadius;/每两度一个点(下面计算不是好理解,但是我们可以借鉴的重点)/ 2的弧度为 (2*PI/180)即约等于 2*3/180=1/30;(作者将PI取整为3啦)/每两度一个点:samples=(int)(angularDistance.Radians/2度的弧度值);/即samples=(int)(angularDistance.Radians/(1/30);intsamples=(int)(angularDistance.Radians*30);/1pointforevery2degrees.if(samples2)samples=2;/构建点集合(线中取samples个点)LinearTrackLine=newCustomVertex.PositionColoredsamples;for(inti=0;iLinearTrackLine.Length;i+)LinearTrackLinei.Color=World.Settings.MeasureLineLinearColorXml;Anglelat,lon=Angle.Zero;for(inti=0;i0)label+=FormatDistance(groundTrack)+Units;elselabel+=FormatDistance(linearDistance)+Units;/在线的中点处画出线段长度(DrawText将文字渲染到球面上某点)drawArgs.defaultDrawingFont.DrawText(null,label,(int)labelXy.X,(int)labelXy.Y,World.Settings.MeasureLineLinearColor);上面代码画出的线和长度,在任何缩放级别下都是可见的,不是太好。下面是我借鉴VE插件代码,实现了缩放级别控制,在一定级别下才显示线的长度。/判断缩放级别publicintGetZoomLevelByTrueViewRange(doubletrueViewRange)intmaxLevel=3;/视角范围为45度intminLevel=19;intnumLevels=minLevel-maxLevel+1;intretLevel=maxLevel;for(inti=0;inumLevels;i+)retLevel=i+maxLevel;doubleviewAngle=180;for(intj=0;j=viewAngle)break;returnretLevel;然后,在上面的Render()里添加控制条件 if (GetZoomLevelByTrueViewRange(drawArgs.WorldCamera.TrueViewRange.Degrees) 4) ,来控制长度的显示。添加层次控制publicvoidRender(DrawArgsdrawArgs)/Drawthemeasureline+endsVector3referenceCenter=newVector3(float)drawArgs.WorldCamera.ReferenceCenter.X,(float)drawArgs.WorldCamera.ReferenceCenter.Y,(float)drawArgs.WorldCamera.ReferenceCenter.Z);drawArgs.device.Transform.World=Matrix.Translation(-referenceCenter);if(World.Settings.MeasureShowGroundTrack&IsGroundTrackValid)drawArgs.device.DrawUserPrimitives(PrimitiveType.LineStrip,GroundTrackLine.Length-1,GroundTrackLine);drawArgs.device.DrawUserPrimitives(PrimitiveType.LineStrip,LinearTrackLine.Length-1,LinearTrackLine);drawArgs.device.Transform.World=drawArgs.WorldCamera.WorldMatrix;if(GetZoomLevelByTrueViewRange(drawArgs.WorldCamera.TrueViewRange.Degrees)4)if(!drawArgs.WorldCamera.ViewFrustum.ContainsPoint(WorldXyzMid)/Labelisinvisiblereturn;Vector3labelXy=drawArgs.WorldCamera.Project(WorldXyzMid-referenceCenter);stringlabel=;/=Text;if(groundTrack0)label+=FormatDistance(groundTrack)+Units;elselabel+=FormatDistance(linearDistance)+Units;drawArgs.defaultDrawingFont.DrawText(null,label,(int)labelXy.X,(int)labelXy.Y,World.Settings.MeasureLineLinearColor);下面我们看一下MeasureToolLayer类。代码publicoverridevoidRender(DrawArgsdrawArgs)if(!isOn)return;/Turnofflightif(World.Settings.EnableSunShading)drawArgs.device.RenderState.Lighting=false;/Checkthattexturesareinitialisedif(!isInitialized)Initialize(drawArgs);if(DrawArgs.MouseCursor=CursorType.Arrow)/Useourcursorwhenthemouseisntoverotherelementsrequiringdifferentcursor/使用自己的鼠标类型(可以借鉴学习)DrawArgs.MouseCursor=CursorType.Measure;if(State=MeasureState.Idle)return;/稍后分析if(!CalculateRectPlacement(drawArgs)return;if(Distance1,endPoint);*/绘制线集合multiline.Render(drawArgs);/Drawtheinforect /赋予纹理device.TextureState0.ColorOperation=TextureOperation.SelectArg1;device.SetTexture(0,m_texture);device.VertexFormat=CustomVertex.TransformedColoredTextured.Format;/绘制矩形(由两个三角形构成)device.DrawUserPrimitives(PrimitiveType.TriangleStrip,2,rect);device.TextureState0.ColorOperation=TextureOperation.Disable;/绘制连接线(三个点)device.DrawUserPrimitives(PrimitiveType.LineStrip,2,rectLineConnection);/绘制矩形边框device.DrawUserPrimitives(PrimitiveType.LineStrip,rectFrame.Length-1,rectFrame);/渲染绘制矩形上的文字drawArgs.defaultDrawingFont.DrawText(null,labelText,labelTextRect,DrawTextFormat.None,0xff24);device.RenderState.ZBufferEnable=true;if(World.Settings.EnableSunShading)drawArgs.device.RenderState.Lighting=true;光标问题DrawArgs.cs中CursorType中所有光标类型。/ / Mouse cursor/ public enum CursorTypeArrow = 0,Hand,Cross,Measure,SizeWE,SizeNS,SizeNESW,SizeNWSE更新光标方法340行更新光标代码publicvoidUpdateMouseCursor(System.Windows.Forms.Controlparent)if(lastCursor=mouseCursor)return;switch(mouseCursor)caseCursorType.Hand:parent.Cursor=System.Windows.Forms.Cursors.Hand;break;caseCursorType.Cross:parent.Cursor=System.Windows.Forms.Cursors.Cross;break;caseCursorType.Measure:if(measureCursor=null)/从外界加载光标measureCursor=ImageHelper.LoadCursor(measure.cur);parent.Cursor=measureCursor;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 个人租赁房屋合同正式样本5篇
- 2025年城市供水特许经营合同风险评估协议
- 2025贵州省卫生中心第十三届贵州人才博览会引才考前自测高频考点模拟试题及答案详解(名师系列)
- 2025内蒙古呼和浩特市金信金融纠纷调解中心招聘5人考前自测高频考点模拟试题及一套完整答案详解
- 2025河南开封市杞县消防救援大队政府专职消防员招聘10人模拟试卷及答案详解(历年真题)
- 2025河北保定市定兴县国有公司领导人员招聘2人考前自测高频考点模拟试题及答案详解(考点梳理)
- 2025年芜湖经济技术开发区招聘公办幼儿园教职工26人考前自测高频考点模拟试题及答案详解(全优)
- 2025湖北天门市顺达劳务有限公司招聘劳务派遣制药剂科调剂药师1人考前自测高频考点模拟试题完整参考答案详解
- 2025昆明市盘龙区人民医院第二季度招聘编外人员(1人)考前自测高频考点模拟试题参考答案详解
- 2025年中国电信卫星公司专业岗位员工招聘12人笔试题库历年考点版附带答案详解
- 2025年法院书记员招聘考试笔试试题含答案
- 重阳节活动致辞
- 地下室结构施工课件
- 2025至2030中国氢燃料电池堆行业项目调研及市场前景预测评估报告
- 牙齿矫正方式对比
- 3.2 中国的矿产资源教学课件 初中地理湘教版(2024)八年级上册
- 学堂在线 高技术与现代局部战争 章节测试答案
- 无人机公司飞手管理制度
- 房地产抵押贷款合同电子版预览
- 公路机电安全培训课件
- DB42-T 2389-2025 陶粒沥青混凝土路面施工技术规程
评论
0/150
提交评论