14

私は空間分析の問題に取り組んでおり、このワークフローの一部は、接続された線分の間の角度を計算することです。

各線分は 2 つの点のみで構成され、各点には 1 対の XY 座標 (直交座標) があります。これは GeoGebra からの画像です。0 から 180 の範囲で正の角度を取得することに常に関心があります。ただし、入力線分の頂点の順序に応じて、あらゆる種類の角度を取得します。

ここに画像の説明を入力

私が扱う入力データは、座標のタプルとして提供されます。頂点の作成順序によっては、各ライン セグメントの最終/終点が異なる場合があります。Python コードでのケースのいくつかを次に示します。取得する線分の順序はランダムですが、タプルのタプルでは、​​最初の要素が始点で、2 番目の要素が終点です。DEたとえば、線分は((1,1.5),(2,2))(1,1.5)座標のタプルの最初の位置にあるため、始点になります。

DE,DFただし、間などで同じ角度になるようにする必要がありED,DFます。

vertexType = "same start point; order 1"
            #X, Y    X Y coords
lineA = ((1,1.5),(2,2)) #DE
lineB = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "same start point; order 2"
lineB = ((1,1.5),(2,2)) #DE
lineA = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)

vertexType = "same end point; order 1"
lineA = ((2,2),(1,1.5)) #ED
lineB = ((2.5,0.5),(1,1.5)) #FE
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "same end point; order 2"
lineB = ((2,2),(1,1.5)) #ED
lineA = ((2.5,0.5),(1,1.5)) #FE
calcAngle(lineA, lineB,vertexType)

vertexType = "one line after another - down; order 1"
lineA = ((2,2),(1,1.5)) #ED
lineB = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "one line after another - down; order 2"
lineB = ((2,2),(1,1.5)) #ED
lineA = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)

vertexType = "one line after another - up; line order 1"
lineA = ((1,1.5),(2,2)) #DE
lineB = ((2.5,0.5),(1,1.5)) #FD
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "one line after another - up; line order 2"
lineB = ((1,1.5),(2,2)) #DE
lineA = ((2.5,0.5),(1,1.5)) #FD
calcAngle(lineA, lineB,vertexType)

線の組み合わせを引数として取り、それらの間の角度を計算する小さな関数を作成しました。私はmath.atan2これに最も適していると思われる を使用しています。

def calcAngle(lineA,lineB,vertexType):
    line1Y1 = lineA[0][1]
    line1X1 = lineA[0][0]
    line1Y2 = lineA[1][1]
    line1X2 = lineA[1][0]

    line2Y1 = lineB[0][1]
    line2X1 = lineB[0][0]
    line2Y2 = lineB[1][1]
    line2X2 = lineB[1][0]

    #calculate angle between pairs of lines
    angle1 = math.atan2(line1Y1-line1Y2,line1X1-line1X2)
    angle2 = math.atan2(line2Y1-line2Y2,line2X1-line2X2)
    angleDegrees = (angle1-angle2) * 360 / (2*math.pi)
    print angleDegrees, vertexType

私が得る出力は次のとおりです。

> -299.744881297 same start point; order 1
> 299.744881297 same start point; order 2
> 60.2551187031 same end point; order 1
> -60.2551187031 same end point; order 2
> -119.744881297 one line after another - down; order 1
> 119.744881297 one line after another - down; order 2
> -119.744881297 one line after another - up; line order 1
> 119.744881297 one line after another - up; line order 2

ご覧のとおり、線分の頂点の順序と線分の順序によって異なる値を取得しています。ソース行がどのような関係にあるかを調べて、行を反転させたり、角度を編集したりして、角度を後処理しようとしました。 -119.744 を 60.255 (鋭角) にするべきか、119.744 (鈍角) のままにするべきかなど、もはや判断できません。

math.atan2受け取った出力角度値を処理して、0 から 180 の範囲の正の値のみを取得する個別の方法はありますか? そうでない場合、他にどのようなアプローチをとるべきですか?

4

3 に答える 3

19

この問題を解決する最も簡単な方法は、内積を使用することです。

このコードを試してください (私は実質的にすべてにコメントしました):

import math

def dot(vA, vB):
    return vA[0]*vB[0]+vA[1]*vB[1]

def ang(lineA, lineB):
    # Get nicer vector form
    vA = [(lineA[0][0]-lineA[1][0]), (lineA[0][1]-lineA[1][1])]
    vB = [(lineB[0][0]-lineB[1][0]), (lineB[0][1]-lineB[1][1])]
    # Get dot prod
    dot_prod = dot(vA, vB)
    # Get magnitudes
    magA = dot(vA, vA)**0.5
    magB = dot(vB, vB)**0.5
    # Get cosine value
    cos_ = dot_prod/magA/magB
    # Get angle in radians and then convert to degrees
    angle = math.acos(dot_prod/magB/magA)
    # Basically doing angle <- angle mod 360
    ang_deg = math.degrees(angle)%360
    
    if ang_deg-180>=0:
        # As in if statement
        return 360 - ang_deg
    else: 
        
        return ang_deg

lineA と lineB のバリエーションを試してみると、すべて同じ答えが得られるはずです。

于 2015-02-01T09:28:28.323 に答える
3

働き過ぎ。2 つのベクトルをそれぞれの線の長さで割った内積の逆余弦の絶対値をとります。

于 2015-02-01T08:56:06.590 に答える