2015-02-01 29 views
6

Ich arbeite an einem räumlichen Analyseproblem, und ein Teil dieses Arbeitsablaufs besteht darin, den Winkel zwischen verbundenen Liniensegmenten zu berechnen.Berechnen von Winkeln zwischen Liniensegmenten (Python) mit math.atan2

Jedes Liniensegment besteht aus nur zwei Punkten und jeder Punkt hat ein Paar XY-Koordinaten (kartesisch). Hier ist das Bild von GeoGebra. Ich bin immer daran interessiert, einen positiven Winkel in 0 bis 180 Bereich zu bekommen. Ich bekomme jedoch alle möglichen Winkel abhängig von der Reihenfolge der Scheitelpunkte in den Eingabezeilensegmenten.

enter image description here

Die Eingangsdaten I mit Arbeit ist als Tupel von Koordinaten vorgesehen sind. Abhängig von der Scheitelpunkt-Erstellungsreihenfolge kann der letzte/Endpunkt für jedes Liniensegment unterschiedlich sein. Hier sind einige Fälle in Python-Code. Die Reihenfolge der Liniensegmente, in denen ich sie erhalte, ist zufällig, aber in einem Tupel-Tupel ist das erste Element der Startpunkt und das zweite Element ist der Endpunkt. 10 Liniensegment zum Beispiel hätte ((1,1.5),(2,2)) und (1,1.5) ist der Startpunkt, weil es die erste Position im Koordinaten-Tupel hat.

Ich muss jedoch sicherstellen, dass ich den gleichen Winkel zwischen DE,DF und ED,DF und so weiter bekomme.

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) 

Ich habe eine winzige Funktion geschrieben, die Kombinationen der Zeilen als Argumente akzeptiert und den Winkel zwischen ihnen berechnet. Ich benutze die math.atan2, die dafür am besten geeignet schien.

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 

Der Ausgang ich erhalte, ist:

> -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 

Wie Sie sehen können, bin ich unterschiedliche Werte immer in einem Liniensegment und Liniensegmente, um in der Größenordnung von Eckpunkten abhängig. Ich habe versucht, die Winkel nachzubearbeiten, indem ich herausgefunden habe, welche Art von Beziehung die Quelllinie hatte und die Linien änderte, den Winkel änderte usw. Ich habe mit einem Dutzend solcher Fälle geendet und irgendwann beginnen sie sich zu überlappen und ich kann nicht, ob -119,744 herausfinden, mehr sollte 60,255 (spitzer Winkel) oder gelassen werden, da 119,744 (stumpfer Winkel) wird usw.

gibt es eine diskrete Art und Weise die Ausgangswinkelwert I erhalten von math.atan2 bekommen nur einen zu verarbeiten positiver Wert im Bereich von 0 bis 180?Wenn nicht, welche Art von anderen Ansatz sollte ich nehmen?

Antwort

6

Der einfachste und logischste Weg, um dieses Problem zu lösen, ist die Verwendung des Dot-Produkts.

Versuchen Sie diesen Code (Ich habe praktisch alles kommentiert):

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 

Versuchen Sie nun Variationen von LINEA und lineB und alle sollten die gleiche Antwort geben.

+0

Der Kern des Test-Code und Ausgabe ist [hier] (https://gist.github.com/abhinavrk/2100332f7d7f4c127b8c) –

+0

danke für das Code-Snippet, groß, um mit zu beginnen. Das Problem mit dem Code ist, dass er keine stumpfen Winkel meldet (> 90). Versuchen Sie sich mit der '' lineA = ((0.6,3,6), (1,6,3)) lineB = ((1,6,3), (2,3,6)) ". Es meldet 87,27, sollte aber 92,73 sein. Was könnte getan werden, um das zu beheben? –

+0

Ich habe meinen Beitrag bearbeitet. Ich glaube, ich habe es behoben, um auch stumpfe Winkel zu geben. Schau mal. –

1

Zu viel Arbeit. Nimm den absoluten Wert des Arccosins der dot product der beiden Vektoren, dividiert durch jede der Längen der Linien.