170 lines
4.7 KiB
Python
Executable File
170 lines
4.7 KiB
Python
Executable File
from decimal import Decimal, getcontext
|
|
from vector import Vector
|
|
|
|
getcontext().prec = 30
|
|
|
|
|
|
class MyDecimal(Decimal):
|
|
def is_near_zero(self, eps=1e-10):
|
|
return abs(self) < eps
|
|
|
|
|
|
class Line(object):
|
|
|
|
NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found'
|
|
|
|
def __init__(self, normal_vector=None, constant_term=None):
|
|
self.dimension = 2
|
|
|
|
if not normal_vector:
|
|
all_zeros = ['0'] * self.dimension
|
|
normal_vector = Vector(all_zeros)
|
|
self.normal_vector = normal_vector
|
|
|
|
if not constant_term:
|
|
constant_term = Decimal('0')
|
|
self.constant_term = Decimal(constant_term)
|
|
|
|
self.set_basepoint()
|
|
|
|
def set_basepoint(self):
|
|
try:
|
|
n = self.normal_vector
|
|
c = self.constant_term
|
|
basepoint_coords = ['0'] * self.dimension
|
|
|
|
initial_index = Line.first_nonzero_index(n)
|
|
initial_coefficient = n[initial_index]
|
|
basepoint_coords[initial_index] = c / initial_coefficient
|
|
self.basepoint = Vector(basepoint_coords)
|
|
|
|
except Exception as e:
|
|
if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG:
|
|
self.basepoint = None
|
|
else:
|
|
raise e
|
|
|
|
def __str__(self):
|
|
|
|
num_decimal_places = 3
|
|
|
|
def write_coefficient(coefficient, is_initial_term=False):
|
|
coefficient = round(coefficient, num_decimal_places)
|
|
if coefficient % 1 == 0:
|
|
coefficient = int(coefficient)
|
|
|
|
output = ''
|
|
|
|
if coefficient < 0:
|
|
output += '-'
|
|
if coefficient > 0 and not is_initial_term:
|
|
output += '+'
|
|
|
|
if not is_initial_term:
|
|
output += ' '
|
|
|
|
if abs(coefficient) != 1:
|
|
output += '{}'.format(abs(coefficient))
|
|
|
|
return output
|
|
|
|
n = self.normal_vector
|
|
|
|
try:
|
|
initial_index = Line.first_nonzero_index(n)
|
|
terms = [write_coefficient(n[i],
|
|
is_initial_term=(i == initial_index)) +
|
|
'x_{}'.format(i + 1)
|
|
for i in range(self.dimension)
|
|
if round(n[i], num_decimal_places) != 0]
|
|
output = ' '.join(terms)
|
|
|
|
except Exception as e:
|
|
if str(e) == self.NO_NONZERO_ELTS_FOUND_MSG:
|
|
output = '0'
|
|
else:
|
|
raise e
|
|
|
|
constant = round(self.constant_term, num_decimal_places)
|
|
if constant % 1 == 0:
|
|
constant = int(constant)
|
|
output += ' = {}'.format(constant)
|
|
|
|
return output
|
|
|
|
@staticmethod
|
|
def first_nonzero_index(iterable):
|
|
for k, item in enumerate(iterable):
|
|
if not MyDecimal(item).is_near_zero():
|
|
return k
|
|
raise Exception(Line.NO_NONZERO_ELTS_FOUND_MSG)
|
|
|
|
def is_parallel(self, line2):
|
|
return self.normal_vector.is_parallel(line2.normal_vector)
|
|
|
|
def __eq__(self, line2):
|
|
if self.normal_vector.is_zero():
|
|
if not line2.normal_vector.is_zero():
|
|
return False
|
|
|
|
diff = self.constant_term - line2.constant_term
|
|
return MyDecimal(diff).is_near_zero()
|
|
|
|
elif line2.normal_vector.is_zero():
|
|
return False
|
|
|
|
if not self.is_parallel(line2):
|
|
return False
|
|
|
|
basepoint_difference = self.basepoint.minus(line2.basepoint)
|
|
return basepoint_difference.is_orthogonal(self.normal_vector)
|
|
|
|
def intersection(self, line2):
|
|
|
|
a, b = self.normal_vector.coordinates
|
|
c, d = line2.normal_vector.coordinates
|
|
k1 = self.constant_term
|
|
k2 = line2.constant_term
|
|
denom = ((a * d) - (b * c))
|
|
|
|
if MyDecimal(denom).is_near_zero():
|
|
if self == line2:
|
|
return self
|
|
else:
|
|
return None
|
|
|
|
one_over_denom = Decimal('1') / ((a * d) - (b * c))
|
|
x_num = (d * k1 - b * k2)
|
|
y_num = (-c * k1 + a * k2)
|
|
|
|
return Vector([x_num, y_num]).times_scalar(one_over_denom)
|
|
|
|
|
|
# first system
|
|
# 4.046x + 2.836y = 1.21
|
|
# 10.115x + 7.09y = 3.025
|
|
|
|
line1 = Line(Vector([4.046, 2.836]), 1.21)
|
|
line2 = Line(Vector([10.115, 7.09]), 3.025)
|
|
|
|
print 'first system instersects in: {}'.format(line1.intersection(line2))
|
|
|
|
|
|
# second system
|
|
# 7.204x + 3.182y = 8.68
|
|
# 8.172x + 4.114y = 9.883
|
|
|
|
line3 = Line(Vector([7.204, 3.182]), 8.68)
|
|
line4 = Line(Vector([8.172, 4.114]), 9.883)
|
|
|
|
print 'second system instersects in: {}'.format(line3.intersection(line4))
|
|
|
|
# third system
|
|
# 1.182x + 5.562y = 6.744
|
|
# 1.773x + 8.343y = 9.525
|
|
|
|
line5 = Line(Vector([1.182, 5.562]), 6.744)
|
|
line6 = Line(Vector([1.773, 8.343]), 9.525)
|
|
|
|
print 'third system instersects in: {}'.format(line5.intersection(line6))
|