What is a public right-of-way?
If you’ve ever taken a driver’s license test you’re probably used to thinking of “right-of-way” as who goes first at an intersection. While this is useful for driving, city staff use the term to describe how wide a public right-of-way is (street, curb, parkway, and sidewalk included). This information is indispensable for planning and public works staff. This is why we see right-of-way widths (in feet) on paper parcel maps dating to the 1960s (figure 1).
maps and rights of way
As you can imagine, cities develop over time and the rights of way can change — maybe the street was widened to accommodate commuters in a growing city or maybe the street is now an alley with new buildings around it. Before modern GIS, you had to search through a book to get the paper maps, and make those edits by hand.
Nowadays we can digitize maps and perform all sorts of analysis on spatial data. Already an improvement to paper maps, we can use a measuring tool common to GIS software, somewhat of a software ruler, to get the rights of way (figure 4.c). But if you wanted this information for the entire city, taking a ruler out and manually measuring/recording every street’s width could take you awhile. Instead, we’ll be writing a Python Script that’ll do just that for us (figure 2).
cooking up an algorithm for rights of way
There are different approaches we can take depending on what data is available. Here we will use a Streets layer of type LineString, and a Parcels layer of type Polygon:
1. Walk along the street, stopping when you’re in the middle. Mark it so you don’t forget where you started.
2. Walk left and…
(a) Count your steps
(b) Stop walking when you’re on someone’s property
3. Walk right and…
(a) Count your steps
(b) Stop walking when you’re on someone’s property
4. Add up how many steps you made in total & record it
The Math of Walking Left and Right
As the algorithm suggests, we need a way of telling the computer to go left & right.
Consider two points A and B. For our algorithm, A represents the start of the street and B the middle of the street.
\( \hspace{2em} \begin{bmatrix} c2/L \\ -c1/L \end{bmatrix} \hspace{2em} \) describes the right perpendicular direction to \(\overrightarrow{C}\).
To actually take that step to the left of B :
And to the right of B:
putting it all together
We’re now equipped with the pieces to write a Python script that will do this for us.
for street in enumerate(streets):
start = 0
mid = (street.geometry().length())/2
pointA = street[start]
pointB = street[mid]
c = pointB-pointA
c1 = c.x()
c2 = c.y()
L = math.sqrt(c1*c1 + c2*c2)
left_direction = [(-c2/L), c1/L]
right_direction = [c2/L, (-c1/L)]
property_found_left = False # flags for tracking
property_found_right = False # if we're on someone's property
left_distance = 0 # stores how many steps we walked
right_distance = 0 # in either direction
MAX_STEPS = 70
steps_to_take = 1 # tracks how many steps we've taken
# Start walking left
while steps_to_take < MAX_STEPS:
# Multiplying our unit directions by some value,
# we can scale the steps we take
scaled_direction = left_direction*steps_to_take
left_of_b = pointB + scaled_direction
# Check if we're on someone's property
if (properties.intersects(left_of_B)):
property_found_left = True
left_distance = steps_to_take
break
# Continue walking if we haven't found
steps_to_take += 1
steps_to_take = 1
# Start walking right
while steps_to_take < MAX_STEPS:
# Multiplying our unit directions by some value,
# we can scale the steps we take
scaled_direction = right_direction*steps_to_take
right_of_b = pointB + scaled_direction
# Check if we're on someone's property
if (properties.intersects(right_of_B)):
property_found_right = True
right_distance = steps_to_take
break
# Continue walking if we haven't found
steps_to_take += 1
# Add up how far we walked left & right
if property_found_left and property_found_right:
right_of_way = left_distance + right_distance
print(f'The Right of Way for {street.attributes('FULLNAME')} is {right_of_way}')