老师让我实现如题的功能,我对着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,拼接字符串的时候要细心,下面是我的代码

 //created by YS 20171218

 //判断属性值是字符串?整型?浮点型?
//返回对应于esri的值类型
function checkValueType(value) {
if (/^-?\d*\.\d+$/.test(value))//是否浮点型
return "esriFieldTypeDouble";
else if (/^\d+$/.test(value))//是否整型
return "esriFieldTypeInteger";
else
return "esriFieldTypeString";//字符串型 }
//******参数类型 graphic集合,必须是单一的点或线或面类型
//******输出类型 json
function convertToJson(graphics) {
var attributes = graphics[0].attributes;//取得属性
//取得属性名
var attributes_name = [];
for (var key in attributes) {
//排除attributes.SHAPE
if (key.toUpperCase() == "SHAPE")
continue;
attributes_name.push(key);
} //判断geometryType类型
var geometryType = "";
switch (graphics[0].geometry.type) {
case "polygon":
geometryType = "esriGeometryPolygon";
break;
case "polyline":
geometryType = "esriGeometryPolyline";
break;
case "point":
geometryType = "esriGeometryPoint";
break;
default: break;
}
//
//获取spatialReference
var spatialReference = $.toJSON(graphics[0].geometry.spatialReference); //判断属性值类型
var attributes_valueType = [];
for (var j = 0; j < attributes_name.length; j++) {
attributes_valueType[j] = checkValueType(graphics[0].attributes[attributes_name[j]]);
} //准备属性名和属性类型
var fields = ""; for (var i = 0; i < graphics.length; i++) {
var field = "";
for (var j = 0; j < attributes_name.length; j++) { if (attributes_valueType[j] == "esriFieldTypeString") {//字符串型字段比其他类型多一个长度属性
var obj = new Object();
obj.name = attributes_name[j];
obj.type = attributes_valueType[j];
obj.alias = attributes_name[j];
obj.length = "50";
field += $.toJSON(obj) + ",";
} else {
var obj = new Object();
obj.name = attributes_name[j];
obj.type = attributes_valueType[j];
obj.alias = attributes_name[j];
field += $.toJSON(obj) + ",";
}
}
}
//去掉最后一个逗号
field = field.substring(0, field.length - 1);
//拼接fields
//***********arcmap将要素转json时,输出数据中有FID*********************************************
//***********该json通过ArcEngine转为shapfile时,不需要拼接FID***********************************
//var fields = "{\"name\":\"FID\",\"type\":\"esriFieldTypeOID\",\"alias\":\"FID\"}," + field;
var fields = field; //准备features(attributes+geometry)
var features = "";
var attributes = [];
var geometry = [];
//*******比下面注释掉的程序省掉多次循环判断,降低时间复杂度*****
if (geometryType == "esriGeometryPolygon") {
for (var i = 0; i < graphics.length; i++) {
//删除“SHAPE”属性
var attr = graphics[i].attributes;
//SHAPE大小写不确定
delete attr.SHAPE;
delete attr.Shape;
attributes[i] = $.toJSON(attr);
//组织面的geometry
geometry[i] = $.toJSON(graphics[i].geometry.rings);
features += "{\"attributes\":" + attributes[i] + ",\"geometry\":{\"rings\":" + geometry[i] + "}},";
}
} else if (geometryType == "esriGeometryPolyline") {
for (var i = 0; i < graphics.length; i++) {
//删除“SHAPE”属性
var attr = graphics[i].attributes;
//SHAPE大小写不确定
delete attr.SHAPE;
delete attr.Shape;
attributes[i] = $.toJSON(attr);
//组织线的geometry
geometry[i] = $.toJSON(graphics[i].geometry.paths);
//如果需要将得到的 线json转成geoJson
//path转json后,去掉最外层的中括号[]
//geometry[i] = geometry[i].substring(1, geometry[i].length - 1); features += "{\"attributes\":" + attributes[i] + ",\"geometry\":{\"paths\":" + geometry[i] + "}},";
}
} else {
for (var i = 0; i < graphics.length; i++) {
//删除“SHAPE”属性
var attr = graphics[i].attributes;
//SHAPE大小写不确定
delete attr.SHAPE;
delete attr.Shape;
attributes[i] = $.toJSON(attr);
//组织点的geometry
var geo = new Object();
geo.x = graphics[i].geometry.x;
geo.y = graphics[i].geometry.y;
var geo = $.toJSON(geo);
features += "{\"attributes\":" + attributes[i] + ",\"geometry\":" + geo + "},";
}
} //去掉最后一个逗号
features = features.substring(0, features.length - 1); //拼接fieldAliases
var fieldAliases = "";
for (var i = 0; i < attributes_name.length; i++) {
fieldAliases += "\"" + attributes_name[i] + "\":\"" + attributes_name[i] + "\",";
}
//去掉最后一个逗号
fieldAliases = fieldAliases.substring(0, fieldAliases.length - 1); //拼接地图实体Json //var Json = "{\"displayFieldName\":\"\",\"fieldAliases\":{\"FID\":\"FID\"," + fieldAliases + "},\"geometryType\":\"" + geometryType + "\",\"spatialReference\":" + spatialReference + ",\"fields\":[" + fields + "],\"features\":[" + features + "]}";
var Json = "{\"displayFieldName\":\"\",\"fieldAliases\":{" + fieldAliases + "},\"geometryType\":\"" + geometryType + "\",\"spatialReference\":" + spatialReference + ",\"fields\":[" + fields + "],\"features\":[" + features + "]}"; //console.log(Json);
return Json;
}

二、JSON转Geometry

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

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

 class jsonToGeo
{
/// <summary>
/// 将json字符串转成动态对象
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
public dynamic convert(string json)
{
var DynamicObject = JsonConvert.DeserializeObject<dynamic>(json);
return DynamicObject; } /// <summary>
/// JSON字符串转成IGeometry
/// </summary>
public ESRI.ArcGIS.Geometry.IGeometry GeometryFromJsonString(string strJson, ESRI.ArcGIS.Geometry.esriGeometryType type)
{
return GeometryFromJsonString(strJson, type, false, false);
} /// <summary>
/// JSON字符串转成IGeometry
/// </summary>
public ESRI.ArcGIS.Geometry.IGeometry GeometryFromJsonString(string strJson, ESRI.ArcGIS.Geometry.esriGeometryType type,
bool bHasZ, bool bHasM)
{
ESRI.ArcGIS.esriSystem.IJSONReader jsonReader = new ESRI.ArcGIS.esriSystem.JSONReaderClass();
jsonReader.ReadFromString(strJson); ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonCon = new ESRI.ArcGIS.Geometry.JSONConverterGeometryClass();
return jsonCon.ReadGeometry(jsonReader, type, bHasZ, bHasM);
}
/// <summary>
/// IGeometry转成JSON字符串
/// </summary>
public string GeometryToJsonString(ESRI.ArcGIS.Geometry.IGeometry geometry)
{
ESRI.ArcGIS.esriSystem.IJSONWriter jsonWriter = new ESRI.ArcGIS.esriSystem.JSONWriterClass();
jsonWriter.WriteToString(); ESRI.ArcGIS.Geometry.JSONConverterGeometryClass jsonCon = new ESRI.ArcGIS.Geometry.JSONConverterGeometryClass();
jsonCon.WriteGeometry(jsonWriter, null, geometry, false); return Encoding.UTF8.GetString(jsonWriter.GetStringBuffer());
} }

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

  /// <summary>
/// 将JSON字符串转成Shapfile文件
/// </summary>
/// <param name="json">输入的Json字符串</param>
/// <param name="outputFileFolder">输出的文件地址</param>
/// <param name="ShapeName">输出的文件名(不带后缀)</param>
public static void JsonToShp(string json, string outputFileFolder, string ShapeName)
{
//将json字符串转成动态对象
jsonToGeo jTG = new jsonToGeo();
var obj = jTG.convert(json); //获取json中的features集
var features = obj["features"];
int count = obj["features"].Count;//图形个数
//obj["features"][0]["geometry"]表示第一个图形的geometry //坐标系
int wkid = (int)obj["spatialReference"]["wkid"]; //创建SpatialReferenceEnvironmentClass对象
ISpatialReferenceFactory2 pSpaRefFactory = new SpatialReferenceEnvironmentClass();
//创建地理坐标系对象
//IGeographicCoordinateSystem pNewGeoSys = pSpaRefFactory.CreateGeographicCoordinateSystem(gcsType);//4214代表Beijing1954
//创建投影坐标系
IProjectedCoordinateSystem pGeoSys = pSpaRefFactory.CreateProjectedCoordinateSystem(wkid);//2437 Beijing_1954_3_Degree_GK_CM_120E //字段集合
var fields = obj["fields"];
dynamic shpFields;
shpFields = fields; //List<IPoint> points = new List<IPoint>();
//List<IPolyline> polylines = new List<IPolyline>();
//List<IPolygon> polygons = new List<IPolygon>(); List<IGeometry> geometryList = new List<IGeometry>(); GeoToFeature gtf = new GeoToFeature(); string geometryType = obj["geometryType"].ToString();
switch (geometryType)
{
case "esriGeometryPoint":
for (int i = ; i < count; i++)
{
IPoint pointLocation = null;
pointLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint) as ESRI.ArcGIS.Geometry.IPoint;
pointLocation.SpatialReference = pGeoSys;
IGeometry point = pointLocation as IGeometry;
//points.Add(pointLocation);
geometryList.Add(point);
}
//创建点shp,并添加字段
gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPoint, pGeoSys, shpFields); break;
case "esriGeometryPolyline":
for (int i = ; i < count; i++)
{
IPolyline polylineLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline) as IPolyline;
polylineLocation.SpatialReference = pGeoSys;
IGeometry polyline = polylineLocation as IGeometry;
//polylines.Add(polylineLocation);
geometryList.Add(polyline);
}
//创建线shp,并添加字段
gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPolyline, pGeoSys, shpFields);
break;
case "esriGeometryPolygon":
for (int i = ; i < count; i++)
{
IPolygon polygonLocation = jTG.GeometryFromJsonString(features[i]["geometry"].ToString(), ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon) as IPolygon;
polygonLocation.SpatialReference = pGeoSys;
IGeometry polygon = polygonLocation as IGeometry;
//polygons.Add(polygonLocation);
geometryList.Add(polygon);
}
//创建面shp,并添加字段
gtf.CreateShapefile(outputFileFolder, ShapeName, esriGeometryType.esriGeometryPolygon, pGeoSys, shpFields); break;
default: break;
} //添加要素
gtf.AddFeatureByBuffer(outputFileFolder, ShapeName, geometryList, features);
}

三、创建Shapfile文件

 /// <summary>
/// 创建 shapfile文件并添加字段
/// </summary>
/// <param name="strShapeFolder">存放地址</param>
/// <param name="strShapeName">文件名</param>
/// <param name="geoType">几何类型</param>
/// <param name="geoSys">坐标系统</param>
/// <param name="shpFields">字段集</param>
public void CreateShapefile(string strShapeFolder, string strShapeName, esriGeometryType geoType, IProjectedCoordinateSystem geoSys, dynamic shpFields)
{
//打开工作空间
const string strShapeFieldName = "shape";
IWorkspaceFactory pWSF = new ShapefileWorkspaceFactoryClass();
IFeatureWorkspace pWS = (IFeatureWorkspace)pWSF.OpenFromFile(strShapeFolder, ); //如果已存在,那么删除
//IFeatureClass pFCChecker = pWS.OpenFeatureClass(strShapeName);
//if (pFCChecker != null)
//{
// IDataset pds = pFCChecker as IDataset;
// pds.Delete();
//} //设置字段集
IFields pFields = new FieldsClass();
IFieldsEdit pFieldsEdit = (IFieldsEdit)pFields; //设置字段
IField pField = new FieldClass();
IFieldEdit pFieldEdit = (IFieldEdit)pField; //创建类型为几何类型的字段
pFieldEdit.Name_2 = strShapeFieldName;
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry; //为esriFieldTypeGeometry类型的字段创建几何定义,包括类型和空间参照
IGeometryDef pGeoDef = new GeometryDefClass(); //The geometry definition for the field if IsGeometry is TRUE.
IGeometryDefEdit pGeoDefEdit = (IGeometryDefEdit)pGeoDef;
//图形的类型
//pGeoDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint;
pGeoDefEdit.GeometryType_2 = geoType;
//pGeoDefEdit.SpatialReference_2 = new UnknownCoordinateSystemClass();
pGeoDefEdit.SpatialReference_2 = geoSys; pFieldEdit.GeometryDef_2 = pGeoDef;
pFieldsEdit.AddField(pField); for (int i = ; i < shpFields.Count; i++)
{
string type = shpFields[i]["type"].ToString();
esriFieldType esriType = new esriFieldType();
switch (type)
{
case "esriFieldTypeDouble":
esriType = esriFieldType.esriFieldTypeDouble;
break;
case "esriFieldTypeInteger":
esriType = esriFieldType.esriFieldTypeInteger;
break;
case "esriFieldTypeString":
esriType = esriFieldType.esriFieldTypeString;
break;
default: break; }
pField = new FieldClass();
pFieldEdit = (IFieldEdit)pField;
//arcgis的字段名最多十个字节,十个字母或五个汉字,多出来的部分不显示,而且乱码
pFieldEdit.Name_2 = GetSubString(shpFields[i]["name"].ToString(), );
pFieldEdit.Type_2 = esriType;
pFieldsEdit.AddField(pField);
} //创建shapefile
try
{
pWS.CreateFeatureClass(strShapeName, pFields, null, null, esriFeatureType.esriFTSimple, strShapeFieldName, "");
}
catch (Exception e)
{
//报错的话,说明有同名文件,再次执行能自动删除
throw e;
} }

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

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

 ///由于ArcGIS的字段最多十个字节,所以只能10字节以内
/// </summary>
/// <param name="origStr">原始字符串</param>
/// <param name="endIndex">提取前endIdex个字节</param>
/// <returns></returns>
public string GetSubString(string origStr, int endIndex)
{
if (origStr == null || origStr.Length == || endIndex < )
return "";
int bytesCount = System.Text.Encoding.GetEncoding("gb2312").GetByteCount(origStr);
if (bytesCount > endIndex)
{
int readyLength = ;
int byteLength;
for (int i = ; i < origStr.Length; i++)
{
byteLength = System.Text.Encoding.GetEncoding("gb2312").GetByteCount(new char[] { origStr[i] });
readyLength += byteLength;
if (readyLength == endIndex)
{
origStr = origStr.Substring(, i + );
break;
}
else if (readyLength > endIndex)
{
origStr = origStr.Substring(, i);
break;
}
}
}
return origStr;
}

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

 /// <summary>
/// 向工作空间添加要素
/// </summary>
/// <param name="strShapeFolder">文件路径</param>
/// <param name="strShapeName">文件名</param>
/// <param name="geometryList">几何图形集</param>
/// <param name="objJsonFeatures">json中的feature对象</param>
public void AddFeatureByBuffer(string strShapeFolder, string strShapeName, List<IGeometry> geometryList, dynamic objJsonFeatures)
{
//利用缓存向shapefile文件中插入feature
//当数据量较大时,IFeatureClass.CreateFeatureBuffer 比 IFeatureClass.CreateFeature 快 //打开工作空间
IWorkspaceFactory pWSF = new ShapefileWorkspaceFactoryClass();
IFeatureWorkspace pWS = (IFeatureWorkspace)pWSF.OpenFromFile(strShapeFolder, ); //添加要素
IFeatureClass featureClass = pWS.OpenFeatureClass(strShapeName); IFeatureCursor featureCursor = featureClass.Insert(true);
IFeatureBuffer featureBuffer = featureClass.CreateFeatureBuffer(); int i = ;
foreach (IGeometry geometry in geometryList)
{
//给每个几何图形赋予属性值 //找到json中的attributes部分
var attributes = objJsonFeatures[i]["attributes"];
foreach (var attribute in attributes)
{
string name = GetSubString(attribute.Name, );
string value = attribute.Value.ToString();
int typeFieldIndex = featureClass.FindField(name);
featureBuffer.set_Value(typeFieldIndex, value);
}
// Set the feature buffer's shape and insert it.
featureBuffer.Shape = geometry;
featureCursor.InsertFeature(featureBuffer);
i++;
} // Flush the buffer to the geodatabase.
featureCursor.Flush(); }

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

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

GIS前端将选中的图形输出为Shapfile文件的更多相关文章

  1. Koala – 开源的前端预处理器语言图形编译工具

    koala 是一个前端预处理器语言图形编译工具,支持 Less.Sass.Compass.CoffeeScript,帮助 Web 开发者更高效地使用它们进行开发.跨平台运行,完美兼容 Windows. ...

  2. (转)用AGG实现高质量图形输出(二)

    本文上接<用AGG实现高质量图形输出(一)>,分别介绍了AGG显示流程中的各个环节. 上次讲了AGG的显示原理并举了一个简单的例子,这一篇文章开始讲AGG工作流程里的每个环节.为了方便对照 ...

  3. C语言 · 图形输出

    算法提高 图形输出   时间限制:1.0s   内存限制:512.0MB      编写一程序,在屏幕上输出如下内容: X | X | X ---+---+--- | | ---+---+--- O ...

  4. C++笔记(7)——一些模拟题:简单模拟、查找元素、图形输出、日期处理、进制转换、字符串处理

    以下内容基本来自<算法笔记>,作者为胡凡,建议直接买书看,我这里只是摘抄部分当笔记,不完整的. 简单模拟 就是一类"题目怎么说你就怎么做"的题目.这类题目不涉及算法,只 ...

  5. 将Matlab中的矩阵输出到txt文件

    将矩阵输出到txt文件中的方法,遍寻网络,始见真经!!! fid=fopen('C:Documents and Settingscleantotal.ped','wt');%写入文件路径 matrix ...

  6. log4j输出日志到文件

    输出端Appender Appender用来指定日志信息输出到哪个地方,可以同时指定多个输出目的地.Log4j允许将信息输出到许多不同的输出设备中,一个log信息输出目的地就叫做一个Appender. ...

  7. C#中使用Log4net日志输出到本地文件、Textbox或Listview

    网上很多配置log4net的方法,但是排行靠前的 根本就没有说明清除,导致浪费了两个小时来搞清楚如何配置,真是无语,特写此文,给那些刚接触log4net的朋友 1.参考链接:http://blog.s ...

  8. Linux将Shelll输出写入到文件

    &>  以覆盖的方式,写入文件 &>> 将输出追加到文件 将命令的正确输出与错误输出都放入文件. /dev/null,垃圾箱. 将无用输出放入垃圾箱. 命令>& ...

  9. 将filenames里的每个字符串输出到out文件对象中注意行首的缩进

    在Linux上用强大的shell脚本应该也可以完成,可是使用Windows的朋友呢?其实象这样一个简单任务用Python这个强大脚本语言只要几条语句就可以搞定了.个大家知道,要完成这样一个任务根本不用 ...

随机推荐

  1. Dijkstra算法(Swift版)

    原理 我们知道,使用Breadth-first search算法能够找到到达某个目标的最短路径,但这个算法没考虑weight,因此我们再为每个edge添加了权重后,我们就需要使用Dijkstra算法来 ...

  2. [转载] Tomcat架构分析

    转载自http://gearever.iteye.com/category/223001

  3. [转]SQL Server 表变量和临时表的区别

    一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约 ...

  4. SQL 之存储过程

    存储过程 是用来执行管理任务或应用复杂的业务规则, 存储过程中可以包含逻辑控制语句和数据操纵语句,它可以接受参数.输出参数.返回单个或多个结果集以及返回值. 存储过程的优点 存储过程已在服务器注册 执 ...

  5. JAVA面试之集合框架(三)

    21.ArrayList和Vector的区别 这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态 ...

  6. JS规范2

    百度SS Javascript编码规范 1.变量.方法命名必须匹配正则:/^[$_a-zA-Z]\w*$/ /** * 虽然Javascript引擎支持多种格式命名的变量, * 比如下面这样的变量,J ...

  7. [NOIP]玩具装箱

    题目:(非常经典的模拟赛题,适合动规入门的OIer) 简要分析:   动态规划,用一维数组 f[i] 表示从位置1 到 位置i 的最优花费 ,由于 f[i ] 以前的最优花费都是确定的,故只需要在 1 ...

  8. 方法的形参、ref参数、out参数的区别

    我们在定义方法时,经常会涉及到传参.因为引用类型的数据在用变量存储时,是存储的地址,所以在传参时,依然是传递的地址,但是值类型的数据在传参时就会有所不同.值类型数据在调用方法传参时,普通情况下是值传递 ...

  9. 史上最全常用正则表达式(Javascript公众号推文)

    2017-04-13 zxin JavaScript很多不太懂正则的朋友,在遇到需要用正则校验数据时,往往是在网上去找很久,结果找来的还是不很符合要求.所以我最近把开发中常用的一些正则表达式整理了一下 ...

  10. mvc约定

    mvc是围绕一些基于约定的默认项,这写默认项在必要时可以覆盖,这个概念通常成为"约定优于配置". 比如没必要在web.config中设置views,models等文件夹的名称,已经 ...