Creating R function to find both distance and angle between two points
Asked Answered
C

2

5

I am trying to create or find a function that calculates the distance and angle between two points, the idea is that I can have two data.frames with x, y coordinates as follows:

Example dataset

From <- data.frame(x = c(0.5,1, 4, 0), y = c(1.5,1, 1, 0))

To <- data.frame(x =c(3, 0, 5, 1), y =c(3, 0, 6, 1))

Current function

For now, I've managed to develop the distance part using Pythagoras:

distance <- function(from, to){
  D <- sqrt((abs(from[,1]-to[,1])^2) + (abs(from[,2]-to[,2])^2))
  return(D)
}

Which works fine:

distance(from = From, to = To)


[1] 2.915476 1.414214 5.099020 1.414214

but I can't figure out how to get the angle part.

What I tried so far:

I tried adapting the second solution of this question

angle <- function(x,y){
  dot.prod <- x%*%y 
  norm.x <- norm(x,type="2")
  norm.y <- norm(y,type="2")
  theta <- acos(dot.prod / (norm.x * norm.y))
  as.numeric(theta)
}

x <- as.matrix(c(From[,1],To[,1]))
y <- as.matrix(c(From[,2],To[,2]))
angle(t(x),y)

But I am clearly making a mess of it

Desired output

I would like having the angle part of the function added to my first function, where I get both the distance and angle between the from and to dataframes

Chromatogram answered 25/1, 2018 at 13:28 Comment(1)
Minor comment on your distance function: The abs is unnecessary. Squares are always positive.Tintinnabulation
R
8

By angle between two points, I am assuming you mean angle between two vectors defined by endpoints (and assuming the start is the origin).

The example you used was designed around only a single pair of points, with the transpose used only on this principle. It is however robust enough to work in more than 2 dimensions.

Your function should be vectorised as your distance function is, as it is expecting a number of pairs of points (and we are only considering 2 dimensional points).

angle <- function(from,to){
    dot.prods <- from$x*to$x + from$y*to$y
    norms.x <- distance(from = `[<-`(from,,,0), to = from)
    norms.y <- distance(from = `[<-`(to,,,0), to = to)
    thetas <- acos(dot.prods / (norms.x * norms.y))
    as.numeric(thetas)
}

angle(from=From,to=To)
[1] 0.4636476       NaN 0.6310794       NaN

The NaNs are due to you having zero-length vectors.

Reckoner answered 25/1, 2018 at 14:4 Comment(3)
+1 for the self-reference to distance()... maybe you want to extend your dot.prods using rowSums(from * to) to work in multiple dimensions as wellGarner
@Garner Good spot, though the distance function would need to be modified to work for multiple dimensions too.Reckoner
true. Seems I didn't pay too much attention.Garner
I
5

how about:

library(useful)
df=To-From
cart2pol(df$x, df$y, degrees = F)

which returns:

# A tibble: 4 x 4
      r theta     x     y
  <dbl> <dbl> <dbl> <dbl>
1  2.92 0.540  2.50  1.50
2  1.41 3.93  -1.00 -1.00
3  5.10 1.37   1.00  5.00
4  1.41 0.785  1.00  1.00

where r us the distance and theta is the angle

Interrogator answered 25/1, 2018 at 13:54 Comment(2)
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - From ReviewGlycolysis
but it returns the distance and angle as resuested. Actually distance (r variable in returning tibble) from my code is the same with distance function shown aboveInterrogator

© 2022 - 2024 — McMap. All rights reserved.