def triangulate(polygon: Polygon, parent: Node) -> Node: """ Performs recursive triangulation of a polygon. Incomplete triangulations are put in tree that has parent as root. Complete triangulations are leaf nodes of that tree. Args: polygon: Polygon that will be triangulated. parent: Root of tree that will contain triangulations Returns: Leaf nodes if polygon is actually triangle. """ if len(polygon.points) == 3: child = Node(extend_triangulation(parent, polygon.points[:3])) parent.add_child(child) return child segment = pick_start_segment(polygon) polygon.points = rearrange_points(segment, polygon) for point in polygon.points[2:]: first_triangle = Triangle(segment.first, segment.second, point) remainders = polygon_remainders(first_triangle, polygon) sub_root = triangulate(Polygon([segment.first, segment.second, point]), parent) triangulate(remainders[0], sub_root) if remainders[1]: second_remainder_root = Node([]) triangulate(remainders[1], second_remainder_root) merge_triangulations(sub_root, second_remainder_root)
def test_depth_first_traversal() -> None: """ Tests if depth_first_traversal works correctly. """ a, b, c, d = Node("a"), Node("b"), Node("c"), Node("d") a.add_child(b) a.add_child(c) c.add_child(d) tree = Tree(a) assert tree.depth_first_traversal() == [a, b, c, d]
def test_get_leaf_nodes() -> None: """ Tests if get_leaf_nodes works correctly. """ a, b, c, d = Node("a"), Node("b"), Node("c"), Node("d") a.add_child(b) a.add_child(c) c.add_child(d) tree = Tree(a) assert tree.get_leaf_nodes() == [b, d]
def merge_triangulations(first: Node, second: Node) -> None: """ For nodes whose children contain incomplete triangulations, generates all possible complete triangulations and appends them to the first tree. Args: first: Root of the first subtree. second: Root of the second subtree. """ first_leaf_nodes = Tree(first).get_leaf_nodes() second_leaf_nodes = Tree(second).get_leaf_nodes() for leaf_1 in first_leaf_nodes: for leaf_2 in second_leaf_nodes: leaf_1.add_child(Node(leaf_1.data + leaf_2.data))
def all_triangulations(polygon: Polygon) -> List[List[Triangle]]: """ Wrapper function for recursive "triangulate" function. Args: polygon: Polygon that will be triangulated. Returns: List of all possible triangulations of this polygon. """ polygon.make_simple() tree = Tree(Node([])) triangulate(polygon, tree.root) return [node.data for node in tree.get_leaf_nodes()]
def test_triangulate() -> None: """ Tests if rearrange_points works correctly. """ quad = Polygon([Point(0, 0), Point(1, -1), Point(2, 0), Point(2, 1)]) root = Node([]) triangulate(quad, root) triangulation_1 = [ Triangle(Point(0, 0), Point(1, -1), Point(2, 0)), Triangle(Point(0, 0), Point(2, 0), Point(2, 1)) ] triangulation_2 = [ Triangle(Point(0, 0), Point(1, -1), Point(2, 1)), Triangle(Point(1, -1), Point(2, 0), Point(2, 1)) ] assert Tree(root).get_leaf_nodes()[0].data == triangulation_1 assert Tree(root).get_leaf_nodes()[1].data == triangulation_2