Original User: joelschlagerThe goal of this project is to rotate address point labels (house number specifically) to be perpendicular to the street to which they belong (purely by street name comparison thus far). Inputs are an address point (point) feature class and a road centerline (polyline) feature class. The output is a point feature class with a field called "angle" populated with a calculated angle for labeling (the input address point feature class has this "angle" field as well but isn't calculated). My problem is with the logic within the ???while??? loop as I tried to account for cul-de-sacs and dead ends but found that it also included the ends of all feature parts. Is there a way to test if a feature part is connected to another feature part? Any help/guidance is appreciated (an illustration and sample data are provided). **NOTE** I had to make the street names match exactly at this point as I have not added tests to check for differences yet.#Import modules import arcpy import math from arcpy import env #Overwrite output to the output feature class env.overwriteOutput = True #Assign variables env.workspace = r"Local_FGDB_Path" addptFC = "TEST_ADD_PTS" clFC = "Street_Test" OutFC = "Output_Add_Pts" #See if in_memory layers exist - delete them if they do if arcpy.Exists("addpts"): arcpy.Delete_management("addpts") if arcpy.Exists("CLs"): arcpy.Delete_management("CLs") #Create in memory feature layers of input feature classes arcpy.MakeFeatureLayer_management(addptFC, "addpts") arcpy.MakeFeatureLayer_management(clFC, "CLs") #Create UpdateCursor addptrows = arcpy.UpdateCursor("addpts", "", "", "STREET_B", "STREET_B A") #Set variable to "shape" field addptDesc = arcpy.Describe("addpts") addptSFN = addptDesc.ShapeFieldName #Field that holds the shape info clDesc = arcpy.Describe("CLs") clSFN = clDesc.ShapeFieldName #Field that holds the shape info #Begin loop for address points for addptrow in addptrows: addptValue = addptrow.getValue("STREET_B") #Create searchCursor for temporary centerline feature layer clrows = arcpy.SearchCursor("CLs", "", "", "ST_BOTH", "ST_BOTH A") #Set variable for feature addptFEAT = addptrow.getValue(addptSFN) #Set variable for feature part addptPART = addptFEAT.getPart() #Set variables for "X" and "Y" coordinates for feature part addptX = addptPART.X addptY = addptPART.Y #Create empty list to store midpoint distances and angles of parts - compare all values to find which feature #with similar street name is closest to address point closestMid = [] #Begin loop for centerlines for clrow in clrows: clValue = clrow.getValue("ST_BOTH") vertexList = [] #Find all like street names between address points and centerlines if addptValue == clValue: #Set variable for feature clFEAT = clrow.getValue(clSFN) #Set variable for feature part clPART = clFEAT.getPart(0) #Set variables for "X" and "Y" coordinates for feature part for clpartObj in clPART: vertexList.append((clpartObj.X, clpartObj.Y)) vertexCount = len(vertexList) if vertexCount < 2: break #If only one vertex then exit loop (no midpoint to calculate) z = 0 #Loop through feature parts and get coordinates for each vertex while z + 2 <= vertexCount: #That is until you run out of pairs to count #Get vertices for segment x1 = vertexList[0] y1 = vertexList[1] x2 = vertexList[z + 1][0] y2 = vertexList[z + 1][1] #Calculate the midpoint of the line segment midX = (x1 + x2)/2 midY = (y1 + y2)/2 #Calculate the distance from the address point to the midpoint of the part distMid = math.sqrt(((addptX - midX)**2) + ((addptY - midY)**2)) if x1 == vertexList[0][0] or x2 == vertexList[len(vertexList)-1][0]: #These delta values calculated between midpoint of feature part and address point deltaX = midX - addptX deltaY = midY - addptY #Calculate label angle for address point addptAngle = (57.2957795 * math.atan2(deltaY, deltaX)) else: #These delta values calculated on the feature parts deltaX = x2 - x1 deltaY = y2 - y1 #Calculate label angle for address point #("90" added so that point angle is perpendicular to line angle) addptAngle = (90 + (57.2957795 * math.atan2(deltaY, deltaX))) #"closestMid" is the nested list storing: # 1) Distance from address point to midpoint of feature part, # 2) Address point label angle closestMid.append((distMid, addptAngle)) z += 1 ####Set up condition so that when "addptValue" does not have a match that ####addptValue is copied to a text file #####NOTE: Make sure that an address point is retreived here if it isn't spelled correctly #####or if it does not legitimately have a centerline in the county elif addptValue != clValue: clrows.next() #Delete the list holding the coordinates of all vertices for all feature parts del vertexList[:] #This is where the closest value for "closestMid" is finalized finalAngle = 0 #The angle the address point will take closestValue = 0 #The closest midpoint-to-address-point distance #Sort the list "closestMid" and assign the first value of midpoint distance and #address point angle to variables closestMid.sort() closestValue = closestMid[0][0] finalAngle = closestMid[0][1] #Write the address point angle to the "angle" field and update the row within #the temporary feature layer "addpts" addptrow.angle = finalAngle addptrows.updateRow(addptrow) #Delete the list holding the midpoint values and address point label angle values #and delete the row and cursor for the centerline feature layer del closestMid[:] del clrow, clrows #Copy the temporary feature layer "addpts" to the feature class "OutFC" arcpy.CopyFeatures_management("addpts", OutFC) #Delete the row and cursor for the address point feature layer del addptrow, addptrows