ArcGis Engine开发技术文档(C#)

1 数据加载问题:

    任何系统都离不开数据的加载,下边就AE中几种常用的数据加载做一个列举。以便查阅:

 

1 、加载个人数据库

    个人数据库是保存在Access中的数据库。其加载方式有两种:通过名字和通过属性加载(也许不只这两种,AE中实现同一功能可以有多种方式)。

 

A 、通过设置属性加载个人数据库。

    首先通过IPropertySet 接口定义要连接数据库的一些相关属性,在个人数据库中为数据库的路径,例如:

         IPropertySet   ropset = new PropertySetClass();  

         Propset.SetProperty("DATABASE",@"D:\test\Ao\data\sh\MapData.mdb" );

    当定义完属性并设置属性后就可以进行打开数据库的操作了,在ArcEngine开发中存在IWorkspaceFactory 、 IFeatureWorkspace 、 IFeatureClass 、 IFeatureLayer 等几个常用的用于打开和操作数据空间地物的接口。IWorkspaceFactory 是一个用于创建和打开工作空间的接口,它是一个抽象的接口,我们在具体应用时要用对应的工作空间实例化它,如下:

        IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();

    如果我们打开的是SDE数据库就要用SdeWorkspaceFactoryClass 实例化Fact 。当我们完成了工作空间的实例化后就可以根据上边设置的属性打开对应的Access数据库了。打开方式如下:

        IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;

    打开Access工作空间后接下来的事情是做什么了,很简单,找到对应的地物类,赋给相应的层,通过MapControl控件添加对应的层,然后刷新地图。以下为添加某一层的代码:

       IFeatureClass Fcls = Workspace.OpenFeatureClass("District");

       IFeatureLayer Fly = new FeatureLayerClass();

       Fly.FeatureClass = Fcls;

       MapCtr.Map.AddLayer (Fly);

       MapCtr.ActiveView.Refresh();

    其中District 为地物类的名字,MapCtr 为AE 中MapControl的对象。上边的通过属性设置加载数据空间的方式还可以用于SDE数据库,在SDE数据库加载时会介绍。

    以下为通过设置属性加载Access数据库的完整C#代码:

public void AddAccessDBByPro()

{

       IPropertySet   ropset = new PropertySetClass();  

       Propset.SetProperty("DATABASE",@"D:\test\Ao\data\sh\MapData.mdb" );

       IWorkspaceFactory Fact = new AccessWorkspaceFactoryClass ();

       IFeatureWorkspace Workspace = Fact.Open(Propset,0) as IFeatureWorkspace;

       IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");

       IFeatureLayer Fly = new FeatureLayerClass();

       Fly.FeatureClass = Fcls;

       MapCtr.Map.AddLayer(Fly);

       MapCtr.ActiveView.Refresh();

}

 

B 、通过数据库名字加载个人数据库

   在这我先把完整的代码写出来,让您先跟上边的代码做个对比。以下为完整的代码:

public void AddAccessDBByName()

{

IWorkspaceName pWorkspaceName = new WorkspaceNameClass() ;

pWorkspaceName.WorkspaceFactoryProgID = "esriDataSourcesGDB.AccessWorkspaceFactory";

pWorkspaceName.PathName = @"D:\test\Ao\data\sh\MapData.mdb";

IName n = pWorkspaceName as IName ;

IFeatureWorkspace Workspace = n.Open() as IFeatureWorkspace;

IFeatureClass Fcls = Workspace.OpenFeatureClass ("District");

IFeatureLayer Fly = new FeatureLayerClass();

Fly.FeatureClass = Fcls;

MapCtr.Map.AddLayer (Fly);

MapCtr.ActiveView.Refresh();

}

    细心的人已经注意到,打开Access工作空间后接下来的代码是一样的,都是找到对应的地物类,赋给相应的层,通过MapControl控件添加对应的层,然后刷新地图。现在讲解一下上边的代码,首先是创建一个个人数据库工作空间名,在指定工作空间名的ProgID,以确定打开的是什么类型的工作空间,例如在打开Access个人数据库时使用的是下边的代码:

IWorkspaceName pWorkspaceName = new WorkspaceNameClass() ;

pWorkspaceName.WorkspaceFactoryProgID = "esriDataSourcesGDB.AccessWorkspaceFactory";

pWorkspaceName.PathName = @"D:\test\Ao\data\sh\MapData.mdb";

    属性WorkspaceFactoryProgID可以确保工作空间是AccessWorkspaceFactory,即个人数据库,同时指定要打开数据库的路径。为了打开数据库,我们通过AE的类图可以发现打开工作空间必须使用IName接口(个人认为,不一定正确,可以思考一下看有其他办法没有),所以接着定义IName对象,并把工作空间名转换成IName类型并赋值给IName对象,然后通过IName对象的Open()方法打开相应的工作空间,代码如下:

IName n = pWorkspaceName as IName ;

IFeatureWorkspace Workspace = n.Open () as IFeatureWorkspace;

    接下来的事情就是上边提到。

 

2 、加载 SDE 数据库

    什么是SDE数据库?这个问题要详细地讲解将花费大量的时间,但我可以告诉你SDE数据数据库可以是任何关系数据库。ESRI公司为了使空间数据能保存在关系数据库中,并且能很好的查询相关的空间属性而开发的一个中间件,使用SDE能很好的将空间数据保存在关系数据库中。如Orcale SQL Server 等。SDE具体细节的了解请查找相关的资料,这里只介绍怎么连接SDE数据库。SDE数据库的联机分为直接连接和通过SDE连接。当服务器的性能比较好的时候可以采用SDE连接,否则采用直接连接,这样可以减轻服务器的任务。建议采用直接连接,其实,SDE连接方式和直接连接的方式只是一个属性参数设置的问题。跟个人数据库采用属性连接的方式一样,先定义一个属性对象,然后设置属性参数,接着定义一个工作空间并用SdeWorkspaceFactoryClass()实例化它,接着加在加载图层,至于加载图层的代码,与加载个人数据库中图层的方法一样,其实不只加载这两种数据类型,加载其他类型的数据时也是采用相同的方法加载图层,只是工作空间采用不同的实例而已,下边为完整的对吗”//”后的为注析:

public void AddSDELayer(bool ChkSdeLinkModle)

{

         // 定义一个属性

         IPropertySet   ropset = new PropertySetClass();  

         if ( ChkSdeLinkModle==true ) // 采用 SDE 连接

         {  

            // 设置数据库服务器名

            Propset.SetProperty ("SERVER", "zhpzh");

            // 设置 SDE 的端口,这是安装时指定的,默认安装时 "port:5151"

            Propset.SetProperty ("INSTANCE", "port:5151");

            //SDE 的用户名

            Propset.SetProperty ("USER", "sa");

            // 密码

            Propset.SetProperty ("PASSWORD", "sa");

            // 设置数据库的名字 , 只有 SQL Server Informix 数据库才需要设置

            Propset.SetProperty ("DATABASE", "sde");

            //SDE 的版本 , 在这为默认版本

            Propset.SetProperty ("VERSION", "SDE.DEFAULT");

          }

         else // 直接连接

         {

           // 设置数据库服务器名 , 如果是本机可以用 "sde:sqlserver:."

           Propset.SetProperty ("INSTANCE", "sde:sqlserver:zhpzh");

            //SDE 的用户名

           Propset.SetProperty ("USER", "sa");

            // 密码

           Propset.SetProperty ("PASSWORD", "sa");

           // 设置数据库的名字 , 只有 SQL Server Informix 数据库才需要设置              Propset.SetProperty ("DATABASE", "sde");

           //SDE 的版本 , 在这为默认版本

           Propset.SetProperty ("VERSION", "SDE.DEFAULT");

          }

        // 定义一个工作空间 , 并实力化为 SDE 的工作空间

       IWorkspaceFactory Fact = new SdeWorkspaceFactoryClass();

       // 打开 SDE 工作空间 , 并转化为地物工作空间

IFeatureWorkspace Workspace = (IFeatureWorkspace )Fact.Open(Propset,0);

/* 定义一个地物类 , 并打开 SDE 中的管点地物类 , 写的时候一定要写全 . 如 SDE 中有一个管点层 , 你不能写成 IFeatureClass Fcls = Workspace.OpenFeatureClass (" 管点 "); 这样 , 一定要写成下边的样子 .*/

       IFeatureClass Fcls = Workspace.OpenFeatureClass ("sde.dbo. 管点 ");

       IFeatureLayer Fly = new FeatureLayerClass ();

       Fly.FeatureClass = Fcls;

       MapCtr.Map.AddLayer (Fly);

       MapCtr.ActiveView.Refresh ();

    }

    不知道注意到了没有,直接连接跟SDE连接的最大的不同是直接连接不要设置端口,同时他们的参数设置也不一样,好好注意参数的设置。

 

3、加载 CAD 图层

    CAD图层的加载可以分为:分图层加载和整幅图加载

A 、 分图层加载

    我们可以把CAD图分为点线面标注加载到MapControl中,跟加载其他数据一样,首先要定义一个工作空间,并用CadWorkspaceFactoryClass()实例化它,当得到了工作空间后就可以打开相应的工作空间,然后再打开指定的层类型。下边为完整的代码:

public void AddCADByLayer()
{

    // 定义工作空间,并用 CadWorkspaceFactoryClass() 实例化它

    IWorkspaceFactory Fact = new CadWorkspaceFactoryClass();

    // 打开相应的工作空间,并赋值给要素空间, OpenFromFile ()

    // 中的参数为 CAD 文件夹的路径

    IFeatureWorkspace Workspace = Fact.OpenFromFile(@"I:\test\",0) as IFeatureWorkspace;

      /* 打开线要素类,如果要打开点类型的要素,需要把下边的代码该成:

      IFeatureClass Fcls = Workspace.OpenFeatureClass ("modle.dwg:point");

      由此可见 modle.dwg 为 CAD 图的名字,后边加上要打开的要素类的类型,中间用冒号  隔开,大家可以想想多边形和标注是怎么打开的。 */

    IFeatureClass Fcls = Workspace.OpenFeatureClass ("modle.dwg:polyline");

      IFeatureLayer Fly = new FeatureLayerClass ();

      Fly.FeatureClass = Fcls;

      MapCtr.Map.AddLayer (Fly);

      MapCtr.ActiveView.Refresh ();

}

 

B 、 整幅 CAD 图的加载

    当我们要加载整幅CAD图时,需要使用下边的代码,这跟加载地物类有一定的区别,详细地介绍请看代码中的注析:

public void AddWholeCAD()
{

/ * 下边的两行代码是定义一个 CAD 工作空间,然后打开它,但这次不是赋值给

IFeatureWorkspace 对象 , 而是赋值给 IWorkspace 定义的对象 */

IWorkspaceFactory Fact = new CadWorkspaceFactoryClass();

       IWorkspace Workspace = Fact.OpenFromFile(@"I:\test\",0);

// 定义一个 CAD 画图空间,并把上边打开的工作空间赋给它

       ICadDrawingWorkspace dw = Workspace as ICadDrawingWorkspace;

// 定义一个 CAD 的画图数据集,并且打开上边指定的工作空间中一幅 CAD 图

// 然后赋值给 CAD 数据集

       ICadDrawingDataset ds = dw.OpenCadDrawingDataset ("modle.DWG");

// 通过 ICadLayer 类,把上边得到的 CAD 数据局赋值给 ICadLayer 类对象的

//CadDrawingDataset 属性

       ICadLayer CadLayer = new CadLayerClass();

       CadLayer.CadDrawingDataset = ds;

        // 利用 MapControl 加载 CAD 层

       MapCtr.Map.AddLayer (CadLayer);

   MapCtr.ActiveView.Refresh ();

}

    通过上边的代码和相关的解析,大家可能对整幅CAD图的加载有一个了解,但要具体搞清楚它的含义,也不那么容易。这留给大家去慢慢体会,在这我谈谈我自己的体会,但不一定正确。要打开数据集,首先要打开它的工作空间,至于什么是工作空间,我也说不太明白,但我的理解是,如果数据是保存在文件中的,工作空间大概就是它对应的文件夹,如果是数据库中的数据,我想大概就是对应的数据库。打开数据空间后,在这因为是整幅CAD图加载,所以跟以前的有点不同,这也就是相当整个CAD图就是一个数据集,所以要转到CAD画图的工作空间,然后把CAD图作为CAD数据集打开。为了在MapControl中加载CAD层,必须使用ICadLayer控件的对象,因为MapCtr.Map.AddLayer ()方法中只能是ICadLayer的对象。

    本人这几天突发奇想,想写点东西,但没有修改,有很多大字错误。敬请原谅。如果大家觉得可以。我会接着写下去。把我自己的资料整理出来。供大家分享。

本人QQ:44811312

 

AE 开发编辑功能

数据编辑问题

    在AE中数据的编辑是一个重点,也是一个难点。它包括的东西非常多,如:地物的添加,地物的修改,地物查询,节点捕捉,地物的符号化等一系列的问题。熟练的使用地物编辑的功能,是开发一个系统必须具备的条件。数据编辑问题解决得好坏直接决定着软件是否操作方便。在这我只是写一些相应的功能函数,至于软件开发中的架构,我不考虑。

1 、 添加地物

    什么是地物,这是 GIS的基本概念,我在这不想多说,我只想说明一点,地物可以表现在地图上,如房子、铁路、水管等等。我们把房子的总称称为一个地物类,在AE中对应一个地物类(IFeatureClass),一个地物类在地图上表示为一个地物层(IFeatureLayer),单独的一栋房子或一条管道我们称为地物(IFeature),Arcgis中一类地物只能放在一个层,通过图层的叠加组成一幅地图。

    熟悉面向对象的编程语言的人都知道,其实上边的地物类,地物的概念就是类和实体的概念。房子、铁路、水管等是一类地物的抽象,而具体的某一房子就是对象了。大家了解了这一点。接下来的开发就容易理解一些了。当然,还有一些其他的概念也必须了解一下:如长事务、短事务、编辑空间等。请大家查找一些相关资料,了解这方面的内容。

    我们先开始最基本的编辑功能:添加点线面的操作。它包括输入添加点线面和通过鼠标拖动添加点线面。下边讨论一下添加点线面的基本的实现方法:

一、添加点

我们可以有多种方法添加点,但基本的思路一样,只是有少量的接口有变化。下边是通过FeatrueClass的CreateFeature()函数添加地物。

public void AddPointByStore()

      {

              //得到要添加地物的图层

              IFeatureLayer l = MapCtr.Map.get_Layer(0) as IFeatureLayer;

              //定义一个地物类,把要编辑的图层转化为定义的地物类

              IFeatureClass fc = l.FeatureClass ;

              //先定义一个编辑的工作空间,然后把转化为数据集,最后转化为编辑工作空间,

              IWorkspaceEdit w = (fc as IDataset).Workspace as IWorkspaceEdit;

              IFeature f ;

              IPoint p;

              //开始事务操作

              w.StartEditing (false);

              //开始编辑

              w.StartEditOperation() ;

              for (int i = 0 ; i< 100 ; i++ )

              {

                   //创建一个地物

                   f= fc.CreateFeature();

                   p = new PointClass();

                   //设置点的坐标

                   p.PutCoords (i,i);

                   //确定图形类型

                   f.Shape = p;

                   //保存地物

                   f.Store();   

              }

              //结束编辑

              w.StopEditOperation();

              //结束事务操作

              w.StopEditing(true);

}

    上边的代码能添加点地物,但不能作为最终的代码使用,细心的人会看到。这段代码只是把第一层加进来,然后在第一层上边添加点地物,如果第一层不是点层,该怎么办,那就要判断了。怎么判断我们以后再说。通过上边的代码,我们已经清楚地了解到,编辑地物的基本框架,这也是我们所说的事务,如果想操作能返回和重做,就必须把代码写在IWorkspaceEdit的StartEditing()和StopEditing()函数之间,把相关的操作写在IWorkspaceEdit的StartEditOperation()和StopEditOperation()之间。并且操作是利用IWorkspaceEdit接口完成的,所以要仔细理会IWorkspaceEdit接口的用处,如何工作空间都可以转化为IWorkspaceEdit的对象,当转化为IWorkspaceEdit定义的对象后,我们定义一个IFeature的对象,然后利用IFeatureClass的CreateFeature()函数创建一个地物,并赋值给定义的IFeature对象。接着设置IFeature对象的一些属性,如:坐标值,坐标系,地物类型等,最后是调用IFeature对象的Store()保存添加的地物。

    上边的方法可以添加点地物,接着看看下边的代码。看有什么不同:

public void AddPointByWrite()

     {

         IFeatureLayer l = MapCtr.Map.get_Layer(0) as IFeatureLayer;

         IFeatureClass fc = l.FeatureClass ;

         IFeatureClassWrite fr = fc as IFeatureClassWrite ;

         IWorkspaceEdit w = (fc as IDataset).Workspace as IWorkspaceEdit;

         IFeature f ; 

         IPoint p;

         w.StartEditing (true);

         w.StartEditOperation() ;

         for (int i = 0 ; i< 100 ; i++ )

         {

              f= fc.CreateFeature();

              p = new PointClass();

              p.PutCoords (i,i);

              f.Shape = p;

              fr.WriteFeature (f);

         }

              w.StopEditOperation();

              w.StopEditing(true);

     }

    代码中用红色标记的两行就是不同的代码,其实他就是保存方式的不同而已。在这利用了IFeatureClassWrite 接口来保存数据。再看看下边的代码:

         public void AddPointByBuffer()

         {

              IFeatureLayer l = MapCtr.Map.get_Layer(0) as IFeatureLayer;

              IFeatureClass fc = l.FeatureClass ;

              IWorkspaceEdit w = (fc as IDataset).Workspace as IWorkspaceEdit;

              w.StartEditing (true);

              w.StartEditOperation() ;

              IPoint p;

              IFeatureBuffer f;

              IFeatureCursor cur = fc.Insert(true);

              for (int i = 0 ; i< 100 ; i++ )

              {

                   f= fc.CreateFeatureBuffer();

                   p = new PointClass();

                   p.PutCoords (i,i);

                   f.Shape = p;

                   cur.InsertFeature (f);

              }

              w.StopEditOperation();

              w.StopEditing(true);

     }

    其实不同的地方就两句代码,红色表示的。在这没有再定义地物接口了(IFeature),而是使用IFeatureBuffer 接口,保存的时候是使用InsertFeature()保存,这对大数据量处理的非常有好处。他是先把要添加的保存到缓冲区里。最后一次性保存。

二、添加线

    添加线的方法跟添加点一样,不同的只是地物类型不一样而已,我把代码贴出来,大家跟添加点的方式进行对比。这样便于记忆。也有利于理解。

     public void AddLineByWrite()

     {

         IFeatureLayer l = MapCtr.Map.get_Layer(0) as IFeatureLayer;

         IFeatureClass fc = l.FeatureClass ;

         IFeatureClassWrite fr = fc as IFeatureClassWrite ;

         IWorkspaceEdit w = (fc as IDataset).Workspace as IWorkspaceEdit;

         IFeature f ; 

//可选参数的设置

object Missing = Type.Missing;

         IPoint p=new PointClass();

         w.StartEditing (true);

         w.StartEditOperation() ;

         for (int i = 0 ; i< 100 ; i++ )

         {

              f = fc.CreateFeature();

              //定义一个多义线对象

              IPolyline PlyLine=new PolylineClass();

              //定义一个点的集合

              IPointCollection ptclo = PlyLine as IPointCollection;

              //定义一系列要添加到多义线上的点对象,并赋初始值

              for(int j=0;j<4;j++)

              { 

                   p.PutCoords(j,j);

                   ptclo.AddPoint(p,ref Missing,ref Missing);

              }

                   f.Shape = PlyLine;

                   fr.WriteFeature (f);

         }

              w.StopEditOperation();

              w.StopEditing(true);

}

    至于添加线的其他两种方法,通过修改添加点的代码,就可以得到。可以自己想想然后测试,这样便于记忆和理解。


如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。