Saturday, 28 September 2019

coordinate system - Using ArcObjects to choose GeoTransformation?



I’m currently building a Desktop add-in tool with ArcObjects that:



  1. Asks a user to select a feature class

  2. Reprojects the feature class to Web Mercator

  3. Executes some geoprocessing


The initial coordinate system of the feature class could be one of many different geographic or projected systems. As a result I need to also have the user select a GeoTransformation if necessary. Obviously, I could present the user with the huge list of transformation provided in the enumerations of esriSRGeoTransformationType, esriSRGeoTransformation2Type, esriSRGeoTransformation3Type. But that would be a huge list. What I’d like to do is narrow that list based on the input and output Coordinate Systems – but I have not been able to figure out how to do that narrowing.


Anyone have experience doing this? I know there must be some way to do, because the Project Tool UI does exactly this narrowing operation. But I can’t find the method, despite an exhaustive internet search.



Answer



See c# code below. (Updated: 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 GetTransformations(ISpatialReference fromSR, ISpatialReference toSR)
{
int fromFactcode = GetGCSFactoryCode(fromSR);
int toFactcode = GetGCSFactoryCode(toSR);


var outList = new List();
// 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()
{

}


}
}

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...