Verwenden Sie ArcObjects, um GeoTransformation auszuwählen?

8

Ich erstelle derzeit ein Desktop-Add-In-Tool mit ArcObjects, das:

  1. Fordert einen Benutzer auf, eine Feature-Class auszuwählen
  2. Projiziert die Feature-Class erneut in Web Mercator
  3. Führt eine Geoverarbeitung aus

Das anfängliche Koordinatensystem der Feature-Class kann eines von vielen verschiedenen geografischen oder projizierten Systemen sein. Daher muss der Benutzer bei Bedarf auch eine GeoTransformation auswählen. Natürlich könnte ich dem Benutzer die riesige Liste der Transformationen präsentieren, die in den Aufzählungen von esriSRGeoTransformationType, esriSRGeoTransformation2Type, esriSRGeoTransformation3Type enthalten sind. Aber das wäre eine riesige Liste. Was ich tun möchte, ist, diese Liste basierend auf den Eingabe- und Ausgabekoordinatensystemen einzugrenzen - aber ich konnte nicht herausfinden, wie diese Eingrenzung durchgeführt werden kann.

Hat jemand Erfahrung damit? Ich weiß, dass es eine Möglichkeit geben muss, da die Benutzeroberfläche des Projekttools genau diese Verengungsoperation ausführt. Aber ich kann die Methode trotz einer umfassenden Internetsuche nicht finden.

rgwozdz
quelle

Antworten:

12

Siehe c # -Code unten. (Aktualisiert: überarbeitet)

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
quelle
Vielen Dank ... hat so ziemlich perfekt funktioniert. Ich wundere mich jedoch über diesen Teil: if ((fromGcsSR.FactoryCode == fromFactcode && toGcsSR.FactoryCode == toFactcode) || (fromGcsSR.FactoryCode == fromFactcode && toGcsSR.FactoryCode == toFactcode)) Beide Seiten des OP-Operators sind identisch.
Rgwozdz
@rgwozdz Hmm, ich habe diese Codezeile korrigiert. Ich bin verwirrt, warum es perfekt funktioniert hat, da diese Zeile ein Fehler ist.
Kirk Kuykendall
2

Bei der GetDir-Methode sollten der zweite und dritte Parameter die Factory-Codes der geografischen Basiskoordinatensysteme der Quell- und Zielkoordinatensysteme sein. Bei projizierten Koordinatensystemen liefert die ISpatialReference-Schnittstelle den Factory-Code des Koordinatensystems, nicht jedoch das geografische Basiskoordinatensystem. Beispielsweise entspricht die NAD27-Zone 12 einem Fabrikcode 26712 und das geografische Basiskoordinatensystem ist 4267 (geografisch NAD27). Die 'out'-Parameter von geoTrans.GetSpatialReferences (out fromSR, out toSR); werden nur Werkscodes für geografische Koordinatensysteme sein.

Sie können das geografische Basiskoordinatensystem eines projizierten Koordinatensystems abrufen, indem Sie ein projiziertes Koordinatensystemobjekt erstellen und dann dessen Basisgeogr abrufen. coord sys Werkscode.

Der folgende Code sollte helfen. Die Ganzzahlen für das ursprüngliche und das Zielkoordinatensystem müssten angegeben werden, um das Objekt ordnungsgemäß zu erstellen. Und der Code erwartet, dass der Typ (projiziert vs. geografisch) der Quell- / Zielkoordinatensysteme bereitgestellt wurde.

//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
quelle
2

Die einfachste Methode besteht darin, ein Python-Skript (arcpy) zu schreiben und es als Toolbox in arcobjects verfügbar zu machen. Dann verwenden Sie arcobjects und rufen dieses Tool auf.

In arcpy haben Sie ListTransformations ( http://resources.arcgis.com/de/help/main/10.1/index.html#/ListTransformations/018v0000001p000000/). )

Toolbox-Tool mit einer Toolbox verfügbar gemacht:

 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")

In Bogenobjekten:

            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);
            }

Sie haben also nur Bezugstransformationen für den Umfang der Eingabe verfügbar

News: Jetzt in ArcGIS Server 10.3 API Rest stehen Ihnen GeometryService -> Project FindTransformations zur Verfügung , die eine Liste der anwendbaren geografischen Transformationen zurückgeben, die beim Projizieren von Geometrien vom eingegebenen räumlichen Bezug zum ausgegebenen räumlichen Bezug verwendet werden sollten

Nicogis
quelle