ArcObjects Custom Geoprocessing Tool SpatialReference Question

5457
13
06-20-2015 12:45 PM
RichardFairhurst
MVP Honored Contributor

I am looking for some conceptual guidance to make sure I am on the right track in how I should deal with spatial references in a geoprocessing tool.  Any .Net code is appreciated, especially if it is in VB.Net, but at least initially I am more concerned that I am making the best overall design decisions for how my tool should behave.  I have to provide a fair amount of background before getting to my questions, so I have highlighted my questions so that they are easier to pick out.

I want my custom geoprocessing tool to behave as much as possible like any other Esri geoprocessing tool, but I am struggling with some complexities related to the spatial reference requirements of the tool.  The tool is ultimately supposed to buffer a polyline input using a custom buffering routine that prevents overlap of the buffers where the lines intersect in the polygon output.  I developed the code to do the buffering in a VS Project that was not designed as a geoprocessing tool, and currently it only works with hard coded inputs and outputs that use the same Projected Coordinate System (PCS) spatial reference that my data commonly uses.  I want to change this code to use a custom tool interface that will let the user configure the input and output work spaces and feature class names and I want it to work for a wide variety of spatial references.

I have separately developed a basic custom geoprocessing tool interface that can take any polyline input in any spatial reference and output an empty polygon feature class to any work space and feature class name.  The output polygon field schema is derived from the polyline field schema and validated for the output work space.  The output spatial reference will be the same as the input spatial reference except when the user either chooses an output Feature Dataset with a different spatial reference from the input or chooses a work space that is not a Feature Dataset and sets the Output Coordinate System of the geoprocessing environment settings to a different spatial reference from the input. Do these behaviors sound like they follow the common geoprocessing tool behaviors that users expect in Esri's geoprocessing tools, or have I overlooked something?  I can provide the code in a later post if you are interested in how I got the tool to do these behaviors.

Currently my basic custom geoprocessing tool can have both the input and output in a Geographic Coordinate System (GCS), but unlike Esri's tools I do not want to support that option in my completed tool, since I want my buffers to be based on Linear Units.  I do not want to have to figure out how to implement Linear Buffers and determine bearings in a coordinate system that uses angular units.  Should I alert the user that they cannot make the input and output both use a GCS by adding an error message on the output feature class in the UpdateMessages portion of the tool when I detect that both the input and output will use a GCS?

I would like my tool to work if either the input or output uses a Projected Coordinate System (PCS).  If the input is in a PCS I plan on using a search cursor to directly read the polyline geometry into a dictionary and use the input coordinate system for the buffering steps.  I would only project the polygon geometry created in memory right before storing it in the output shape field if the output is in a different coordinate system.

If the input is in a GCS, then the output would have to be in a PCS.  I would want to project the polyline geometry of the input after reading it using a cursor and prior to storing it in the dictionary.  After that the buffering and output polygon would all use the output spatial reference.

Assuming I figure out how to control the logic of choosing the spatial reference the code will use for the buffering, I was thinking of using the IGeometry2.ProjectEx method to actually do the projection of either the output polygon or the input polyline when that step is necessary.  I would like to use that method to handle densification of the geometry.  Does that sound like the approach I should take?

If the user specifies a different spatial reference for the input and output I have developed code that can read the environment settings to configure any geographic transformation chosen by the user.  However, since the geographic transformation list presented in the environment settings contains so many irrelevant transformations, should I instead add an optional parameter to the tool interface where the user would choose a transformation from a narrower list of transformations that fit the input and output spatial references?  I have seen some code that I should be able to adapt that would do that.  If I set up that list, then the user should only be required to choose a transformation if the input/output spatial references have different underlying GCS's.  Is there a help reference for how to make a parameter only appear when it is required?  Or should I just make my transformation parameter an optional parameter that is always present and then only add an error message when the input/output require it?

Thanks in advance for any input you can provide.

0 Kudos
13 Replies
OwenEarley
Occasional Contributor III

Should I alert the user that they cannot make the input and output both use a GCS by adding an error message on the output feature class in the UpdateMessages portion of the tool when I detect that both the input and output will use a GCS?

Yes, at the very least you should alert the user. An ideal solution would be to limit the output spatial reference selection options to only include projected coordinate systems.

OwenEarley
Occasional Contributor III

Assuming I figure out how to control the logic of choosing the spatial reference the code will use for the buffering, I was thinking of using the IGeometry2.ProjectEx method to actually do the projection of either the output polygon or the input polyline when that step is necessary.  I would like to use that method to handle densification of the geometry.  Does that sound like the approach I should take?

The only other option would be to project the entire feature class to a temporary one for use in analysis but I don't think you get the densification option if you do it this way.

OwenEarley
Occasional Contributor III

However, since the geographic transformation list presented in the environment settings contains so many irrelevant transformations, should I instead add an optional parameter to the tool interface where the user would choose a transformation from a narrower list of transformations that fit the input and output spatial references?

This would be a good idea as the large geotransformation list can be confusing to users. The following code should get you started. Please note that this is taken from an old VB.Net project and may need to be updated. The code was used to locate geotransformations between WGS84 and any other datum.

        'Create WGS84 spatial reference
        Dim SRF As ISpatialReferenceFactory2 = Nothing
        Dim factoryType As Type = Type.GetTypeFromProgID("esriGeometry.SpatialReferenceEnvironment")
        SRF = CType(Activator.CreateInstance(factoryType), ISpatialReferenceFactory2)
        Dim WGS84 As IGeographicCoordinateSystem = SRF.CreateGeographicCoordinateSystem(esriSRGeoCSType.esriSRGeoCS_WGS1984)


        'Search all GeoTransformations for matches
        Dim _GTList As New List(Of IGeoTransformation) 'List of ArcGIS Transformations
        Dim GTSet As ESRI.ArcGIS.esriSystem.ISet = Nothing
        Dim GT As IGeoTransformation
        Dim SR1 As ISpatialReference = Nothing
        Dim SR2 As ISpatialReference = Nothing
        Dim ht As New Hashtable ' used to filter duplicate items

        GTSet = SRF.CreatePredefinedGeographicTransformations


        For i As Integer = 0 To GTSet.Count - 1
          GT = GTSet.Next()
          GT.GetSpatialReferences(SR1, SR2)
          If (SR1.FactoryCode = Me.OtherGCS.FactoryCode) And (SR2.FactoryCode = WGS84.FactoryCode) Then
            If ht.ContainsKey(GT.Name) = False Then
              _GTList.Add(GT)
              ht.Add(GT.Name, GT.Name)
            End If
          End If
        Next
OwenEarley
Occasional Contributor III

Is there a help reference for how to make a parameter only appear when it is required?  Or should I just make my transformation parameter an optional parameter that is always present and then only add an error message when the input/output require it?

You should be able to use the Enabled property to do this (see: IGPParameter3).