def repGeomString(shp): return str(round(shp.area)) + '|' + str(round(shp.centroid.X, 2)) + '|' + str(round(shp.centroid.Y, 2))
def fasterFindID(fc): """Records geometrical attributes of all features, then returns a dictionary: overlapDict: key = OID; value = identical overlap OIDs. The parameter fc is assumed to be the product of an overlap operation like Union or Intersect.""" # this creates a representation of a geometry string by concatenating various attributes to create a "unique" identifier def repGeomString(shp): return str(round(shp.area)) + '|' + str(round(shp.centroid.X, 2)) + '|' + str(round(shp.centroid.Y, 2)) # two dictionaries to keep track of duplicate geometries and their OIDs geomDictByOID = {} # key = OID; value = represented geometry string uniqueGeoms = {} # key = represented geometry string; value = list of OIDs with same geometry oidFieldName = arcpy.Describe(fc).oidFieldName nullCentroids = [] # gather geometries, and if centroid null, append to list with arcpy.da.SearchCursor(fc, ("OID@", "SHAPE@")) as cursor: for row in cursor: try: # get full k,v pair of OID and geometries geomDictByOID[row[0]] = repGeomString(row[1]) # initialize empty list as value of unique geometry key uniqueGeoms[repGeomString(row[1])] = [] except: nullCentroids.append(row[0]) # if null centroids exist, convert features to point and reread centroids # post-conversion, centroids will exist... for some reason if len(nullCentroids) > 0: # Format to string tuple for SQL query, and remove trailing comma for len = 1 if len(nullCentroids) > 1: nullCentroidsFormat = str(tuple(nullCentroids)) else: nullCentroidsFormat = str(tuple(nullCentroids)).replace(',', '') arcpy.MakeFeatureLayer_management(fc, 'nLyr', '"{0}" IN {1}'.format(oidFieldName, nullCentroidsFormat)) nullCentroidsPts = arcpy.FeatureToPoint_management('nLyr', arcpy.Describe(fc).name + 'NullCentroids') # loop through null centroid features and read new centroids with arcpy.da.SearchCursor(nullCentroidsPts, ("OID@", "SHAPE@")) as cursor: for row in cursor: # get full k,v pair of OID and geometries geomDictByOID[row[0]] = repGeomString(row[1]) # initialize empty list as value of unique geometry key uniqueGeoms[repGeomString(row[1])] = [] # for each geometry key in uniqueGeoms, append all OIDs that match for oid, g in geomDictByOID.iteritems(): uniqueGeoms.append(oid) # create dictionary that relates each oid to its overlaps overlapDict = {} for oid, g in geomDictByOID.iteritems(): if len(uniqueGeoms) > 1: overlapDict[oid] = [k for k in uniqueGeoms if k != oid] # Delete potentially large dicts del geomDictByOID del uniqueGeoms return overlapDict
All I'm really interested in is which shapes are identical to each other after a union operation on buffers.
#Flatten this puppy! shatteredFC = fgdbPath + "\\shattered" arcpy.Union_analysis(dissolveFC, shatteredFC, "ALL", "1 FEET", "GAPS"); showGpMessage() singlePartFC = fgdbPath + "\\single_part" arcpy.MultipartToSinglepart_management(shatteredFC, singlePartFC); showGpMessage() searchRows = arcpy.da.SearchCursor(singlePartFC, ["SHAPE@","*"]) polyIdDict = {} polyIdValue = 1 decimalTolerance = 2 for searchRow in searchRows: shapeFieldValue = searchRow[searchRows.fields.index("SHAPE@")] xCentroidValue = round(shapeFieldValue.centroid.X, decimalTolerance) yCentroidValue = round(shapeFieldValue.centroid.Y, decimalTolerance) areaValue = round(shapeFieldValue.area, decimalTolerance) axyValue = (xCentroidValue,yCentroidValue,areaValue) catagoryNameValue = searchRow[searchRows.fields.index("CATEGORY")] releaseYearValue = searchRow[searchRows.fields.index("RELEASE_YR")] retentionPctValue = searchRow[searchRows.fields.index("RETENTION_PCNT")] forestedFlagValue = searchRow[searchRows.fields.index("FORESTED")] if axyValue not in polyIdDict: polyIdDict[axyValue] = polyIdValue, [catagoryNameValue], [releaseYearValue],[retentionPctValue],[forestedFlagValue] polyIdValue = polyIdValue + 1 else: polyIdDict[axyValue][1].append(catagoryNameValue) polyIdDict[axyValue][2].append(releaseYearValue) polyIdDict[axyValue][3].append(retentionPctValue) polyIdDict[axyValue][4].append(forestedFlagValue) del searchRow, searchRows #Sort the thing the way we want it for axyValue in polyIdDict: polyIdDict[axyValue][1].sort() #catagory name polyIdDict[axyValue][2].sort(reverse=True) #release year polyIdDict[axyValue][3].sort(reverse=True) #retention percent polyIdDict[axyValue][4].sort() #forested arcpy.AddField_management(singlePartFC, "POLY_ID", "LONG"); showGpMessage() arcpy.AddField_management(singlePartFC, "LCL_RSN", "TEXT", "", "", "150"); showGpMessage() arcpy.AddField_management(singlePartFC, "RELEASE_YR_MAX", "SHORT"); showGpMessage() arcpy.AddField_management(singlePartFC, "RETENTION_PCNT_MAX", "SHORT"); showGpMessage() arcpy.AddField_management(singlePartFC, "FORESTED_MAX", "TEXT", "", "", "1"); showGpMessage() arcpy.AddField_management(singlePartFC, "LCL_RP_FLG", "SHORT"); showGpMessage() arcpy.AddField_management(singlePartFC, "LCL_UP_FLG", "SHORT"); showGpMessage() arcpy.AddField_management(singlePartFC, "LCL_US_FLG", "SHORT"); showGpMessage() arcpy.AddField_management(singlePartFC, "LCL_WT_FLG", "SHORT"); showGpMessage() updateRows = arcpy.da.UpdateCursor(singlePartFC, ["SHAPE@","*"]) for updateRow in updateRows: shapeFieldValue = updateRow[updateRows.fields.index("SHAPE@")] xCentroidValue = round(shapeFieldValue.centroid.X, decimalTolerance) yCentroidValue = round(shapeFieldValue.centroid.Y, decimalTolerance) areaValue = round(shapeFieldValue.area, decimalTolerance) axyValue = (xCentroidValue,yCentroidValue,areaValue) updateRow[updateRows.fields.index("POLY_ID")] = polyIdDict[axyValue][0] updateRow[updateRows.fields.index("LCL_RSN")] = ",".join(i for i in sorted(set(polyIdDict[axyValue][1]))) updateRow[updateRows.fields.index("RELEASE_YR_MAX")] = polyIdDict[axyValue][2][0] updateRow[updateRows.fields.index("RETENTION_PCNT_MAX")] = polyIdDict[axyValue][3][0] updateRow[updateRows.fields.index("FORESTED_MAX")] = polyIdDict[axyValue][4][0] if "RIPARIAN_AREA" in polyIdDict[axyValue][1] or "RMZ" in polyIdDict[axyValue][1]: updateRow[updateRows.fields.index("LCL_RP_FLG")] = 1 if "WETLAND" in polyIdDict[axyValue][1] or "WMZ" in polyIdDict[axyValue][1]: updateRow[updateRows.fields.index("LCL_WT_FLG")] = 1 if 'SLOPE_STABILITY_ISSUE' in polyIdDict[axyValue][1] or 'SLOPE_STABILITY_POTENTIAL' in polyIdDict[axyValue][1] or 'SLOPE_STABILITY_VERIFIED' in polyIdDict[axyValue][1] or 'UNSTABLE_SLOPES' in polyIdDict[axyValue][1]: updateRow[updateRows.fields.index("LCL_US_FLG")] = 1 #A bit of a work around just for SPS - untl the new schema is completed... if 'AREA_REGULATION' in polyIdDict[axyValue][1] and polyIdDict[axyValue][3][0] < 50: updateRow[updateRows.fields.index("RETENTION_PCNT_MAX")] = 50 updateRows.updateRow(updateRow) del updateRow, updateRows
Signed in members can post, follow updates, and more. New here? Register a free account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.