ArcObject 实现FeatureClass 投影转换

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秒
原文地址:https://www.cnblogs.com/lqqgis/p/12642491.html