Quantcast
Channel: Forums - Python
Viewing all articles
Browse latest Browse all 2485

Address Point Labeling Script

$
0
0
The 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.
Code:

#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[z][0]
                y1 = vertexList[z][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

Attached Thumbnails
Click image for larger version

Name:	Vis_Examp_1.jpg‎
Views:	N/A
Size:	33.0 KB
ID:	20257  
Attached Files

Viewing all articles
Browse latest Browse all 2485

Trending Articles