GIS前端将选中的图形输出为Shapfile文件

老师让我实现如题的功能,我对着ArcGIS js api找了半天,没有发现该方法接口,找了很多资料,前后问了三个前辈。

第一个前辈说用GP服务,我在ArcMap的工具箱里找到convert to layerfile这个功能,试过之后。发现该方法的不足之处在于①只能输出整张图层,我希望能选择任意的部分输出②发布成GP服务后,只能控制输入参数(输入的图层),而输出参数(输出的文件名)不能控制。该方法GG。

第二个前辈说,将查询出来的实体写进gdb里。我就找啊找,找啊找,没找到api有这个功能。

后来自己分析查询出来的graphics,分析其dom组成部分,意外的发现,存在attributes和gepmetry两个部分,又发现ArcMap的工具箱里存在JSON TO Feature和Feature  TO JSON两个功能,似乎可以搞点事情出来。此时,正好遇到第三个前辈,我跟他提出了我的问题以及自己的想法,认可了我的观点,并指出不要用现成的工具箱发布GP服务来转,会有问题,用Arcengine二次开发,自己解析。我可是想偷懒的人,放着GP服务不用是不是有点可惜,试了下,ArcMap将点转出为JSON,再将JSON转为点没问题,而转线和面时,问题就出来了,能转出JSON,而不能再将JSON转回去。前辈诚不欺我。

好了,不说废话了,下面介绍我的解决方法,分四步:①graphics转JSON ②JSON转Geometry ③Geometry转Feature ④Feature输出为Shapfile

一、graphics转JSON

我的graphics只有三种简单类型,point,polyline,polygon,拼接字符串的时候要细心,下面是我的代码

  1 //created by YS 20171218
  2 
  3 //判断属性值是字符串?整型?浮点型?
  4 //返回对应于esri的值类型
  5 function checkValueType(value) {
  6     if (/^-?\d*\.\d+$/.test(value))//是否浮点型
  7         return "esriFieldTypeDouble";
  8     else if (/^\d+$/.test(value))//是否整型
  9         return "esriFieldTypeInteger";
 10     else
 11         return "esriFieldTypeString";//字符串型
 12 
 13 }
 14 //******参数类型 graphic集合,必须是单一的点或线或面类型
 15 //******输出类型 json
 16 function convertToJson(graphics) {
 17     var attributes = graphics[0].attributes;//取得属性
 18     //取得属性名
 19     var attributes_name = [];
 20     for (var key in attributes) {
 21         //排除attributes.SHAPE
 22         if (key.toUpperCase() == "SHAPE")
 23             continue;
 24         attributes_name.push(key);
 25     }
 26 
 27     //判断geometryType类型
 28     var geometryType = "";
 29     switch (graphics[0].geometry.type) {
 30         case "polygon":
 31             geometryType = "esriGeometryPolygon";
 32             break;
 33         case "polyline":
 34             geometryType = "esriGeometryPolyline";
 35             break;
 36         case "point":
 37             geometryType = "esriGeometryPoint";
 38             break;
 39         default: break;
 40     }
 41     //
 42     //获取spatialReference
 43     var spatialReference = $.toJSON(graphics[0].geometry.spatialReference);
 44 
 45     //判断属性值类型
 46     var attributes_valueType = [];
 47     for (var j = 0; j < attributes_name.length; j++) {
 48         attributes_valueType[j] = checkValueType(graphics[0].attributes[attributes_name[j]]);
 49     }
 50 
 51     //准备属性名和属性类型
 52     var fields = "";
 53 
 54     for (var i = 0; i < graphics.length; i++) {
 55         var field = "";
 56         for (var j = 0; j < attributes_name.length; j++) {
 57 
 58             if (attributes_valueType[j] == "esriFieldTypeString") {//字符串型字段比其他类型多一个长度属性
 59                 var obj = new Object();
 60                 obj.name = attributes_name[j];
 61                 obj.type = attributes_valueType[j];
 62                 obj.alias = attributes_name[j];
 63                 obj.length = "50";
 64                 field += $.toJSON(obj) + ",";
 65             } else {
 66                 var obj = new Object();
 67                 obj.name = attributes_name[j];
 68                 obj.type = attributes_valueType[j];
 69                 obj.alias = attributes_name[j];
 70                 field += $.toJSON(obj) + ",";
 71             }
 72         }
 73     }
 74     //去掉最后一个逗号
 75     field = field.substring(0, field.length - 1);
 76     //拼接fields
 77     //***********arcmap将要素转json时,输出数据中有FID*********************************************
 78     //***********该json通过ArcEngine转为shapfile时,不需要拼接FID***********************************
 79     //var fields = "{\"name\":\"FID\",\"type\":\"esriFieldTypeOID\",\"alias\":\"FID\"}," + field;
 80     var fields = field;
 81 
 82     //准备features(attributes+geometry)
 83     var features = "";
 84     var attributes = [];
 85     var geometry = [];
 86     //*******比下面注释掉的程序省掉多次循环判断,降低时间复杂度*****
 87     if (geometryType == "esriGeometryPolygon") {
 88         for (var i = 0; i < graphics.length; i++) {
 89             //删除“SHAPE”属性
 90             var attr = graphics[i].attributes;
 91             //SHAPE大小写不确定
 92             delete attr.SHAPE;
 93             delete attr.Shape;
 94             attributes[i] = $.toJSON(attr);
 95             //组织面的geometry
 96             geometry[i] = $.toJSON(graphics[i].geometry.rings);
 97             features += "{\"attributes\":" + attributes[i] + ",\"geometry\":{\"rings\":" + geometry[i] + "}},";
 98         }
 99     } else if (geometryType == "esriGeometryPolyline") {
100         for (var i = 0; i < graphics.length; i++) {
101             //删除“SHAPE”属性
102             var attr = graphics[i].attributes;
103             //SHAPE大小写不确定
104             delete attr.SHAPE;
105             delete attr.Shape;
106             attributes[i] = $.toJSON(attr);
107             //组织线的geometry
108             geometry[i] = $.toJSON(graphics[i].geometry.paths);
109             //如果需要将得到的 线json转成geoJson
110             //path转json后,去掉最外层的中括号[]
111             //geometry[i] = geometry[i].substring(1, geometry[i].length - 1);
112 
113             features += "{\"attributes\":" + attributes[i] + ",\"geometry\":{\"paths\":" + geometry[i] + "}},";
114         }
115     } else {
116         for (var i = 0; i < graphics.length; i++) {
117             //删除“SHAPE”属性
118             var attr = graphics[i].attributes;
119             //SHAPE大小写不确定
120             delete attr.SHAPE;
121             delete attr.Shape;
122             attributes[i] = $.toJSON(attr);
123             //组织点的geometry
124             var geo = new Object();
125             geo.x = graphics[i].geometry.x;
126             geo.y = graphics[i].geometry.y;
127             var geo = $.toJSON(geo);
128             features += "{\"attributes\":" + attributes[i] + ",\"geometry\":" + geo + "},";
129         }
130     }
131     
158 
159     //去掉最后一个逗号
160     features = features.substring(0, features.length - 1);
161 
163 
164     //拼接fieldAliases
165     var fieldAliases = "";
166     for (var i = 0; i < attributes_name.length; i++) {
167         fieldAliases += "\"" + attributes_name[i] + "\":\"" + attributes_name[i] + "\",";
168     }
169     //去掉最后一个逗号
170     fieldAliases = fieldAliases.substring(0, fieldAliases.length - 1);
171 
172     //拼接地图实体Json
173 
174     //var Json = "{\"displayFieldName\":\"\",\"fieldAliases\":{\"FID\":\"FID\"," + fieldAliases + "},\"geometryType\":\"" + geometryType + "\",\"spatialReference\":" + spatialReference + ",\"fields\":[" + fields + "],\"features\":[" + features + "]}";
175     var Json = "{\"displayFieldName\":\"\",\"fieldAliases\":{" + fieldAliases + "},\"geometryType\":\"" + geometryType + "\",\"spatialReference\":" + spatialReference + ",\"fields\":[" + fields + "],\"features\":[" + features + "]}";
176 
177 
178     //console.log(Json);
179     return Json;
180 }

二、JSON转Geometry

接下来的部分就属于ArcEngine二次开发了,已经有一年没碰过它了,捡起来心真累。

ArcEngine提供了JSONConverterGeometryClass接口,用于geometry字符串转geometry对象

 1 class jsonToGeo
 2     {
 3         /// <summary>
 4         /// 将json字符串转成动态对象
 5         /// </summary>
 6         /// <param name="json"></param>
 7         /// <returns></returns>
 8         public dynamic convert(string json)
 9         {
10             var DynamicObject = JsonConvert.DeserializeObject<dynamic>(json);
11             return DynamicObject;
12 
13         }
14 
15         /// <summary>    
16         /// JSON字符串转成IGeometry    
17         /// </summary>    
18         public ESRI.ArcGIS.Geometry.IGeometry GeometryFromJsonString(string strJson, ESRI.ArcGIS.Geometry.esriGeometryType type)
19         {
20             return GeometryFromJsonString(strJson, type, false, false);
21         }
22 
23         /// <summary>    
24         /// JSON字符串转成IGeometry    
25         /// </summary>    
26         public ESRI.ArcGIS.Geometry.IGeometry GeometryFromJsonString(string strJson, ESRI.ArcGIS.Geometry.esriGeometryType type,
27             bool bHasZ, bool bHasM)
28         {
29             ESRI.ArcGIS.esriSystem.IJSONReader jsonReader = new ESRI.ArcGIS.esriSystem.JSONReaderClass();
30             jsonReader.ReadFromString(strJson);
31 
32             ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonCon = new ESRI.ArcGIS.Geometry.JSONConverterGeometryClass();
33             return jsonCon.ReadGeometry(jsonReader, type, bHasZ, bHasM);
34         }
35         /// <summary>  
36         /// IGeometry转成JSON字符串  
37         /// </summary>  
38         public string GeometryToJsonString(ESRI.ArcGIS.Geometry.IGeometry geometry)
39         {
40             ESRI.ArcGIS.esriSystem.IJSONWriter jsonWriter = new ESRI.ArcGIS.esriSystem.JSONWriterClass();
41             jsonWriter.WriteToString();
42 
43             ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonCon = new ESRI.ArcGIS.Geometry.JSONConverterGeometryClass();
44             jsonCon.WriteGeometry(jsonWriter, null, geometry, false);
45 
46             return Encoding.UTF8.GetString(jsonWriter.GetStringBuffer());
47         }
48 
49     }

解析JSON,先将其转成JSON对象,提取出List<IGeometry> 

 1  /// <summary>
 2         /// 将JSON字符串转成Shapfile文件
 3         /// </summary>
 4         /// <param name="json">输入的Json字符串</param>
 5         /// <param name="outputFileFolder">输出的文件地址</param>
 6         /// <param name="ShapeName">输出的文件名(不带后缀)</param>
 7         public static void JsonToShp(string json, string outputFileFolder, string ShapeName)
 8         {
 9             //将json字符串转成动态对象
10             jsonToGeo jTG = new jsonToGeo();
11             var obj = jTG.convert(json);
12 
13             //获取json中的features集
14             var features = obj["features"];
15             int count = obj["features"].Count;//图形个数
16             //obj["features"][0]["geometry"]表示第一个图形的geometry
17 
18             //坐标系
19             int wkid = (int)obj["spatialReference"]["wkid"];
20 
21             //创建SpatialReferenceEnvironmentClass对象
22             ISpatialReferenceFactory2 pSpaRefFactory = new SpatialReferenceEnvironmentClass();
23             //创建地理坐标系对象
24             //IGeographicCoordinateSystem pNewGeoSys = pSpaRefFactory.CreateGeographicCoordinateSystem(gcsType);//4214代表Beijing1954
25             //创建投影坐标系
26             IProjectedCoordinateSystem pGeoSys = pSpaRefFactory.CreateProjectedCoordinateSystem(wkid);//2437 Beijing_1954_3_Degree_GK_CM_120E 
27 
28             //字段集合
29             var fields = obj["fields"];
30             dynamic shpFields;
31             shpFields = fields;
32 
33 
34 
35             //List<IPoint> points = new List<IPoint>();
36             //List<IPolyline> polylines = new List<IPolyline>();
37             //List<IPolygon> polygons = new List<IPolygon>();
38 
39             List<IGeometry> geometryList = new List<IGeometry>();
40 
41             GeoToFeature gtf = new GeoToFeature();
42 
43 
44             string geometryType = obj["geometryType"].ToString();
45             switch (geometryType)
46             {
47                 case "esriGeometryPoint":
48                     for (int i = 0; i < count; i++)
49                     {
50                         IPoint pointLocation = null;
51                         pointLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint) as ESRI.ArcGIS.Geometry.IPoint;
52                         pointLocation.SpatialReference = pGeoSys;
53                         IGeometry point = pointLocation as IGeometry;
54                         //points.Add(pointLocation);
55                         geometryList.Add(point);
56                     }
57                     //创建点shp,并添加字段
58                     gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPoint, pGeoSys, shpFields);
59 
60                     break;
61                 case "esriGeometryPolyline":
62                     for (int i = 0; i < count; i++)
63                     {
64                         IPolyline polylineLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline) as IPolyline;
65                         polylineLocation.SpatialReference = pGeoSys;
66                         IGeometry polyline = polylineLocation as IGeometry;
67                         //polylines.Add(polylineLocation);
68                         geometryList.Add(polyline);
69                     }
70                     //创建线shp,并添加字段
71                     gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPolyline, pGeoSys, shpFields);
72                     break;
73                 case "esriGeometryPolygon":
74                     for (int i = 0; i < count; i++)
75                     {
76                         IPolygon polygonLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon) as IPolygon;
77                         polygonLocation.SpatialReference = pGeoSys;
78                         IGeometry polygon = polygonLocation as IGeometry;
79                         //polygons.Add(polygonLocation);
80                         geometryList.Add(polygon);
81                     }
82                     //创建面shp,并添加字段
83                     gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPolygon, pGeoSys, shpFields);
84 
85 
86                     break;
87                 default: break;
88             }
89 
90             //添加要素
91             gtf.AddFeatureByBuffer(outputFileFolder, ShapeName, geometryList, features);
92         }

三、创建Shapfile文件

 1 /// <summary>
 2         /// 创建 shapfile文件并添加字段
 3         /// </summary>
 4         /// <param name="strShapeFolder">存放地址</param>
 5         /// <param name="strShapeName">文件名</param>
 6         /// <param name="geoType">几何类型</param>
 7         /// <param name="geoSys">坐标系统</param>
 8         /// <param name="shpFields">字段集</param>
 9         public void CreateShapefile(string strShapeFolder, string strShapeName, esriGeometryType geoType, IProjectedCoordinateSystem geoSys, dynamic shpFields)
10         {
11             //打开工作空间
12             const string strShapeFieldName = "shape";
13             IWorkspaceFactory pWSF = new ShapefileWorkspaceFactoryClass();
14             IFeatureWorkspace pWS = (IFeatureWorkspace)pWSF.OpenFromFile(strShapeFolder, 0);
15 
16             //如果已存在,那么删除
17             //IFeatureClass pFCChecker = pWS.OpenFeatureClass(strShapeName);
18             //if (pFCChecker != null)
19             //{
20             //    IDataset pds = pFCChecker as IDataset;
21             //    pds.Delete();
22             //}
23 
24             //设置字段集
25             IFields pFields = new FieldsClass();
26             IFieldsEdit pFieldsEdit = (IFieldsEdit)pFields;
27 
28             //设置字段
29             IField pField = new FieldClass();
30             IFieldEdit pFieldEdit = (IFieldEdit)pField;
31 
32             //创建类型为几何类型的字段
33             pFieldEdit.Name_2 = strShapeFieldName;
34             pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;
35 
36             //为esriFieldTypeGeometry类型的字段创建几何定义,包括类型和空间参照 
37             IGeometryDef pGeoDef = new GeometryDefClass();     //The geometry definition for the field if IsGeometry is TRUE.
38             IGeometryDefEdit pGeoDefEdit = (IGeometryDefEdit)pGeoDef;
39             //图形的类型
40             //pGeoDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;
41             pGeoDefEdit.GeometryType_2 = geoType;
42             //pGeoDefEdit.SpatialReference_2 = new UnknownCoordinateSystemClass();
43             pGeoDefEdit.SpatialReference_2 = geoSys;
44 
45             pFieldEdit.GeometryDef_2 = pGeoDef;
46             pFieldsEdit.AddField(pField);
47 
48 
49             for (int i = 0; i < shpFields.Count; i++)
50             {
51                 string type = shpFields[i]["type"].ToString();
52                 esriFieldType esriType = new esriFieldType();
53                 switch (type)
54                 {
55                     case "esriFieldTypeDouble":
56                         esriType = esriFieldType.esriFieldTypeDouble;
57                         break;
58                     case "esriFieldTypeInteger":
59                         esriType = esriFieldType.esriFieldTypeInteger;
60                         break;
61                     case "esriFieldTypeString":
62                         esriType = esriFieldType.esriFieldTypeString;
63                         break;
64                     default: break;
65 
66                 }
67                 pField = new FieldClass();
68                 pFieldEdit = (IFieldEdit)pField;
69                 //arcgis的字段名最多十个字节,十个字母或五个汉字,多出来的部分不显示,而且乱码
70                 pFieldEdit.Name_2 = GetSubString(shpFields[i]["name"].ToString(), 10);
71                 pFieldEdit.Type_2 = esriType;
72                 pFieldsEdit.AddField(pField);
73             }
74 
75             //创建shapefile
76             try
77             {
78                 pWS.CreateFeatureClass(strShapeName, pFields, null, null, esriFeatureType.esriFTSimple, strShapeFieldName, "");
79             }
80             catch (Exception e)
81             {
82                 //报错的话,说明有同名文件,再次执行能自动删除
83                 throw e;
84             }
85 
86 
94         }

这里有一坑,ArcGIS的字段名最多只支持十个字节,如果添加字段时没有注意到这一点,那么接下来你是无法插入属性的

为此,我准备了截取字符串前n个字节的方法

 1 ///由于ArcGIS的字段最多十个字节,所以只能10字节以内
 2         /// </summary>
 3         /// <param name="origStr">原始字符串</param>
 4         /// <param name="endIndex">提取前endIdex个字节</param>
 5         /// <returns></returns>
 6         public string GetSubString(string origStr, int endIndex)
 7         {
 8             if (origStr == null || origStr.Length == 0 || endIndex < 0)
 9                 return "";
10             int bytesCount = System.Text.Encoding.GetEncoding("gb2312").GetByteCount(origStr);
11             if (bytesCount > endIndex)
12             {
13                 int readyLength = 0;
14                 int byteLength;
15                 for (int i = 0; i < origStr.Length; i++)
16                 {
17                     byteLength = System.Text.Encoding.GetEncoding("gb2312").GetByteCount(new char[] { origStr[i] });
18                     readyLength += byteLength;
19                     if (readyLength == endIndex)
20                     {
21                         origStr = origStr.Substring(0, i + 1);
22                         break;
23                     }
24                     else if (readyLength > endIndex)
25                     {
26                         origStr = origStr.Substring(0, i);
27                         break;
28                     }
29                 }
30             }
31             return origStr;
32         }

四、将要素写入创建的Shapfile中

 1 /// <summary>
 2         /// 向工作空间添加要素
 3         /// </summary>
 4         /// <param name="strShapeFolder">文件路径</param>
 5         /// <param name="strShapeName">文件名</param>
 6         /// <param name="geometryList">几何图形集</param>
 7         /// <param name="objJsonFeatures">json中的feature对象</param>
 8         public void AddFeatureByBuffer(string strShapeFolder, string strShapeName, List<IGeometry> geometryList, dynamic objJsonFeatures)
 9         {
10             //利用缓存向shapefile文件中插入feature
11             //当数据量较大时,IFeatureClass.CreateFeatureBuffer 比 IFeatureClass.CreateFeature 快
12 
13             //打开工作空间
14             IWorkspaceFactory pWSF = new ShapefileWorkspaceFactoryClass();
15             IFeatureWorkspace pWS = (IFeatureWorkspace)pWSF.OpenFromFile(strShapeFolder, 0);
16 
17             //添加要素
18             IFeatureClass featureClass = pWS.OpenFeatureClass(strShapeName);
19 
20             IFeatureCursor featureCursor = featureClass.Insert(true);
21             IFeatureBuffer featureBuffer = featureClass.CreateFeatureBuffer();
22 
23             int i = 0;
24             foreach (IGeometry geometry in geometryList)
25             {
26                 //给每个几何图形赋予属性值
27 
28                 //找到json中的attributes部分
29                 var attributes = objJsonFeatures[i]["attributes"];
30                 foreach (var attribute in attributes)
31                 {
32                     string name = GetSubString(attribute.Name, 10);
33                     string value = attribute.Value.ToString();
34                     int typeFieldIndex = featureClass.FindField(name);
35                     featureBuffer.set_Value(typeFieldIndex, value);
36                 }
37                 // Set the feature buffer's shape and insert it.
38                 featureBuffer.Shape = geometry;
39                 featureCursor.InsertFeature(featureBuffer);
40                 i++;
41             }
42 
43             // Flush the buffer to the geodatabase.
44             featureCursor.Flush();
45 
46 
47         }

综合以上程序,就能将图形输出到指定目录,并自定义文件名

以此随笔,纪念我逝去的两星期时间 T-T

转载于:https://www.cnblogs.com/dangergis/p/8118441.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值