前言:根据项目经验总结了一大波iObject .net 开发的坑及处理方法,和二次封装了一些好用的函数。
参考文档:SuperMap iObjects .NET 10i 联机帮助
和arcgis、qgis最显著的不同,超图不能直接打开放在硬盘里面的shp文件,tif文件等,必须要将数据导入到工程里面的udb里面才可以显示出来(类似ArcGIS把数据导入到gbd),其他的大同小异都差不多。
常用的结构分支如下,其他的在二维平面开发不怎么用到:
-| 工程文件(.smwu) #类似arcgis的.mxd
--| 数据源文件(.udb || .udbx) # 类似arcgis的gdb
--| 地图文件(.xml) # 显示地图的配置,下次打开工程的时候就可以还原上次关闭时候地图的显示形态(哪个图层显示的什么颜色、显示的中心在哪儿、显示范围多大之类的)
同一个图层数据,在SuperMap和ArcGIS打开以后,很多参数显示名称是不一致的,用ESPG:4524这个坐标系举例:
①坐标系名字:
在arcgis打开显示为:CGCS2000 / 3-degree Gauss-Kruger zone 36”
在超图打开显示为:China_2000_3_DEGREE_GK_Zone_36
②坐标系的GeoDatum(超图里面是叫GeoDatum,位于PrjCoordSys.GeoCoordSys.Datum):
在arcgis显示为:D_CGCS_2000
在超图显示为:D_China_2000
③投影方法:
在超图设置为“GaussKruger "以后,在arcgis里面打开显示为 “Transverse_Mercator”;
在ArcGIS设置为“Transverse_Mercator”以后,超图打开显示“TransverseMercator”,少了一条下划线,谜之操作。
检查两个投影坐标系是否相同的代码如下:
MapControl.Redo()、Undo()只支持:将图层调整为编辑状态后,用鼠标在界面上对Geometry进行:拖动、节点编辑、删除的撤销和恢复,其他任何用代码对Geometry进行编辑都无法通过调用MapControl.Redo()、Undo()这两个函数对刚才的操作进行撤销或者恢复,如:Recordset.setGeometry(),Recordset.Delete()和Geometries类对Geometry的求交、擦除、合并等操作。
必须要用mapControl.EditHistory.add()来保存编辑的操作,然后再调用mapControl.EditHistory.Redo()、Undo()来实现恢复和撤销。
即:用鼠标对Geometry的操作只需调用MapControl.Redo()、Undo()来实现撤销和恢复;用代码对Geometry实现的操作需要调用mapControl.EditHistory.add()、mapControl.EditHistory.Redo()、Undo()这三个来实现撤销和恢复。
具体的代码在超图官方的CSDN账号里面找到了,地址如下:SuperMap iObjects.NET编辑撤销操作详解_SuperMap技术控-CSDN博客
如下图所示,被选中的蓝色图斑周围,一共有三个地块与它有邻接关系,接壤的公共边长度依次为:59、0、46,这里就有问题了:为什么存在具有邻接关系但公共边长度为0的情况?这就是最大的坑!如图所示,②图斑和蓝色地块只有一个点接触到了,但这也会被算做是接壤,点是不具有长度概念的,所以邻接长度为0。ps:其实点和线是人思想中的一个理想状态,真实世界是不存在点和线的,放大以后都会是个面,改编一下马克思哲学的运动观来概括:面是绝对的,点线是相对的🤔
搜索邻接图斑的代码如下:
求公共边长度的代码如下:
图斑的融合也是很大的一个坑点,必须要用 :
Recordset deleteRecord = sideRecord.Dataset.Query($"SmID == {sideRecord.GetID()}", CursorType.Dynamic);
deleteRecord.delete();
// 不能用sideRecord.delete()直接删除自己,有时候会出bug,最好是像上面代码那样绕一圈在原图层通过SmID搜索到自己然后删除掉
通过在自己的所属图层里面搜索自己的SmID来删除自己,不能直接sideRecord.delete()来删,否则会出莫名其妙的bug(被坑了5天),完整封装代码如下
叠加分析调用SuperMap.Analyst.SpatialAnalyst就可以了,超图官方文档写的很详细,主要的坑在于它里面的一个参数:OverlayAnalystParameter的tolerance,即叠加分析的容限值,决定了叠加分析的精度。但是这个参数有两个大坑,
①如果追求极致精度,这个tolerance一定不能设为0,如果设为0则api会自动改为默认值,默认值具体是多少官方文档没说,感觉大概是0.015m左右。追求极致精度就设为0.0001之类的,切记。
②如果需要进行叠加分析连续操作,这个tolerance最好要统一并且一定不能设得太低,最小就0.01,再低会有严重的精度问题,比如:两个图斑把比例尺放的很大的情况下,目视都是邻接关系,但是容限值设的过低如0.00001米,它两者就会变成相交关系。切记!!!
7.1 新增
图层新增一条数据
详见超图官方文档的 Recordset.AddNew方法,没啥坑
7.2 删除
删除数据: Recordset.Delete();
坑详见上面第五点合并图斑,必须要在原图层找到自己然后删除,不然很可能会失败 :
var deleteRecordset = recordset.Dataset.Query($"SmID == {recordset.GetID()}", CursorType.Dynamic);
deleteRecordset.Delete();
7.3 修改
1.修改某行数据的某字段数据
2.修改所有数据的某字段数据
3.根据空间关系进行数据更新: 没有坑,详见超图官方文档的Recordset.UpdateFields
7.4 查询
详见超图官方文档的DatasetVector.Query,主要的坑是:
① 如果要查询的字段是非数值型的,需要在值的两侧加小引号,如果是数值就不需要,如下所示:cityname是文本字段搜索时候'chengdu'要加引号,区号areanumber是数值型的就不需要
datasetVector.Query( "cityname == 'chengdu' ", CursorType.Dynamic);
datasetVector.Query( "areanumber == 028 " , CursorType.Dynamic);
字段操作的坑有两点:
①数据量很大的时候,删除字段会出现删除不了的情况:如下面代码中的“ ClearFieldInfos ”函数用于清空非系统字段的时候,按常理只需要把IsSystemField等于false的删掉就可以了,但是数据量大以后会删不掉,必须while循环一直检查非系统是否被删完,删完了再退出。
②字段拷贝时候,是否保留原来字段携带的DefaultValue(默认值)和IsRequired(是否必填)属性:因为我们有时候只想复制字段的名称、类型、长度等信息,不想要它的默认值和是否必填信息。例如:现有图层A(包含字段a,b,c)和图层B(包含字段a,b),我现在要把B图层相比与A缺少的字段(即字段c)给自动补充到B图层中,如果要保留c字段的默认值,则c字段被添加到B图层后,B图层所有数据的字段c都会被填充上默认值。该坑在函数“ BatchAddField(FieldInfos targetFieldInfos, FieldInfos sourceFieldInfos, bool ignoreDefaultValue = true, bool ignoreRequired = true)”中有所体现。
字段操作已经被封装为一个静态类,完整代码如下:
①先检查是否可以添加到地图中,因为有些datasetVector是表格(Tabular)或者数据库表(linkTable),这些数据不携带Geometry信息,不能添加到地图中。
②检查该图层是否可以被附图层风格,因为如:栅格、模型、遥感影像等是不能被设置图层颜色等的风格信息的。
③随机给图层附上一个现有地图不存在的颜色风格。
代码如下:
10.1 多部件的检查
10.2 多部件的拆解
没什么坑,就是在官方文档里面比较难找,在这里记录一下,代码如下:
tips: 超图的数据导入设计成为了工厂模式,对设计模式不熟的可以参考学习一下
12.1 导入shp文件(坑指数⭐⭐)
导入时的时候,注意要把importSetting的Isimport3D参数设为false ,因为:一个二维点的.shp数据(线、面数据同理),如果用ArcGIS打开后在属性里面勾选了Z坐标,再在超图iObject进行导入,会导入为一个三维点数据(但是在iDesktop里面导入又还是二维的点数据,不知道它官方是怎么进行判断的,我能做的只是把Isimport3D设为false)。设置以后,一个二维数据就算在ArcGIS里面勾选了Z坐标属性,导入进超图后也还是会是二维数据。
12.2 导入MDB文件(坑指数⭐⭐⭐)
需要在电脑上安装一个AccessDatabaseEngine的插件才可以在超图里成功导入MDB数据文件。插件的微软官方下载地址: ,导入代码如下:
12.3 导入TIF文件
导入TIF的坑主要是导入以后影像每个波段都会被单独导入为一张图片,但我们希望的是导入以后就是一张影像,具体的配置如下:
没有坑,但是不好找到,记录一下,true为逆时针,false为顺时针。注:在GIS面要素图层中,顺时针为面,逆时针为洞。
GeoReigon.IsCounterClockwise(int index)
拿得到一个矢量图层datasetVector后,要把图层数据清空的API有两个,一个是DatasetVector自带的truncated方法:
DatasetVector.Truncate() ;
一个是通过找到他的Recordset,再调用Recordset里面的deleteAll方法:
var recordset = datasetVector.getRecordset(false, Cursor.Dynamic);
recordset.deleteAll();
一定要用第二个deleteAll方法!!! 第一个直接truncated会有很严重的bug!!!!(Truncate不能把数据删除干净,出现各种bug,而且还会把datasetvector数据给破坏掉,不能再进行任何的增删改查)被坑了2天
多对象的含义:一条recordset数据里面,有多个geometry,如下图所示,多个分离的图斑组合为了一条数据,也可以理解为有多块飞地的数据。
函数GeoRegion.ProtectedDecompose ,就可以把这些图斑都打散,形成一个个独立的图斑,但是在精度极高的情况下(tolerance在0.001米的时候)会出现bug,如下图所示,有一个很小的图斑(0.000025平方米)和这个多子对象图斑呈邻接关系,在把这个多子对象图斑拆解后,这个小图斑就会和被拆下来的大图版呈分离关系,两个的距离大概有0.0015米。这个的解决方案:无解,是超图内部算法有误。暂时的解决方法就是自己封装一个带tolerance的邻接算法,总体思路就是:datasetvector.query方法找到touched邻接图版 + ProximityAnalyst.ComputeRangeDistance计算离自己0.0015米以内是否有图版,如果有也看做是邻接的,这样就自己封装了一个带有tolerance的邻接搜索函数。
本文地址:http://lianchengexpo.xrbh.cn/quote/11466.html 迅博思语资讯 http://lianchengexpo.xrbh.cn/ , 查看更多