Spatial join - distance from outline

3753
6
Jump to solution
01-12-2016 02:43 AM
AdrianMarsden
Occasional Contributor III

Hi

Anyone any ideas how I can do a spatial join that is similar to the "within distance of"  but looks at the outline of the initial feature?

So, for example, I have a polygon and some points.  I want to join the two layers where the points are within a set distance of the OUTLINE - so if it is 1 m from the outline, either outside the polygon or inside it gets counted.  If it is 1 metre away from the outline INSIDE the polygon it gets ignored.

Cheers


ACM

Edit - as I work around I have used FME to create a polyline version of the feature, retaining the origional object ID, the doing the join, then hoplefully atribute join the original layer back to get the joincount - which is the field I am after.

0 Kudos
1 Solution

Accepted Solutions
DanPatterson_Retired
MVP Emeritus

Select by Location within a distance of ... Select Layer By Location—Help | ArcGIS for Desktop

spatial join with the same option Spatial Join—Help | ArcGIS for Desktop and

near are your options Near—Help | ArcGIS for Desktop

if a polygon is used and something is inside, its distance is 0 so a point overlapping a polygon would get selected, however, if the destination feature was converted to a polyline, then it may not be.  You have to choose which option you want

View solution in original post

6 Replies
DanPatterson_Retired
MVP Emeritus

Select by Location within a distance of ... Select Layer By Location—Help | ArcGIS for Desktop

spatial join with the same option Spatial Join—Help | ArcGIS for Desktop and

near are your options Near—Help | ArcGIS for Desktop

if a polygon is used and something is inside, its distance is 0 so a point overlapping a polygon would get selected, however, if the destination feature was converted to a polyline, then it may not be.  You have to choose which option you want

XanderBakker
Esri Esteemed Contributor

If you have already converted the polygon boundaries into a polyline featureclass, you can best you the Select By Location described by Dan. It would be nice to be able to use the polygons directly as input, but the options "touch the boundary of the source layer" and "are crossed by the outline of the source layer" do not allow you to specify a buffer distance.

As an alternative you could also buffer the polygon with 1 m and with -1 m, and erase the area (-1 m) from the other buffer area (1m) and use the Select By Location with the intesect option. This would require Advanced license and contains more steps than the converting the polygon outlines to line features.

AdrianMarsden
Occasional Contributor III

Cheers - the polyline method seemed to work fine, gave me what I wanted, but a shame I had to use another program to create the polylines - we've only got an ArcEditor license, so the Esri tool wasn't available.

0 Kudos
XanderBakker
Esri Esteemed Contributor

You are right, there are a number of very common features that are only available with the Advanced license level. It is however, quite simple to create a tool (using some Python code) to generate the outlines based on the polygon boundaries.

It you are interested, I can see what I can do.

0 Kudos
AdrianMarsden
Occasional Contributor III

Thanks - but as I have FME as well, it was very simple.

0 Kudos
XanderBakker
Esri Esteemed Contributor

In fact, I already made a tool that extracts the polygon outline and creates a polyline featureclass. Below the code of the tool:

The parameters are:

  • Input polygon featureclass
  • output polyline featureclass
  • option preserve input attributes (true, false)

#-------------------------------------------------------------------------------
# Name:        FeatureToLine.py
# Purpose:     Convertir feature a punto
#
# Author:      xbakker
#
# Created:     14/10/2015
#-------------------------------------------------------------------------------
import arcpy
import os

def main():
    # parameters
    fc_in = arcpy.GetParameterAsText(0)
    fc_out = arcpy.GetParameterAsText(1)
    preserve_atts = arcpy.GetParameter(2) # true o false

    # geometria de salida
    geomtype = "POLYLINE"
    sr = arcpy.Describe(fc_in).spatialReference

    # recreate fc_out based on fc_lines (in) using template
    ws_name, fc_name = os.path.split(fc_out)
    if preserve_atts:
        createFeatureClassTemplate(fc_out, fc_in, geomtype, fc_in, sr)
    else:
        createFeatureClass(fc_out, fc_in, geomtype, sr)

    # cursors:
    cnt = 0
    if preserve_atts:
        flds = getAllFieldsWithoutGeometryFields(fc_in)
    else:
        flds = ('SHAPE@')

    with arcpy.da.InsertCursor(fc_out, flds) as curs_out:
        with arcpy.da.SearchCursor(fc_in, flds) as curs:
            for row in curs:
                polygon = row[0]
                polyline = polygon.boundary()

                if preserve_atts:
                    lst_row = list(row)
                    lst_row[0] = polyline
                    row_out = tuple(lst_row)
                else:
                    row_out = (polyline, )

                # store polyline
                cnt += 1
                if cnt % 100 == 0:
                    arcpy.AddMessage("Procesando feature: {0}".format(cnt))
                curs_out.insertRow(row_out)

    arcpy.AddMessage("{0} features procesados...".format(cnt))


def getAllFieldsWithoutGeometryFields(fc):
    flds = [fld.name for fld in arcpy.ListFields(fc)]
    desc = arcpy.Describe(fc)
    fld_length = desc.lengthFieldName
    fld_area = desc.areaFieldName
    fld_shape = desc.shapeFieldName
    if fld_length in flds:
        flds.pop(flds.index(fld_length))
    if fld_area in flds:
        flds.pop(flds.index(fld_area))
    if fld_shape in flds:
        flds.pop(flds.index(fld_shape))
    flds.insert(0, 'SHAPE@')
    return flds

def createFeatureClass(fc_out, fc_in, geomtype, sr):
    ws_name, fc_name = os.path.split(fc_out)
    arcpy.CreateFeatureclass_management(ws_name, fc_name, geomtype, spatial_reference=sr)

def createFeatureClassTemplate(fc_out, fc_in, geomtype, template,  sr):
    ws_name, fc_name = os.path.split(fc_out)
    arcpy.CreateFeatureclass_management(ws_name, fc_name, geomtype, template, spatial_reference=sr)


if __name__ == '__main__':
    main()