【问题标题】:Move xy coordinates based on a given distance and bearing from transect根据给定距离和方位角移动 xy 坐标
【发布时间】:2018-03-27 02:58:42
【问题描述】:

我有一艘船沿着横断面行驶,寻找动物。有人站在船顶上,面朝前,正在记录与船的距离以及看到动物时船头的方位。我有这些信息以及看到动物时船的 xy 坐标。 我需要根据这些信息获取动物本身的 xy 坐标。

我没有船原来的罗盘方位,这让这很棘手;但我所拥有的是船的下一个 GPS (xy) 坐标,我可以从中计算起始角度。由此,应该可以添加或减去看到动物的方位角,以给出一个归一化的角度,该角度可用于使用三角法找到动物的 xy 坐标。不幸的是,我的数学技能还不能胜任这份工作。

我有几百个点,所以我需要将其放入 Python 脚本中以遍历所有点。

总的来说,数据集有:

原始X,原始Y,结束(下一个)X,结束(下一个)Y,方位,距离

编辑:对不起,我很着急,没有很好地解释这一点。

我看到这个问题有 3 个阶段。

  1. 寻找样带的原始方位
  2. 查找点相对于样带的方位
  3. 根据这个归一化的角度和与船在起点 xy 处的距离查找该点的新坐标

下面是我最初的 Python 代码,虽然用处不大 - 给出的数字是示例。

    distFromBoat = 100
    bearing = 45


    lengthOpposite = origX-nextX
    lengthAdjacent = origY - nextY
    virtX = origX #virtual X
    virtY = origY-lengthOpposite #virtual Y
    angle = math.degrees(math.asin(math.radians((lengthOpposite/transectLen))))
    newangle = angle + bearing
    newLenAdj = math.cos(newangle)*distFromBoat
    newLenOpp = math.sqrt(math.pow(distFromBoat,2) + math.pow(newLenAdj,2) - 2*(distFromBoat*newLenAdj)*(math.cos(newangle)))
    newX = virtX-newLenOpp
    newY = origY-newLenAdj
    print str(newX) +"---"+str(newY)

提前感谢您的帮助!

【问题讨论】:

  • 我不太清楚你到底在问什么(+/- 部分似乎模棱两可)。附带说明一下,我认为您不需要将 lengthOpposite/transectLen 的比率声明为弧度,这与除法本身有关。

标签: python coordinates


【解决方案1】:

Matt 的函数有点问题,所以我用atan2 来告诉你船行进的角度。

编辑:这比我预期的要复杂。最后,您需要减去 90 并取逆以从地理参考角到三角角。

(还有一个内置的 angles 库(可能还有其他地理库)。

现在这需要origXorigY,找到三角角并将其转换为heading,将方位角添加到为横断面确定的角度。然后它会触发距离,但使用转换回三角度的角度-(X-90)。它有点扭曲,因为我们习惯于将 0 度视为北/上,但在 trig 中它是“向右”,并且 trig 是逆时针而不是顺时针导航。

import math

origX = 0.0
origY = 0.0

nextX = 0.0
nextY = -1.0

distance = 100.0
bearing = 45


def angle(origX,origY,nextX,nextY):
    opp = float(nextY - origY)
    adj = float(nextX - origX)
    return(math.degrees(math.atan2(adj,opp)))
# atan2 seems to even work correctly (return zero) when origin equals next

transectAngle = angle(origX,origY,nextX,nextY) # assuming the function has been defined
print "bearing plus trans", transectAngle + bearing
trigAngle = -(transectAngle + bearing -90)
print "trig equiv angle", trigAngle
newX = origX + distance * math.cos(math.radians(trigAngle))
newY = origY + distance * math.sin(math.radians(trigAngle))

print "position",newX,newY

输出:

-70.7106781187 -70.7106781187

这是一个打印一堆测试用例的函数(使用全局变量,所以应该折叠到上面的代码中)

def testcase():
    bearinglist = [-45,45,135,-135]
    dist = 10
    for bearing in bearinglist:
        print "----transect assuming relative bearing of {}------".format(bearing)
        print "{:>6}  {:>6}  {:>6}  {:>6}  {:>6}  {:>6}  {:>6}  {:>6}".format("x","y","tran","head","trigT","trigH","newX","newY")  
        for x in [0,.5,-.5]:
            for y in [0,.5,1,-.5]:
                # print "A:", x,y,angle(origX,origY,x,y)
                tA = newangle(origX,origY,x,y)
                trigA = -(tA-90)
                heading = tA + bearing
                trigHead = -(heading-90)
                Xnew = distance * math.cos(math.radians(trigHead))
                Ynew = distance * math.sin(math.radians(trigHead))
                print "{:>6.1f}  {:>6.1f}  {:>6.1f}  {:>6.1f}  {:>6.1f}  {:>6.1f}  {:>6.1f}  {:>6.1f}".format(x,y,tA,heading,trigA,trigHead,Xnew,Ynew)

【讨论】:

  • 嗯实际上,当 origY > nextY 时,它似乎无法正常工作。如果您能检查一下,我将不胜感激,但我实际上无法确定它如何不起作用的模式......似乎没有给出正确角度的示例值(通过视觉):bearing = 45, dist = 2000, origxy = 95485,729380, nextxy = 95241,729215 给我 95108, 731344 看起来根本不对
  • 角度计算功能有问题,所以我用atan2做了一个新的。我还将它更改为使用自制的eq 函数来测试浮点数的相等性,因为由于精度问题,您不应该使用==
  • 使用新代码和您的样本点,它会给出95864.3 727416.3 看起来对吗?
  • 恐怕不行;这似乎在象限中的正确位置,但在错误的象限中 - 它应该在 93731、730302 左右。虽然并不是所有的点都偏离了这个数量,但有些点在正确的位置。另一个错误是方位角为 -10 和 dist 2000 的错误,其中 X1 大致等于 X2 并且 Y2>Y1(并且应该给出一个几乎指向北的点)给出一个 2000m 处的点,但角度看起来大约是距北 100 度。再次感谢您的帮助!
  • 对不起。稍后我将不得不为此工作。单元测试的好案例。我做了一些测试,但由于错误的原因它们碰巧是正确的!不仅三角函数偏离 90°,而且它们是相反的,所以一旦你得到角度(在你得到最终的 sin cos 和来自atan2 的角度之前),就需要进行反转。 /跨度>
【解决方案2】:

据我了解,这是你的问题:

  • 您有 2 个点,startnext,您在它们之间行走
  • 假设您已经面向startnext,您希望找到第三个点New 的坐标,该坐标应该与start 有一段距离和方位。

我的解决办法是这样的:

  • 创建一个从startnext 的标准化向量
  • 按给定方位旋转归一化矢量
  • 将归一化的旋转矢量乘以您的距离,然后将其添加到start
  • start当作一个向量,相加的结果就是你的新点

因为逆时针旋转(从当前点“向左”)被认为是正向,您需要反转 bearing 以便端口与负相关,右舷与正相关。

代码

import math
origX = 95485
origY = 729380

nextX = 95241
nextY = 729215

distance = 2000.0
bearing = 45

origVec = origX, origY
nextVec = nextX, nextY


#Euclidean distance between vectors (L2 norm)
dist = math.sqrt((nextVec[0] - origVec[0])**2 + (nextVec[1] - origVec[1])**2)

#Get a normalized difference vector
diffVec = (nextVec[0] - origVec[0])/dist, (nextVec[1] - origVec[1])/dist


#rotate our vector by bearing to get a vector from orig towards new point
#also, multiply by distance to get new value
#invert bearing, because +45 in math is counter-clockwise (left), not starboard
angle = math.radians(-bearing)

newVec = origVec[0]+(diffVec[0]*math.cos(angle) - diffVec[1]*math.sin(angle))*distance, \
         origVec[1]+(diffVec[0]*math.sin(angle) + diffVec[1]*math.cos(angle))*distance

print newVec

输出:

(93521.29597031244, 729759.2973553676)

【讨论】:

  • 当我对此进行测试时,它似乎没有给出我正在寻找的答案,但由于 beroe 的答案似乎有效,我没有调查原因。不过谢谢 - 你设法比我更优雅地解释了我的问题和解决方案。
  • @JakeHanson:感谢您的反馈。就我自己而言,我想知道我的程序无法使用的示例输入/输出,以便我可以改进这个答案。
  • 如果您查看我对 beroe 答案的评论,有一组示例值 - 不幸的是,beroe 给出的答案实际上似乎也不完全正确。我很高兴听到您从该示例中得到什么结果,您的版本给出的值对我来说似乎还有很长的路要走——我希望这些数字与开始和结束 xy 值处于相似的区域。再次感谢
  • 我更新了角度算法,它现在应该可以工作了...?
  • @JakeHanson:哎呀!看起来我做了nextVec[0] - origVec[1] 而不是nextVec[0] - origVec[0]!它现在应该工作得很好。
【解决方案3】:

(可能)有比这更优雅的解决方案...假设我正确理解了您的问题。但是,这将为您提供原始位置的方位:

(以硬编码输入为例)

import math

origX = 0.0
origY = 0.0

nextX = 1.0
nextY = 0.0

Dist = ((nextX - origX)**2 + (nextY - origY)**2)**0.5

if origX == nextX and origY == nextY:
    angle = 0

if origX == nextX and nextY < origY:
    angle = 180

if nextY < origY and origX > nextX:
    angle = math.degrees(math.asin((nextX -origX)/Dist)) - 90

if nextX > origX and nextY < origY:
    angle = math.degrees(math.asin((nextX -origX)/Dist)) + 90

else:
    angle = math.degrees(math.asin((nextX -origX)/Dist))

print angle

【讨论】:

  • 谢谢马特,这解决了我编辑的问题中的问题 1+2 - 我现在只需要根据这些信息找到点的新坐标 - 有什么想法吗?谢谢。
  • 这个函数被证明是有缺陷的。事实证明,atan2 是一种处理所有不同象限条件的简单方法......
猜你喜欢
  • 2010-10-27
  • 2011-05-30
  • 2017-12-22
  • 2016-01-05
  • 1970-01-01
  • 2012-05-18
  • 2020-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多