def test_make_simple() -> None: """ Tests if Polygon class method make_simple works correctly. """ polygon_1 = 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) ]) simple = Polygon([ Point(4, 1), Point(5, 3), Point(5, 6), Point(3, 4), Point(2, 3), Point(4, 8), Point(2, 5), Point(1, 1) ]) polygon_1.make_simple() assert simple == polygon_1
def test_make_convex() -> None: """ Tests if Polygon class method make_convex works correctly. """ 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) ]) convex = Polygon([ Point(1, 1), Point(4, 1), Point(5, 3), Point(5, 6), Point(4, 8), Point(2, 5) ]) polygon.make_convex_hull() assert convex == polygon
def flip_edge(triangulation: Triangulation, edge: LineSegment) -> None: """ If edge is illegal, replaces it with its pair and recursivly flips neighboring edges if they need flipping, else leaves this as they are. Args: triangulation: Current triangulation. edge: Potential illegal edge. """ pair, faces = find_pair_edge(triangulation, edge) quad = Polygon([edge.first, pair.first, edge.second]) quad.make_simple() quad.points.append(pair.second) if not empty_circle(quad) and len(faces) == 2: triangulation.remove(faces[0]) triangulation.remove(faces[1]) triangulation.add(Triangle(pair.first, pair.second, edge.first)) triangulation.add(Triangle(pair.first, pair.second, edge.second)) for triangle in faces: for _edge in triangle.get_sides(): if not _edge.is_equal_undirected(pair) and \ not _edge.is_equal_undirected(edge): flip_edge(triangulation, _edge)
def contains_point() -> None: polygon = Polygon(points[0: len(points) - 1]) polygon.draw(canvas) if polygon.does_contain(points[-1]): messagebox.showinfo("Result", "Point is INSIDE polygon") else: messagebox.showinfo("Result", "Point is OUTSIDE polygon")
def is_convex() -> None: polygon = Polygon(points) polygon.draw(canvas) if polygon.is_convex(): messagebox.showinfo("Result", "Polygon IS convex") else: messagebox.showinfo("Result", "Polygon IS NOT convex")
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 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_empty_circle() -> None: """ Tests if empty_circle method works correctly. """ a, b, c, d = [Point(4, 3), Point(-1, 2), Point(1, 1), Point(2, 1)] poly = Polygon([a, b, c]) poly.make_simple() poly.points.append(d) assert empty_circle(poly)
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_delaunay_triangulation() -> None: """ Tests if delaunay_triangulation method works correctly. """ a, b, c, d = [Point(4, 3), Point(-1, 2), Point(1, 1), Point(2, 1)] polygon = Polygon([a, b, c, d]) triangulation = delaunay_triangulation(polygon) assert triangulation.triangles == [Triangle(c, a, d), Triangle(c, a, b)]
def from_tuples(self, *args): vertices = [] for arg in args: vertices.append(arg) if not self.__validate_vlist(vertices): raise ValueError() return Polygon(vertices)
class DecoratedPolygon: def __init__(self, vlist): corrected_vlist = self.__correct(vlist) self.polygon = Polygon(corrected_vlist) @property def vlist(self): return self.polygon.vlist def area(self): return self.polygon.area() def set_areaAlg(self, alg): self.polygon.set_areaAlg(alg) def __correct(self, vlist): new_vlist = vlist if new_vlist[-1] != new_vlist[0]: new_vlist.append(new_vlist[0]) return new_vlist
def test_orientation() -> None: """ Tests if Polygon class method orientation works correctly. """ polygon_1 = 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) ]) polygon_2 = Polygon([ Point(1, 1), Point(2, 3), Point(2, 5), Point(5, 3), Point(4, 8), Point(5, 6), Point(4, 1), Point(3, 4) ]) assert polygon_1.orientation() == 1 assert polygon_2.orientation() == -1
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 polygon_remainders(triangle: Triangle, polygon: Polygon) -> List[Polygon]: """ From a given polygon, and a triangle within it, creates smaller remainder or two of them (depending on the position of the triangle within the polygon.) Args: triangle: Triangle object that lies within polygon. polygon: Convex polygon. Returns: One or two smaller polygon remainders. """ diagonals = [ segment for segment in triangle.get_sides() if polygon.has_diagonal(segment) ] if len(diagonals) == 1: remainder_points = list(polygon.points) triangle_points = triangle.get_points() for point in triangle_points: if not diagonals[0].does_contain(point): remainder_points.remove(point) return [Polygon(remainder_points), None] else: if diagonals[1].does_contain(diagonals[0].first): common_point = diagonals[0].first else: common_point = diagonals[0].second common_point_index = polygon.points.index(common_point) return [ Polygon(polygon.points[1:common_point_index + 1]), Polygon([polygon.points[0]] + polygon.points[common_point_index:]) ]
def test_is_empty() -> None: """ Tests if Polygon class method is_empty 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) ]) no_points = [] points_out = [Point(0, 0), Point(10, 10), Point(0, 6), Point(-1, 12)] points_in = [Point(0, 0), Point(4, 4), Point(0, 6), Point(-1, 12)] assert polygon.is_empty(no_points) assert polygon.is_empty(points_out) assert not polygon.is_empty(points_in)
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 test_does_contain() -> None: """ Tests if Polygon class method does_contain 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) ]) point_in = Point(4, 4) point_out = Point(0, 0) point_edge = Point(5, 3) assert polygon.does_contain(point_in) assert not polygon.does_contain(point_out) assert polygon.does_contain(point_edge)
def delaunay_triangulation(polygon: Polygon) -> Triangulation: """ Generates Delaunay triangulation from a given set of points. Args: polygon: Polygon object that contains list of points in 2D plane. Returns: Triangulation object containing list of triangles that form Delaunay triangulation of passed polygon. """ polygon.make_simple() start_point = find_start_point(polygon.points) polygon.points = sort_other_points(polygon.points, start_point) first, second, third = polygon.points[:3] triangulation = Triangulation([Triangle(first, second, third)]) for point in polygon.points[3:]: index = polygon.points.index(point) add_triangles(triangulation, point, polygon.points[:index]) return triangulation
def test_polygon_remainders() -> None: """ Tests if polygon_remainders works correctly. Tests two possible cases. """ hexagon = Polygon([ Point(0, 0), Point(1, 0), Point(2, 0), Point(2, 1), Point(1, 2), Point(0, 1) ]) triangle_1 = Triangle(Point(2, 0), Point(2, 1), Point(1, 2)) triangle_2 = Triangle(Point(1, 0), Point(2, 0), Point(1, 2)) remainders_1 = [ Polygon( [Point(0, 0), Point(1, 0), Point(2, 0), Point(1, 2), Point(0, 1)]), None ] remainders_2 = [ Polygon([Point(1, 0), Point(2, 0), Point(2, 1), Point(1, 2)]), Polygon([Point(0, 0), Point(1, 2), Point(0, 1)]) ] assert polygon_remainders(triangle_1, hexagon) == remainders_1 assert polygon_remainders(triangle_2, hexagon) == remainders_2
def test_all_triangulations() -> None: """ Tests if all_triangulations works correctly. """ quad = Polygon([Point(0, 0), Point(1, -1), Point(2, 0), Point(2, 1)]) all_triangs = [[ Triangle(Point(1, -1), Point(2, 0), Point(2, 1)), Triangle(Point(1, -1), Point(2, 1), Point(0, 0)) ], [ Triangle(Point(1, -1), Point(2, 0), Point(0, 0)), Triangle(Point(2, 0), Point(2, 1), Point(0, 0)) ]] assert all_triangulations(quad) == all_triangs
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
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) ]
def test_is_convex() -> None: """ Tests if Polygon class method is_convex works correctly. """ 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) ]) convex = Polygon( [Point(1, 1), Point(3, 3), Point(0, 5), Point(-1, 4), Point(-1, 2)]) assert not polygon.is_convex() assert convex.is_convex()
def from_list(self, vlist): if self.__validate_vlist(vlist): return Polygon(vlist) else: raise ValueError()
from db.dal import save_triangulations from structures.point import Point from structures.polygon import Polygon from triangulations.triangulations import all_triangulations _5gon = Polygon([Point(4, 2), Point(1, 0), Point(2, 4), Point(0, 2), Point(3, 0)]) _6gon = Polygon([Point(0, 3), Point(3, 0), Point(3, 6), Point(1, 1), Point(6, 2), Point(5, 4)]) _7gon = Polygon([Point(3, 1), Point(4, 6), Point(1, 1), Point(0, 4), Point(2, 8), Point(2, 0), Point(0, 3), ]) _8gon = Polygon([Point(0, 0), Point(4, 4), Point(2, 3), Point(5, 2), Point(0, 1), Point(1, 0), Point(4, 1), Point(5, 3)]) _9gon = Polygon([Point(0, 0), Point(4, 4), Point(2, 1), Point(3, 9), Point(5, 5), Point(0, 3), Point(3, 2), Point(4, 8), Point(1, 5)]) _10gon = Polygon([Point(1, 0), Point(5, 4), Point(2, 0), Point(3, 8), Point(5, 3), Point(0, 3), Point(4, 2), Point(4, 6), Point(0, 5), Point(1, 7)]) _11gon = Polygon([Point(1, 1), Point(5, 4), Point(2, 0), Point(3, 8), Point(4, 1), Point(0, 3), Point(5, 3), Point(4, 6), Point(0, 6), Point(2, 9), Point(1, 9)]) print("{}: {}".format(len(_5gon.points), len(all_triangulations(_5gon)))) print("{}: {}".format(len(_6gon.points), len(all_triangulations(_6gon))))
vertices = self._polygon.vlist area = 0.0 for i in range(0, len(vertices) - 3): area += self.__calc_triang_area(vertices[i], vertices[i + 1], vertices[i + 2]) return fabs(area) def __calc_triang_area(self, v1, v2, v3): l1 = (v2[0] - v1[0], v2[1] - v1[1]) l2 = (v3[0] - v1[0], v3[1] - v1[1]) cross = (0, 0, l1[0] * l2[1] - l1[1] * l2[0]) area = sqrt(cross[0]**2 + cross[1]**2 + cross[2]**2) / 2 return area if __name__ == "__main__": # Making us some pretty triangle poly = Polygon([(0, 0), (0.866, 0.5), (1, 0)]) # Wanna know its area. Bridge will call specific area function poly.set_areaAlg(OnlyTriangleAreaAlg(poly)) print(poly.area()) # Now it's some messed up non-convex polygon. Ouch poly = Polygon([(0, 0), (1, 0), (2, 1), (3, 4), (3, 5), (2, 2), (1, 2), (0, 0)]) # Need new algorithm for that poly.set_areaAlg(GeneralAreaAlg(poly)) print(poly.area())
def make_simple_polygon() -> None: polygon = Polygon(points) polygon.make_simple() polygon.draw(canvas)
def make_convex_hull() -> None: polygon = Polygon(points) polygon.make_convex_hull() polygon.draw(canvas)
def delaunay() -> None: polygon = Polygon(points) triangulation = delaunay_triangulation(polygon) for triangle in triangulation.triangles: triangle.draw(canvas)