Rotate Polylines based on Existing Polyline Angles

6619
30
Jump to solution
01-14-2019 02:17 PM
AdamThompson3
New Contributor III

Hey Everyone,

Currently what I am trying to do is rotate polylines in certain grid sections to the same orientation of existing polylines in that grid. This seems to be quite complicated as I have looked quite extensively for something like this, but to no success. Currently right now I have implemented a tool that was posted here arcpy - Drawing parallel lines inside polygons (Well Paths) using ArcGIS Desktop? - Geographic Infor...  now this works for me and does what it should... but here is my problem posted below. 

The grid lines that were drawn automatically (yellow) are  horizontal where as I would like them be vertical. If there is a way through arcpy or other tools where I can rotate these lines to be the same direction of polylines that are currently there. This is just one example, this happens many times in different areas. 

Thank you!

30 Replies
AdamThompson3
New Contributor III

Hey Dan, These links and suggestions were super helpful! Ive been able to at least rotate them now and this is the fartheset I have been yet! The only problem I am facing currently is those starting points. For example, If my lines are going vertical but I want them to be horizontal, I need to change that starting point to a different line or else it looks like this. 

Now I believe I have the correct logic on how to fix this problem, but how to put into code is another story haha. I will use a search cursor on the grid shapefile to search for the azimuth angle lines in that grid should be drawn at. I will give ranges after in a If statement saying If row[0] = 90 (for example), I will plot my starting points on the West or East side of the polygon cause then I know they will be drawn horizontally. 

Where I am stuck is distinguishing which side is west, east, north, south on each feature I iterate through, and then assigning that as my line where I plot the first starting points. After that I can do the add geometry, bearing distance and I think I will have solved my problem. 

0 Kudos
AdamThompson3
New Contributor III

To update this*** I was looking it further and it creates Polylines with the shape of the polygon actually instead of a polygon which could make it more troublesome to determine E,W,N,S. 

0 Kudos
RandyBurton
MVP Alum

Here's some code that I have been experimenting with that may give you some ideas.  It takes a polygon feature class and creates a layer of points marking each polygon's centroid.  It also creates a line through the centroid at a given azimuth.

polygons

From here, you need to add additional parallel lines and clip them to the polygon.

import arcpy
import math

def draw_line(point, distance, bearing):
    angle = 90 - bearing
    bearing = math.radians(bearing)
    angle = math.radians(angle)
    cosa = math.cos(angle)
    cosb = math.cos(bearing)
    x1, y1 = \
            (point[0] + (distance * cosa), point[1] + (distance * cosb))
    x2, y2 = \
            (point[0] - (distance * cosa), point[1] - (distance * cosb))
    return [[x1, y1], [x2, y2]]

polyFC = "poly_line" # the polygon feature layer
azimuth = 347

desc = arcpy.Describe(polyFC)
SR = desc.spatialReference
arcpy.env.overwriteOutput = True
arcpy.env.outputCoordinateSystem = SR

points = []
lines = []

with arcpy.da.SearchCursor(polyFC,['SHAPE@']) as cursor:
    for row in cursor:
        centroid = row[0].centroid
        points.append(arcpy.PointGeometry(centroid))
        dist = 0
        for part in row[0]:
            for pnt in part:
                cent_vert_dist = arcpy.PointGeometry(pnt).distanceTo(centroid)
                if cent_vert_dist > dist:
                    dist = cent_vert_dist
                    # far_point = arcpy.PointGeometry(pnt)
        # points.append(far_point)

        feature_info = [ draw_line((centroid.X, centroid.Y), dist, azimuth) ]
        for feature in feature_info:
            lines.append(
                arcpy.Polyline(
                    arcpy.Array([arcpy.Point(*coords) for coords in feature])))

arcpy.CopyFeatures_management(points,'in_memory\points')
arcpy.CopyFeatures_management(lines,'in_memory\lines')
AdamThompson3
New Contributor III

Hey Randy, Awesome script!! I am wondering now if this might be easier to implement then my previous one, or try and incorporate pieces of both. If I could keep the option parameter of spacing between lines somewhere that would be ideal. This is awesome though, I did not even think of drawing from a points centroid. 

0 Kudos
RandyBurton
MVP Alum

Just some thoughts...

Distance is measured in the units of the spatial reference so you may need to do some conversion.  Depending upon false northing value in the spatial reference, you may wish to adjust your azimuth setting. 

For distance between lines, you would need to calculate an x value offset.  With the desired distance being one side of a right triangle that is perpendicular to the line, you would use the hypotenuse value as an x offset.  Adding/subtracting this value from the x value at the ends of the first line should provide parallel lines at the proper distance 

If you have an odd number of lines, you can draw the first line through the centroid.  If you want an even number of lines, use half the x offset value to move the first line to the right or left of the centroid and then add the rest of your lines.

Hope this helps.

AdamThompson3
New Contributor III

Randy this helps a lot, awesome script! I am tweaking it just a bit where instead of one singular azimuth to go off of, I would like to pull my azimuth value from a field within the polygon shapefile. I have been attempting to use a search cursor to look on that field and then say row=azimuth, but have not been successful! What I get is this... 

Here is the portion of code I tweaked; 

Perhaps my syntax is a bit wonky somewhere. Thank you again for everything

Also This is what I am trying to pull as my azimuth value 

each shape it iterates through should draw lines based on this value. 

0 Kudos
RandyBurton
MVP Alum

You need the geometry field (SHAPE@) in the search cursor for the centroid.

Untested, but try something like (note code changes in rows 2 and 6):

# ... 
with arcpy.da.SearchCursor(polyFC,['SHAPE@', 'AVGAzimuth']) as cursor:
    for row in cursor:
        centroid = row[0].centroid
        points.append(arcpy.PointGeometry(centroid))
        azimuth = row[1]
        dist = 0
        for part in row[0]:
# ...‍‍‍‍‍‍‍‍‍
AdamThompson3
New Contributor III

Yup that worked perfectly! I really can't thank you guys enough for all this help, still a beginner id say in this world and learn so much from individuals such as yourself! Thank you very much. Next steps now are I just have to copy the lines on both sides and try and figuring out the spacing with the logic you provided! 

Thank you again!

0 Kudos
DanPatterson_Retired
MVP Emeritus

interesting problem... if anyone needs to start lines from scratch, I documented an alternate line forming process to cover some of these ideas and some other thoughts

/blogs/dan_patterson/2019/01/17/transect-lines-parallel-lines-offset-lines 

AdamThompson3
New Contributor III

Hey Dan, wow this awesome!! Pretty sure exactly the last step I need, but I am struggling a bit with integrating it into my current script. So currently I am iterating through each grid shape, finding the center point and drawing a line based on a azimuth that is given to me. That is all good, now I would like to take that current line and replicate it X number of times and a X distance from it.

I see that your scipt indeed does this! I am not sure If I understand all the logic and code that is happening, there is a lot going on and I am not sure If I am to use all of it or only pieces. Given that I have already created a line, can I Incorporate some portions of your script where I am still iterating through each grid creating a line and replicating it. So it shows something like this (replicates created manually)

I am essentially trying to keep it all within one loop and trying to incorporate your code in this area of mine; 

Thank you again for all the help, I am still looking at your code and trying to understand how I can implement it into mine. I am using the script Randy provided above with just a slight modification where I am grabbing the azimuth attribute from the table of the grid shapefile. 

0 Kudos