ArcGIS Engine10.0轻松入门级教程(4)——基本功能开发

时间:2022-09-29 17:10:09

1地图编辑功能

  地图编辑功能涉及到比较复杂的地图与鼠标的交互以及事件的响应,ArcGIS提供了强大的地图编辑的相关功能。本节我们将尝试实现一些简单的地图编辑功能,包括点、线、面要素形状的创建和移动。通过本节希望你能掌握ArcEngine实现地图编辑的机制以及常用的地图编辑的接口。

    新建一个C#.Net项目,项目名称为MapEdit,添加MapControlLicenceControl、四个Button、一个ComboBox、一个Label等控件。如下图:

ArcGIS Engine10.0轻松入门级教程(4)——基本功能开发

     ArcEngine中的地图编辑使用IWorkspaceEdit接口来进行编辑状态的管理,在需要对指定的工作空间进行编辑时,首先使用IWorkspaceEdit获取该工作空间的数据,然后使用StartEditing方法开始编辑状态,StartEditOperation方法打开具体编辑的操作,编辑完成后,使用StopEditOperation方法关闭编辑操作,使用StopEditing方法关闭编辑状态,完成编辑。

    在本例中,我们实现了新的点线面要素的创建和移动的功能,涉及到了比较复杂的鼠标与地图间的交互,这个功能的实现中,IDisplayFeedback是一个十分关键的接口,它具有涉及创建要素,移动要素、编辑节点等31个实现类,能够实现鼠标与地图交互中的事件的追踪,返回新的几何对象。

   创建项目后注意把ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDesktop);这句代码加入到Program.cs文件中。   

   using ESRI.ArcGIS.Carto;
   using ESRI.ArcGIS.Controls;

   using ESRI.ArcGIS.Geometry;
   using ESRI.ArcGIS.Geodatabase;
   using ESRI.ArcGIS.Display;
   定义如下成员变量。

        //操作类型
        string strOperator = "";
        //当前地图视图
        IActiveView m_activeView = null;
        //当前操作图层
        IFeatureLayer m_FeatureLayer = null;
        //当前操作实体
        IFeature m_Feature = null;
        //当前点移动反馈对象
        IMovePointFeedback m_MovePointFeedback = new MovePointFeedbackClass();
        //当前线移动反馈对象
        IMoveLineFeedback m_MoveLineFeedback = new MoveLineFeedbackClass();
        //当前面移动反馈对象
        IMovePolygonFeedback m_MovePolygonFeedback = new MovePolygonFeedbackClass();

     加载地图文档的函数代码:

      private void button1_Click(object sender, EventArgs e)
        {
            //加载地图文档
            loadMapDocument();
            //将图层名填加到下拉列表框
            for (int i = 0; i < this.axMapControl1.LayerCount; i++)
            {
                ILayer layer = this.axMapControl1.get_Layer(i);
                this.comboBox1.Items.Add(layer.Name);
            }           
        }

        //加载地图文档
        private void loadMapDocument()
        {
            System.Windows.Forms.OpenFileDialog openFileDialog;
            openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "打开地图文档";
            openFileDialog.Filter = "map documents(*.mxd)|*.mxd";
            openFileDialog.ShowDialog();
            string filePath = openFileDialog.FileName;
            if (axMapControl1.CheckMxFile(filePath))
            {
                axMapControl1.MousePointer = esriControlsMousePointer.esriPointerHourglass;
                axMapControl1.LoadMxFile(filePath, 0, Type.Missing);
                axMapControl1.MousePointer = esriControlsMousePointer.esriPointerDefault;
            }
            else
            {
                MessageBox.Show(filePath + "不是有效的地图文档");
            }
        }

     combobox1添加selectedchange事件。

    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.comboBox1.Text != "")
            {
                for (int i = 0; i < this.axMapControl1.LayerCount; i++)
                {
                    ILayer layer = this.axMapControl1.get_Layer(i);
                    if (layer.Name == this.comboBox1.Text.ToString())
                    {
                        m_FeatureLayer = layer as IFeatureLayer;
                        m_Feature = m_FeatureLayer.FeatureClass.GetFeature(0);

                        if (m_Feature != null)
                        {
                            this.axMapControl1.Map.ClearSelection();
                            this.axMapControl1.Map.SelectFeature(m_FeatureLayer, m_Feature);
                            this.axMapControl1.Refresh();
                        }
                        m_activeView = this.axMapControl1.ActiveView;
                        return;
                    }
                }
            }
        }

           移动要素按钮添加事件:

        private void button2_Click(object sender, EventArgs e)
        {
            strOperator = "move";
            m_MovePointFeedback = new MovePointFeedbackClass();
            m_MoveLineFeedback = new MoveLineFeedbackClass();
            m_MovePolygonFeedback = new MovePolygonFeedbackClass();
        }

    下面添加鼠标与地图的交互事件,包括移动要素时鼠标的PanMouseDown事件、MouseMove事件和MouseUp事件。代码如下:

创建要素时首先在MouseDown事件中获取鼠标点击的点位,若图层为点图层,则直接创建要素,若为线图层或面图层,则作为第一个节点,以后每次点击都会添加一个节点,直到双击鼠标完成要素的创建。创建要素时的MouseDown事件在这里定义为CreateMouseDown。代码如下:

     private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
        {
            IPoint point = new PointClass();
            IFeatureClass featureClass = null;
            if (m_Feature == null) return;
            switch (strOperator)
            {
                case "move":
                    //将当前鼠标位置的点转换为地图上的坐标
                    point = m_activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y);
                    if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPoint)
                    {
                        //设置显示对象,并启动移动
                        m_MovePointFeedback.Display = m_activeView.ScreenDisplay;
                        m_MovePointFeedback.Start(m_Feature.Shape as IPoint, point);
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
                    {
                        //设置显示对象,并启动移动
                        m_MoveLineFeedback.Display = m_activeView.ScreenDisplay;
                        m_MoveLineFeedback.Start(m_Feature.Shape as IPolyline, point);
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
                    {
                        //设置显示对象,并启动移动
                        m_MovePolygonFeedback.Display = m_activeView.ScreenDisplay;
                        m_MovePolygonFeedback.Start(m_Feature.Shape as IPolygon, point);
                    }
                    break;
            }
        }

        private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
        {
            IPoint point = new PointClass();
            switch (strOperator)
            {
                case "move":
                    if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPoint)
                    {
                        if (m_MovePointFeedback != null)
                        {
                            //将当前鼠标位置的点转换为地图上的坐标
                            point = m_activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y);
                            //移动对象到当前鼠标位置
                            m_MovePointFeedback.MoveTo(point);
                        }
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
                    {
                        if (m_MoveLineFeedback != null)
                        {
                            //将当前鼠标位置的点转换为地图上的坐标
                            point = m_activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y);
                            //移动对象到当前鼠标位置
                            m_MoveLineFeedback.MoveTo(point);
                        }
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
                    {
                        if (m_MovePolygonFeedback != null)
                        {
                            //将当前鼠标位置的点转换为地图上的坐标
                            point = m_activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(e.x, e.y);
                            //移动对象到当前鼠标位置
                            m_MovePolygonFeedback.MoveTo(point);
                        }
                    }
                    break;
            }
        }

        private void axMapControl1_OnMouseUp(object sender, IMapControlEvents2_OnMouseUpEvent e)
        {
            if (m_Feature == null) return;
            IGeometry resultGeometry = null;
            switch (strOperator)
            {
                case "move":
                    if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPoint)
                    {
                        //停止移动
                        resultGeometry = m_MovePointFeedback.Stop() as IGeometry;
                        m_Feature.Shape = resultGeometry;
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
                    {
                        //停止移动
                        resultGeometry = m_MoveLineFeedback.Stop() as IGeometry;
                        m_Feature.Shape = resultGeometry;
                    }
                    else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
                    {
                        //停止移动
                        resultGeometry = m_MovePolygonFeedback.Stop() as IGeometry;
                        m_Feature.Shape = resultGeometry;
                    }
                    IWorkspaceEdit workspaceEdit;
                    IWorkspace workspace;
                    IDataset dataset = m_FeatureLayer.FeatureClass as IDataset;
                    workspace = dataset.Workspace;
                    workspaceEdit = workspace as IWorkspaceEdit;
                    //开始编辑
                    workspaceEdit.StartEditing(true);
                    workspaceEdit.StartEditOperation();
                    //保存实体
                    m_Feature.Store();
                    //结束编辑
                    workspaceEdit.StopEditOperation();
                    workspaceEdit.StopEditing(true);
                    m_MovePointFeedback = null;
                    m_MoveLineFeedback = null;
                    m_MovePolygonFeedback = null;
                    break;
            }
            m_activeView.Refresh();
            this.axMapControl1.Map.ClearSelection();
        }

     删除节点按钮事件的代码如下:

     private void button3_Click(object sender, EventArgs e)
        {
            IPointCollection pointCollection;
            if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
            {
                pointCollection = new PolylineClass();
                IPolyline polyline = m_Feature.Shape as IPolyline;

                pointCollection = polyline as IPointCollection;
                //如果点个数少于两个无法构成线
                if (pointCollection.PointCount > 2)
                {
                    //移除指定的节点
                    pointCollection.RemovePoints(pointCollection.PointCount - 1, 1);
                }
            }
            else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
            {
                pointCollection = new PolygonClass();
                IPolygon polygon = m_Feature.Shape as IPolygon;
                pointCollection = polygon as IPointCollection;
                //如果点个数少于三个无法构成面
                if (pointCollection.PointCount > 3)
                {
                    //移除指定的节点
                    pointCollection.RemovePoints(pointCollection.PointCount - 1, 1);
                }
            }
            IWorkspaceEdit workspaceEdit;
            IWorkspace workspace;
            IDataset dataset = m_FeatureLayer.FeatureClass as IDataset;
            workspace = dataset.Workspace;
            workspaceEdit = workspace as IWorkspaceEdit;
            //开始编辑
            workspaceEdit.StartEditing(true);
            workspaceEdit.StartEditOperation();
            //保存数据
            m_Feature.Store();
            //结束编辑
            workspaceEdit.StopEditOperation();
            workspaceEdit.StopEditing(true);
            m_activeView.Refresh();
        }

     双击“增加节点”添加如下代码:

        private void button4_Click(object sender, EventArgs e)
        {
            IPointCollection pointCollection;
            IPoint point = new PointClass();
            IPoint fromPoint = new PointClass();
            IPoint toPoint = new PointClass();
            if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolyline)
            {
                pointCollection = new PolylineClass();
                IPolyline polyline = m_Feature.Shape as IPolyline;

                object missing1 = Type.Missing;
                object missing2 = Type.Missing;
                pointCollection = polyline as IPointCollection;
                //获取线对象的最后两个点
                fromPoint = pointCollection.get_Point(pointCollection.PointCount - 2);
                toPoint = pointCollection.get_Point(pointCollection.PointCount - 1);
                //根据线最后两个点,创建一个新点
                point.PutCoords((fromPoint.X + toPoint.X) / 2, (fromPoint.Y + toPoint.Y) / 2 + 50);
                //将新点添加到线对象的点集合中
                pointCollection.AddPoint(point, ref missing1, ref missing2);

            }
            else if (m_Feature.Shape.GeometryType == esriGeometryType.esriGeometryPolygon)
            {
                pointCollection = new PolygonClass();
                IPolygon polygon = m_Feature.Shape as IPolygon;

                object missing1 = Type.Missing;
                object missing2 = Type.Missing;
                pointCollection = polygon as IPointCollection;
                //获取面对象点集最后两个点
                fromPoint = pointCollection.get_Point(pointCollection.PointCount - 2);
                toPoint = pointCollection.get_Point(pointCollection.PointCount - 1);
                //根据线最后两个点,创建一个新点
                point.PutCoords((fromPoint.X + toPoint.X) / 2, (fromPoint.Y + toPoint.Y) / 2 + 50);
                //将新点添加到线对象的点集合中
                pointCollection.AddPoint(point, ref missing1, ref missing2);
            }
            IWorkspaceEdit workspaceEdit;
            IWorkspace workspace;
            IDataset dataset = m_FeatureLayer.FeatureClass as IDataset;
            workspace = dataset.Workspace;
            workspaceEdit = workspace as IWorkspaceEdit;
            //开始编辑
            workspaceEdit.StartEditing(true);
            workspaceEdit.StartEditOperation();
            //保存数据
            m_Feature.Store();
            //结束编辑
            workspaceEdit.StopEditOperation();
            workspaceEdit.StopEditing(true);
            m_activeView.Refresh();
        }

     至此,我们完成了代码的编写,效果如图所示。

ArcGIS Engine10.0轻松入门级教程(4)——基本功能开发

    地图编辑的GIS中比较复杂和困难的环节,涉及到的对象和接口非常多,上面实例只是实现了最基础的编辑的活动,如果读者对二次开发感兴趣,可以自己试着阅读GIS二次开发相关书籍,了解与编辑相关的接口和方法,自己实现。

2地理变换

      以下演示了如何改变一个图层的空间参考。运行效果如下图:

ArcGIS Engine10.0轻松入门级教程(4)——基本功能开发

    先新建一个MapControl Application模板,添加菜单按钮,事件代码为:

     private void 空间参考ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Transform attributeQueryForm = new Transform(this.axMapControl1);
            attributeQueryForm.Show();
        }

     然后见一个窗体,命名为Transform,控件布局见上图。添加变量:

        //地图数据
        private AxMapControl mMapControl;
        //选中图层
        private IFeatureLayer mFeatureLayer;

        构造函数修改为:

       public Transform(AxMapControl mapControl)
        {
            InitializeComponent();
            this.mMapControl = mapControl;
        }

       Load事件为:

     

private void Transform_Load(object sender, EventArgs e)
        {
            //MapControl中没有图层时返回
            if (this.mMapControl.LayerCount <= 0)
                return;

            //获取MapControl中的全部图层名称,并加入ComboBox
            //图层
            ILayer pLayer;
            //图层名称
            string strLayerName;
            for (int i = 0; i < this.mMapControl.LayerCount; i++)
            {
                pLayer = this.mMapControl.get_Layer(i);
                strLayerName = pLayer.Name;
                //图层名称加入cboLayer
                this.comboBox1.Items.Add(strLayerName);
            }
            //默认显示第一个选项
            this.comboBox1.SelectedIndex = 0;
        }

      comboBox1_SelectedIndexChanged事件为:

      private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //获取cboLayer中选中的图层
            mFeatureLayer = mMapControl.get_Layer(comboBox1.SelectedIndex) as IFeatureLayer;
        }

         添加改变图层的空间参考的函数:

        /// <summary>
        /// 改变图层的空间参考
        /// </summary>
        /// <param name="pFeatureLayer">图层</param>
        /// <param name="pGeoType">空间参考类型</param>
        private void ChangeLayerRef(IFeatureLayer pFeatureLayer, int gcsType)
        {
            try
            {
                IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
                //QI到IGeoDataset
                IGeoDataset pGeoDataset = pFeatureClass as IGeoDataset;
                //QI到IGeoDatasetSchemaEdit
                IGeoDatasetSchemaEdit pGeoDatasetSchemaEdit = pGeoDataset as IGeoDatasetSchemaEdit;
                if (pGeoDatasetSchemaEdit.CanAlterSpatialReference == true)
                {
                    //创建SpatialReferenceEnvironmentClass对象
                    ISpatialReferenceFactory2 pSpaRefFactory = new SpatialReferenceEnvironmentClass();
                    //创建地理坐标系对象
                    IGeographicCoordinateSystem pNewGeoSys = pSpaRefFactory.CreateGeographicCoordinateSystem(gcsType);//4214代表Beijing1954
                    pGeoDatasetSchemaEdit.AlterSpatialReference(pNewGeoSys);
                }
            }
            catch (Exception Err)
            {
                MessageBox.Show(Err.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        在转换坐标按钮下添加事件:

        private void button1_Click(object sender, EventArgs e)
        {
            ChangeLayerRef(mFeatureLayer, 4214);
            MessageBox.Show("转换成功!");
        }

        运行就能成功了!