title: Calculating angles between line segments (Python) with math.atan2
body: <p>I am working on a spatial analysis problem and part of this workflow is to calculate the angle between connected line segments.</p>
  
  <p>Each line segment is composed of only two points, and each point has a pair of XY coordinates (Cartesian). Here is the image from GeoGebra. <strong>I am always interested in getting a positive angle in 0 to 180 range</strong>. However, I get all kind of angles depending on the order of vertices in input line segments.</p>
  
  <p><img src="https://i.stack.imgur.com/iSNAq.png" alt="enter image description here"></p>
  
  <p>The input data I work with is provided as tuples of coordinates. Depending on the vertex creation order, the last/end point for each line segment can be different. Here are some of the cases in Python code. The order of line segments in which I get them is random, but in a tuple of tuples, the first element is the start point and the second one is the end point. <code>DE</code> line segment, for instance, would have <code>((1,1.5),(2,2))</code> and the <code>(1,1.5)</code> is the start point because it has the first position in the tuple of coordinates.</p>
  
  <p>I however need to make sure I will get the same angle between <code>DE,DF</code> and <code>ED,DF</code> and so forth.</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>I have written a tiny function that takes combinations of the lines as args and calculates the angle between them. I am using the <code>math.atan2</code> which seemed to be best suited for this. </p>
  
  <pre><code>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
  </code></pre>
  
  <p>The output I get is:</p>
  
  <pre><code>&gt; -299.744881297 same start point; order 1
  &gt; 299.744881297 same start point; order 2
  &gt; 60.2551187031 same end point; order 1
  &gt; -60.2551187031 same end point; order 2
  &gt; -119.744881297 one line after another - down; order 1
  &gt; 119.744881297 one line after another - down; order 2
  &gt; -119.744881297 one line after another - up; line order 1
  &gt; 119.744881297 one line after another - up; line order 2
  </code></pre>
  
  <p>As you can see, I am getting different values depending on the order of vertices in a line segment and line segments order. I have tried to post-process the angles by finding out what kind of relation the source line had and flipping the lines, editing the angle etc. I've ended with a dozen of such cases and at some point they start to overlap and I cannot any longer find out whether -119.744 should become 60.255 (acute angle) or be left as 119.744 (obtuse angle) etc.</p>
  
  <p><strong>Is there any discrete way to process the output angle values I receive from <code>math.atan2</code> to get only a positive value in 0 to 180 range?</strong> <strong>If not, what kind of other approach should I take?</strong></p>