def _calculate_coordinates(self):
        """
        Calculate coordinates for each grid, and then calculate coordinates for each node.

        :return: None
        """

        row_max_ids = {}
        for col, row in self._grid_max_horizontal_id:
            if row not in row_max_ids or self._grid_max_horizontal_id[(col, row)] > row_max_ids[row]:
                row_max_ids[row] = self._grid_max_horizontal_id[(col, row)]

        y = 0
        # calculate the top margin based on the number of horizontal edges above
        top_margin_height = self.row_margin * 2
        if 0 in row_max_ids:
            top_margin_height += self.y_margin * (row_max_ids[0] + 2)
        y += top_margin_height

        for row in range(-1, self._max_row + 2):
            x = 0

            for col in range(-1, self._max_col + 2):
                self._grid_coordinates[(col, row)] = (x, y)
                x += self._col_widths[col] + self.col_margin
            if self._row_heights[row] is None:
                self._row_heights[row] = 0

            # calculate the bottom margin based on the number of horizontal edges below
            bottom_margin_height = self.row_margin * 2
            if (row + 1) in row_max_ids:
                bottom_margin_height += self.y_margin * (row_max_ids[row + 1] + 2)
            y += self._row_heights[row] + bottom_margin_height

        # nodes
        for node in self.graph.nodes():
            col, row = self._locations[node]
            grid_x, grid_y = self._grid_coordinates[(col, row)]
            grid_a_width, grid_b_width = self._col_widths[col], self._col_widths[col + 1]
            grid_height = self._row_heights[row]
            node_width, node_height = self._node_sizes[node]

            self.node_coordinates[node] = (
                grid_x + ((grid_a_width + grid_b_width) // 2 - node_width // 2),
                grid_y + (grid_height // 2 - node_height // 2),
            )

        # edges
        for edge in self.edges:
            src_node_x, src_node_y = self.node_coordinates[edge.src]
            src_node_width, src_node_height = self._node_sizes[edge.src]

            dst_node_x, dst_node_y = self.node_coordinates[edge.dst]
            dst_node_width, dst_node_height = self._node_sizes[edge.dst]

            # dst_node_col, dst_node_row = self._locations[edge.dst]

            # start point
            _, _, start_x_index = edge.points[0]
            start_point_x_base = src_node_x + src_node_width // 2 - (self.x_margin * (edge.max_start_index + 1) // 2)
            start_point_x = self._indexed_x(start_point_x_base, start_x_index)
            start_point = (start_point_x, src_node_y + src_node_height)
            edge.add_coordinate(*start_point)

            prev_col, prev_row = self._locations[edge.src]
            prev_col += 1
            prev_row += 1
            x, y_base = start_point[0], start_point[1] + self.row_margin

            if len(edge.points) > 1:
                next_col, next_row, next_idx = edge.points[1]
                starting_col, starting_row = self._locations[edge.src]
                y_base = self._nointersecting_y(starting_row, starting_col, next_col, default=y_base) + self.row_margin
                y = self._indexed_y(y_base, next_idx)
            else:
                y = y_base

            # add a line that moves downwards from the exit
            edge.add_coordinate(x, y)

            # set previous x and y
            prev_x, prev_y = x, y

            # each point on the edge

            for point_id, (col, row, _) in enumerate(edge.points[1:-1]):
                if col == prev_col:
                    assert row != prev_row
                    # vertical
                    x = prev_x

                    base_y = self._grid_coordinates[(col, row - 1)][1] + self._row_heights[row - 1] + self.row_margin
                    if point_id + 1 == len(edge.points) - 2:
                        y = base_y
                    else:
                        next_col, next_row, next_idx = edge.points[point_id + 1 + 1]
                        y = self._indexed_y(base_y, next_idx)

                elif row == prev_row:
                    assert col != prev_col
                    # horizontal
                    if point_id + 1 == len(edge.points) - 2:
                        base_x = dst_node_x + dst_node_width // 2
                        x = self._indexed_x(base_x, edge.end_index)
                    else:
                        next_col, next_row, next_idx = edge.points[point_id + 1 + 1]
                        base_x = self._grid_coordinates[(col, row)][0]
                        x = self._indexed_x(base_x, next_idx)

                    y = prev_y

                else:
                    # the impossible branch
                    raise AssertionError

                edge.add_coordinate(x, y)

                # update prev_*
                prev_col, prev_row = col, row
                prev_x, prev_y = x, y

            # the last point, which is always at the top of the destination node
            base_x = dst_node_x + dst_node_width // 2 - (self.x_margin * (edge.max_end_index + 1) // 2)
            _, _, end_x_index = edge.points[-1]
            x = self._indexed_x(base_x, end_x_index)
            if x != prev_x:
                # add an extra coordinate to move horizontally
                edge.add_coordinate(x, prev_y)
            end_point = (x, dst_node_y - 6)
            edge.add_coordinate(*end_point)

        Calculate coordinates for each grid, and then calculate coordinates for each node.

        :return: None
        
angrmanagement/utils/graph_layouter.py