You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1630 lines
78 KiB
1630 lines
78 KiB
using ESRI.ArcGIS.Carto; |
|
using ESRI.ArcGIS.DataSourcesGDB; |
|
using ESRI.ArcGIS.Display; |
|
using ESRI.ArcGIS.Geodatabase; |
|
using ESRI.ArcGIS.Geometry; |
|
using KGIS.Framework.Utils; |
|
using KGIS.Framework.Utils.ExtensionMethod; |
|
using KGIS.Framework.VCT.Entity; |
|
using KGIS.Framework.VCT.Enums; |
|
using KGIS.Framework.VCT.Helper; |
|
using stdole; |
|
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Linq; |
|
|
|
namespace kingo.Plugin.BGResultManager.Helper |
|
{ |
|
public class VCTToMDBHelper3 |
|
{ |
|
public string RootPath { get; set; } |
|
|
|
public void VCTToMDB(string vctfilepath, bool iscreateidx = false) |
|
{ |
|
int i = 0; |
|
try |
|
{ |
|
if (string.IsNullOrEmpty(RootPath)) |
|
{ |
|
throw new Exception("mdb保存路径错误!"); |
|
} |
|
if (!iscreateidx) |
|
{ |
|
//判断VCT索引是否存在,不存在则创建索引 |
|
string vct_idx = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(vctfilepath), System.IO.Path.GetFileNameWithoutExtension(vctfilepath) + "_idx"); |
|
if (System.IO.Directory.Exists(vct_idx)) |
|
{ |
|
DirectoryInfo root = new DirectoryInfo(vct_idx); |
|
FileInfo[] files = root.GetFiles(); |
|
//判断索引文件夹下是否存在idx索引文件,不存在则需要创建索引,存在则不创建 |
|
if (files != null && files.Length > 0 && files.Where(x => x.Extension.Equals(".idx", StringComparison.CurrentCultureIgnoreCase)).Count() > 0) |
|
{ |
|
iscreateidx = false; |
|
} |
|
else |
|
{ |
|
iscreateidx = true; |
|
} |
|
} |
|
else |
|
{ |
|
iscreateidx = true; |
|
} |
|
} |
|
if (iscreateidx) |
|
{ |
|
VCTIndexHelper vctindexhelper = new VCTIndexHelper(); |
|
vctindexhelper.CreateIdxByVCTFile(vctfilepath, false); |
|
} |
|
if (!Directory.Exists(RootPath)) |
|
{ |
|
Directory.CreateDirectory(RootPath); |
|
//Directory.Delete(idxdirectory, true); |
|
} |
|
string mdbfilename = System.IO.Path.GetFileNameWithoutExtension(vctfilepath) + ".mdb"; |
|
string mdbpath = System.IO.Path.Combine(RootPath, mdbfilename); |
|
if (File.Exists(mdbpath)) |
|
{ |
|
File.Delete(mdbpath); |
|
} |
|
VCTFileConvertHelper h = new VCTFileConvertHelper(); |
|
VctVectorData vctdata = h.GetVctVectorData(vctfilepath, false); |
|
string prj = GetprjStr(vctdata); |
|
//创建mdb |
|
CreateMdbFile(RootPath, mdbfilename, vctdata, prj); |
|
//开始导出数据到mdb |
|
//第一步,建varchar索引,放在内存中,bsm,开始位置,结束位置 |
|
using (System.IO.FileStream streamvct = System.IO.File.OpenRead(vctfilepath)) |
|
{ |
|
long attributebeginposition = 0; |
|
Dictionary<int, VctPositionEntity> dicvarchar = new Dictionary<int, VctPositionEntity>(); |
|
Dictionary<string, long> dicConstant = new Dictionary<string, long>(); |
|
Dictionary<string, long> dicRelationtable = new Dictionary<string, long>(); |
|
Dictionary<string, long> dicRepresentation = new Dictionary<string, long>(); |
|
string lineStr = VCTIndexHelper.ReadLine(streamvct); |
|
//读到LINEBEGIN |
|
|
|
while (lineStr != null) |
|
{ |
|
i++; |
|
lineStr = lineStr.Trim().ToUpper(); |
|
if (lineStr == "ATTRIBUTEBEGIN") |
|
{ |
|
attributebeginposition = streamvct.Position; |
|
} |
|
else if (lineStr == "VARCHARBEGIN") |
|
{ |
|
SetVarcharValueToDic(streamvct, dicvarchar, vctdata.VctHead.Separator); |
|
} |
|
//else if (lineStr == "CONSTANTBEGIN")//常量 |
|
//{ |
|
// SetConstantValueToDic(streamvct, dicConstant); |
|
//} |
|
//else if (lineStr == "RELATIONTABLEBEGIN")//值对应 |
|
//{ |
|
// SetRelationtableOrRepresentationValueToDic(streamvct, dicRelationtable, "RELATIONTABLEEND"); |
|
//} |
|
//else if (lineStr == "REPRESENTATIONBEGIN")//图形表现样式 |
|
//{ |
|
// SetRelationtableOrRepresentationValueToDic(streamvct, dicRepresentation, "REPRESENTATIONEND"); |
|
//} |
|
lineStr = VCTIndexHelper.ReadLine(streamvct); |
|
} |
|
using (ESRI.ArcGIS.ADF.ComReleaser comreleaser = new ESRI.ArcGIS.ADF.ComReleaser()) |
|
{ |
|
//第二步,处理无图形的属性表数据 |
|
AccessWorkspaceFactory fac = new AccessWorkspaceFactory(); |
|
IWorkspace pWorkspace = fac.OpenFromFile(mdbpath, 0); |
|
IFeatureWorkspace pFeatureWorkSpace = pWorkspace as IFeatureWorkspace; |
|
comreleaser.ManageLifetime(fac); |
|
comreleaser.ManageLifetime(pWorkspace); |
|
comreleaser.ManageLifetime(pFeatureWorkSpace); |
|
if (vctdata.TableStructureList.Count(x => x.NoneGeometry) > 0) |
|
{ |
|
var nonegeotable = vctdata.TableStructureList.Where(x => x.NoneGeometry).ToList(); |
|
streamvct.Position = attributebeginposition; |
|
InsertDataToNoneGeoTable(streamvct, vctdata, dicvarchar, pFeatureWorkSpace, nonegeotable); |
|
} |
|
string idxdir = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(vctfilepath), System.IO.Path.GetFileNameWithoutExtension(vctfilepath) + "_idx"); |
|
//所有的topo线 |
|
Dictionary<int, VCTIDXEntity> dictopoline = new Dictionary<int, VCTIDXEntity>(); |
|
string idxfilepath = System.IO.Path.Combine(idxdir, "TopoArcs.idx"); |
|
if (File.Exists(idxfilepath))//缓存topo线集合 |
|
{ |
|
ReadTopoArcsIDX(dictopoline, idxfilepath); |
|
} |
|
List<string> templist = new List<string>(); |
|
//插入空间图层 |
|
foreach (var item in vctdata.FeatureCodeTypeList) |
|
{ |
|
VctTableStructureEntity ts = vctdata.TableStructureList.FirstOrDefault(x => x.TableName == item.AttributeTableName); |
|
if (ts == null) |
|
{ |
|
continue; |
|
} |
|
idxfilepath = System.IO.Path.Combine(idxdir, item.AttributeTableName + ".idx"); |
|
if (templist.Count(x => x == idxfilepath) > 0)//记录已经处理过的索引文件,因为有相同属性表名的空间表,此时应该只处理一次 |
|
{ |
|
continue; |
|
} |
|
else |
|
{ |
|
templist.Add(idxfilepath); |
|
} |
|
if (!File.Exists(idxfilepath)) |
|
{ |
|
continue; |
|
} |
|
InsertDataPointAndLine(streamvct, vctdata, dicvarchar, pFeatureWorkSpace, idxfilepath, dictopoline, dicConstant, dicRelationtable, dicRepresentation); |
|
} |
|
} |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
var a = i; |
|
LogAPI.Debug(ex); |
|
throw ex; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 获取prj字符串 |
|
/// 修改时间:2019.1.7 |
|
/// 修改原因:数慧验证我们的VCT坐标参考不正确,借鉴数慧公司处理方法,将坐标参考中 |
|
/// GEOGCS参数GCS_China_Geodetic_Coordinate_System_2000和DATUM['D_China_2000']默认设置,修改后仅支持GGCS2000坐标参考 |
|
/// 修改人:高山 |
|
/// </summary> |
|
/// <param name="vctdata"></param> |
|
/// <returns></returns> |
|
public string GetprjStr(VctVectorData vctdata) |
|
{ |
|
string prj = @"PROJCS['{0}',GEOGCS['GCS_China_Geodetic_Coordinate_System_2000',DATUM['D_China_2000',SPHEROID['{1}',{2},{3}]],PRIMEM['{4}',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['{5}'],PARAMETER['False_Easting',{6}],PARAMETER['False_Northing',{7}],PARAMETER['Central_Meridian',{8}],PARAMETER['Scale_Factor',{9}],PARAMETER['Latitude_Of_Origin',{10}],UNIT['Meter',1.0]]"; |
|
string prj0 = vctdata.VctHead.Spheroid.Split(',')[0]; |
|
string prjName = vctdata.VctHead.Spheroid.Split(',')[0] + "_" + vctdata.VctHead.Parameters.Split(',')[4] + "_Degree_GK_Zone_" + vctdata.VctHead.Parameters.Split(',')[5]; |
|
string prj1 = vctdata.VctHead.Spheroid.Split(',')[1]; |
|
string prj2 = vctdata.VctHead.Spheroid.Split(',')[2]; |
|
string prj3 = vctdata.VctHead.PrimeMeridian; |
|
string prj4 = vctdata.VctHead.Projection; |
|
//string prj4 = "Gauss_Kruger"; |
|
string prj5 = vctdata.VctHead.Parameters.Split(',')[2]; |
|
string prj6 = vctdata.VctHead.Parameters.Split(',')[3]; |
|
string prj7 = vctdata.VctHead.Parameters.Split(',')[0]; |
|
string prj8 = vctdata.VctHead.Parameters.Split(',')[1]; |
|
string prj9 = "0.0";// vctdata.VctHead.Parameters.Split(',')[1]; |
|
if (prj0.StartsWith("CGCS", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
prj = string.Format(prj, prjName, prj0, prj1, prj2, prj3, prj4, prj5, prj6, prj7, prj8, prj9); |
|
} |
|
else//修改前构建坐标参考方式:为了兼容其他坐标参考VCT |
|
{ |
|
prj = @"PROJCS['{0}',GEOGCS['GCS_{0}',DATUM['D_{0}',SPHEROID['{0}',{1},{2}]],PRIMEM['{3}',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['{4}'],PARAMETER['False_Easting',{5}],PARAMETER['False_Northing',{6}],PARAMETER['Central_Meridian',{7}],PARAMETER['Scale_Factor',{8}],PARAMETER['Latitude_Of_Origin',{9}],UNIT['Meter',1.0]]"; |
|
prj = string.Format(prj, prj0, prj1, prj2, prj3, prj4, prj5, prj6, prj7, prj8, prj9); |
|
} |
|
return prj; |
|
} |
|
|
|
/// <summary> |
|
/// 创建MDB |
|
/// </summary> |
|
/// <param name="mdbfolder"></param> |
|
/// <param name="mdbName"></param> |
|
/// <param name="vectordata"></param> |
|
/// <param name="prj"></param> |
|
public void CreateMdbFile(string mdbfolder, string mdbName, VctVectorData vectordata, string prj) |
|
{ |
|
using (ESRI.ArcGIS.ADF.ComReleaser comreleaser = new ESRI.ArcGIS.ADF.ComReleaser()) |
|
{ |
|
IWorkspaceFactory pFtWsFct = new AccessWorkspaceFactory(); |
|
IWorkspaceName workspaceName = pFtWsFct.Create(mdbfolder, mdbName, null, 0); |
|
IWorkspace pWorkSpace = (workspaceName as ESRI.ArcGIS.esriSystem.IName).Open() as IWorkspace; |
|
if (pWorkSpace == null) |
|
{ |
|
new Exception("创建mdb数据库失败"); |
|
} |
|
IFeatureDataset targetFeatureDataset = null; |
|
comreleaser.ManageLifetime(pFtWsFct); |
|
//comreleaser.ManageLifetime(workspaceName); |
|
comreleaser.ManageLifetime(pWorkSpace); |
|
comreleaser.ManageLifetime(targetFeatureDataset); |
|
string datasetName = "TDBZSJJ"; |
|
if (!string.IsNullOrEmpty(datasetName)) |
|
{ |
|
targetFeatureDataset = CreateFeatureDataset(pWorkSpace, datasetName, prj); //创建数据集 |
|
if (targetFeatureDataset == null) |
|
{ |
|
new Exception("创建要素集失败"); |
|
} |
|
} |
|
List<string> tcmclist = new List<string>(); |
|
double MapScale = vectordata.VctHead.MapScale.ToDouble(); |
|
foreach (var item in vectordata.FeatureCodeTypeList) |
|
{ |
|
if (tcmclist.Count(x => x == item.TCMC) > 0) |
|
{ |
|
if (item.TCMC.Trim().Equals("ZJ", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
continue; |
|
} |
|
else |
|
{ |
|
int xh = 1; |
|
while (tcmclist.Count(x => x == item.TCMC) > 0) |
|
{ |
|
item.TCMC = item.TCMC + xh; |
|
xh++; |
|
} |
|
} |
|
} |
|
tcmclist.Add(item.TCMC); |
|
CreateFeatureClassToMdb(pWorkSpace, vectordata.TableStructureList.FirstOrDefault(x => x.TableName == item.AttributeTableName), item, prj, MapScale, targetFeatureDataset); |
|
} |
|
if (vectordata.TableStructureList.Count(x => x.NoneGeometry == true) > 0) |
|
{ |
|
var nonegeolist = vectordata.TableStructureList.Where(x => x.NoneGeometry == true).ToList(); |
|
foreach (var item in nonegeolist) |
|
{ |
|
CreateTableToMdb(pWorkSpace, item); |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 缓存varchar |
|
/// </summary> |
|
/// <param name="vctfilepath"></param> |
|
/// <param name="dicvarchar"></param> |
|
/// <param name="Separator"></param> |
|
public void SetVarcharValueToDic(FileStream stream, Dictionary<int, VctPositionEntity> dicvarchar, string Separator) |
|
{ |
|
int linecount = 0; |
|
//streamvct.Position = 0; |
|
string linestr = string.Empty; |
|
long bsmPosition = 0; |
|
int bsm = 0; |
|
long tablebsmposition = stream.Position; |
|
linestr = VCTIndexHelper.ReadLine(stream).Trim(); |
|
while (!linestr.Equals("VARCHAREND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(linestr)) |
|
{ |
|
continue; |
|
} |
|
//记录标识码的位置 |
|
if (linecount == 0) |
|
{ |
|
bsm = int.Parse(linestr); |
|
} |
|
if (linecount == 1) |
|
{ |
|
bsmPosition = tablebsmposition; |
|
} |
|
//当前线段结束 |
|
if (linestr.Equals(Separator, StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
VctPositionEntity positionentity = new VctPositionEntity(); |
|
positionentity.BeginPosition = bsmPosition; |
|
positionentity.EndPostion = tablebsmposition; |
|
dicvarchar.Add(bsm, positionentity); |
|
linecount = 0; |
|
continue; |
|
} |
|
linecount++; |
|
} |
|
finally |
|
{ |
|
tablebsmposition = stream.Position; |
|
linestr = VCTIndexHelper.ReadLine(stream).Trim(); |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 插入数据到无图形的属性表 |
|
/// </summary> |
|
/// <param name="vctfilepath"></param> |
|
/// <param name="pFeatBuff"></param> |
|
/// <param name="vctdata"></param> |
|
/// <param name="dicvarchar"></param> |
|
/// <param name="pFeatureWorkSpace"></param> |
|
/// <param name="nonegeotable"></param> |
|
private void InsertDataToNoneGeoTable(FileStream streamReader, VctVectorData vctdata, Dictionary<int, VctPositionEntity> dicvarchar, IFeatureWorkspace pFeatureWorkSpace, List<VctTableStructureEntity> nonegeotable) |
|
{ |
|
using (ESRI.ArcGIS.ADF.ComReleaser comreleaser = new ESRI.ArcGIS.ADF.ComReleaser()) |
|
{ |
|
IFields pFlds = null; |
|
ITable resulttable = null; |
|
ICursor ptableCursor = null; |
|
IRowBuffer pRowBuff = null; |
|
comreleaser.ManageLifetime(pFlds); |
|
comreleaser.ManageLifetime(resulttable); |
|
comreleaser.ManageLifetime(ptableCursor); |
|
comreleaser.ManageLifetime(pRowBuff); |
|
List<VctColumnItem> ColumnNameList = null; |
|
string currenttablename = string.Empty; |
|
string linestr = string.Empty; |
|
long tablebsmposition = streamReader.Position; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
while (!linestr.Equals("ATTRIBUTEEND", StringComparison.CurrentCultureIgnoreCase) && nonegeotable.Count > 0) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(linestr)) |
|
{ |
|
continue; |
|
} |
|
if (linestr.Equals("TABLEEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
if (!string.IsNullOrEmpty(currenttablename) && nonegeotable.Count(x => x.TableName.ToUpper() == currenttablename.ToUpper()) > 0) |
|
{ |
|
nonegeotable.Remove(nonegeotable.FirstOrDefault(x => x.TableName.ToUpper() == currenttablename.ToUpper())); |
|
} |
|
currenttablename = string.Empty; |
|
continue; |
|
} |
|
if (string.IsNullOrEmpty(currenttablename)) |
|
{ |
|
currenttablename = linestr; |
|
if (nonegeotable.Count(x => x.TableName.ToUpper() == currenttablename.ToUpper()) <= 0) |
|
{ |
|
currenttablename = string.Empty; |
|
} |
|
else |
|
{ |
|
ColumnNameList = vctdata.TableStructureList.FirstOrDefault(x => x.TableName == currenttablename).Columns; |
|
resulttable = pFeatureWorkSpace.OpenTable(currenttablename); |
|
ptableCursor = resulttable.Insert(true); |
|
pFlds = ptableCursor.Fields; |
|
pRowBuff = resulttable.CreateRowBuffer(); |
|
} |
|
continue; |
|
} |
|
else |
|
{ |
|
try |
|
{ |
|
//插入属性 |
|
linestr = linestr.Substring(linestr.IndexOf(vctdata.VctHead.Separator) + 1); |
|
string[] ColumnValueArry = linestr.Split(vctdata.VctHead.Separator.ToArray()); |
|
//string tempysdm = ColumnValueArry[ColumnNameList.IndexOf(ColumnNameList.FirstOrDefault(x => x.ColumnName == "YSDM"))]; |
|
#region 属性赋值 |
|
SetAttributeValue(streamReader, vctdata, dicvarchar, pFlds, pRowBuff, ColumnNameList, ColumnValueArry); |
|
#endregion |
|
ptableCursor.InsertRow(pRowBuff); |
|
|
|
} |
|
catch (Exception ex) |
|
{ |
|
LogAPI.Debug("导出VCT错误:表:" + currenttablename + "---" + ex); |
|
} |
|
} |
|
} |
|
finally |
|
{ |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private void ReadTopoArcsIDX(Dictionary<int, VCTIDXEntity> dictopoline, string idxfilepath) |
|
{ |
|
using (FileStream streamvct = System.IO.File.OpenRead(idxfilepath)) |
|
{ |
|
string lineStr = VCTIndexHelper.ReadLine(streamvct); |
|
//读到LINEBEGIN |
|
while (lineStr != null) |
|
{ |
|
lineStr = lineStr.Trim().ToUpper(); |
|
if (lineStr == "INDEXBEGIN") |
|
{ |
|
lineStr = VCTIndexHelper.ReadLine(streamvct).Trim(); |
|
while (!lineStr.Equals("INDEXEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(lineStr)) |
|
{ |
|
continue; |
|
} |
|
string[] idxarry = lineStr.Split(',');//当前行索引 |
|
if (idxarry.Length != 7) |
|
{ |
|
continue; |
|
} |
|
VCTIDXEntity idxentity = new VCTIDXEntity() |
|
{ |
|
BSM = int.Parse(idxarry[0]), |
|
ShapePosition = long.Parse(idxarry[5]) |
|
}; |
|
dictopoline.Add(idxentity.BSM, idxentity); |
|
|
|
} |
|
finally |
|
{ |
|
lineStr = VCTIndexHelper.ReadLine(streamvct).Trim(); |
|
} |
|
} |
|
break; |
|
} |
|
lineStr = VCTIndexHelper.ReadLine(streamvct).Trim(); |
|
} |
|
} |
|
} |
|
|
|
private void InsertDataPointAndLine(FileStream streamReader, VctVectorData vctdata, Dictionary<int, VctPositionEntity> dicvarchar, IFeatureWorkspace pFeatureWorkSpace, string idxfilepath, Dictionary<int, VCTIDXEntity> dictopoline, Dictionary<string, long> dicConstant, Dictionary<string, long> dicRelationtable, Dictionary<string, long> dicRepresentation) |
|
{ |
|
using (FileStream streamvct = System.IO.File.OpenRead(idxfilepath)) |
|
{ |
|
string lineStr = VCTIndexHelper.ReadLine(streamvct); |
|
//读到LINEBEGIN |
|
while (lineStr != null) |
|
{ |
|
lineStr = lineStr.Trim().ToUpper(); |
|
if (lineStr == "INDEXBEGIN") |
|
{ |
|
using (ESRI.ArcGIS.ADF.ComReleaser comreleaser = new ESRI.ArcGIS.ADF.ComReleaser()) |
|
{ |
|
IGeometryFactory3 factory = new GeometryEnvironment() as IGeometryFactory3; |
|
IFeatureClass resultFeatureClass = null; |
|
//向shape文件shape赋值 |
|
IFeatureCursor pFeatCur = null; |
|
IFeatureBuffer pFeatBuff = null; |
|
IFields pFlds = null; |
|
comreleaser.ManageLifetime(factory); |
|
comreleaser.ManageLifetime(resultFeatureClass); |
|
comreleaser.ManageLifetime(pFeatCur); |
|
comreleaser.ManageLifetime(pFeatBuff); |
|
comreleaser.ManageLifetime(pFlds); |
|
|
|
List<VctColumnItem> ColumnNameList = null; |
|
string ysdm = string.Empty; |
|
string currenttablename = string.Empty; |
|
GeoTypeEnum geotype = GeoTypeEnum.ANNOTATION; |
|
byte[] buffer = new byte[256]; |
|
lineStr = VCTIndexHelper.ReadLine(streamvct).Trim(); |
|
while (!lineStr.Equals("INDEXEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(lineStr)) |
|
{ |
|
continue; |
|
} |
|
string[] idxarry = lineStr.Split(',');//当前行索引 |
|
if (idxarry.Length != 7) |
|
{ |
|
continue; |
|
} |
|
//图斑索引文件对应的BSM |
|
//if (idxarry[0].Equals("526509")) |
|
//{ |
|
|
|
//} |
|
//else |
|
//{ |
|
// continue; |
|
//} |
|
streamReader.Position = long.Parse(idxarry[5]); |
|
List<string> linelist = ReadLine(streamReader, buffer, 2);//前两行,标识码和要素代码 |
|
if (linelist == null || linelist.Count != 2 || linelist[0] != idxarry[0])//为空、没有两行、或者标识码不相等就不处理 |
|
{ |
|
continue; |
|
} |
|
if (ysdm != linelist[1])//判断当前要素代码是否和上次打开的图层一致,不一致,重新打开图层 |
|
{ |
|
var featurecodetype = vctdata.FeatureCodeTypeList.FirstOrDefault(x => x.Code == linelist[1]); |
|
if (featurecodetype == null) |
|
{ |
|
featurecodetype = vctdata.FeatureCodeTypeList.FirstOrDefault(x => x.AttributeTableName == currenttablename); |
|
} |
|
ColumnNameList = vctdata.TableStructureList.FirstOrDefault(x => x.TableName == featurecodetype.AttributeTableName).Columns; |
|
currenttablename = featurecodetype.TCMC; |
|
geotype = featurecodetype.GeoType; |
|
resultFeatureClass = pFeatureWorkSpace.OpenFeatureClass(currenttablename); |
|
if (pFeatCur != null) |
|
{ |
|
pFeatCur.Flush(); |
|
} |
|
pFeatCur = resultFeatureClass.Insert(true); |
|
pFlds = resultFeatureClass.Fields; |
|
pFeatBuff = resultFeatureClass.CreateFeatureBuffer(); |
|
} |
|
ysdm = linelist[1]; |
|
long shapeposition = streamReader.Position; |
|
//读取属性 |
|
string[] ColumnValueArry = null; |
|
long attributepos = long.Parse(idxarry[6]); |
|
if (attributepos > 0)//有属性 |
|
{ |
|
streamReader.Position = attributepos; |
|
//插入属性 |
|
lineStr = VCTIndexHelper.ReadLine(streamReader); |
|
lineStr = RegexReplace(lineStr.Substring(lineStr.IndexOf(vctdata.VctHead.Separator) + 1)); |
|
ColumnValueArry = lineStr.Split(vctdata.VctHead.Separator.ToArray()); |
|
SetAttributeValue(streamReader, vctdata, dicvarchar, pFlds, pFeatBuff as IRowBuffer, ColumnNameList, ColumnValueArry); |
|
} |
|
//读取空间图形 |
|
streamReader.Position = shapeposition; |
|
switch (geotype) |
|
{ |
|
case GeoTypeEnum.POINT: |
|
case GeoTypeEnum.LINE: |
|
case GeoTypeEnum.POLYGON: |
|
IGeometry geo = GetGeo(streamReader, factory, geotype, dictopoline); |
|
//if (geo.GeometryType == esriGeometryType.esriGeometryPolygon) |
|
//{ |
|
// if (IsSelfCross(geo)) |
|
// { |
|
// IsSimple(ref geo); |
|
// } |
|
//} |
|
pFeatBuff.Shape = geo;//.set_Value(pFlds.FindField("SHAPE"), geo); |
|
//ISpatialReferenceTolerance tolerance = (resultFeatureClass as ESRI.ArcGIS.Geodatabase.IGeoDataset).SpatialReference as ISpatialReferenceTolerance; |
|
break; |
|
case GeoTypeEnum.ANNOTATION: |
|
IAnnotationFeature2 pAnnoFeature = pFeatBuff as IAnnotationFeature2; |
|
if (ColumnValueArry != null) |
|
{ |
|
pAnnoFeature.Status = esriAnnotationStatus.esriAnnoStatusPlaced; |
|
pAnnoFeature.Annotation = GetAnnotation(streamReader, factory, ColumnNameList, ColumnValueArry); |
|
} |
|
//pAnnoFeature.Annotation = GetAnnotation(streamReader, factory, dicConstant, dicRelationtable, dicRepresentation); |
|
break; |
|
default: |
|
break; |
|
} |
|
pFeatCur.InsertFeature(pFeatBuff); |
|
} |
|
catch |
|
{ |
|
} |
|
//catch (Exception ex) |
|
//{ |
|
// LogAPI.Debug(ex); |
|
//} |
|
finally |
|
{ |
|
lineStr = VCTIndexHelper.ReadLine(streamvct).Trim(); |
|
} |
|
} |
|
if (pFeatCur != null) |
|
{ |
|
pFeatCur.Flush(); |
|
} |
|
//RepairGeometry(resultFeatureClass); |
|
} |
|
break; |
|
} |
|
lineStr = VCTIndexHelper.ReadLine(streamvct); |
|
} |
|
} |
|
} |
|
|
|
private string RegexReplace(string str) |
|
{ |
|
return System.Text.RegularExpressions.Regex.Replace(str, @"\t", "\r\n"); |
|
} |
|
|
|
/// <summary> |
|
/// 创建要素数据集 |
|
/// </summary> |
|
/// <param name="workspace"></param> |
|
/// <param name="datasetName"></param> |
|
/// <returns></returns> |
|
public IFeatureDataset CreateFeatureDataset(IWorkspace workspace, string datasetName, string prj) |
|
{ |
|
try |
|
{ |
|
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspace; |
|
//创建要素集 |
|
IFeatureDataset featureDataset = featureWorkspace.CreateFeatureDataset(datasetName, GetSpatialReference(prj, workspace)); |
|
return featureDataset; |
|
} |
|
catch (Exception ex) |
|
{ |
|
throw ex; |
|
} |
|
} |
|
|
|
public ISpatialReference GetSpatialReference(string prj, IWorkspace workspace) |
|
{ |
|
//创建一个要素集创建一个投影 |
|
ISpatialReferenceFactory pSpatialRefFac = new SpatialReferenceEnvironmentClass(); |
|
ISpatialReference spatialReference; |
|
int s; |
|
//prj = "PROJCS['CGCS2000_3_Degree_GK_Zone_40',GEOGCS['GCS_China_Geodetic_Coordinate_System_2000',DATUM['D_China_2000',SPHEROID['CGCS2000',6378137.0,298.257222101]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Gauss_Kruger'],PARAMETER['False_Easting',40500000.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',120.0],PARAMETER['Scale_Factor',1.0],PARAMETER['Latitude_Of_Origin',0.0],UNIT['Meter',1.0],AUTHORITY['EPSG',4528]]"; |
|
/* |
|
* 修改人:高山 |
|
* 修改时间:2018.12.4 |
|
* 修改原因:北京评测部分公司此处是中文“高斯-克吕格投影”,此次pSpatialRefFac.CreateESRISpatialReference无法创建坐标参考 |
|
*/ |
|
prj = prj.Replace("'", "\"").Replace("高斯-克吕格投影", "GAUSS_KRUGER"); |
|
pSpatialRefFac.CreateESRISpatialReference(prj, out spatialReference, out s); |
|
//确定是否支持高精度存储空间 |
|
Boolean supportsHighPrecision = false; |
|
IWorkspaceProperties workspaceProperties = (IWorkspaceProperties)workspace; |
|
IWorkspaceProperty workspaceProperty = workspaceProperties.get_Property |
|
(esriWorkspacePropertyGroupType.esriWorkspacePropertyGroup, |
|
(int)esriWorkspacePropertyType.esriWorkspacePropSupportsHighPrecisionStorage); |
|
if (workspaceProperty.IsSupported) |
|
{ |
|
supportsHighPrecision = Convert.ToBoolean(workspaceProperty.PropertyValue); |
|
} |
|
//设置投影精度 |
|
IControlPrecision2 controlPrecision = (IControlPrecision2)spatialReference; |
|
controlPrecision.IsHighPrecision = supportsHighPrecision; |
|
//设置容差 |
|
ISpatialReferenceResolution spatialRefResolution = (ISpatialReferenceResolution)spatialReference; |
|
spatialRefResolution.ConstructFromHorizon(); |
|
spatialRefResolution.SetDefaultXYResolution(); |
|
|
|
double Tolerance = 0.0001; |
|
ISpatialReferenceTolerance tolerance = spatialReference as ISpatialReferenceTolerance; |
|
if (tolerance != null) |
|
{ |
|
tolerance.XYTolerance = Tolerance; |
|
tolerance.ZTolerance = Tolerance; |
|
tolerance.MTolerance = Tolerance; |
|
} |
|
//(spatialReference as ISpatialReferenceResolution).set_XYResolution(true, 0.00005); |
|
return spatialReference; |
|
} |
|
|
|
/// <summary> |
|
/// 属性赋值 |
|
/// </summary> |
|
/// <param name="streamReader"></param> |
|
/// <param name="vctdata"></param> |
|
/// <param name="dicvarchar"></param> |
|
/// <param name="pFlds"></param> |
|
/// <param name="pRowBuff"></param> |
|
/// <param name="ColumnNameList"></param> |
|
/// <param name="ColumnValueArry"></param> |
|
private void SetAttributeValue(FileStream streamReader, VctVectorData vctdata, Dictionary<int, VctPositionEntity> dicvarchar, IFields pFlds, IRowBuffer pRowBuff, List<VctColumnItem> ColumnNameList, string[] ColumnValueArry) |
|
{ |
|
for (int i = 0; i < ColumnNameList.Count; i++) |
|
{ |
|
int findex = pFlds.FindField(ColumnNameList[i].ColumnName); |
|
if (findex == -1) |
|
{ |
|
continue; |
|
} |
|
|
|
pRowBuff.set_Value(findex, DBNull.Value);//优先清空上一次的列值 |
|
if (string.IsNullOrEmpty(ColumnValueArry[i])) |
|
{ |
|
continue; |
|
} |
|
ColumnValueArry[i] = GetReplaceDH(ColumnValueArry[i]); |
|
if (pFlds.Field[findex].Type == esriFieldType.esriFieldTypeDate) |
|
{ |
|
try |
|
{ |
|
DateTime? dt = null; |
|
if (ColumnValueArry[i].Length > 8 && ColumnValueArry[i].IndexOf('T') > 0) |
|
{ |
|
dt = DateTime.ParseExact(ColumnValueArry[i], "yyyyMMddTHH:mm:ss", System.Globalization.CultureInfo.CurrentCulture); |
|
} |
|
else if (ColumnValueArry[i].Length == 8) |
|
{ |
|
dt = DateTime.ParseExact(ColumnValueArry[i], "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture); |
|
} |
|
if (dt != null) |
|
{ |
|
pRowBuff.set_Value(findex, dt.Value); |
|
} |
|
} |
|
catch (Exception) |
|
{ |
|
} |
|
} |
|
else if (ColumnNameList[i].ColumnType == VctColumsTypeEnum.VARBIN) |
|
{ |
|
if (!string.IsNullOrEmpty(ColumnValueArry[i])) |
|
{ |
|
#region 外挂文件拷贝 |
|
string newpath = VarBinFileCoby(vctdata.TableStructureList[i].TableName, ColumnValueArry[i]); |
|
pRowBuff.set_Value(findex, newpath); |
|
#endregion |
|
} |
|
} |
|
else if (ColumnNameList[i].ColumnType == VctColumsTypeEnum.VARCHAR) |
|
{ |
|
int varbsm; |
|
int.TryParse(ColumnValueArry[i], out varbsm); |
|
if (varbsm > 0 && dicvarchar.ContainsKey(varbsm)) |
|
{ |
|
pRowBuff.set_Value(findex, GetVarcharValue(streamReader, dicvarchar[varbsm])); |
|
dicvarchar.Remove(varbsm); |
|
} |
|
else |
|
{ |
|
pRowBuff.set_Value(findex, "");//优先清空上一次的列值 |
|
} |
|
} |
|
//屏蔽原因:北京数慧公司认为,VCT数据是什么,转MDB的时候就是什么,不应再对数据四舍五入 |
|
//修改原因:float和double类型的数据需要保留字段精度小数 修改人:高山 修改时间:2018.12.4 |
|
//else if (ColumnNameList[i].ColumnType == VctColumsTypeEnum.FLOAT) |
|
//{ |
|
//如果小数位数和当前列的精度一致,则不需要四舍五入,反之四舍五入 |
|
//if (ColumnValueArry[i].Length - ColumnValueArry[i].IndexOf(".") - 1 <= ColumnNameList[i].Precision) |
|
//{ |
|
// pRowBuff.set_Value(findex, ColumnValueArry[i]); |
|
//} |
|
//else |
|
//{ |
|
// float value = 0f; |
|
// if (float.TryParse(ColumnValueArry[i], out value)) |
|
// { |
|
// if (ColumnNameList[i].Precision > 0) |
|
// { |
|
// pRowBuff.set_Value(findex, Math.Round(value, ColumnNameList[i].Precision, MidpointRounding.AwayFromZero)); |
|
// } |
|
// else |
|
// { |
|
// pRowBuff.set_Value(findex, ColumnValueArry[i]); |
|
// } |
|
// } |
|
//} |
|
//} |
|
//else if (ColumnNameList[i].ColumnType == VctColumsTypeEnum.DOUBLE) |
|
//{ |
|
//如果小数位数和当前列的精度一致,则不需要四舍五入,反之四舍五入 |
|
// if (ColumnValueArry[i].Length - ColumnValueArry[i].IndexOf(".") - 1 <= ColumnNameList[i].Precision) |
|
// { |
|
// pRowBuff.set_Value(findex, ColumnValueArry[i]); |
|
// } |
|
// else |
|
// { |
|
// double value = 0; |
|
// if (double.TryParse(ColumnValueArry[i], out value)) |
|
// { |
|
// if (ColumnNameList[i].Precision > 0) |
|
// { |
|
// pRowBuff.set_Value(findex, Math.Round(value, ColumnNameList[i].Precision, MidpointRounding.AwayFromZero)); |
|
// } |
|
// else |
|
// { |
|
// pRowBuff.set_Value(findex, ColumnValueArry[i]); |
|
// } |
|
// } |
|
// } |
|
//} |
|
else |
|
{ |
|
pRowBuff.set_Value(findex, ColumnValueArry[i]); |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 创建图层到MDB |
|
/// </summary> |
|
/// <param name="pWorkspace"></param> |
|
/// <param name="vctTableStructureEntity"></param> |
|
/// <param name="featurecode"></param> |
|
/// <param name="targetFeatureDataset"></param> |
|
private void CreateFeatureClassToMdb(IWorkspace pWorkspace, VctTableStructureEntity vctTableStructureEntity, VctFeatureCodeEntity featurecode, string prj, double ReferenceScale, IFeatureDataset targetFeatureDataset = null) |
|
{ |
|
esriFeatureType esriFeatureTypetmp = esriFeatureType.esriFTSimple; |
|
try |
|
{ |
|
IFeatureWorkspace pFeatureWorkSpace = pWorkspace as IFeatureWorkspace; |
|
|
|
if (featurecode.GeoType == GeoTypeEnum.ANNOTATION) |
|
{ |
|
CreateAnnotationToMdb(pWorkspace, vctTableStructureEntity, featurecode, prj, ReferenceScale, targetFeatureDataset); |
|
return; |
|
} |
|
IObjectClassDescription ocDescription = new FeatureClassDescriptionClass(); |
|
|
|
IFeatureClassDescription fcDescription = (IFeatureClassDescription)ocDescription; |
|
|
|
IFields fields = ocDescription.RequiredFields; |
|
int shapeFieldIndex = fields.FindField(fcDescription.ShapeFieldName); |
|
IField field = fields.get_Field(shapeFieldIndex); |
|
SetField(ref fields, vctTableStructureEntity); |
|
IGeometryDef geometryDef = field.GeometryDef; |
|
IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef; |
|
switch (featurecode.GeoType) |
|
{ |
|
case GeoTypeEnum.POINT: |
|
geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPoint; |
|
esriFeatureTypetmp = esriFeatureType.esriFTSimple; |
|
break; |
|
case GeoTypeEnum.LINE: |
|
geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline; |
|
esriFeatureTypetmp = esriFeatureType.esriFTSimple; |
|
break; |
|
case GeoTypeEnum.POLYGON: |
|
geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolygon; |
|
esriFeatureTypetmp = esriFeatureType.esriFTSimple; |
|
break; |
|
case GeoTypeEnum.ANNOTATION: |
|
geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolygon; |
|
esriFeatureTypetmp = esriFeatureType.esriFTAnnotation; |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
IFeatureClass resultFeatureClass = null; |
|
if (targetFeatureDataset != null) |
|
{ |
|
resultFeatureClass = targetFeatureDataset.CreateFeatureClass(featurecode.TCMC, fields, |
|
ocDescription.InstanceCLSID, ocDescription.ClassExtensionCLSID, |
|
esriFeatureTypetmp, fcDescription.ShapeFieldName, ""); |
|
} |
|
else |
|
{ |
|
geometryDefEdit.SpatialReference_2 = GetSpatialReference(prj, pFeatureWorkSpace as Workspace); |
|
IFieldChecker fieldChecker = new FieldCheckerClass(); |
|
IEnumFieldError enumFieldError = null; |
|
IFields validatedFields = null; //将传入字段 转成 validatedFields |
|
fieldChecker.ValidateWorkspace = (ESRI.ArcGIS.Geodatabase.IWorkspace)pFeatureWorkSpace; |
|
fieldChecker.Validate(fields, out enumFieldError, out validatedFields); |
|
resultFeatureClass = pFeatureWorkSpace.CreateFeatureClass(featurecode.TCMC, validatedFields, ocDescription.InstanceCLSID, ocDescription.ClassExtensionCLSID, esriFeatureTypetmp, fcDescription.ShapeFieldName, ""); |
|
} |
|
|
|
} |
|
catch (Exception ex) |
|
{ |
|
throw ex; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 创建属性表 |
|
/// </summary> |
|
/// <param name="pWorkspace"></param> |
|
/// <param name="vctTableStructureEntity"></param> |
|
private void CreateTableToMdb(IWorkspace pWorkspace, VctTableStructureEntity vctTableStructureEntity) |
|
{ |
|
try |
|
{ |
|
IFeatureWorkspace pFeatureWorkSpace = pWorkspace as IFeatureWorkspace; |
|
IFields fields = new FieldsClass(); |
|
SetField(ref fields, vctTableStructureEntity); |
|
ESRI.ArcGIS.esriSystem.UID uid = new ESRI.ArcGIS.esriSystem.UIDClass(); |
|
uid.Value = "esriGeoDatabase.Object"; |
|
IFieldChecker fieldChecker = new FieldCheckerClass(); |
|
IEnumFieldError enumFieldError = null; |
|
IFields validatedFields = null; //将传入字段 转成 validatedFields |
|
fieldChecker.ValidateWorkspace = (ESRI.ArcGIS.Geodatabase.IWorkspace)pFeatureWorkSpace; |
|
fieldChecker.Validate(fields, out enumFieldError, out validatedFields); |
|
ITable table = pFeatureWorkSpace.CreateTable(vctTableStructureEntity.TableName, validatedFields, uid, null, ""); |
|
} |
|
catch (Exception ex) |
|
{ |
|
throw ex; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// 创建注记图层 |
|
/// </summary> |
|
/// <param name="pWorkspace"></param> |
|
/// <param name="vctTableStructureEntity"></param> |
|
/// <param name="featurecode"></param> |
|
/// <param name="prj"></param> |
|
/// <param name="targetFeatureDataset"></param> |
|
private void CreateAnnotationToMdb(IWorkspace pWorkspace, VctTableStructureEntity vctTableStructureEntity, VctFeatureCodeEntity featurecode, string prj, double ReferenceScale, IFeatureDataset targetFeatureDataset = null) |
|
{ |
|
try |
|
{ |
|
IFeatureWorkspace pFeatureWorkSpace = pWorkspace as IFeatureWorkspace; |
|
|
|
// Create an annotation class and provide it with a name. |
|
ILabelEngineLayerProperties labelEngineLayerProperties = new LabelEngineLayerPropertiesClass(); |
|
IAnnotateLayerProperties annotateLayerProperties = (IAnnotateLayerProperties)labelEngineLayerProperties; |
|
annotateLayerProperties.Class = "Annotation Class 1"; |
|
// Get the symbol from the annotation class. Make any changes to its properties |
|
// here. |
|
ITextSymbol annotationTextSymbol = labelEngineLayerProperties.Symbol; |
|
ISymbol annotationSymbol = (ISymbol)annotationTextSymbol; |
|
// Create a symbol collection and add the default symbol from the |
|
// annotation class to the collection. Assign the resulting symbol ID |
|
// to the annotation class. |
|
ISymbolCollection symbolCollection = new SymbolCollectionClass(); |
|
ISymbolCollection2 symbolCollection2 = (ISymbolCollection2)symbolCollection; |
|
ISymbolIdentifier2 symbolIdentifier2 = null; |
|
symbolCollection2.AddSymbol(annotationSymbol, "Annotation Class 1", out |
|
symbolIdentifier2); |
|
labelEngineLayerProperties.SymbolID = symbolIdentifier2.ID; |
|
// Add the annotation class to a collection. |
|
IAnnotateLayerPropertiesCollection annotateLayerPropsCollection = new |
|
AnnotateLayerPropertiesCollectionClass(); |
|
annotateLayerPropsCollection.Add(annotateLayerProperties); |
|
|
|
// Create a graphics layer scale object. |
|
IGraphicsLayerScale graphicsLayerScale = new GraphicsLayerScaleClass(); |
|
graphicsLayerScale.ReferenceScale = ReferenceScale; |
|
graphicsLayerScale.Units = ESRI.ArcGIS.esriSystem.esriUnits.esriDecimalDegrees; |
|
|
|
// Create the overposter properties for the standard label engine. |
|
IOverposterProperties overposterProperties = new BasicOverposterPropertiesClass(); // Instantiate a class description object. |
|
IObjectClassDescription ocDescription = new AnnotationFeatureClassDescriptionClass(); |
|
IFeatureClassDescription fcDescription = (IFeatureClassDescription)ocDescription; |
|
// Get the shape field from the class description's required fields. |
|
IFields requiredFields = ocDescription.RequiredFields; |
|
int shapeFieldIndex = requiredFields.FindField(fcDescription.ShapeFieldName); |
|
IField shapeField = requiredFields.get_Field(shapeFieldIndex); |
|
IGeometryDef geometryDef = shapeField.GeometryDef; |
|
IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef; |
|
geometryDefEdit.SpatialReference_2 = GetSpatialReference(prj, pFeatureWorkSpace as Workspace); |
|
// Create the annotation layer factory. |
|
IAnnotationLayerFactory annotationLayerFactory = new FDOGraphicsLayerFactoryClass(); |
|
// Create the annotation feature class and an annotation layer for it. |
|
IAnnotationLayer annotationLayer = annotationLayerFactory.CreateAnnotationLayer |
|
(pFeatureWorkSpace, targetFeatureDataset, featurecode.TCMC, geometryDef, null, |
|
annotateLayerPropsCollection, graphicsLayerScale, symbolCollection, false, |
|
false, false, true, overposterProperties, ""); |
|
|
|
List<IField> fieldlist = GetField(vctTableStructureEntity); |
|
if (fieldlist != null && fieldlist.Count > 0) |
|
{ |
|
IFeatureLayer featureLayer = (IFeatureLayer)annotationLayer; |
|
IFeatureClass featureClass = featureLayer.FeatureClass; |
|
foreach (var item in fieldlist) |
|
{ |
|
if (featureClass.Fields.FindField(item.Name) == -1) |
|
{ |
|
featureClass.AddField(item); |
|
} |
|
} |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
throw ex; |
|
} |
|
} |
|
|
|
public List<string> ReadLine(System.IO.FileStream fs, byte[] buffer, int lineCount = 1) |
|
{ |
|
List<string> valuelist = new List<string>(); |
|
List<byte> linebytes = new List<byte>(); |
|
while (lineCount > 0) |
|
{ |
|
int count = fs.Read(buffer, 0, buffer.Length); |
|
if (count == 0) |
|
{ |
|
break; |
|
} |
|
for (int j = 0; j < count; j++) |
|
{ |
|
if (buffer[j] == 10) |
|
{ |
|
if (j > 0 && buffer[j - 1] == 13) |
|
{ |
|
linebytes.RemoveAt(linebytes.Count - 1); |
|
} |
|
if (linebytes.Count > 0) |
|
{ |
|
valuelist.Add(GetStrByByteArry(linebytes.ToArray())); |
|
linebytes.Clear(); |
|
} |
|
lineCount--; |
|
if (lineCount == 0) |
|
{ |
|
fs.Seek(j - count + 1, SeekOrigin.Current); |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
linebytes.Add(buffer[j]); |
|
} |
|
} |
|
} |
|
return valuelist; |
|
} |
|
|
|
|
|
public IGeometry GetGeo(FileStream streamReader, IGeometryFactory3 factory, GeoTypeEnum geotype, Dictionary<int, VCTIDXEntity> dictopoline) |
|
{ |
|
string geostr = string.Empty; |
|
byte[] geobytearry = null; |
|
switch (geotype) |
|
{ |
|
case GeoTypeEnum.POINT: |
|
geobytearry = GetGeoPointByte(streamReader); |
|
break; |
|
case GeoTypeEnum.LINE: |
|
geobytearry = GetGeoLineByte(streamReader); |
|
|
|
break; |
|
case GeoTypeEnum.POLYGON: |
|
geobytearry = GetGeoPolygonByte(streamReader, dictopoline); |
|
break; |
|
default: |
|
break; |
|
} |
|
if (geobytearry == null) |
|
{ |
|
return null; |
|
} |
|
IGeometry geom = ConvertWKBToGeometry(factory, geobytearry); |
|
if (geom != null && !geom.IsEmpty && geom.GeometryType == esriGeometryType.esriGeometryPolygon && (geom as IArea).Area < 0) |
|
{ |
|
IPolygon pPolygon = geom as IPolygon; |
|
pPolygon.ReverseOrientation(); |
|
} |
|
return geom; |
|
} |
|
|
|
public IElement GetAnnotation(FileStream streamReader, IGeometryFactory3 factory, List<VctColumnItem> ColumnNameList, string[] ColumnValueArry) |
|
{ |
|
Dictionary<string, string> dicannoation = new Dictionary<string, string>(); |
|
for (int i = 0; i < ColumnNameList.Count; i++) |
|
{ |
|
if (string.IsNullOrEmpty(ColumnValueArry[i])) |
|
{ |
|
continue; |
|
} |
|
ColumnValueArry[i] = GetReplaceDH(ColumnValueArry[i]); |
|
dicannoation.Add(ColumnNameList[i].ColumnName, ColumnValueArry[i]); |
|
} |
|
//string[] points = dicannoation["POINT"].ToString().Split(','); |
|
ArrayList result = new ArrayList(); |
|
result.Add((byte)OSGeo.OGR.wkbByteOrder.wkbNDR); |
|
result.AddRange(BitConverter.GetBytes((int)OSGeo.OGR.wkbGeometryType.wkbPoint)); |
|
result.AddRange(BitConverter.GetBytes(double.Parse(dicannoation["ZJDZXJXZB"]))); |
|
result.AddRange(BitConverter.GetBytes(double.Parse(dicannoation["ZJDZXJYZB"]))); |
|
ITextElement textElement = new TextElementClass(); |
|
//textElement.ScaleText = true; |
|
string zjfx = dicannoation.ContainsKey("ZJFX") ? dicannoation["ZJFX"] : "0"; |
|
textElement.Symbol = GetTextElement2(dicannoation, double.Parse(zjfx)); |
|
if (dicannoation.ContainsKey("ZJNR")) |
|
{ |
|
textElement.Text = RegexReplace(dicannoation["ZJNR"]); |
|
} |
|
IElement element = textElement as IElement; |
|
element.Geometry = ConvertWKBToGeometry(factory, (byte[])result.ToArray(typeof(byte))); |
|
return element; |
|
} |
|
|
|
private string GetReplaceDH(string inputstr) |
|
{ |
|
return inputstr.Replace("&", ","); |
|
} |
|
|
|
/// <summary> |
|
/// 外挂文件拷贝 |
|
/// </summary> |
|
/// <param name="tablename"></param> |
|
/// <param name="hsb"></param> |
|
/// <param name="valueobj"></param> |
|
private string VarBinFileCoby(string tablename, object valueobj) |
|
{ |
|
string newpath = string.Empty; |
|
if (File.Exists(valueobj.ToTrim())) |
|
{ |
|
newpath = System.IO.Path.Combine(RootPath, "外挂文件", tablename); |
|
if (!System.IO.Directory.Exists(newpath)) |
|
{ |
|
System.IO.Directory.CreateDirectory(newpath); |
|
} |
|
newpath = System.IO.Path.Combine(newpath, System.IO.Path.GetFileName(valueobj.ToTrim())); |
|
File.Copy(valueobj.ToTrim(), newpath); |
|
} |
|
return newpath; |
|
} |
|
|
|
public string GetVarcharValue(FileStream fs, VctPositionEntity position) |
|
{ |
|
long currentpos = fs.Position; |
|
fs.Position = position.BeginPosition; |
|
byte[] buffer = new byte[position.EndPostion - position.BeginPosition]; |
|
fs.Read(buffer, 0, buffer.Length); |
|
fs.Position = currentpos; |
|
string value = RegexReplace(System.Text.Encoding.GetEncoding("gb2312").GetString(buffer)).TrimEnd(); |
|
return value; |
|
} |
|
|
|
/// <summary> |
|
/// 设置列 |
|
/// </summary> |
|
/// <param name="fields"></param> |
|
/// <param name="lstEntity"></param> |
|
public void SetField(ref IFields fields, VctTableStructureEntity vctTableStructureEntity) |
|
{ |
|
try |
|
{ |
|
IField pField = new FieldClass(); |
|
IFieldEdit pFieldEdit = (IFieldEdit)pField; |
|
IFieldsEdit pFieldsEdit = (IFieldsEdit)fields; |
|
|
|
foreach (var item in vctTableStructureEntity.Columns) |
|
{ |
|
pField = new FieldClass(); |
|
pFieldEdit = (IFieldEdit)pField; |
|
pFieldEdit.Name_2 = item.ColumnName; |
|
switch (item.ColumnType) |
|
{ |
|
case VctColumsTypeEnum.CHAR: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
pFieldEdit.Length_2 = item.Length; |
|
break; |
|
case VctColumsTypeEnum.VARCHAR: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
if (item.Length > 0) |
|
{ |
|
pFieldEdit.Length_2 = item.Length; |
|
} |
|
else |
|
{ |
|
pFieldEdit.Length_2 = 254; |
|
} |
|
break; |
|
case VctColumsTypeEnum.INT: |
|
case VctColumsTypeEnum.INT2: |
|
case VctColumsTypeEnum.INT4: |
|
case VctColumsTypeEnum.INT8: |
|
if (item.Length < 4) |
|
{ |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeSmallInteger; |
|
} |
|
else |
|
{ |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeInteger; |
|
} |
|
pFieldEdit.Length_2 = item.Length; |
|
break; |
|
case VctColumsTypeEnum.FLOAT: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble; |
|
pFieldEdit.Length_2 = item.Length; |
|
pFieldEdit.Precision_2 = item.Precision; |
|
break; |
|
case VctColumsTypeEnum.DATE: |
|
case VctColumsTypeEnum.DATETIME: |
|
case VctColumsTypeEnum.TIME: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeDate; |
|
break; |
|
case VctColumsTypeEnum.VARBIN: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
pFieldEdit.Length_2 = 1024; |
|
break; |
|
default: |
|
break; |
|
} |
|
pFieldsEdit.AddField(pField); |
|
} |
|
|
|
} |
|
catch (Exception) |
|
{ |
|
|
|
throw; |
|
} |
|
} |
|
|
|
public List<IField> GetField(VctTableStructureEntity vctTableStructureEntity) |
|
{ |
|
try |
|
{ |
|
List<IField> result = new List<IField>(); |
|
IField pField = new FieldClass(); |
|
IFieldEdit pFieldEdit = (IFieldEdit)pField; |
|
|
|
foreach (var item in vctTableStructureEntity.Columns) |
|
{ |
|
pField = new FieldClass(); |
|
pFieldEdit = (IFieldEdit)pField; |
|
pFieldEdit.Name_2 = item.ColumnName; |
|
switch (item.ColumnType) |
|
{ |
|
case VctColumsTypeEnum.CHAR: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
pFieldEdit.Length_2 = item.Length; |
|
break; |
|
case VctColumsTypeEnum.VARCHAR: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
pFieldEdit.Length_2 = 2147483647; |
|
break; |
|
case VctColumsTypeEnum.INT: |
|
case VctColumsTypeEnum.INT2: |
|
case VctColumsTypeEnum.INT4: |
|
case VctColumsTypeEnum.INT8: |
|
if (item.Length < 4) |
|
{ |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeSmallInteger; |
|
} |
|
else |
|
{ |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeInteger; |
|
} |
|
pFieldEdit.Length_2 = item.Length; |
|
break; |
|
case VctColumsTypeEnum.FLOAT: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble; |
|
pFieldEdit.Length_2 = item.Length; |
|
pFieldEdit.Precision_2 = item.Precision; |
|
break; |
|
case VctColumsTypeEnum.DATE: |
|
case VctColumsTypeEnum.DATETIME: |
|
case VctColumsTypeEnum.TIME: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeDate; |
|
break; |
|
case VctColumsTypeEnum.VARBIN: |
|
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeString; |
|
pFieldEdit.Length_2 = 1024; |
|
break; |
|
default: |
|
break; |
|
} |
|
result.Add(pField); |
|
} |
|
return result; |
|
|
|
} |
|
catch (Exception) |
|
{ |
|
|
|
throw; |
|
} |
|
} |
|
|
|
public string GetStrByByteArry(byte[] buffer) |
|
{ |
|
return System.Text.Encoding.GetEncoding("gb2312").GetString(buffer.ToArray()).Trim(); |
|
} |
|
|
|
/// <summary> |
|
/// 获取点 |
|
/// </summary> |
|
/// <param name="streamReader"></param> |
|
/// <returns></returns> |
|
public byte[] GetGeoPointByte(FileStream streamReader) |
|
{ |
|
#region 点 |
|
string[] linearry = new string[3]; |
|
int linecount = 0; |
|
string linestr = string.Empty; |
|
long tablebsmposition = streamReader.Position; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
while (!linestr.Equals("POINTEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(linestr)) |
|
{ |
|
continue; |
|
} |
|
//当前段结束 |
|
if (linestr == "0") |
|
{ |
|
string[] pointxy = linearry[2].Split(','); |
|
ArrayList result = new ArrayList(); |
|
result.Add((byte)OSGeo.OGR.wkbByteOrder.wkbNDR); |
|
result.AddRange(BitConverter.GetBytes((int)OSGeo.OGR.wkbGeometryType.wkbPoint)); |
|
result.AddRange(BitConverter.GetBytes(double.Parse(pointxy[0]))); |
|
result.AddRange(BitConverter.GetBytes(double.Parse(pointxy[1]))); |
|
return (byte[])result.ToArray(typeof(byte)); |
|
} |
|
if (linecount < 3)//开始读取 |
|
{ |
|
linearry[linecount] = linestr; |
|
} |
|
linecount++; |
|
} |
|
finally |
|
{ |
|
tablebsmposition = streamReader.Position; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
} |
|
} |
|
#endregion |
|
return null; |
|
} |
|
|
|
public byte[] GetGeoLineByte(FileStream streamReader) |
|
{ |
|
#region 线 |
|
List<string> linelist = GetGeoLineList(streamReader); |
|
if (linelist != null && linelist.Count > 0) |
|
{ |
|
ArrayList pointlist = new ArrayList(); |
|
foreach (var item in linelist) |
|
{ |
|
string[] pointarry = item.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); |
|
if (pointarry.Length < 2) |
|
{ |
|
continue; |
|
} |
|
pointlist.AddRange(BitConverter.GetBytes(double.Parse(pointarry[0]))); |
|
pointlist.AddRange(BitConverter.GetBytes(double.Parse(pointarry[1]))); |
|
} |
|
ArrayList result = new ArrayList(); |
|
result.Add((byte)OSGeo.OGR.wkbByteOrder.wkbNDR); |
|
result.AddRange(BitConverter.GetBytes((int)OSGeo.OGR.wkbGeometryType.wkbLineString)); |
|
result.AddRange(BitConverter.GetBytes(pointlist.Count / 16)); |
|
result.AddRange(pointlist); |
|
return (byte[])result.ToArray(typeof(byte)); |
|
} |
|
#endregion |
|
return null; |
|
} |
|
|
|
public byte[] GetGeoPolygonByte(FileStream streamReader, Dictionary<int, VCTIDXEntity> dictopoline) |
|
{ |
|
#region 面 |
|
int linecount = 0; |
|
string linestr = string.Empty; |
|
long tablebsmposition = streamReader.Position; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
List<List<int>> polygontolinebsmlist = new List<List<int>>(); |
|
List<ArrayList> polygontolineArrayList = new List<ArrayList>(); |
|
while (!linestr.Equals("POLYGONEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(linestr)) |
|
{ |
|
continue; |
|
} |
|
//当前段结束 |
|
if (linestr == "0") |
|
{ |
|
if (polygontolinebsmlist.Count == 0) |
|
{ |
|
return null; |
|
} |
|
|
|
byte[] buffer = new byte[256]; |
|
foreach (var linebsmlist in polygontolinebsmlist) |
|
{ |
|
double[] linebeginxy = new double[] { double.MinValue, double.MinValue }; |
|
ArrayList itemArrayList = new ArrayList(); |
|
foreach (var linebsm in linebsmlist) |
|
{ |
|
int bsm = Math.Abs(linebsm); |
|
if (dictopoline.ContainsKey(bsm)) |
|
{ |
|
streamReader.Position = dictopoline[bsm].ShapePosition; |
|
List<string> linelist = ReadLine(streamReader, buffer, 2);//前两行,标识码和要素代码 |
|
if (linelist == null || linelist.Count != 2 || linelist[0] != bsm.ToString())//为空、没有两行、或者标识码不相等就不处理 |
|
{ |
|
continue; |
|
} |
|
List<string> linepointlist = GetGeoLineList(streamReader); |
|
if (linepointlist != null && linepointlist.Count > 0) |
|
{ |
|
if (linebsm < 0) |
|
{ |
|
linepointlist.Reverse(); |
|
} |
|
foreach (var linepointstr in linepointlist) |
|
{ |
|
string[] xy = linepointstr.Split(','); |
|
double x = double.Parse(xy[0]); |
|
double y = double.Parse(xy[1]); |
|
if (linebeginxy[0] == x && linebeginxy[1] == y) |
|
{ |
|
continue; |
|
} |
|
linebeginxy[0] = x; |
|
linebeginxy[1] = y; |
|
itemArrayList.AddRange(BitConverter.GetBytes(x)); |
|
itemArrayList.AddRange(BitConverter.GetBytes(y)); |
|
} |
|
} |
|
} |
|
} |
|
if (itemArrayList.Count >= 48)//一个面至少有三个点,所以此处判断必须大于等于48 |
|
{ |
|
polygontolineArrayList.Add(itemArrayList); |
|
} |
|
} |
|
if (polygontolineArrayList.Count > 0) |
|
{ |
|
ArrayList result = new ArrayList(); |
|
result.Add((byte)OSGeo.OGR.wkbByteOrder.wkbNDR); |
|
result.AddRange(BitConverter.GetBytes((int)OSGeo.OGR.wkbGeometryType.wkbPolygon)); |
|
result.AddRange(BitConverter.GetBytes(polygontolineArrayList.Count)); |
|
foreach (var item in polygontolineArrayList) |
|
{ |
|
result.AddRange(BitConverter.GetBytes(item.Count / 16)); |
|
result.AddRange(item); |
|
} |
|
return (byte[])result.ToArray(typeof(byte)); |
|
} |
|
break; |
|
} |
|
if (linecount > 4)//开始读取坐标 |
|
{ |
|
string[] pointarry = linestr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); |
|
foreach (var item in pointarry) |
|
{ |
|
int bsm = int.Parse(item); |
|
if (bsm != 0) |
|
{ |
|
if (polygontolinebsmlist.Count == 0) |
|
{ |
|
polygontolinebsmlist.Add(new List<int>()); |
|
} |
|
polygontolinebsmlist[polygontolinebsmlist.Count - 1].Add(bsm); |
|
} |
|
else |
|
{ |
|
polygontolinebsmlist.Add(new List<int>()); |
|
} |
|
} |
|
} |
|
linecount++; |
|
} |
|
finally |
|
{ |
|
tablebsmposition = streamReader.Position; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
} |
|
} |
|
#endregion |
|
return null; |
|
} |
|
|
|
public IGeometry ConvertWKBToGeometry(IGeometryFactory3 factory, byte[] wkb) |
|
{ |
|
IGeometry geom; |
|
int countin = wkb.GetLength(0); |
|
factory.CreateGeometryFromWkbVariant(wkb, out geom, out countin); |
|
return geom; |
|
} |
|
|
|
public ITextSymbol GetTextElement2(Dictionary<string, string> dicannoation, double angle) |
|
{ |
|
float[] dxfarry = new float[3];//字体大小:高度,宽度,间隔:TODO此处还不知道怎么设置字体的大小 |
|
dxfarry[0] = 2.5f; |
|
dxfarry[1] = 2.5f; |
|
dxfarry[2] = 0; |
|
if (dicannoation.ContainsKey("BS")) |
|
{ |
|
float.TryParse(dicannoation["BS"], out dxfarry[0]); |
|
} |
|
if (dicannoation.ContainsKey("KD")) |
|
{ |
|
float.TryParse(dicannoation["KD"], out dxfarry[1]); |
|
} |
|
if (dicannoation.ContainsKey("JG")) |
|
{ |
|
float.TryParse(dicannoation["JG"], out dxfarry[2]); |
|
} |
|
string[] ysarry = null; |
|
string zt = string.Empty; |
|
if (dicannoation.ContainsKey("ZT")) |
|
{ |
|
zt = dicannoation["ZT"]; |
|
} |
|
else |
|
{ |
|
zt = "宋体"; |
|
} |
|
if (dicannoation.ContainsKey("YS")) |
|
{ |
|
ysarry = dicannoation["YS"].Split(','); |
|
} |
|
if (ysarry == null || ysarry.Length < 3) |
|
{ |
|
ysarry = new string[] { "0", "0", "0" }; |
|
} |
|
int bold = 0; |
|
if (dicannoation.ContainsKey("XZ")) |
|
{ |
|
int.TryParse(dicannoation["XZ"], out bold); |
|
} |
|
int underline = 0; |
|
if (dicannoation.ContainsKey("XHX")) |
|
{ |
|
int.TryParse(dicannoation["XHX"], out underline); |
|
} |
|
ITextSymbol textSymbol = new TextSymbolClass(); |
|
textSymbol.Color = ColorCustom(int.Parse(ysarry[0]), int.Parse(ysarry[1]), int.Parse(ysarry[2])); |
|
////不可以直接修改textSymbol.Font.Bold等属性,无效 |
|
stdole.IFontDisp font = GetIFontDisp(underline > 0, zt); |
|
font.Bold = bold > 400; |
|
textSymbol.Font = font; |
|
textSymbol.Angle = 180 / Math.PI * angle; //弧度转为角度 ; |
|
textSymbol.Size = Convert.ToDouble(dxfarry[0]); |
|
|
|
//保证点在注记的左下角 |
|
textSymbol.HorizontalAlignment = esriTextHorizontalAlignment.esriTHALeft; |
|
textSymbol.VerticalAlignment = esriTextVerticalAlignment.esriTVABaseline; |
|
|
|
//add by tornado |
|
textSymbol.HorizontalAlignment = esriTextHorizontalAlignment.esriTHACenter; |
|
textSymbol.VerticalAlignment = esriTextVerticalAlignment.esriTVACenter; |
|
return textSymbol; |
|
} |
|
|
|
public List<string> GetGeoLineList(FileStream streamReader) |
|
{ |
|
#region 线 |
|
int linecount = 0; |
|
string linestr = string.Empty; |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
List<string> pointlist = new List<string>(); |
|
while (!linestr.Equals("LINEEND", StringComparison.CurrentCultureIgnoreCase)) |
|
{ |
|
try |
|
{ |
|
if (string.IsNullOrWhiteSpace(linestr)) |
|
{ |
|
continue; |
|
} |
|
//当前段结束 |
|
if (linestr == "0") |
|
{ |
|
return pointlist; |
|
} |
|
if (linecount > 4)//开始读取坐标 |
|
{ |
|
string[] pointarry = linestr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); |
|
if (pointarry.Length < 2) |
|
{ |
|
continue; |
|
} |
|
pointlist.Add(linestr); |
|
} |
|
linecount++; |
|
} |
|
finally |
|
{ |
|
linestr = VCTIndexHelper.ReadLine(streamReader).Trim(); |
|
} |
|
} |
|
#endregion |
|
return null; |
|
} |
|
|
|
/// <summary> |
|
/// 自定义颜色 |
|
/// </summary> |
|
/// <param name="r">The r.</param> |
|
/// <param name="g">The g.</param> |
|
/// <param name="b">The b.</param> |
|
/// <returns>IRgbColor</returns> |
|
/// <remarks></remarks> |
|
private IRgbColor ColorCustom(int r, int g, int b) |
|
{ |
|
IRgbColor myColor = new RgbColor(); |
|
myColor.Red = r; |
|
myColor.Blue = b; |
|
myColor.Green = g; |
|
return myColor; |
|
|
|
} |
|
|
|
/// <summary> |
|
/// 字体设置 |
|
/// </summary> |
|
/// <param name="size">The size.</param> |
|
/// <param name="fontname">The fontname.</param> |
|
/// <returns> |
|
/// IFontDisp |
|
/// </returns> |
|
public stdole.IFontDisp GetIFontDisp(bool underline, string fontname) |
|
{ |
|
IFontDisp font = new StdFontClass() as IFontDisp; |
|
font.Name = fontname; |
|
font.Underline = underline; |
|
//string fontFamilyName = fontname; |
|
//FontStyle fontStyle = FontStyle.Regular; |
|
//Font font = new Font(fontname, float.Parse(size.ToString()) * 96 / 85, fontStyle); |
|
//return ESRI.ArcGIS.ADF.COMSupport.OLE.GetIFontDispFromFont(font) as stdole.IFontDisp; |
|
return font; |
|
} |
|
} |
|
|
|
public class VctPositionEntity |
|
{ |
|
public long BeginPosition { get; set; } |
|
|
|
public long EndPostion { get; set; } |
|
} |
|
}
|
|
|