def _route_edge(self, src, dst, edge_sort=None):
        """
        Find a series of grids to route an edge from the source node to the destination node.

        :param src:         The beginning of the edge to route.
        :param dst:         The end of the edge to route.
        :return:            None
        """

        MOVE_LEFT = 0
        MOVE_RIGHT = 2

        # build the edge
        edge = Edge(src, dst, sort=edge_sort)

        start_col, start_row = self._node_locations[src]
        end_col, end_row = self._node_locations[dst]

        # start from the middle of the block
        start_col += 1
        end_col += 1
        # start from the next row
        start_row += 1

        start_idx = self._assign_edge_to(edge, "vertical", start_col, start_row, 0)
        edge.add_point(start_col, start_row, start_idx)

        if start_row < end_row:
            min_row, max_row = start_row, end_row
        else:
            max_row, min_row = start_row, end_row

        # find a vertical column to route the edge to the target node
        col = start_col
        if self._edge_available(col, min_row, max_row):
            pass
        else:
            offset = 1
            while True:
                if self._edge_available(col + offset, min_row, max_row):
                    col = col + offset
                    break
                if self._edge_available(col - offset, min_row, max_row):
                    col = col - offset
                    break
                offset += 1

        if col != start_col:
            # generate a line to move to the target column

            if start_col < col:
                min_col, max_col = start_col, col
                move = MOVE_RIGHT
            else:
                max_col, min_col = start_col, col
                move = MOVE_LEFT

            idx = self._assign_edge_to(edge, "horizontal", min_col, start_row, max_col - min_col)
            edge.add_point(col, start_row, idx)
            edge.add_move(move)
        else:
            # there will be a horizontal edge even when the beginning column and the target column are the same, since
            # the two blocks may not be aligned.
            _ = self._assign_edge_to(edge, "horizontal", start_col, start_row, 1)
            # however, we do not need to add the point to the edge

        if start_row != end_row:
            # generate a line to move to the target row
            idx = self._assign_edge_to(edge, "vertical", col, min(start_row + 1, end_row), abs(end_row - start_row) + 1)
            edge.add_point(col, end_row, idx)

        if col != end_col:
            # generate a line to move to the target column
            if col < end_col:
                min_col, max_col = col, end_col
                move = MOVE_RIGHT
            else:
                max_col, min_col = col, end_col
                move = MOVE_LEFT
            idx = self._assign_edge_to(edge, "horizontal", min_col, end_row, max_col - min_col)
            edge.add_point(end_col, end_row, idx)
            edge.add_move(move)

            # move downwards
            # in a new grid, we need a new edge index
            idx = self._assign_edge_to(edge, "vertical", end_col, end_row, 0)
            edge.add_point(end_col, end_row, idx)

        self._add_edge(edge)
        # print(src, dst, edge.points)

        return edge

        Find a series of grids to route an edge from the source node to the destination node.

        :param src:         The beginning of the edge to route.
        :param dst:         The end of the edge to route.
        :return:            None
        
angrmanagement/utils/graph_layouter.py