Menggunakan ArcObjects untuk memilih GeoTransformation?

8

Saat ini saya sedang membangun alat tambahan Desktop dengan ArcObjects yang:

  1. Meminta pengguna untuk memilih kelas fitur
  2. Memproyeksikan ulang kelas fitur ke Web Mercator
  3. Menjalankan beberapa proses geoproses

Sistem koordinat awal dari kelas fitur dapat menjadi salah satu dari banyak sistem geografis atau proyeksi yang berbeda. Akibatnya saya perlu juga meminta pengguna memilih GeoTransformation jika perlu. Jelas, saya bisa menyajikan kepada pengguna daftar besar transformasi yang disediakan dalam penghitungan esriSRGeoTransformationType, esriSRGeoTransformation2Type, esriSRGeoTransformation3Type. Tapi itu akan menjadi daftar besar. Yang ingin saya lakukan adalah mempersempit daftar itu berdasarkan input dan output Sistem Koordinat - tapi saya belum bisa menemukan cara untuk melakukan penyempitan itu.

Adakah yang punya pengalaman melakukan ini? Saya tahu pasti ada cara untuk melakukannya, karena Project Tool UI melakukan operasi penyempitan ini dengan tepat. Tetapi saya tidak dapat menemukan metodenya, meskipun pencarian internet lengkap.

rgwozdz
sumber

Jawaban:

12

Lihat kode c # di bawah ini. (Diperbarui: refactored)

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using ESRI.ArcGIS.Geometry;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Framework;

namespace HansenAddin
{
    public class PickGeoTransButton : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        public PickGeoTransButton()
        {
        }

        protected override void OnClick()
        {
            try
            {
                // let user choose a transformation for projecting from featureclass's spatial ref
                // into the dataframe's spatial ref.
                var featClass = ((IFeatureLayer)ArcMap.Document.FocusMap.get_Layer(0)).FeatureClass;

                var fromSR = ((IGeoDataset)featClass).SpatialReference;
                var toSR = ArcMap.Document.FocusMap.SpatialReference;

                IGeoTransformation geoTrans;
                esriTransformDirection direction;
                ChooseGeotrans(fromSR, toSR, ArcMap.Application.hWnd, out geoTrans, out direction);
                if (geoTrans != null)
                {
                    MessageBox.Show(String.Format("{0} \n{1} \n{2} \n{3}", geoTrans.Name, fromSR.Name, toSR.Name, direction));
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public static void ChooseGeotrans(ISpatialReference fromSR, ISpatialReference toSR, int hWnd,
            out IGeoTransformation geoTrans, out esriTransformDirection direction)
        {
            geoTrans = null;
            direction = esriTransformDirection.esriTransformForward;

            var list = GetTransformations(fromSR, toSR);
            if (list.Count == 0)
            {
                MessageBox.Show(String.Format("No geotransforms to go from {0} to {1}", fromSR.Name, toSR.Name));
                return;
            }
            IListDialog dlg = new ListDialogClass();
            foreach (IGeoTransformation gt in list)
                dlg.AddString(gt.Name);
            if (dlg.DoModal("Choose a Geotransformation", 0, hWnd))
            {
                geoTrans = list[dlg.Choice];
                direction = GetDir(geoTrans, fromSR, toSR);
            }
        }

        public static List<IGeoTransformation> GetTransformations(ISpatialReference fromSR, ISpatialReference toSR)
        {
            int fromFactcode = GetGCSFactoryCode(fromSR);
            int toFactcode = GetGCSFactoryCode(toSR);

            var outList = new List<IGeoTransformation>();
            // Use activator to instantiate arcobjects singletons ...
            var type = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment");
            var srf = Activator.CreateInstance(type) as ISpatialReferenceFactory2;

            var gtSet = srf.CreatePredefinedGeographicTransformations();
            gtSet.Reset();
            for (int i = 0; i < gtSet.Count; i++)
            {
                ISpatialReference fromGcsSR;
                ISpatialReference toGcsSR;
                var geoTrans = (IGeoTransformation)gtSet.Next();
                geoTrans.GetSpatialReferences(out fromGcsSR, out toGcsSR);
                if ((fromGcsSR.FactoryCode == fromFactcode && toGcsSR.FactoryCode == toFactcode) ||
                    (fromGcsSR.FactoryCode == toFactcode && toGcsSR.FactoryCode == fromFactcode))
                {
                    outList.Add(geoTrans);
                }
            }
            return outList;
        }
        private static esriTransformDirection GetDir(IGeoTransformation geoTrans, ISpatialReference sr1, ISpatialReference sr2)
        {
            int code1 = GetGCSFactoryCode(sr1);
            int code2 = GetGCSFactoryCode(sr2);
            ISpatialReference fromSR;
            ISpatialReference toSR;
            geoTrans.GetSpatialReferences(out fromSR, out toSR);
            if (fromSR.FactoryCode == code1 && toSR.FactoryCode == code2)
                return esriTransformDirection.esriTransformForward;
            else if (fromSR.FactoryCode == code2 && toSR.FactoryCode == code1)
                return esriTransformDirection.esriTransformReverse;
            else
                throw new Exception(String.Format("{0} does not support going between {1} and {2}",
                    geoTrans.Name, sr1.Name, sr2.Name));
        }

        private static int GetGCSFactoryCode(ISpatialReference sr)
        {
            if (sr is IProjectedCoordinateSystem)
                return ((IProjectedCoordinateSystem)sr).GeographicCoordinateSystem.FactoryCode;
            else if (sr is IGeographicCoordinateSystem)
                return ((IGeographicCoordinateSystem)sr).FactoryCode;
            else
                throw new Exception("unsupported spatialref type");
        }
        protected override void OnUpdate()
        {

        }

    }
}
Kirk Kuykendall
sumber
Terima kasih banyak ... cukup berhasil. Saya bertanya-tanya tentang bagian ini: if ((fromGcsSR.FactoryCode == fromFactcode && toGcsSR.FactoryCode == toFactcode) || (fromGcsSR.FactoryCode == fromFactcode && toGcsSR.FactoryCode == toFactcode)) Kedua sisi operator OR identik.
rgwozdz
@ rgwozdz Hmm, saya sudah memperbaiki garis kode itu. Saya bingung mengapa itu bekerja dengan sempurna mengingat bahwa garis itu adalah kesalahan.
Kirk Kuykendall
2

Untuk metode GetDir, parameter kedua dan ketiga harus kode pabrik dari sistem koordinat geografis dasar dari sumber dan sistem koordinat target. Untuk sistem koordinat yang diproyeksikan, antarmuka ISpatialReference akan memberikan kode pabrik dari sistem koordinat tetapi bukan sistem koordinat geografis dasar. Misalnya, NAD27 Zona 12 sama dengan kode pabrik 26712 dan sistem koordinat geografis dasar adalah 4267 (NAD27 geografis). Parameter 'out' dari geoTrans.GetSpatialReferences (keluar dariSR, out toSR); hanya akan menjadi kode pabrik untuk sistem koordinat geografis.

Anda bisa mendapatkan sistem koordinat geografis dasar dari sistem koordinat yang diproyeksikan dengan membuat objek sistem koordinat yang diproyeksikan dan kemudian mendapatkan geogr dasarnya. coord sys kode pabrik.

Kode di bawah ini akan membantu. Bilangan bulat untuk sistem koordinat target dan asli harus disediakan untuk membuat objek dengan benar. Dan kode mengharapkan tipe (diproyeksikan vs geografis) dari sistem koordinat sumber / target telah disediakan.

//Create Spatial Reference Factory

ISpatialReferenceFactory3 srFactory = new SpatialReferenceEnvironmentClass();
IProjectedCoordinateSystem3 pcsSource; 
IGeographicCoordinateSystem2 gcsSource; 
IProjectedCoordinateSystem3 pcsTarget; 
IGeographicCoordinateSystem2 gcsTarget;
ISpatialReference3 srSourceCoordSys;
ISpatialReference3 srTargetCoordSys;
int OriginalCoordSys;
int TargetCoordSys;

        int SourceGeographicBaseID = 0;
        int TargetGeographicBaseID = 0;

        //Define the source coordinate system
        if (OrigCoordSysType.ToUpper() == "PROJECTED")
        {
            pcsSource = (IProjectedCoordinateSystem3)srFactory.CreateProjectedCoordinateSystem(OriginalCoordSys);
            SourceGeographicBaseID = pcsSource.GeographicCoordinateSystem.FactoryCode;
            srSourceCoordSys = (ISpatialReference3)pcsSource;
        }
        else
        {
            gcsSource = (IGeographicCoordinateSystem2)srFactory.CreateGeographicCoordinateSystem(OriginalCoordSys);
            SourceGeographicBaseID = gcsSource.FactoryCode;
            srSourceCoordSys = (ISpatialReference3)gcsSource;
        }

        //Define the target coordinate system
        if (TargetCoordSysType.ToUpper() == "PROJECTED")
        {
            pcsTarget = (IProjectedCoordinateSystem3)srFactory.CreateProjectedCoordinateSystem(TargetCoordSys);
            TargetGeographicBaseID = pcsTarget.GeographicCoordinateSystem.FactoryCode;
            srTargetCoordSys = (ISpatialReference3)pcsTarget;

        }
        else
        {
            gcsTarget = (IGeographicCoordinateSystem2)srFactory.CreateGeographicCoordinateSystem(TargetCoordSys);
            TargetGeographicBaseID = gcsTarget.FactoryCode;
            srTargetCoordSys = (ISpatialReference3)gcsTarget;
        }
Dennis Geasan
sumber
2

Metode paling sederhana adalah menulis skrip python (arcpy) dan memaparkannya bagaimana toolbox di arcobjects. Kemudian Anda menggunakan arcobjects dan memanggil alat ini.

Di arcpy Anda memiliki ListTransformations ( http://resources.arcgis.com/en/help/main/10.1/index.html#/ListTransformations/018v0000001p000000/ )

toolbox alat terbuka dengan kotak alat:

 import arcpy
 try:

     layer = arcpy.GetParameter(0)
     layerDescribe = arcpy.Describe(layer)

     from_sr = layerDescribe.featureClass.spatialReference
     to_sr = arcpy.GetParameter(1)
     extent = layerDescribe.extent

     transformations = arcpy.ListTransformations(from_sr, to_sr, extent)
     arcpy.SetParameter(2, transformations)

 except StandardError, ErrDesc:
     arcpy.AddMessage("Error: " + str(ErrDesc))
 except:
     arcpy.AddMessage("Error: get list transformations")

Dalam arcobjects:

            IVariantArray parameters = new VarArrayClass();

            parameters.Add(this.pathLayer); //path and file lyr example c:\temp\test.lyr
            parameters.Add(this.spatialReferenceOut);

            IGPValue output = null;
            Geoprocessor geoprocessor = new Geoprocessor();
            geoprocessor.AddToolbox(@"c:\Temp\myToolbox.tbx");
            ExecuteTask(this.geoprocessor, parameters, "ListTransformations", 0 ,out output);   //ListTransformations is the name of your toolbox tool

            IGPMultiValue GPMultiValue = output as IGPMultiValue;

            for (int i = 0; i < GPMultiValue.Count;i++ )
            {
                cboDatumTransformation.Items.Add((GPMultiValue.get_Value(i) as IGPString).Value);
            }

Jadi, Anda hanya memiliki transformasi datum yang tersedia untuk tingkat input

Berita: sekarang di ArcGIS Server 10.3 API Rest Anda telah tersedia di GeometryService -> Project FindTransformasi yang mengembalikan daftar transformasi geografis yang berlaku yang harus digunakan ketika memproyeksikan geometri dari referensi spasial input ke referensi spasial output

nicogis
sumber