예제 #1
0
    def test_path_intersect_no_mirror_2(self):
        anchor_points_0 = [
            GraphicsPoint(100, 100),
            Point(473.7132417184837, 208.4978496002687),
            GraphicsPoint(457, 125)
        ]

        anchor_points_1 = [
            GraphicsPoint(500, 400),
            Point(573, 371),
            Point(550, 177),
            Point(586, 146),
            Point(337, 129),
            Point(536, 22),
            Point(689, 67),
            Point(728, 344),
            Point(650, 472)
        ]

        p_start = GraphicsPoint(100, 100)
        p_end = GraphicsPoint(457, 125)

        path = Path([
            GraphicsBezier(p_start, p_end, Point(278.5, 112.5),
                           Point(404.8987230708711, 188.92401096739675))
        ], p_start, p_end)
        path2 = Path.from_points(anchor_points_1)

        intersections = path.intersects(path2)
        intersections_2 = path2.intersects(path)

        show_paths_2([path, path2], intersections + intersections_2)
        self.assertEqual(len(intersections), len(intersections_2))
예제 #2
0
    def test_path_intersect_no_mirror_3(self):
        anchor_points_0 = [
            Point(600, 300),
            Point(763, 232),
            Point(760, 248),
            Point(763.3812601455536, 279.9618353762123),
            Point(759.093503294539, 324.7570933974201),
            Point(752.2129530873079, 369.22796058983914),
            Point(728.8190694506658, 407.66916515467096)
        ]

        anchor_points_1 = [
            Point(100, 100),
            Point(638, 170),
            Point(727, 212),
            Point(594, 357),
            Point(476, 177),
            Point(261, 207),
            Point(167.76045105799363, 197.0495733490862)
        ]
        path = Path.from_points(anchor_points_0)
        path2 = Path.from_points(anchor_points_1)

        intersections = path.intersects(path2)
        intersections_2 = path2.intersects(path)

        show_paths_2([path, path2], intersections + intersections_2)
        self.assertEqual(len(intersections), len(intersections_2))
예제 #3
0
    def validate_path(self, path: Path) -> Tuple[List[Point], bool]:
        valid_path = True
        all_intersections = []

        # if preview_path.start_point == preview_path.end_point and (len(preview_path.start_point.paths) + 2 >= 3):
        if path.start_point.equals(path.end_point):
            if path.start_point.num_paths + 2 > 3:
                valid_path = False
                print("too many connections")

        # Does created path collide with existing paths, and if so, where
        for p in self.paths:
            intersections = path.intersects(p)
            if intersections:
                all_intersections.extend(intersections)
                valid_path = False
                print("collides with existing paths")

        self_intersections = path.self_intersections()
        if self_intersections:
            all_intersections.extend(self_intersections)
            valid_path = False
            print("collides with itself")

        # If the path is still valid, test if it intersects with any points
        if valid_path:
            for point in self.points:
                if path.point_touches_path(point):
                    all_intersections.append(point)
                    valid_path = False
                    print("collides existing points")
        return all_intersections, valid_path
예제 #4
0
def init_dead_ends_0():
    positions = {0: (0, 0), 1: (30, 0), 2: (30, 20), 3: (60, 0)}
    points = init_points(positions)

    paths = [
        Path.from_points([points[0], points[1]]),
        Path.from_points([points[0], Point(30, -10), points[3]]),
        Path.from_points([points[1], points[2]]),
        Path.from_points([points[1], points[3]])
    ]

    return points, init_edge_map(paths)
예제 #5
0
def find_path_segment(path: Path, point: Point) -> Segment:
    approximation = path.approximate()

    if path.start_point == point:
        return Segment(point, approximation[1])
    else:
        return Segment(point, approximation[-2])
예제 #6
0
    def test_path_intersect_5(self):
        anchor_points_0 = [
            GraphicsPoint(403.01382054213786, 117.09675232181752),
            GraphicsPoint(450, 100)
        ]

        anchor_points_1 = [
            GraphicsPoint(422.05639822420903, 417.833171793951),
            GraphicsPoint(450.55461679819734, 407.4265792951324),
            GraphicsPoint(500, 400)
        ]

        path = Path.from_points(anchor_points_0)

        path2 = Path.from_points(anchor_points_1)

        intersections = path.intersects(path2)

        show_paths_2([path, path2], intersections)
        self.assertEqual(False, len(intersections) > 0)
예제 #7
0
    def test_path_intersect_4(self):
        anchor_points_0 = [
            GraphicsPoint(440.3994196807172, 149.06963274300102),
            GraphicsPoint(450, 100)
        ]

        anchor_points_1 = [
            GraphicsPoint(450, 100),
            GraphicsPoint(402.0865680692103, 419.70860894843224),
            GraphicsPoint(422.05639822420903, 417.833171793951)
        ]

        path = Path.from_points(anchor_points_0)

        path2 = Path.from_points(anchor_points_1)

        intersections = path.intersects(path2)

        show_paths_2([path, path2], intersections)
        self.assertEqual(False, len(intersections) > 0)
예제 #8
0
    def build_sub_path(self, node, alt_start_node=None):
        path_points = []
        if alt_start_node:
            path_points.append(alt_start_node.point)
        i = 0
        while node and i < 4:
            path_points.append(node.point)
            node = node.parent
            i += 1

        return Path.from_points_non_graphic(path_points)
예제 #9
0
    def test_path_intersect_3(self):
        anchor_points_0 = [
            GraphicsPoint(100, 100),
            Point(376, 61),
            Point(639, 217),
            GraphicsPoint(546, 357)
        ]

        anchor_points_1 = [
            GraphicsPoint(450, 100),
            GraphicsPoint(440.3994196807172, 149.06963274300102)
        ]

        path = Path.from_points(anchor_points_0)

        path2 = Path.from_points(anchor_points_1)

        intersections = path2.intersects(path)

        show_paths_2([path, path2], intersections)
        self.assertEqual(False, len(intersections) > 0)
예제 #10
0
    def test_path_intersect_no_mirror(self):
        anchor_points_0 = [
            GraphicsPoint(450, 100),
            Point(473.7132417184837, 208.4978496002687),
            GraphicsPoint(466, 268)
        ]

        anchor_points_1 = [
            GraphicsPoint(100, 100),
            Point(230, 177),
            Point(548, 178),
            GraphicsPoint(701, 347)
        ]

        path = Path.from_points(anchor_points_0)
        path2 = Path.from_points(anchor_points_1)

        intersections = path.intersects(path2)
        intersections_2 = path2.intersects(path)

        show_paths_2([path, path2], intersections + intersections_2)
        self.assertEqual(len(intersections), len(intersections_2))
예제 #11
0
    def test_path_self_no_intersect(self):
        start_end = GraphicsPoint(376, 95)
        anchor_points = [
            start_end,
            Point(154, 199),
            Point(302, 315),
            Point(493, 120), start_end
        ]

        path = Path.from_points(anchor_points)
        intersections = path.self_intersections()
        show_paths_2([path], intersections)
        self.assertEqual(0, len(intersections))
예제 #12
0
def init_connected_faces():
    positions = {0: (0, 0), 1: (30, 0), 2: (50, 0), 3: (70, 0), 4: (90, 0)}
    points = init_points(positions)

    paths = [
        Path.from_points([points[0], points[1]]),
        Path.from_points([points[0], Point(15, -10), points[1]]),
        Path.from_points([points[1], points[2]]),
        Path.from_points([points[2], points[3]]),
        Path.from_points([points[3], points[4]]),
        Path.from_points([points[3], Point(15, -10), points[4]])
    ]

    return points, init_edge_map(paths)
예제 #13
0
def init_onion_graph():
    positions = {
        0: (0, 0),
        1: (0, 30),
        2: (0, -20),
        3: (0, 10),
        4: (0, 20),
        5: (0, -10)
    }

    points = init_points(positions)

    paths = [
        Path.from_points([points[0], Point(-10, 5), points[3]]),
        Path.from_points([points[0], Point(10, 5), points[3]]),
        Path.from_points([points[0], points[5]]),
        Path.from_points([points[5], points[2]]),
        Path.from_points([points[1], Point(-30, 0), points[2]]),
        Path.from_points([points[1], Point(30, 0), points[2]]),
        Path.from_points([points[1], points[4]]),
        Path.from_points([points[3], points[4]]),
    ]

    return points, init_edge_map(paths)
예제 #14
0
    def run_game(self, initial_points, initial_paths):
        self.set_initial_state(initial_points, initial_paths)
        last_mouse_pos = (0, 0)

        spacing = "                 "
        legend_text = "Esc: cancel path" + spacing + "Right Click: Path suggestion" + spacing + "Left Click: Draw path" + spacing + "Backspace: Main menu"
        legend = Label(0, 0, 800, 30, pygame.SRCALPHA, pygame.SRCALPHA, 0,
                       legend_text, 18, gc.UI_BUTTON_TEXT_COLOR)

        player_1_label = Label(0, 0, 60, 30, gc.PLAYER_1_COLOR, gc.BLACK, 2,
                               "Player 1", 20, gc.UI_BUTTON_TEXT_COLOR)
        player_2_label = Label(gc.WINDOW_WIDTH - 60, 0, 60, 30,
                               gc.PLAYER_2_COLOR, gc.PLAYER_2_COLOR, 2,
                               "Player 2", 20, gc.UI_BUTTON_TEXT_COLOR)

        surfaces = []

        surfaces.extend(
            [legend.draw(),
             player_1_label.draw(),
             player_2_label.draw()])

        if self.game_over(self.base_region):
            self.update_screen([])
            return (State.GAME_OVER, [initial_points, initial_paths])

        while True:
            current_mouse_pos = pygame.mouse.get_pos()

            surfaces.extend(
                [legend.draw(),
                 player_1_label.draw(),
                 player_2_label.draw()])

            for event in pygame.event.get():
                # exit via X in window corner
                if event.type == pygame.QUIT:
                    sys.exit()
                # key pressed
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_BACKSPACE:
                        # self.SCREEN.fill(gc.BACKGROUND_COLOR)
                        self.hard_reset()
                        return (State.MAIN_MENU, [])

                    self.key_event_handler(event)

                # mouse clicked
                if event.type == pygame.MOUSEBUTTONDOWN:
                    mouse_point = Point(*event.pos)
                    current_region = self.base_region.find_region(
                        Point(*event.pos))

                    # p is a Point if collision exists, else None
                    p = self.point_collision(current_region.game_points,
                                             event.pos)

                    self.update_screen(surfaces)

                    # right click = suggest a path (if point pressed is GraphicsPoint
                    if event.button == 3 and p:
                        self.suggest_points.append(p)
                        if len(self.suggest_points) == 2:

                            suggested_path_points = self.find_path()

                            # User canceled
                            if not suggested_path_points:
                                self.soft_reset()
                                break

                            self.finalize_path(suggested_path_points)

                            self.change_turn(player_1_label, player_2_label)

                            # check for game over state
                            if self.game_over(self.base_region):
                                self.update_screen([])
                                return (State.GAME_OVER,
                                        [initial_points, initial_paths])

                            # reset control variables
                            self.soft_reset()
                        break
                    elif event.button == 3:
                        break

                    # Cant draw straight lines by pressing twice in the same pixel
                    if len(self.preview_points) > 0 and mouse_point.equals(
                            self.preview_points[-1]):
                        break

                    # point collision and not drawing a path already
                    if p and not self.creating_path:
                        self.preview_path = None
                        self.all_intersections = []
                        self.creating_path = True
                        self.preview_points = [p]
                        self.preview_path = Path.from_points(
                            self.preview_points + [Point(*event.pos)])

                    # no point collision and creating path already
                    elif not p and self.creating_path:
                        self.preview_points.append(Point(*event.pos))

                    # point collision and creating path already
                    elif p and self.creating_path:
                        if p == self.preview_points[0] and len(
                                self.preview_points) == 1:
                            self.soft_reset()
                            break
                        self.preview_points.append(p)
                        self.preview_path = Path.from_points(
                            self.preview_points)

                        (self.all_intersections,
                         valid_path) = self.validate_path(self.preview_path)

                        # path is not valid, show intersections
                        if not valid_path:
                            self.creating_path = False
                            self.preview_path.change_color(gc.RED)

                            self.all_intersections = self.points_to_graphicspoints(
                                self.all_intersections, gc.BLACK, 5)
                            self.soft_reset()
                            break

                        # Split path in two and calculate new point
                        self.finalize_path(self.preview_points)

                        self.change_turn(player_1_label, player_2_label)
                        if self.game_over(self.base_region):
                            self.update_screen([])
                            return (State.GAME_OVER,
                                    [initial_points, initial_paths])

                        self.soft_reset()

            if self.preview_points and self.creating_path:
                cur_point = Point(*pygame.mouse.get_pos())
                self.preview_path.redraw(self.preview_points + [cur_point],
                                         self.get_color())

            # Update the screen if the cursor has moved
            if last_mouse_pos != current_mouse_pos:
                self.SCREEN.fill(gc.BACKGROUND_COLOR)
                last_mouse_pos = current_mouse_pos
                self.update_screen(surfaces)
                pygame.display.update()

            surfaces = []
            # controls fps
            self.CLOCK.tick(gc.FPS)
예제 #15
0
 def build_complete_path(self, node):
     path_points = []
     while node:
         path_points.append(node.point)
         node = node.parent
     return path_points, Path.from_points(path_points)
예제 #16
0
    def insert_rotation(self, new_region: 'Region'):
        # Find all exclusions in self, that need to be moved to new region
        rotation_regions = set()
        new_region_splitted = False
        clear_region = False
        for exclusion in self.exclusions:
            all_points_in_region = True # All game point of current exclusion are located within the new region
            all_on_border = True # All of the current exclusion's game point are located on the border of the new region
            border_set = new_region.get_outer_set() # All game points on the border of the new region
            on_border = 0 # amount of the exclusion's game points that are located on the border of the new region

            #Get the game point of the current exclusion
            if exclusion.game_points:
                points_inside_exclusion = exclusion.game_points
            else:
                points_inside_exclusion = exclusion.get_outer_set()

            #Iterate the current exclusion's game points
            for game_point in points_inside_exclusion:
                if game_point in border_set: # Is the point part of the new regions border?
                    on_border += 1
                if not (new_region.is_point_in_polygon(game_point) or game_point in new_region.game_points): #Is the point inside the new region?
                    all_points_in_region = False
                    break

            # The exclusion lies inside new_region (sharply)
            if all_points_in_region and on_border < 1:
                rotation_regions.add(exclusion)
            elif all_points_in_region and on_border > 1:
                # The exclusion either split the new_region in two
                # Or is a neighbouring region
                exclusion_cycle = set(exclusion.cycle)
                all_paths_in_region = True
                # Validate whether all paths in exclusion are contained within new_region
                for path in exclusion_cycle:
                    if not path in new_region.cycle:
                        # Find if path is inside the region
                        path_mid_point = Path.calculate_mid_point(path)
                        if not new_region.is_point_in_region(path_mid_point):
                            all_paths_in_region = False
                            break
                # The exclusion is contained within new_region (and new_region is split in two)
                if all_paths_in_region:
                    if new_region_splitted:
                        clear_region = True
                    else:
                        new_region_splitted = True
                    rotation_regions.add(exclusion)

        # Update the parent regions exclusions
        parent_regions = self.exclusions.difference(rotation_regions)
        parent_regions.add(new_region)
        self.exclusions = parent_regions

        #Add exclusions to the new region
        new_region.exclusions = rotation_regions
        #Update the parent of the new region's exclusions
        for region in rotation_regions:
            region.parent = new_region
        #Update the new region's edge map and the parent region's (self)
        new_region.add_edges(rotation_regions)
        self.remove_edges(rotation_regions)
        # Is the new region a container region? If so, clear it
        if clear_region:
            new_region.clear()
        return new_region_splitted
예제 #17
0
    def faces(self, root: Point, came_from: Point, path_to_follow: Path,
              directions_taken):
        next_point = path_to_follow.get_other_point(came_from)

        # Base case
        if next_point == root:
            return [], [path_to_follow], directions_taken

        # Find paths in next_point to discover
        other_paths = []
        for n_path in self.edge_map.get(next_point.index, []):
            if n_path == path_to_follow:
                continue
            other_paths.append(n_path)

        if not other_paths:
            # Dead end
            return [], [], directions_taken

        elif len(other_paths) == 1:
            # Only one path to take
            first_path = other_paths[0]
            faces_found, constructed_path, directions_taken = self.take_path(
                root, first_path, next_point, directions_taken)

            if constructed_path:
                # Must only add if currently backtracking
                return faces_found, constructed_path + [path_to_follow
                                                        ], directions_taken
            return [], [], directions_taken
        else:
            # Find segments to find angles between edges
            seg_start = find_path_segment(path_to_follow, next_point)
            seg_0 = find_path_segment(other_paths[0], next_point)
            seg_1 = find_path_segment(other_paths[1], next_point)

            # Assume path 1 has a smaller angle
            first_path = other_paths[1]
            second_path = other_paths[0]

            if segment_angle(seg_start, seg_0) < segment_angle(
                    seg_start, seg_1):
                # Path 0 had a smaller angle
                first_path = other_paths[0]
                second_path = other_paths[1]

            # Take first path
            found_faces, constructed_path_first, directions_taken = self.take_path(
                root, first_path, next_point, directions_taken)

            if constructed_path_first:
                # Only start a new face if the first path also contains a face
                found_faces_second, constructed_path_second, directions_taken = self.take_path(
                    next_point, second_path, next_point, directions_taken)
                found_faces.extend(found_faces_second)

                if constructed_path_second:
                    found_faces.append(constructed_path_second)

            else:
                # Discard empty path from taking first
                found_faces, constructed_path_first, directions_taken = self.take_path(
                    root, second_path, next_point, directions_taken)

            if constructed_path_first:
                return found_faces, constructed_path_first + [
                    path_to_follow
                ], directions_taken
            else:
                return found_faces, [], directions_taken
예제 #18
0
def convert_to_game_structure(graph: nx.Graph, embedding: nx.PlanarEmbedding,
                              path_grouping):
    positions = scale_positions(
        nx.combinatorial_embedding_to_pos(embedding, True))
    points = [GraphicsPoint] * len(graph.nodes)
    paths = []

    # Initialize points
    for index, position in positions.items():
        point = GraphicsPoint(*position, False)
        point.index = index
        points[index] = point

    # Initialize paths
    for path_start, path_end, mid_point in path_grouping:
        start_point = points[path_start[0]]
        end_point = points[path_end[1]]

        # The path was created from the same point to itself
        if start_point == end_point:
            end_point = points[path_start[1]]

            # Make small difference to width of the paths
            delta_pos = end_point - start_point
            mid_point = start_point + delta_pos.scalar(0.5)
            shift = delta_pos.rotate_anticlock().normalized().scalar(5)

            pos_control = mid_point + shift
            neg_control = mid_point - shift

            path_0 = Path([
                GraphicsBezier(start_point, end_point, gc.LINE_COLOR,
                               pos_control, pos_control)
            ], start_point, end_point)
            path_1 = Path([
                GraphicsBezier(start_point, end_point, gc.LINE_COLOR,
                               neg_control, neg_control)
            ], start_point, end_point)

            # Update paths of points
            start_point.add_to_path(path_0)
            start_point.add_to_path(path_1)
            end_point.add_to_path(path_0)
            end_point.add_to_path(path_1)

            paths.append((path_0, path_1, points[path_start[1]]))
        # Normal path
        else:
            middle_point = points[path_start[1]]

            path_0 = Path([GraphicsBezier(start_point, middle_point)],
                          start_point, middle_point)
            path_1 = Path([GraphicsBezier(middle_point, end_point)],
                          middle_point, end_point)

            # Update paths of points
            start_point.add_to_path(path_0)
            middle_point.add_to_path(path_0)
            middle_point.add_to_path(path_1)
            end_point.add_to_path(path_1)

            paths.append((path_0, path_1, middle_point))

        # Test whether the points are still valid
        valid_point(start_point, start_point, end_point)
        valid_point(end_point, start_point, end_point)
    return points, paths