Vision Zero Polygon Maintenance

GIS workflow for updating the Vision Zero Location Polygons layer

Project background and goals

The Vision Zero Location Polygons are used by the Vision Zero team to capture crashes on Austin streets and analyze the factors involved to determine if appropriate safety interventions are needed. The polygons provide complete coverage of all Austin roads in the Austin Strategic Mobility Plan Street Network.

The Project can be found on the network here ..._GIS\Vision_Zero\Polygon_Updates\

Digitizing New Polygons

The dimensions of each polygon are determined by the road's street level as specified below:

Road Segmentation

  1. Level 1 or 2 streets: 150 feet

  2. Level 3 or 4 streets: 250 feet

Buffer width

The distances below are the actual distances in feet to type into the buffer geoprocess tool

  1. Street levels 1 or 2: 40 feet

  2. Street level 3: 50 feet

  3. Street level 4: 75 feet

Given that roads are typically longer than the length of the polygon, we set the length of the polygons by tracing along the ASMP streets and buffering these to the appropriate width. The following example can serve as a guide for digitizing new polygons in most scenarios.

Henneman Drive Example

In this example, we are tasked with digitizing Henneman Drive, along with all the streets that are missing polygon coverage:

When the polygons were first generated, this subdivision had not been completed. To cover this area, we must prep existing polygons to be compatible with new ones, trace polygon-length lines along the ASMP starting at intersections, dissolving intersection lines, buffering to the appropriate width, and appending them to the authoritative layer.

Prep existing polygons

Start by removing the rounded end points of the polygon so that are squared off and ready to join other polygons:

The easiest way to do this is to keep the circled vertices and lasso-deleting the vertices in between:

Tracing along the ASMP

  1. Trace lines along the ASMP streets with the Trace Limit Length set to match the street level.

    1. Trace options are accessed by pressing the letter O after clicking on the starting point of your trace.

  2. Trace all intersections and all L sections first, starting with the middle point, and working your way outwards

    1. Set your trace limit to half the corresponding street level/segment length. For example, set the trace limit to 75 for street levels 1&2

  3. Merge each intersection and L sections

    1. This will ensure that the buffers are drawn correctly and will minimize buffering errors.

  4. Draw in the rest of the segments at full length, according to street level

    1. If some segments are shorter, that is okay, but try to not let them get too small

      1. If a segment is going to be too small (~10 -20 feet), it is best to draw/edit a nearby segment the necessary length to cover it

Tracing along the CTN

If the ASMP does not have good geometry to digitize from, use the CTN - it is updated frequently. If the CTN is missing data, or the polylines do not follow the actual centerline of the street, request that the CTN is fixed before tracing any new edit lines. We want the best data possible, and we don't want to duplicate our work. Drawing new edit lines while leaving the CTN in bad shape would create more work for the future, and it is unlikely to be ever fixed.

Buffering Polygons

Polygons have rounded ends and square joins to each other. For this reason, we run the buffer geoprocessing tool on our segment-lines twice. Currently, we overwrite each buffer output. This means that each buffering session deletes the previous content of the feature, and writes in the new buffers for your current edit session.

This will require the editor to append their buffered polygons before moving on to the next area to digitize. The main logic behind overwriting the data is to allow for the subsequent Append step to run quickly - if we save each buffer output as its own feature class, eventually the Append tool will begin to run slowly because it has to read a long list of un-indexed items to find the correct features to append from the file geo database (FGDB)*.

*NOTE: The issue is not the size of the FGDB, as there's no size limit, but rather finding the data. It's like tossing dirty laundry into a large hamper. Tossing dirty clothes into it is no problem, as you can toss the whole load into the wash, but finding a single sock would be difficult. We recently ran into this issue with the iMOPED data. In that project, it may be important to keep all update data, so we create quarterly file geodatabases, so that the outputs of the weekly update only reach about 12-15 features each before starting a new FGDB. This may work well in this project if keeping update data is important for the QA process.

  1. Select all segment lines that will result in square-end polygons (all segments that connect to other segments)

    1. In the buffering tool, select the appropriate buffer width

    2. Do not dissolve

    3. Save the output as flat_polygons

  2. Select all segment lines that will result in found-end polygons (all segments that are the end of a street, or a cul-de-sac)

    1. In the buffering tool, select the appropriate buffer width

    2. Do not dissolve

    3. Save the output as round_polygons

Appending Polygons

  1. Once all segments have been properly buffered, do a final close-up inspection to ensure no slivers are present.

  2. Open the Append geoprocessing tool

  3. In the append tool, select both flat_polygons and round_polygons as your inputs

  4. For the target dataset, select the polygons layer from MAINT

  5. Use the field mapper to remove all attribute matching

  6. Run the append tool

Attribute edits

Now that the polygons are all in the MAINT layer, you'll notice that all new polygons have a Polygon Sequece ID and a Global ID, but no other attributes.

  1. Fill in Road Name

  2. Fill in Street Level

  3. Select In Use - Yes

Polygon Hex IDs

The Polygon Hex IDs will be calculated from the Global ID. Create a model that does the following:

  1. Remove all special characters

  2. Select the first 10 digits of the Global ID

  3. Field-calculate this selection into the Polygon Hex ID field

Bonus Points if this makes it into the model, but it can be done by hand:

  1. Run unique field tool on Polygon Hex ID field

  2. If all are unique, you're done!

  3. If some duplicates exist, randomly change some characters and run again

Publishing to AGOL

Once all edits are in the MAINT layer, publish to AGOL

Merging Polygons

Merging polygons should maintain the original Hex IDs from the parent polygons. We do this by ensuring that both (or however many more) polygons' IDs are copied into the legacy ID fields. For example, if we're merging polygon A1 with polygon B2, the attribute table should look like this:

Polygon Hex IDLegacy ID 1Legacy ID 2

A1

A1

B2

B2

A1

B2

Once the polygons are merged, the original IDs are preserved in the legacy fields, allowing the Vision Zero team to compare historical crashes with new data at the same location. The new polygon will have a global ID and polygon sequence ID automatically generated

Removing Polygons

Because Polygon Hex IDs are tied to historical crash data, it is important to not delete any polygons, even if they were drawn incorrectly, or if the street has been reconfigured. For any polygons that no longer serve their function, we simply switch the In Use value to No.

Tips for resolving issues

Due to the complexity of this project, it is impossible for documentation to give direct instructions on how to solve every problem. However, when in doubt, let the guiding principles of this project guide your decision-making. The most important function of the polygons is to cover the entirety of our roadways so that we can collect geotagged crash reports accurately. This allows us to analyze whether certain design elements (difficult intersections, lack of sidewalks, lack of lighting, etc) are contributing to crashes, in order to make appropriate and targeted safety interventions.

Prioritize Intersections

Understanding that crashes are more common at intersections than mid-block gives the intersection priority while digitizing. Because no two streets are the same, it can be difficult to get consistent results while digitizing. This invariably results in polygons being of different dimensions than the specs indicate. If sticking to the specs in every scenario is impossible, the best we can do is ensure that polygons that are likeliest to be the sites of crash to follow the specifications as closely as possible - thus intersections should go first.

Funky polygons

When digitizing, you may find that certain new polygons would be really small. As stated in the Tracing the ASMP section, It is preferable to extend the length of adjacent polygons than creating a new tiny polygon. Other steps of digitization may result in self-intersecting polygons. Whenever these are found, make sure to simplify them and to maintain coverage. The cleaner the data, the easier it is to use.

Solve the root cause of the issue

It is sometimes difficult to decide when to stop an edit. In the Hanneman Dr example, many other streets had been added that needed polygon coverage. As we scanned the neighborhood, we noticed several more subdivisions were beginning to connect through new level 1 streets. While our aim is to cover every street, we are assigned issues to prioritize locations where polygon maintenance work is needed. There are no set rules for when to stop digitizing, but there is no need to keep digitizing new street endlessly that have not been requested when there are other streets in our queue. If while editing, you notice areas that need digitzing, create a github issue about it, place it in the backlog, and decide how to prioritize these through sprint planning. For reference, the Hanneman Drive issue (which included surrounding streets in the request) took about 2 hours to digitize. Hanneman Dr was used to develop this workflow, and it is entirely possible it could be done faster. However, no issue should take longer than 2 hours to finish, if this workflow is followed (and hopefully improved upon!). If you find issues/requests that seem longer than that, break it up into smaller pieces at sprint planning, and ask the VZ team to submit smaller/more targeted requests.

Legacy Documentation

The documentation below details the algorithm used to create the initial set of polygons

Definitions and environment

  1. Street Level: The designated street level as found in the ASMP network's attribute street_lev or similar. These are coded as 1 for the smallest, residential streets up to 5 for the major, on-system roads.

  2. Data Projection: All operations described below were executed in SRID 2277, the state plane projection for our portion of Texas which provides for measuring distance in our customary, US foot.

  3. Road segments: A linestring between two intersections, but not extending over or through an intersection.

  4. Intersections: Where road segments touch in the GIS sense or meet in the human sense. Roads can cross each other and not intersect, such as the case when one road goes over or under another without opportunity for drivers to switch between them. One is reliant on the topology of the street network used as input to sort these two cases out.

  5. Legs: The length of a road segment, emanating from an intersection, which ends up being part of an intersection polygon. A leg can be thought of as "one of the arms of the plus-shaped polygons for an intersection."

  6. Intermediate segments & polygons: Where legs are created at intersections, the remaining "middle" portion of the road's linestring is the intermediate segment. When divided up and on a street without curves, these become the simplest, rectangular polygons.

A note on measuring distance along linestrings

When measuring distance along linestrings, one must avoid measuring "as the crow flies" and instead find a way to measure along the linestring. I found success in computing this by mapping (in the computer science sense) the a line segment's length to the interval between 0 and 1. PostGIS offers functions to find a point along an arbitrarily shaped linestring that n% along that linestring, and these two constructs allow for you to find the point an arbitrary number of feet along a linestring.

Polygon creation algorithm

  1. Create a set of points, intersections, which are derived from the intersections of two or more street line segments.

  2. Create a set of legs, being linestrings that emanate out from each intersection point a certain distance along the road linestrings which contributed to each intersection. The length of these legs is defined as follows:

    1. If the road is either level 1 or 2, the length of the leg is 150 feet. The intent here is that an intersection of small roads will have proportionally smaller storage lanes and small area of influence.

    2. If the road is either level 3 or 4, the length of the leg is 250 feet. Larger roads, longer storage lanes, and thus a longer leg length.

    3. A downtown special case is cut out for the downtown streets due to their highly regular grid formation and short road segment lengths, and a leg length is defined downtown as being as long as needed to reach exactly half way to down the road segment to the next intersection.

    4. A too-close-intersections special case is called out when two intersections are closer than the sum of the two legs that would reach toward each other on a road segment. In this case, the leg length is 1/2 of the length of the road segment, such that the legs meet in the middle similar to the downtown case.

    5. A no intermediate slivers special case is called out when there is enough length along a linestring to create full length legs but the intermediate length left between them would result in an overly thin polygon. In this case, the legs are extended out so they meet and eliminate the need for the thin, intermediate sliver. The percentage of the ideal length of an intermediate polygon which is deemed "too thin" is a parameter to the algorithm and is currently set to .7.

  3. With each road segment's linestring now having a leg which covers the beginning and the end of the linestring, the remaining, central portion of the line string is deemed the intermediate segment. This segment is divided evenly into n segments such that the segment length is as close to the ideal polygon length as possible. The ideal polygon length is defined as:

    1. Level 1 or 2 streets: 150 feet

    2. Level 3 or 4 streets: 250 feet

    As it is unlikely that the intermediate segment of the road segment's linestring will divide evenly by the ideal intermediate polygon length, the number of intermediate polygon's is adjusted to the nearest integer value which results in polygon lengths closest to the ideal length.

  4. With the entire road network now divided into segments, each segment is buffered out a certain distance. This distance is determined by the street level as follows:

    1. Street levels 1 or 2: 40 feet

    2. Street level 3: 50 feet

    3. Street level 4: 75 feet

    The buffer operation is done using postGIS' ST_Buffer(<input linestring>, 'endcap=flat join=round') such that polygons meet with square ends but roads with dead-ends are given a rounded terminus.

  5. Polygons generated from leg linestrings will overlap in the middle of the intersection. For each intersection, all polygons which are generated from the legs emanating from that particular intersection are unioned together in the GIS sense.

  6. The set of polygons must now be "deoverlapped." In the cases of particularly dense areas of roads and/or when roads come close to each other but do not actually touch, there may be points (GIS sense) which are contained in two or more polygons. Doing this in a way which is most sensical to representing a road network in areal geography is particularly difficult, and I experimented with a process (similar, but not exactly like the diagram shown here) which would use Voronoi diagrams and Delaunay triangles to define the a line which divides the overlap of two areas such that each contributing area receives an approximately equal amount of the area and the dividing line remains centered between the edges of the overlapping area. This worked well in the cases of only two polygons overlapping, but did not produce suitable results in particularly dense areas of roadways. In the interest of time, I settled on using a naïve approach:

While there is at least one pair of overlapping polygons:
    Iterate over each pair:
        Give the common area between the pair to the polygon of larger area
  1. Populate metadata for each polygon keeping track of the road segment in the input road network layer that contributed to each intermediate polygon. For intersections, one must keep an array of road segments which contributed to the legs of an intersection, deduplicate this list, and generate metadata in the form of comma separated lists or similar, depending on the particular metadata.

Last updated