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 = 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.coordinates 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 is_parallel(self, vector2): return self.normal_vector.is_parallel_to(vector2.normal_vector) def __eq__(self, vector2): if self.normal_vector.is_zero(): if not vector2.normal_vector.is_zero(): return False else: diff = self.constant_term - vector2.constant_term return MyDecimal(diff).is_near_zero() elif vector2.normal_vector.is_zero(): return False # consists of the same set of points if not self.is_parallel(vector2): return False direction_vector = self.basepoint - vector2.basepoint return direction_vector.is_orthogonal(self.normal_vector) def intersects(self, vector2): if(self == vector2): return 'The lines are equal, so there are infinite intersections.' if(self.is_parallel(vector2) and not self == vector2): return 'No intersection! The lines are parallel to each other.' A, B = self.normal_vector.coordinates C, D = vector2.normal_vector.coordinates k1 = self.constant_term k2 = vector2.constant_term x = ((D * k1) - (B * k2)) / ((A * D) - (B * C)) y = ((-C * k1) + (A * k2)) / ((A * D) - (B * C)) return Vector([x,y]) 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.coordinates 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)
class Plane(object): NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found' def __init__(self, normal_vector=None, constant_term=None): self.dimension = 3 if not normal_vector: all_zeros = ['0']*self.dimension normal_vector = Vector(all_zeros) self.normal_vector = 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.coordinates c = self.constant_term basepoint_coords = ['0']*self.dimension initial_index = Plane.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) == Plane.NO_NONZERO_ELTS_FOUND_MSG: self.basepoint = None else: raise e def is_parallel(self, plane): return self.normal_vector.is_parallel_to(plane.normal_vector) def __eq__(self, plane): if self.normal_vector.is_zero(): if not plane.normal_vector.is_zero(): return False else: diff = self.constant_term - plane.constant_term return MyDecimal(diff).is_near_zero() elif plane.normal_vector.is_zero(): return False if not self.is_parallel(plane): return False direction_vector = self.basepoint - plane.basepoint return direction_vector.is_orthogonal(self.normal_vector) 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.coordinates try: initial_index = Plane.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(Plane.NO_NONZERO_ELTS_FOUND_MSG)