Skip to Content.

mget-help - RE: [mget-help] RE: find nearest feature problem

Please Wait...

Subject: Marine Geospatial Ecology Tools (MGET) help

Text archives


From: "Jason Roberts" <>
To: "'Arlene Merems'" <>
Cc: <>
Subject: RE: [mget-help] RE: find nearest feature problem
Date: Mon, 27 Jul 2009 16:21:31 -0400

Arlene,

 

It was as I suspected. We were bungling the call to Near, passing 'NOANGLE' rather than 'NO_ANGLE'. I fixed the problem and the tool ran fine with the data you sent. My apologies for this.

 

To fix this on your own system, please do the following:

 

1.    Shut down all ArcGIS applications.

2.    Overwrite the file C:\Python25\Lib\site-packages\GeoEco\SpatialAnalysis\Points.py with the attached Points.py.

3.    Start Arc and try again.

 

This fix will be included in the final release of MGET 0.7, due to be released tomorrow, providing that the rest of our testing goes well.

 

Best,

Jason

 

From: Jason Roberts [mailto:]
Sent: Monday, July 27, 2009 3:58 PM
To: 'Arlene Merems'
Cc:
Subject: [mget-help] RE: find nearest feature problem

 

Hi Arlene,

 

Thanks for your interest in MGET. I'm sorry you're seeing this problem. Based on the error message you sent, my guess is that we messed up MGET's call to ArcGIS's Near tool and did not catch the problem in testing. It looks like MGET is calling Near with the string 'NOANGLE' rather than 'NO_ANGLE', and ArcGIS is saying that it doesn't know what 'NOANGLE' means (this is probably what "Input to parameter angle not within domain" means).

 

Thanks for sending your data. I will try to run the tool using your data and let you know what I find out. If I am right, the fix should be very easy and I'll be able to send you a file to patch the tool to work properly. In the mean time, you may be able to get the tool working by adding an Angle field to your points and telling the tool to populate it. This will cause it to pass 'ANGLE' to Near, which should work. My guess is that our test code always included an Angle field, thus we never tested the tool without one and did not hit this bug in MGET. Thank you for finding it!

 

Best regards,

 

Jason

 

From: Arlene Merems [mailto:]
Sent: Monday, July 27, 2009 3:19 PM
To:
Subject: find nearest feature problem
Importance: High

 

Hello, and thanks for being readily available with tech support!

 

I am excited to find this great GIS analysis tool for marine data! But having a problem with the Find Nearest Features tool. It keeps returning error messages. See error message below.

 

 I have a point file “blackrock.shp” of fish observations and a polygon file “bpi200_ridge.shp” of a single habitat type (converted from a raster of multiple habitat types). I want to measure the distance of each fish observation to this habitat feature. Seems straight forward enough. I created a field called “dist-ridge” in the fish shapefile as the field to receive the feature distance value. I tried adding a search radius of 5m and again as ‘unknown’.  Those are the only parameters I set.  I don’t know why its not working. Can’t decifer the error message. Can you help?  I attached the point shapefile and the polygon shapefile in case you want to try it.

 

Thanks! Arlene

 

 

Error message:

<class 'GeoEco.ArcGIS.ArcGISError'>: An ArcGIS geoprocessing function failed. This usually results from a problem with your inputs. Please check them and try again. Also review any preceding error messages and the detailed error information that appears at the end of this message. If you suspect the failure is due to a programming mistake in this tool or ArcGIS, please contact the author of this tool for assistance. Detailed error information: ArcGIS Geoprocessor object 0x1E825DA0: Invocation of Near_analysis(*args=('C:\\Temp\\GeoEcoTemp_meremsa\\tmp0tkne0\\Temp.mdb\\CopiedPoints', 'C:\\Temp\\GeoEcoTemp_meremsa\\tmp0tkne0\\Temp.mdb\\ConvertedLines', '5 Meters', 'NO_LOCATION', 'NOANGLE')) raised ExecuteError: ERROR 000622: Failed to execute (Near). Parameters are not valid.

ERROR 000621: Input to parameter angle not within domain.

 

Failed to execute (ArcGISPointsFindNearestFeatures).

End Time: Mon Jul 27 11:57:45 2009 (Elapsed Time: 29.00 seconds)

 

 

Arlene Merems

Oregon Department of Fish and Wildlife

Marine Resources Program

2040 SE Marine Science Dr.

Newport, OR 97365

ph: 541-867-0300 ext. 246

fax: 541-867-0311

 

# Points.py - Provides methods for general-purpose operations with points.
#
# Copyright (C) 2007 Jason J. Roberts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License (available in the file LICENSE.TXT)
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.

import os.path

from GeoEco.DynamicDocString import DynamicDocString
from GeoEco.Internationalization import _
from GeoEco.Logging import Logger, ProgressReporter


class ArcGISPoints(object):
    __doc__ = DynamicDocString()

    @classmethod
    def _InsertPoint(cls, gp, insertCursor, x, y, z=None, m=None, 
attributes=None, shapeFieldName=u'Shape'):

        # Set the geometry field.

        point = gp.CreateObject(u'Point')
        
        point.X = x
        point.Y = y
        if z is not None:
            point.Z = z
        if m is not None:
            point.M = m
            
        insertCursor.SetValue(shapeFieldName, point)

        # If the caller provided any attributes, set them.

        if attributes is not None:
            for field, value in attributes.items():
                insertCursor.SetValue(field, value)

        # Insert the row.

        insertCursor.InsertRow()

    @classmethod
    def InsertPoint(cls, insertCursor, x, y, z=None, m=None, attributes=None, 
shapeFieldName=u'Shape'):
        cls.__doc__.Obj.ValidateMethodInvocation()

        # Perform additional parameter validation.

        if not insertCursor.IsOpen:
            Logger.RaiseException(ValueError(_(u'The insert cursor must be 
open.')))

        # Insert the point.

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        cls._InsertPoint(gp, insertCursor, x, y, z, m, attributes, 
shapeFieldName)

    @classmethod
    def AppendPointsToFeatureClass(cls, featureClass, coordinates, 
hasZ=False, hasM=False, attributes=None):
        cls.__doc__.Obj.ValidateMethodInvocation()

        # Validate the length of the coordinates list.

        if not hasZ and not hasM:
            if len(coordinates) % 2 != 0:
                Logger.RaiseException(ValueError(_(u'The length of the input 
list of point coordinates must be evenly divisible by 2, because each point 
must have an X and a Y coordinate.')))
            numPoints = len(coordinates) / 2
            
        elif hasZ and not hasM:
            if len(coordinates) % 3 != 0:
                Logger.RaiseException(ValueError(_(u'The length of the input 
list of point coordinates must be evenly divisible by 3, because each point 
must have X, Y, and Z coordinates.')))
            numPoints = len(coordinates) / 3
            
        elif not hasZ and hasM:
            if len(coordinates) % 3 != 0:
                Logger.RaiseException(ValueError(_(u'The length of the input 
list of point coordinates must be evenly divisible by 3, because each point 
must have X and Y coordinates and a measure value.')))
            numPoints = len(coordinates) / 3
            
        else:
            if len(coordinates) % 4 != 0:
                Logger.RaiseException(ValueError(_(u'The length of the input 
list of point coordinates must be evenly divisible by 4, because each point 
must have X, Y, and Z coordinates and a measure value.')))
            numPoints = len(coordinates) / 4

        # Validate that the caller provided or did not provide Z or M
        # values.

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        describe = gp.Describe(featureClass)

        if hasZ and not describe.HasZ:
            Logger.RaiseException(ValueError(_(u'The input list of point 
coordinates includes Z coordinates but the feature class %(fc)s does not have 
Z coordinates. Please specify a different feature class or remove the Z 
coordinates from the input list of point coordinates.') % {u'fc': 
featureClass}))
        if not hasZ and describe.HasZ:
            Logger.RaiseException(ValueError(_(u'The input list of point 
coordinates does not include Z coordinates but the feature class %(fc)s has Z 
coordinates. Please specify a different feature class or add Z coordinates to 
the input list of point coordinates.') % {u'fc': featureClass}))
        if hasM and not describe.HasM:
            Logger.RaiseException(ValueError(_(u'The input list of point 
coordinates includes measure values but the feature class %(fc)s does not 
have measure values. Please specify a different feature class or remove the 
measure values from the input list of point coordinates.') % {u'fc': 
featureClass}))
        if not hasM and describe.HasM:
            Logger.Warning(_(u'The feature class %(fc)s has measure values 
but the input list of point coordinates does not include measure values. The 
points will be added to the feature class with NULL measure values.') % 
{u'fc': featureClass})

        # Determine the name of the shape field.

        shapeFieldName = describe.ShapeFieldName

        # Open an insert cursor to the feature class and insert the points.

        Logger.Info(_(u'Inserting %(count)i points into feature class 
%(fc)s...') % {u'count': numPoints, u'fc': featureClass})

        from GeoEco.DatabaseAccess.ArcGIS import ArcGIS91DatabaseConnection
        
        connection = ArcGIS91DatabaseConnection()
        cursor = connection.OpenInsertCursor(featureClass, rowCount=numPoints)
        try:
            for i in range(numPoints):
                if attributes is not None and i < len(attributes):
                    attrs = attributes[i]
                else:
                    attrs = None
                    
                if not hasZ and not hasM:
                    cls._InsertPoint(gp, cursor, x=coordinates[i*2], 
y=coordinates[i*2 + 1], attributes=attrs, shapeFieldName=shapeFieldName)
                elif hasZ and not hasM:
                    cls._InsertPoint(gp, cursor, x=coordinates[i*3], 
y=coordinates[i*3 + 1], z=coordinates[i*3 + 2], attributes=attrs, 
shapeFieldName=shapeFieldName)
                elif not hasZ and hasM:
                    cls._InsertPoint(gp, cursor, x=coordinates[i*3], 
y=coordinates[i*3 + 1], m=coordinates[i*3 + 2], attributes=attrs, 
shapeFieldName=shapeFieldName)
                else:
                    cls._InsertPoint(gp, cursor, x=coordinates[i*4], 
y=coordinates[i*4 + 1], z=coordinates[i*4 + 2], m=coordinates[i*4 + 3], 
attributes=attrs, shapeFieldName=shapeFieldName)
        finally:
            del cursor

    @classmethod
    def AppendPointsToFeatureClass2(cls, featureClass, xyCoordinates, 
zCoordinates=None, mValues=None, intAttrsToSet=None, intAttrValues=None, 
floatAttrsToSet=None, floatAttrValues=None, stringAttrsToSet=None, 
stringAttrValues=None, dateAttrsToSet=None, dateAttrValues=None):
        cls.__doc__.Obj.ValidateMethodInvocation()

        # Parse the coordinates into lists.

        coords = []
        
        for i in range(len(xyCoordinates)):
            x, y = PointTypeMetadata.ParseFromArcGISString(xyCoordinates[i])
            coords.append(x)
            coords.append(y)
            if zCoordinates is not None:
                coords.append(zCoordinates[i])
            if mValues is not None:
                coords.append(mValues[i])

        # Build a dictionary of attributes to set.

        attributesDict = {}

        if intAttrsToSet is not None:
            for i in range(len(intAttrsToSet)):
                attributesDict[intAttrsToSet[i]] = intAttrValues[i]

        if floatAttrsToSet is not None:
            for i in range(len(floatAttrsToSet)):
                attributesDict[floatAttrsToSet[i]] = floatAttrValues[i]

        if stringAttrsToSet is not None:
            for i in range(len(stringAttrsToSet)):
                attributesDict[stringAttrsToSet[i]] = stringAttrValues[i]

        if dateAttrsToSet is not None:
            for i in range(len(dateAttrsToSet)):
                attributesDict[dateAttrsToSet[i]] = dateAttrValues[i]

        # If the caller provided multiple points, all of them will
        # receive the same attribute values. Build a list of attribute
        # dictionaries. Each element of the list will point to the
        # same dictionary.

        if len(attributesDict) > 0:
            attributes = []
            for i in range(len(xyCoordinates)):
                attributes.append(attributesDict)
                
        else:
            attributes = None

        # Append the points to the feature class.

        cls.AppendPointsToFeatureClass(featureClass, coords, zCoordinates is 
not None, mValues is not None, attributes)

        # Return successfully.

        return featureClass
            
    @classmethod
    def CreateFeatureClassWithPoints(cls, featureClass, spatialReference, 
coordinates, hasZ=False, hasM=False, attributes=None, configKeyword=None, 
spatialGrid1=0, spatialGrid2=0, spatialGrid3=0, overwriteExisting=False):
        cls.__doc__.Obj.ValidateMethodInvocation()

        # Create a temporary directory to hold the output feature
        # class while we are constructing it. If the output
        # feature class is not a shapefile, create a temporary
        # personal geodatabase to hold the feature class.

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        from GeoEco.DataManagement.Directories import TemporaryDirectory
        tempDir = TemporaryDirectory()
        outputIsShapefile = featureClass.lower().endswith(u'.shp')

        if outputIsShapefile:
            tempGeoDB = None
            tempWorkspace = tempDir.Path
            tempExt = u'.shp'
        else:
            gp.CreatePersonalGDB_management(tempDir.Path, u'Temp.mdb')
            tempGeoDB = os.path.join(tempDir.Path, u'Temp.mdb')
            tempWorkspace = tempGeoDB
            tempExt = u''

        try:
            # Create the temporary output feature class.

            if not hasZ and not hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'DISABLED', u'DISABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            elif hasZ and not hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'DISABLED', u'ENABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            elif not hasZ and hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'ENABLED', u'DISABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            else:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'ENABLED', u'ENABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)

            tempFC = os.path.join(tempWorkspace, u'Temp' + tempExt)

            # Append the points.

            cls.AppendPointsToFeatureClass(tempFC, coordinates, hasZ, hasM, 
attributes)

            # Extract the output feature class from the temporary
            # directory or geodb.

            oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
            Logger.SetLogInfoAsDebug(True)
            try:
                GeoprocessorManager.CopyArcGISObject(tempFC, featureClass, 
overwriteExisting, [u'featureclass', u'shapefile'], _(u'feature class'))
            finally:
                Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)

        finally:
            # If we created a temporary personal geodatabase,
            # delete it now. If we do not explicitly delete it
            # here, the geoprocessor will keep a handle open
            # through MS Access APIs, and the temporary directory
            # will not be able to be deleted.

            if tempGeoDB is not None:
                try:
                    gp.Delete_management(tempGeoDB)
                except:
                    pass
            
    @classmethod
    def CreateFeatureClassWithPoints2(cls, featureClass, spatialReference, 
xyCoordinates, zCoordinates=None, mValues=None, configKeyword=None, 
spatialGrid1=0, spatialGrid2=0, spatialGrid3=0, overwriteExisting=False):
        cls.__doc__.Obj.ValidateMethodInvocation()

        # Create a temporary directory to hold the output feature
        # class while we are constructing it. If the output
        # feature class is not a shapefile, create a temporary
        # personal geodatabase to hold the feature class.

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        from GeoEco.DataManagement.Directories import TemporaryDirectory
        tempDir = TemporaryDirectory()
        outputIsShapefile = featureClass.lower().endswith(u'.shp')

        if outputIsShapefile:
            tempGeoDB = None
            tempWorkspace = tempDir.Path
            tempExt = u'.shp'
        else:
            gp.CreatePersonalGDB_management(tempDir.Path, u'Temp.mdb')
            tempGeoDB = os.path.join(tempDir.Path, u'Temp.mdb')
            tempWorkspace = tempGeoDB
            tempExt = u''

        try:
            # Create the temporary output feature class.

            hasZ = zCoordinates is not None
            hasM = mValues is not None

            if not hasZ and not hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'DISABLED', u'DISABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            elif hasZ and not hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'DISABLED', u'ENABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            elif not hasZ and hasM:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'ENABLED', u'DISABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)
            else:
                gp.CreateFeatureClass_management(tempWorkspace, u'Temp', 
u'POINT', u'', u'ENABLED', u'ENABLED', spatialReference, configKeyword, 
spatialGrid1, spatialGrid2, spatialGrid3)

            tempFC = os.path.join(tempWorkspace, u'Temp' + tempExt)

            # Append the points.

            cls.AppendPointsToFeatureClass2(tempFC, xyCoordinates, 
zCoordinates, mValues)

            # Extract the output feature class from the temporary
            # directory or geodb.

            oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
            Logger.SetLogInfoAsDebug(True)
            try:
                GeoprocessorManager.CopyArcGISObject(tempFC, featureClass, 
overwriteExisting, [u'featureclass', u'shapefile'], _(u'feature class'))
            finally:
                Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)

        finally:
            # If we created a temporary personal geodatabase,
            # delete it now. If we do not explicitly delete it
            # here, the geoprocessor will keep a handle open
            # through MS Access APIs, and the temporary directory
            # will not be able to be deleted.

            if tempGeoDB is not None:
                try:
                    gp.Delete_management(tempGeoDB)
                except:
                    pass

    @classmethod
    def FindNearestFeatures(cls, pointFeatures, nearFeatures, 
searchRadius=None, fidField=None, distanceField=None, angleField=None, 
overlappingPolygonDistance=u'Zero', wherePointFeatures=None, 
whereNearFeatures=None, nearestFieldsToCopy=None, 
destinationPointFields=None):
        cls.__doc__.Obj.ValidateMethodInvocation()
        try:
            # Validate and/or create the point fields.

            fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields, fidFieldNullValue, distanceFieldNullValue, 
angleFieldNullValue, destinationPointFieldsNullValues, tempJoinFIDField, 
tempNearFIDField = cls._ValidateAndCreatePointFields(pointFeatures, 
nearFeatures, fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields)
            try:

                # If the point feature class is empty, return now.

                from GeoEco.ArcGIS import GeoprocessorManager
                gp = GeoprocessorManager.GetWrappedGeoprocessor()

                if gp.GetCount_management(pointFeatures) <= 0:
                    Logger.Info(_(u'The point feature class %(points)s is 
empty. There is no work to do.') % {u'points': pointFeatures})
                    return pointFeatures

                # Create a temp directory and geodatabase to hold temp
                # feature classes.

                from GeoEco.DataManagement.Directories import 
TemporaryDirectory
                tempDir = TemporaryDirectory()

                tempGeoDB = os.path.join(tempDir.Path, 'Temp.mdb')
                gp.CreatePersonalGDB_management(tempDir.Path, 'Temp')
                try:

                    # Find the near features.

                    cls._FindNearestFeatures(tempDir=tempDir.Path,
                                             tempGeoDB=tempGeoDB,
                                             pointFeatures=pointFeatures,
                                             
tempJoinFIDField=tempJoinFIDField,
                                             
tempNearFIDField=tempNearFIDField,
                                             nearFeatures=nearFeatures,
                                             searchRadius=searchRadius,
                                             fidField=fidField,
                                             
fidFieldNullValue=fidFieldNullValue,
                                             distanceField=distanceField,
                                             
distanceFieldNullValue=distanceFieldNullValue,
                                             angleField=angleField,
                                             
angleFieldNullValue=angleFieldNullValue,
                                             
overlappingPolygonDistance=overlappingPolygonDistance,
                                             
wherePointFeatures=wherePointFeatures,
                                             
whereNearFeatures=whereNearFeatures,
                                             
nearestFieldsToCopy=nearestFieldsToCopy,
                                             
destinationPointFields=destinationPointFields,
                                             
destinationPointFieldsNullValues=destinationPointFieldsNullValues,
                                             skipArgumentValidation=True)

                # Delete the temp geodatabase. If we do not explicitly
                # delete it here, the geoprocessor will keep a handle open
                # through MS Access APIs, and the temporary directory will
                # not be able to be deleted.

                finally:
                    try:
                        gp.Delete_management(tempGeoDB)
                    except:
                        pass

            # Delete the temporary fields that
            # _ValidateAndCreatePointFields created in the caller's
            # points.

            finally:
                from GeoEco.DatabaseAccess.ArcGIS import 
ArcGIS91DatabaseConnection
                conn = ArcGIS91DatabaseConnection()
                try:
                    conn.DeleteField(pointFeatures, tempJoinFIDField)
                except:
                    pass
                if fidField is None:
                    try:
                        conn.DeleteField(pointFeatures, tempNearFIDField)
                    except:
                        pass

        except:
            Logger.LogExceptionAsError()
            raise

        # Return successfully.

        return pointFeatures

    @classmethod
    def _ValidateAndCreatePointFields(cls, pointFeatures, nearFeatures, 
fidField=None, distanceField=None, angleField=None, nearestFieldsToCopy=None, 
destinationPointFields=None):

        # Validate that the caller provided a sufficient number and
        # combination of field parameters.
        
        if fidField is None and distanceField is None and angleField is None 
and nearestFieldsToCopy is None:
            Logger.RaiseException(ValueError(_(u'The FID field, distance 
field, angle field, and fields to copy parameters cannot all be omitted. You 
must specify at least one of these parameters.')))

        if nearestFieldsToCopy is not None and fidField is None:
            Logger.RaiseException(ValueError(_(u'You specified fields to copy 
from the near features but did not specify a field for the FID fo the near 
features. In order to copy fields, you must specify a field for the FID.')))

        # If the caller provided nearestFieldsToCopy, pointFeatures
        # and nearFeatures cannot have the same basename, because we
        # have to join them.

        if nearestFieldsToCopy is not None and 
os.path.basename(pointFeatures) == os.path.basename(nearFeatures):
            Logger.RaiseException(ValueError(_(u'You requested that fields be 
copied from the near features to the point features, but the point features 
and near features have the same base name %(name)s. In order to copy fields 
from one to the other, they must have different base names (this constraint 
is imposed by the ArcGIS Add Join tool, which is used to implement the 
copying).') % {u'name': os.path.basename(pointFeatures)}))

        # Validate or create the FID field.

        from GeoEco.DatabaseAccess.ArcGIS import ArcGIS91DatabaseConnection
        conn = ArcGIS91DatabaseConnection()

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        fidFieldNullValue = 'NULL'
        if fidField is not None:
            addedField = False
            if conn.FieldExists(pointFeatures, fidField):
                dt = conn.GetFieldDataType(pointFeatures, fidField)
                if dt != u'LONG':
                    Logger.RaiseException(ValueError(_(u'The field %(field)s 
of the point features cannot be used to store the feature ID of the near 
feature because it has the data type %(dt)s. This field must have the data 
type of LONG. Please specify the name of a different field. If you specify a 
non-existing field, it will be created for you.') % {u'field': fidField, 
u'dt': dt}))
            else:
                fidField = conn.AddField(pointFeatures, fidField, u'LONG')
                addedField = True
                
            if not conn.FieldIsNullable(pointFeatures, fidField):
                fidFieldNullValue = -1
                if addedField:
                    gp.CalculateField_management(pointFeatures, fidField, 
str(fidFieldNullValue))

        # Validate or create the distance field.

        distanceFieldNullValue = 'NULL'
        if distanceField is not None:
            addedField = False
            if conn.FieldExists(pointFeatures, distanceField):
                dt = conn.GetFieldDataType(pointFeatures, distanceField)
                if dt not in [u'FLOAT', u'DOUBLE']:
                    Logger.RaiseException(ValueError(_(u'The field %(field)s 
of the point features cannot be used to store the distance to the near 
feature because it has the data type %(dt)s. This field must have the data 
type FLOAT or DOUBLE. Please specify the name of a different field. If you 
specify a non-existing field, it will be created for you.') % {u'field': 
distanceField, u'dt': dt}))
            else:
                distanceField = conn.AddField(pointFeatures, distanceField, 
u'DOUBLE')
                addedField = True
                
            if not conn.FieldIsNullable(pointFeatures, distanceField):
                distanceFieldNullValue = -999999999999.
                if addedField:
                    gp.CalculateField_management(pointFeatures, 
distanceField, str(distanceFieldNullValue))

        # Validate or create the angle field.

        angleFieldNullValue = 'NULL'
        if angleField is not None:
            addedField = False
            if conn.FieldExists(pointFeatures, angleField):
                dt = conn.GetFieldDataType(pointFeatures, angleField)
                if dt not in [u'FLOAT', u'DOUBLE']:
                    Logger.RaiseException(ValueError(_(u'The field %(field)s 
of the point features cannot be used to store the angle to the near feature 
because it has the data type %(dt)s. This field must have the data type FLOAT 
or DOUBLE. Please specify the name of a different field. If you specify a 
non-existing field, it will be created for you.') % {u'field': angleField, 
u'dt': dt}))
            else:
                angleField = conn.AddField(pointFeatures, angleField, 
u'DOUBLE')
                addedField = True
                
            if not conn.FieldIsNullable(pointFeatures, angleField):
                angleFieldNullValue = -9999.
                if addedField:
                    gp.CalculateField_management(pointFeatures, angleField, 
str(angleFieldNullValue))

        # Validate or create the destination fields.

        if destinationPointFields is not None and (nearestFieldsToCopy is 
None or len(nearestFieldsToCopy) < len(destinationPointFields)):
            Logger.RaiseException(ValueError(_(u'The number of point fields 
to receive copied values exceeds the number of near feature fields to copy 
values from. For each point field, you must also specify a near feature 
field.')))

        destinationPointFieldsNullValues = []
        
        if nearestFieldsToCopy is not None:
            if destinationPointFields is None:
                destinationPointFields = []
            if len(destinationPointFields) < len(nearestFieldsToCopy):
                
destinationPointFields.extend(nearestFieldsToCopy[len(destinationPointFields):])
            for i in range(len(nearestFieldsToCopy)):
                if nearFeatures is not None:
                    sourceDT = conn.GetFieldDataType(nearFeatures, 
nearestFieldsToCopy[i])
                addedField = False
                if conn.FieldExists(pointFeatures, destinationPointFields[i]):
                    destDT = conn.GetFieldDataType(pointFeatures, 
destinationPointFields[i])
                    if nearFeatures is not None and \
                       (sourceDT == u'SHORT' and destDT not in [u'SHORT', 
u'LONG', u'FLOAT', u'DOUBLE', u'TEXT'] or \
                        sourceDT == u'LONG' and destDT not in [u'LONG', 
u'FLOAT', u'DOUBLE', u'TEXT'] or \
                        sourceDT == u'FLOAT' and destDT not in [u'FLOAT', 
u'DOUBLE', u'TEXT'] or \
                        sourceDT == u'DOUBLE' and destDT not in [u'DOUBLE', 
u'TEXT'] or \
                        sourceDT == u'TEXT' and destDT not in [u'TEXT'] or \
                        sourceDT == u'DATE' and destDT not in [u'DATE', 
u'TEXT']):
                        Logger.RaiseException(ValueError(_(u'Field %(nf)s of 
the near features cannot be copied to field %(pf)s of the point features 
because the data types are incompatible: %(ndt)s values cannot be coerced 
into %(pdt)s values, at least not without a loss of data. Please specify a 
different destination field of the point features. If you specify a 
non-existing field, it will be created for you.') % {u'nf': 
nearestFieldsToCopy[i], u'pf': destinationPointFields[i], u'ndt': sourceDT, 
u'pdt': destDT}))
                else:
                    if nearFeatures is None:
                        Logger.RaiseException(ValueError(_(u'You specified 
that the %(source)s field of the near features should be copied to the 
%(dest)s field of the point features, but that point field does not exist. In 
this situation, this tool is designed to create the point field 
automatically. But you did not provide a near feature class or layer, so the 
tool cannot determine what data type should be used to create the field. 
Please create the field yourself and try again, or provide a near feature 
class or layer that contains the field.') % {u'source': 
nearestFieldsToCopy[i], u'dest': destinationPointFields[i]}))
                    destDT = sourceDT
                    destinationPointFields[i] = conn.AddField(pointFeatures, 
destinationPointFields[i], destDT)     # TODO: copy length, precision, etc.
                    addedField = True

                if not conn.FieldIsNullable(pointFeatures, 
destinationPointFields[i]):
                    if destDT == u'SHORT':
                        destinationPointFieldsNullValues.append(-999)
                    elif destDT == u'LONG':
                        destinationPointFieldsNullValues.append(-99999999)
                    elif destDT in [u'FLOAT', u'DOUBLE']:
                        destinationPointFieldsNullValues.append(-1e+030)
                    elif destDT in [u'TEXT']:
                        destinationPointFieldsNullValues.append('""')
                    else:
                        destinationPointFieldsNullValues.append(None)
                    if addedField:
                        gp.CalculateField_management(pointFeatures, 
destinationPointFields[i], str(destinationPointFieldsNullValues[i]))
                else:
                    destinationPointFieldsNullValues.append('NULL')

                if destinationPointFieldsNullValues[i] != 'NULL':
                    Logger.Warning(_(u'Because field %(field)s of the point 
features cannot receive NULL values, the value %(val)s will be stored instead 
of NULL.') % {u'field': destinationPointFields[i], u'val': 
str(destinationPointFieldsNullValues[i])})

        # Create a couple of temporary fields to hold FIDs. We will
        # delete these when our processing is complete.
        #
        # tempJoinFIDField contains a copy of the FID of the point
        # features. We need this field so we are assured of a stable
        # copy of the original FID that survives geoprocessing
        # operations.
        #
        # tempNearFIDField contains the FID of the near feature. We
        # only create this field of the caller did not specify a
        # destination FID field. We need this, ultimately, because the
        # ArcGIS Calculate Field tool cannot copy a NULL value from
        # one field to another. When a near feature is not found
        # within the search radius, Near_analysis stores -1 for the
        # FID. We need to copy it to the caller's points and THEN set
        # it to NULL.

        import random
        
        tempJoinFIDField = None
        tempNearFIDField = fidField

        while tempJoinFIDField is None or conn.FieldExists(pointFeatures, 
tempJoinFIDField):
            tempJoinFIDField = 'OFID_' + str(random.randint(10000,99999))
        conn.AddField(pointFeatures, tempJoinFIDField, 'LONG')
        try:
            gp.CalculateField_management(pointFeatures, tempJoinFIDField, '[' 
+ gp.Describe(pointFeatures).OIDFieldName + ']')

            if fidField is not None:
                tempNearFIDField = fidField
            else:
                while tempNearFIDField is None or 
conn.FieldExists(pointFeatures, tempNearFIDField):
                    tempNearFIDField = 'NFID_' + 
str(random.randint(10000,99999))
                conn.AddField(pointFeatures, tempNearFIDField, 'LONG')
        except:
            try:
                conn.DeleteField(pointFeatures, tempJoinFIDField)
            except:
                pass
            raise

        # Return successfully.

        return fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields, fidFieldNullValue, distanceFieldNullValue, 
angleFieldNullValue, destinationPointFieldsNullValues, tempJoinFIDField, 
tempNearFIDField

    @classmethod
    def _FindNearestFeatures(cls, tempDir, tempGeoDB, pointFeatures, 
tempJoinFIDField, tempNearFIDField, nearFeatures, searchRadius=None, 
fidField=None, fidFieldNullValue=None, distanceField=None, 
distanceFieldNullValue=None, angleField=None, angleFieldNullValue=None, 
overlappingPolygonDistance=u'Zero', wherePointFeatures=None, 
whereNearFeatures=None, nearestFieldsToCopy=None, 
destinationPointFields=None, destinationPointFieldsNullValues=None, 
skipArgumentValidation=False):
        if not skipArgumentValidation:
            cls.__doc__.Obj.ValidateMethodInvocation()

        # Obtain metadata about the points and near features.

        from GeoEco.ArcGIS import GeoprocessorManager
        gp = GeoprocessorManager.GetWrappedGeoprocessor()

        pointFeaturesDescribe = gp.Describe(pointFeatures)
        pointFeaturesInShapefile = pointFeaturesDescribe.DataType.lower() == 
'shapefile'
        pointFeaturesCS = 
gp.CreateSpatialReference_management(pointFeatures).split(';')[0]
        if GeoprocessorManager.GetArcGISMajorVersion() == 9 and 
GeoprocessorManager.GetArcGISMinorVersion() == 1:
            pointsAreProjected = 
hasattr(pointFeaturesDescribe.SpatialReference, 'Classification')
        else:
            pointsAreProjected = 
pointFeaturesDescribe.SpatialReference.ProjectionCode != 0

        nearFeaturesDescribe = gp.Describe(nearFeatures)
        nearFeaturesInShapefile = nearFeaturesDescribe.DataType.lower() == 
'shapefile'
        nearFeaturesCS = 
gp.CreateSpatialReference_management(nearFeatures).split(';')[0]
        if GeoprocessorManager.GetArcGISMajorVersion() == 9 and 
GeoprocessorManager.GetArcGISMinorVersion() == 1:
            nearAreProjected = hasattr(nearFeaturesDescribe.SpatialReference, 
'Classification')
        else:
            nearAreProjected = 
nearFeaturesDescribe.SpatialReference.ProjectionCode != 0

        # Validate that either the points or the near features are
        # projected.

        if not pointsAreProjected and not nearAreProjected:
            Logger.RaiseException(ValueError(_(u'Neither the point features 
(%(points)s) nor the near features (%(near)s) use a projected coordinate 
system. One or the other of these must use a projected coordinate system. 
Please project one or the other of them and try again.') % {u'points': 
pointFeatures, u'near': nearFeatures}))

        # Copy the caller's points into the temp geodatabase,
        # selecting the points specified by the caller's where clause
        # (if any) and only copying the tempJoinFIDField field.

        pointsLayer = GeoprocessorManager.GetUniqueLayerName()

        fieldInfo = []
        visibleFields = [pointFeaturesDescribe.ShapeFieldName, 
pointFeaturesDescribe.OIDFieldName, tempJoinFIDField]
        fields = gp.ListFields(pointFeatures)
        f = fields.Next()
        while f is not None:
            if f.Name not in visibleFields:
                fieldInfo.append(f.Name + ' ' + f.Name + ' HIDDEN')
            elif f.Name == tempJoinFIDField:
                fieldInfo.append(f.Name + ' ' + f.Name + ' VISIBLE')
            f = fields.Next()
        fieldInfo = ';'.join(fieldInfo)

        gp.MakeFeatureLayer_management(pointFeatures, pointsLayer, 
wherePointFeatures, None, fieldInfo)
        try:
            if gp.GetCount_management(pointsLayer) <= 0:
                if wherePointFeatures is None:
                    Logger.Info(_(u'The point feature class %(points)s is 
empty. There is no work to do.') % {u'points': pointFeatures})
                else:
                    Logger.Info(_(u'The where clause %(where)s did not select 
any points from feature class %(points)s. There is no work to do.') % 
{u'where': wherePointFeatures, u'points': pointFeatures})
                return

            Logger.Info(_(u'Copying the points.'))
            
            if os.path.splitext(os.path.basename(pointFeatures))[0].lower() 
!= 'copiedpoints':       # Our temp name has to be different than 
pointFeatures, so we can join the two.
                copiedPoints = os.path.join(tempGeoDB, 'CopiedPoints')
            else:
                copiedPoints = os.path.join(tempGeoDB, 'CopiedPoints1')
            if gp.Exists(copiedPoints):
                gp.Delete(copiedPoints)
                
            gp.CopyFeatures_management(pointsLayer, copiedPoints)
        finally:
            try:
                gp.Delete(pointsLayer)
            except:
                pass

        # If the points are not projected, or are projected but
        # not in the near features' coordinate system, project
        # them to the near features coordinate system.
        #
        # Note: Do not try to combine this with the copying step
        # above. Unfortunately, for shapefiles, the ArcGIS 9.2
        # Project tool ignores the where clause specified to Make
        # Feature Layer and projects the entire shapefile, not
        # just the features selected by the where clause.

        if not pointsAreProjected or pointsAreProjected and nearAreProjected 
and pointFeaturesCS.lower() != nearFeaturesCS.lower():
            Logger.Info(_(u'Projecting the points to the near features\' 
coordinate system.'))
            
            if os.path.splitext(os.path.basename(pointFeatures))[0].lower() 
!= 'projectedpoints':       # Our temp name has to be different than 
pointFeatures, so we can join the two.
                projectedPoints = os.path.join(tempGeoDB, 'ProjectedPoints')
            else:
                projectedPoints = os.path.join(tempGeoDB, 'ProjectedPoints1')
            if gp.Exists(projectedPoints):
                gp.Delete(projectedPoints)
                
            gp.Project_management(copiedPoints, projectedPoints, 
nearFeaturesCS)

        # Otherwise, the points are already in the desired coordinate
        # system and we can just use the ones that we copied.

        else:
            projectedPoints = copiedPoints

        # We are now going to do any necessary processing with the
        # near features prior to running the Near_analysis tool. If
        # the near features are a shapefile, we have an important
        # constraint: ArcGIS tools such as Select_analysis and
        # CopyFeatures_management, when provided a where clause, do
        # not assign the FIDs of the output features to those of the
        # input shapefile features. They renumber the FIDs starting
        # with 0. But we must keep the original FIDs throughout our
        # processing because we need Near_analysis to populate the
        # NEAR_FID field with the original FIDs. (We got around this
        # problem with the point features by requiring the caller to
        # copy the FIDs to the tempJoinFIDField field, but we cannot
        # do that with the near features because we want to treat them
        # as read-only.)
        #
        # First, project the near features, if necessary. To maximize
        # performance and minimize space utilization, we can omit
        # fields that are not referenced by the caller's where clause
        # (if any).

        if not nearAreProjected:
            Logger.Info(_(u'Projecting the near features to the points\' 
coordinate system.'))

            nearFeaturesLayer = GeoprocessorManager.GetUniqueLayerName()

            fieldInfo = []
            fieldsToIgnore = [pointFeaturesDescribe.ShapeFieldName, 
pointFeaturesDescribe.OIDFieldName]
            fields = gp.ListFields(nearFeatures)
            f = fields.Next()
            while f is not None:
                if f.Name not in fieldsToIgnore:
                    if whereNearFeatures is None or f.Name.lower() not in 
whereNearFeatures.lower():
                        fieldInfo.append(f.Name + ' ' + f.Name + ' HIDDEN')
                    else:
                        fieldInfo.append(f.Name + ' ' + f.Name + ' VISIBLE')
                f = fields.Next()
            fieldInfo = ';'.join(fieldInfo)

            if not nearFeaturesInShapefile:
                gp.MakeFeatureLayer_management(nearFeatures, 
nearFeaturesLayer, whereNearFeatures, None, fieldInfo)     # If not a 
shapefile, Project_management will honor the where clause and maintain 
original OBJECTIDs in the output, so we might as well apply whereNearFeatures
            else:
                gp.MakeFeatureLayer_management(nearFeatures, 
nearFeaturesLayer, None, None, fieldInfo)                  # If a shapefile, 
Project_management will ignore the where clause and project all the points 
anyway
            try:
                if nearFeaturesInShapefile:
                    projectedNearFeatures = os.path.join(tempDir, 
'ProjectedNear.shp')
                else:
                    projectedNearFeatures = os.path.join(tempGeoDB, 
'ProjectedNear')
                if gp.Exists(projectedNearFeatures):
                    gp.Delete(projectedNearFeatures)
                    
                gp.Project_management(nearFeatures, projectedNearFeatures, 
pointFeaturesCS)
            finally:
                try:
                    gp.Delete(nearFeaturesLayer)
                except:
                    pass

        # If we did not need to project the near features, we can just
        # use them directly.

        else:
            projectedNearFeatures = nearFeatures

        # Create a feature layer that selects the near features
        # specified by the caller's where clause (if any).

        convertedNearFeaturesToLines = False
        projectedNearLayer = GeoprocessorManager.GetUniqueLayerName()
        gp.MakeFeatureLayer_management(projectedNearFeatures, 
projectedNearLayer, whereNearFeatures)
        try:

            # Determine if the near features are empty.

            totalNearFeatures = gp.GetCount_management(projectedNearLayer)
            if totalNearFeatures <= 0:
                if whereNearFeatures is not None:
                    Logger.Info(_(u'The where clause %(where)s did not select 
any features from near feature class %(near)s. All points will be updated 
with NULL values (or the equivalent).') % {u'where': whereNearFeatures, 
u'near': nearFeatures})
                else:
                    Logger.Info(_(u'The near feature class %(near)s is empty. 
All points will be updated with NULL values (or the equivalent).') % 
{u'near': nearFeatures})
            else:
                
                # The near features are not empty. If they are
                # polylines or polygons, we need to do some special
                # processing. If they are polygons, we need to convert
                # them to polylines, because the ArcGIS 9.2 and lower
                # Near_analysis tool cannot operate on polygons. Also,
                # regardless of whether the caller provided polylines
                # or we got some by converting the caller's polygons,
                # we have to work around an apparent bug that exists
                # in ArcGIS 9.2 that causes Near_analysis to not work
                # right on polylines that contain more than two
                # vertices (i.e. polylines that contain multiple line
                # segments). With Arc 9.2 SP6, I noticed Near was
                # calculating the distance to the wrong polylines.
                # This seemed to be rectified if I split the lines
                # using the Split Lines at Vertices tool.
                #
                # So: First call Feature To Line. If the near features
                # are polygons, it will convert them to polylines. If
                # they are polylines already, it will copy them. In
                # both cases, Feature To Line will add a FID field
                # that we can reference later, to obtain the FID of
                # the original feature (polygon or polyline).
                #
                # Next: Call Split Lines at Vertices to produce a
                # feature class of lines having only two vertices.
                #
                # TODO: Check whether we can omit these steps with Arc
                # 9.3. The 9.3 Near tool appears to have been
                # completely rewritten.
                
                if nearFeaturesDescribe.ShapeType.lower() in ['polygon', 
'polyline']:
                    if nearFeaturesDescribe.ShapeType.lower() == 'polygon':
                        Logger.Info(_(u'Converting the polygons to lines.'))
                    else:
                        Logger.Info(_(u'Copying the near features.'))

                    convertedLinesBeforeSplit = os.path.join(tempGeoDB, 
'ConvertedLinesBeforeSplit')
                    if gp.Exists(convertedLinesBeforeSplit):
                        gp.Delete(convertedLinesBeforeSplit)

                    gp.FeatureToLine_management(projectedNearLayer, 
convertedLinesBeforeSplit)

                    Logger.Info(_(u'Splitting the lines to work around a bug 
in the ArcGIS Near tool.'))

                    convertedLines = os.path.join(tempGeoDB, 'ConvertedLines')
                    if gp.Exists(convertedLines):
                        gp.Delete(convertedLines)

                    gp.SplitLine_management(convertedLinesBeforeSplit, 
convertedLines)

                    convertedNearFeaturesToLines = True
                
                Logger.Info(_(u'Finding the near features nearest to the 
points.'))

            # Run Near_analysis. Run it even if there are no near
            # features, so it will add the fields to the point feature
            # class.

            if angleField is not None:
                angleParam = u'ANGLE'
            else:
                angleParam = u'NO_ANGLE'

            if convertedNearFeaturesToLines:
                gp.Near_analysis(projectedPoints, convertedLines, 
searchRadius, u'NO_LOCATION', angleParam)
            else:
                gp.Near_analysis(projectedPoints, projectedNearLayer, 
searchRadius, u'NO_LOCATION', angleParam)
        
        # Delete the near features layer.

        finally:
            try:
                gp.Delete(projectedNearLayer)
            except:
                pass

        # If the near features are polygons or polylines, we converted
        # them to single-segment lines prior to running Near_analysis.
        # Near_analysis stored the line FIDs in the NEAR_FID field.
        # But we need the FIDs of the original polygons or polylines.
        # FeatureToLine_management added them to the lines as an
        # attribute. Now, add a field called NEAR_FID2 and populate it
        # with the original FIDs.

        NEAR_FID_FieldName = 'NEAR_FID'
        if convertedNearFeaturesToLines:

            # Add NEAR_FID2 to the temporary projected points in the
            # geodatabase, initializing it to -1.

            from GeoEco.DatabaseAccess.ArcGIS import 
ArcGIS91DatabaseConnection
            conn = ArcGIS91DatabaseConnection()
            
            NEAR_FID_FieldName = 'NEAR_FID2'
            conn.AddField(projectedPoints, 'NEAR_FID2', 'LONG')
            gp.CalculateField_management(projectedPoints, 'NEAR_FID2', '-1')

            # Join the projected points to the lines and copy the
            # original FIDs to NEAR_FID2.

            projectedPointsLayer = GeoprocessorManager.GetUniqueLayerName()
            gp.MakeFeatureLayer_management(projectedPoints, 
projectedPointsLayer)
            try:
                gp.AddJoin_management(projectedPointsLayer, 'NEAR_FID', 
convertedLines, gp.Describe(convertedLines).OIDFieldName, 'KEEP_COMMON')
                try:
                    if gp.GetCount_management(projectedPointsLayer) > 0:
                        gp.CalculateField_management(projectedPointsLayer, 
os.path.basename(projectedPoints) + '.NEAR_FID2', '[ConvertedLines.' + 
conn.GetFieldNameAtIndex(convertedLines, 2) + ']')
                finally:
                    gp.RemoveJoin_management(projectedPointsLayer, 
'ConvertedLines')

                # If the near features are polygons, it is possible
                # that some of the points overlap them. We need to
                # detect this, for two reasons:
                #
                # 1) Near_analysis calculated the distance to the edge of
                #    the polygon. The caller might want us to set the
                #    distance to zero or negative.
                #
                # 2) If the caller's polygons shared borders (e.g.
                #    adjacent cells of a grid), those borders were
                #    converted to overlapping lines. We don't know which
                #    line Near_analysis picked as the nearest. If it
                #    picked the line corresponding to the adjacent
                #    polygon, it would cause us to obtain the FID and
                #    other desired fields from that polygon, rather than
                #    the one that the point overlaps. The caller wants the
                #    overlapped polygon.
                #
                # So: intersect the points with the polygons, join the
                # resulting feature class back to the points, copy the
                # FIDs from the intersecting polygons to the NEAR_FID2
                # field fo the points, and adjust the NEAR_DIST field as
                # requested by the caller.

                if nearFeaturesDescribe.ShapeType.lower() == 'polygon':
                    Logger.Info(_(u'Intersecting the points with the polygons 
to detect points that overlap the polygons.'))

                    intersectedPoints = os.path.join(tempGeoDB, 
'IntersectedPoints')
                    if gp.Exists(intersectedPoints):
                        gp.Delete(intersectedPoints)

                    projectedNearLayer = 
GeoprocessorManager.GetUniqueLayerName()
                    gp.MakeFeatureLayer_management(projectedNearFeatures, 
projectedNearLayer, whereNearFeatures)
                    try:
                        
                        # Unlike previous releases, the Intersect tool
                        # in ArcGIS 9.3 will fail with the error
                        # "ERROR 000953: Extent of the overlay
                        # operation will be empty." if no points
                        # intersect the polygons. This problem can be
                        # avoided by explicitly specifying the Extent
                        # environment setting. I consider this a bug
                        # in ArcGIS since it worked in the previous
                        # release.

                        if GeoprocessorManager.GetArcGISMajorVersion() > 9 or 
GeoprocessorManager.GetArcGISMajorVersion() == 9 and 
GeoprocessorManager.GetArcGISMinorVersion() >= 3:
                            oldExtent = gp.Extent
                            gp.Extent = 'MAXOF'
                        try:
                            gp.Intersect_analysis(projectedPoints + ' #;' + 
projectedNearLayer + ' #', intersectedPoints, 'ONLY_FID')
                        finally:
                            if GeoprocessorManager.GetArcGISMajorVersion() > 
9 or GeoprocessorManager.GetArcGISMajorVersion() == 9 and 
GeoprocessorManager.GetArcGISMinorVersion() >= 3:
                                gp.Extent = oldExtent
                        
                    finally:
                        try:
                            gp.Delete(projectedNearLayer)
                        except:
                            pass

                    gp.AddJoin_management(projectedPointsLayer, 
gp.Describe(projectedPoints).OIDFieldName, intersectedPoints, 
conn.GetFieldNameAtIndex(intersectedPoints, 2), 'KEEP_COMMON')
                    try:
                        if gp.GetCount_management(projectedPointsLayer) > 0:
                            pointsFCName = os.path.basename(projectedPoints)
                            
gp.CalculateField_management(projectedPointsLayer, pointsFCName + 
'.NEAR_FID2', '[IntersectedPoints.' + 
conn.GetFieldNameAtIndex(convertedLines, 2) + ']')
                            if distanceField is not None:
                                if overlappingPolygonDistance == 'zero':
                                    
gp.CalculateField_management(projectedPointsLayer, pointsFCName + 
'.NEAR_DIST', '0')
                                elif overlappingPolygonDistance == 'negative':
                                    
gp.CalculateField_management(projectedPointsLayer, pointsFCName + 
'.NEAR_DIST', '0 - [' + pointsFCName + '.NEAR_DIST]')
                    finally:
                        gp.RemoveJoin_management(projectedPointsLayer, 
'IntersectedPoints')

            # Delete the projected point features layer that we had to
            # create to accomplish the joins.

            finally:
                try:
                    gp.Delete(projectedPointsLayer)
                except:
                    pass

        # We are now ready to populate the caller's specified fields
        # of pointFeatures. Join projectedPoints to pointFeatures on
        # tempJoinFIDField.

        Logger.Info(_(u'Updating the points\' fields.'))

        pointsLayer = GeoprocessorManager.GetUniqueLayerName()
        gp.MakeFeatureLayer_management(pointFeatures, pointsLayer)
        try:
            pointsFCName = 
os.path.splitext(os.path.basename(pointFeatures))[0]
            projectedPointsFCName = os.path.basename(projectedPoints)
            gp.AddJoin_management(pointsLayer, tempJoinFIDField, 
projectedPoints, tempJoinFIDField, 'KEEP_COMMON')
            try:

                # Copy the NEAR_FID (or NEAR_FID2), NEAR_DIST, and
                # NEAR_ANGLE to the callers specified fields of
                # pointFeatures. If the caller did not specify a
                # fidField, we copy NEAR_FID (or NEAR_FID2) to a
                # temporary field that we created.
                
                gp.CalculateField_management(pointsLayer, pointsFCName + '.' 
+ tempNearFIDField, '[' + projectedPointsFCName + '.' + NEAR_FID_FieldName + 
']')      # Note: if fidField was specified by the caller, tempNearFIDField 
== fidField
                if distanceField is not None:
                    gp.CalculateField_management(pointsLayer, pointsFCName + 
'.' + distanceField, '[' + projectedPointsFCName + '.NEAR_DIST]')
                if angleField is not None:
                    gp.CalculateField_management(pointsLayer, pointsFCName + 
'.' + angleField, '[' + projectedPointsFCName + '.NEAR_ANGLE]')

                # If the caller specified fields to copy from the near
                # features to the point features, join the near
                # features to pointsLayer on fidField (or
                # tempNearFIDField) and copy the fields.

                if nearestFieldsToCopy is not None:
                    gp.SelectLayerByAttribute_management(pointsLayer, 
'NEW_SELECTION', pointsFCName + '.' + tempNearFIDField + ' >= 0')
                    if gp.GetCount_management(pointsLayer) > 0:
                        nearFCName = 
os.path.splitext(os.path.basename(nearFeatures))[0]
                        gp.AddJoin_management(pointsLayer, tempNearFIDField, 
nearFeatures, nearFeaturesDescribe.OIDFieldName, 'KEEP_COMMON')
                        try:
                            for i in range(len(nearestFieldsToCopy)):
                                gp.CalculateField_management(pointsLayer, 
destinationPointFields[i], '[' + nearFCName + '.' + nearestFieldsToCopy[i] + 
']')
                        finally:
                            gp.RemoveJoin_management(pointsLayer, nearFCName)

                # At this point, fidField (or tempNearFIDField) of
                # pointFeatures has -1 for all points for which there
                # was no near feature. Select these points and set
                # their various fields to NULL, or the equivalent.

                gp.SelectLayerByAttribute_management(pointsLayer, 
'NEW_SELECTION', pointsFCName + '.' + tempNearFIDField + ' = -1')
                if gp.GetCount_management(pointsLayer) > 0:
                    if distanceField is not None:
                        gp.CalculateField_management(pointsLayer, 
pointsFCName + '.' + distanceField, str(distanceFieldNullValue))
                    if angleField is not None:
                        gp.CalculateField_management(pointsLayer, 
pointsFCName + '.' + angleField, str(angleFieldNullValue))

                    if nearestFieldsToCopy is not None:
                        for i in range(len(nearestFieldsToCopy)):
                            gp.CalculateField_management(pointsLayer, 
pointsFCName + '.' + destinationPointFields[i], 
str(destinationPointFieldsNullValues[i]))
                        
                    if fidField is not None and fidFieldNullValue != -1:
                        gp.CalculateField_management(pointsLayer, 
pointsFCName + '.' + fidField, str(fidFieldNullValue))      # Not sure if 
this must be done last, but doing it anyway, for safety

            finally:
                gp.RemoveJoin_management(pointsLayer, projectedPointsFCName)
        finally:
            try:
                gp.Delete(pointsLayer)
            except:
                pass

    @classmethod
    def FindNearestFeaturesListedInField(cls, pointFeatures, 
nearFeaturesField, searchRadius=None, fidField=None, distanceField=None, 
angleField=None, overlappingPolygonDistance=u'Zero', wherePointFeatures=None, 
whereNearFeaturesField=None, nearestFieldsToCopy=None, 
destinationPointFields=None):
        cls.__doc__.Obj.ValidateMethodInvocation()
        try:

            # If the caller did not specify any fields to copy from
            # the near features to the point features, validate and/or
            # create the point fields now.
            #
            # If they did specify fields to copy, we can't perform
            # this validation until we obtain one of the near feature
            # classes or layers, so we can examine the data types of
            # the fields.

            if nearestFieldsToCopy is None:
                fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields, fidFieldNullValue, distanceFieldNullValue, 
angleFieldNullValue, destinationPointFieldsNullValues, tempJoinFIDField, 
tempNearFIDField = cls._ValidateAndCreatePointFields(pointFeatures, 
nearFeatures, fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields)
            try:

                # Use the Frequency_analysis tool to count the unique
                # combinations of near features and where clauses present
                # in the caller's table. We must call _FindNearestFeatures
                # once with each unique combination.

                if whereNearFeaturesField is None:
                    Logger.Info(_(u'Enumerating the unique near feature 
classes listed in the %(field)s field.') % {u'field': nearFeaturesField})
                else:
                    Logger.Info(_(u'Enumerating the unique combinations of 
near feature classes listed in the %(field1)s field and where clauses listed 
in the %(field2)s field.') % {u'field1': nearFeaturesField, u'field2': 
whereNearFeaturesField})

                from GeoEco.ArcGIS import GeoprocessorManager
                gp = GeoprocessorManager.GetWrappedGeoprocessor()

                from GeoEco.DatabaseAccess.ArcGIS import 
ArcGIS91DatabaseConnection
                conn = ArcGIS91DatabaseConnection()

                from GeoEco.DataManagement.Directories import 
TemporaryDirectory
                tempDir = TemporaryDirectory()

                nearFeatureCombos = None
                pointsLayer = GeoprocessorManager.GetUniqueLayerName()
                gp.MakeFeatureLayer_management(pointFeatures, pointsLayer, 
wherePointFeatures)
                try:
                    if gp.GetCount_management(pointsLayer) > 0:
                        nearFeatureCombos = []

                        # Run Frequency_analysis to produce DBF file in a
                        # temp directory.
                        
                        freqTable = os.path.join(tempDir.Path, 
GeoprocessorManager.GetUniqueLayerName() + '.dbf')
                        if whereNearFeaturesField is None:
                            gp.Frequency_analysis(pointsLayer, freqTable, 
nearFeaturesField)
                        else:
                            gp.Frequency_analysis(pointsLayer, freqTable, 
nearFeaturesField + ';' + whereNearFeaturesField)

                        # Read the DBF file and populate nearFeatureCombos.

                        nfField = conn.GetFieldNameAtIndex(freqTable, 2)
                        if whereNearFeaturesField is not None:
                            wcField = conn.GetFieldNameAtIndex(freqTable, 3)
                        warnedAboutNull = False
                            
                        cur = conn.OpenSelectCursor(freqTable)
                        try:
                            while cur.NextRow():
                                nf = cur.GetValue(nfField)
                                if nf is not None:
                                    nf = nf.strip()
                                    if len(nf) <= 0:
                                        nf = None

                                if nf is None:
                                    if not warnedAboutNull:
                                        Logger.Warning(_(u'At least one point 
contains NULL or an empty string in the %(field)s field. These points will be 
ignored.') % {u'field': nearFeaturesField})
                                        warnedAboutNull = True
                                else:
                                    if whereNearFeaturesField is None:
                                        nearFeatureCombos.append([nf, None])
                                    else:
                                        wc = cur.GetValue(wcField)      # 
Note: do not convert empty strings or sequences of just whitespace to None 
here. This will be handled later.
                                        nearFeatureCombos.append([nf, wc])
                            pass
                        finally:
                            del cur

                        # Sort nearFeatureCombos, so we process them in a
                        # deterministic order.

                        nearFeatureCombos.sort()
                        
                finally:
                    try:
                        gp.Delete(pointsLayer)
                    except:
                        pass

                # If we didn't get any points with near features, return
                # now.

                if nearFeatureCombos is None or len(nearFeatureCombos) <= 0:
                    if nearFeatureCombos is None:
                        if wherePointFeatures is None:
                            Logger.Info(_('The point feature class does not 
contain any points. There is no work to do.'))
                        else:
                            Logger.Info(_('The where clause did not select 
any points from the point feature class. There is no work to do.'))
                        if nearestFieldsToCopy is not None:
                            Logger.Warning(_(u'You requested that fields be 
copied from the near features to the points, but you did not provide any 
points. As a consequence, this tool could not examine the data types of those 
fields in the near features for the purpose of creating those fields in the 
point features, or, if the fields already exist, validating their data types. 
The point fields were not checked or created.'))
                    else:
                        if wherePointFeatures is None:
                            Logger.Info(_('The point feature class does not 
contain any points that contain a near feature class in the %(field)s field. 
There is no work to do.') % {u'field': nearFeaturesField})
                        else:
                            Logger.Info(_('The where clause did not select 
any points from the point feature class that contain a near feature class in 
the %(field)s field. There is no work to do.') % {u'field': 
nearFeaturesField})
                        if nearestFieldsToCopy is not None:
                            Logger.Warning(_(u'You requested that fields be 
copied from the near features to the points, but none of the points contained 
near features. As a consequence, this tool could not examine the data types 
of those fields in the near features for the purpose of creating those fields 
in the point features, or, if the fields already exist, validating their data 
types. The point fields were not checked or created.'))
                        
                    return pointFeatures

                # Create a temp geodatabase to hold temp feature classes.

                tempGeoDB = os.path.join(tempDir.Path, 'Temp.mdb')
                gp.CreatePersonalGDB_management(tempDir.Path, 'Temp')
                try:

                    # Process each unique combination in nearFeatureCombos.

                    fidFieldNullValue = None
                    distanceFieldNullValue = None
                    angleFieldNullValue = None
                    destinationPointFieldsNullValues = None
                    
                    for i in range(len(nearFeatureCombos)):

                        # If the caller asked us to copy fields from the
                        # near features to the points and this is the
                        # first time through the loop, we will not have
                        # validated the point fields yet. Do it now.

                        if i <= 0 and nearestFieldsToCopy is not None:
                            if not gp.Exists(nearFeatureCombos[i][0]):
                                Logger.RaiseException(ValueError(_(u'The near 
feature class %(fc)s does not exist.') % {u'fc': nearFeatureCombos[i][0]}))
                            fidField, distanceField, angleField, 
nearestFieldsToCopy, destinationPointFields, fidFieldNullValue, 
distanceFieldNullValue, angleFieldNullValue, 
destinationPointFieldsNullValues, tempJoinFIDField, tempNearFIDField = 
cls._ValidateAndCreatePointFields(pointFeatures, nearFeatureCombos[i][0], 
fidField, distanceField, angleField, nearestFieldsToCopy, 
destinationPointFields)

                        # If this is the first time through the loop,
                        # start the progress reporter.

                        if i <= 0:
                            if whereNearFeaturesField is None:
                                Logger.Info(_(u'Finding nearest features for 
%(count)i unique feature classes listed in the %(field)s field.') % 
{u'count': len(nearFeatureCombos), u'field': nearFeaturesField})
                            else:
                                Logger.Info(_(u'Finding nearest features for 
%(count)i unique combinations of near feature classes listed in the 
%(field1)s field and where clauses listed in the %(field2)s field.') % 
{u'count': len(nearFeatureCombos), u'field1': nearFeaturesField, u'field2': 
whereNearFeaturesField})
                            progressReporter = ProgressReporter()
                            progressReporter.Start(len(nearFeatureCombos))

                        # Call _FindNearestFeatures on this combination.

                        where1 = u'%s = \'%s\'' % (nearFeaturesField, 
nearFeatureCombos[i][0])
                        if whereNearFeaturesField is not None:
                            if nearFeatureCombos[i][1] is not None:
                                where1 = u' AND '.join([where1, u'%s = 
\'%s\'' % (whereNearFeaturesField, nearFeatureCombos[i][1].replace("'", 
"''"))])
                            else:
                                where1 = u' AND '.join([where1, u'%s IS NULL' 
% whereNearFeaturesField])
                        if wherePointFeatures is not None:
                            where1 = u' AND '.join([where1, 
wherePointFeatures])

                        where2 = nearFeatureCombos[i][1]
                        if where2 is not None and len(where2.strip()) <= 0:   
  # Now treat empty strings and sequences of whitespace as None. We didn't 
want to do it in where1 above, because that would cause us to not select the 
proper points.
                            where2 = None

                        oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
                        Logger.SetLogInfoAsDebug(True)
                        try:
                            cls._FindNearestFeatures(tempDir=tempDir.Path,
                                                     tempGeoDB=tempGeoDB,
                                                     
pointFeatures=pointFeatures,
                                                     
tempJoinFIDField=tempJoinFIDField,
                                                     
tempNearFIDField=tempNearFIDField,
                                                     
nearFeatures=nearFeatureCombos[i][0],
                                                     
searchRadius=searchRadius,
                                                     fidField=fidField,
                                                     
fidFieldNullValue=fidFieldNullValue,
                                                     
distanceField=distanceField,
                                                     
distanceFieldNullValue=distanceFieldNullValue,
                                                     angleField=angleField,
                                                     
angleFieldNullValue=angleFieldNullValue,
                                                     
overlappingPolygonDistance=overlappingPolygonDistance,
                                                     
wherePointFeatures=where1,
                                                     whereNearFeatures=where2,
                                                     
nearestFieldsToCopy=nearestFieldsToCopy,
                                                     
destinationPointFields=destinationPointFields,
                                                     
destinationPointFieldsNullValues=destinationPointFieldsNullValues)
                        finally:
                            Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)

                        # Report our progress.

                        progressReporter.ReportProgress()

                        if i == 1:
                            break      # TODO: REMOVE

                # Delete the temp geodatabase. If we do not explicitly
                # delete it here, the geoprocessor will keep a handle
                # open through MS Access APIs, and the temporary
                # directory will not be able to be deleted.

                finally:
                    try:
                        pass
                        #gp.Delete_management(tempGeoDB)        # TODO: ENABLE
                    except:
                        pass

            # Delete the temporary fields that
            # _ValidateAndCreatePointFields created in the caller's
            # points.

            finally:
                from GeoEco.DatabaseAccess.ArcGIS import 
ArcGIS91DatabaseConnection
                conn = ArcGIS91DatabaseConnection()
                try:
                    conn.DeleteField(pointFeatures, tempJoinFIDField)       # 
DeleteField succeeds silently if the field does not exist.
                except:
                    pass
                if fidField is None:
                    try:
                        conn.DeleteField(pointFeatures, tempNearFIDField)
                    except:
                        pass

        except:
            Logger.LogExceptionAsError()
            raise

        # Return successfully.

        return pointFeatures


###############################################################################
# Metadata: module
###############################################################################

from GeoEco.ArcGIS import ArcGISDependency, ArcGISProductDependency
from GeoEco.DatabaseAccess import InsertCursor
from GeoEco.Metadata import *
from GeoEco.Types import *

AddModuleMetadata(shortDescription=_(u'Provides methods for general-purpose 
operations with points.'))

###############################################################################
# Metadata: ArcGISPoints class
###############################################################################

AddClassMetadata(ArcGISPoints,
    shortDescription=_(u'Provides methods for general-purpose operations with 
ArcGIS points.'),
    isExposedAsCOMServer=True,
    comIID=u'{AB7A5328-0568-448B-9F7B-1E969F9F4241}',
    comCLSID=u'{E640B02D-4A18-480F-A458-543AA360E153}')

# Public method: ArcGISPoints.InsertPoint

AddMethodMetadata(ArcGISPoints.InsertPoint,
    shortDescription=_(u'Inserts a point with an insert cursor opened to an 
ArcGIS point feature class.'),
    isExposedToPythonCallers=True,
    dependencies=[ArcGISDependency(9, 1)])

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'cls',
    typeMetadata=ClassOrClassInstanceTypeMetadata(cls=ArcGISPoints),
    description=_(u'%s class or an instance of it.') % ArcGISPoints.__name__)

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'insertCursor',
    typeMetadata=ClassInstanceTypeMetadata(cls=InsertCursor),
    description=_(
u"""Insert cursor opened to the feature class that will receive the
point. The cursor will still be open when this function returns."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'x',
    typeMetadata=FloatTypeMetadata(),
    description=_(u"""X coordinate of the point."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'y',
    typeMetadata=FloatTypeMetadata(),
    description=_(u"""Y coordinate of the point."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'z',
    typeMetadata=FloatTypeMetadata(canBeNone=True),
    description=_(
u"""Z coordinate of the point. Only provide this if the feature class
has Z coordinates."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'm',
    typeMetadata=FloatTypeMetadata(canBeNone=True),
    description=_(
u"""Meaure value of the point. Only provide this if the feature class
has measure values."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'attributes',
    typeMetadata=DictionaryTypeMetadata(keyType=UnicodeStringTypeMetadata(), 
valueType=AnyObjectTypeMetadata(), canBeNone=True),
    description=_(
u"""Dictionary of polygon attributes (a.k.a. fields) to set before
inserting the point. The dictionary's keys and values are the
attribute's names and values."""))

AddArgumentMetadata(ArcGISPoints.InsertPoint, u'shapeFieldName',
    typeMetadata=UnicodeStringTypeMetadata(),
    description=_(
u"""Name of the shape field (the geometry field) for the cursor. This
may be obtained from the ShapeFieldName property of object returned by
the geoprocessor's Describe method."""))

# Public method: ArcGISPoints.AppendPointsToFeatureClass

AddMethodMetadata(ArcGISPoints.AppendPointsToFeatureClass,
    shortDescription=_(u'Appends points to an existing ArcGIS point feature 
class.'),
    isExposedToPythonCallers=True,
    dependencies=[ArcGISDependency(9, 1)])

CopyArgumentMetadata(ArcGISPoints.InsertPoint, u'cls', 
ArcGISPoints.AppendPointsToFeatureClass, u'cls')

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'featureClass',
    typeMetadata=ArcGISFeatureClassTypeMetadata(allowedShapeTypes=[u'Point'], 
mustExist=True),
    description=_(u"""Feature class that will receive the points."""),
    arcGISDisplayName=_(u'Point feature class'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'coordinates',
    typeMetadata=ListTypeMetadata(elementType=FloatTypeMetadata(), 
minLength=2, canBeNone=True),
    description=_(
u"""List of coordinates for the points to insert. If the points do not
have Z coordinates nor M values, the list must be of the form::

    [x1, y1, x2, y2, x3, y3, ... ]

If the points have X, Y and Z coordinates but not M values, the list
must be of the form::

    [x1, y1, z1, x2, y2, z2, x3, y3, z3, ... ]

If the points have X and Y coordinates and M values but no Z
coordinates, the list must be of the form::

    [x1, y1, m1, x2, y2, m2, x3, y3, m3, ... ]

If the points have X, Y and Z coordinates and M values, the list must
be of the form::

    [x1, y1, z1, m1, x2, y2, z2, m2, x3, y3, z3, m3, ... ]
"""))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'hasZ',
    typeMetadata=BooleanTypeMetadata(),
    description=_(
u"""Indicates whether or not the input list of coordinates contains Z
coordinates. If it does, you must pass True for this parameter."""))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'hasM',
    typeMetadata=BooleanTypeMetadata(),
    description=_(
u"""Indicates whether or not the input list of coordinates contains
measure values. If it does, you must pass True for this
parameter."""))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'attributes',
    
typeMetadata=ListTypeMetadata(elementType=DictionaryTypeMetadata(keyType=UnicodeStringTypeMetadata(),
 valueType=AnyObjectTypeMetadata(), canBeNone=True), canBeNone=True),
    description=_(
u"""List of dictionaries that parallels the list of coordinates. Each
dictionary defines the attributes (a.k.a. fields) to set for a point
before it is inserted. The dictionary's keys and values are the
attribute's names and values."""))

# Public method: ArcGISPoints.AppendPointsToFeatureClass2

AddMethodMetadata(ArcGISPoints.AppendPointsToFeatureClass2,
    shortDescription=_(u'Appends points to an existing ArcGIS point feature 
class.'),
    isExposedToPythonCallers=True,
    isExposedByCOM=True,
    isExposedAsArcGISTool=True,
    arcGISDisplayName=_(u'Append Points'),
    arcGISToolCategory=_(u'Spatial Analysis\\Create Points'),
    dependencies=[ArcGISDependency(9, 1)])

CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'cls', 
ArcGISPoints.AppendPointsToFeatureClass2, u'cls')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, 
u'featureClass', ArcGISPoints.AppendPointsToFeatureClass2, u'featureClass')

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'xyCoordinates',
    typeMetadata=ListTypeMetadata(elementType=PointTypeMetadata(), 
minLength=1),
    description=_(
u"""X and Y coordinates of the points to create.

If you are invoking this tool programmatically, you must specify each
point as a string, as must be done when invoking an ArcGIS tool that
accepts a point as input. For example, to create three points when
invoking this tool from Python, you use the list::

    [u'1 2', u'3 4', u'5 6']
"""),
    arcGISDisplayName=_(u'Points'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, u'zCoordinates',
    typeMetadata=ListTypeMetadata(elementType=FloatTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'xyCoordinates'),
    description=_(
u"""Z coordinates of the points to create.

If you are invoking this tool programmatically, specify these
coordinates as floating point numbers, not strings as is done with the
xyCoordinates parameter."""),
    arcGISDisplayName=_(u'Z coordinates'),
    arcGISCategory=_(u'Point options'))


AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, u'mValues',
    typeMetadata=ListTypeMetadata(elementType=FloatTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'xyCoordinates'),
    description=_(
u"""Measure values of the points to create.

If you are invoking this tool programmatically, specify these values
as floating point numbers, not strings as is done with the
xyCoordinates parameter."""),
    arcGISDisplayName=_(u'M values'),
    arcGISCategory=_(u'Point options'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'intAttrsToSet',
    
typeMetadata=ListTypeMetadata(elementType=ArcGISFieldTypeMetadata(mustExist=True,
 allowedFieldTypes=[u'SHORT', u'LONG']), canBeNone=True),
    description=_(
u"""LONG and SHORT integer attributes of the points that should be set
to the values you specify. This parameter specifies the names of the
attributes to set and the Integer Attribute Values parameter specifies
their values. If you create multiple points, they will all receive the
same attribute values.

This parameter is optional. If you do not set a particular attribute,
ArcGIS determines its default value. For shapefiles, it will be 0. For
geodatabases, it will be the default value specified by the database
schema, or NULL if the field is nullable and no default is
specified."""),
    arcGISDisplayName=_(u'Integer attributes to set'),
    arcGISCategory=_(u'Point options'),
    arcGISParameterDependencies=[u'featureClass'])

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'intAttrValues',
    typeMetadata=ListTypeMetadata(elementType=IntegerTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'intAttrsToSet'),
    description=_(
u"""Values for the LONG and SHORT integer attributes to set for the
points. You must provide a value for each attribute you specified for
the Integer Attributes to Set parameter."""),
    arcGISDisplayName=_(u'Integer attribute values'),
    arcGISCategory=_(u'Point options'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'floatAttrsToSet',
    
typeMetadata=ListTypeMetadata(elementType=ArcGISFieldTypeMetadata(mustExist=True,
 allowedFieldTypes=[u'FLOAT', u'DOUBLE']), canBeNone=True),
    description=_(
u"""FLOAT and DOUBLE attributes of the points that should be set to
the values you specify. This parameter specifies the names of the
parameters to set and the Floating Point Attribute Values parameter
specifies their values. If you create multiple points, they will all
receive the same attribute values.

This parameter is optional. If you do not set a particular attribute,
ArcGIS determines its default value. For shapefiles, it will be 0. For
geodatabases, it will be the default value specified by the database
schema, or NULL if the field is nullable and no default is
specified."""),
    arcGISDisplayName=_(u'Floating point attributes to set'),
    arcGISCategory=_(u'Point options'),
    arcGISParameterDependencies=[u'featureClass'])

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'floatAttrValues',
    typeMetadata=ListTypeMetadata(elementType=FloatTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'floatAttrsToSet'),
    description=_(
u"""Values for the FLOAT and DOUBLE attributes to set for the points.
You must provide a value for each attribute you specified for the
Floating Point Attributes to Set parameter."""),
    arcGISDisplayName=_(u'Floating point attribute values'),
    arcGISCategory=_(u'Point options'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'stringAttrsToSet',
    
typeMetadata=ListTypeMetadata(elementType=ArcGISFieldTypeMetadata(mustExist=True,
 allowedFieldTypes=[u'TEXT']), canBeNone=True),
    description=_(
u"""TEXT attributes of the points that should be set to the values you
specify. This parameter specifies the names of the parameters to set
and the Text Attribute Values parameter specifies their values. If you
create multiple points, they will all receive the same attribute
values.

This parameter is optional. If you do not set a particular attribute,
ArcGIS determines its default value. For shapefiles, it will be a
zero-length string. For geodatabases, it will be the default value
specified by the database schema, or NULL if the field is nullable and
no default is specified."""),
    arcGISDisplayName=_(u'Text attributes to set'),
    arcGISCategory=_(u'Point options'),
    arcGISParameterDependencies=[u'featureClass'])

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'stringAttrValues',
    typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'stringAttrsToSet'),
    description=_(
u"""Values for the TEXT attributes to set for the points. You must
provide a value for each attribute you specified for the Text
Attributes to Set parameter."""),
    arcGISDisplayName=_(u'Text attribute values'),
    arcGISCategory=_(u'Point options'))

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'dateAttrsToSet',
    
typeMetadata=ListTypeMetadata(elementType=ArcGISFieldTypeMetadata(mustExist=True,
 allowedFieldTypes=[u'DATE']), canBeNone=True),
    description=_(
u"""DATE attributes of the points that should be set to the values you
specify. This parameter specifies the names of the parameters to set
and the Date Attribute Values parameter specifies their values. If you
create multiple points, they will all receive the same attribute
values.

This parameter is optional. If you do not set a particular attribute,
ArcGIS determines its default value. For shapefiles, it will be NULL.
For geodatabases, it will be the default value specified by the
database schema, or NULL if the field is nullable and no default is
specified."""),
    arcGISDisplayName=_(u'Date attributes to set'),
    arcGISCategory=_(u'Point options'),
    arcGISParameterDependencies=[u'featureClass'])

AddArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'dateAttrValues',
    typeMetadata=ListTypeMetadata(elementType=DateTimeTypeMetadata(), 
canBeNone=True, mustBeSameLengthAsArgument=u'dateAttrsToSet'),
    description=_(
u"""Values for the DATE attributes to set for the points. You must
provide a value for each attribute you specified for the Date
Attributes to Set parameter. Your date may include a time if the
underlying feature class supports it."""),
    arcGISDisplayName=_(u'Date attribute values'),
    arcGISCategory=_(u'Point options'),
    arcGISParameterDependencies=[u'featureClass'])

AddResultMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'updatedFeatureClass',
    typeMetadata=ArcGISFeatureClassTypeMetadata(),
    description=_(u"""Updated feature class containing the new points."""),
    arcGISDisplayName=_(u'Updated feature class'),
    arcGISParameterDependencies=[u'featureClass'])

# Public method: ArcGISPoints.CreateFeatureClassWithPoints

AddMethodMetadata(ArcGISPoints.CreateFeatureClassWithPoints,
    shortDescription=_(u'Creates points in a new ArcGIS point feature 
class.'),
    isExposedToPythonCallers=True,
    dependencies=[ArcGISDependency(9, 1)])

CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'cls', 
ArcGISPoints.CreateFeatureClassWithPoints, u'cls')

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'featureClass',
    
typeMetadata=ArcGISFeatureClassTypeMetadata(deleteIfParameterIsTrue=u'overwriteExisting',
 createParentDirectories=True),
    description=_(u"""Output point feature class to create."""),
    direction = u'Output',
    arcGISDisplayName=_(u'Output point feature class'))

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialReference',
    typeMetadata=SpatialReferenceTypeMetadata(),
    description=_(u'Spatial reference for the output feature class.'),
    arcGISDisplayName=_(u'Spatial reference'))

CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'coordinates', 
ArcGISPoints.CreateFeatureClassWithPoints, u'coordinates')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'hasZ', 
ArcGISPoints.CreateFeatureClassWithPoints, u'hasZ')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'hasM', 
ArcGISPoints.CreateFeatureClassWithPoints, u'hasM')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass, u'attributes', 
ArcGISPoints.CreateFeatureClassWithPoints, u'attributes')

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'configKeyword',
    typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
    description=_(
u"""The configuration keyword that determines the storage parameters
of the table in a Relational Database Management System
(RDBMS)--ArcSDE only."""),
    arcGISDisplayName=_(u'Configuration keyword'),
    arcGISCategory=_(u'Geodatabase settings for output feature class'))

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid1',
    typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=0),
    description=_(
u"""The size of the output feature class's spatial grid index. The
following formats support spatial grid index grids: personal
geodatabase, file geodatabase or ArcSDE geodatabase. If not provided,
or if the value 0 is provided, a valid grid size will be calculated
automatically by ArcGIS."""),
    arcGISDisplayName=_(u'Output spatial grid 1'),
    arcGISCategory=_(u'Geodatabase settings for output feature class'))

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid2',
    typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=0),
    description=_(
u"""The size of the output feature class's second spatial grid index.
The value must be at least three times larger than the first index
grid. The following formats support spatial grid index grids: personal
geodatabase, file geodatabase or ArcSDE geodatabase. Note that
personal geodatabases support only one spatial index grid."""),
    arcGISDisplayName=_(u'Output spatial grid 2'),
    arcGISCategory=_(u'Geodatabase settings for output feature class'))

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid3',
    typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=0),
    description=_(
u"""The size of the output feature class's second spatial grid index.
The value must be at least three times larger than the second index
grid. The following formats support spatial grid index grids: personal
geodatabase, file geodatabase or ArcSDE geodatabase. Note that
personal geodatabases support only one spatial index grid."""),
    arcGISDisplayName=_(u'Output spatial grid 3'),
    arcGISCategory=_(u'Geodatabase settings for output feature class'))

AddArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'overwriteExisting',
    typeMetadata=BooleanTypeMetadata(),
    description=_(
u"""If True, the output feature class will be overwritten, if it
exists. If False, a ValueError will be raised if the output feature
class exists."""),
    initializeToArcGISGeoprocessorVariable=u'OverwriteOutput')

# Public method: ArcGISPoints.CreateFeatureClassWithPoints2

AddMethodMetadata(ArcGISPoints.CreateFeatureClassWithPoints2,
    shortDescription=_(u'Creates points in a new ArcGIS point feature 
class.'),
    isExposedToPythonCallers=True,
    isExposedByCOM=True,
    isExposedAsArcGISTool=True,
    arcGISDisplayName=_(u'Create Points'),
    arcGISToolCategory=_(u'Spatial Analysis\\Create Points'),
    dependencies=[ArcGISDependency(9, 1)])

CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, u'cls', 
ArcGISPoints.CreateFeatureClassWithPoints2, u'cls')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'featureClass', ArcGISPoints.CreateFeatureClassWithPoints2, u'featureClass')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialReference', ArcGISPoints.CreateFeatureClassWithPoints2, 
u'spatialReference')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'xyCoordinates', ArcGISPoints.CreateFeatureClassWithPoints2, 
u'xyCoordinates')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, 
u'zCoordinates', ArcGISPoints.CreateFeatureClassWithPoints2, u'zCoordinates')
CopyArgumentMetadata(ArcGISPoints.AppendPointsToFeatureClass2, u'mValues', 
ArcGISPoints.CreateFeatureClassWithPoints2, u'mValues')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'configKeyword', ArcGISPoints.CreateFeatureClassWithPoints2, 
u'configKeyword')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid1', ArcGISPoints.CreateFeatureClassWithPoints2, u'spatialGrid1')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid2', ArcGISPoints.CreateFeatureClassWithPoints2, u'spatialGrid2')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'spatialGrid3', ArcGISPoints.CreateFeatureClassWithPoints2, u'spatialGrid3')
CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, 
u'overwriteExisting', ArcGISPoints.CreateFeatureClassWithPoints2, 
u'overwriteExisting')

# Public method: ArcGISPoints.FindNearestFeatures

AddMethodMetadata(ArcGISPoints.FindNearestFeatures,
    shortDescription=_(u'For each point, finds the nearest feature and writes 
its ID, distance, angle, and/or values of specified fields to fields of the 
point.'),
    isExposedToPythonCallers=True,
    isExposedByCOM=True,
    isExposedAsArcGISTool=True,
    arcGISDisplayName=_(u'Find Nearest Features'),
    arcGISToolCategory=_(u'Spatial Analysis\\Find Features Nearest to 
Points'),
    dependencies=[ArcGISDependency(9, 1), 
ArcGISProductDependency(u'ArcInfo')])

CopyArgumentMetadata(ArcGISPoints.CreateFeatureClassWithPoints, u'cls', 
ArcGISPoints.FindNearestFeatures, u'cls')

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'pointFeatures',
    typeMetadata=ArcGISFeatureClassTypeMetadata(allowedShapeTypes=[u'Point'], 
mustExist=True),
    description=_(
u"""Feature class containing points for which the nearest point, line,
or polygon feature should be found.

You must have an ArcInfo product license to use this tool. This tool
finds the nearest feature using the ArcGIS Near tool, which requires
ArcInfo.

Distances between features are calculated using the Pythagorean
theorem. This is known as Euclidean distance. The nearest feature is
the one with the smallest Euclidean distance.

Either the point features or the near features must be in a projected
coordinate system, so that Euclidean distance may be properly
calculated. If neither is in a projected coordinate system, an error
will be reported. If just one is in a projected coordinate system, the
other will be automatically projected to that system prior to
performing distance calculations. If they are in two different
projected coordinate systems, the points will be automatically
projected to the near feature's coordinate system. An error will be
reported if this is not possible without performing a geographic
transformation (e.g. the features use different datums). In this case,
you must manually project the points or the near features yourself,
prior to running this tool."""),
    arcGISDisplayName=_(u'Point features'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'nearFeatures',
    typeMetadata=ArcGISFeatureClassTypeMetadata(allowedShapeTypes=[u'Point', 
u'Polyline', u'Polygon'], mustExist=True),         # Do not change this to 
ArcGISFeatureLayerTypeMetadata
    description=_(
u"""Feature class containing points, lines, or polygons.

This tool is not designed to operate on overlapping near features. If
the near features overlap, the behavior of this tool is undefined. It
may report a strange error, or it may appear to run successfully but
the results may not be correct. Please check the results carefully
when using overlapping near features.

It is ok if the points overlap the near features."""),
    arcGISDisplayName=_(u'Near features'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'searchRadius',
    typeMetadata=LinearUnitTypeMetadata(canBeNone=True),
    description=_(
u"""The maximum distance from a point to search for the nearest
feature. If not specified, the search radius is assumed to be
infinite."""),
    arcGISDisplayName=_(u'Search radius'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'fidField',
    typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
    description=_(
u"""Name of the point field that will receive the feature ID of the
nearest feature. In shapefiles, this is the value of the FID field. In
geodatabases, it is the value of the OBJECTID field.

This field must have the LONG data type. This field will be created if
it does not already exist.

If no feature is found within the specified search radius, NULL will
be stored in this field. If the field does not allow NULL (e.g. the
point features are a shapefile), -1 will be stored instead."""),
    arcGISDisplayName=_(u'Field to receive nearest feature ID'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'distanceField',
    typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
    description=_(
u"""Name of the point field that will receive the Euclidean distance
to the nearest feature.

This field must have the FLOAT or DOUBLE data type. This field will be
created with the DOUBLE data type if it does not already exist.

If no feature is found within the specified search radius, NULL will
be stored in this field. If the field does not allow NULL (e.g. the
point features are a shapefile), -999999999999 will be stored instead.
If the field is has the FLOAT data type, it may not be able to store
this value at full precision, so the value may be slightly
different."""),
    arcGISDisplayName=_(u'Field to receive nearest feature distance'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'angleField',
    typeMetadata=UnicodeStringTypeMetadata(canBeNone=True),
    description=_(
u"""Name of the point field that will receive the angle to the nearest
feature.

This field must have the FLOAT or DOUBLE data type. This field will be
created with the DOUBLE data type if it does not already exist.

Angles are measured in degrees, where one degree represents 1/360 of a
circle, and fractions of a degree are represented as decimal points.
Angles are measured from 180 to -180; 0 to the east, 90 to the north,
180 (or -180) to the west, and -90 to the south.

If no feature is found within the specified search radius, NULL will
be stored in this field. If the field does not allow NULL (e.g. the
point features are a shapefile), -9999 will be stored instead."""),
    arcGISDisplayName=_(u'Field to receive nearest feature angle'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'overlappingPolygonDistance',
    typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'Zero', 
u'Positive', u'Negative'], makeLowercase=True),
    description=_(
u"""Distance algorithm that should be used for points that overlap
polygons.

This parameter is only used when the input near features are polygons
and you specify a field to receive the distance to the nearest
polygon.

This parameter only applies to points that overlap polygons. It
controls how distance is calculated for those points and may be one of
the following:

* Zero - the distance will be zero. This is the default. This is
  appropriate when you want to know that the point intersected the
  polygon; for example, when the points represent sightings of marine
  animals and the polygons represent land and you want to know far the
  animals are from land, with the value 0 meaning the animal is on or
  over land.

* Positive - the distance will be positive. This is appropriate when
  you want the distance to the polygon edge, regardless of whether the
  point overlaps the polygon or not; for example, when the points
  represent sightings of marine animals and the polygons represent
  land and you want to know how far the animals are from the
  shoreline, regardless of whether they are on water or land.

* Negative - the distance will be negative. This is appropriate when
  you want the distance to the polygon edge, but need to know whether
  the point overlapped the polygon or not. Overlapping points will
  have negative distances and positive points will have positive
  distances.

When a point does not overlap a polygon, this parameter is ignored and
the distance will be positive.

**WARNING:** If you specify a value for the Search Radius parameter,
points that overlap polygons and are farther than this radius from the
nearest polygon edge will have a distance of zero, regardless of what
distance algorithm you select here. To work around this problem, omit
your search radius. Then, after running this tool, construct a feature
layer that omits points with distances that exceed your desired
radius."""),
    arcGISDisplayName=_(u'Distance to use when points overlap polygons'),
    arcGISCategory=_(u'Additional options'))

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'wherePointFeatures',
    typeMetadata=SQLWhereClauseTypeMetadata(canBeNone=True),
    description=_(
u"""SQL WHERE clause expression that specifies the subset of the
points to to use. If this parameter is not provided, all of the points
will be used.

**WARNING:** You should not reference FID, OID, or OBJECTID fields in
this expression. This tool uses the ArcGIS Add Join tool internally.
Add Join suffers some limitations that prevent correct operation when
those fields are referenced. To work around this problem, use the
ArcGIS Select tool to extract your desired points to a new feature
class and use that feature class instead.

The exact syntax of this expression depends on the type of feature
class that contains the near features. ESRI recommends you reference
fields using the following syntax:

* If the points are stored in an ArcInfo coverage or a shapefile,
  enclose field names in double quotes in the SQL expression:
  "MY_FIELD".

* If the points are stored in personal a geodatabase (.mdb file),
  enclose field names in square brackets: [MY_FIELD].

* If the points are stored in an ArcSDE or ArcIMS feature
  class, don't enclose field names: MY_FIELD."""),
    arcGISDisplayName=_(u'Point features where clause'),
    arcGISCategory=_(u'Additional options'),
    arcGISParameterDependencies=[u'pointFeatures'])

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'whereNearFeatures',
    typeMetadata=SQLWhereClauseTypeMetadata(canBeNone=True),
    description=_(
u"""SQL WHERE clause expression that specifies the subset of the near
features to to use. If this parameter is not provided, all of the near
features will be used.

The exact syntax of this expression depends on the type of feature
class that contains the near features. ESRI recommends you reference
fields using the following syntax:

* If the features are stored in an ArcInfo coverage or a shapefile,
  enclose field names in double quotes in the SQL expression:
  "MY_FIELD".

* If the features are stored in personal a geodatabase (.mdb file),
  enclose field names in square brackets: [MY_FIELD].

* If the features are stored in an ArcSDE or ArcIMS feature
  class, don't enclose field names: MY_FIELD."""),
    arcGISDisplayName=_(u'Near features where clause'),
    arcGISCategory=_(u'Additional options'),
    arcGISParameterDependencies=[u'nearFeatures'])

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'nearestFieldsToCopy',
    
typeMetadata=ListTypeMetadata(elementType=ArcGISFieldTypeMetadata(mustExist=True),
 canBeNone=True, minLength=1),
    description=_(
u"""Fields of the near features to copy to the points.

If you provide this parameter, you must also provide a field to
receive the feature ID of the near feature. An error will be reported
if you provide this parameter but omit that one.

WARNING: This tool uses the ArcGIS Calculate Fields tool to copy the
values from the near features' fields to the points' fields. Calculate
Fields cannot copy database NULL values and will report a strange
warning when asked to do so. As a result, for a given point, if a near
feature field contains NULL, the destination field of the point will
remain unchanged."""),
    arcGISDisplayName=_(u'Fields of the near features to copy'),
    arcGISCategory=_(u'Additional options'),
    arcGISParameterDependencies=[u'nearFeatures'])

AddArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'destinationPointFields',
    
typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(canBeNone=True),
 canBeNone=True, minLength=1),
    description=_(
u"""Names of the point fields to receive values copied from the near
feature fields.

If you omit this parameter, the tool will use the near feature field
names. If the point fields do not already exist, they will be created
using the data type and characteristics of the near feature fields. If
the point fields do already exist, the best results will be obtained
if they same data type and other characteristics as the near feature
fields. If the data type and other characteristics are not the same,
the value will be coerced to the destination field if possible. If
this is not possible, or it would result in a loss of data, an error
will be reported."""),
    arcGISDisplayName=_(u'Fields to receive copied values'),
    arcGISCategory=_(u'Additional options'))

AddResultMetadata(ArcGISPoints.FindNearestFeatures, u'updatedPointFeatures',
    typeMetadata=ArcGISFeatureClassTypeMetadata(allowedShapeTypes=[u'Point']),
    description=_(u"""Updated point features."""),
    arcGISDisplayName=_(u'Updated point features'))

# Public method: ArcGISPoints._FindNearestFeatures

AddMethodMetadata(ArcGISPoints._FindNearestFeatures,
    shortDescription=_(u'This private function implements 
FindNearestFeatures.'))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'cls', 
ArcGISPoints._FindNearestFeatures, u'cls')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'tempDir',
    typeMetadata=UnicodeStringTypeMetadata(),
    description=_(
u"""Path to the temp directory."""))

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'tempGeoDB',
    typeMetadata=UnicodeStringTypeMetadata(),
    description=_(
u"""Path to the temp geodatabase."""))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'pointFeatures', 
ArcGISPoints._FindNearestFeatures, u'pointFeatures')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'tempJoinFIDField',
    typeMetadata=UnicodeStringTypeMetadata(),
    description=_(
u"""Name of the temp FID field for joining to the point features."""))

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'tempNearFIDField',
    typeMetadata=UnicodeStringTypeMetadata(),
    description=_(
u"""Name of the temp field of the near feature FID."""))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'nearFeatures', 
ArcGISPoints._FindNearestFeatures, u'nearFeatures')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'searchRadius', 
ArcGISPoints._FindNearestFeatures, u'searchRadius')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'fidField', 
ArcGISPoints._FindNearestFeatures, u'fidField')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'fidFieldNullValue',
    typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
    description=_(
u"""Value to be written to fidField to represent NULL."""))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'distanceField', 
ArcGISPoints._FindNearestFeatures, u'distanceField')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, 
u'distanceFieldNullValue',
    typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
    description=_(
u"""Value to be written to distanceField to represent NULL."""))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'angleField', 
ArcGISPoints._FindNearestFeatures, u'angleField')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, u'angleFieldNullValue',
    typeMetadata=AnyObjectTypeMetadata(canBeNone=True),
    description=_(
u"""Value to be written to angleField to represent NULL."""))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'overlappingPolygonDistance', ArcGISPoints._FindNearestFeatures, 
u'overlappingPolygonDistance')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'wherePointFeatures', 
ArcGISPoints._FindNearestFeatures, u'wherePointFeatures')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'whereNearFeatures', 
ArcGISPoints._FindNearestFeatures, u'whereNearFeatures')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'nearestFieldsToCopy', ArcGISPoints._FindNearestFeatures, 
u'nearestFieldsToCopy')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'destinationPointFields', ArcGISPoints._FindNearestFeatures, 
u'destinationPointFields')

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, 
u'destinationPointFieldsNullValues',
    
typeMetadata=ListTypeMetadata(elementType=AnyObjectTypeMetadata(canBeNone=True),
 canBeNone=True),
    description=_(
u"""Values to be written to the destinationPointFields to represent NULL."""))

AddArgumentMetadata(ArcGISPoints._FindNearestFeatures, 
u'skipArgumentValidation',
    typeMetadata=BooleanTypeMetadata(),
    description=_(
u"""If True, this function will skip the validation of the input
arguments against their GeoEco metadata. For efficiency, it is
intended that FindNearestFeatures will pass True to skip the
validation, because it already performs the validation."""))

# Public method: ArcGISPoints.FindNearestFeaturesListedInField

AddMethodMetadata(ArcGISPoints.FindNearestFeaturesListedInField,
    shortDescription=_(u'For each point, using the feature class or layer 
listed in a field, finds the nearest feature and writes its ID, distance, 
angle, and/or values of specified fields to fields of the point. Use this 
tool when you have a single point feature class but need to find distances to 
different near feature classes or layers for different points.'),
    isExposedToPythonCallers=True,
    isExposedByCOM=True,
    isExposedAsArcGISTool=True,
    arcGISDisplayName=_(u'Find Nearest Features Listed in Field'),
    arcGISToolCategory=_(u'Spatial Analysis\\Find Features Nearest to 
Points'),
    dependencies=[ArcGISDependency(9, 1), 
ArcGISProductDependency(u'ArcInfo')])

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'cls', 
ArcGISPoints.FindNearestFeaturesListedInField, u'cls')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'pointFeatures', 
ArcGISPoints.FindNearestFeaturesListedInField, u'pointFeatures')

AddArgumentMetadata(ArcGISPoints.FindNearestFeaturesListedInField, 
u'nearFeaturesField',
    typeMetadata=ArcGISFieldTypeMetadata(mustExist=True, 
allowedFieldTypes=[u'TEXT']),
    description=_(
u"""Field of the point features that lists the feature classes
containing near features to be used for each point. The near features
may be points, lines, or polygons.

Typically, you use the ArcGIS Calculate Field tool to populate this
field based on the other fields of the points. For example, if your
points represent observations of a marine animal and your near
features are polygons that show monthly sea ice extents, you would use
Calculate Field to compute the path and name of the of the sea ice
polygon feature class using the date that the animal was observed. If
you use a Visual Basic expression with Calculate Field too, the VB
date processing functions will often be useful; these include
DatePart, DateAdd, and DateDiff. If you use a Python expression, the
strptime function and the datetime module will often be useful.

This tool is not designed to operate on overlapping near features. If
the near features overlap, the behavior of this tool is undefined. It
may report a strange error, or it may appear to run successfully but
the results may not be correct. Please check the results carefully
when using overlapping near features.

It is ok if the points overlap the near features.

This tool is designed for efficient processing. Rather than processing
one point at a time, it processes points in batches, where each batch
consists of the points that reference the same near features."""),
    arcGISDisplayName=_(u'Field listing near features'),
    arcGISParameterDependencies=[u'pointFeatures'])

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'searchRadius', 
ArcGISPoints.FindNearestFeaturesListedInField, u'searchRadius')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'fidField', 
ArcGISPoints.FindNearestFeaturesListedInField, u'fidField')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'distanceField', 
ArcGISPoints.FindNearestFeaturesListedInField, u'distanceField')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'angleField', 
ArcGISPoints.FindNearestFeaturesListedInField, u'angleField')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'overlappingPolygonDistance', ArcGISPoints.FindNearestFeaturesListedInField, 
u'overlappingPolygonDistance')
CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, u'wherePointFeatures', 
ArcGISPoints.FindNearestFeaturesListedInField, u'wherePointFeatures')

AddArgumentMetadata(ArcGISPoints.FindNearestFeaturesListedInField, 
u'whereNearFeaturesField',
    typeMetadata=ArcGISFieldTypeMetadata(canBeNone=True, mustExist=True, 
allowedFieldTypes=[u'TEXT']),
    description=_(
u"""Field of the point features that contains a SQL WHERE clause
expression that specifies the subset of the near features to to use.
If this parameter is not provided, all of the near features will be
used.

Typically, you use the ArcGIS Calculate Field tool to populate this
field based on the other fields of the points. For example, if your
points represent observations of a marine animal and they all
reference a single feature class that contains a monthly time series
of sea ice polygons, you would use Calculate Field to produce
expressions that selected polygons for the date the animals were
observed.

The exact syntax of WHERE expressions depends on the types of feature
classes that contain the near features. ESRI recommends you reference
fields using the following syntax:

* If the features are stored in an ArcInfo coverages or shapefiles,
  enclose field names in double quotes in the SQL expression:
  "MY_FIELD".

* If the features are stored in personal geodatabases (.mdb files),
  enclose field names in square brackets: [MY_FIELD].

* If the features are stored in ArcSDE or ArcIMS feature
  classes, don't enclose field names: MY_FIELD.
"""),
    arcGISDisplayName=_(u'Field listing near features where clauses'),
    arcGISCategory=_(u'Additional options'),
    arcGISParameterDependencies=[u'pointFeatures'])

AddArgumentMetadata(ArcGISPoints.FindNearestFeaturesListedInField, 
u'nearestFieldsToCopy',
    typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), 
canBeNone=True, minLength=1),
    description=_(
u"""Fields of the near features to copy to the points.

The fields you specify must exist in all of the near feature classes
or layers that are processed by the tool. A given field must have the
same data type and other characteristics in all of the feature classes
or layers. An error will be reported if the tool encounters a feature
class or layer that does not include all of the fields, or if the data
types and characteristics are not consistent."""),
    arcGISDisplayName=_(u'Fields of the near features to copy'),
    arcGISCategory=_(u'Additional options'))

CopyArgumentMetadata(ArcGISPoints.FindNearestFeatures, 
u'destinationPointFields', ArcGISPoints.FindNearestFeaturesListedInField, 
u'destinationPointFields')

CopyResultMetadata(ArcGISPoints.FindNearestFeatures, u'updatedPointFeatures', 
ArcGISPoints.FindNearestFeaturesListedInField, u'updatedPointFeatures')

###############################################################################
# Names exported by this module
###############################################################################

__all__ = ['ArcGISPoints']
Archives powered by MHonArc.
Top of Page