将笛卡尔坐标转换为极坐标,然后计算到原点的距离。

8
我一直在寻找一个解决方案,以将我所拥有的笛卡尔坐标(纬度,经度)转换为极坐标,以便于我想运行的模拟。然而,在R中没有发现任何关于此的问题或答案。虽然Matlab内置了cart2pol函数等多种选项,但我的所有数据都在R中,并且我想继续熟悉这个框架。
问题:
我从标记数据中获得了纬度/经度坐标,并希望将它们转换为极坐标(指跳跃大小和角度:http://en.wikipedia.org/wiki/Polar_coordinate_system),以便我可以将它们随机排列或自助重采样(还没有决定),约1,000次,并计算每个模拟轨迹的直线距离从起点开始。我有一个真实轨迹,并且我有兴趣确定这种动物是否表现出网站亲和性,通过模拟具有相同跳跃大小和转向角度但完全不同的顺序和组合的1,000个随机轨迹来进行比较。因此,我需要从原点获取1,000条直线距离来创建距离分布,然后将其与我的真实数据集的直线距离进行比较。
我擅长启动引导,但卡在第一步,即将笛卡尔纬度/经度坐标转换为极坐标(跳跃大小和旋转角度)。我知道其他程序(比如Matlab)中有内置函数可以做到这一点,但我找不到在 R 中实现的方法。我可以手动使用for循环完成,但如果有包或更简单的方法可用,我更喜欢使用它。
理想情况下,我希望将数据转换为极坐标,运行模拟,然后针对每个随机轨迹输出一个端点作为笛卡尔坐标、纬度/经度,以便我可以计算直线距离。
我没有发布任何样本数据,因为它只是一个纬度和经度坐标的两列数据框。
感谢您提供的任何帮助!如果这个网站或其他地方有易于理解的解释,请指引我!我找不到任何信息。
干杯

你是指Matlab的cart2pol函数吗? - Nishanth
circular 包可能会引起您的兴趣:http://cran.r-project.org/web/packages/circular/circular.pdf - Ricardo Saporta
好的,cart2pol。我会看一下circular包,谢谢! - stewart6
1
为什么答案不只是:r= sqrt(x^2+y^2)?(如果你不知道反向转换,只需查看维基百科或任何坐标几何文本即可?) - IRTFM
在现实世界中,坐标轴是倾斜的,并且原点不是在0,0。 - skan
然后 r= sqrt( (x-x0)^2+(y-y0)^2) ... 结果应该与旋转无关。但如果问题实际上是关于“地球表面上”的距离,那么它将因纬度而异,因为纬度/经度通常不是“笛卡尔坐标系”。如果这些数据都在一小范围的纬度内收集,则可以在进行计算之前对所有经度值应用简单的余弦校正因子。 - IRTFM
7个回答

7

如果x-y坐标使用相同的单位(例如米而不是纬度和经度),您可以使用此函数获取跳跃大小和转弯角(以度为单位)的数据框。

getSteps <- function(x,y) {
    d <- diff(complex(real = x, imaginary = y))
    data.frame(size = Mod(d), 
               angle = c(NA, diff(Arg(d)) %% (2*pi)) * 360/(2*pi))
}

## Try it out   
set.seed(1)
x <- rnorm(10)
y <- rnorm(10)
getSteps(x, y)
#        size     angle
# 1 1.3838360        NA
# 2 1.4356900 278.93771
# 3 2.9066189 101.98625
# 4 3.5714584 144.00231
# 5 1.6404354 114.73369
# 6 1.3082132 135.76778
# 7 0.9922699  74.09479
# 8 0.2036045 141.67541
# 9 0.9100189 337.43632

## A plot helps check that this works
plot(x, y, type = "n", asp = 1)
text(x, y, labels = 1:10)

enter image description here


嗨,乔希 - 这对于将我的纬度/经度点转换为步长和角度非常有效。在赤道上,纬度和经度坐标之间的每个度数大约具有相同的距离,因此它们本质上是相同的单位。如果我随机化它们后,你如何从大小和旋转角度的数据框中转换回笛卡尔坐标? - stewart6
@stewart6 -- 要转换回来,将角度从度数转换为弧度(通过除以 360/(2*pi)),然后使用sin()cos()从极坐标移动到x-y坐标系。我会把这当作一个好的练习留给你 ;) 此外,除非您确实在赤道附近工作,否则请注意不要假设纬度/经度的度数是等价的。在我所在的地方,大约在45度纬度左右,一个经度的长度只有一个纬度的长度的70%... - Josh O'Brien
嗨,Josh - 我今天早上开始实施你的解决方案,并成功地得到了合理的输出结果,但我认为由于某种原因,它所输出的数据是不正确的...我在下面详细说明了。我会感激任何建议! - stewart6

3
你可以通过以下方式在直角坐标系和极坐标系之间进行转换:
polar2cart <- function(r, theta) {
  data.frame(x = r * cos(theta), y = r * sin(theta))
}

cart2polar <- function(x, y) {
  data.frame(r = sqrt(x^2 + y^2), theta = atan2(y, x))
}

2

由于这很直截了当,你可以自己编写函数。在R中类似Matlab的cart2pol函数:

cart2pol <- function(x, y)
{
  r <- sqrt(x^2 + y^2)
  t <- atan(y/x)

  c(r,t)
}

2
这并没有考虑90度到270度之间的角度(使用你的代码会出现错误)。 - Yossi Farjoun
在现实世界中,坐标轴是倾斜的,并且原点不是0,0。 - skan

1
我使用了Josh O'Brien的代码,并得到了合理的跳跃和角度,它们与粗略的点之间的距离和方向相当匹配。然后,我使用他的建议中的公式创建了一个函数,将极坐标转换回笛卡尔坐标,并使用for循环将该函数应用于所有极坐标数据框。循环似乎有效,并且输出是正确的单位,但我不认为输出的值对应于我的数据。因此,要么我在公式上做错了计算,要么有其他问题。更多详细信息如下:
这是我的经纬度数据的头部:
> head(Tag1SSM[,3:4])
       lon       lat
1 130.7940 -2.647957
2 130.7873 -2.602994
3 130.7697 -2.565903
4 130.7579 -2.520757
5 130.6911 -2.704841
6 130.7301 -2.752182

当我将整个数据集作为值绘制时,得到了这个图形:Lat-Long Plot,这与我在R中使用任何空间或地图包绘制的图形完全相同。
然后,我使用Josh的函数将我的数据转换为极坐标:
x<-Tag1SSM$lon
y<-Tag1SSM$lat

getSteps <- function(x,y) {
  d <- diff(complex(real = x, imaginary = y))
  data.frame(size = Mod(d), 
             angle = c(NA, diff(Arg(d)) %% (2*pi)) * 360/(2*pi))
}

这将适当地产生以下极坐标:

> polcoords<-getSteps(x,y)
> head(polcoords)
        size     angle
1 0.04545627        NA
2 0.04103718  16.88852
3 0.04667590 349.38153
4 0.19581350 145.35439
5 0.06130271  59.37629
6 0.01619242  31.86359

这些看起来对我来说是正确的,与点之间的实际角度和相对距离相符。到目前为止一切顺利。

现在我想将它们转换回笛卡尔坐标,并从原点计算欧几里得距离。这些不必是真正的经纬度,因为我只是在它们之间进行比较。所以我很高兴将原点设置为(0,0),并且距离是根据参考x,y值而不是公里或类似单位来计算的。

因此,我使用了这个函数,在Josh的帮助下和一些网上搜索:

polar2cart<-function(x,y,size,angle){

  #convert degrees to radians (dividing by 360/2*pi, or multiplying by pi/180)
  angle=angle*pi/180
  if(is.na(x)) {x=0} #this is for the purpose of the for loop below
  if(is.na(y)) {y=0}
  newx<-x+size*sin(angle)  ##X #this is how you convert back to cartesian coordinates
  newy<-y+size*cos(angle)  ##Y
  return(c("x"=newx,"y"=newy)) #output the new x and y coordinates
}

然后将它插入到这个 for 循环中:
u<-polcoords$size
v<-polcoords$angle
n<-162 #I want 162 new coordinates, starting from 0
N<-cbind(rep(NA,163),rep(NA,163)) #need to make 163 rows, though, for i+1 command below— first row will be NA
for(i in 1:n){
  jump<-polar2cart(N[i,1],N[i,2],u[i+1],v[i+1]) #use polar2cart function above, jump from previous coordinate in N vector 
  N[i+1,1]<-jump[1] #N[1,] will be NA's which sets the starting point to 0,0—new coords are then calculated from each previous N entry
  N[i+1,2]<-jump[2]
  Dist<-sqrt((N[163,1]^2)+(N[163,2]^2)) 
}

然后,我可以根据这些跳跃的新坐标查看 N:

> N
               [,1]        [,2]
  [1,]           NA          NA
  [2,]  0.011921732  0.03926732
  [3,]  0.003320851  0.08514394
  [4,]  0.114640605 -0.07594871
  [5,]  0.167393509 -0.04472125
  [6,]  0.175941466 -0.03096891

这就是问题所在... N 的 x,y 坐标逐渐变大——其中有一些变化,但如果您向下滚动列表,y 从 0.39 到 11.133,几乎没有回到较低值的步骤。这不是我的纬度/经度数据所做的,如果我正确计算了 cart->pol 和 pol->cart,这些来自 N 的新值应该与我的纬度/经度数据匹配,只是在另一个坐标系中。这是 N 值的绘图结果:

back-converted cartesian coordinates

不一样... 在N中,最后一个点是距离原点最远的点,而在我的纬度/经度数据中,最后一个点实际上非常靠近第一个点,并且绝对不是最远的点。我认为问题必须出在我从极坐标转换回笛卡尔坐标时,但我不确定如何解决它...任何帮助解决这个问题都将不胜感激!干杯

干得好。抱歉,时间不多,但这是我首先想到的。我希望看到类似于 v <- cumsum(polcoords$angle) 的东西代替 v <- polcoords$angle(在执行 v[is.na(v)] <- 0 来消除 NAs 后)。毕竟,每个跳跃的方向都是所有前面转角的累积,而我认为你的代码还没有反映出来。暂时无法再查看此问题,所以我希望我只是碰巧发现了(唯一的)错误。 - Josh O'Brien
还有一个想法——在构建这段代码时,您可能想尝试一组非常简单的跳跃。我可能会构建并使用一个数据框,其中包含4个直角跳跃和几个直线跳跃。这将使我们更容易看到代码中的任何错误所在。 - Josh O'Brien
嗨,Josh - 感谢您的建议。我会看看能想出什么解决方案,并在这里发布解决方案或进一步的问题。非常感谢您的帮助! - stewart6

1
我认为我写的这段代码可以转换成极坐标:
# example data
x<-runif(30)
y<-runif(30)
# center example around 0
x<-x-mean(x)
y<-y-mean(y)

# function to convert to polar coordinates
topolar<-function(x,y){

    # calculate angles 
    alphas<-atan(y/x)

    # correct angles per quadrant
    quad2<-which(x<0&y>0)
    quad3<-which(x<0&y<0)
    quad4<-which(x>0&y<0)
    alphas[quad2]<-alphas[quad2]+pi
    alphas[quad3]<-alphas[quad3]+pi
    alphas[quad4]<-alphas[quad4]+2*pi

    # calculate distances to 0,0
    r<-sqrt(x^2+y^2)

    # create output
    polar<-data.frame(alphas=alphas,r=r)

}

# call function
polar_out<-topolar(x,y)
# get out angles
the_angles<-polar_out$alphas

0

另一种仅限于度数的选项

pol2car = function(angle, dist){
    co = dist*sin(angle)
    ca = dist*cos(angle)
    return(list(x=ca, y=co))
}
pol2car(angle = 45, dist = sqrt(2))

0

cart2sph {pracma} 在二维和三维中,转换直角、球面、极坐标和柱面坐标系。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接