Вопрос

This is a problem that I fought with for a bit and couldn't find a good answer out there. I did eventually solve it in R, but thought I would post it anyway in case others need it. If anyone has a more elegant solution, I would love to see it. This is a bit of a brute force effort.

I have a series of paired XY (Cartesian) coordinates. I can easily get the angles between them using a simple atan() command. However, I want the angles in compass (polar? cardinal?) directions (where north=0°, east=90°, and so forth). Here's a minimal example to make the data and the Cartesian angles, and I've posted my brute force conversion to compass angle below. The degree conversion (from radians) uses deg() from the 'circular' package.

require(circular)
test <- data.frame(x=c(0,1,1,1,0,-1,-1,-1),y=c(1,1,0,-1,-1,-1,0,1))
test$angle <- deg(atan(test$y/test$x))
test

...produces

   x  y angle
1  0  1    90
2  1  1    45
3  1  0     0
4  1 -1   -45
5  0 -1   -90
6 -1 -1    45
7 -1  0     0
8 -1  1   -45

Note that the angles into the lower-left and upper-left quadrants are the same as that into the lower- and upper-right quadrants, losing the directionality of the vectors.

Это было полезно?

Решение

ang <- function(x,y) { 
  z <- x + 1i * y
  res <- 90 - Arg(z) / pi * 180
  res %% 360
}

ang(test$x, test$y)
#[1]   0  45  90 135 180 225 270 315

Другие советы

First, shifting the angles to measure of the y-axis (or North=0) can be done easily by altering the angle line of the code by subtracting 90 degrees (thanks JK):

test$angle <- 90-deg(atan(test$y/test$x))

However, the conversion of the left-bound vectors needs to be maintained, so an adjustment for these angles based on the signs of the X and Y values was my solution:

# Make new column for the polar/compass angles
test$polar <- test$angle
# Then make the necessary adjustments
# Adjustment for quadrant C (bottom left, 180 to 270°)
test[sign(test$x)==-1 & sign(test$y)==-1,"polar"] <- ((1-(test[sign(test$x)==-1 & sign(test$y)==-1,"angle"]/90))*90)+180
# Adjustment for quadrant D (top left, 270 to 360°)
test[sign(test$x)==-1 & sign(test$y)>=0, "polar"] <- abs(test[sign(test$x)==-1 & sign(test$y)>=0,"angle"])+180

...producing:

   x  y angle polar
1  0  1     0     0
2  1  1    45    45
3  1  0    90    90
4  1 -1   135   135
5  0 -1   180   180
6 -1 -1    45   225
7 -1  0    90   270
8 -1  1   135   315

Again, I'm posting this as a working solution, but more elegant or easier suggestions would be appreciated too!

Its all linear. There are two difficulties: the direction of increasing angle is CCW in a Cartesian system, and CW in a Navigation system, and 0° Cartesian is 90° on a chart. We can fix the first problem by changing the sign: N <= -C.

Now 0 maps to 0. We want 0 to map to 90, so just add 90: N <= -C + 90.

But, whoops, that gives us some angles outside the usual range 0-360. But, angles repeat mod 360, so we can fix that easily: N <= -c + 90 modulo 360.

Modulo operators disagree as to how to deal with negative numbers, so to be safe, add 360 first to eliminate the problem: N <= (-C + 90 + 360) modulo 360.

In Excel, MOD(450 - C, 360) or in javascript, ((450 - C)) % 360. I'm afraid I don't know R. [But in Fortran IV, it would be FN = mod(450.0 - C, 360.0)]

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top