This is a follow-up question to Having two input feature layers and derived output feature layer in ArcGIS Python Toolbox tool?.

The following Python Toolbox tool accepts one or more points from the user and calculates the station, offset, and orientation of the point(s) based on a single polyline (an 'alignment'). It works fine as a geoprocessing tool in ArcMap with all the layers in the local Tennessee State Plane NAD83 coordinate system. However, I'd like this to also work correctly from within the Geoprocessing Widget in Web AppBuilder. When the user goes to digitize the point(s) in WAB, they are of course in the Web Mercator (auxiliary sphere) coordinate system. For the geoprocessing service to work correctly, I need to somehow project those points from Web Mercator back to TN State Plane so that the queryPointAndDistance method correctly calculates the station, offset, and orientation. What is the best (or easiest) method for accomplishing this?

import arcpy

class Toolbox(object):
    def __init__(self):
        self.label = "Station Offset toolbox"
        self.alias = "StationOffset"

        # List of tool classes associated with this toolbox
        self.tools = [CalculateStationOffset]

class CalculateStationOffset(object):
    def __init__(self):
        self.label = "Calculate Station Offset"
        self.description = "Calculate Station Offset"

def getParameterInfo(self):
    #Define parameter definitions

    # Input Features parameter
    in_features = arcpy.Parameter(
        displayName="Input Features",

    in_features.filter.list = ["Point"]

    # Alignment parameter
    in_alignment = arcpy.Parameter(

    in_alignment.filter.list = ["Polyline"]

    # Derived Output Features parameter
    out_features = arcpy.Parameter(
        displayName="Output Features",

    out_features.parameterDependencies = [in_features.name]
    out_features.schema.clone = True

    parameters = [in_features, in_alignment, out_features] 

    return parameters

    def isLicensed(self):
        return True

    def updateParameters(self, parameters):
        if parameters[0].altered:
            parameters[1].value = arcpy.ValidateFieldName(parameters[1].value, parameters[0].value)

    def updateMessages(self, parameters):

def execute(self, parameters, messages):
    fc_pnt         = parameters[0].valueAsText
    fc_line        = parameters[1].valueAsText

    # Fields
    fields = ['SHAPE@', 'MEAS', 'Distance', 'NEAR_X', 'NEAR_Y', 'Orient', 'POINT_X', 'POINT_Y', 'NEAR_ANGLE']

    # Get line geometry - assumes only one feature in feature class
    polyline = arcpy.da.SearchCursor(fc_line, "SHAPE@").next()[0]

    # Loop over the point feature class
    with arcpy.da.UpdateCursor(fc_pnt, fields) as cursor:
        for row in cursor:
            dist=polyline.queryPointAndDistance(row[0], False)
            row[1] = dist[1]
            row[2] = dist[2]
            row[3] = dist[0].centroid.X
            row[4] = dist[0].centroid.Y
            if dist[3] == 0:
            row[6] = row[0].centroid.X
            row[7] = row[0].centroid.Y

enter image description here

  • Note that polyline 'alignment' feature layer is not exposed to the user. It is a single feature that's basically hard-coded in for the time being. Its coordinate system is Tennessee State Plane NAD83. – Rayner Apr 28 '16 at 13:45
  • 1
    I cant get at the WAB right now, but do you see any way to set coordinate systems when configuring the widget? If you were to write your own web app, you'd control this yourself with the outSpatialReference settings. – KHibma Apr 28 '16 at 13:49
  • 1
    Also give a read of this spatial ref topic – KHibma Apr 28 '16 at 13:51

It may not be pretty, but was able to get this to work using the following code:

    # Loop over the point feature class
    with arcpy.da.UpdateCursor(fc_pnt, fields) as cursor:
        for row in cursor:
            projPt = arcpy.PointGeometry(arcpy.Point(row[0].centroid.X,row[0].centroid.Y),arcpy.SpatialReference(102100)).projectAs(arcpy.SpatialReference(102736))
            dist = polyline.queryPointAndDistance(projPt, False)
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.