FeatureClass投影转换方法总结
方法1:使用IGeoDatasetSchemaEdit.AlterSpatialReference#
/// <summary>
/// 用于未知空间参考坐标系的数据集赋予空间参考坐标系,且会覆盖已存在的空间参考系
/// </summary>
/// <param name="geoDataset"></param>
/// <param name="spatialReference"></param>
/// <param name="isSucceed"></param>
public void DefineProjection(IGeoDataset geoDataset,ISpatialReference spatialReference, out bool isSucceed)
{
isSucceed = false;
IGeoDatasetSchemaEdit geoDatasetSchemaEidt = geoDataset as IGeoDatasetSchemaEdit;
if (geoDatasetSchemaEidt.CanAlterSpatialReference == true)
{
geoDatasetSchemaEidt.AlterSpatialReference(spatialReference);
isSucceed = true;
}
}
上面方法相当于实现了 ArcMap Toolbox中的Define Projection, 只做了投影定义,没有起点投影转换作用
参考ArcEngine帮助:
方法2:IFeatureDataConverter.ConvertFeatureClass#
/// <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);
}
上面的方法相当于实现了ArcMap的Toolbox中的Project,但是不具备选择地理基准面的转换方式
方法3:通过创建新的FeatureClass,将原有FeatureClass的要素复制到新的FeatureClass的过程中,使用IGeometry5.Project与IGeometry5.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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?