I need to calculate the angle between an array of points and an array of vectors (adjusting for the direction of the vectors). I'm using the angle2 function (based on atan2) from this to calculate the angle, however I seem to be doing something wrong.
The data are 2 continuous tracks. One track comes with a course value, the other one is simply coordinates. So one track (Easting2, Northing2) is an array of vectors, the other (Easting, Northing) - of just points. I figured I had to make the points into vectors relative to the other, vector-based, track, then use the atan2 approach. Here's my thought process:
However, in the example here, I would have expected to get an angle of ~30 degrees for the first row and ~50 degrees for the second row. What am I doing wrong??
toy example:
library(dplyr)
df <- structure(list(Easting = c(519984.801109577, 520254.016648783
), Northing = c(8015778.00697284, 8017130.41190275), Easting2 = c(520033.416692364,
518599.418722116), Northing2 = c(8029164.59837475, 8023952.71894817
), Course = c(195.6, 196)), .Names = c("Easting", "Northing",
"Easting2", "Northing2", "Course"), row.names = c(NA, -2L), class = c("tbl_df",
"tbl", "data.frame"))
# function from the linked post, to calculate angles between vectors
angle2 <- function(M,N){
atan2(N[2],N[1]) - atan2(M[2],M[1])
}
df %>%
mutate(Easting.adj = Easting - Easting2,
Northing.adj = Northing - Northing2,
Course.rad = Course * pi / 180,
Next.Easting2 = cos(Course.rad),
Next.Northing2 = sin(Course.rad)) %>%
rowwise() %>%
mutate(Angle = angle2(c(Next.Easting2, Next.Northing2), c(Easting.adj, Northing.adj)),
# convert back to degrees
Angle = Angle * 180 / pi)
The image is not totally accurate for the supplied numbers, since Easting.adj
is negative for row 1 and positive for row 2. The problem is caused because Mathematical angles are defined counter-clockwise from the x-direction, while your nautical course seems to be defined clockwise from the north-direction. One should use 90 - Course
:
df %>%
mutate(Easting.adj = Easting - Easting2,
Northing.adj = Northing - Northing2,
Course.rad = (90 - Course) * pi / 180,
Next.Easting2 = cos(Course.rad),
Next.Northing2 = sin(Course.rad)) %>%
rowwise() %>%
mutate(Angle = angle2(c(Next.Easting2, Next.Northing2), c(Easting.adj, Northing.adj)),
# convert back to degrees
Angle = Angle * 180 / pi)
The above code generates 15.4 degree and 29.6 degree as your angles. Alternatively, you can stay with angles:
df %>%
mutate(Easting.adj = Easting - Easting2,
Northing.adj = Northing - Northing2,
math_course = 90 - Course) %>%
rowwise() %>%
mutate(direction = atan2(Northing.adj, Easting.adj) * 180 / pi,
angle = direction - math_course)