4

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

Derek Corcoran
  • 3,930
  • 2
  • 25
  • 54
  • 1
    Minor comment on your distance function: The `abs` is unnecessary. Squares are always positive. – G5W Jan 25 '18 at 13:55

2 Answers2

7

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.

James
  • 65,548
  • 14
  • 155
  • 193
  • 1
    +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 well – Tom Jan 25 '18 at 14:11
  • @Tom Good spot, though the distance function would need to be modified to work for multiple dimensions too. – James Jan 25 '18 at 15:04
  • true. Seems I didn't pay too much attention. – Tom Jan 25 '18 at 19:35
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

Antonios
  • 1,919
  • 1
  • 11
  • 18
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/low-quality-posts/18624950) – TheGeorgeous Jan 25 '18 at 14:27
  • 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 above – Antonios Jan 25 '18 at 14:35