I have a set of points. I want to separate them into 2 distinct sets. To do this, I choose two points (a and b) and draw an imaginary line between them. Now I want to have all points that are left from this line in one set and those that are right from this line in the other set.
How can I tell for any given point z whether it is in the left or in the right set? I tried to calculate the angle between a-z-b – angles smaller than 180 are on the right hand side, greater than 180 on the left hand side – but because of the definition of ArcCos, the calculated angles are always smaller than 180°. Is there a formula to calculate angles greater than 180° (or any other formula to chose right or left side)?
Try this code which makes use of a cross product:
Where a = line point 1; b = line point 2; c = point to check against.
If the formula is equal to 0, the points are colinear.
If the line is horizontal, then this returns true if the point is above the line.
First check if you have a vertical line:
Then, calculate the slope:
m = (y2-y1)/(x2-x1)
Then, create an equation of the line using point slope form:
y - y1 = m*(x-x1) + y1
. For the sake of my explanation, simplify it to slope-intercept form (not necessary in your algorithm):y = mx+b
.Now plug in
(x3, y3)
forx
andy
. Here is some pseudocode detailing what should happen:Here's a version, again using the cross product logic, written in Clojure.
Example usage:
Which is to say that the point (0, 10) is to the left of the line determined by (-3, -1) and (3, 1).
NOTE: This implementation solves a problem that none of the others (so far) does! Order matters when giving the points that determine the line. I.e., it's a "directed line", in a certain sense. So with the above code, this invocation also produces the result of
true
:That's because of this snippet of code:
Finally, as with the other cross product based solutions, this solution returns a boolean, and does not give a third result for collinearity. But it will give a result that makes sense, e.g.:
I implemented this in java and ran a unit test (source below). None of the above solutions work. This code passes the unit test. If anyone finds a unit test that does not pass, please let me know.
Code: NOTE:
nearlyEqual(double,double)
returns true if the two numbers are very close.Here's the unit test:
Use the sign of the determinant of vectors
(AB,AM)
, whereM(X,Y)
is the query point:It is
0
on the line, and+1
on one side,-1
on the other side.The vector
(y1 - y2, x2 - x1)
is perpendicular to the line, and always pointing right (or always pointing left, if you plane orientation is different from mine).You can then compute the dot product of that vector and
(x3 - x1, y3 - y1)
to determine if the point lies on the same side of the line as the perpendicular vector (dot product >0
) or not.