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,拼接字符串的时候要细心,下面是我的代码
//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文件的更多相关文章
- Koala – 开源的前端预处理器语言图形编译工具
koala 是一个前端预处理器语言图形编译工具,支持 Less.Sass.Compass.CoffeeScript,帮助 Web 开发者更高效地使用它们进行开发.跨平台运行,完美兼容 Windows. ...
- (转)用AGG实现高质量图形输出(二)
本文上接<用AGG实现高质量图形输出(一)>,分别介绍了AGG显示流程中的各个环节. 上次讲了AGG的显示原理并举了一个简单的例子,这一篇文章开始讲AGG工作流程里的每个环节.为了方便对照 ...
- C语言 · 图形输出
算法提高 图形输出 时间限制:1.0s 内存限制:512.0MB 编写一程序,在屏幕上输出如下内容: X | X | X ---+---+--- | | ---+---+--- O ...
- C++笔记(7)——一些模拟题:简单模拟、查找元素、图形输出、日期处理、进制转换、字符串处理
以下内容基本来自<算法笔记>,作者为胡凡,建议直接买书看,我这里只是摘抄部分当笔记,不完整的. 简单模拟 就是一类"题目怎么说你就怎么做"的题目.这类题目不涉及算法,只 ...
- 将Matlab中的矩阵输出到txt文件
将矩阵输出到txt文件中的方法,遍寻网络,始见真经!!! fid=fopen('C:Documents and Settingscleantotal.ped','wt');%写入文件路径 matrix ...
- log4j输出日志到文件
输出端Appender Appender用来指定日志信息输出到哪个地方,可以同时指定多个输出目的地.Log4j允许将信息输出到许多不同的输出设备中,一个log信息输出目的地就叫做一个Appender. ...
- C#中使用Log4net日志输出到本地文件、Textbox或Listview
网上很多配置log4net的方法,但是排行靠前的 根本就没有说明清除,导致浪费了两个小时来搞清楚如何配置,真是无语,特写此文,给那些刚接触log4net的朋友 1.参考链接:http://blog.s ...
- Linux将Shelll输出写入到文件
&> 以覆盖的方式,写入文件 &>> 将输出追加到文件 将命令的正确输出与错误输出都放入文件. /dev/null,垃圾箱. 将无用输出放入垃圾箱. 命令>& ...
- 将filenames里的每个字符串输出到out文件对象中注意行首的缩进
在Linux上用强大的shell脚本应该也可以完成,可是使用Windows的朋友呢?其实象这样一个简单任务用Python这个强大脚本语言只要几条语句就可以搞定了.个大家知道,要完成这样一个任务根本不用 ...
随机推荐
- 网页如何展示PPT文档
最近再做一个新项目,其中有一个难点,就是如何在网页上展示PPT,我网上找到了几种方法,但是真正符合我目前这个项目的就只有这一种方法了, 使用PowerPoint to Flash将ppt文 ...
- SHA1 安全哈希算法(Secure Hash Algorithm)
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 (Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signatu ...
- IDEA安装步骤详解
IDEA开发工具是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.各类版本工具(git.svn.github ...
- 第一份开发工作,边学边做android
我刚刚毕业,在培训学校学的Java web开发,虽然学的没有大学生那么丰富细致,没有他们理论基础扎实,但是这是我学习软件开发的唯一方式了. 从小学我学习就是倒数2.3等,所有人都认为我是个没法学习的孩 ...
- osap一站式分析模型
运营系统分析平台技术设计: 项目定义于运营系统关键指标的数据分析 关键代码描述: HiveWriter 主要用于写hive表抽象,包括加分区,写hive表,写success文件: import org ...
- C# winform 实现图片轮播
作为一个C#winform刚刚入门的我 觉得这可能是初学者都会遇到的 我自己也觉得很神奇 首先 窗体里有一个Button按钮,和一个pictureBox 图片框 定义一个线程方法 /// < ...
- RecyclerView.ItemDecoration
decoration 英文意思: 英[ˌdekəˈreɪʃn] 美[ˌdɛkəˈreʃən] n. 装饰品; 装饰,装潢; 装饰图案,装饰风格; 奖章; [例句]The decoration and ...
- 项目实战9—企业级分布式存储应用与实战MogileFS、FastDFS
企业级分布式存储应用与实战-mogilefs 环境:公司已经有了大量沉淀用户,为了让这些沉淀用户长期使用公司平台,公司决定增加用户粘性,逐步发展基于社交属性的多样化业务模式,决定开展用户讨论区.卖家秀 ...
- eclipse环境下基于tomcat-7.0.82构建struts2项目
开山第一篇,毕业4个月目前接触最多的框架还是s2sh框架.... 具备完整的开发环境下,在eclipse下启动tomcat出现如下所示画面表示环境构建成功. 第一步:创建web项目,截图如下 此页面只 ...
- h5前端流行的框架
很多时候别人问你,上手的框架有哪些,其实我们都是知道的,只是一时却也说不上哪些比较,这里想给大家介绍一下,我所遇到的,还算好用的框架,做个分享 1 Bootstrap 官网:http://getboo ...