def set_basepoint(self): try: n = self.normal_vector c = self.constant_term base_point_coordinates = [0.0] * self.dimension initial_index = Line.first_nonzero_index(n) initial_coefficient = n[initial_index] base_point_coordinates[initial_index] = c / initial_coefficient self.base_point = Vector(base_point_coordinates) except Exception as e: if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG: self.base_point = None else: raise e
def get_intersection(self, ln): if self.normal_vector.is_zero() or ln.normal_vector.is_zero(): return None if self.is_parallel(ln): if self.is_coincident(ln, True): raise Exception(self.COINCIDENT_VECTOR) else: return None a, b = self.normal_vector.coordinates c, d = ln.normal_vector.coordinates k1 = self.constant_term k2 = ln.constant_term base = a * d - b * c x = (d * k1 - b * k2) / base y = (-c * k1 + a * k2) / base return Vector([x, y])
def boundedMoveVertex(self, pos): index, shape = self.hVertex, self.hShape point = shape[index] if self.outOfPixmap(pos): size = self.pixmap.size() clipped_x = min(max(0, pos.x()), size.width()) clipped_y = min(max(0, pos.y()), size.height()) pos = QPointF(clipped_x, clipped_y) opposite_point_index = (index + 2) % 4 o_to_pos_vector = Vector(shape[opposite_point_index], pos) o_to_prev_vector = Vector(shape[opposite_point_index], shape[(index + 3) % 4]) o_to_next_vector = Vector(shape[opposite_point_index], shape[(index + 1) % 4]) if self.drawSquare: opposite_point = shape[opposite_point_index] min_size = min(abs(pos.x() - opposite_point.x()), abs(pos.y() - opposite_point.y())) directionX = -1 if pos.x() - opposite_point.x() < 0 else 1 directionY = -1 if pos.y() - opposite_point.y() < 0 else 1 shiftPos = QPointF( opposite_point.x() + directionX * min_size - point.x(), opposite_point.y() + directionY * min_size - point.y()) else: o_to_pos_mag = o_to_pos_vector.magnitude() o_to_prev_mag = o_to_prev_vector.magnitude() o_to_next_mag = o_to_next_vector.magnitude() o_to_pos_u_vector = QPointF(o_to_pos_vector.x / o_to_pos_mag, o_to_pos_vector.y / o_to_pos_mag) o_to_prev_u_vector = QPointF(o_to_prev_vector.x / o_to_prev_mag, o_to_prev_vector.y / o_to_prev_mag) o_to_next_u_vector = QPointF(o_to_next_vector.x / o_to_next_mag, o_to_next_vector.y / o_to_next_mag) if o_to_pos_u_vector.x() == o_to_prev_u_vector.x( ) and o_to_pos_u_vector.y() == o_to_prev_u_vector.y(): pos = pos + o_to_next_u_vector if o_to_pos_u_vector.x() == o_to_next_u_vector.x( ) and o_to_pos_u_vector.y() == o_to_next_u_vector.y(): pos = pos + o_to_prev_u_vector shiftPos = pos - point point_to_pos_vector = Vector(point, pos) prev_proj = point_to_pos_vector.projection(o_to_prev_vector) next_proj = point_to_pos_vector.projection(o_to_next_vector) prev_shiftPos = QPointF(o_to_prev_vector.x * prev_proj, o_to_prev_vector.y * prev_proj) next_shiftPos = QPointF(o_to_next_vector.x * next_proj, o_to_next_vector.y * next_proj) shape.moveVertexBy(index, shiftPos) shape.moveVertexBy((index + 3) % 4, prev_shiftPos) shape.moveVertexBy((index + 1) % 4, next_shiftPos)
class Line(object): NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found' COINCIDENT_VECTOR = 'Vector is coincident' dimension = 2 normal_vector = Vector([0.0] * dimension) constant_term = 0.0 base_point = None def __init__(self, normal_vector=None, constant_term=None): self.normal_vector = normal_vector self.constant_term = constant_term self.set_basepoint() def __eq__(self, other): if self.normal_vector.is_zero(): if other.normal_vector.is_zero(): return self.constant_term == other.constant_term else: return False elif other.normal_vector.is_zero(): return False else: return self.is_coincident(other) def set_basepoint(self): try: n = self.normal_vector c = self.constant_term base_point_coordinates = [0.0] * self.dimension initial_index = Line.first_nonzero_index(n) initial_coefficient = n[initial_index] base_point_coordinates[initial_index] = c / initial_coefficient self.base_point = Vector(base_point_coordinates) except Exception as e: if str(e) == Line.NO_NONZERO_ELTS_FOUND_MSG: self.base_point = None else: raise e def is_parallel(self, ln): return self.normal_vector.is_parallel(ln.normal_vector) def get_intersection(self, ln): if self.normal_vector.is_zero() or ln.normal_vector.is_zero(): return None if self.is_parallel(ln): if self.is_coincident(ln, True): raise Exception(self.COINCIDENT_VECTOR) else: return None a, b = self.normal_vector.coordinates c, d = ln.normal_vector.coordinates k1 = self.constant_term k2 = ln.constant_term base = a * d - b * c x = (d * k1 - b * k2) / base y = (-c * k1 + a * k2) / base return Vector([x, y]) def is_coincident(self, ln, is_parallel_proven=False): if not is_parallel_proven: is_parallel_proven = self.is_parallel(ln) if not is_parallel_proven: return False two_base_points = self.base_point.minus(ln.base_point) return two_base_points.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 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 float_is_zero(item): return k raise Exception(Line.NO_NONZERO_ELTS_FOUND_MSG)
from libs.vector import Vector from libs.plane import Plane from libs.linsys import LinearSystem p0 = Plane(normal_vector=Vector([1, 1, 1]), constant_term=1) p1 = Plane(normal_vector=Vector([0, 1, 0]), constant_term=2) p2 = Plane(normal_vector=Vector([1, 1, -1]), constant_term=3) p3 = Plane(normal_vector=Vector([1, 0, -2]), constant_term=2) s = LinearSystem([p0, p1, p2, p3]) s.swap_rows(0, 1) if not (s[0] == p1 and s[1] == p0 and s[2] == p2 and s[3] == p3): print('test case 1 failed') s.swap_rows(1, 3) if not (s[0] == p1 and s[1] == p3 and s[2] == p2 and s[3] == p0): print('test case 2 failed') s.swap_rows(3, 1) if not (s[0] == p1 and s[1] == p0 and s[2] == p2 and s[3] == p3): print('test case 3 failed') s.multiply_coefficient_and_row(1, 0) if not (s[0] == p1 and s[1] == p0 and s[2] == p2 and s[3] == p3): print('test case 4 failed') s.multiply_coefficient_and_row(-1, 2) if not (s[0] == p1 and s[1] == p0 and s[2] == Plane( normal_vector=Vector([-1, -1, 1]), constant_term=-3) and s[3] == p3): print('test case 5 failed')
class Plane(object): NO_NONZERO_ELTS_FOUND_MSG = 'No nonzero elements found' dimension = 3 normal_vector = Vector([0.0] * dimension) constant_term = 0.0 basepoint = Vector([0.0] * dimension) def __init__(self, normal_vector=None, constant_term=None): if normal_vector: self.normal_vector = normal_vector if constant_term: self.constant_term = constant_term self.set_basepoint() def set_basepoint(self): try: n = self.normal_vector c = self.constant_term basepoint_coords = [0.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 __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 = 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 def is_parallel(self, pl): return self.normal_vector.is_parallel(pl.normal_vector) def __eq__(self, other): if self.normal_vector.is_zero(): if other.normal_vector.is_zero(): return self.constant_term == other.constant_term else: return False elif other.normal_vector.is_zero(): return False elif not self.is_parallel(other): return False else: test_vector = self.basepoint.minus(other.basepoint) return test_vector.is_orthogonal(self.normal_vector) @staticmethod def first_nonzero_index(iterable): for k, item in enumerate(iterable): if not float_is_zero(item): return k raise Exception(Plane.NO_NONZERO_ELTS_FOUND_MSG)