1 使用 Project 与 ProjectEx 实现要素投影转换
使用 IGeometry5.Project 与 ProjectEx 方法 对要素进行投影转换
/// <summary>
/// 要素类从现有投影转换为新的投影
/// </summary>
/// <param name="featureClass">要素类</param>
/// <param name="newSpatialReference">新的坐标参考系</param>
/// <param name="out_path">输出路径</param>
/// <param name="out_name">输出要素类名</param>
/// <param name="out_featureDataset_name">输出路径为Geodatabae时, 要素数据集名</param>
/// <param name="esriSRGeoTransformationTypeObject">地理基准面转换方式</param>
/// <returns></returns>
public IFeatureClass Project(IFeatureClass featureClass,
ISpatialReference newSpatialReference,
string out_path,
string out_name,
string out_featureDataset_name = null,
object esriSRGeoTransformationTypeObject = null)
{
var geoDataset = (IGeoDataset)featureClass;
var spatialReference = geoDataset.SpatialReference;
IClone comparison = spatialReference as IClone;
if (comparison.IsEqual((IClone)newSpatialReference))
return null;
// 检查地理基准面转换
int gTransformationType = int.MinValue;
if (esriSRGeoTransformationTypeObject is esriSRGeoTransformationType)
gTransformationType = (int)esriSRGeoTransformationTypeObject;
else if (esriSRGeoTransformationTypeObject is esriSRGeoTransformation2Type)
gTransformationType = (int)esriSRGeoTransformationTypeObject;
else if (esriSRGeoTransformationTypeObject is esriSRGeoTransformation3Type)
gTransformationType = (int)esriSRGeoTransformationTypeObject;
IGeoTransformation geoTransformation = null;
if (gTransformationType != int.MinValue)
{
ISpatialReferenceFactory2 spatialReferenceFactory2 = new SpatialReferenceEnvironmentClass();
geoTransformation = (IGeoTransformation)spatialReferenceFactory2.CreateGeoTransformation(gTransformationType);
}
// 打开输出路径的工作空间
Type factoryType = null;
string extension = System.IO.Path.GetExtension(out_path);
if (extension == ".gdb")
{
factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
}
else if (extension == "")
{
factoryType = Type.GetTypeFromProgID("esriDataSourcesFile.ShapefileWorkspaceFactory");
out_featureDataset_name = null;
}
else
return null;
var out_workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
var out_workspace = out_workspaceFactory.OpenFromFile(out_path, 0);
var featureWorkspace = (IFeatureWorkspace)out_workspace;
// 删掉存在的同名要素类
IFeatureClass out_featureClass = null;
var workspace2 = (IWorkspace2)out_workspace;
if (workspace2.get_NameExists(esriDatasetType.esriDTFeatureClass, out_name))
{
out_featureClass = featureWorkspace.OpenFeatureClass(out_name);
((IDataset)out_featureClass).Delete();
}
// 复制属性字段,添加修改的SHAPE字段
int shapeFieldIndex = featureClass.FindField(featureClass.ShapeFieldName); // 获得Shape字段索引
IFields out_fields = new FieldsClass();
IFieldsEdit fieldsEdit = (IFieldsEdit)out_fields;
for (int i = 0; i < featureClass.Fields.FieldCount; i++)
{
if (i == shapeFieldIndex)
{
IGeometryDef geometryDef = new GeometryDefClass();
IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef;
geometryDefEdit.GeometryType_2 = featureClass.ShapeType;
geometryDefEdit.SpatialReference_2 = newSpatialReference;
IField shpField = new FieldClass();
IFieldEdit pFieldEdit = (IFieldEdit)shpField;
pFieldEdit.Name_2 = "SHAPE";
pFieldEdit.AliasName_2 = "SHAPE";
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry;
pFieldEdit.GeometryDef_2 = geometryDef;
fieldsEdit.AddField(shpField);
}
else
{
fieldsEdit.AddField(featureClass.Fields.Field[i]);
}
}
// 创建要素类
if (String.IsNullOrWhiteSpace(out_featureDataset_name))
{ // 在Geodatabase/Shapefile工作空间建立要素类
out_featureClass = featureWorkspace.CreateFeatureClass(out_name, out_fields,
featureClass.CLSID,
featureClass.EXTCLSID,
esriFeatureType.esriFTSimple,
"Shape", "");
}
else
{ // 在Geodatabase的FeatureDataset建立要素类
IFeatureDataset featureDataset = null;
if (workspace2.get_NameExists(esriDatasetType.esriDTFeatureDataset,
out_featureDataset_name))
featureDataset = featureWorkspace.OpenFeatureDataset(out_featureDataset_name);
else
featureDataset = featureWorkspace.CreateFeatureDataset(out_featureDataset_name,
spatialReference);
out_featureClass = featureDataset.CreateFeatureClass(out_name, out_fields,
featureClass.CLSID,
featureClass.EXTCLSID,
esriFeatureType.esriFTSimple,
"Shape", "");
Marshal.ReleaseComObject(featureDataset);
}
// 生成两个要素类字段的对应表
Dictionary<int, int> fieldsDictionary = new Dictionary<int, int>();
for (int i = 0; i < featureClass.Fields.FieldCount; i++)
{
if (featureClass.Fields.Field[i].Editable == false)
continue; // 跳过系统自动生成的不可编辑的字段
string field_name = featureClass.Fields.Field[i].Name.ToUpper();
for (int j = 0; j < out_featureClass.Fields.FieldCount; j++)
{
string field_name2 = out_featureClass.Fields.Field[j].Name.ToUpper();
if (field_name == field_name2)
fieldsDictionary.Add(i, j);
}
}
// 向输出要素类中添加要素
var searchFeatureCursor = featureClass.Search(null, false);
var insertFeatureCursor = out_featureClass.Insert(true);
IFeatureBuffer insertFeatureBuffer = out_featureClass.CreateFeatureBuffer();
IFeature feature = searchFeatureCursor.NextFeature();
int index = 0;
while (feature != null)
{
// 复制要素的属性值
foreach (KeyValuePair<int, int> keyValue in fieldsDictionary)
{
if (keyValue.Key == shapeFieldIndex) // 投影转换
{
IGeometry5 geometry = feature.ShapeCopy as IGeometry5;
if (geoTransformation == null)
geometry.Project(newSpatialReference);
else
geometry.ProjectEx(newSpatialReference,
esriTransformDirection.esriTransformForward,
geoTransformation, false, 0, 0);
insertFeatureBuffer.Shape = geometry;
}
else
{
insertFeatureBuffer.set_Value(keyValue.Value,
feature.get_Value(keyValue.Key));
}
}
insertFeatureCursor.InsertFeature(insertFeatureBuffer);
feature = searchFeatureCursor.NextFeature();
if (index++ % 1000 == 0) insertFeatureCursor.Flush();
}
insertFeatureCursor.Flush();
Marshal.ReleaseComObject(spatialReference);
Marshal.ReleaseComObject(out_workspace);
Marshal.ReleaseComObject(searchFeatureCursor);
Marshal.ReleaseComObject(insertFeatureCursor);
Marshal.ReleaseComObject(insertFeatureBuffer);
return out_featureClass;
}
2. 利用 ConvertFeatureClass 实现投影转换
利用 IFeatureDataConverter.ConvertFeatureClass 实现 FeatureClass 的投影转换。
/// <summary>
/// 要素类从现有投影转换为新的投影
/// </summary>
/// <param name="featureClass">要素类</param>
/// <param name="newSpatialReference">新的坐标参考系</param>
/// <param name="out_path">输出路径</param>
/// <param name="out_name">输出要素类名</param>
/// <param name="out_featureDataset_name">输出路径为Geodatabae时, 要素数据集名</param>
public void Project(IFeatureClass featureClass,
IQueryFilter queryFilter,
ISpatialReference newSpatialReference,
string out_path,
string out_name,
string out_featureDataset_name = null)
{
var geoDataset = (IGeoDataset)featureClass;
var spatialReference = geoDataset.SpatialReference;
IClone comparison = spatialReference as IClone;
if (comparison.IsEqual((IClone)newSpatialReference))
return;
Type factoryType = null;
string extension = System.IO.Path.GetExtension(out_path);
if (extension == ".gdb")
{
factoryType = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
}
else if (extension == "")
{
factoryType = Type.GetTypeFromProgID("esriDataSourcesFile.ShapefileWorkspaceFactory");
out_featureDataset_name = null;
}
else
return;
var out_workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
var out_workspace = out_workspaceFactory.OpenFromFile(out_path, 0);
// 删除已存在同名要素类
IWorkspace2 out_workspace2 = (IWorkspace2)out_workspace;
IFeatureWorkspace out_featureWorkspace = (IFeatureWorkspace)out_workspace2;
if (out_workspace2.get_NameExists(esriDatasetType.esriDTFeatureClass, out_name))
{
var tmp_dataset = (IDataset)out_featureWorkspace.OpenFeatureClass(out_name);
tmp_dataset.Delete();
}
// 输出要素数据集名
IFeatureDataset out_featureDataset = null;
IFeatureDatasetName out_featureDatasetName = null;
if (!String.IsNullOrWhiteSpace(out_featureDataset_name))
{
if (out_workspace2.get_NameExists(esriDatasetType.esriDTFeatureDataset,
out_featureDataset_name))
out_featureDataset = out_featureWorkspace.OpenFeatureDataset(out_featureDataset_name);
else
out_featureDataset = out_featureWorkspace.CreateFeatureDataset(out_featureDataset_name,
spatialReference);
// 判断要素数据集的空间参考系与新参考系是否相同
var tmp_geoDataset = (IGeoDataset)out_featureDataset;
var tmp_comparison = tmp_geoDataset.SpatialReference as IClone;
if (!tmp_comparison.IsEqual((IClone)newSpatialReference))
return;
out_featureDatasetName = (IFeatureDatasetName)out_featureDataset.FullName;
}
// 输出工作空间名
IDataset out_dataset = (IDataset)out_workspace;
IWorkspaceName out_workspaceName = (IWorkspaceName)out_dataset.FullName;
// 输出FeatureClass名
IFeatureClassName out_featureClassName = new FeatureClassNameClass();
IDatasetName out_datasetName = out_featureClassName as IDatasetName;
out_datasetName.WorkspaceName = out_workspaceName;
out_datasetName.Name = out_name;
// 输入的工作空间
IDataset in_dataset = featureClass as IDataset;
IFeatureClassName in_featureClassName = in_dataset.FullName as IFeatureClassName;
IWorkspace in_workspace = in_dataset.Workspace;
//检查字段的有效性
IFieldChecker fieldChecker = new FieldCheckerClass();
fieldChecker.InputWorkspace = in_workspace;
fieldChecker.ValidateWorkspace = out_workspace;
IFields in_fields = featureClass.Fields;
IEnumFieldError enumFieldError;
IFields out_fields;
fieldChecker.Validate(in_fields, out enumFieldError, out out_fields);
// 获取源要素类的空间参考,可以通过获取源要素类中Shape字段的GeometryDef字段获得
// 这里应该也可以自定义GeometryDef,实现源要素类的投影变换?
IGeometryDef geometryDef = new GeometryDefClass();
IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef;
geometryDefEdit.GeometryType_2 = featureClass.ShapeType;
geometryDefEdit.SpatialReference_2 = newSpatialReference;
// 调用IFeatureDataConverter接口进行数据转换
IFeatureDataConverter featureDataConverter = new FeatureDataConverterClass();
featureDataConverter.ConvertFeatureClass(in_featureClassName,
queryFilter,
out_featureDatasetName,
out_featureClassName,
geometryDef,
out_fields,
"", 1000, 0);
}
上面的方法实现了ArcToolbox的Project工具
方案1可以选择理基准面的转换方式,方案2不可以
在不进行地理基准面转换时,对 478911个点的FeatureClass数据进行投影转换
ArcMap Toolbox的 Project工具 用时 39.06秒
IGeometry5.Project 用时 31.50秒
IFeatureDataConverter.ConvertFeatureClass 用时 24.86秒