# Lengthening 1st and last point of GeoJSON LineString containing lat/lon coordinates maintaining angle and direction

I am fairly new to the gis topic and may not be using correct terms.

I have a GeoJSON LineString containing lat/lon coordinates. I would like to lengthen the 1st coordinate and the last coordinate by a certain distance, maintaining the angle and direction (heading?) between the 1st and 2nd coordinate respectively the "next to last" and last element.

in other words, lengthen the line between the 1st and 2nd coordinate respectively lengthen the line between the "next to last" and last coordinate. as a result, the coordinate of the 1st and last element changes.

The following is a simplified LineString:

``````from shapely.geometry import LineString

line_orig=LineString([(4,5),(6,7),(8,7),(10,8),(12,8),(13,7)])
``````

The result would be this one if the ends are lengthened by 1:

``````line_edited=LineString([(3.29,4.29),(6,7),(8,7),(10,8),(12,8),(13.71,7.29)])
``````

not sure how to approach this. I would prefer a python library handling this server side. so far I was not successful finding something.

I would like to avoid calculating "manually" like

``````import math

# first line coords
firstLine_x1 = 4
firstLine_y1 = 5
firstLine_x2 = 6
firstLine_y2 = 7

# last line coords
lastLine_x1 = 12
lastLine_y1 = 8
lastLine_x2 = 13
lastLine_y2 = 7

def lineDirection(start_x1, start_y1, end_x2, end_y2):
return math.atan2(end_y2 - start_y1, end_x2 - start_x1) * 180 / math.pi

firstLine_angle = lineDirection(firstLine_x2, firstLine_y2, firstLine_x1, firstLine_y1)
lastLine_angle = lineDirection(lastLine_x1, lastLine_y1, lastLine_x2, lastLine_y2)

print(firstLine_angle, lastLine_angle)
``````
• Please decide whether you are trying to do this using Python or JavaScript, and include a code snippet to illustrate what you have tried with that choice.
– PolyGeo
Oct 28 '16 at 23:26
• ok. tried to add some info. I prefer to handle it server side with Python but I'm ok to tackle it client side with JavaScript if there is a handy library.
– udo
Oct 29 '16 at 9:19

You have also more classical solutions

1) Trigonometry

``````import math
from shapely.geometry import Point, LineString
length = 1
line_orig=LineString([(4,5),(6,7),(8,7),(10,8),(12,8),(13,7)])
orig = list(line_orig.coords)[:2]
print orig
[(4.0, 5.0), (6.0, 7.0)]
end = list(line_orig.coords)[-2:]
print end
[(12.0, 8.0), (13.0, 7.0)]
def polar(x1,x2,y1,y2):
az = math.atan2(x1 - x2, y1-y2)
sina = math.sin(az)
cosa = math.cos(az)
return sina, cosa
sina,cosa = polar(orig, orig, orig,orig)
print Point(orig+(length*sina), orig+(length*cosa))
POINT (3.292893218813453 4.292893218813452)
sinb,cosb = polar(end,end, end,end)
print Point(end +(longueur*sinb), end+(longueur*cosb))
POINT (13.70710678118655 6.292893218813452)
``````

2) With affine

``````from affine import Affine
sina,cosa = polar(orig, orig, orig,orig)
fwd = Affine.translation(sina*length, cosa*length)
first = fwd * orig
sinb,cosb = polar(end,end, end,end)
fwd = Affine.translation(sinb*length, cosb*length)
last =fwd * (end)
``````

3) result

``````line_edited=list(line_orig.coords)[1:-1]
line_edited.insert(0,first)
line_edited.append(last)
print line_edited
[(3.2928932188134525, 4.292893218813452), (6.0, 7.0), (8.0, 7.0), (10.0, 8.0), (12.0, 8.0), (13.707106781186548, 6.292893218813452)]
``````

Python has the ability to process cartesian coordinates directly with complex number support. We can also convert directly to polar coordinates to give an angle and distance.

``````import cmath

# x2 and y2 are the first or last point
# x1 and y1 are adjacent to x2,y2

def lineDirection (x1, y1, x2, y2, dist):
# calculate the x,y change between the points
difference = complex(x2,y2) - complex(x1,y1)

# convert the difference to polar coordinates
(distance, angle) = cmath.polar(difference)

#calculate a new x,y change based on the angle and desired distance
displacement = cmath.rect(dist, angle)

# add the displacement to the start and end point
xy3 = displacement + complex(x2,y2)

x3 = xy3.real
y3 = xy3.imag

return (x3,y3)

print lineDirection(6,7, 4,5,  1)  # returns 3.29, 4.29
``````