问题
I have two points, (x1,y1)
and (x2,y2)
, that I'd like to draw a line between. I know I can figure out the angle (in degrees) of that line using arctangent and the slope:
atan((y2-y1)/(x2-x1))*180/pi
However, how would I convert this angle to a [0,360] scale? Basically, I want my angle to be on a compass scale in which "North" is 0 deg, "East" is 90 deg, "South" is 180 deg, and "West" is 270 deg.
Thanks!
回答1:
(450-atan2(y2-y1,x2-x1)*180/pi)%%360
segmentToAngle <- function(x1,y1,x2,y2) atan2(y2-y1,x2-x1)*180/pi;
segmentToAngle(0,0,1,0); ## east
## [1] 0
segmentToAngle(0,0,0,1); ## north
## [1] 90
segmentToAngle(0,0,-1,0); ## west
## [1] 180
segmentToAngle(0,0,0,-1); ## south
## [1] -90
segmentToCompassAngle <- function(x1,y1,x2,y2) (450-segmentToAngle(x1,y1,x2,y2))%%360;
segmentToCompassAngle(0,0,1,0); ## east
## [1] 90
segmentToCompassAngle(0,0,0,1); ## north
## [1] 0
segmentToCompassAngle(0,0,-1,0); ## west
## [1] 270
segmentToCompassAngle(0,0,0,-1); ## south
## [1] 180
回答2:
Just to generalize @bgoldst's answer:
(A1 - atan2(y2-y1,x2-x1) * 180/pi ) %%360
Here is the explanation of the various parts of this equation:
You have to use
atan2()
instead ofatan()
.atan2()
is the arctangent function with two arguments. The purpose of using two arguments is to gather information on the signs of the inputs in order to return the appropriate quadrant of the computed angle. This is not possible for the single-argument arctangent (atan
) function.The modulus operator
%%
is used in this case to give the remainder of dividing the angle by 360. In this way, we force the angles to "wrap around" at 360.The angle calculated using
atan2
is multiplied by180/pi
in order to convert the answer from radians (atan2's default output) into degrees.If we stopped there, the resulting angle would be based on standard trigonometric form in which "East" = 0 degrees. All angles would be relative to "East" = 0.
By subtracting our calculated angle in degrees from some angle (A1), we can offset the calculated angle by A1 degrees. In the case of the navigational-bearing scale (with "North" = 0 degrees) we would set
A1 = 90
.(90 - atan2(y2-y1,x2-x1) * 180/pi ) %%360
回答3:
For "North" 0 deg. "East" 90 deg. "South" 180 deg. and "West" 270 deg.
you can use the formula:
f(E,N)=180-90*(1+sign(N))* (1-sign(E)^2)-45*(2+sign(N))*sign(E)
-180/pi()*sign(E*N)*atan((abs(N)-abs(E))/(abs(N)+abs(E)))
E=E2-E1 and N=N2-N1
回答4:
I do not want to discredit the math-focussed discussion here. However, you are speaking about a navigational bearing. From that I assume, your focus is on navigating := applying math to get a navigational task done (my personal definition).
The 'geosphere package' will help you a lot in this area. It offers a set of geo / nav functions (for spherical calculations). To move from one point p1 to another p2, the functions 'geosphere::bearing()' or 'geosphere::bearingRhumb()' will give you the azimuth direction expressed in degrees, i.e. -180 ... +180. You can find a bit of more explanation in the answer to this related question.
As also flagged by @theforestecologist, the following will do the trick using the modulo approach to determine the rest of any angle math beyond a full circle, i.e. 360 degrees. The modulo operator gives you the rest on top of the modulo basis (in our case 360). This solves the negative sign issue for the azimuth. For example
- -90 + 360 = 270 ==> 270 %% 360 := (0 * 360) + 270 = 270
- 30 + 360 = 30 ==> 30 %% 360 := (0 * 360) + 30 = 30
- for math-purists re the modulo, any number of full circles can be added, e.g. 2* 360 degrees = 720. This will yield: -30 + 720 = 690 ==> 690 %% 360 := (1 * 360) + 330 = 330
Use the following in R/RStudio with the geoshere
package loaded. Please note that the geosphere package uses x-y position concept, i.e. longitude before latitude, rather than the navigational practice of latitude-before-longitude (e.g. 43N 3E)!
brg <- geosphere::bearing(c(p1_lon, p1_lat), c(p2_lon, p2_lat))
crs <- (brg + 360) %% 360 # to generate 0...360 courses
Note 2: if you work with multiple point-to-point relationships. Recode them as matrices using cbind():
brg <- geosphere::bearing(cbind(p1_lon, p1_lat), cbind(p2_lon, p2_lat))
来源:https://stackoverflow.com/questions/31838855/how-do-i-easily-convert-a-line-angle-to-a-navigational-bearing-scale-i-e-with