(dom_i, cod_i, dom_j, cod_j, grid)
return (free_up, free_down, backwards)
For a diagonal morphism, checks whether there is free space
        (i.e., space not occupied by any objects) above the morphism
        or below it.
For a diagonal morphism, checks whether there is free space
        (i.e., space not occupied by any objects) above the morphism
        or below it.
For a diagonal morphism checks whether there is free space ( i . e . space not occupied by any objects ) above the morphism or below it .
def _check_free_space_diagonal(dom_i, cod_i, dom_j, cod_j, grid):
        """
        For a diagonal morphism, checks whether there is free space
        (i.e., space not occupied by any objects) above the morphism
        or below it.
        """
        def abs_xrange(start, end):
            if start < end:
                return xrange(start, end + 1)
            else:
                return xrange(end, start + 1)

        if dom_i < cod_i and dom_j < cod_j:
            # This morphism goes from top-left to
            # bottom-right.
            (start_i, start_j) = (dom_i, dom_j)
            (end_i, end_j) = (cod_i, cod_j)
            backwards = False
        elif dom_i > cod_i and dom_j > cod_j:
            # This morphism goes from bottom-right to
            # top-left.
            (start_i, start_j) = (cod_i, cod_j)
            (end_i, end_j) = (dom_i, dom_j)
            backwards = True
        if dom_i < cod_i and dom_j > cod_j:
            # This morphism goes from top-right to
            # bottom-left.
            (start_i, start_j) = (dom_i, dom_j)
            (end_i, end_j) = (cod_i, cod_j)
            backwards = True
        elif dom_i > cod_i and dom_j < cod_j:
            # This morphism goes from bottom-left to
            # top-right.
            (start_i, start_j) = (cod_i, cod_j)
            (end_i, end_j) = (dom_i, dom_j)
            backwards = False

        # This is an attempt at a fast and furious strategy to
        # decide where there is free space on the two sides of
        # a diagonal morphism.  For a diagonal morphism
        # starting at ``(start_i, start_j)`` and ending at
        # ``(end_i, end_j)`` the rectangle defined by these
        # two points is considered.  The slope of the diagonal
        # ``alpha`` is then computed.  Then, for every cell
        # ``(i, j)`` within the rectangle, the slope
        # ``alpha1`` of the line through ``(start_i,
        # start_j)`` and ``(i, j)`` is considered.  If
        # ``alpha1`` is between 0 and ``alpha``, the point
        # ``(i, j)`` is above the diagonal, if ``alpha1`` is
        # between ``alpha`` and infinity, the point is below
        # the diagonal.  Also note that, with some beforehand
        # precautions, this trick works for both the main and
        # the secondary diagonals of the rectangle.

        # I have considered the possibility to only follow the
        # shorter diagonals immediately above and below the
        # main (or secondary) diagonal.  This, however,
        # wouldn't have resulted in much performance gain or
        # better detection of outer edges, because of
        # relatively small sizes of diagram grids, while the
        # code would have become harder to understand.

        alpha = float(end_i - start_i)/(end_j - start_j)
        free_up = True
        free_down = True
        for i in abs_xrange(start_i, end_i):
            if not free_up and not free_down:
                break

            for j in abs_xrange(start_j, end_j):
                if not free_up and not free_down:
                    break

                if (i, j) == (start_i, start_j):
                    continue

                if j == start_j:
                    alpha1 = "inf"
                else:
                    alpha1 = float(i - start_i)/(j - start_j)

                if grid[i, j]:
                    if (alpha1 == "inf") or (abs(alpha1) > abs(alpha)):
                        free_down = False
                    elif abs(alpha1) < abs(alpha):
                        free_up = False

        return (free_up, free_down, backwards)
def _check_free_space_diagonal ( dom_i , cod_i , dom_j , cod_j , grid ) : def abs_xrange ( start , end ) : if start < end : return xrange ( start , end + 1 ) else : return xrange ( end , start + 1 ) if dom_i < cod_i and dom_j < cod_j : # This morphism goes from top-left to # bottom-right. ( start_i , start_j ) = ( dom_i , dom_j ) ( end_i , end_j ) = ( cod_i , cod_j ) backwards = False elif dom_i > cod_i and dom_j > cod_j : # This morphism goes from bottom-right to # top-left. ( start_i , start_j ) = ( cod_i , cod_j ) ( end_i , end_j ) = ( dom_i , dom_j ) backwards = True if dom_i < cod_i and dom_j > cod_j : # This morphism goes from top-right to # bottom-left. ( start_i , start_j ) = ( dom_i , dom_j ) ( end_i , end_j ) = ( cod_i , cod_j ) backwards = True elif dom_i > cod_i and dom_j < cod_j : # This morphism goes from bottom-left to # top-right. ( start_i , start_j ) = ( cod_i , cod_j ) ( end_i , end_j ) = ( dom_i , dom_j ) backwards = False # This is an attempt at a fast and furious strategy to # decide where there is free space on the two sides of # a diagonal morphism.  For a diagonal morphism # starting at ``(start_i, start_j)`` and ending at # ``(end_i, end_j)`` the rectangle defined by these # two points is considered.  The slope of the diagonal # ``alpha`` is then computed.  Then, for every cell # ``(i, j)`` within the rectangle, the slope # ``alpha1`` of the line through ``(start_i, # start_j)`` and ``(i, j)`` is considered.  If # ``alpha1`` is between 0 and ``alpha``, the point # ``(i, j)`` is above the diagonal, if ``alpha1`` is # between ``alpha`` and infinity, the point is below # the diagonal.  Also note that, with some beforehand # precautions, this trick works for both the main and # the secondary diagonals of the rectangle. # I have considered the possibility to only follow the # shorter diagonals immediately above and below the # main (or secondary) diagonal.  This, however, # wouldn't have resulted in much performance gain or # better detection of outer edges, because of # relatively small sizes of diagram grids, while the # code would have become harder to understand. alpha = float ( end_i - start_i ) / ( end_j - start_j ) free_up = True free_down = True for i in abs_xrange ( start_i , end_i ) : if not free_up and not free_down : break for j in abs_xrange ( start_j , end_j ) : if not free_up and not free_down : break if ( i , j ) == ( start_i , start_j ) : continue if j == start_j : alpha1 = "inf" else : alpha1 = float ( i - start_i ) / ( j - start_j ) if grid [ i , j ] : if ( alpha1 == "inf" ) or ( abs ( alpha1 ) > abs ( alpha ) ) : free_down = False elif abs ( alpha1 ) < abs ( alpha ) : free_up = False return ( free_up , free_down , backwards )