예제 #1
0
    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)
예제 #2
0
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)