How can you determine a point is between two other points on a line segment?
Check if the cross product of (b-a) and (c-a) is 0, as tells Darius Bacon, tells you if the points a, b and c are aligned.
But, as you want to know if c is between a and b, you also have to check that the dot product of (b-a) and (c-a) is positive and is less than the square of the distance between a and b.
In non-optimized pseudocode:
def isBetween(a, b, c):
crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y)
# compare versus epsilon for floating point values, or != 0 if using integers
if abs(crossproduct) > epsilon:
return False
dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y)
if dotproduct < 0:
return False
squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y)
if dotproduct > squaredlengthba:
return False
return True
Determine if a point is between 2 other points on a line
Assuming that point1 and point2 are different, first you check whether the point lies on the line. For that you simply need a "cross-product" of vectors point1 -> currPoint and point1 -> point2.
dxc = currPoint.x - point1.x;
dyc = currPoint.y - point1.y;
dxl = point2.x - point1.x;
dyl = point2.y - point1.y;
cross = dxc * dyl - dyc * dxl;
Your point lies on the line if and only if cross is equal to zero.
if (cross != 0)
return false;
Now, as you know that the point does lie on the line, it is time to check whether it lies between the original points. This can be easily done by comparing the x coordinates, if the line is "more horizontal than vertical", or y coordinates otherwise
if (abs(dxl) >= abs(dyl))
return dxl > 0 ?
point1.x <= currPoint.x && currPoint.x <= point2.x :
point2.x <= currPoint.x && currPoint.x <= point1.x;
else
return dyl > 0 ?
point1.y <= currPoint.y && currPoint.y <= point2.y :
point2.y <= currPoint.y && currPoint.y <= point1.y;
Note that the above algorithm if entirely integral if the input data is integral, i.e. it requires no floating-point calculations for integer input. Beware of potential overflow when calculating cross though.
P.S. This algorithm is absolutely precise, meaning that it will reject points that lie very close to the line but not precisely on the line. Sometimes this is not what's needed. But that's a different story.
Test if a point is approximately on a line segment formed by two other points
Here is the final javascript function I am now using.
The first part is using the distance formula as explained in Ashley Tharp's answer, we first test if c
is inside a pre-defined distance (tolerance
) of a line going through a
and b
.
The second part is taken from Cyrille Ka' answer from a similar question.
Then, to know if
c
is betweena
andb
, you also have to check
that the dot product of(b-a)
and(c-a)
is positive and is less
than the square of the distance betweena
andb
.
// a and b are vertices of the segment AB and c is the tested point (here from a mouseclick event (e))
var a={}, b={}, c={};
a.x = 100;
a.y = 100;
b.x = 200;
b.y = 200;
c.x = e.screenX
c.y = e.screeny
console.log(isBetween(a, b, c, 5));
function isBetween(a, b, c, tolerance) {
//test if the point c is inside a pre-defined distance (tolerance) from the line
var distance = Math.abs((c.y - b.y)*a.x - (c.x - b.x)*a.y + c.x*b.y - c.y*b.x) / Math.sqrt(Math.pow((c.y-b.y),2) + Math.pow((c.x-b.x),2));
if (distance > tolerance) { return false; }
//test if the point c is between a and b
var dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y)*(b.y - a.y);
if (dotproduct < 0) { return false; }
var squaredlengthba = (b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y);
if (dotproduct > squaredlengthba) { return false; }
return true;
};
How to check if a point is between two other points, but not limited to be aligned on a straight line?
Assuming we're on a plane and not a sphere, even though you mentioned lattitude/longitude...
A is "between" B and C if angle ∠ABC and angle ∠ACB are both less than or equal to ninety degrees.
Handily, we don't even need trigonometry to detect this; an angle ∠PQR is greater than ninety degrees iff PQ^2 + QR^2 < QR^2.
def lies_between(A,B,C):
a = distance(B,C)
b = distance(C,A)
c = distance(A,B)
return a**2 + b**2 >= c**2 and a**2 + c**2 >= b**2
def distance(A,B):
return math.sqrt((A.x - B.x)**2 + (A.y - B.y)**2)
(Where **
is the exponentiation operator.)
How to check if a point lies on a line between 2 other points
Assuming that point1
and point2
are different, first you check whether the point lies on the line. For that you simply need a "cross-product" of vectors point1 -> currPoint
and point1 -> point2
.
dxc = currPoint.x - point1.x;
dyc = currPoint.y - point1.y;
dxl = point2.x - point1.x;
dyl = point2.y - point1.y;
cross = dxc * dyl - dyc * dxl;
Your point lies on the line if and only if cross
is equal to zero.
if (cross != 0)
return false;
Now, as you know that the point does lie on the line, it is time to check whether it lies between the original points. This can be easily done by comparing the x
coordinates, if the line is "more horizontal than vertical", or y
coordinates otherwise
if (abs(dxl) >= abs(dyl))
return dxl > 0 ?
point1.x <= currPoint.x && currPoint.x <= point2.x :
point2.x <= currPoint.x && currPoint.x <= point1.x;
else
return dyl > 0 ?
point1.y <= currPoint.y && currPoint.y <= point2.y :
point2.y <= currPoint.y && currPoint.y <= point1.y;
Note that the above algorithm if entirely integral if the input data is integral, i.e. it requires no floating-point calculations for integer input. Beware of potential overflow when calculating cross
though.
P.S. This algorithm is absolutely precise, meaning that it will reject points that lie very close to the line but not precisely on the line. Sometimes this is not what's needed. But that's a different story.
Find if point lies on line segment
If the point is on the line then:
(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1) = (z - z1) / (z2 - z1)
Calculate all three values, and if they are the same (to some degree of tolerance), your point is on the line.
To test if the point is in the segment, not just on the line, you can check that
x1 < x < x2, assuming x1 < x2, or
y1 < y < y2, assuming y1 < y2, or
z1 < z < z2, assuming z1 < z2
How can I determine if a point is on a line between two other points in 3d in Lua (or other language)?
If you know that the points lie on a single line, you may just calculate a dot product, and if 0 ≤ 〈AB, AP〉 ≤ 〈AB, AB〉, then P is between A and B. But note that if P is not exactly on the line, this method may give strange results. But it should be the fastest.
You may also want to calculate 2 values, distance from P to AB and (orthogonal) projection of AP onto AB. The latter is AP_AB = 〈AP, AB〉 / 〈AB, AB〉 (in AB units, so that if AP and AB are collinear, AP = AB * AP_AB), and the former is ρ(P, AB) = ρ(AP, AB * AP_AB) = |AP - AB * AP_AB|. So, if the ρ(P, AB) is small, you decide that if 0 ≤ AP_AB ≤ 1, then P is between A and B
finding point on a line which is equidistant from 2 other points
TL;DR. The solution is at the bottom.
Alright, so let's say these are our parameters:
x0 and x1, that describe the line.
a and b, the two points.
Where
x0 = [x0, y0, z0]
x1 = [x1, y1, z1]
a = [xa, ya, za]
b = [xb, yb, zb]
δ = [δx, δy, δz] = (x1 - x0)
Then our description of the line can be seen as a parametric function:
l(λ) = x0 + λ*(x1 - x0)
So we are trying to find a value for λ that satisfies the following equation:
(l(λ) - a)2 = (l(λ) - b)2
(Here I'm cheating with notation a bit, so x2 = x.x)
So expanding everything we get:
(λx1 + (1 - λ)x0 - xa)2 +
(λy1 + (1 - λ)y0 - ya)2 +
(λz1 + (1 - λ)z0 - za)2 =
(λx1 + (1 - λ)x0 - xb)2 +
(λy1 + (1 - λ)y0 - yb)2 +
(λz1 + (1 - λ)z0 - zb)2
Simplifying, we get:
(λδx + x0 - xa)2 +
(λδy + y0 - ya)2 +
(λδz + z0 - za)2 =
(λδx + x0 - xb)2 +
(λδy + y0 - yb)2 +
(λδz + z0 - zb)2
Expanding the brackets and cancelling, we get:
-2δxxaλ + (x0 - xa)2 +
-2δyyaλ + (y0 - ya)2 +
-2δzzaλ + (z0 - za)2 =
-2δxxbλ + (x0 - xb)2 +
-2δyybλ + (y0 - yb)2 +
-2δzzbλ + (z0 - zb)2
Which we can simplify further into some nice neat vector operations:
2λδ.(xb - xa) =
(x0 - xb)2 -
(x0 - xa)2
Which is pretty simple to rearrange to get a linear equation in λ with one unique solution.
Related Topics
Cs50: Like Operator, Variable Substitution with % Expansion
How to Color Python Logging Output
How to Install 2 Anacondas (Python 2 and 3) on MAC Os
Reimport a Module While Interactive
Why Are There No ++ and -- Operators in Python
How to Dynamically Create Derived Classes from a Base Class
How to Sum Values in a Column That Match a Given Condition Using Pandas
How to Filter Rows in Pandas by Regex
Scrolling to Element Using Webdriver
Flask SQLalchemy Query, Specify Column Names
How to Use 'Else' in a List Comprehension
How to Install Pycrypto on Windows
How to Do Multiple Arguments to Map Function Where One Remains the Same
Convert to Binary and Keep Leading Zeros
How to Sort Objects by Multiple Keys
Transpose Nested List in Python
Seeing Escape Characters When Pressing the Arrow Keys in Python Shell