20

How can I check if a point is below a line or not ?

I've the following data:

Line [ {x1,y1}, {x2,y2} ]
Points {xA,yA}, {xB,yB} ...

I need to write a small algorithm in python to detect points on one side and the other side of the line.

thanks

gameboy90
  • 303
  • 3
  • 9
aneuryzm
  • 63,052
  • 100
  • 273
  • 488

3 Answers3

19

You could try using a cross product -- http://en.wikipedia.org/wiki/Cross_product.

v1 = (x2-x1, y2-y1)   # Vector 1
v2 = (x2-xA, y2-yA)   # Vector 2
xp = v1[0]*v2[1] - v1[1]*v2[0]  # Cross product (magnitude)
if xp > 0:
    print('on one side')
elif xp < 0:
    print('on the other')
else:
    print('on the same line!')

You'd need to calibrate what each side is. If you want it to be "below" or "above" you need to ensure the points on the line are sorted horizontally.

I haven't tested this.

Edit I initially put in the dot product formula. :o

Edit 2 D'oh, I was putting the coordinates into a set instead of a tuple. Using namedtuple('point', 'x y') for the vectors is nice if you're running a reasonably modern version of Python.

Luckily I found Calculating a 2D Vector's Cross Product.

Celsiuss
  • 895
  • 7
  • 19
Edmund
  • 10,533
  • 3
  • 39
  • 57
  • 1
    What if xp is 0.00000000000000000000000000001 (possibly due to floating point representation)? Isn't it possible that this point is actually on the line then? (probably want to compare to some epsilon, rather than 0.0) – PaulMcG Oct 01 '10 at 16:27
  • Good point! Though I don't know how you'd find the most appropriate epsilon value. – Edmund Oct 01 '10 at 23:44
  • cos(π/2) should evaluate to 0, but `math.cos(math.pi/2)` on my system gives `6.1230317691118863e-017`, so I would guess an epsilon in `1e-15` or `1e-16` range would be about right. (Put it into your own constant `EPS` so that you can easily tune it by adjusting just in one place instead of everywhere you do floating point comparisons.) – PaulMcG Oct 07 '10 at 07:50
  • Or if you are using Python 3.x, you can use unicode ε as your variable name for epsilon. – PaulMcG Oct 07 '10 at 08:09
  • Hi. I was trying to run the code. But at one point, I got an error. The error message says that 'set object has no attribute x'. That is, it cannot access the x and y element of vector. Is there any solution? – Kapilfreeman Oct 30 '19 at 20:53
  • Hi @Kapilfreeman, I made the mistake of using sets instead of tuples. Hopefully the example is fixed now! – Edmund Oct 31 '19 at 22:05
2

You could try using a cross product, but the trick is how to choose the point to form a vector, here I choose the closest point from points, assume I got pointA(you can fairly loop points to calculate to distance from loop point to Line):

v1 = {x2-x1, y2-y1}   # Vector 1
v2 = {xA-x1, yA-y1}   # Vector 2
cross_product = v1.x*v2.y - v1.y*v2.x
if cross_product > 0:
    print 'pointA is on the counter-clockwise side of line'
elif cross_product < 0:
    print 'pointA is on the clockwise side of line'
else:
    print 'pointA is exactly on the line'
Community
  • 1
  • 1
gameboy90
  • 303
  • 3
  • 9
0

Lets say you've given 2 points A, B and you want to know in which halfplane a third point C lies. The terms "below" and "above" as criteria are very vague, so you need a reference point, for example the origin. Just be sure this reference point is not collinear with A and B.

What you have now is a triangle (A, B, C). Using the determinant you can calculate the signed area (see here, or here). The only interesting thing here is to remember the sign.

Next step: for a given point D calculate the signed area of the triangle (A, B, D). If the result has the same sign as the area of your reference triangle -> C and D are on the same side of (A, B). If the sign differs -> C and D lie on opposite sides of the line. If the area of (A, B, D) is 0 then A, B and D are collinear. Note: use the Python builtin cmp to compare the triangle areas.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
atomocopter
  • 948
  • 10
  • 20