PIE SDK 使用心得 -- 四个TIPS
从去年接触PIE SDK二次开发,至今已有两年。回顾过去的点点滴滴,印象最深的是航天宏图的技术大牛们细致入微的问题答疑和线上培训。在可以想象的未来,非常期待航天宏图的软件产品。国产软件的崛起,也必然有她的一席之地。言归正传,下面介绍一下我使用PIE SDK做二次开发的经验、心得和技巧。
TIP 1:没有制图控件(PageLayoutControl),如何保存地图文档(PmdContents)。
参考代码:PIE SDK专题制图保存模板(https://www.cnblogs.com/PIESat/p/10175673.html)。这个博客里专门写的是关于制图时保存模板的操作,它使用的是制图控件作为桥梁去保存模板。但是,有时候我们可能不需要制图控件,这个时候该怎么办呢?是有办法的,我们只需要将制图控件改为地图控件即可,示例代码如下。
1 private void buttonItem_SaveProject_Click(object sender, EventArgs e) 2 { 3 //获取当前地图文档 4 IMapDocument mapDocument = (mapControlMain as Control).Tag as IMapDocument; //PIE DesktopCommand中可用m_Application.MapDocument来获取 5 if (mapDocument == null) 6 { 7 mapDocument = new MapDocument(); 8 mapDocument.ReplaceContents(mapControlMain); 9 } 10 11 //保存文档 12 string pmdFilePath = mapDocument.GetDocumentFilename(); 13 if (string.IsNullOrEmpty(pmdFilePath)) 14 { 15 SaveFileDialog saveFileDialog = new SaveFileDialog(); 16 saveFileDialog.Title = "地图文档保存为:"; 17 saveFileDialog.Filter = "PMD|*.pmd"; 18 if (saveFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; 19 pmdFilePath = saveFileDialog.FileName; 20 if (string.IsNullOrEmpty(pmdFilePath)) return; 21 22 if (!pmdFilePath.EndsWith(".pmd")) 23 { 24 pmdFilePath = pmdFilePath + ".pmd"; 25 } 26 } 27 mapDocument.SaveAs(pmdFilePath, false, false); 28 29 MessageBox.Show(DateTime.Now + " : 工程保存成功!\n", m_AppTitle, MessageBoxButtons.OKCancel, MessageBoxIcon.Information); 30 }
TIP 2:循环中注意内存释放,以矢量feature遍历为例。
在矢量feature遍历的过程中,循环代码中注意添加(featureCursor as IDisposable).Dispose()和featureCursor = null这两句代码,否则的话会导致意想不到的bug。我写的代码里就出现这样一个问题:没有释放内存,程序总是会卡在某个feature上,不再执行后续代码,示例代码如下。
1 private void buttonItem_CreateBatchSampleOfShp_Click(object sender, EventArgs e) 2 { 3 Test_AutoCreateBatchImageSampleParasOfShape dlgTest_AutoCreateImageSampleParas = new Test_AutoCreateBatchImageSampleParasOfShape(); 4 if (dlgTest_AutoCreateImageSampleParas.ShowDialog() != DialogResult.OK) return; 5 string strAppDirectory = System.AppDomain.CurrentDomain.BaseDirectory; 6 string strBaseImageFile = dlgTest_AutoCreateImageSampleParas.textBox_InputBaseImageFile.Text; 7 string strBaseVectorFile = dlgTest_AutoCreateImageSampleParas.textBox_InputBaseVectorFile.Text; 8 string strBaseBoundaryFile = dlgTest_AutoCreateImageSampleParas.textBox_InpurtBaseBoundaryFile.Text; 9 string strOutputDir = dlgTest_AutoCreateImageSampleParas.textBox_OutputDir.Text; 10 //存储单个boundary范围 11 IField field1 = new Field("Class", FieldType.OFTInteger, 8, 1); 12 field1.Name = "Class"; 13 field1.AliasName = "标签"; 14 IFields fieldsSave = new Fields(); 15 fieldsSave.AddField(field1); 16 ILayer layerLabel = PIE.Carto.LayerFactory.CreateDefaultLayer(strBaseVectorFile); 17 IFeatureLayer labelFeatureLayer = (layerLabel as IFeatureLayer); 18 ILayer layerBoundary = PIE.Carto.LayerFactory.CreateDefaultLayer(strBaseBoundaryFile); 19 IFeatureClass boundaryFeatures = (layerBoundary as IFeatureLayer).FeatureClass; 20 IFields fields = boundaryFeatures.GetFields(); 21 int fieldIndex = fields.GetFieldIndex("Name"); 22 IField field = fields.GetField(fieldIndex); 23 IEnvelope envelop = new Envelope(); 24 //IPointCollection polygon = new Polygon(); 25 for (int i = 0; i < boundaryFeatures.GetFeatureCount(); i++) 26 { 27 IFeature feature = boundaryFeatures.GetFeature(i); 28 string strBoundaryFile = strTempSample + feature.GetValue(field.Name) + "_boundary.shp"; 29 IFeatureDataset boundaryFeatureDataset = DatasetFactory.CreateFeatureDataset(strBoundaryFile, fieldsSave, GeometryType.GeometryEnvelope, layerLabel.SpatialReference, "SHP"); 30 IFeature boundaryFeature = boundaryFeatureDataset.CreateNewFeature(); 31 boundaryFeature.Geometry = feature.Geometry; 32 boundaryFeature.Geometry.SpatialReference = layerLabel.SpatialReference; 33 boundaryFeature.FID = 0; 34 boundaryFeature.SetValue(0, 0);//Class 35 boundaryFeatureDataset.AddFeature(boundaryFeature); 36 boundaryFeatureDataset.Save(); 37 (boundaryFeature as IDisposable).Dispose(); 38 boundaryFeature = null; 39 (boundaryFeatureDataset as IDisposable).Dispose(); 40 boundaryFeatureDataset = null; 41 IQueryFilter queryFilter = new QueryFilter(); 42 queryFilter.SetSpatialQuery(feature.Geometry); 43 IFeatureCursor featureCursor = labelFeatureLayer.FeatureClass.Search(queryFilter); 44 this.progressBarItem.Value++; 45 (featureCursor as IDisposable).Dispose(); 46 featureCursor = null; 47 } 48 }
TIP 3:坐标系统对矢量要素编辑操作的影响。
在进行矢量要素编辑时,如果地图框架坐标系为经纬度坐标系统的话,就会导致要素编辑时出现飞点或程序直接崩溃(PIE SDK版本为5.2,32位),如下图所示。与技术人员核实,这个问题确实存在,后续版本会更新修复。经过一系列思考和测试,发现有一种解决的办法:主旨只有一个,要素编辑操作的时候保证地图框架坐标系为投影坐标系统,就可以正常编辑矢量要素。具体办法为:在地图框架(Map)上,单击右键,在弹出的右键菜单中,单击“修改坐标系”,设置地图框架坐标系为相对应的投影坐标系统。
TIP 4:mapControlMain.FocusMap.DeleteLayers()函数中的bug。
我遇到的问题是:调用DeleteLayers()函数,地图视图窗口(mapControlMain控件)中图层确实是删除了,但是,TOCControl控件中图层列表中没有同步删掉(PIE SDK版本为5.2,32位)。对于这个问题,首先想到的是mapControlMain和TOCControl控件是否关联?遗憾的是,这两个控件确实已经关联过了,但仍然出现了这样的问题。与技术人员核实后,发现这个问题也确实存在。解决的办法是:调用 mapControlMain.FocusMap.DeleteLayer()函数,倒序遍历图层,一个一个删除。
1 private void buttonItem_CloseProject_Click(object sender, EventArgs e) 2 { 3 m_ElementEdit = false; 4 mapControlMain.CurrentTool = null; 5 labelItem_CoordinateSystem.Text = ""; 6 if (mapControlMain.FocusMap.LayerCount < 3) return; 7 //清除主视图和鹰眼视图中的地图 8 while (mapControlMain.FocusMap.LayerCount > 2) 9 if (mapControlMain.FocusMap.GetLayer(mapControlMain.FocusMap.LayerCount - 1).LayerType != LayerType.LayerTypeTiledLayer) 10 mapControlMain.FocusMap.DeleteLayer(mapControlMain.FocusMap.GetLayer(mapControlMain.FocusMap.LayerCount - 1)); 11 mapHawkEyeControl.FocusMap.ClearLayers(); 12 //mapHawkEyeControl.FocusMap.DeleteLayer(mapHawkEyeControl.FocusMap.GetLayer(0)); 13 //清除主视图和鹰眼视图中的元素 14 mapHawkEyeControl.ActiveView.GraphicsContainer.DeleteElement(m_DrawPolygonElement); 15 mapControlMain.ActiveView.GraphicsContainer.DeleteAllElements(); 16 //刷新视图 17 mapControlMain.ActiveView.ZoomTo(mapControlMain.ActiveView.FullExtent as IGeometry); 18 mapControlMain.ActiveView.PartialRefresh(PIE.Carto.ViewDrawPhaseType.ViewAll); 19 mapHawkEyeControl.ActiveView.PartialRefresh(PIE.Carto.ViewDrawPhaseType.ViewAll); 20 }
到此为止,我的分享就暂告一段落,有不对的地方,请大家批评指正!