根据距离和方位从样线移动xy坐标

1 投票
3 回答
8859 浏览
提问于 2025-04-18 00:01

我有一艘船在水面上移动,寻找动物。船上有一个人站在船顶,面朝前方,当看到动物时,他会记录下船与动物之间的距离和方向。我有这些信息,还有在看到动物时船的xy坐标。我需要根据这些信息计算出动物的xy坐标。

不过,我没有船的原始方向,这让事情变得有些复杂;但我有船下一个GPS(xy)坐标,这样我可以计算出一个起始角度。然后,我可以根据看到动物时的方向来加或减这个角度,从而得到一个标准化的角度,这个角度可以用来通过三角函数找到动物的xy坐标。不幸的是,我的数学水平还不够好,无法完成这个任务。

我有几百个点,所以我需要把这个过程写成一个Python脚本,来处理所有的点。

总的来说,数据集中包含:

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

编辑:抱歉,我刚才说得不太清楚。

我认为这个问题可以分为三个阶段。

  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)

提前感谢任何帮助!

3 个回答

0

这可能有更简单优雅的解决办法……前提是我理解你的问题没错。不过,这段代码可以帮你找到从你原来的位置到目标位置的方向:

(这里的输入是硬编码的,作为示例)

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
3

马特的函数有点问题,所以我用了 atan2 来帮你计算船的航向角度。

补充说明:这比我想的要复杂。最后你需要减去90度,并取反,这样才能把地理角度转换成三角函数角度。

(还有一个 angles 库(可能还有其他地理相关的库)里面已经有这个功能了。)

现在这个过程是这样的:它取 origXorigY,找到三角函数角度,然后把它转换成 heading,再把航向加到为横断面确定的角度上。接着,它会根据距离进行三角函数计算,但使用的是转换回三角函数度数的角度 -(X-90)。这有点复杂,因为我们习惯把 0 度看作北方/上方,但在三角函数中是“向右”,而且三角函数是逆时针的,而导航是顺时针的。

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)

在这里输入图片描述 添加路径

2

根据我的理解,你的问题是这样的:

  • 你有两个点,startnext,你在这两个点之间移动。
  • 你想找到一个第三个点,New,这个点应该在距离 start 一定的距离和方向上,而你已经是从 start 指向 next 的方向。

我的解决方法是这样的:

  • 先从 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)

撰写回答