Calculating Rights-of-Way

What is a public right-of-way?

1960s City Assessor Paper Map containing Rights of Way
figure 1

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).

A digitized map displaying a Rights of Way layer with modern GIS software.
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.

Walk along the street, stopping when you're in the middle.
figure 3

2. Walk left and…
(a) Count your steps
(b) Stop walking when you’re on someone’s property

From the middle of the street to the right-side Property is about 32 ft.
figure 4.a

3. Walk right and…
(a) Count your steps
(b) Stop walking when you’re on someone’s property

From the middle of the street to the right-side Property is about 28 ft.
figure 4.b

4. Add up how many steps you made in total & record it

Therefore the street is about 60ft, which matches the 1960s paper map.
figure 4.c

The Math of Walking Left and Right

As the algorithm suggests, we need a way of telling the computer to go left & right. 

Taking a left or right while walking along a street makes a 90 degree angle.
Notice when we’re walking left & right, we’ll be walking in a direction that is 90° from the street. So walking left/right boils down to finding a line perpendicular to the street. This sounds complicated, but thankfully some smart math people figured out some formulas for this a long time ago. Following each step will eventually get us the perpendicular line we need. For a deeper dive into the math, check out this video.

Consider two points A and B. For our algorithm, A represents the start of the street and B the middle of the street.
\( A = \begin{bmatrix} a1 \\ a2 \end{bmatrix}, B = \begin{bmatrix} b1 \\ b2 \end{bmatrix} \)
 
\( B – A = \begin{bmatrix} b1 – a1 \\ b2 – a2 \end{bmatrix} = \overrightarrow{C} \\ \)
Calculating Right of Ways - Point A Start, Point B End, and vector C
\( (1)\hspace{2em} \overrightarrow{C} = \begin{bmatrix} c1 \\ c2 \end{bmatrix} \hspace{2em} \) describes the direction from A to B
\( (2)\hspace{2em} L = \sqrt{(c1)^2 + (c2)^2} \hspace{2em} \) describes the entire length from A to B
\( (3)\hspace{2em} \begin{bmatrix} c1/L \\ c2/L \end{bmatrix} \hspace{2em} \) describes the unit direction from A to B.

(i.e. describes the direction from A to B but only takes one step from A to B)
\( (4)\hspace{2em} \begin{bmatrix} -c2/L \\ c1/L \end{bmatrix} \hspace{2em} \) describes the left perpendicular direction to \(\overrightarrow{C}\).
\( \hspace{2em} \begin{bmatrix} c2/L \\ -c1/L \end{bmatrix} \hspace{2em} \) describes the right perpendicular direction to \(\overrightarrow{C}\).
Furthermore, thanks to (3), this is also only one step in the left/right direction. Make note of the components being reversed and one of them negative.
 
Now (4) only describes the directions we need to take.
To actually take that step to the left of B :
\( \begin{bmatrix} b1 \\ b2 \end{bmatrix} + \begin{bmatrix} -c2/L \\ c1/L \end{bmatrix} \)


And to the right of B:
\( \begin{bmatrix} b1 \\ b2 \end{bmatrix} + \begin{bmatrix} c2/L \\ -c1/L \end{bmatrix} \)

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}') 
1960s City Assessor Paper Map containing Rights of Way A digitized map displaying a Rights of Way layer with modern GIS software.

Leave a Comment

Your email address will not be published. Required fields are marked *