關於ArcShapeFileNet
.net下操作shp文件的類庫不是很多,git上找一找也能找到不少。
但是呢,這麼多年一致用的是Arcgis全家桶,所以呢就找了找,還真找到了一個古老的Arcgis對shp文件操作的類庫。
老歸老,但能滿足需求,所以足夠了。
主要用途是用於dwg轉換shp格式,又不想花錢,又要東西,很爲難。
ArcShapeFileNet到底多少年了,沒深究,但裏面的有些設計,明顯能感覺到很古老,比如數組是從1開始計數。
又比如對編碼格式的支持,中文的只有gb2312,且這個國標android不認識,uft-8是沒有的。
原版類庫獲取方式
1、可以去Arcgis portal資源中心去找,有下載地址
2、百度雲下載
鏈接:https://pan.baidu.com/s/1MjiWsV3eNub33hk9DYTKHg
提取碼:qwsj
這個是官網原版的類庫,不過並不好用,缺點就是中文支持不好,數組都是從1開始計數,不習慣了。
修改過後的類庫和代碼
後來呢,又認真找了找,發現了源碼,不過被修改過,數組從0開始了
有些不合適的屬性和函數也修改過,但還是不支持utf8
所以呢,只好自己加上utf8編碼,重新編譯了一下
源碼和編譯後的dll百度雲
鏈接:https://pan.baidu.com/s/1zKaIERISJli_dXY0amD1aQ
提取碼:nqwi
支持utf8編碼修改代碼很少
eLanguage枚舉增加了 Codepage_UTF_8 = 0x76
GetCodePageName()函數增加了三行代碼
case eLanguage.Codepage_UTF_8:
functionReturnValue = "UTF-8";
break;
SetDelimiter()函數修改了
case eLanguage.Codepage_932_Japanese_Windows:
case eLanguage.Codepage_936_Chinese_Windows:
case eLanguage.Codepage_950_Chinese_Windows:
case eLanguage.Codepage_UTF_8:
DelimterValue = ".";
break;
然後就可以愉快的使用utf8編碼了。以後的代碼都是基於修改後的類庫。
操作shp文件
打開shp文件
//filePath爲shp文件全路徑
public static ShapeFile OpenShapeFile(string filePath)
{
ShapeFile shapeFiles = new ShapeFile();
shapeFiles.Language = eLanguage.Codepage_UTF_8;
shapeFiles.Open(filePath);
return shapeFiles;
}
創建shp文件
//filePath爲shp文件全路徑,type是文件類型
public static ShapeFile CreateShpFile(string filePath, eShapeType type)
{
ShapeFile shapeFiles = new ShapeFile();
shapeFiles.Language = eLanguage.Codepage_UTF_8;
shapeFiles.Open(filePath, type);
return shapeFiles;
}
添加屬性字段
//字段名稱、字段類型、字段長度、精度
//如果是文本字段長度不能超多255、精度可不給
public static void AddField(ShapeFile shapeFiles, string name, eFieldType type, short size = 0, short fieldDecimal = 0)
{
if (shapeFiles == null)
{
return;
}
shapeFiles.Fields.Add(name, type, size, fieldDecimal);
shapeFiles.WriteFieldDefs();
}
添加數據記錄
shapeFiles.Vertices.Add(dBPoint.Position.X, dBPoint.Position.Y);
shapeFiles.Fields[ShpFieldNames.DataType].Value = dBPoint.GetType().Name;
shapeFiles.Fields[ShpFieldNames.Layer].Value = dBPoint.Layer;
shapeFiles.WriteShape();
添加線數據記錄
shapeFiles.Vertices.Add(line.StartPoint.X, line.StartPoint.Y);
shapeFiles.Vertices.Add(line.EndPoint.X, line.EndPoint.Y);
shapeFiles.Fields[ShpFieldNames.DataType].Value = line.GetType().Name;
shapeFiles.Fields[ShpFieldNames.Layer].Value = line.Layer;
shapeFiles.Fields[ShpFieldNames.Code].Value = line.Linetype;
shapeFiles.WriteShape();
這個類庫操作shp很簡單,並不想AO那樣有很複雜的集合圖形結構
這裏都是直接堆點,只要順序堆得堆,其他都不是問題
這個類庫也支持多環,只需要將點放入到shapeFiles.Parts集合裏面就可以。
下面是一個從Patrs屬性獲取多換的例子
for (int i = 0; i < shapeFiles.Parts.Count; i++)
{
Part part = shapeFiles.Parts[i];
using (Polyline polyline = new Polyline())
{
for (int j = part.Begins; j < part.Ends; j++)
{
polyline.AddVertexAt(j - part.Begins, new Point2d(shapeFiles.Vertices[j].X_Cord, shapeFiles.Vertices[j].Y_Cord), 0, 0, 0);
}
blockTableRecord.AppendEntity(polyline);
}
}
遍歷shp文件的數據
//屬性、用法都是比較遠古
ShapeFile shapeFiles = InputShapeFiles[i];
while (!shapeFiles.EOF)
{
OnConvertFeature(shapeFiles, OutputDatabase, blockTableRecord);
shapeFiles.MoveNext();
}
其他
這個庫操作shp效率很高,也不存在鎖死shp文件的問題,用完不關閉文件也不會鎖定shp文件。
其他源碼修改
後來在使用過程中發現對於點類型的數據,shp文件中心點座標信息計算有問題。
看源碼發現如果是點,就沒有去計算中心點值,後來追加了計算代碼。
在ShaprFile文件10130行開始位置
case eShapeType.shpPoint:
if (mvarReadmode != eReadMode.FastRead)
{
if (mvarCentroidX == 0)
{
mvarCentroidX = mvarVertices.xMin;
}
else
{
mvarCentroidX = (mvarVertices.xMin + mvarCentroidX) / 2.0;
}
if (mvarCentroidY == 0)
{
mvarCentroidY = mvarVertices.yMin;
}
else
{
mvarCentroidY = (mvarVertices.yMin + mvarCentroidY) / 2.0;
}
mvarVertices.Add(mvarVertices.xMin, mvarVertices.yMin);
}
break;
case eShapeType.shpPointM:
if (mvarReadmode != eReadMode.FastRead)
{
if (mvarCentroidX == 0)
{
mvarCentroidX = mvarVertices.xMin;
}
else
{
mvarCentroidX = (mvarVertices.xMin + mvarCentroidX) / 2.0;
}
if (mvarCentroidY == 0)
{
mvarCentroidY = mvarVertices.yMin;
}
else
{
mvarCentroidY = (mvarVertices.yMin + mvarCentroidY) / 2.0;
}
MVal = mvarVertices.mMin;
mvarVertices.Add(mvarVertices.xMin, mvarVertices.yMin, MVal);
}
break;
case eShapeType.shpPointZ:
if (mvarReadmode != eReadMode.FastRead)
{
if (mvarCentroidX == 0)
{
mvarCentroidX = mvarVertices.xMin;
}
else
{
mvarCentroidX = (mvarVertices.xMin + mvarCentroidX) / 2.0;
}
if (mvarCentroidY == 0)
{
mvarCentroidY = mvarVertices.yMin;
}
else
{
mvarCentroidY = (mvarVertices.yMin + mvarCentroidY) / 2.0;
}
MVal = mvarVertices.mMin;
mvarVertices.Add(mvarVertices.xMin, mvarVertices.yMin, MVal, Convert.ToDouble(mvarVertices.zMin));
}
break;