Reputation: 41
I have a line made of two points BA and a point P. I would like to find the distance from P to the perpendicular of BA and to the parallel of BA. Do you know if there is any fuction aready doing it in R or Matlab?? I attacht a picture to make it easier to understand.
Upvotes: 4
Views: 541
Reputation: 76402
The function coding is straightforward from the textbook formula.
dist_point2line <- function(P, A, B){
dx <- B[1] - A[1]
dy <- B[2] - A[2]
numer <- abs(dy*P[1] - dx*P[2] + B[1]*A[2] - B[2]*A[1])
denom <- sqrt(dx^2 + dy^2)
d <- numer/denom
inv_cos_ang <- if(dy == 0) 1 else sqrt(1 + (dx/dy)^2)
p <- d*inv_cos_ang
list(dist = d, parallel = p)
}
Test with the distance from the origin to the line passing by (0, 1)
and (1, 0)
. The result is sqrt(2)/2
and the distance parallel to the x axis is 1
.
sqrt(2)/2
#[1] 0.7071068
dist_point2line(c(0, 0), c(1, 0), c(0, 1))
#$dist
#[1] 0.7071068
#
#$parallel
#[1] 1
Another example, taken from @ThomasIsCoding's answer. Note that the results are different, this one is right.
A <- c(1, 3)
B <- c(5, 10)
P <- c(7, 7)
dist_point2line(P, A, B)
#$dist
#[1] 3.224903
#
#$parallel
#[1] 3.714286
To see that this one is right just notice that the distance from P to the line segment parallel to the x axis is visibly around 3, not 0.8.
plot(1, type = "n", xlim = c(0, 8), ylim = c(0, 11))
points(P[1], P[2], col = "red")
points(A[1], A[2])
points(B[1], B[2])
segments(A[1], A[2], B[1], B[2])
abline(h = P[2])
Following a request by the OP to have the function compute the distance parallel to the y axis, here is a new version of the above function.
dist_point2line <- function(P, A, B){
dx <- B[1] - A[1]
dy <- B[2] - A[2]
numer <- abs(dy*P[1] - dx*P[2] + B[1]*A[2] - B[2]*A[1])
denom <- sqrt(dx^2 + dy^2)
d <- numer/denom
inv_cos_ang <- if(dy == 0) 1 else sqrt(1 + (dx/dy)^2)
inv_sin_ang <- if(dx == 0) 1 else sqrt(1 + (dy/dx)^2)
px <- d*inv_cos_ang
py <- d*inv_sin_ang
list(dist = d, parallel = c(xdist = px, ydist = py))
}
Upvotes: 3
Reputation: 101129
You can try the code below, where function names perp_dist
and xparal
denotes perpendicular to AB and parallel to x-axis distances
perp_dist <- function(P,A,B) {
norm(pracma::cross(c(P-A,0),c(B-A,0)),"2")/norm(B-A,"2") # use cross product of vectors to calculate the distance
}
xparal_dist <- function(P,A,B) {
AB <- B-A
perp_dist(P,A,B)*ifelse(AB[2]==0,1,sqrt(1+(AB[1]/AB[2])**2))
}
Example
A <- c(1,3)
B <- c(5,10)
P <- c(7,7)
perp_dist(P,A,B)
xparal_dist(P,A,B)
which gives
> perp_dist(P,A,B)
[1] 0.6933752
> xparal_dist(P,A,B)
[1] 0.8333333
function d = perp_dist(P,A,B)
d = norm(cross([P-A,0],[B-A,0]))/norm(B-A); % use cross product of vectors to calculate the distance
end
function d = xparal_dist(P,A,B)
AB = B-A;
if AB(2)==0
f = 1;
else
f = sqrt(1+(AB(1)/AB(2))^2);
end
d = perp_dist(P,A,B)*f;
end
Example
A = [0,0];
B = [6,9];
P = [2.5,2.5];
perp_dist(P,A,B)
xparal_dist(P,A,B)
such that
>> perp_dist(P,A,B)
ans = 0.6934
>> xparal_dist(P,A,B)
ans = 0.8333
If you have A
, B
and P
in form of data.frame
, e.g.,
set.seed(1)
A <- data.frame(X = rnorm(5),Y = rnorm(5))
B <- data.frame(X = rnorm(5),Y = rnorm(5))
P <- data.frame(X = rnorm(5),Y = rnorm(5))
then you can use Vectorize
over your data frames, i.e.,
dperp <- Vectorize(perp_dist)(data.frame(t(P)),data.frame(t(A)),data.frame(t(B)))
dxparal <- Vectorize(xparal_dist)(data.frame(t(P)),data.frame(t(A)),data.frame(t(B)))
such that
> dperp
X1 X2 X3 X4 X5
0.1916007 0.3101444 2.2245761 1.2821965 0.2617655
> dxparal
X1 X2 X3 X4 X5
0.5619376 0.3351336 3.2146859 19.9448870 0.3494685
If you want to calculate distance parallel to y axis, you can use the following code (MATLAB version is similar)
yparal_dist <- function(P,A,B) {
AB <- B-A
perp_dist(P,A,B)*ifelse(AB[1]==0,1,sqrt(1+(AB[2]/AB[1])**2))
}
Upvotes: 2