3

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)
2
  • 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
3

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[0][0], orig[1][0], orig[0][1],orig[1][1])
print Point(orig[0][0]+(length*sina), orig[0][1]+(length*cosa))
POINT (3.292893218813453 4.292893218813452)
sinb,cosb = polar(end[1][0],end[0][0], end[1][1],end[0][1])
print Point(end[1][0] +(longueur*sinb), end[1][1]+(longueur*cosb))
POINT (13.70710678118655 6.292893218813452)

2) With affine

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

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)]
2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.