def intersect(self, line: Line) -> float: point_a = self.__points[0] point_b = self.__points[1] point_c = self.__points[2] # degenerate line: 0x + 0y + 0 = 0, so it is point try: deviation_a = line.normalize().get_deviation(point_a[0], point_a[1]) deviation_b = line.normalize().get_deviation(point_b[0], point_b[1]) deviation_c = line.normalize().get_deviation(point_c[0], point_c[1]) except ZeroDivisionError: return 0 # line goes throw a vertex of triangle for point in self.__points: if line.contains_point(point[0], point[1]): other_points = list(set(self.__points) - {point}) intersection_point = line.intersect_with_line(Line(other_points[0][0], other_points[0][1], other_points[1][0], other_points[1][1])) return ((point[0] + intersection_point[0]) ** 2 + (point[1] + intersection_point[1]) ** 2) ** (1 / 2) # the line goes throw two sides of triangle new_points = [] if deviation_a * deviation_b < 0: proportionality_coefficient = abs(deviation_a / deviation_b) x = (point_a[0] + proportionality_coefficient * point_b[0]) / (1 + proportionality_coefficient) y = (point_a[1] + proportionality_coefficient * point_b[1]) / (1 + proportionality_coefficient) new_points.append((x, y)) if deviation_a * deviation_c < 0: proportionality_coefficient = abs(deviation_a / deviation_c) x = (point_a[0] + proportionality_coefficient * point_c[0]) / (1 + proportionality_coefficient) y = (point_a[1] + proportionality_coefficient * point_c[1]) / (1 + proportionality_coefficient) new_points.append((x, y)) if deviation_b * deviation_c < 0: proportionality_coefficient = abs(deviation_b / deviation_c) x = (point_b[0] + proportionality_coefficient * point_c[0]) / (1 + proportionality_coefficient) y = (point_b[1] + proportionality_coefficient * point_c[1]) / (1 + proportionality_coefficient) new_points.append((x, y)) # the line doesn't cross triangle if len(new_points) < 2: return 0 point1 = new_points[0] point2 = new_points[1] return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** (1 / 2)
class Vector(object): def __init__(self, pos, direction): self.beginning_point = pos self.direction = direction self.angle = math.atan2(direction[1], direction[0]) #angle from horizontal self.terminating_point = (self.beginning_point[0] + self.direction[0], self.beginning_point[1] + self.direction[1]) self.magnitude = (self.direction[0]**2 + self.direction[1]**2)**(1 / 2) self.line = Line( pos, Line.find_slope(self.beginning_point, self.terminating_point)) def __repr__(self): return f"""\ Vector {(int(self.direction[0]), int(self.direction[1]))} \ at {(int(self.beginning_point[0]), int(self.beginning_point[1]))} \ """ @staticmethod def get_unit_vector(vector): if math.isclose(vector.magnitude, 1): #already a unit vector return vector else: unit_direction = (vector.direction[0] / vector.magnitude, vector.direction[1] / vector.magnitude) return Vector((0, 0), unit_direction) #center unit vectors at the origin def angle_to( self, vector, counter_clockwise=True ): #calculates the angle to vector going counter-clockwise (unless specified otherwise) angle = vector.angle - self.angle if counter_clockwise and angle < 0: angle = math.pi * 2 + angle elif not counter_clockwise and angle < 0: angle = abs(angle) elif not counter_clockwise: angle = math.pi * 2 - angle return angle def point_in_domain_and_range(self, point): (x, y) = point (x0, y0) = self.beginning_point (x1, y1) = self.terminating_point if (min(x0, x1) <= x <= max(x0, x1) and min(y0, y1) <= y <= max(y0, y1)): return True elif ((math.isclose(x0, x, abs_tol=1e-7) and math.isclose(y0, y, abs_tol=1e-7)) or (math.isclose(x1, x, abs_tol=1e-7) and math.isclose(y1, y, abs_tol=1e-7))): return True else: return False def contains_point(self, point): if self.line.contains_point(point) and self.point_in_domain_and_range( point): return True else: return False def intersects(self, other): if isinstance(other, Vector): if self.line.intersects(other.line): intersection = self.line.intersection(other.line) if (self.point_in_domain_and_range(intersection) and other.point_in_domain_and_range(intersection)): return True elif isinstance(other, Line): if self.line.intersects(other): intersection = self.line.intersection(other) if self.point_in_domain_and_range(intersection): return True return False def intersection(self, other): if isinstance(other, Line): if self.line.intersects(other): intersection = self.line.intersection(other) if self.point_in_domain_and_range(intersection): return intersection return None elif isinstance(other, Vector): return self.line.intersection(other.line)