martes, 16 de septiembre de 2014

Standard form of a line given 2 points

Formula derivation

The Standard equation of a line is a way to represent a 2D line with the following form: $Ax+By=C$

Given two cartesian coordinates in the 2D space, one can calculate the line that intersects both points $(x_1, y_1)$ and $(x_2, y_2)$. To derivate the coefficients A, B and C of the standard equation, I will start with the equation of a straight line that intersects the point $(x_1, y_1)$ and has a slope $m$:
$y - y_1 = m(x - x_1)$ (eq. 1).

The problem with this representation is that the slope $m$  is defined as the change in 'y' with respect to the change in 'x' as $m=\frac{\Delta Y}{\Delta X}=\frac{y_2 - y_1}{x_2 - x_1}$. In the case of vertical lines $x_2 - x_1=0$ and that would undefine the slope for them.

With this context, let us find a more generic representation that can handle vertical lines. Given (eq. 1) we have the following:
$y - y_1 = mx - mx_1$(eq. 2)
$y - mx = y_1 - mx_1$(eq. 3)
The magic trick is to assign A and B as the numerator and denominator of the slope:
$m = \frac{y_2 - y_1}{x_2 - x_1} = \frac{-A}{B}$ (eq. 4)
Then, substitute (eq. 4) in (eq. 3) and do some algebra:
$y - \left( \frac{-A}{B}\right)x = y_1 - \left( \frac{-A}{B}\right)x_1$
$\frac{A}{B}x + y = y_1 + \frac{A}{B}x_1$
$Ax + By = B(y_1 + \frac{A}{B}x_1)$
$Ax + By = By_1 + Ax_1$
Finally, if we rename the right hand side of the equation, the constant side, $C$, we'll have:
$Ax + By = C$
For the constants:
$A = y_1 - y_2$
$B = x_2 - x_1$
$C = Ax_1 + By_1$

Python 3.4 code


# Standard Form of a line Ax + By = C
#-------------------------------
# inputs: Two 2D points in the format: x-value, y-value
# output: The standard form equation of the line 
#         that passes through those points
# by IF, 9.16.2014
#-------------------------------
import unittest

# GLOBAL VARIABLES
#----------------------
answer = 'y'
err = 0;

# FUNCTIONS
#----------------------
def printAnswer():
 print('')
 if (B >= 0):
  print(str(round(A,2)) + "x+" + str(round(B,2)) + "y" " = " + str(round(C,2)))
 if (B < 0):
  print(str(round(A,2)) + "x" + str(round(B,2)) + "y" " = " + str(round(C,2)))
 print('')
 
def parseCoords(p):
 global err
 
 # split by comma
 coordList = p.split(',')
 
 # validate for 2D coordinates
 if (len(coordList) != 2):
  err = 2
  return
 # validate numeric input
 try:
  x = float(coordList[0])
 except ValueError:  
  x = 0
  err = 1
 try:
  y = float(coordList[1])
 except ValueError:
  y = 0
  err = 1
 return x, y, err

# From http://stackoverflow.com/questions/11175131/code-for-greatest-common-divisor-in-python
def GCD(a, b):
 if b == 0:
  return a
 else:
  return GCD(b, a % b)
 
def simplifyEq(a,b,c):
 # check if they are all integers
 global A, B, C
 if ( a%1 == 0 and b%1 == 0 and c%1 == 0):
  a = int(a)
  b = int(b)
  c = int(c)
  
  gcd = GCD(a,GCD(b,c))
  if (gcd <= 1):
   return
  else:
   A = A/gcd;
   B = B/gcd;
   C = C/gcd;
   return
 
# ------------------
# MAIN FUNCTION
#-------------------
while(answer == 'y'):
 # read input from user
 p = input("Enter 1st point in the format x1,y1: ")
 p = parseCoords(p)
 
 if(err == 1):
  print("Error 1: Values must be numbers separated by a comma")
  print("Format: x,y")
 elif(err == 2):
  print("Error 2: Only two values are accepted")
  print("Format: x,y")
 else:
  x1 = p[0]
  y1 = p[1]
 
  p = input("Enter 2nd point in the format x2,y2: ")
  p = parseCoords(p)
  if(err == 1):
   print("Error 1: Values must be numbers separated by a comma")
   print("Format: x,y")
  elif(err == 2):
   print("Error 2: Only two values are accepted")
   print("Format: x,y")
  else:
   x2 = p[0]
   y2 = p[1]
  
   # For the derivation go to:http://howdidisolvedit.blogspot.ca/2014/09/standard-form-of-line-given-2-points.html
   A = y1 - y2
   B = x2 - x1
   C = A*x1 + B*y1
   
   # can the coefficients be simplified?
   simplifyEq(A,B,C)
   
   printAnswer()
 
 answer = input("Test again? [y/n]: ")
 if (answer == 'y'):
  err = 0

# TESTING
# --------------------  
class MyTest(unittest.TestCase):
 def test_GCD(self):
  self.assertEqual(GCD(144,12),12)
 
 def test_simplifyEq(self):
  raised = False
  try:
   simplifyEq(0,0,0)
  except:
   raised = True
  self.assertFalse(raised, 'Exception rised')
  
if __name__ == '__main__':
 unittest.main()

Upload of python and Google App Engine

http://stdlines.appspot.com/

Further info on Python + Google App Engine. Uploaded by Stefano Locati:
https://www.youtube.com/watch?v=j7OQZp2S5pY

No hay comentarios:

Publicar un comentario