def intersection_count(self, line_segment: LineSegment) -> Tuple[int, bool]: """ HELPER: Determines number of times that LineSegment object intersects with polygon (self) Args: line_segment: LineSegment object Returns: tuple consisting of int and bool. int is number of intersections, bool is True if point "lies" on one of the edges of the polygon """ intersections_counter, on_edge = 0, False points_count = len(self.points) for i in range(0, points_count): first = self.points[i % points_count] second = self.points[(i + 1) % points_count] current_line_segment = LineSegment(first=first, second=second) if current_line_segment.does_contain(line_segment.first): on_edge = True if current_line_segment.does_intersect_or_touch(line_segment): intersections_counter += 1 return intersections_counter, on_edge
def find_pair_edge(triangulation: Triangulation, edge: LineSegment) -> Tuple[LineSegment, List[Triangle]]: """ For edge that is diagonal of a convex quadrilateral in triangulation, finds other diagonal of that quadrilateral. Args: triangulation: Current triangulation edge: Some non frontier edge in triangulation. Returns: Other diagonal if quadrilateral is convex, edge if it is concave. """ faces = [] for triangle in triangulation.triangles: if edge in triangle.get_sides() or edge.reversed() in \ triangle.get_sides(): faces.append(triangle) if len(faces) != 2: return edge, faces endpoints = [] for triangle in faces: for point in triangle.get_points(): if not edge.does_contain(point): endpoints.append(point) return LineSegment(endpoints[0], endpoints[1]), faces
def test_pick_start_segment() -> None: """ Tests if pick_start_segment works correctly. One common and one edge case. """ hex_1 = Polygon([ Point(0, 0), Point(1, -1), Point(2, 0), Point(2, 1), Point(1, 2), Point(0, 1) ]) hex_2 = Polygon([ Point(0, 0), Point(1, 0), Point(2, 0), Point(2, 1), Point(1, 2), Point(0, 1) ]) assert pick_start_segment(hex_1) == LineSegment(Point(0, 0), Point(1, -1)) assert pick_start_segment(hex_2) == LineSegment(Point(2, 0), Point(2, 1))
def test_find_pair_edge() -> None: """ Tests if find pair edge method works correctly. """ a, b, c, d = [Point(4, 3), Point(-1, 2), Point(1, 1), Point(2, 1)] triangles = [Triangle(b, c, d), Triangle(b, a, d)] triangulation = Triangulation(triangles) pair = find_pair_edge(triangulation, LineSegment(b, d)) assert pair == (LineSegment(c, a), triangles)
def get_sides(self) -> List[LineSegment]: """ Gets segments of self as a list of three elements. Returns: List of three LineSegments. """ return [ LineSegment(self.first, self.second), LineSegment(self.second, self.third), LineSegment(self.third, self.first) ]
def line_segs() -> None: first = LineSegment(points[0], points[1]) second = LineSegment(points[2], points[3]) first.draw(canvas) second.draw(canvas) if first.does_intersect_or_touch(second): messagebox.showinfo("Result", "Segments DO intersect") else: messagebox.showinfo("Result", "Segments DO NOT intersect")
def test__eq__() -> None: """ Tests if overriden __eq__ method works correctly """ point_1 = Point(1, 2) point_2 = Point(-2, -4) point_3 = Point(3, 3) point_4 = Point(0, 0) line_segment_1 = LineSegment(first=point_1, second=point_2) line_segment_2 = LineSegment(first=point_1, second=point_2) line_segment_3 = LineSegment(first=point_3, second=point_4) assert line_segment_1 == line_segment_2 assert not line_segment_1 == line_segment_3
def draw(self, canvas) -> None: """ Draws polygon object onto the canvas.Takes translation into consideration. Args: canvas: Canvas object on which line segment will be drawn to. """ first = self.points[0] for i in range(0, len(self.points) - 1): LineSegment(self.points[i], self.points[i + 1]).draw(canvas) LineSegment(self.points[-1], first).draw(canvas)
def test_contains_point() -> None: """ Tests if contains_point determines relationship between line_segment and point correctly. Tests both common and edge cases. """ point_1 = Point(1, 2) point_2 = Point(-2, -4) point_3 = Point(3, 3) point_4 = Point(0, 0) line_segment = LineSegment(first=point_1, second=point_2) assert line_segment.does_contain(point_1) assert line_segment.does_contain(point_2) assert not line_segment.does_contain(point_3) assert line_segment.does_contain(point_4)
def new_edges(t_points: List[Point], t_edges: List[LineSegment], point: Point) -> List[LineSegment]: """ Makes valid edges from one point to all points in triangulation so far. Args: t_points: Points in triangulation t_edges: Edges in triangulation point: Point that is not yet in triangulation. Returns: List of valid LineSegments. """ n_edges = [] for tri_p in t_points: new_edge = LineSegment(point, tri_p) valid = True for edge in t_edges: if edge.strict_intersect(new_edge): valid = False break if valid: n_edges.append(new_edge) return n_edges
def test_does_intersect() -> None: """ Tests if does_intersect works correctly. Tests both common and edge cases. """ line_segment_1 = LineSegment(first=Point(1, 1), second=Point(4, 4)) reversed_segment = LineSegment(first=Point(4, 4), second=Point(1, 1)) line_segment_2 = LineSegment(first=Point(1, 1), second=Point(-2, -4)) line_segment_3 = LineSegment(first=Point(3, 3), second=Point(5, 5)) line_segment_4 = LineSegment(first=Point(1, 0), second=Point(5, -5)) assert line_segment_1.does_intersect_or_touch(reversed_segment) assert line_segment_1.does_intersect_or_touch(line_segment_2) assert line_segment_1.does_intersect_or_touch(line_segment_3) assert not line_segment_1.does_intersect_or_touch(line_segment_4)
def test_number_of_intersections() -> None: """ Tests if Polygon class method number_of_intersections works correctly. """ line_segment_intersect = LineSegment(first=Point(0, 0), second=Point(10, 10)) line_segment_no_intersect = LineSegment(first=Point(0, 0), second=Point(-10, -10)) polygon = Polygon([ Point(1, 1), Point(5, 6), Point(5, 3), Point(2, 5), Point(4, 8), Point(2, 3), Point(4, 1), Point(3, 4) ]) assert polygon.intersection_count(line_segment_intersect) == (6, False) assert polygon.intersection_count(line_segment_no_intersect) == (0, False)
def test_does_intersect() -> None: """ Tests if Polygon class method does_intersect works correctly. Two common and one edge case. """ polygon = Polygon([ Point(1, 1), Point(5, 6), Point(5, 3), Point(2, 5), Point(4, 8), Point(2, 3), Point(4, 1), Point(3, 4) ]) line_segment_intersect = LineSegment(Point(0, 2), Point(2, 2)) line_segment_no_intersect = LineSegment(Point(0, 0), Point(-5, 2)) line_segment_match = LineSegment(polygon.points[4], polygon.points[5]) assert polygon.does_intersect(line_segment_intersect) assert not polygon.does_intersect(line_segment_no_intersect) assert polygon.does_intersect(line_segment_match)
def add_triangles(triangulation: Triangulation, point: Point, t_points: List[Point]) -> None: """ Adds triangles from new point to triangulation. Args: triangulation: Current triangulation. point: New point that is not yet in triangulation. t_points: Points in triangulation. """ t_edges = triangulation.get_edges() n_edges = new_edges(t_points, t_edges, point) edges_to_flip = [] for edge_1 in n_edges: for edge_2 in n_edges: if edge_1 == edge_2: break tri_edge = LineSegment(edge_1.second, edge_2.second) if tri_edge in t_edges: tri_edge = t_edges[t_edges.index(tri_edge)] elif tri_edge.reversed() in t_edges: tri_edge = t_edges[t_edges.index(tri_edge.reversed())] else: continue tri_edge.frontier = False edges_to_flip.append(tri_edge) tri_1 = Triangle(edge_1.second, edge_2.second, point) triangulation.add(tri_1) flip_edges(triangulation, edges_to_flip)
def does_contain(self, point: Point) -> bool: """ Determines if point "lies" in polygon (self) Args: point: Point object to be tested Returns: True if point is in polygon, False otherwise """ # NOTE: PSEUDO_INF used instead of float("inf") of numpy.inf because # usage of these methods gave incorrect results. Float comparison error? ray = LineSegment(first=point, second=Point(PSEUDO_INF, point.y)) num_of_int, on_edge = self.intersection_count(ray) return num_of_int % 2 != 0 or on_edge
def test_new_edges() -> None: """ Tests if new_edges method works correctly. """ a, b, c, d = [Point(4, 3), Point(-1, 2), Point(1, 1), Point(2, 1)] t_points = [a, b, c, d] t_edges = [ LineSegment(b, c), LineSegment(c, d), LineSegment(b, d), LineSegment(b, a), LineSegment(a, d) ] point = Point(1, 3) assert new_edges(t_points, t_edges, point) == [LineSegment(point, a), LineSegment(point, b)]
def pick_start_segment(polygon: Polygon) -> LineSegment: points_count = len(polygon.points) if points_count > 3: for i in range(points_count): ref_points = (polygon.points[(i - 1) % points_count], polygon.points[i % points_count], polygon.points[(i + 1) % points_count], polygon.points[(i + 2) % points_count]) or_1 = orientation(ref_points[0], ref_points[1], ref_points[2]) or_2 = orientation(ref_points[1], ref_points[2], ref_points[3]) if or_1 != 0 and or_2 != 0: return LineSegment(ref_points[1], ref_points[2]) raise ValueError("Polygon consists only out of collinear points!") else: raise ValueError("Polygon size is less than 3!")
def diagonals_from_point(self, start_point: Point) -> List[LineSegment]: """ For a given polygon points, creates all diagonals that start in that point. Args: start_point: One of the points of the polygon Returns: List of LineSegments (diagonals) """ self.make_simple() diagonals = [] for index, point in enumerate(self.points): if not neighbors(start_point, point, self.points): diagonals.append(LineSegment(start_point, point)) return diagonals
def test_rearrange_points() -> None: """ Tests if rearrange_points works correctly. """ hexagon = Polygon([ Point(0, 0), Point(1, -1), Point(2, 0), Point(2, 1), Point(1, 2), Point(0, 1) ]) segment = LineSegment(Point(1, -1), Point(2, 0)) assert rearrange_points(segment, hexagon) == [ Point(1, -1), Point(2, 0), Point(2, 1), Point(1, 2), Point(0, 1), Point(0, 0) ]