I’m currently building a Desktop add-in tool with ArcObjects that:
- Asks a user to select a feature class
- Reprojects the feature class to Web Mercator
- 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