如何动态添加图层并进行查询

如何动态添加图层并进行查询,第1张

首先,要得到地图的IMap接口才能对地图的图层进行 *** 作。

清单1 获取IMap接口

1 AGSLocalMapResource res = (AGSLocalMapResource)webContext getResources()get("ags0");

2 comesriarcgiscartoMapServer mapServer = resgetLocalMapServer();

3 try {

4 IMap map = mapServergetMap(mapServergetDefaultMapName());

5 mapaddLayer(ILayer layer);

6 }catch(Exception e){

7 }

动态添加图层的核心代码就是第5行,它接收的参数是实现了ILayer接口的对象。因此,接下来我们需要把file geodatabase里的feature class组装成一个ILayer对象。

清单2 从Feature Class到ILayer

1 IServerContext sctx = resgetServerContext();

2 IWorkspaceFactory pWorkspaceFactory = (IWorkspaceFactory) sctx createObject(FileGDBWorkspaceFactorygetClsid());

3 IFeatureWorkspace pFWS = (IFeatureWorkspace) pWorkspaceFactory openFromFile("E:\\data\\qixiang\\qixianggdb", 0);

4 IFeatureClass fc = pFWSopenFeatureClass("Road");

5 IFeatureLayer fLayer = (IFeatureLayer) sctx createObject(FeatureLayergetClsid());

6 fLayersetFeatureClassByRef(fc);

7 fLayersetName("Road");

Server中的AO对象,必须在一个IServerContext上下文中使用,因此,AO对象的创建跟一般的Java类有所不同。因为数据是保存在filegeodatabase,所以在第2行代码中我们创建了一个FileGDBWorkspaceFactory,接下来的两行利用这个工厂类打开了一个IFeatureWorkspace,然后读取了其中的一个feature class。最后,用这个feature class设置了一个IFeatureLayer(ILayer的一个子类)。

有了IMap和IFeatureLayer对象以后,其实就已经能动态添加图层了。但是这样添加的图层有一点欠缺的地方——它的渲染方式是随机的。就像我们用ArcMap直接打开一个polygon feature class时,ArcMap会随机选择一个填充色。为了保证每次用户添加图层以后能够看到同样的效果,我们需要为动态图层设置一个渲染方式。当然,我们可以在程序中为不同类型的要素分别设置一个Renderer,但是本文将探讨另一种方式。先用ArcMap设置好渲染方式,然后保存成一个lyr文件,动态添加图层的时候从lyr文件中读取Renderer信息,然后添加到IFeatureLayer。毕竟,用ArcMap设置Renderer比写代码要简单多了!而且,也更易于分发。

清单3 从lyr文件中读取Renderer信息

1 IMapDocument doc = (IMapDocument)sctxcreateObject(MapDocumentgetClsid());

2 docopen(lyrFilePath, null);

3 ILayer lyr = docgetLayer(0, 0);//get the first map's first layer

4 IFeatureRenderer renderer = null;

5 if(lyr instanceof IGeoFeatureLayer){

6 IGeoFeatureLayer geoLyr = (IGeoFeatureLayer)lyr;

7 renderer = geoLyrgetRenderer();

8 }

在清单3中我们创建了一个MapDocument对象来读取lyr文件(API说明:The MapDocument CoClass encapsulates map document files (mxd, mxt, pmf) and layer files (lyr))。第2行代码中的lyrFilePath就是lyr文件存放的路径。由于打开的是lyr文件,只有一个图层,所以第3行代码的两个参数都为零,表示打开的是第一个地图的第一个图层。接下来从图层文件中读取Renderer信息。

接下来,我们就可以把Renderer信息赋给图层,然后将图层添加到地图上。

清单4 设置渲染方式,添加图层

1 if(renderer != null){

2 IGeoFeatureLayer geoFeatureLyr = (IGeoFeatureLayer)fLayer;

3 geoFeatureLyrsetRendererByRef(renderer);

4 }

5 fLayersetVisible(true);

6 mapaddLayer(fLayer);

7 mapmoveLayer(fLayer, 1);

至此,我们通过map service提供的AO接口完成了动态添加图层的工作,但是如果这时候我们去刷新浏览器,并不会看到新增加的图层!这是由于Web ADF层还不知道图层信息发生变化了。这与Web ADF的初始化有关,当一个session启动的时候,WebContext会根据map service的信息完成初始化,包括一些列的functionalities以及attributes,这些初始化信息中就包含图层信息(保存在comesriarcgiswsMapDescription和comesriarcgiswsMapLayerInfo等类中)。在WebContext初始化完成以后,如果map service的信息发生改变,必须由程序员自己去刷新Web ADF中的相关对象,实现Web ADF对象与map service同步。有趣的是,并不是所有对map service的修改都要自己去通知Web ADF,比如修改图层的Renderer信息就不需要。我觉得如果comesriarcgisws包中的与AO同名的对象,很可能就需要手工修改,因为这些对象都是初始化的时候创建的;如果没有,说明没有必要为其单独创建Web ADF对象,需要的时候就直接访问AO接口了。

清单5 刷新ADF对象

1 mapServerrefreshServerObjects();

2 IMapServerInfo serverInfo = mapServergetServerInfo(mapServergetDefaultMapName());

3 agsServerInfo = (comesriarcgiswsMapServerInfo)AGSUtilcreateStubFromArcObject(serverInfo,comesriarcgiswsMapServerInfoclass,sctx);

4 comesriarcgiswsMapServerInfo si = mapFungetMapServerInfo();

5 sisetMapLayerInfos(agsServerInfogetMapLayerInfos());

6 mapFunsetMapDescription(agsServerInfogetDefaultMapDescription());

在清单5中,我们先刷新了map server object,然后获取了新的IMapServerInfo对象。第3行代码中我们完成了从AO对象到ADF对象的转换,这样,ADF就有了一个反映当前map service状态的comesriarcgiswsMapServerInfo。4到6行代码用新的comesriarcgiswsMapServerInfo刷新了AGSMapFunctionality,从而完成了ADF与map service的同步。下面的截图显示了动态添加图层的效果。

由于WebContext以及它管理的一系列ADF资源只在session开始时进行一次初始化,因此动态添加的图层就无法用WebQuery来进行查询和高亮显示。在清单5中已经介绍了如何刷新ADF端的对象,因此,我们可以用更新以后的comesriarcgiswsMapServerPort对动态添加的图层进行查询。

接下来的例子中,让用户在地图上拖一个矩形框,然后查询所有图层中与该矩形框相交的要素,并将它们高亮显示。首先需要将用户在地图上绘制的矩形框传递到服务器端,并创建一个comesriarcgiswsPolygonN对象。

清单6 捕获屏幕 *** 作并构造服务器端几何要素

1 WebExtent ext = (WebExtent)eventgetWebGeometry()toMapGeometry(webContextgetWebMap());

2 EnvelopeN env = (EnvelopeN)AGSUtiltoAGSGeometry(ext);

接下来可以根据该PolygonN新建一个comesriarcgiswsSpatialFilter对象。

清单7 创建SpatailFilter对象

1 SpatialFilter spatialFilter = new SpatialFilter();

2 spatialFiltersetSpatialRel(EsriSpatialRelEnumesriSpatialRelIntersects);

3 spatialFiltersetWhereClause("");

4 spatialFiltersetSearchOrder(EsriSearchOrderesriSearchOrderSpatial);

5 spatialFiltersetSpatialRelDescription("");

6 spatialFiltersetGeometryFieldName("");

7 spatialFiltersetFilterGeometry(env);

comesriarcgiswsMapServerPort的queryFeatureData()方法只能对某一个图层进行查询,所以,如果要查询所有的图层,需要对所有图层做一次循环。

清单8 空间查询

1 AGSMapFunctionality mapFunc = (AGSMapFunctionality)resgetFunctionality("map");

2 int layerCount = mapFuncgetLayerDescriptions()length;

3 MapServerPort svrPort = resgetMapServer();

4 try{

5 for(int i=0;i<layerCount;i++){

6 RecordSet rs = svrPortqueryFeatureData(“”,i, spatialFilter);

7 }

8 }catch(Exception e){

9 }

第8行代码对每一个图层都做了一次空间查询,将查询结果保存在comesriarcgiswsRecordSet中。查询结果中包含了图层要素的所有信息,包括属性信息和空间信息,可以根据需要进行提取。这个例子中需要对查询结果做高亮显示,所以接下来我们关心的焦点就是获取查询结果的空间信息。

清单9 高亮显示查询结果

1 Record[] records = rsgetRecords();

2 for(int j=0;j<recordslength;j++){

3 Record item = records[j];

4 int n = itemgetValues()length;

5 for(int k=0;k<n;k++){

6 Object obj = itemgetValues()[k];

7 if(obj instanceof comesriarcgiswsGeometry){

8 WebGeometry geom = AGSUtilfromAGSGeometry((comesriarcgiswsGeometry)obj);

9 queryaddDisplayGeometry(geom);

10 }

11 }

12 }

comesriarcgiswsRecord对应的是某个图层的一条记录,它的getValues()方法获取该记录属性表中的所有信息(包括shape字段)。第6行开始我们读取每一个字段的值,判断该字段是否记录了shape信息,如果是,就将shape信息转成WebGeometry对象,然后用WebQuery进行高亮显示。

IFeayureLayer是ILayer的子类 ,

IFeature是IFeatureLayer中的一个要素,

可以从IFeatureLayer中得到IFeatureClass  

再利用游标IFeatureCursor就可以把这些IFeature一个个遍历出来了。

ArcGIS Engine是ArcGIS的一套软件开发引擎,可以让程序员创建自定义的GIS桌面程序。

ArcGIS Engine支持多种开发语言,包括COM、NET框架、Java和C++,能够运行在Windows、Linux和Solaris等平台上。这套API提供了一系列比较高级的可视化控件,大大方便了程序员构建基于ArcGIS的应用程序。

是ESRI在ArcGIS9版本才开始推出的新产品,它是一套完备的嵌入式GIS 组件库和工具库,使用ArcGIS Engine开发的GIS应用程序可以脱离ArcGIS Desktop而运行。

1 打开 SDE 数据。 SDE 数据一定要使用工作空间工厂去初始化工作空间,在工作空间打开 FeatureClass,这是 最常规的 *** 作。下面通过一段 C#代码连接 SDE,打开并返回一个 IWorkspace。 public IWorkspace FindWsByDefault() { IPropertySet propSet = new PropertySetClass(); propSetSetProperty("Server", Lan); propSetSetProperty("Instance", yangyang); propSetSetProperty("Database", ""); propSetSetProperty("User", user); propSetSetProperty("Password", pwd); propSetSetProperty("Version", version); IWorkspaceFactory factory = new SdeWorkspaceFactoryClass(); IWorkspace workspace = factoryOpen(propSet, 0); return workspace; } 通过上述代码打开了 SDE 的工作空间,接下来要做的就是获取要编辑的 FeatureClass。写一 个函数,通过 FeatureClass 的别名和所在的 Dataset 返回 FeatureClass。做法是先遍历所有的 DataSet, 找到符合要求的 Dataset 之后遍历里面的要素, 返回与参与别名一致的 FeatureClass (顺便说一下,FeatureClass 在没有指定别名的时候默认与 FeatureClass 名称相同) //查找指定要素 public IFeatureClass FindClassByName(IWorkspace ws, string className, string dsName) { IEnumDataset enumDs; if (dsName != "") { enumDs = wsget_Datasets(esriDatasetTypeesriDTFeatureDataset); IFeatureDataset featureDs = enumDsNext() as IFeatureDataset; while (featureDs != null) { if (featureDsName == dsName) { return GetFcFromDataset(featureDs, className); } featureDs = enumDsNext() as IFeatureDataset; } } else { enumDs = wsget_Datasets(esriDatasetTypeesriDTFeatureClass); return GetFcFromEnumDataset(enumDs,className); } return null; } //在数据集中查找要素类 private IFeatureClass GetFcFromDataset(IFeatureDataset featDs, string className) { IFeatureClass featClass; IFeatureClassContainer fcContainer = featDs as IFeatureClassContainer; for (int i = 0; i < fcContainerClassCount; i++) { featClass = fcContainerget_Class(i); if (featClassAliasName == className) { return featClass; } } return null; } //在要素类集合中查找要素类 private IFeatureClass GetFcFromEnumDataset(IEnumDataset enumDs, string className) { IFeatureClass featClass = enumDsNext() as IFeatureClass; while (featClass != null) { if (featClassAliasName == className) { return featClass; } featClass = enumDsNext() as IFeatureClass; } return null; } //通过要素类名和数据集名在指定的工作空间中寻找要素类 public IFeatureClass FindClassByName(string className, string datasetName) { IWorkspace ws = FindWsByDefault(); IFeatureClass featClass = FindClassByName(ws, className, datasetName); return featClass; } 特别需要留意的是最后一个函数 FindClassByName(,,先是打开 SDE 的工作空间,在这 ) 个工作空间返回符合条件的要素集。通过这样的指向才能对 SDE 的 FeatureClass 进行写入 和删除的 *** 作。 可以把上述代码写成一个静态类, 这样就可以很方便的通过数据集名称和要 数集别名指向要编辑的 FeatureClass 了。 值得一提的是, 很多新手都没有养成这种良好的习惯, 就是先打开工作空间再进行数据的编 辑 ,即便是使用 shp 文件或是 MDB 数据。他们习惯性的使用 MapControl 去加载 MXD 文 件,然后在 MapControl 通过 MapControlget_layer(index)的方法去获取图层,然后将其转为 IFeatureLayer 或是 IFeatureClass 进行 *** 作。 事实上,MXD 已经不用开发者写一句加载图层的代码就完成了对图层的加载,确实比较方 便。 但是它有很多看不见的 *** 作没有表现出来, 加载完数据之后就把工作空间给自动关闭了。 对于 shp 文件和 MDB 数据,通过读取地图控件的图层是可以直接达到写入的目的,但一旦 有用户进行 *** 作该图层文件就会被锁死,这就是不支持版本技术的表现。而 SDE 数据由于 存在版本(原理不多说了) ,因此有需要去确保数据的安全性和一致性,必须使用工作空间 的形式去打开。如果用读取 MapControl 图层的方法去获取 FeatureClass,实际上获取的是一 个没有打开的编辑 *** 作的 FeatureClass,在 ESRI 的帮助文档里面我们不难发现它是只读的, 就像在 ArcMap 里面没有用 Editor 执行 startEdit 一样。 2 编辑 SDE 数据 利用上述的方法获取了 FeatureClass 后就可以用常规的方式对其进行编辑,如 delete()和 CreateFeature(),或是更改属性值。但是仍然会出现无法编辑数据的现象,这种现象通常提 示没有足够的授权去编辑数据,这就涉及到 AE 对 SDE 数据编辑的授权,也就是 gdbedite 的授权(主要是在 AE92 里面) 。 关于 GDBEdite 的授权,懒羊羊已经在之前发过一份比较完整的文档,但还是在这里再归纳 一下。 ArcEngine92 在用户许可上做了很大的改动,应用程序是强制初始化许可,也就是说必须使 用 LicenseControl 或 AO 接口初始化许可, 否则应用程序无法启动。 Engine91 未采取强制初 始化许可策略,而是应用程序创建时就初始化标准 Engine 许可。在一般情况下,我们会用 将 LicenseControl 拖放到主窗体上完成初始化。但当 Engine 程序需要使用 ArcGIS Engine Enterprise Geodatabase(以下简称 GDB Update)许可的时候,我们就往往会由于意识不到应 该使用该许可,以及无法正确的初始化该许可而陷入麻烦。 对于许可这东西,首先要学会看软件产品的购货单。下表是一份关于 ArcEngine92 的购货 单。 下面对 GDB update 许可进行讨论 1. 什么情况下需要 GDB Update 许可 当需要对 SDE 里数据进行编辑时,以及需要在 SDE 和 Personal Geodatabase 中创建复杂 ArcGIS 对象时,需要使用 GDB Update 许可。 对 SDE 里的数据编辑,很好理解,大致就是进行数据插入,删除,更新;对表添加、删除 和修改,表结构的变化(添加、删除列)等,因为这些动作都会造成后台数据库的写 *** 作。 对于 Personal Geodatabase,进行简单数据对象和编辑,包括创建、删除和修改普通表都是不 需要 GDB Update 许可的, 但对于复杂的 Geodatabse 对象的创建、 删除和修改, 则需要 GDB Update 许可,其中复杂的 Geodatabse 对象包括几何网络,网络分析模型,拓扑,关系类。 这也是为什么往往有写好了一个创建几何网络或拓扑的程序后,执行起来会被报“需要 Geodatabase Update 许可”的错。 2. 怎样初始化 GDB Update 许可 当我们意识到需要使用 Engine 的 GDB Update 许可时,怎样才能将它正确的初始化呢? Engine 给我们提供了两种初始化许可的方法: 1) 使用 LicenseControl 控件。将该控件拖放到主窗体之上,勾选适当的许可,并确保 程序启动该窗体可加载,就可以完成许可初始化。如下图: 2) 使用 IAoInitializeInitialize 方法加入适当的参数进行初始化 下面是 C#的代码 private IAoInitialize m_AoInitialize = new AoInitializeClass(); private void Form1_Load(object sender, EventArgs e) { m_AoInitializeInitialize(esriLicenseProductCodeesriLicenseProductCo deEngineGeoDB); } 在窗体加载的时候初始化 GDB 许可。 当然, 对于一个健壮的程序而言, 我们还需要在初始化之前先判断将被初始化的许可是否可 用,应先使用 IsProductCodeAvailable 方法进行判断,需要初始化扩展模块的许可,可使用 CheckOutExtension 方法。

以上就是关于如何动态添加图层并进行查询全部的内容,包括:如何动态添加图层并进行查询、arcgis engine中怎样获取arcgis图层的图元,用的是C#,求代码、如何编辑SDE数据等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9557498.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存