def calculateRampUniqueIdValues(): layerForRampsSelection = 'layerForRampsSelection' MakeFeatureLayer_management(fcToCalculateTargetKeysIn, layerForRampsSelection) selectionQuery = """ SourceRouteId LIKE '___X%' OR LRS_ROUTE_PREFIX = 'X' """ updateFields = ['SourceRouteId', uniqueIdTarget] newCursor = daUpdateCursor(fcToCalculateTargetKeysIn, updateFields, selectionQuery) for updateItem in newCursor: updateListItem = list(updateItem) keyToUse = '' if updateListItem[0] is not None: sourceIdFull = str(updateListItem[0]) if len(sourceIdFull) >= 11: idToUse = sourceIdFull[9:11] else: idToUse = '00' else: idToUse = '00' updateListItem[1] = idToUse newCursor.updateRow(updateListItem) try: del newCursor except: pass
def prepareAggregateTable(): env.workspace = in_memory FeatureClassToFeatureClass_conversion(kanDriveSpatialConditions,"in_memory","aggregateTable") rowDeletionCursor = daUpdateCursor(aggregateTable, '*') for rowToDelete in rowDeletionCursor: rowDeletionCursor.deleteRow() try: del rowDeletionCursor except: pass
def duplicateCheckForMAndC(): print( "Checking for duplicate route numbers in the target route numbers for R, M, and C Routes." ) # Select the R routes. # Cursor them, and add their route number to a dict. # Then, select the M routes. # Cursor them and add their route number to a dict. # Then, select the C routes. # Cursor them and add their route number to a dict. # Create a list of free route numbers that are not in any of the 3 dicts. # Then, for each M route, if its routenumber is not in the R routes dict, # mark the M route's targetRouteNumChanged to "Kept". # Otherwise, if its routenumber is in the R routes dict, # Select the next free route number in the free route numbers list. # Remove the free route number from the free route numbers list. # Assign the free route number to the M route and mark the M route's # targetRouteNumChanged to "Changed". # Then, for each C route, if its routenumber is not in the R routes dict # and if it is also not in the M routes dict, # mark the C route's targetRouteNumChanged to "Kept". # Otherwise, if its routenumber is in the R routes dict or the M routes dict, # Select the next free route number in the free route numbers list. # Remove the free route number from the free route numbers list. # Assign the free route number to the C route and mark the C route's # targetRouteNumChanged to "Changed". rRoutesDict = dict() mRoutesDict = dict() cRoutesDict = dict() rRoutesSelectionQuery = """ SourceRouteId LIKE '___R%' OR LRS_ROUTE_PREFIX = 'R' """ mRoutesSelectionQuery = """ SourceRouteId LIKE '___M%' OR LRS_ROUTE_PREFIX = 'M' """ cRoutesSelectionQuery = """ SourceRouteId LIKE '___C%' OR LRS_ROUTE_PREFIX = 'C' """ searchCursorFields = [ sourceRouteNum, targetRouteNum, targetRouteNumChanged ] newCursor = daSearchCursor(fcToCalculateTargetKeysIn, searchCursorFields, rRoutesSelectionQuery) for cursorItem in newCursor: rRoutesDict[cursorItem[-3]] = 1 try: del newCursor except: pass newCursor = daSearchCursor(fcToCalculateTargetKeysIn, searchCursorFields, mRoutesSelectionQuery) for cursorItem in newCursor: mRoutesDict[cursorItem[-3]] = 1 try: del newCursor except: pass newCursor = daSearchCursor(fcToCalculateTargetKeysIn, searchCursorFields, cRoutesSelectionQuery) for cursorItem in newCursor: cRoutesDict[cursorItem[-3]] = 1 try: del newCursor except: pass usedRoutesList = [x for x in rRoutesDict.keys()] usedRoutesList = usedRoutesList + [y for y in mRoutesDict.keys()] usedRoutesList = usedRoutesList + [z for z in cRoutesDict.keys()] sortedUsedRoutesList = sorted(usedRoutesList) freeRoutesList = [ str(x).zfill(5) for x in xrange(12000, 64000) if str(x).zfill(5) not in sortedUsedRoutesList ] print("Used routes are as follows:") for usedRouteNumber in sortedUsedRoutesList: print("Used route number = " + str(usedRouteNumber) + ".") sortedFreeRoutesList = sorted(freeRoutesList) reverseSortedFreeRoutesList = sortedFreeRoutesList[::-1] print( "Updating lrs target numbers for M routes where they conflict with R routes." ) # Check the target lrs route numbers for M routes against the R routes. rRoutesKeys = rRoutesDict.keys() newCursor = daUpdateCursor(fcToCalculateTargetKeysIn, searchCursorFields, mRoutesSelectionQuery) for mRouteItem in newCursor: mRouteListItem = list(mRouteItem) if mRouteListItem[-2] in rRoutesKeys: mRouteListItem[-1] = 'Changed' mRouteListItem[-2] = reverseSortedFreeRoutesList.pop() mRoutesDict[mRouteListItem[-2]] = 1 newCursor.updateRow(mRouteListItem) else: pass try: del newCursor except: pass print( "Updating lrs target numbers for C routes where they conflict with R routes or M routes." ) # Check the target lrs route numbers for C routes against the R routes and the M routes. mRoutesKeys = mRoutesDict.keys() newCursor = daUpdateCursor(fcToCalculateTargetKeysIn, searchCursorFields, cRoutesSelectionQuery) for cRouteItem in newCursor: cRouteListItem = list(cRouteItem) if cRouteListItem[-2] in rRoutesKeys or cRouteListItem[ -2] in mRoutesKeys: cRouteListItem[-1] = 'Changed' cRouteListItem[-2] = reverseSortedFreeRoutesList.pop() newCursor.updateRow(cRouteListItem) else: pass try: del newCursor except: pass
def recalculateKeyValues(): # As long as the KDOT_LRS_KEY is not null, calculate from the # current fields. # Prior to doing any of this, I added a field to cache the # current KDOT_LRS_KEY to check for mistakes and recover from # them if any were found. # Use the prefix field to decide on what action to take to update the KDOTRouteId. # If the prefix is null, do nothing. # If the prefix is I, U, K, create the KDOTRouteId value from the SHS component parts. selectionQuery = """ "LRS_ROUTE_PREFIX" IN ('I', 'U', 'K') """ necessaryFields = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "KDOT_DIRECTION_CALC" ] dynNonNullSelectionQuery = GenerateNonNullSelectionQuery(necessaryFields) fullSelectionQuery = selectionQuery + """ AND """ + dynNonNullSelectionQuery fieldsToUseForUpdating = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "KDOT_DIRECTION_CALC", "KDOT_LRS_KEY" ] newCursor = daUpdateCursor(fcAsFeatureLayer, fieldsToUseForUpdating, fullSelectionQuery) for cursorRowItem in newCursor: cursorListItem = list(cursorRowItem) countyPre = cursorListItem[0] routePre = cursorListItem[1] routeNum = cursorListItem[2] routeSuf = cursorListItem[3] lrsUniqueIdent = cursorListItem[4] if len(lrsUniqueIdent) > 1: lrsUniqueIdent = lrsUniqueIdent[-1] else: pass directionCalc = cursorListItem[5] directionText = '' # Modified 2017-17-27 to fix the issue of non-primary sides, esp. on odd-numbered routes, receiving '-EB'. try: if int(routeNum) % 2 == 0: if directionCalc is not None and int(directionCalc) == 1: directionText = '-WB' else: # Default, if the non-primary side is receiving this, make sure that it has a 1 in the directionCalc. directionText = '-EB' if int(routeNum) % 2 == 1: if directionCalc is not None and int(directionCalc) == 1: directionText = '-SB' else: # Default, if the non-primary side is receiving this, make sure that it has a 1 in the directionCalc. directionText = '-NB' newKey = str(countyPre) + str(routePre) + str(routeNum) + str( routeSuf) + str(lrsUniqueIdent) + directionText cursorListItem[6] = newKey # For Debugging ##print("Updating the lrs key to: " + str(newKey) + ".") newCursor.updateRow(cursorListItem) except: try: print(traceback.format_exc()) print("Could not calculate a new LRS_KEY for the given row.") print("The row looks like this: " + str(cursorListItem) + ".") except: pass newCursor.next() try: del newCursor except: pass ###------------------------------------------------------------------------------------------------------------### ### If the prefix is not I, U, K and not X, create the KDOTRouteID from the Non-SHS, Non-Ramp component parts. ### ###------------------------------------------------------------------------------------------------------------### # For prefix R & M selectionQuery = """ "LRS_ROUTE_PREFIX" IN ('R', 'M') """ necessaryFields = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO" ] dynNonNullSelectionQuery = GenerateNonNullSelectionQuery(necessaryFields) fullSelectionQuery = selectionQuery + """ AND """ + dynNonNullSelectionQuery fieldsToUseForUpdating = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO", "KDOT_DIRECTION_CALC", "KDOT_LRS_KEY" ] newCursor = daUpdateCursor(fcAsFeatureLayer, fieldsToUseForUpdating, fullSelectionQuery) for cursorRowItem in newCursor: cursorListItem = list(cursorRowItem) countyPre = cursorListItem[0] routePre = cursorListItem[1] routeNum = cursorListItem[2] routeSuf = cursorListItem[3] lrsUniqueIdent = cursorListItem[4] if len(lrsUniqueIdent) > 1: lrsUniqueIdent = lrsUniqueIdent[ -1] # Get the right-most value. e.g. 47 => 7, 52 => 2 else: pass lrsAdmo = cursorListItem[5] directionCalc = cursorListItem[6] if directionCalc is None: directionCalc = '0' else: pass try: newKey = str(countyPre) + str(routePre) + str(routeNum) + str( routeSuf) + str(lrsUniqueIdent) + str(lrsAdmo) + str( directionCalc) cursorListItem[7] = newKey newCursor.updateRow(cursorListItem) except: try: print(traceback.format_exc()) print("Could not calculate a new LRS_KEY for the given row.") print("The row looks like this: " + str(cursorListItem) + ".") except: pass newCursor.next() try: del newCursor except: pass # For prefix C, Urban Classified, which uses LRS_URBAN_PRE. selectionQuery = """ "LRS_ROUTE_PREFIX" IN ('C') """ necessaryFields = [ "LRS_URBAN_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO" ] dynNonNullSelectionQuery = GenerateNonNullSelectionQuery(necessaryFields) # Uses LRS_ADMO ####LRS_ROUTE_NUM, LRS_ROUTE_SUFFIX, LRS_UNIQUE_IDENT, then LRS_ADMO, then 0 for inventory direction. fullSelectionQuery = selectionQuery + """ AND """ + dynNonNullSelectionQuery fieldsToUseForUpdating = [ "LRS_URBAN_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO", "KDOT_DIRECTION_CALC", "KDOT_LRS_KEY" ] newCursor = daUpdateCursor(fcAsFeatureLayer, fieldsToUseForUpdating, fullSelectionQuery) for cursorRowItem in newCursor: cursorListItem = list(cursorRowItem) urbanPre = cursorListItem[0] routePre = cursorListItem[1] routeNum = cursorListItem[2] routeSuf = cursorListItem[3] lrsUniqueIdent = cursorListItem[4] if len(lrsUniqueIdent) > 1: lrsUniqueIdent = lrsUniqueIdent[ -1] # Get the right-most value. e.g. 47 => 7, 52 => 2 else: pass lrsAdmo = cursorListItem[5] directionCalc = cursorListItem[6] if directionCalc is None: directionCalc = '0' else: pass try: newKey = str(urbanPre) + str(routePre) + str(routeNum) + str( routeSuf) + str(lrsUniqueIdent) + str(lrsAdmo) + str( directionCalc) cursorListItem[7] = newKey newCursor.updateRow(cursorListItem) except: try: print(traceback.format_exc()) print("Could not calculate a new LRS_KEY for the given row.") print("The row looks like this: " + str(cursorListItem) + ".") except: pass newCursor.next() try: del newCursor except: pass # If the prefix is X, create the KDOTRouteID from the Ramp route component parts. selectionQuery = """ "LRS_ROUTE_PREFIX" = 'X' """ # Doesn't make sense to require *_SUFFIX on ramps. - Just use '0' if it is null. # Only 12 Ramps have non-null LRS_ROUTE_SUFFIX values. For those, it is all '0' or 'No Suffix'. # If people set LRS_ROUTE_SUFFIX to 'G' or 'Z' for ramps though, that needs to be handled correctly. necessaryFields = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_UNIQUE_IDENT", "LRS_ADMO" ] dynNonNullSelectionQuery = GenerateNonNullSelectionQuery(necessaryFields) fullSelectionQuery = selectionQuery + """ AND """ + dynNonNullSelectionQuery fieldsToUseForUpdating = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO", "KDOT_DIRECTION_CALC", "KDOT_LRS_KEY" ] newCursor = daUpdateCursor(fcAsFeatureLayer, fieldsToUseForUpdating, fullSelectionQuery) for cursorRowItem in newCursor: cursorListItem = list(cursorRowItem) countyPre = cursorListItem[0] routePre = cursorListItem[1] routeNum = cursorListItem[2] routeSuf = cursorListItem[3] if routeSuf is None: routeSuf = '0' else: # Use whatever character is in the Route Suffix if it's not None/Null. pass lrsUniqueIdent = cursorListItem[4] if len(lrsUniqueIdent) > 1: lrsUniqueIdent = lrsUniqueIdent[-1] else: pass lrsAdmo = cursorListItem[5] directionCalc = cursorListItem[6] if directionCalc is None: directionCalc = '0' else: pass try: newKey = str(countyPre) + str(routePre) + str(routeNum) + str( routeSuf) + str(lrsUniqueIdent) + str(lrsAdmo) + str( directionCalc) cursorListItem[7] = newKey newCursor.updateRow(cursorListItem) except: try: print(traceback.format_exc()) print("Could not calculate a new LRS_KEY for the given row.") print("The row looks like this: " + str(cursorListItem) + ".") except: pass newCursor.next() try: del newCursor except: pass # For all other prefixes. selectionQuery = """ "LRS_ROUTE_PREFIX" NOT IN ('I', 'U', 'K', 'X', 'R', 'M', 'C') """ necessaryFields = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO" ] dynNonNullSelectionQuery = GenerateNonNullSelectionQuery(necessaryFields) fullSelectionQuery = selectionQuery + """ AND """ + dynNonNullSelectionQuery fieldsToUseForUpdating = [ "LRS_COUNTY_PRE", "LRS_ROUTE_PREFIX", "LRS_ROUTE_NUM", "LRS_ROUTE_SUFFIX", "LRS_UNIQUE_IDENT", "LRS_ADMO", "KDOT_DIRECTION_CALC", "KDOT_LRS_KEY" ] newCursor = daUpdateCursor(fcAsFeatureLayer, fieldsToUseForUpdating, fullSelectionQuery) for cursorRowItem in newCursor: cursorListItem = list(cursorRowItem) countyPre = cursorListItem[0] routePre = cursorListItem[1] routeNum = cursorListItem[2] routeSuf = cursorListItem[3] lrsUniqueIdent = cursorListItem[4] if len(lrsUniqueIdent) > 1: lrsUniqueIdent = lrsUniqueIdent[-1] else: pass lrsAdmo = cursorListItem[5] directionCalc = cursorListItem[6] if directionCalc is None: directionCalc = '0' else: pass try: newKey = str(countyPre) + str(routePre) + str(routeNum) + str( routeSuf) + str(lrsUniqueIdent) + str(lrsAdmo) + str( directionCalc) cursorListItem[7] = newKey newCursor.updateRow(cursorListItem) except: try: print(traceback.format_exc()) print("Could not calculate a new LRS_KEY for the given row.") print("The row looks like this: " + str(cursorListItem) + ".") except: pass newCursor.next() try: del newCursor except: pass # Something's not right. The calculates should fail every time because the n1 fields don't exist in this layer yet. :( selectionQuery = """ "KDOT_LRS_KEY" IS NOT NULL """ SelectLayerByAttribute_management(fcAsFeatureLayer, "NEW_SELECTION", selectionQuery) # SourceRouteId = KDOT_LRS_KEY CalculateField_management(fcAsFeatureLayer, n1RouteId, "!" + str(KDOTRouteId) + "!", "PYTHON_9.3") # SourceFromMeasure = county_log_begin CalculateField_management(fcAsFeatureLayer, n1FromMeas, "!" + str(KDOTMeasBeg) + "!", "PYTHON_9.3") # SourceToMeasure = county_log_end CalculateField_management(fcAsFeatureLayer, n1ToMeas, "!" + str(KDOTMeasEnd) + "!", "PYTHON_9.3") selectionQuery = """ KDOT_LRS_KEY IS NOT NULL AND county_log_begin IS NULL AND county_log_end IS NULL AND (COUNTY_BEGIN_MP IS NOT NULL OR COUNTY_END_MP IS NOT NULL) """ SelectLayerByAttribute_management(fcAsFeatureLayer, "NEW_SELECTION", selectionQuery) countResult = GetCount_management(fcAsFeatureLayer) intCount = int(countResult.getOutput(0)) print( "After the new selection query to deal with the fact that some State routes did not have their begin and end measure populated correctly, " + str(intCount) + " segments were selected.") # SourceFromMeasure = COUNTY_BEGIN_MP CalculateField_management(fcAsFeatureLayer, n1FromMeas, "!COUNTY_BEGIN_MP!", "PYTHON_9.3") # SourceToMeasure = COUNTY_END_MP CalculateField_management(fcAsFeatureLayer, n1ToMeas, "!COUNTY_END_MP!", "PYTHON_9.3")
def createUniqueIdentifier(): '''filters through records and calculates an incremental Unique Identifier for routes that are not border routes, to handle Y's, eyebrows, and splits that would cause complex routes''' workspaceLocation = gdb #MakeFeatureLayer_management(lyr,"RCL_Particles",where_clause="COUNTY_L = COUNTY_R AND STATE_L = STATE_R AND ( L_F_ADD =0 OR L_T_ADD =0 OR R_F_ADD =0 OR R_T_ADD =0)") featureClassName = lyr #from arcpy.da import SearchCursor as daSearchCursor, UpdateCursor as daUpdateCursor, Editor as daEditor alphabetListForConversion = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] newCursor = daSearchCursor(featureClassName, uniqueIdInFields) searchList = list() for searchRow in newCursor: searchList.append(list(searchRow)) # Transforms the row tuple into a list so it can be edited. if "newCursor" in locals(): del newCursor else: pass matchCount = 0 matchList = list() for testRow in searchList: if (testRow[1] == testRow[2] and testRow[3] == testRow[4] and (str(testRow[5]) == "0" or str(testRow[6]) == "0" or str(testRow[7]) == "0" or str(testRow[8]) == "0")): matchCount += 1 matchList.append(testRow) matchedRowDictionary = dict() for matchedRow in matchList: matchedRowContainer = list() # If the key already exists, assign the previous list of lists # to the list container, then append the new list # before updating the new value to that key in the dictionary. if matchedRow[10] in matchedRowDictionary: matchedRowContainer = matchedRowDictionary[matchedRow[10]] matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer # Otherwise, the key needs to be created # with the value, the list container, having only # one list contained within it for now. else: matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer for LRSKey in matchedRowDictionary: outRowContainer = matchedRowDictionary[LRSKey] # Sort based on length outRowContainer = sorted(outRowContainer, key = lambda sortingRow: sortingRow[11]) countVariable = 0 # Start at 0 for unique values LRSVariable = "" for outRowIndex, outRow in enumerate(outRowContainer): # Is this the first list/row in the key's list container? # If so, then set the Resolution_Order to 0 if outRowIndex == 0: outRow[9] = 0 else: countVariable += 1 if countVariable in [1, 2, 3, 4, 5, 6, 7, 8, 9]: outRow[9] = countVariable elif countVariable >= 10 and countVariable <= 34: outRow[9] = alphabetListForConversion[countVariable - 10] # Converts countVariable to an alpha character, without the letter "O". else: print "The count Variable is above 34. Ran out of numbers and letters to use as unique values." LRSVariable = outRow[10] LRSVariableShortened = str(LRSVariable[:-1]) # Returns the LRSVariable without the last character. LRSVariable = LRSVariableShortened + str(outRow[9]) outRow[10] = LRSVariable outRowString = "" for outRowElement in outRow: outRowString = outRowString + str(outRowElement) + " " print outRowString outRowContainer[outRowIndex] = outRow matchedRowDictionary[LRSKey] = outRowContainer newEditingSession = daEditor(workspaceLocation) newEditingSession.startEditing() newEditingSession.startOperation() newCursor = daUpdateCursor(featureClassName, uniqueIdOutFields) # @UndefinedVariable for existingRow in newCursor: formattedOutRow = list() if existingRow[2] in matchedRowDictionary.keys(): outRowContainer = matchedRowDictionary[existingRow[2]] for outRow in outRowContainer: if existingRow[0] == outRow[0]: # Test for matching OBJECTID fields. formattedOutRow.append(outRow[0]) formattedOutRow.append(outRow[9]) formattedOutRow.append(outRow[10]) newCursor.updateRow(formattedOutRow) else: pass else: pass newEditingSession.stopOperation() newEditingSession.stopEditing(True) if "newCursor" in locals(): del newCursor else: pass
def RoadinName(roadFeatures, nameExclusions): """This module corrects the road names in the soundex code where the road is named like Road A or Road 12 """ # Need to add logic to remove the ST from roads like 3RD ST and make sure that this translates to 0003 # and not 003. fieldList = ['OBJECTID', 'RD', 'Soundex'] #Placeholder. Recompiled in nameExclusions for loop. listMatchString = re.compile(r'^WEST', re.IGNORECASE) roadNameString = '' roadPreSoundexString = '' roadSoundexString = '' holderList = list() testMatch0 = None testMatch1 = None testMatch2 = None testMatch3 = None # Get the data from the geodatabase so that it can be used in the next part of the function. cursor = daSearchCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: listRow = list(row) holderList.append(listRow) # Clean up if "cursor" in locals(): del cursor else: pass if "row" in locals(): del row else: pass # Matches any group of 3 alpha characters in the string, ignoring case. tripleAlphaMatchString = re.compile(r'[A-Z][A-Z][A-Z]', re.IGNORECASE) # Matches 1 or 2 alpha characters at the start of a string, ignoring case. singleOrDoubleAlphaMatchString = re.compile(r'^[A-Z]$|^[A-Z][A-Z]$', re.IGNORECASE) # Matches 1 to 4 digits at the start of a string, probably no reason to ignore case in the check. singleToQuadNumberMatchString = re.compile(r'^[0-9]$|^[0-9][0-9]$|^[0-9][0-9][0-9]$|^[0-9][0-9][0-9][0-9]$') anyNumberMatchString = re.compile(r'[0-9]', re.IGNORECASE) # For roads that don't match a name exclusion: singleOrDoubleNumberThenAlphaMatchString = re.compile(r'^[0-9][0-9][A-Z]$|^[0-9][A-Z]$', re.IGNORECASE) # For roads that don't match a name exclusion and should be normally Numdexed. firstCharacterNumberString = re.compile(r'^[0-9]') ## Significant structure change here 2014-11-05. ## Watch for possible bugs. ## ## Added Numdex logic to this part, which ## caused some issues. ## ## Flattened the loops out here so that it only ## does a run through the ## <for heldRow in holderList> ## loop once instead of doing it once per ## entry in the nameExclusions list via ## <for excludedText in nameExclusions> ## ## Runs faster now. After changing the regex string ## to be dynamically generated prior to compilation ## and using \b{0}\b as part of the pattern, ## errors *seem* to be gone. stringToCompile = "" # Perform some regex on the strings to produce a new soundex in certain cases. for i, excludedText in enumerate(nameExclusions): #shift left start excludedText = str(excludedText) excludedText = excludedText.upper() #listMatchString = re.compile(r'^{0}\s'.format(re.escape(excludedText)), re.IGNORECASE) ## Old version, pre-dynamic generation. if i == 0: stringToCompile = r'^\b{0}\b\ '.format(re.escape(excludedText)) else: stringToCompile = stringToCompile + r'|^\b{0}\b\ '.format(re.escape(excludedText)) print i listMatchString = re.compile(stringToCompile, re.IGNORECASE) print "stringToCompile = " + str(stringToCompile) for heldRow in holderList: roadNameString = '' roadPreSoundexString = '' roadSoundexString = '' roadNameString = str(heldRow[1]) roadNameString = roadNameString.upper() roadNameString = roadNameString.replace(".", "") exclusionMatch = listMatchString.search(roadNameString) if exclusionMatch != None: # Testing for excluded Road Names such as "Road" and "CR" in "Road 25" and "CR 2500". # Get the characters from the end of the testMatch to the end of the string. # Should return a string that starts with a space. roadPreSoundexString = roadNameString[exclusionMatch.end():] # Replace with a search for " " by group in regex. roadPreSoundexString = roadPreSoundexString.replace(" ", "") roadPreSoundexString = roadPreSoundexString.replace(" ", "") # then loop through the groups to replace with "" so that any number # of spaces can be removed. print "roadNameString = " + str(roadNameString) print "roadPreSoundexString = " + str(roadPreSoundexString) # Do subbing for #ST, #ND, #RD, #TH etc... for numberEnding in ordinalNumberEndings: nonsensitiveReplace = re.compile(r'[0-9]{0}'.format(re.escape(numberEnding), re.IGNORECASE)) replaceMatch = nonsensitiveReplace.search(roadNameString) if replaceMatch != None: roadPreSoundexString = re.sub(replaceMatch.group(0), "", roadPreSoundexString) else: pass # Replace with regex string that matches spaces as groups, then loop through groups to replace. roadPreSoundexString = roadPreSoundexString.replace(" ", "") roadPreSoundexString = roadPreSoundexString.replace(" ", "") testMatch0 = None testMatch0 = tripleAlphaMatchString.search(roadPreSoundexString) testMatch1 = None testMatch1 = singleOrDoubleAlphaMatchString.search(roadPreSoundexString) testMatch2 = None testMatch2 = singleToQuadNumberMatchString.search(roadPreSoundexString) testMatch3 = None testMatch3 = anyNumberMatchString.search(roadPreSoundexString) if testMatch0 != None: roadSoundexString = soundex(roadPreSoundexString) # Slice the roadSoundexString to remove the first character, but keep the rest. if len(roadSoundexString) >= 4: roadSoundexString = roadSoundexString[1:4] # The next line looks complicated, but exclusionMatch.group(0)[0:1] # is actually just getting the first letter of the first matched pattern. roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString elif len(roadSoundexString) == 3: roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString elif len(roadSoundexString) == 2 or len(roadSoundexString) == 1: roadSoundexString = roadSoundexString.zfill(3) roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString else: pass heldRow[2] = roadSoundexString elif testMatch1 != None: # Road A, Road BB, or similar. roadPreSoundexString = roadPreSoundexString[testMatch1.start():testMatch1.end()] if len(roadPreSoundexString) > 2: pass elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString else: pass elif testMatch2 != None: roadPreSoundexString = roadPreSoundexString[testMatch2.start():testMatch2.end()] if len(roadPreSoundexString) > 4: pass elif len(roadPreSoundexString) == 4: # Slice the string to include only the first 3 characters, as slice end is non-inclusive. roadSoundexString = roadPreSoundexString[:4] roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 3: roadSoundexString = roadPreSoundexString roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = exclusionMatch.group(0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString else: pass else: pass else: roadNameString = heldRow[1] testMatch4 = None testMatch4 = singleOrDoubleNumberThenAlphaMatchString.search(roadNameString) testMatch5 = None testMatch5 = firstCharacterNumberString.search(roadNameString) # Numdex with one or two numbers, then alpha. if testMatch4 != None: roadPreSoundexString = roadNameString[testMatch4.start():] roadSoundexString = roadPreSoundexString.zfill(4) heldRow[2] = roadSoundexString # Normal Numdex if there were not one or two numbers, then alpha, but the string starts with a number. elif testMatch5 != None: numerical_re = re.compile("[A-Z]|[^0-9][^0-9][^0-9][^0-9]") roadPreSoundexString = roadNameString.replace(" ", "") roadSoundexString = re.sub(numerical_re,"", roadPreSoundexString.zfill(4)) if len(roadSoundexString) > 4: roadSoundexString = roadSoundexString[:5] else: pass roadSoundexString = roadSoundexString.zfill(4) heldRow[2] = roadSoundexString else: # Check for AA, BB, EE, etc without an excluded name in front of it if len(roadNameString) == 2: if roadNameString[0] == roadNameString[1]: roadPreSoundexString = roadNameString roadSoundexString = roadPreSoundexString.zfill(4) else: # Normal Soundex roadPreSoundexString = roadNameString roadSoundexString = soundex(roadPreSoundexString) heldRow[2] = roadSoundexString # shift left end try: # Start an edit session for this workspace because the centerline # feature class participates in a topology. editSession = daEditor(gdb) editSession.startEditing(False, False) editSession.startOperation() print "Editing started." cursor = daUpdateCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: for heldRow in holderList: # N^2 looping, try not to place print statements inside this block. if str(row[0]) == str(heldRow[0]): cursor.updateRow(heldRow) else: pass editSession.stopOperation() editSession.stopEditing(True) print "Editing complete." except Exception as e: print "Failed to update the Soundex values." print e.message print GetMessages(2) finally: # Clean up if "cursor" in locals(): del cursor else: pass if "row" in locals(): del row else: pass
def labelAngleNormalization(quarterOrHalf): if quarterOrHalf.lower() == "quarter": countyBorderFeature = countyBorderFeature_Q countyRoadNameRosette = countyRoadNameRosette_Q elif quarterOrHalf.lower() == "half": countyBorderFeature = countyBorderFeature_H countyRoadNameRosette = countyRoadNameRosette_H else: print "quarterOrHalf variable not correctly defined." raise (Exception("quarterOrHalf error.")) print "Normalizing the label angle values." if "COUNTY_NAME" not in ListFields(countyRoadNameRosette): AddField_management(countyRoadNameRosette, "COUNTY_NAME", "TEXT", "", "", "55") else: pass newCursor = daSearchCursor(countyBorderFeature, countyBorderFields) countyTranslationDictionary = dict() # countyBorderItem[3] is the number, countyBorderItem[2] is the name. # -- Use for translating from county number to county name. for countyBorderItem in newCursor: if countyBorderItem[3] not in countyTranslationDictionary: countyTranslationDictionary[ countyBorderItem[3]] = countyBorderItem[2] else: pass if "newCursor" in locals(): del newCursor else: pass newCursor = daUpdateCursor(countyRoadNameRosette, countyRoadNameRosetteFields) for countyPointItem in newCursor: countyPointItem = list(countyPointItem) # Takes the remainder of the angle divided by 360. # Uses fmod due to floating point issues with the normal modulo operator in python. countyPointItem[0] = math.fmod(countyPointItem[0], 360) # countyPointItem[1] is County Name, countyPointItem[2] is County Number. if countyPointItem[0] >= 250 and countyPointItem[0] <= 290: countyPointItem[0] = 270 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[ countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif countyPointItem[0] >= 160 and countyPointItem[0] <= 200: countyPointItem[0] = 180 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[ countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif countyPointItem[0] >= 70 and countyPointItem[0] <= 110: countyPointItem[0] = 90 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[ countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif (countyPointItem[0] >= 0 and countyPointItem[0] <= 20) or (countyPointItem[0] >= 340 and countyPointItem[0] <= 360): countyPointItem[0] = 0 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[ countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) else: print "Deleting a row for having an angle more than 20 degrees away from a cardinal direction." newCursor.deleteRow() if "newCursor" in locals(): del newCursor else: pass print "Label angle normalization complete!" print "Done extending and intersecting road features." # Need to break this into two pieces and pass some of the inmemorylayers
def main(): # Do this by county. # Get a list of all of the available county numbers. # Then create an updateCursor for each county, using # a selection that looks at the LRS_COUNTY_PRE and LRS_PREFIX or existing KDOT_LRS_KEY. tempDesc = Describe(fcWithLocalRoutesToDissolveAndMeasure) print( "Updating the concatenated LRS Key Field and start/end measures for selected features in " + returnFeatureClass(tempDesc.catalogPath) + ".") OIDFieldName = str(tempDesc.OIDFieldName) try: del tempDesc except: pass uniqueCountyCodeDict = dict() countyCodeFieldsList = ['KDOT_COUNTY_L', 'KDOT_COUNTY_R'] newCursor = daSearchCursor(fcWithLocalRoutesToDissolveAndMeasure, countyCodeFieldsList) for cursorRow in newCursor: uniqueCountyCodeDict[str(cursorRow[0])] = 1 uniqueCountyCodeDict[str(cursorRow[1])] = 1 try: del newCursor except: pass uniqueCountyCodeList = list() for uniqueCountyCode in uniqueCountyCodeDict.keys(): uniqueCountyCodeList.append(uniqueCountyCode) try: del uniqueCountyCodeDict except: pass try: uniqueCountyCodeList.remove('None') except: pass sortedUniqueCountyCodes = sorted( uniqueCountyCodeList ) # No need to specify a key since it's one column. for uniqueCountyCodeItem in sortedUniqueCountyCodes: print('Selecting features based on countyCode: ' + str(uniqueCountyCodeItem) + '.') routeFeaturesList = list() listOfFieldsToUse = [ OIDFieldName, 'LRS_COUNTY_PRE', 'LRS_ROUTE_PREFIX', 'LRS_ROUTE_NUM', 'LRS_ROUTE_SUFFIX', 'LRS_UNIQUE_IDENT', 'LRS_UNIQUE_IDENT1', lrsKeyToUse ] # Modified from the original localroutenumbering sql to include an exception for '%W%' routes, because I don't think that those # were included in the localroutenumbering, even though they should have been. selectionQuery1 = """ KDOT_COUNTY_L = '""" + str( uniqueCountyCodeItem ) + """' AND (((KDOT_LRS_KEY IS NULL AND LRS_ROUTE_PREFIX = 'L') OR KDOT_LRS_KEY LIKE '%L%') AND NOT KDOT_LRS_KEY LIKE '%W%') """ selectionQuery2 = """ KDOT_COUNTY_L IS NULL AND KDOT_COUNTY_R = '""" + str( uniqueCountyCodeItem ) + """' AND (((KDOT_LRS_KEY IS NULL AND LRS_ROUTE_PREFIX = 'L') OR KDOT_LRS_KEY LIKE '%L%') AND NOT KDOT_LRS_KEY LIKE '%W%') """ newCursor = daUpdateCursor(fcWithLocalRoutesToDissolveAndMeasure, listOfFieldsToUse, selectionQuery1) for cursorRow in newCursor: cursorListItem = list(cursorRow) # change each cursorRow to a list # then pass the list to a function that concats the parts # into the LRS key field. concattedKeyListItem = concatTheLRSParts(cursorListItem, uniqueCountyCodeItem) # Receive the list back and use it to update the # row. newCursor.updateRow(concattedKeyListItem) try: del newCursor except: pass newCursor = daUpdateCursor(fcWithLocalRoutesToDissolveAndMeasure, listOfFieldsToUse, selectionQuery2) for cursorRow in newCursor: cursorListItem = list(cursorRow) # change each cursorRow to a list # then pass the list to a function that concats the parts # into the LRS key field. concattedKeyListItem = concatTheLRSParts(cursorListItem, uniqueCountyCodeItem) # Receive the list back and use it to update the # row. newCursor.updateRow(concattedKeyListItem) try: del newCursor except: pass # At this point, all of the local features in a county should have had # their LRS keys updated. # What we need to do now is to dissolve them based on LRS key. dissolveBasedOnLocalRouteKeys(fcWithLocalRoutesToDissolveAndMeasure, selectionQuery1) dissolveBasedOnLocalRouteKeys(fcWithLocalRoutesToDissolveAndMeasure, selectionQuery2) # At this point, all of the local featuers should be dissolved into # single part lines. # Go ahead and add the measures based on 0-to-shapelength. calculateMeasuresForLocalRoutes(fcWithLocalRoutesToDissolveAndMeasure, selectionQuery1) calculateMeasuresForLocalRoutes(fcWithLocalRoutesToDissolveAndMeasure, selectionQuery2)
def importCommentsToChangedSource(sourceWithComments, targetToHaveCommentsAdded): # Since I forgot to ask that the ReviewUser and ReviewInfo fields be kept, need to get the # data back. Thankfully, it appears to still be in the same objectID order, so we can # use that and the GCIDs to try to transfer it over, then make additional quality checks # to be sure that the transfer was successful and did not introduce any errors. # 0.) Add the ReviewUser and ReviewInfo fields to the copy if they do not already exist. # That way, the information from the edits can flow through to future edit sessions # and error checks. tfcDesc = Describe(targetToHaveCommentsAdded) tfcFields = tfcDesc.fields tfcFieldNames = [x.name for x in tfcFields] try: del tfcDesc except: pass # Check for ReviewUser field in the targetFeaturesCopy, then add it if missing. if 'ReviewUser' not in tfcFieldNames: #ReviewUser (String, 50) AddField_management(targetToHaveCommentsAdded, 'ReviewUser', "TEXT", "", "", 50, 'ReviewUser', nullable) else: pass # Check for ReviewInfo field in the targetFeaturesCopy, then add it if missing. if 'ReviewInfo' not in tfcFieldNames: #ReviewInfo (String, 250) AddField_management(targetToHaveCommentsAdded, 'ReviewInfo', "TEXT", "", "", 250, 'ReviewInfo', nullable) else: pass tfcUpdatedDesc = Describe(targetToHaveCommentsAdded) tfcUpdatedFields = tfcUpdatedDesc.fields tfcUpdatedOIDFieldName = tfcUpdatedDesc.OIDFieldName tfcUpdatedFieldNames = [x.name for x in tfcUpdatedFields] try: del tfcUpdatedDesc except: pass try: tfcUpdatedFieldNames.remove(tfcUpdatedOIDFieldName) except: pass try: tfcUpdatedFieldNames.remove(GCIDFieldName) except: pass tfcUpdatedFieldNames.append(tfcUpdatedOIDFieldName) tfcUpdatedFieldNames.append(GCIDFieldName) swcDesc = Describe(sourceWithComments) swcFields = swcDesc.fields swcOIDFieldName = swcDesc.OIDFieldName swcFieldNames = [x.name for x in swcFields] try: del swcDesc except: pass try: swcFieldNames.remove(swcOIDFieldName) except: pass try: swcFieldNames.remove(GCIDFieldName) except: pass swcFieldNames.append(swcOIDFieldName) # Add the OIDFieldName so that it is the 2nd to last swcFieldNames.append(GCIDFieldName) # Add 'GCID' so that it is the last sharedFieldNames = [x for x in tfcUpdatedFieldNames if x in swcFieldNames] # 1.) Use a searchCursor to pull the sourceWithComments features, including the OID and their GCID. withCommentsList = list() newCursor = daSearchCursor(sourceWithComments, sharedFieldNames) for cursorRow in newCursor: withCommentsList.append(cursorRow) try: del newCursor except: pass print("The sharedFieldNames are: " + str(sharedFieldNames) + ".") # 2.) Use an updateCursor to match the pulled rows and update the target rows with the ReviewUser and ReviewInfo. newCursor = daUpdateCursor(targetToHaveCommentsAdded, sharedFieldNames) for cursorRow in newCursor: for commentedRowItem in withCommentsList: if cursorRow[-1] == commentedRowItem[-1] and cursorRow[-2] == commentedRowItem[-2]: print ('Updating a row with GCID: ' + str(cursorRow[-1]) + ' and OID: ' + str(cursorRow[-2]) + '.') newCursor.updateRow(commentedRowItem) try: del newCursor except: pass
def labelAngleNormalization(): if "COUNTY_NAME" not in arcpy.ListFields(countyRoadNameRosette): arcpy.AddField_management(countyRoadNameRosette, "COUNTY_NAME", "TEXT", "", "", "55") else: pass newCursor = daSearchCursor(countyBorderFeature, countyBorderFields) countyTranslationDictionary = dict() for countyBorderItem in newCursor: if countyBorderItem[4] not in countyTranslationDictionary: countyTranslationDictionary[countyBorderItem[4]] = countyBorderItem[3] else: pass if "newCursor" in locals(): del newCursor else: pass newCursor = daUpdateCursor(countyRoadNameRosette, countyRoadNameRosetteFields) for countyPointItem in newCursor: countyPointItem = list(countyPointItem) # Takes the remainder of the angle divided by 360. countyPointItem[0] = math.fmod(countyPointItem[0], 360) # Uses fmod due to floating point issues with the modulo operator in python. if countyPointItem[0] >= 250 and countyPointItem[0] <= 290: countyPointItem[0] = 270 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif countyPointItem[0] >= 160 and countyPointItem[0] <= 200: countyPointItem[0] = 180 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif countyPointItem[0] >= 70 and countyPointItem[0] <= 110: countyPointItem[0] = 90 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) elif (countyPointItem[0] >= 0 and countyPointItem[0] <= 20) or (countyPointItem[0] >= 340 and countyPointItem[0] <= 360): countyPointItem[0] = 0 if countyPointItem[2] in countyTranslationDictionary: countyPointItem[1] = countyTranslationDictionary[countyPointItem[2]] else: countyPointItem[1] = "" newCursor.updateRow(countyPointItem) else: print "Deleting row for having an angle more than 20 degrees away from a cardinal direction." newCursor.deleteRow() if "newCursor" in locals(): del newCursor else: pass print "Label angle normalization complete!" print "Done extending and intersecting road features." # Need to break this into two pieces and pass some of the inmemorylayers
def createUniqueIdentifier(): '''filters through records and calculates an incremental Unique Identifier for routes that are not border routes, to handle Y's, eyebrows, and splits that would cause complex routes''' workspaceLocation = gdb #MakeFeatureLayer_management(lyr,"RCL_Particles",where_clause="COUNTY_L = COUNTY_R AND STATE_L = STATE_R AND ( L_F_ADD =0 OR L_T_ADD =0 OR R_F_ADD =0 OR R_T_ADD =0)") featureClassName = lyr #from arcpy.da import SearchCursor as daSearchCursor, UpdateCursor as daUpdateCursor, Editor as daEditor alphabetListForConversion = [ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" ] newCursor = daSearchCursor(featureClassName, uniqueIdInFields) searchList = list() for searchRow in newCursor: searchList.append( list(searchRow) ) # Transforms the row tuple into a list so it can be edited. if "newCursor" in locals(): del newCursor else: pass matchCount = 0 matchList = list() for testRow in searchList: if (testRow[1] == testRow[2] and testRow[3] == testRow[4] and (str(testRow[5]) == "0" or str(testRow[6]) == "0" or str(testRow[7]) == "0" or str(testRow[8]) == "0")): matchCount += 1 matchList.append(testRow) matchedRowDictionary = dict() for matchedRow in matchList: matchedRowContainer = list() # If the key already exists, assign the previous list of lists # to the list container, then append the new list # before updating the new value to that key in the dictionary. if matchedRow[10] in matchedRowDictionary: matchedRowContainer = matchedRowDictionary[matchedRow[10]] matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer # Otherwise, the key needs to be created # with the value, the list container, having only # one list contained within it for now. else: matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer for LRSKey in matchedRowDictionary: outRowContainer = matchedRowDictionary[LRSKey] # Sort based on length outRowContainer = sorted(outRowContainer, key=lambda sortingRow: sortingRow[11]) countVariable = 0 # Start at 0 for unique values LRSVariable = "" for outRowIndex, outRow in enumerate(outRowContainer): # Is this the first list/row in the key's list container? # If so, then set the Resolution_Order to 0 if outRowIndex == 0: outRow[9] = 0 else: countVariable += 1 if countVariable in [1, 2, 3, 4, 5, 6, 7, 8, 9]: outRow[9] = countVariable elif countVariable >= 10 and countVariable <= 34: outRow[9] = alphabetListForConversion[ countVariable - 10] # Converts countVariable to an alpha character, without the letter "O". else: print "The count Variable is above 34. Ran out of numbers and letters to use as unique values." LRSVariable = outRow[10] LRSVariableShortened = str( LRSVariable[:-1] ) # Returns the LRSVariable without the last character. LRSVariable = LRSVariableShortened + str(outRow[9]) outRow[10] = LRSVariable outRowString = "" for outRowElement in outRow: outRowString = outRowString + str(outRowElement) + " " print outRowString outRowContainer[outRowIndex] = outRow matchedRowDictionary[LRSKey] = outRowContainer newEditingSession = daEditor(workspaceLocation) newEditingSession.startEditing() newEditingSession.startOperation() newCursor = daUpdateCursor(featureClassName, uniqueIdOutFields) # @UndefinedVariable for existingRow in newCursor: formattedOutRow = list() if existingRow[2] in matchedRowDictionary.keys(): outRowContainer = matchedRowDictionary[existingRow[2]] for outRow in outRowContainer: if existingRow[0] == outRow[ 0]: # Test for matching OBJECTID fields. formattedOutRow.append(outRow[0]) formattedOutRow.append(outRow[9]) formattedOutRow.append(outRow[10]) newCursor.updateRow(formattedOutRow) else: pass else: pass newEditingSession.stopOperation() newEditingSession.stopEditing(True) if "newCursor" in locals(): del newCursor else: pass
def RoadinName(roadFeatures, nameExclusions): """This module corrects the road names in the soundex code where the road is named like Road A or Road 12 """ # Need to add logic to remove the ST from roads like 3RD ST and make sure that this translates to 0003 # and not 003. fieldList = ['OBJECTID', 'RD', 'Soundex'] #Placeholder. Recompiled in nameExclusions for loop. listMatchString = re.compile(r'^WEST', re.IGNORECASE) roadNameString = '' roadPreSoundexString = '' roadSoundexString = '' holderList = list() testMatch0 = None testMatch1 = None testMatch2 = None testMatch3 = None # Get the data from the geodatabase so that it can be used in the next part of the function. cursor = daSearchCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: listRow = list(row) holderList.append(listRow) # Clean up if "cursor" in locals(): del cursor else: pass if "row" in locals(): del row else: pass # Matches any group of 3 alpha characters in the string, ignoring case. tripleAlphaMatchString = re.compile(r'[A-Z][A-Z][A-Z]', re.IGNORECASE) # Matches 1 or 2 alpha characters at the start of a string, ignoring case. singleOrDoubleAlphaMatchString = re.compile(r'^[A-Z]$|^[A-Z][A-Z]$', re.IGNORECASE) # Matches 1 to 4 digits at the start of a string, probably no reason to ignore case in the check. singleToQuadNumberMatchString = re.compile( r'^[0-9]$|^[0-9][0-9]$|^[0-9][0-9][0-9]$|^[0-9][0-9][0-9][0-9]$') anyNumberMatchString = re.compile(r'[0-9]', re.IGNORECASE) # For roads that don't match a name exclusion: singleOrDoubleNumberThenAlphaMatchString = re.compile( r'^[0-9][0-9][A-Z]$|^[0-9][A-Z]$', re.IGNORECASE) # For roads that don't match a name exclusion and should be normally Numdexed. firstCharacterNumberString = re.compile(r'^[0-9]') ## Significant structure change here 2014-11-05. ## Watch for possible bugs. ## ## Added Numdex logic to this part, which ## caused some issues. ## ## Flattened the loops out here so that it only ## does a run through the ## <for heldRow in holderList> ## loop once instead of doing it once per ## entry in the nameExclusions list via ## <for excludedText in nameExclusions> ## ## Runs faster now. After changing the regex string ## to be dynamically generated prior to compilation ## and using \b{0}\b as part of the pattern, ## errors *seem* to be gone. stringToCompile = "" # Perform some regex on the strings to produce a new soundex in certain cases. for i, excludedText in enumerate(nameExclusions): #shift left start excludedText = str(excludedText) excludedText = excludedText.upper() #listMatchString = re.compile(r'^{0}\s'.format(re.escape(excludedText)), re.IGNORECASE) ## Old version, pre-dynamic generation. if i == 0: stringToCompile = r'^\b{0}\b\ '.format(re.escape(excludedText)) else: stringToCompile = stringToCompile + r'|^\b{0}\b\ '.format( re.escape(excludedText)) print i listMatchString = re.compile(stringToCompile, re.IGNORECASE) print "stringToCompile = " + str(stringToCompile) for heldRow in holderList: roadNameString = '' roadPreSoundexString = '' roadSoundexString = '' roadNameString = str(heldRow[1]) roadNameString = roadNameString.upper() roadNameString = roadNameString.replace(".", "") exclusionMatch = listMatchString.search(roadNameString) if exclusionMatch != None: # Testing for excluded Road Names such as "Road" and "CR" in "Road 25" and "CR 2500". # Get the characters from the end of the testMatch to the end of the string. # Should return a string that starts with a space. roadPreSoundexString = roadNameString[exclusionMatch.end():] # Replace with a search for " " by group in regex. roadPreSoundexString = roadPreSoundexString.replace(" ", "") roadPreSoundexString = roadPreSoundexString.replace(" ", "") # then loop through the groups to replace with "" so that any number # of spaces can be removed. print "roadNameString = " + str(roadNameString) print "roadPreSoundexString = " + str(roadPreSoundexString) # Do subbing for #ST, #ND, #RD, #TH etc... for numberEnding in ordinalNumberEndings: nonsensitiveReplace = re.compile(r'[0-9]{0}'.format( re.escape(numberEnding), re.IGNORECASE)) replaceMatch = nonsensitiveReplace.search(roadNameString) if replaceMatch != None: roadPreSoundexString = re.sub(replaceMatch.group(0), "", roadPreSoundexString) else: pass # Replace with regex string that matches spaces as groups, then loop through groups to replace. roadPreSoundexString = roadPreSoundexString.replace(" ", "") roadPreSoundexString = roadPreSoundexString.replace(" ", "") testMatch0 = None testMatch0 = tripleAlphaMatchString.search(roadPreSoundexString) testMatch1 = None testMatch1 = singleOrDoubleAlphaMatchString.search( roadPreSoundexString) testMatch2 = None testMatch2 = singleToQuadNumberMatchString.search( roadPreSoundexString) testMatch3 = None testMatch3 = anyNumberMatchString.search(roadPreSoundexString) if testMatch0 != None: roadSoundexString = soundex(roadPreSoundexString) # Slice the roadSoundexString to remove the first character, but keep the rest. if len(roadSoundexString) >= 4: roadSoundexString = roadSoundexString[1:4] # The next line looks complicated, but exclusionMatch.group(0)[0:1] # is actually just getting the first letter of the first matched pattern. roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString elif len(roadSoundexString) == 3: roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString elif len(roadSoundexString) == 2 or len( roadSoundexString) == 1: roadSoundexString = roadSoundexString.zfill(3) roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString else: pass heldRow[2] = roadSoundexString elif testMatch1 != None: # Road A, Road BB, or similar. roadPreSoundexString = roadPreSoundexString[testMatch1.start( ):testMatch1.end()] if len(roadPreSoundexString) > 2: pass elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString else: pass elif testMatch2 != None: roadPreSoundexString = roadPreSoundexString[testMatch2.start( ):testMatch2.end()] if len(roadPreSoundexString) > 4: pass elif len(roadPreSoundexString) == 4: # Slice the string to include only the first 3 characters, as slice end is non-inclusive. roadSoundexString = roadPreSoundexString[:4] roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 3: roadSoundexString = roadPreSoundexString roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = exclusionMatch.group( 0)[0:1] + roadSoundexString heldRow[2] = roadSoundexString else: pass else: pass else: roadNameString = heldRow[1] testMatch4 = None testMatch4 = singleOrDoubleNumberThenAlphaMatchString.search( roadNameString) testMatch5 = None testMatch5 = firstCharacterNumberString.search(roadNameString) # Numdex with one or two numbers, then alpha. if testMatch4 != None: roadPreSoundexString = roadNameString[testMatch4.start():] roadSoundexString = roadPreSoundexString.zfill(4) heldRow[2] = roadSoundexString # Normal Numdex if there were not one or two numbers, then alpha, but the string starts with a number. elif testMatch5 != None: numerical_re = re.compile("[A-Z]|[^0-9][^0-9][^0-9][^0-9]") roadPreSoundexString = roadNameString.replace(" ", "") roadSoundexString = re.sub(numerical_re, "", roadPreSoundexString.zfill(4)) if len(roadSoundexString) > 4: roadSoundexString = roadSoundexString[:5] else: pass roadSoundexString = roadSoundexString.zfill(4) heldRow[2] = roadSoundexString else: # Check for AA, BB, EE, etc without an excluded name in front of it if len(roadNameString) == 2: if roadNameString[0] == roadNameString[1]: roadPreSoundexString = roadNameString roadSoundexString = roadPreSoundexString.zfill(4) else: # Normal Soundex roadPreSoundexString = roadNameString roadSoundexString = soundex(roadPreSoundexString) heldRow[2] = roadSoundexString # shift left end try: # Start an edit session for this workspace because the centerline # feature class participates in a topology. editSession = daEditor(gdb) editSession.startEditing(False, False) editSession.startOperation() print "Editing started." cursor = daUpdateCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: for heldRow in holderList: # N^2 looping, try not to place print statements inside this block. if str(row[0]) == str(heldRow[0]): cursor.updateRow(heldRow) else: pass editSession.stopOperation() editSession.stopEditing(True) print "Editing complete." except Exception as e: print "Failed to update the Soundex values." print e.message print GetMessages(2) finally: # Clean up if "cursor" in locals(): del cursor else: pass if "row" in locals(): del row else: pass
def Kdot_RouteNameCalc(): AliasTablePath = os.path.join(gdb, Alias) cursorFields = ["OBJECTID", "A_RD", "KDOT_ROUTENAME"] sCursor = daSearchCursor(AliasTablePath, cursorFields) searchDict = dict() print "In Kdot_RouteNameCalc..." for foundRow in sCursor: searchDict[foundRow[0]] = list(foundRow) # Transforms the row tuple into a list so it can be edited. print str(foundRow[0]) + "\t" + str(foundRow[1]) try: del sCursor except: pass # Matches an I, U, or K at the start of the string, ignoring case. IUKMatchString = re.compile(r'^[IUK]', re.IGNORECASE) # Matches 1 to 3 digits at the end of a string, probably no reason to ignore case in the check. singleToTripleNumberEndMatchString = re.compile(r'[0-9][0-9][0-9]|[0-9][0-9]|[0-9]') # Probably need to use regular expressions here. # Yes, rebuild with regex. Too many problems just trying to slice the strings. for keyName in searchDict: firstPart = "" secondPart = "" fullRouteName = "" listItem = searchDict[keyName] listItemRD = listItem[1] testResult0 = None testResult1 = None #################################################################################### testResult0 = re.search(IUKMatchString, listItemRD) testResult1 = re.search(singleToTripleNumberEndMatchString, listItemRD) #################################################################################### if testResult0 is not None and testResult1 is not None: print "Found matches." firstPart = str(testResult0.group(0)) secondPart = str(testResult1.group(0)) # Pad the string with prepended zeroes if it is not 3 digits long already. if len(secondPart) == 2: secondPart = secondPart.zfill(3) print "secondPart = " + secondPart elif len(secondPart) == 1: secondPart = secondPart.zfill(3) print "secondPart = " + secondPart else: pass fullRouteName = firstPart + secondPart listItem[2] = fullRouteName searchDict[keyName] = listItem print "Resulting RouteName = " + str(listItem[2]) + "." else: print "Did not find matches." fullRouteName = firstPart + secondPart listItem[2] = fullRouteName searchDict[keyName] = listItem uCursor = daUpdateCursor(AliasTablePath, cursorFields) for uCursorItem in uCursor: for keyName in searchDict: listItem = searchDict[keyName] if uCursorItem[0] == listItem[0]: print "ObjectIDs matched: " + str(uCursorItem[0]) + " & " + str(listItem[0]) print "The road name (for updateCursor) is: " + str(listItem[1]) uCursor.updateRow(listItem) if listItem[2] is not None and listItem[2] != "": print "The routeNameFull is: " + str(listItem[2]) else: print "RouteNameFull is None/Null/Empty. =(" else: pass try: del uCursor except: pass
def soundex(s): """ Encode a string using Soundex. Takes a string and returns its Soundex representation.""" replacementString = "" #Added a "." here, should replace correctly now. replacementDict = {"A":"1", "E":"2", "H":"3", "I":"4", "O":"5", "U":"6", "W":"7", "Y":"8", ".":""} if len(s) == 2: if s[0] == s[1]:# Only affects one very specific road name type. Kind of a narrow fix. for keyName in replacementDict: if keyName == str(s[1].upper(): replacementString = replacementDict[keyName] enc = str(str(s[0]) + replacementString).zfill(4) return enc else: pass else: pass elif len(s) == 1: enc = str(s[0]).zfill(4) return enc elif len(s) == 0: enc = str("x").zfill(4) return enc else: pass s = normalize(s) last = None enc = s[0] for c in s[1:]: if len(enc) == 4: break if charsubs[c] != last: enc += charsubs[c] last = charsubs[c] while len(enc) < 4: enc += '0' return enc def numdex(s): """this module applies soundex to named streets, and pads the numbered streets with zeros, keeping the numbering system intact""" if s[0] in ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.']: # I don't think having a '.' here will do anything unless the road name is ".SomeName" since it # only checks the first character of the string. numerical_re = re.compile("[A-Z]|[^0-9][^0-9][^0-9][^0-9]") s=re.sub(numerical_re,"", s.zfill(4)) return s.zfill(4) else: return soundex(s) def StreetNetworkCheck(gdb): """removes street centerlines from the topology and creates geometric network, then checks geometric network connectivity""" from arcpy import ListDatasets, VerifyAndRepairGeometricNetworkConnectivity_management, RemoveFeatureClassFromTopology_management, CreateGeometricNetwork_management, FindDisconnectedFeaturesInGeometricNetwork_management #print topo fd = ListDatasets(gdb) print fd[0] geonet = fd[0]+"\Street_Network" #print geonet if Exists(geonet): print "Street Geometric Network Already Exists" else: RemoveFeatureClassFromTopology_management(topo, "RoadCenterline") CreateGeometricNetwork_management(fd, "Street_Network", "RoadCenterline SIMPLE_EDGE NO", "#", "#", "#", "#", "#") FindDisconnectedFeaturesInGeometricNetwork_management(fd+"/RoadCenterline", "Roads_Disconnected") StreetLogfile = reviewpath+"/KDOTReview/"+ntpath.basename(ng911)+".log" VerifyAndRepairGeometricNetworkConnectivity_management(geonet, StreetLogfile, "VERIFY_ONLY", "EXHAUSTIVE_CHECK", "0, 0, 10000000, 10000000") def ConflateKDOTrestart(gdb, DOTRoads): """Conflation restart for selecting KDOT roads to conflate to the NG911 Network""" MakeFeatureLayer_management(DOTRoads+"/KDOT_HPMS_2012","KDOT_Roads","#","#","#") MakeFeatureLayer_management(checkfile+"/RoadCenterline","RoadCenterline","#","#","#") SelectLayerByLocation_management("KDOT_Roads","INTERSECT","RoadCenterline","60 Feet","NEW_SELECTION") FeatureClassToFeatureClass_conversion("KDOT_Roads",checkfile+r"/NG911","KDOT_Roads_Review","#","#","#") def ConflateKDOT(gdb, DOTRoads): """detects road centerline changes and transfers the HPMS key field from the KDOT roads via ESRI conflation tools""" from arcpy import TransferAttributes_edit, DetectFeatureChanges_management, RubbersheetFeatures_edit, GenerateRubbersheetLinks_edit, RubbersheetFeatures_edit checkfile = gdb spatialtolerance = "20 feet" MakeFeatureLayer_management(DOTRoads+"/KDOT_HPMS_2012","KDOT_Roads","#","#","#") MakeFeatureLayer_management(checkfile+"/RoadCenterline","RoadCenterline","#","#","#") if Exists(checkfile+r"/NG911/KDOT_Roads_Review"): print "selection of KDOT roads for conflation already exists" else: SelectLayerByLocation_management("KDOT_Roads","INTERSECT","RoadCenterline","60 Feet","NEW_SELECTION") FeatureClassToFeatureClass_conversion("KDOT_Roads",checkfile+r"/NG911","KDOT_Roads_Review","#","#","#") MakeFeatureLayer_management(checkfile+"/KDOT_Roads_Review","KDOT_Roads_Review","#","#","#") GenerateRubbersheetLinks_edit("KDOT_Roads_Review","RoadCenterline",checkfile+r"/NG911/RoadLinks",spatialtolerance,"ROUTE_ID LRSKEY",checkfile+r"/RoadMatchTbl") MakeFeatureLayer_management(checkfile+"/NG911/RoadLinks","RoadLinks","#","#","#") MakeFeatureLayer_management(checkfile+"/NG911/RoadLinks_pnt","RoadLinks_pnt","#","#","#") RubbersheetFeatures_edit("KDOT_Roads_Review","RoadLinks","RoadLinks_pnt","LINEAR") DetectFeatureChanges_management("KDOT_Roads_Review","RoadCenterline",checkfile+r"/NG911/RoadDifference",spatialtolerance,"#",checkfile+r"/RoadDifTbl",spatialtolerance,"#") MakeFeatureLayer_management(checkfile+"/NG911/RoadDifference","RoadDifference","#","#","#") TransferAttributes_edit("KDOT_Roads_Review","RoadCenterline","YEAR_RECORD;ROUTE_ID",spatialtolerance,"#",checkfile+r"/LRS_MATCH") def addAdminFields(lyr, Alias): try: AddIndex(lyr,"SEGID;COUNTY_L;COUNTY_R;MUNI_L;MUNI_R","RCL_INDEX","NON_UNIQUE","NON_ASCENDING") except: print "indexed" FieldList3=("KDOT_COUNTY_R", "KDOT_COUNTY_L","KDOT_CITY_R", "KDOT_CITY_L", 'UniqueNo' ) for field in FieldList3: addField(lyr, field, "TEXT", "#", "#", "3") FieldList1=('KDOT_ADMO', 'KDOTPreType', 'PreCode', 'SuffCode', 'TDirCode') for field in FieldList1: addField(lyr, field, "TEXT", "#", "#", "1") addField(lyr, "Soundex", "TEXT", "#", "#", "5") addField(lyr, "RID", "TEXT", "#", "#", "26") addField(lyr, "KDOT_START_DATE", "DATE") addField(lyr, "KDOT_END_DATE", "DATE") addField(lyr, "SHAPE_MILES", "Double", "#", "#", "#" ) addField(Alias, "KDOT_PREFIX", "TEXT", "#", "#", "1" ) addField(Alias, "KDOT_CODE", "LONG" ) addField(Alias, "KDOT_ROUTENAME", "TEXT", "#", "#", "3" ) def CalcAdminFields(lyr, Kdotdbfp): """Populate Admin Fields with Default or Derived values""" CalcField(lyr,"UniqueNo",'000',"PYTHON_9.3","#") CalcField(lyr,"KDOT_START_DATE","1/1/1901","PYTHON_9.3","#") CalcField(lyr,"KDOTPreType","!ROUTE_ID![3]","PYTHON_9.3","#") #PreType is a conflated field, consider changing this to calculate from NENA fields TableView(lyr, "NewPretype", "KDOTPreType is Null") CalcField("NewPretype","KDOTPreType","'L'","PYTHON_9.3","#") CalcField(lyr,"KDOT_ADMO","'X'","PYTHON_9.3","#") CalcField(lyr,"PreCode","0","PYTHON_9.3","#") CalcField(lyr,"KDOT_CITY_L","999","PYTHON_9.3","#") CalcField(lyr,"KDOT_CITY_R","999","PYTHON_9.3","#") CalcField(lyr,"TDirCode","0","PYTHON_9.3","#") CalcField(lyr,"SHAPE_MILES","!Shape_Length!/5280.010560021","PYTHON_9.3","#") #There are slightly more than 5280 miles per US Survey foot TableView(Kdotdbfp+"\\NG911_RdDir", "NG911_RdDir") JoinTbl(lyr,"PRD","NG911_RdDir", "RoadDir", "KEEP_COMMON") CalcField(lyr,"PreCode","!NG911_RdDir.RdDirCode!","PYTHON_9.3","#") removeJoin(lyr) TableView(Kdotdbfp+"\NG911_RdTypes", "NG911_RdTypes") CalcField(lyr,"SuffCode","0","PYTHON_9.3","#") JoinTbl(lyr,"STS","NG911_RdTypes", "RoadTypes", "KEEP_COMMON") CalcField(lyr,"SuffCode","!NG911_RdTypes.LRS_CODE_TXT!","PYTHON_9.3","#") removeJoin(lyr) def CountyCode(lyr): """Codify the County number for LRS (based on right side of street based on addressing direction, calculated for LEFT and RIGHT from NG911)""" TableView(Kdotdbfp+"\NG911_County", "NG911_County") JoinTbl(lyr,"COUNTY_L","NG911_County", "CountyName", "KEEP_COMMON") CalcField(lyr,"KDOT_COUNTY_L","!NG911_County.CountyNumber!","PYTHON_9.3","#") removeJoin(lyr) JoinTbl(lyr,"COUNTY_R","NG911_County", "CountyName", "KEEP_COMMON") CalcField(lyr,"KDOT_COUNTY_R","!NG911_County.CountyNumber!","PYTHON_9.3","#") removeJoin(lyr) def CityCodes(lyr, Kdotdbfp): """Codify the City Limit\city number for LRS , calculated for LEFT and RIGHT from NG911)""" TableView(Kdotdbfp+"\City_Limits", "City_Limits") JoinTbl(lyr,"MUNI_R","City_Limits", "CITY", "KEEP_COMMON") CalcField(lyr,"KDOT_CITY_R","str(!City_Limits.CITY_CD!).zfill(3)","PYTHON_9.3","#") removeJoin(lyr) JoinTbl(lyr,"MUNI_L","City_Limits", "CITY", "KEEP_COMMON") CalcField(lyr,"KDOT_CITY_L","str(!City_Limits.CITY_CD!).zfill(3)","PYTHON_9.3","#") removeJoin(lyr) TableView(lyr, "CityRoads", "KDOT_CITY_R = KDOT_CITY_L AND KDOT_CITY_R not like '999'") CalcField("CityRoads","KDOT_ADMO","'W'","PYTHON_9.3","#") def RoadinName1(lyr): """This module corrects the road names in the soundex code where the road is named like Road A or Road 12 """ TableView(lyr,"ROAD_NAME","RD LIKE 'ROAD %'") CalcField("ROAD_NAME","Soundex",""""R"+!RD![5:].zfill(3)""","PYTHON_9.3","#") TableView(lyr,"RD_NAME","RD LIKE 'RD %'") CalcField(lyr,"Soundex","""("R"+!RD![1:5]).zfill(3)""","PYTHON_9.3","#") def RoadinName(roadFeatures, nameExclusions): """This module corrects the road names in the soundex code where the road is named like Road A or Road 12 """ fieldList = ['OBJECTID', 'RD', 'Soundex'] listMatchString = re.compile(r'^WEST', re.IGNORECASE) roadNameString = '' roadPreSoundexString = '' roadSoundexString = '' testMatch = None testMatch1 = None testMatch2 = None # Get the data from the geodatabase so that it can be used in the next part of the function. cursor = daSearchCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: listRow = list(row) holderList.append(listRow) # Clean up if cursor: del cursor else: pass if row: del row else: pass # Perform some regex on the strings to produce a new soundex in certain cases. for excludedText in nameExclusions: excludedText = str(excludedText) excludedText = excludedText.upper() listMatchString = re.compile(r'^{0}\s'.format(re.escape(excludedText)), re.IGNORECASE) # Matches 1 or 2 alpha characters at the start of a string, ignoring case. singleOrDoubleAlphaMatchString = re.compile(r'^[a-z]$|^[a-z][a-z]$', re.IGNORECASE) # Matches 1 to 4 digits at the start of a string, probably no reason to ignore case in the check. singleToQuadNumberMatchString = re.compile(r'^[0-9]$|^[0-9][0-9]$|^[0-9][0-9][0-9]$|^[0-9][0-9][0-9][0-9]$') for heldRow in holderList: roadNameString = str(heldRow[1]) roadNameString = roadNameString.upper() testMatch = listMatchString.search(roadNameString) if testMatch != None: roadPreSoundexString = roadNameString[testMatch.end():] roadPreSoundexString = roadPreSoundexString.replace(" ", "") # Do subbing for #ST, #ND, #RD, #TH etc... for numberEnding in ordinalNumberEndings: nonsensitiveReplace = re.compile(r'[0-9]{0}'.format(re.escape(numberEnding), re.IGNORECASE)) replaceMatch = nonsensitiveReplace.search(roadNameString) if replaceMatch != None: roadPreSoundexString = re.sub(replaceMatch.group(0), replaceMatch.group(0)[0:1], roadPreSoundexString) else: pass # Test for the following conditions: # A, AA as in Road A, RD AA testMatch1 = None testMatch1 = singleOrDoubleAlphaMatchString.search(roadPreSoundexString) # Test for the following conditions: # 1, 10, 100, 1000 as in Road 1, RD 10, Road 100, CR1000 testMatch2 = None testMatch2 = singleToQuadNumberMatchString.search(roadPreSoundexString) if testMatch1 != None: # Road A, Road BB, or similar. roadPreSoundexString = roadPreSoundexString[testMatch1.start():testMatch1.end()] if len(roadPreSoundexString) > 2: pass elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString # Adds the first letter from the excluded text to the start of the Soundex string. roadSoundexString = excludedText[0:1] + roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = excludedText[0:1] + roadSoundexString else: pass elif(testMatch2 != None): roadPreSoundexString = roadPreSoundexString[testMatch2.start():testMatch2.end()] if len(roadPreSoundexString) > 4: pass elif len(roadPreSoundexString) == 4: # Slice the string to include only the first 3 characters. roadSoundexString = roadPreSoundexString[:4] # Add the first letter from the excluded text to the start of the Soundex string. roadSoundexString = excludedText[0:1] + roadSoundexString elif len(roadPreSoundexString) == 3: roadSoundexString = roadPreSoundexString roadSoundexString = excludedText[0:1] + roadSoundexString elif len(roadPreSoundexString) == 2: roadSoundexString = "0" + roadPreSoundexString roadSoundexString = excludedText[0:1] + roadSoundexString elif len(roadPreSoundexString) == 1: roadSoundexString = "00" + roadPreSoundexString roadSoundexString = excludedText[0:1] + roadSoundexString else: pass # One of the excluded texts was found at the start of the name, but it was not followed by # A, AA, 1, 20, 340, 5670, etc... # Instead something like "Road Hitch" or "RD Empire" # Do soundex normally, but replace the first character with the first character from the # excluded text. else: roadSoundexString = soundex(roadPreSoundexString) # Slice the roadSoundexString to remove the first character, but keep the rest. roadSoundexString = roadSoundexString[1:] # Add the first letter from the excluded text to the start of the Soundex string. roadSoundexString = excludedText[0:1] + roadSoundexString # Assign the new road soundex string to the held row's third slot, heldRow[2], # to be used in an update cursor to update the data in the geodatabase. heldRow[2] = roadSoundexString else: pass # Start an edit session for this workspace because the centerline # feature class participates in a topology. editSession = daEditor(gdb) editSession.startEditing(False, False) editSession.startOperation() cursor = daUpdateCursor(roadFeatures, fieldList) # @UndefinedVariable for row in cursor: for heldRow in holderList: if row[0] == heldRow[0]: cursor.updateRow(heldRow) else: pass # Clean up if cursor: del cursor else: pass if row: del row else: pass editSession.stopOperation() editSession.stopEditing(True) def RouteCalc(lyr, soundexNameExclusions): """calculate what should be a nearly unique LRS Route key based on the decoding and street name soundex/numdex function""" #CalcField(lyr,"Soundex","numdex(!RD!)","PYTHON_9.3","#") RoadinName(lyr, soundexNameExclusions) CalcField(lyr, "RID", "str(!KDOT_COUNTY_R!)+str(!KDOT_COUNTY_L!)+str(!KDOT_CITY_R!)+str(!KDOT_CITY_L!)+str(!PreCode!) + !Soundex! + str(!SuffCode!)+str(!UniqueNo!)+str(!TDirCode!)","PYTHON_9.3","#") # Instead of calling numdex here, rewrite and incorporate numdex and soundex functionality into the RoadinName function. def AliasCalc(Alias, DOTRoads): CalcField(Alias, "KDOT_PREFIX", "!LABEL![0]","PYTHON_9.3","#") CalcField(Alias,"KDOT_ROUTENAME","""!A_RD![1:].replace("S","").zfill(3)""","PYTHON_9.3","#") TableView(DOTRoads+"\KDOT_RoutePre", "KDOT_RoutePre") JoinTbl("RoadAlias", "KDOT_PREFIX", "KDOT_RoutePre", "LRSPrefix", "KEEP_COMMON") CalcField("RoadAlias","RoadAlias.KDOT_CODE","!KDOT_RoutePre.PreCode!","PYTHON_9.3","#") removeJoin("RoadAlias") def HighwayCalc(lyr, gdb, Alias): """Pull out State Highways to preserve KDOT LRS Key (CANSYS FORMAT - non directional CRAD)""" if Exists(gdb+"\RoadAlias_Sort"): Delete(gdb+"\RoadAlias_Sort") else: pass Sort_management(Alias,gdb+"\RoadAlias_Sort","KDOT_CODE ASCENDING;KDOT_ROUTENAME ASCENDING","UR") #Heiarchy did not sort or calc correctly for Cheyenne County, US36 over K161 1st #Sot and join doesnt accomplish primary route key designsation... but calculaing over hte heirarchy should... #Remember to check the primary route heirarchy calculates correctly where US rides US and I rides I Heriarchy = ["K", "U", "I"] for routeClass in Heriarchy: rideselect = "KDOT_PREFIX LIKE '"+routeClass+"%'" print rideselect, routeClass TableView(gdb+"\RoadAlias_Sort", "RoadAlias_Sort", rideselect) JoinTbl(lyr,"SEGID","RoadAlias_Sort", "SEGID", "KEEP_COMMON") CalcField(lyr,lyr+".KDOTPreType","!RoadAlias_Sort.KDOT_PREFIX!","PYTHON_9.3","#") CalcField(lyr,lyr+".Soundex","!RoadAlias_Sort.KDOT_PREFIX!+!RoadAlias_Sort.KDOT_ROUTENAME!","PYTHON_9.3","#") CalcField(lyr,"KDOT_ADMO","'S'","PYTHON_9.3","#") CalcField(lyr,"PreCode","0","PYTHON_9.3","#") removeJoin(lyr) CalcField(lyr, "RID", "str(!KDOT_COUNTY_R!)+str(!KDOT_COUNTY_L!)+str(!KDOT_CITY_R!)+str(!KDOT_CITY_L!)+str(!PreCode!) + !Soundex! + str(!SuffCode!)+str(!UniqueNo!)+str(!TDirCode!)","PYTHON_9.3","#") CalcField(lyr, "LRSKEY", "str(!RID!)", "PYTHON_9.3","#") def ScratchCalcs(): CalcField("RoadCenterline","RoadCenterline.Soundex","""!RoadAlias.A_RD![0] + !RoadAlias.A_RD![1:].replace("S","").zfill(3)""","PYTHON_9.3","#") CalcField(in_table="RoadCenterline",field="RoadCenterline.KDOTPreType",expression="!RoadAlias.A_RD![0] ",expression_type="PYTHON_9.3",code_block="#") CalcField(in_table="RoadCenterline",field="RoadCenterline.PreCode",expression="'0'",expression_type="PYTHON_9.3",code_block="#") CalcField(in_table="RoadCenterline",field="RoadCenterline.KDOT_ADMO",expression="'S'",expression_type="PYTHON_9.3",code_block="#") def LRS_Tester(): """makes the LRS route layer and dissolves the NG911 fields to LRS event tables""" # Replace a layer/table view name with a path to a dataset (which can be a layer file) or create the layer/table view within the script # The following inputs are layers or table views: "RoadCenterline" from arcpy import Dissolve_management as dissolve CalcField(lyr, "LRSKEY", "str(!KDOT_COUNTY_R!)+str(!KDOT_COUNTY_L!)+str(!KDOT_CITY_R!)+str(!KDOT_CITY_L!)+str(!PreCode!) + !Soundex! + str(!SuffCode!)+str(!UniqueNo!)+str(!TDirCode!)","PYTHON_9.3","#") CalcField(lyr, "RID", "str(!KDOT_COUNTY_R!)+str(!KDOT_COUNTY_L!)+str(!KDOT_CITY_R!)+str(!KDOT_CITY_L!)+str(!PreCode!) + !Soundex! + str(!SuffCode!)+str(!UniqueNo!)+str(!TDirCode!)","PYTHON_9.3","#") env.overwriteOutput = 1 dissolve(lyr,gdb+"/NG911/RCLD1","LRSKEY","SEGID COUNT;L_F_ADD MIN;L_T_ADD MAX;L_F_ADD RANGE;L_T_ADD RANGE;SHAPE_MILES SUM","MULTI_PART","DISSOLVE_LINES") dissolve(lyr,gdb+"/NG911/RCLD2","LRSKEY","SEGID COUNT;L_F_ADD MIN;L_T_ADD MAX;L_F_ADD RANGE;L_T_ADD RANGE;SHAPE_MILES SUM","MULTI_PART","UNSPLIT_LINES") #MakeRouteLayer_na() pass uniqueIdInFields = ["OBJECTID", "COUNTY_L", "COUNTY_R", "STATE_L", "STATE_R", "L_F_ADD", "L_T_ADD", "R_F_ADD", "R_T_ADD", "UniqueNo", "LRSKEY", "SHAPE_MILES"] uniqueIdOutFields = ["OBJECTID", "UniqueNo", "LRSKEY"] def createUniqueIdentifier(gdb, lyr, inFieldNamesList, outFieldNamesList): '''filters through records and calculates an incremental Unique Identifier for routes that are not border routes, to handle Y's, eyebrows, and splits that would cause complex routes''' workspaceLocation = gdb #MakeFeatureLayer_management(lyr,"RCL_Particles",where_clause="COUNTY_L = COUNTY_R AND STATE_L = STATE_R AND ( L_F_ADD =0 OR L_T_ADD =0 OR R_F_ADD =0 OR R_T_ADD =0)") featureClassName = lyr from arcpy.da import SearchCursor as daSearchCursor, UpdateCursor as daUpdateCursor, Editor as daEditor alphabetListForConversion = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] newCursor = daSearchCursor(featureClassName, inFieldNamesList) searchList = list() for searchRow in newCursor: searchList.append(list(searchRow)) # Transforms the row tuple into a list so it can be edited. if "newCursor" in locals(): del newCursor else: pass matchCount = 0 matchList = list() for testRow in searchList: if (testRow[1] == testRow[2] and testRow[3] == testRow[4] and (str(testRow[5]) == "0" or str(testRow[6]) == "0" or str(testRow[7]) == "0" or str(testRow[8]) == "0")): matchCount += 1 matchList.append(testRow) matchedRowDictionary = dict() for matchedRow in matchList: matchedRowContainer = list() # If the key already exists, assign the previous list of lists # to the list container, then append the new list # before updating the new value to that key in the dictionary. if matchedRow[10] in matchedRowDictionary: matchedRowContainer = matchedRowDictionary[matchedRow[10]] matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer # Otherwise, the key needs to be created # with the value, the list container, having only # one list contained within it for now. else: matchedRowContainer.append(matchedRow) matchedRowDictionary[matchedRow[10]] = matchedRowContainer for LRSKey in matchedRowDictionary: outRowContainer = matchedRowDictionary[LRSKey] # Sort based on length outRowContainer = sorted(outRowContainer, key = lambda sortingRow: sortingRow[11]) countVariable = 0 # Start at 0 for unique values LRSVariable = "" for outRowIndex, outRow in enumerate(outRowContainer): # Is this the first list/row in the key's list container? # If so, then set the Resolution_Order to 0 if outRowIndex == 0: outRow[9] = 0 else: countVariable += 1 if countVariable in [1, 2, 3, 4, 5, 6, 7, 8, 9]: outRow[9] = countVariable elif countVariable >= 10 and countVariable <= 34: outRow[9] = alphabetListForConversion[countVariable - 10] # Converts countVariable to an alpha character, without the letter "O". else: print "The count Variable is above 34. Ran out of numbers and letters to use as unique values." LRSVariable = outRow[10] LRSVariableShortened = str(LRSVariable[:-1]) # Returns the LRSVariable without the last character. LRSVariable = LRSVariableShortened + str(outRow[9]) outRow[10] = LRSVariable outRowString = "" for outRowElement in outRow: outRowString = outRowString + str(outRowElement) + " " print outRowString outRowContainer[outRowIndex] = outRow matchedRowDictionary[LRSKey] = outRowContainer newEditingSession = daEditor(workspaceLocation) newEditingSession.startEditing() newEditingSession.startOperation() newCursor = daUpdateCursor(featureClassName, outFieldNamesList) # @UndefinedVariable for existingRow in newCursor: formattedOutRow = list() if existingRow[2] in matchedRowDictionary.keys(): outRowContainer = matchedRowDictionary[existingRow[2]] for outRow in outRowContainer: if existingRow[0] == outRow[0]: # Test for matching OBJECTID fields. formattedOutRow.append(outRow[0]) formattedOutRow.append(outRow[9]) formattedOutRow.append(outRow[10]) newCursor.updateRow(formattedOutRow) else: pass else: pass newEditingSession.stopOperation() newEditingSession.stopEditing(True) if "newCursor" in locals(): del newCursor else: pass #ConflateKDOT(gdb, DOTRoads) #addAdminFields(lyr, Alias) #CalcAdminFields(lyr, Kdotdbfp) #CountyCode(lyr) #CityCodes(lyr, Kdotdbfp) RouteCalc(lyr, soundexNameExclusions) #AliasCalc(Alias, DOTRoads) #HighwayCalc(lyr, gdb, Alias) #StreetNetworkCheck(gdb) #createUniqueIdentifier(gdb, lyr, uniqueIdInFields, uniqueIdOutFields) #LRS_Tester()
def concatFullTargetKeys(): # County Key Calculation # County Code (3) + Prefix (1) + Route number (5) + Suffix (1) + Inventory Direction (1) = 11 characters. # County Code (3) + Prefix (1) + Route number (5) + Suffix (1) + Inventory Direction (1) + Unique ID (2) = 13 characters. # First, start an update cursor, # then update the columns with this format: # lrsKeyCountyTarget = countycode.zfill(3) + prefix_target + routenumber_target + suffix + inventorydirection or 0 + unique id (ramp code), or null if not a ramp (PREFIX_TARGET is not 'X') and unique id/ramp code == '00'. updateFields = [ 'LRS_COUNTY_PRE', 'ROUTE_PREFIX_TARGET', 'LRS_ROUTE_NUM_TARGET', 'LRS_ROUTE_SUFFIX', 'LRS_DIRECTION', 'KDOT_DIRECTION_CALC', uniqueIdTarget, 'LRS_UNIQUE_IDENT', 'LRS_UNIQUE_IDENT1', targetCountyLRSKey ] # If uniqueID is None OR uniqueID == '00' and prefix_target != 'X', # uniqueIDPartForConcat = '' newCursor = daUpdateCursor(fcToCalculateTargetKeysIn, updateFields) for updateItem in newCursor: updateListItem = list(updateItem) keyToUse = '' if str(updateListItem[0]).lower() != 'none': countyPre = updateListItem[0] else: countyPre = '404' # County Not Found if str(updateListItem[1]).lower() != 'none': prefixTarget = updateListItem[1] else: prefixTarget = '8' # For 'other'. if str(updateListItem[2]).lower() != 'none': routeNumTarget = updateListItem[2] else: routeNumTarget = str('').zfill(5) if str(updateListItem[3]).lower() != 'none': if updateListItem[1] in ('1', '2', '3', '4', '5', '6'): routeSuffix = updateListItem[3] elif updateListItem[1] in ('0', 'G'): routeSuffix = updateListItem[3] else: routeSuffix = '0' else: routeSuffix = '0' lrsDirToUse = '' if updateListItem[5] in ('0', '1'): lrsDirToUse = str(updateListItem[5]) elif updateListItem[4] in ('EB', 'NB'): lrsDirToUse = '0' elif updateListItem[4] in ('WB', 'SB'): lrsDirToUse = '1' else: lrsDirToUse = '0' uniqueToUse = '' if str(updateListItem[6]).lower() != 'none': uniqueToUse = updateListItem[6] elif str(updateListItem[8]).lower() != 'none': uniqueToUse = updateListItem[8] elif str(updateListItem[7]).lower() != 'none': uniqueToUse = updateListItem[7] if uniqueToUse == '00' and prefixTarget != 'X': uniqueToUse = '' else: pass keyToUse = countyPre + prefixTarget + routeNumTarget + routeSuffix + lrsDirToUse + uniqueToUse updateListItem[9] = keyToUse newCursor.updateRow(updateListItem) try: del newCursor except: pass # state system only # This should be a 8-9 character key, with the last character being a reduced length unique id that's nullable. # Prefix (1) + Route number (5) + Suffix (1) + Inventory Direction (1) = 8 characters. # Prefix (1) + Route number (5) + Suffix (1) + Inventory Direction (1) + Unique ID (2 reduced to 1) = 9 characters. stateSystemSelectionQuery = """ SourceRouteId LIKE '___I%' OR LRS_ROUTE_PREFIX = 'I' OR SourceRouteId LIKE '___U%' OR LRS_ROUTE_PREFIX = 'U' OR SourceRouteId LIKE '___K%' OR LRS_ROUTE_PREFIX = 'K' """ updateFields = [ 'LRS_COUNTY_PRE', 'ROUTE_PREFIX_TARGET', 'LRS_ROUTE_NUM_TARGET', 'LRS_ROUTE_SUFFIX', 'LRS_DIRECTION', 'KDOT_DIRECTION_CALC', uniqueIdTarget, 'LRS_UNIQUE_IDENT', 'LRS_UNIQUE_IDENT1', targetStateLRSKey ] newCursor = daUpdateCursor(fcToCalculateTargetKeysIn, updateFields, stateSystemSelectionQuery) for updateItem in newCursor: updateListItem = list(updateItem) keyToUse = '' #ignore countyPre for state network keys countyPre = '' ''' if updateListItem[0] is not None: countyPre = updateListItem[0] else: countyPre = '404' # County Not Found ''' if str(updateListItem[1]).lower() != 'none': prefixTarget = updateListItem[1] else: prefixTarget = '8' # For 'other'. if str(updateListItem[2]).lower() != 'none': routeNumTarget = updateListItem[2] else: routeNumTarget = str('').zfill(5) if str(updateListItem[3]).lower() != 'none': if int(str(updateListItem[1])) <= 6: routeSuffix = updateListItem[3] elif updateListItem in ('0', 'G'): routeSuffix = updateListItem[3] else: routeSuffix = '0' else: routeSuffix = '0' lrsDirToUse = '' if updateListItem[5] in ('0', '1'): lrsDirToUse = str(updateListItem[5]) elif updateListItem[4] in ('EB', 'NB'): lrsDirToUse = '0' elif updateListItem[4] in ('WB', 'SB'): lrsDirToUse = '1' else: lrsDirToUse = '0' uniqueToUse = '' if str(updateListItem[6]).lower() != 'none': uniqueToUse = str(updateListItem[6])[-1] elif str(updateListItem[8]).lower() != 'none': uniqueToUse = str(updateListItem[8])[-1] elif str(updateListItem[7]).lower() != 'none': uniqueToUse = str(updateListItem[7])[-1] if uniqueToUse == '00' and prefixTarget != 'X': uniqueToUse = '' else: pass keyToUse = countyPre + prefixTarget + routeNumTarget + routeSuffix + lrsDirToUse + uniqueToUse updateListItem[9] = keyToUse newCursor.updateRow(updateListItem) try: del newCursor except: pass
def duplicateNameRemoval(quarterOrHalf): if quarterOrHalf.lower() == "quarter": countyRoadNameRosette = countyRoadNameRosette_Q elif quarterOrHalf.lower() == "half": countyRoadNameRosette = countyRoadNameRosette_H else: print "quarterOrHalf variable not correctly defined." raise (Exception("quarterOrHalf error.")) print "Starting duplicate name removal." countyRoadNameRosetteFields = ListFields(countyRoadNameRosette) print "countyRoadNameRosetteFields: " for fieldItem in countyRoadNameRosetteFields: print str(fieldItem.name) newCursor = daSearchCursor(countyRoadNameRosette, countyRoadNameRosetteFieldsObjShape) # Debug only #print "Created a new cursor..." countyNamePointList = list() for eachPoint in newCursor: countyNamePointList.append(eachPoint) try: del newCursor except: pass # Debug only #print "Completed using the new cursor." pointDeleteList = list() for pointItem in countyNamePointList: for pointToCheck in countyNamePointList: # If the points share a road name, and a county number, but not the same ObjectID... if pointItem[0] not in pointDeleteList: if pointItem[3] == pointToCheck[3] and str( pointItem[2]).upper() == str( pointToCheck[2]).upper() and (not pointItem[0] == pointToCheck[0]): # Use the distance formula to check to see if these points are within a # certain distance from one another. # If so, add the pointToCheck to the pointDeleteList. distance = 0 point1 = pointItem[1] point2 = pointToCheck[1] distance = calcPointDistance(point1, point2) # Change this to add just the objectid to the pointDeleteList # instead of the whole point row to increase the speed # of the check when the list grows to a decent size. # Distance of 10000 seems to give good results. if distance >= 0 and distance < 10000 and pointToCheck[ 0] not in pointDeleteList: pointDeleteList.append(pointToCheck[0]) else: pass else: pass else: pass newCursor = daUpdateCursor(countyRoadNameRosette, countyRoadNameRosetteFieldsObjShape) for updateableRow in newCursor: for pointToDeleteOID in pointDeleteList: if updateableRow[0] == pointToDeleteOID: print "Selected a point for " + str( updateableRow[2]) + " in " + str( updateableRow[4]) + " county to delete." newCursor.deleteRow() print "Point deleted." else: pass #updateCursor #delete pointToDelete from countyRoadNameRosette. #print a message saying that the point was deleted. try: del newCursor except: pass
def localRouteNumbering(): tempDesc = Describe(routeFeaturesFC) print("Calculating LRS Key sub-parts for features in " + returnFeatureClass(tempDesc.catalogPath) + ".") OIDFieldName = tempDesc.OIDFieldName try: del tempDesc except: pass # ReAdd the fields that we're interested in, in the correct order. # sortPointDist will be appended later, making it [-1] and 'LRS_UNIQUE_IDENT1' will be [-2]. fieldsToUse = [ OIDFieldName, 'SHAPE@', 'LABEL', 'LRS_ROUTE_PREFIX', 'LRS_ROUTE_NUM', 'LRS_UNIQUE_IDENT', 'LRS_UNIQUE_IDENT1' ] currentFields = fieldsToUse shapeTokenPosition = 1 uniqueCountyCodeDict = dict() countyCodeFieldsList = ['KDOT_COUNTY_L', 'KDOT_COUNTY_R'] newCursor = daSearchCursor(routeFeaturesFC, countyCodeFieldsList) for cursorRow in newCursor: uniqueCountyCodeDict[str(cursorRow[0])] = 1 uniqueCountyCodeDict[str(cursorRow[1])] = 1 try: del newCursor except: pass uniqueCountyCodeList = list() for uniqueCountyCode in uniqueCountyCodeDict.keys(): uniqueCountyCodeList.append(uniqueCountyCode) try: del uniqueCountyCodeDict except: pass try: uniqueCountyCodeList.remove('None') except: pass sortedUniqueCountyCodes = sorted( uniqueCountyCodeList ) # No need to specify a key since it's one column. for uniqueCountyCodeItem in sortedUniqueCountyCodes: print('Selecting features based on countyCode: ' + str(uniqueCountyCodeItem) + '.') routeFeaturesList = list() uniqueLabelDict = dict() # This should include a check for LRS_PREFIX = 'L' when the KDOT_LRS_KEY IS NULL, instead of taking everything that has a NULL # KDOT LRS_KEY. Need another parenthesis to group the condition inside the current parenthesis. selectionQuery1 = """ KDOT_COUNTY_L = '""" + str( uniqueCountyCodeItem ) + """' AND ((KDOT_LRS_KEY IS NULL AND LRS_PREFIX = 'L') OR KDOT_LRS_KEY LIKE '%L%') """ selectionQuery2 = """ KDOT_COUNTY_L IS NULL AND KDOT_COUNTY_R = '""" + str( uniqueCountyCodeItem ) + """' AND ((KDOT_LRS_KEY IS NULL AND LRS_PREFIX = 'L') OR KDOT_LRS_KEY LIKE '%L%') """ labelField = ['LABEL'] newCursor = daSearchCursor(routeFeaturesFC, labelField, selectionQuery1) for cursorRow in newCursor: uniqueLabelDict[str(cursorRow[0])] = 1 try: del newCursor except: pass newCursor = daSearchCursor(routeFeaturesFC, labelField, selectionQuery2) for cursorRow in newCursor: uniqueLabelDict[str(cursorRow[0])] = 1 try: del newCursor except: pass countyLocalNumber = 0 # Narrow the features that are looked at further. ### Change this to just give you the features instead of ### ### cursoring them back out. ### ### Figure out a way to create dicts/lists that store the features ### in the way that you want them instead of having to run another ### separate pair of selects after this. for uniqueLabelKey in uniqueLabelDict.keys(): if uniqueLabelKey is not 'None': # Labels with single quotes cause problems in selections. if str.find(uniqueLabelKey, "'") > -1: # So, escape them by replacing individual single quotes with double single quotes. uniqueLabelKey = str.replace(uniqueLabelKey, "'", "''") else: pass print("Using the LABEL field value of: " + str(uniqueLabelKey) + ".") countyLocalNumber += 1 selectionQuery3 = selectionQuery1 + """ AND LABEL = '""" + str( uniqueLabelKey) + """' """ selectionQuery4 = selectionQuery2 + """ AND LABEL = '""" + str( uniqueLabelKey) + """' """ labeledRouteFeaturesList = list() firstCounter = 0 newCursor = daSearchCursor(routeFeaturesFC, currentFields, selectionQuery3) for cursorRow in newCursor: firstCounter += 1 labeledRouteFeaturesList.append(list(cursorRow)) try: del newCursor except: pass print("FirstCounter found : " + str(firstCounter) + " segments.") secondCounter = 0 newCursor = daSearchCursor(routeFeaturesFC, currentFields, selectionQuery4) for cursorRow in newCursor: secondCounter += 1 labeledRouteFeaturesList.append(list(cursorRow)) try: del newCursor except: pass print("SecondCounter found : " + str(secondCounter) + " segments.") sortedLabeledRouteFeaturesList = addDistanceAndSort( labeledRouteFeaturesList, shapeTokenPosition) del labeledRouteFeaturesList labelUniqueNumber = 0 previousFeatureGeom = None outputFeaturesDict = dict() for sortedLabeledRouteFeatureItem in sortedLabeledRouteFeaturesList: if previousFeatureGeom == None: # This is the first feature of this label. # Don't need to check for incrementing the labelUniqueNumber. # Just assign the current countyLocalNumber to this feature. # Then, set the previousFeatureGeom to this feature's shape. previousFeatureGeom = sortedLabeledRouteFeatureItem[ shapeTokenPosition] else: # Check to see if this feature's firstpoint or lastpoint are # a match for the previous feature's firstpoint or lastpoint. thisFeatureGeom = sortedLabeledRouteFeatureItem[ shapeTokenPosition] ## This part needs work because it always fails. :(. ## Create a function to check the arrays for relevant matching values instead. ## And let it "match" when there are points that are within the feature tolerance ## of one another. The non-matching is most likely a problem with floating point ## math and equalities. -- See videolog lookup C# for ideas, if needed. # Change this to look at math.abs(firstPoint.X - other.firstPoint.X) < 2*Epsilon, # and math.abs(firstPoint.Y - other.firstPoint.Y) < 2*Epsilon # Since each Point is a Python object and they won't have the same # identity in Python when it performs a comparison on them. # The only time that this will work correctly is when you have # two variable names referencing the same object # (in the same memory location). if polylineStartEndPointsMatch( thisFeatureGeom, previousFeatureGeom, currentXYTolerance) == True: # The feature is contiguous without a gap. The labelUniqueNumber doesn't need to be incremented. # Assign the county code as it's routeNumber and the labelUniqueNumber as its unique ID. pass else: # If not, increment the labelUniqueNumber by 1 # prior to assignment on this feature. labelUniqueNumber += 1 # If greater than 99, then you have to split it so that part of it goes into LRS_UNIQUE_IDENT # and part of it goes into LRS_UNIQUE_IDENT1. if labelUniqueNumber > 99: onesAndTens = labelUniqueNumber % 100 hundredsAndThousands = labelUniqueNumber / 100 pass else: onesAndTens = labelUniqueNumber hundredsAndThousands = 0 sortedLabeledRouteFeatureItem[-2] = str( onesAndTens).zfill(2) ## 2 chars sortedLabeledRouteFeatureItem[-3] = str( hundredsAndThousands).zfill( 1 ) ## 2 chars # Should only be 1char, but /shrug sortedLabeledRouteFeatureItem[-4] = str( countyLocalNumber).zfill(5) ## 5 chars # Then, set the previousFeatureGeom to this feature's shape. previousFeatureGeom = sortedLabeledRouteFeatureItem[ shapeTokenPosition] print( "Adding a feature to the outputFeaturesDict with a countyLocalNumber of: " + str(countyLocalNumber) + " and a labelUniqueNumber of: " + str(labelUniqueNumber) + ".") outputFeaturesDict[sortedLabeledRouteFeatureItem[ 0]] = sortedLabeledRouteFeatureItem[:-1] newCursor = daUpdateCursor(routeFeaturesFC, currentFields, selectionQuery3) for cursorRow in newCursor: if cursorRow[0] in outputFeaturesDict.keys(): newCursor.updateRow(outputFeaturesDict[cursorRow[0]]) try: del newCursor except: pass newCursor = daUpdateCursor(routeFeaturesFC, currentFields, selectionQuery4) for cursorRow in newCursor: if cursorRow[0] in outputFeaturesDict.keys(): newCursor.updateRow(outputFeaturesDict[cursorRow[0]]) try: del newCursor except: pass try: del sortedLabeledRouteFeaturesList except: pass else: pass #Cleanup try: del sortedLabeledRouteFeaturesList except: pass try: del sortedLabeledRouteFeaturesList except: pass
def duplicateNameRemoval(): print "Starting duplicate name removal." newCursor = daSearchCursor(countyRoadNameRosette, countyRoadNameRosetteFieldsObjShape) countyNamePointList = list() for eachPoint in newCursor: countyNamePointList.append(eachPoint) if "newCursor" in locals(): del newCursor else: pass pointDeleteList = list() for pointItem in countyNamePointList: for pointToCheck in countyNamePointList: # If the points share a road name, and a county number, but not the same ObjectID... if pointItem[0] not in pointDeleteList: if pointItem[3] == pointToCheck[3] and str(pointItem[2]).upper() == str(pointToCheck[2]).upper() and (not pointItem[0] == pointToCheck[0]): # Use the distance formula to check to see if these points are within a # certain distance from one another. # If so, add the pointToCheck to the pointDeleteList. distance = 0 point1 = pointItem[1] point2 = pointToCheck[1] distance = calcPointDistance(point1, point2) # Added "and pointToCheck not in pointDeleteList" # to prevent two points from both adding a 3rd point to the list. # Also, the distance looks enormous, but it's only about 1500 meters in Lambert_Conformal_Conic_2SP. # @ 450,000 = maxDistance. -- Check smaller values before implementing, however... # as going from 15000 to 450000 adds a long time to this function's execution. # maybe remove the equality on the upper bound, and change the lower bound # to -1 or something like that. # Change this to add just the objectid to the pointDeleteList # instead of the whole point row to increase the speed # of the check when the list grows to a decent size. # Distance of 10000 seems to give good results. if distance >= 0 and distance < 10000 and pointToCheck[0] not in pointDeleteList: pointDeleteList.append(pointToCheck[0]) else: pass else: pass else: pass newCursor = daUpdateCursor(countyRoadNameRosette, countyRoadNameRosetteFieldsObjShape) for updateableRow in newCursor: for pointToDeleteOID in pointDeleteList: if updateableRow[0] == pointToDeleteOID: print "Selected a point for " + str(updateableRow[2]) + " in " + str(updateableRow[3]) + " county to delete." newCursor.deleteRow() print "Point deleted." else: pass #updateCursor #delete pointToDelete from countyRoadNameRosette. #print a message saying that the point was deleted. if "newCursor" in locals(): del newCursor else: pass