How to use a line draiwng algorithm with min/max? F# - algorithm

Sorry if this question is not suited for this site, but I don't know where else too ask it. I'm pretty confused, I use min and max I believe correctly. When I move the weapon with arrow keys the line seem to works find when its moving right or down. If anybody knows how to fix it or just put me on the right track I'd greatly appreciate it. For anyone interested I am creating this program for a game which I need a line of sight in for the weapon.
EDIT:
I am trying to achieve a state where I can use w,a,s,d keys to move the C (character) and arrow keys to move W (weapon). Eventually when I add enemies the line between the character and weapon will be used to see if they are in range to be attacked. Like a gun shooting in any direction. But when I move C in it's current state the line does not connect to C anymore. I'm not sure why this is.
open System
let [<Literal>] CharacterN = ConsoleKey.W
let [<Literal>] CharacterE = ConsoleKey.D
let [<Literal>] CharacterS = ConsoleKey.S
let [<Literal>] CharacterW = ConsoleKey.A
let [<Literal>] WeaponN = ConsoleKey.UpArrow
let [<Literal>] WeaponE = ConsoleKey.RightArrow
let [<Literal>] WeaponS = ConsoleKey.DownArrow
let [<Literal>] WeaponW = ConsoleKey.LeftArrow
type Point =
{ X : int
Y : int }
let p1 = { X = 0; Y = 0 }
let p2 = { X = 10; Y = 10 }
let rec main p1 p2 =
Console.Clear()
let dx = min p1.X p2.X - max p1.X p2.X
let dy = min p1.Y p2.Y - max p1.Y p2.Y
for x in min p1.X p2.X .. max p1.X p2.X do
let y = min p1.X p2.X + dy * (x - min p1.X p2.X) / dx
Console.SetCursorPosition(x, y)
printf "."
Console.SetCursorPosition(p1.X, p1.Y)
printf "C"
Console.SetCursorPosition(p2.X, p2.Y)
printf "W"
match Console.ReadKey().Key with
| CharacterN -> main { X = p1.X; Y = p1.Y - 1 } p2
| CharacterE -> main { X = p1.X + 1; Y = p1.Y } p2
| CharacterS -> main { X = p1.X; Y = p1.Y + 1 } p2
| CharacterW -> main { X = p1.X - 1; Y = p1.Y } p2
| WeaponN -> main p1 { X = p2.X; Y = p2.Y - 1 }
| WeaponE -> main p1 { X = p2.X + 1; Y = p2.Y }
| WeaponS -> main p1 { X = p2.X; Y = p2.Y + 1 }
| WeaponW -> main p1 { X = p2.X - 1; Y = p2.Y }
| _ -> ()
main p1 p2
Console.Read() |> ignore

I believe that are several issues with your code. Probably the most important one is in the logic of the line:
let y = min p1.X p2.X + dy * (x - min p1.X p2.X) / dx
Obviously it should have been something like
y = y0 + (x-x0)*dy/dx
i.e. the first term shuold be something about Y rather than X. Unfortunately with your looping logic it should be the Y of the point that has the smaller X. It is not that easy to say that. IMHO it is easier to fix looping using negative step.
Another naive assumption is that you can always draw a line as having some y for each x. This is obviously not so when dy > dx. Moreover in case of a vertical line when dx is 0, the code will fail. The most most popular Bresenham's line algorithm requires you to handle those cases as explicitly different. Here is a simple implementation that handle those cases:
let drawLine p1 p2 =
let dx = p2.X - p1.X
let dy = p2.Y - p1.Y
if((dx <> 0) || (dy <> 0)) then
if abs(dx) >= abs(dy) then
let step = if (p1.X < p2.X) then 1 else -1
for x in p1.X ..step.. p2.X do
let y = p1.Y + dy * (x - p1.X) / dx
Console.SetCursorPosition(x, y)
printf "."
else
let step = if (p1.Y < p2.Y) then 1 else -1
for y in p1.Y .. step .. p2.Y do
let x = p1.X + dx * (y - p1.Y) / dy
Console.SetCursorPosition(x, y)
printf "."
As for other issues, you probably want to restrict positions of your points to some visible area between 0 and some max value. SetCursorPosition call with a negative value or a value larger than the buffer size will crash your app.

Related

MATLAB: Efficient way to find the feasible region of first-order polynomials x, y with unknown coefficents in [-1, 1]

As in the title, in MATLAB, I need the feasible region (bounds of all feasible solutions) of
x_0 + x_1 e_1 + ... + x_n e_n
and
y_0 + y_1 e_1 + ... + y_n e_n
where all unknown e_i are in the interval [-1, 1]. I would prefer the solution to not depend on non-standard 3rd party functions.
Below is my quick-and-dirty attempt, but the complexity grows O(2^n), where n is the number of e_i. Any thoughts?
x0 = 3;
x = [1; -3; 0];
y0 = -1;
y = [3; -2; 4];
% Get all permutations of noise symbol extremities
terms = size(x, 1);
xx = zeros(2^terms, 1);
yy = zeros(2^terms, 1);
for j = 1:2^terms
e = double(bitget(j - 1, 1:terms))';
e(e == 0) = -1;
xx(j) = x0 + sum(x .* e);
yy(j) = y0 + sum(y .* e);
end
k = convhull(xx, yy);
plot(xx(k), yy(k));
% First generate all possible permutations for [-1, 1] for n terms. This is similar to what you have done but uses a matlab function
all_e = de2bi(0:(2^terms-1), terms).';
all_e(all_e == 0) = -1;
% Multiply corresponding values of x and y with those of e
xx = x0 + arrayfun(#(z) sum(x .* all_e(:, z)), 1:(2^terms));
yy = x0 + arrayfun(#(z) sum(y .* all_e(:, z)), 1:(2^terms));
You can read more about the function de2bi here
A method to find the absolute minimum and maximum bounds is as follows:
max_e = double(x >= 0);
min_e = double(~max_e);
max_e(max_e == 0) = -1;
min_e(min_e == 0) = -1;
absMax = x0 + sum(x .* max_e);
absMin = x0 + sum(x .* min_e);
Similarly you could do for y

Matlab image rotation

I am new to image processing, I have implemented a code for image warping and it works perfectly. I would like to improve the code by using linear interpolation to rotate the image WITHOUT using the built-in function (interp). Here is my code:
close all;
clear all;
img = 'woods.jpg';
input_image =double(imread(img))./255;
H=size(input_image,1);
W=size(input_image,2);
th=pi/4;
s0 = 2;
s1 = 2;
x0 = -W/2;
x1 = -H/2;
T=[1 0 x0 ; ...
0 1 x1 ; ...
0 0 1];
RST = [ (s0*cos(th)) (-s1*sin(th)) ((s0*x0*cos(th))-(s1*x1*sin(th))); ...
(s0*sin(th)) (s1*cos(th)) ((s0*x0*sin(th))+(s1*x1*cos(th))); ...
0 0 1];
M=inv(T)*R;
N = inv(M);
output_image=zeros(H,W,3);
for i=1:W
for j=1:H
x = [i ; j ; 1];
y = N * x;
a = y(1)/y(3);
b = y(2)/y(3);
a = round(a);
b = round(b);
if (a>0 && a<=W && b>0 && b<=H)
output_image(j,i,:)=input_image(b,a,:);
end
end
end
imgshow(output_image);
Check the following solution:
I verified implementation by comparing to Matalb build in function [imwarp][1].
close all;
clear all;
img = 'peppers.png';
input_image =double(imread(img))./255;
H=size(input_image,1); % height
W=size(input_image,2); % width
th=pi/4;
s0 = 2;
s1 = 2;
x0 = -W/2;
x1 = -H/2;
T=[1 0 x0 ; ...
0 1 x1 ; ...
0 0 1];
RST = [ (s0*cos(th)) (-s1*sin(th)) ((s0*x0*cos(th))-(s1*x1*sin(th))); ...
(s0*sin(th)) (s1*cos(th)) ((s0*x0*sin(th))+(s1*x1*cos(th))); ...
0 0 1];
M=inv(T)*RST;
N = inv(M);
output_image=zeros(H,W,3);
for i=1:W
for j=1:H
x = [i ; j ; 1];
y = N * x;
a = y(1)/y(3);
b = y(2)/y(3);
%Nearest neighbor
%a = round(a);
%b = round(b);
x1 = floor(a);
y1 = floor(b);
x2 = x1 + 1;
y2 = y1 + 1;
%Bi-linear interpolation ilsutration:
%Image coordinates style (horizontal index first)
%
%(x1,y1) | (x2,y1)
% | 1-dy
% 1-dx | dx
% ------(a,b)------------
% |
% |
% |
% | dy
% |
% |
%(x1,y2) | (x2,y2)
if ((x1 >= 1) && (y1 >= 1) && (x2 <= W) && (y2 <= H))
%Load 2x2 pixels
i11 = input_image(y1, x1, :); %Top left pixel
i21 = input_image(y2, x1, :); %Bottom left pixel
i12 = input_image(y1, x2, :); %Top right pixel
i22 = input_image(y2, x2, :); %Bottom right pixel
%Interpolation wieghts
dx = x2 - a;
dy = y2 - b;
%Bi-lienar interpolation
output_image(j, i, :) = i11*dx*dy + i21*dx*(1-dy) + i12*(1-dx)*dy + i22*(1-dx)*(1-dy);
end
end
end
imshow(output_image);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Verify implementation by comparing with Matalb build in function imwarp:
tform = affine2d(M');
ref_image = imwarp(input_image, tform, 'OutputView', imref2d(size(input_image)), 'Interp', 'linear');
figure;imshow(ref_image)
figure;imshow(output_image - ref_image)
max_diff = max(abs(output_image(:) - ref_image(:)));
disp(['Maximum difference from imwarp = ', num2str(max_diff)]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Result:
Remark:
I missed the following execelnt post that resizes an image using bilinear interpolation (bilinear interpolation is explained better):
Resize an image with bilinear interpolation without imresize

Finding the intersection of two lines

I have two lines:
y = -1/3x + 4
y = 3x + 85
The intersection is at [24.3, 12.1].
I have a set of coordinates prepared:
points = [[1, 3], [4, 8], [25, 10], ... ]
#y = -1/3x + b
m_regr = -1/3
b_regr = 4
m_perp = 3 #(1 / m_regr * -1)
distances = []
points.each do |pair|
x1 = pair.first
y2 = pair.last
x2 = ((b_perp - b_regr / (m_regr - m_perp))
y2 = ((m_regr * b_perp) / (m_perp * b_regr))/(m_regr - m_perp)
distance = Math.hypot((y2 - y1), (x2 - x1))
distances << distance
end
Is there a gem or some better method for this?
NOTE: THE ABOVE METHOD DOES NOT WORK. See my answer for a solution that works.
What's wrong with using a little math?
If you have:
y = m1 x + b1
y = m2 x + b2
It's a simple system of linear equations.
If you solve them, your intersection is:
x = (b2 - b1)/(m1 - m2)
y = (m1 b2 - m2 b1)/(m1 - m2)
After much suffering and many different tries, I found a simple algebraic method here that not only works but is dramatically simplified.
distance = ((y - mx - b).abs / Math.sqrt(m**2 + 1))
where x and y are the coordinates for the known point.
For Future Googlers:
def solution k, l, m, n, p, q, r, s
intrsc_x1 = m - k
intrsc_y1 = n - l
intrsc_x2 = r - p
intrsc_y2 = s - q
v1 = (-intrsc_y1 * (k - p) + intrsc_x1 * (l - q)) / (-intrsc_x2 * intrsc_y1 + intrsc_x1 * intrsc_y2);
v2 = ( intrsc_x2 * (l - q) - intrsc_y2 * (k - p)) / (-intrsc_x2 * intrsc_y1 + intrsc_x1 * intrsc_y2);
(v1 >= 0 && v1 <= 1 && v2 >= 0 && v2 <= 1) ? true : false
end
The simplest and cleanest way I've found on the internet.

Trilateration and locating the point (x,y,z)

I want to find the coordinate of an unknown node which lie somewhere in the space which has its reference distance away from 3 or more nodes which all of them have known coordinate.
This problem is exactly like Trilateration as described here Trilateration.
However, I don't understand the part about "Preliminary and final computations" (refer to the wikipedia site). I don't get where I could find P1, P2 and P3 just so I can put to those equation?
Thanks
Trilateration is the process of finding the center of the area of intersection of three spheres. The center point and radius of each of the three spheres must be known.
Let's consider your three example centerpoints P1 [-1,1], P2 [1,1], and P3 [-1,-1]. The first requirement is that P1' be at the origin, so let us adjust the points accordingly by adding an offset vector V [1,-1] to all three:
P1' = P1 + V = [0, 0]
P2' = P2 + V = [2, 0]
P3' = P3 + V = [0,-2]
Note: Adjusted points are denoted by the ' (prime) annotation.
P2' must also lie on the x-axis. In this case it already does, so no adjustment is necessary.
We will assume the radius of each sphere to be 2.
Now we have 3 equations (given) and 3 unknowns (X, Y, Z of center-of-intersection point).
Solve for P4'x:
x = (r1^2 - r2^2 + d^2) / 2d //(d,0) are coords of P2'
x = (2^2 - 2^2 + 2^2) / 2*2
x = 1
Solve for P4'y:
y = (r1^2 - r3^2 + i^2 + j^2) / 2j - (i/j)x //(i,j) are coords of P3'
y = (2^2 - 2^2 + 0 + -2^2) / 2*-2 - 0
y = -1
Ignore z for 2D problems.
P4' = [1,-1]
Now we translate back to original coordinate space by subtracting the offset vector V:
P4 = P4' - V = [0,0]
The solution point, P4, lies at the origin as expected.
The second half of the article is describing a method of representing a set of points where P1 is not at the origin or P2 is not on the x-axis such that they fit those constraints. I prefer to think of it instead as a translation, but both methods will result in the same solution.
Edit: Rotating P2' to the x-axis
If P2' does not lie on the x-axis after translating P1 to the origin, we must perform a rotation on the view.
First, let's create some new vectors to use as an example:
P1 = [2,3]
P2 = [3,4]
P3 = [5,2]
Remember, we must first translate P1 to the origin. As always, the offset vector, V, is -P1. In this case, V = [-2,-3]
P1' = P1 + V = [2,3] + [-2,-3] = [0, 0]
P2' = P2 + V = [3,4] + [-2,-3] = [1, 1]
P3' = P3 + V = [5,2] + [-2,-3] = [3,-1]
To determine the angle of rotation, we must find the angle between P2' and [1,0] (the x-axis).
We can use the dot product equality:
A dot B = ||A|| ||B|| cos(theta)
When B is [1,0], this can be simplified: A dot B is always just the X component of A, and ||B|| (the magnitude of B) is always a multiplication by 1, and can therefore be ignored.
We now have Ax = ||A|| cos(theta), which we can rearrange to our final equation:
theta = acos(Ax / ||A||)
or in our case:
theta = acos(P2'x / ||P2'||)
We calculate the magnitude of P2' using ||A|| = sqrt(Ax + Ay + Az)
||P2'|| = sqrt(1 + 1 + 0) = sqrt(2)
Plugging that in we can solve for theta
theta = acos(1 / sqrt(2)) = 45 degrees
Now let's use the rotation matrix to rotate the scene by -45 degrees.
Since P2'y is positive, and the rotation matrix rotates counter-clockwise, we'll use a negative rotation to align P2 to the x-axis (if P2'y is negative, don't negate theta).
R(theta) = [cos(theta) -sin(theta)]
[sin(theta) cos(theta)]
R(-45) = [cos(-45) -sin(-45)]
[sin(-45) cos(-45)]
We'll use double prime notation, '', to denote vectors which have been both translated and rotated.
P1'' = [0,0] (no need to calculate this one)
P2'' = [1 cos(-45) - 1 sin(-45)] = [sqrt(2)] = [1.414]
[1 sin(-45) + 1 cos(-45)] = [0] = [0]
P3'' = [3 cos(-45) - (-1) sin(-45)] = [sqrt(2)] = [ 1.414]
[3 sin(-45) + (-1) cos(-45)] = [-2*sqrt(2)] = [-2.828]
Now you can use P1'', P2'', and P3'' to solve for P4''. Apply the reverse rotation to P4'' to get P4', then the reverse translation to get P4, your center point.
To undo the rotation, multiply P4'' by R(-theta), in this case R(45). To undo the translation, subtract the offset vector V, which is the same as adding P1 (assuming you used -P1 as your V originally).
This is the algorithm I use in a 3D printer firmware. It avoids rotating the coordinate system, but it may not be the best.
There are 2 solutions to the trilateration problem. To get the second one, replace "- sqrtf" by "+ sqrtf" in the quadratic equation solution.
Obviously you can use doubles instead of floats if you have enough processor power and memory.
// Primary parameters
float anchorA[3], anchorB[3], anchorC[3]; // XYZ coordinates of the anchors
// Derived parameters
float Da2, Db2, Dc2;
float Xab, Xbc, Xca;
float Yab, Ybc, Yca;
float Zab, Zbc, Zca;
float P, Q, R, P2, U, A;
...
inline float fsquare(float f) { return f * f; }
...
// Precompute the derived parameters - they don't change unless the anchor positions change.
Da2 = fsquare(anchorA[0]) + fsquare(anchorA[1]) + fsquare(anchorA[2]);
Db2 = fsquare(anchorB[0]) + fsquare(anchorB[1]) + fsquare(anchorB[2]);
Dc2 = fsquare(anchorC[0]) + fsquare(anchorC[1]) + fsquare(anchorC[2]);
Xab = anchorA[0] - anchorB[0];
Xbc = anchorB[0] - anchorC[0];
Xca = anchorC[0] - anchorA[0];
Yab = anchorA[1] - anchorB[1];
Ybc = anchorB[1] - anchorC[1];
Yca = anchorC[1] - anchorA[1];
Zab = anchorB[2] - anchorC[2];
Zbc = anchorB[2] - anchorC[2];
Zca = anchorC[2] - anchorA[2];
P = ( anchorB[0] * Yca
- anchorA[0] * anchorC[1]
+ anchorA[1] * anchorC[0]
- anchorB[1] * Xca
) * 2;
P2 = fsquare(P);
Q = ( anchorB[1] * Zca
- anchorA[1] * anchorC[2]
+ anchorA[2] * anchorC[1]
- anchorB[2] * Yca
) * 2;
R = - ( anchorB[0] * Zca
+ anchorA[0] * anchorC[2]
+ anchorA[2] * anchorC[0]
- anchorB[2] * Xca
) * 2;
U = (anchorA[2] * P2) + (anchorA[0] * Q * P) + (anchorA[1] * R * P);
A = (P2 + fsquare(Q) + fsquare(R)) * 2;
...
// Calculate Cartesian coordinates given the distances to the anchors (La, Lb and Lc)
// First calculate PQRST such that x = (Qz + S)/P, y = (Rz + T)/P.
// P, Q and R depend only on the anchor positions, so they are pre-computed
const float S = - Yab * (fsquare(Lc) - Dc2)
- Yca * (fsquare(Lb) - Db2)
- Ybc * (fsquare(La) - Da2);
const float T = - Xab * (fsquare(Lc) - Dc2)
+ Xca * (fsquare(Lb) - Db2)
+ Xbc * (fsquare(La) - Da2);
// Calculate quadratic equation coefficients
const float halfB = (S * Q) - (R * T) - U;
const float C = fsquare(S) + fsquare(T) + (anchorA[1] * T - anchorA[0] * S) * P * 2 + (Da2 - fsquare(La)) * P2;
// Solve the quadratic equation for z
float z = (- halfB - sqrtf(fsquare(halfB) - A * C))/A;
// Substitute back for X and Y
float x = (Q * z + S)/P;
float y = (R * z + T)/P;
Here are the Wikipedia calculations, presented in an OpenSCAD script, which I think helps to understand the problem in a visual wayand provides an easy way to check that the results are correct. Example output from the script
// Trilateration example
// from Wikipedia
//
// pA, pB and pC are the centres of the spheres
// If necessary the spheres must be translated
// and rotated so that:
// -- all z values are 0
// -- pA is at the origin
pA = [0,0,0];
// -- pB is on the x axis
pB = [10,0,0];
pC = [9,7,0];
// rA , rB and rC are the radii of the spheres
rA = 9;
rB = 5;
rC = 7;
if ( pA != [0,0,0]){
echo ("ERROR: pA must be at the origin");
assert(false);
}
if ( (pB[2] !=0 ) || pC[2] !=0){
echo("ERROR: all sphere centers must be in z = 0 plane");
assert(false);
}
if (pB[1] != 0){
echo("pB centre must be on the x axis");
assert(false);
}
// show the spheres
module spheres(){
translate (pA){
sphere(r= rA, $fn = rA * 10);
}
translate(pB){
sphere(r = rB, $fn = rB * 10);
}
translate(pC){
sphere (r = rC, $fn = rC * 10);
}
}
function unit_vector( v) = v / norm(v);
ex = unit_vector(pB - pA) ;
echo(ex = ex);
i = ex * ( pC - pA);
echo (i = i);
ey = unit_vector(pC - pA - i * ex);
echo (ey = ey);
d = norm(pB - pA);
echo (d = d);
j = ey * ( pC - pA);
echo (j = j);
x = (pow(rA,2) - pow(rB,2) + pow(d,2)) / (2 * d);
echo( x = x);
// size of the cube to subtract to show
// the intersection of the spheres
cube_size = [10,10,10];
if ( ((d - rA) >= rB) || ( rB >= ( d + rA)) ){
echo ("Error Y not solvable");
}else{
y = (( pow(rA,2) - pow(rC,2) + pow(i,2) + pow(j,2)) / (2 * j))
- ( i / j) * x;
echo(y = y);
zpow2 = pow(rA,2) - pow(x,2) - pow(y,2);
if ( zpow2 < 0){
echo ("z not solvable");
}else{
z = sqrt(zpow2);
echo (z = z);
// subtract a cube with one of its corners
// at the point where the sphers intersect
difference(){
spheres();
translate ([x,y - cube_size[1],z]){
cube(cube_size);
}
}
translate ([x,y - cube_size[1],z]){
%cube(cube_size);
}
}
}

How to check if a point lies on a line between 2 other points

How would I write this function? Any examples appreciated
function isPointBetweenPoints(currPoint, point1, point2):Boolean {
var currX = currPoint.x;
var currY = currPoint.y;
var p1X = point1.x;
var p1y = point1.y;
var p2X = point2.x;
var p2y = point2.y;
//here I'm stuck
}
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.
Distance(point1, currPoint)
+ Distance(currPoint, point2)
== Distance(point1, point2)
But be careful if you have floating point values, things are different for them...
When concerned about the computational cost of computing "the square roots", don't:
Just compare "the squares".
This is independent of Javascript. Try the following algorithm, with points p1=point1 and p2=point2, and your third point being p3=currPoint:
v1 = p2 - p1
v2 = p3 - p1
v3 = p3 - p2
if (dot(v2,v1)>0 and dot(v3,v1)<0) return between
else return not between
If you want to be sure it's on the line segment between p1 and p2 as well:
v1 = normalize(p2 - p1)
v2 = normalize(p3 - p1)
v3 = p3 - p2
if (fabs(dot(v2,v1)-1.0)<EPS and dot(v3,v1)<0) return between
else return not between
You want to check whether the slope from point1 to currPoint is the same as the slope from currPoint to point2, so:
m1 = (currY - p1Y) / (currX - p1X);
m2 = (p2Y - currY) / (p2X - currX);
You also want to check whether currPoint is inside the box created by the other two, so:
return (m1 == m2) && (p1Y <= currY && currY <= p2Y) && (p1X <= currX && currX <= p2X);
Edit: This is not a very good method; look at maxim1000's solution for a much more correct way.
I'll use Triangle approach:
First, I'll check the Area, if the Area is close to 0, then the Point lies on the Line.
But think about the case where the length of AC is so great, then the Area increases far from 0, but visually, we still see that B is on AC: that when we need to check the height of the triangle.
To do this, we need to remember the formula we learn from first grade: Area = Base * Height / 2
Here is the code:
bool Is3PointOn1Line(IList<Vector2> arrVert, int idx1, int idx2, int idx3)
{
//check if the area of the ABC triangle is 0:
float fArea = arrVert[idx1].x * (arrVert[idx2].y - arrVert[idx3].y) +
arrVert[idx2].x * (arrVert[idx3].y - arrVert[idx1].y) +
arrVert[idx3].x * (arrVert[idx1].y - arrVert[idx2].y);
fArea = Mathf.Abs(fArea);
if (fArea < SS.EPSILON)
{
//Area is zero then it's the line
return true;
}
else
{
//Check the height, in case the triangle has long base
float fBase = Vector2.Distance(arrVert[idx1], arrVert[idx3]);
float height = 2.0f * fArea / fBase;
return height < SS.EPSILON;
}
}
Usage:
Vector2[] arrVert = new Vector2[3];
arrVert[0] = //...
arrVert[1] = //...
arrVert[2] = //...
if(Is3PointOn1Line(arrVert, 0, 1, 2))
{
//Ta-da, they're on same line
}
PS: SS.EPSILON = 0.01f and I use some function of Unity (for ex: Vector2.Distance), but you got the idea.
Ready for what seems to be infinitely simpler than some of these other solutions?
You pass it three points (three objects with an x and y property). Points 1 and 2 define your line, and point 3 is the point you are testing.
function pointOnLine(pt1, pt2, pt3) {
const dx = (pt3.x - pt1.x) / (pt2.x - pt1.x);
const dy = (pt3.y - pt1.y) / (pt2.y - pt1.y);
const onLine = dx === dy
// Check on or within x and y bounds
const betweenX = 0 <= dx && dx <= 1;
const betweenY = 0 <= dy && dy <= 1;
return onLine && betweenX && betweenY;
}
console.log('pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 2, y: 2})');
console.log(pointOnLine({ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 2 }));
console.log('pointOnLine({x: 0, y: 0}, {x: 1, y: 1}, {x: 0.5, y: 0.5})');
console.log(pointOnLine({ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 0.5, y: 0.5 }));
Edit: Simplified further according to RBarryYoung's observation.
This approach is similar to Steve's approach, just shorter and improved to use as little memory and process power as possible. But first the mathematical idea:
Let a, b be the ends of the line, ab the difference between them and p the point to check. Then p is exactly then on the line, if
a + i * ab = p
with i being a number in the interval [0;1] representing the index on the line. We can write that as two separate equations (for 2D):
a.x + i * ab.x = p.x
a.y + i * ab.y = p.y
⇔
i = (p.x - a.x) / ab.x
i = (p.y - a.y) / ab.y
Which gives us to requirements for p to be on the line from a to b:
(p.x - a.x) / ab.x = (p.y - a.y) / ab.y
and
0 ≤ i ≤ 1
In code:
function onLine(a, b, p) {
var i1 = (p.x - a.x) / (b.x - a.x), i2 = (p.y - a.y) / (b.y - a.y);
return i1 == i2 && i1 <= 0 && i1 >= 1;
}
Technically you could even inline i2 but that makes it even harder to read.
private static boolean pointInLine(int2 lineBegin, int2 lineEnd, int2 point)
{ boolean result = false;
int2 b = int2(min(lineBegin.x, lineEnd.x), min(lineBegin.y, lineEnd.y));
int2 e = int2(max(lineBegin.x, lineEnd.x), max(lineBegin.y, lineEnd.y));
if (point.x >= b.x && point.x <= e.x &&
point.y >= b.y && point.y <= e.y)
{ int2 normal = lineEnd.sub(lineBegin).perp();
int2 d0 = lineBegin.sub(point);
if (d0.dot(normal) == 0x0)
{ result = true;
}
}
return result;
}
This works for any slope, even if lineBegin == lineEnd == point.
First, create two points b and e, which ensures b <= e. (This is two support lines that have a negative slope) Check if point lands on the box (inclusive) created by those two points.
Then, get the normal of the line, which is a vector perpendicular to it.
You can do this by negating the x and transposing, x,y --> y, -x.
Then you can simply create a vector that points to the line from the point
or to the point from the line, it doesn't matter and doesn't have to be from the center of the line. Once you do that check if the vector is perpendicular to the normal by getting the dot product of the normal and the point vector.
It also makes it a bit easier on you if you've got some sort of math lib or at least a struct with x,y components. But you can do this with scalar components aswell. But getting the dot product and the normal are very simple calculations.
Here's the dot product:
.dot(int2 v) = (x * v.x + y * v.y)
Here's the perpendicular:
.perp() = new int2(y, -x)
.sub() .add() Do what you'd expect and params are in the same order.

Resources