0

Given two lines of which we know the starting XY points and intersecting point, I need to find which line is left and which line is right. The lines are always crossing and can be turned in any direction. Here are 4 possible scenarios as an image where A is always on the left line:

enter image description here

Below are the same four scenarios as data, where every scenario has two crossing lines. Each line has a start point (x, y) and an end (x, y) point. In the scenarios below, the starting point of A is always on the left of the starting point B and therefore lineA is on the left of lineB:

line_A1 = ((1, 1), (0, 0))
line_B1 = ((0, 1), (1, 0))

line_A2 = ((0, 1), (1, 0))
line_B2 = ((0, 0), (1, 1))

line_A3 = ((0, 0), (1, 1))
line_B3 = ((1, 0), (0, 1))

line_A4 = ((1, 0), (0, 1))
line_B4 = ((1, 1), (0, 0))

middlepoint_C = (0.5, 0.5) #The middle point in all 4 scenarios is (0.5, 0.5)

How can we determine left and right side of the crossing lines in the four scenarios above?

Preference for solution would be with built in Python modules or shapely, but all solutions are welcome since we are kinda stuck.

4
  • 1
    a) Are the lines always a single leg/segment? b) Does the right/left distinction always only count for the part before the intersection or why is a always left in the examples above? c) Can they have the same origin (which would be the intersection then)? Commented Nov 16, 2020 at 20:38
  • Thanks for the good questions. a) Yes, the lines are always a single leg/segment. b) The right/left distinction counts for the whole line, but is based on the right/left distinction of the two initial XY points (A and B). If we know the right/left distinction of the XY points (A and B), then we know the right/left distinction of the lines aswell. c) The two lines can never have same origin or destination.
    – Davma
    Commented Nov 16, 2020 at 20:43
  • I think it may be done with azimuths (there must be implementations of postgis's st_azimuth in python), departing from the intersection (st_intersection returns a point), in the 2nd, 3rd and 4th case azimuth for A would be larger than B, in the first case, azimuth for A is shorter but the difference between the two azimuths is greater than 180
    – Elio Diaz
    Commented Nov 16, 2020 at 20:55
  • Someone gave downvotes to this question. It would be nice with downvotes to know why this is not a good question? Then we can improve this question
    – Davma
    Commented Nov 23, 2020 at 12:14

3 Answers 3

3

Consider using the cross product approach as discussed here. Pure mathematical approach that does not rely on any third party module.

I would take the start point and test against the line. I think this code assumes the line is a simple line composed of 2 vertices and not a polyline.

2

Here is an approach using Postgis, it shouldn't be difficult to replicate in Python, code finds the azimuths from the intersection to the starting points, if it geom A's azimuth is greater than geom B's and its difference (azimuth A - azimuth B) is not greater than 1pi (180 degrees turns the direction to the opposite, to take into account cases where startpoints fall both sides close to the north), left will be A.

WITH 
  tbla AS (select st_geomfromtext('LINESTRING(1 1, 0 0)',4326) as A, st_geomfromtext('LINESTRING(0 1, 1 0)',4326) as B), 
  tblb as (select st_astext(a) as a,st_astext(b) as b, st_astext(st_intersection(a,b)) as aib, st_azimuth(st_intersection(a,b), st_startpoint(a)) as za, 
  st_azimuth(st_intersection(a,b), st_startpoint(b)) as zb from tbla) 
select a, b, aib, za, zb, 
case when za > zb and za-zb < 3.14 then 'left is a' 
     when zb > za and zb-za < 3.14 then 'left is b' 
     when za > zb and za-zb > 3.14 then 'left is b' 
     else 'left is a'  end direction from tblb;
          a          |          b          |      aib       |        za         |        zb        | direction 
---------------------+---------------------+----------------+-------------------+------------------+-----------
 LINESTRING(1 1,0 0) | LINESTRING(0 1,1 0) | POINT(0.5 0.5) | 0.785398163397448 | 5.49778714378214 | left is a
2
  • Thanks for the answer Elio! I'll try the solution in Python and share code here
    – Davma
    Commented Nov 17, 2020 at 8:12
  • I'm curious to see if it will work in all your cases, not just those you presented in here; besides that, you have to find first the crossing lines, which shouldn't either be difficult. I use python also -and R, maybe better than postgis, but i was not sure these functions were in python.
    – Elio Diaz
    Commented Nov 17, 2020 at 16:18
2

Here is working code example in Python based on great answer of Elio in Postgis.

from shapely.ops import LineString, Point
import math

def calc_azimuth(point1, point2):
  """Calculate azimuth in radians between 2 shapely points."""
  angle = math.atan2(point2.x - point1.x, point2.y - point1.y)
  return angle

A4 = Point(2, 0)
B4 = Point(2, 1)
C4 = Point(1, 0.5)
geomA = LineString([A4, C4])
geomB = LineString([B4, C4])
azimuthA = calc_azimuth(Point(geomA.coords[0]), geomC)
azimuthB = calc_azimuth(Point(geomB.coords[0]), geomC)
if (azimuthA > azimuthB) and ((azimuthA - azimuthB) < math.pi):
  print('1: Left is A')
elif (azimuthB > azimuthA) and ((azimuthB - azimuthA) < math.pi):
  print('2: Left is B')
elif (azimuthA > azimuthB) and ((azimuthA - azimuthB) > math.pi):
  print('3: Left is B')
else:
  print('4: Left is A')
2
  • 1
    Hi, I built the left_is into a function and changed 3.14 for math.pi and added a case when geoms don't intersect. I noticed in your example the lines have a common ending (C4)point, is it also a possible case?
    – Elio Diaz
    Commented Nov 18, 2020 at 14:50
  • Uhm the lines normally don't have a common ending, but they do have a common point that intersects. For the determination of left and right it does not matter in this case if the line ends at endpoint of line or ends at intersection point. Good suggestion to replace 3.14 with math.pi :) The geometries should always intersect in my example.
    – Davma
    Commented Nov 18, 2020 at 20:58

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