Is it possible to select streets based on their direction? I am actually missing the N or S prefix for my street names, so I cannot filter based on that criteria. I am hoping to select these streets to run a field calculator that enters the prefix direction.
Any help would be greatly appreciated!
In theory, if one has an Advanced license, one could do this:
1. Use Feature Vertices to Points with the Both Ends option to create end points for each street. Feature Vertices To Points—Data Management toolbox | ArcGIS Desktop
2. Copy the Feature Class.
3. Use Generate Near Table, using the original and the copy, and with the ANGLE option on
4. Cull the data down in the resulting output table to the original end points and check the angle of matching points (the output will be a comparison of all points to all points, so will be many records, of which only a few are actually needed).
A near angle measures from the x-axis (horizontal axis) to the direction of the line connecting an input feature to its nearest feature at their closest locations, and it is within the range of 0 to 180 or 0 to -180 decimal degrees - 0 to the east, 90 to the north, 180 (-180°) to the west, and -90 to the south.
In other words, the measuring starts at zero with East, then increases as one goes counter-clockwise to North, producing positive angles. So North is 90 degrees, increasing to a maximum of 180 degrees at West.
Starting at East and heading to South (clockwise), the angle values are increasingly negative. East is zero and South is -90, and West is at -180.
As a result, to query out North for your streets, try checking for an angle between 45 and 135. For South, check between -45 to -135.
Caveats:
This assumes the street data is set up in a way that allows checking of whole streets. If a street is segmented out into multiple pieces, a Dissolve or other aggregation method may be needed to combine the pieces.
Also, I suspect there probably is a refined way to do all this in Python. I'll leave suggestions on how to do that to the many Python guru's we have here on GeoNet.
Chris Donohue, GISP
EDIT: cleaned up some wording for clarity
This is a great work-around! I will try this out and let you know how it goes. Thank you!
Tagging several people who might already have solutions to something like this.
I just have a bunch of field calculator defs that work with angles, that may be useful
I find that it very useful to calculate the X and Y coordinates of both ends of my network lines into four separate double fields stored in the line attributes (FROM_X, FROM_Y, TO_X, TO_Y). You can easily calculate the values for these fields using the geometry calculator. I automatically maintain these fields whenever I edit the line geometry using the Attribute Assistant X_Coordinate and Y_Coordinate methods with the S (start) or E (end) value options (only works for geodatabases, not shapefiles). As Chris Donohue, GISP, said, if your network is highly segmented and you want the overall trend of a complete road you would need to use the Dissolve tool, Create Route tool or some other aggregating tool first to get those trends.
Once you have these coordinate fields it is relatively straight forward to select the lines that are trending more north/south than east/west provided you are using a projected coordinate system (which expresses coordinates in linear units like meters or feet) and your lines are not very sinuous (curvy) or multipart lines with large gaps or self intersections. You can do a selection like:
To find north trending lines:
ABS(TO_X - FROM_X) < ABS(TO_Y - FROM_Y) AND FROM_Y < TO_Y
To find south trending lines:
ABS(TO_X - FROM_X) < ABS(TO_Y - FROM_Y) AND FROM_Y > TO_Y
If you are concerned that some of your roads are very curvy you can separate those roads as long as you have a length field (for geodatabases this is built-in, but for shapefiles you have to calculate this using the geometry calculator or a python calculation). Assuming the linear units of the length and coordinates are the same kind, you can exclude sinuous roads by adding this clause to the selection expressions above (this SQL works for a File Geodatabase and shapefile and may not work for Personal Geodatabases and enterprise geodatabases like SQL Server and Oracle):
AND Shape_Length / Power((Power(From_X - To_X, 2) + Power(From_Y - To_Y, 2)), 0.5) <= 1.5
Change the above expression to > 1.5 to find roads that are considered meandering. You can adjust the sinuosity factor number (1.5) to higher numbers to tolerate more curviness, or to lower numbers to tolerate less curviness. A perfectly straight singlepart line has a sinuosity factor of 1. Closed lines (lines that start and end at the same point) have an infinite or divide by zero error sinuosity factor. Multipart lines with large gaps between parts can have a sinuosity factor that is less than 1.
Is there a good way to use expressions (like you have above) for east/west roads?
forgot the link.. here is one, you can substitute the firstpoint last point with a variety of other combinations. for example, you can formulate a
You get the drift.
I have similar functions that enable you to feed in the whole geometry and calculate the Interpoint angles from which you can determine average, dominant or other directions types. The numpy import is only done once. The fromNorth allows you to do angles as they relate to the x-axis or from North, depending on what you want... fromNorth=True would be what you would set line_dir to
import numpy as np
def line_dir(orig, dest, fromNorth=False):
"""Direction of a line given 2 points
: orig, dest - two points representing the start and end of a line.
: fromNorth - True or False gives angle relative to x-axis)
:
"""
orig = np.asarray(orig)
dest = np.asarray(dest)
dx, dy = dest - orig
ang = np.degrees(np.arctan2(dy, dx))
if fromNorth:
ang = np.mod((450.0 - ang), 360.)
return ang
# Expression box
line_dir(!shape.firstPoint!, !shape.lastPoint!)