def polygon_clip(poly, clip_poly):
    """
    Computes the intersection of an arbitray polygon with a convex clipping polygon, by
    implementing Sutherland-Hodgman's algorithm for polygon clipping.

    :param poly: list of tuples, representing the arbitrary polygon
    :param clip_poly: list of tuples, representing the convex clipping polygon, given in counter-clockwise order
    :return: list of tuples, representing the intersection / clipped polygon
    """

    def is_inside(r, e):
        """
        Returns `True` if the point `r` lies on the inside of the edge `e = (p,q)`.

        To do so, it computes the z-coordinate of the cross product of the two vectors `[pq]` & `[pr]`.
        If the result is 0, the points are collinear. If it is positive, the three points constitute
        a 'left turn' (counter-clockwise), otherwise a 'right turn' (clockwise).
        """
        p = e[0]
        q = e[1]
        return (q[0] - p[0]) * (r[1] - p[1]) - (r[0] - p[0]) * (q[1] - p[1]) > 0

    def compute_intersection(e1, e2):
        """
        Computes the intersection point of the edges `e1` & `e2`.
        """
        # x-y-coordinates of the four points
        x1, y1 = e1[0][0], e1[0][1]
        x2, y2 = e1[1][0], e1[1][1]
        x3, y3 = e2[0][0], e2[0][1]
        x4, y4 = e2[1][0], e2[1][1]
        # help variables to reduce computations
        dx12 = x1 - x2
        dx34 = x3 - x4
        dy12 = y1 - y2
        dy34 = y3 - y4
        # nominator part 1 and 2
        n1 = x1 * y2 - y1 * x2
        n2 = x3 * y4 - y3 * x4
        # denominator
        d = 1.0 / (dx12 * dy34 - dy12 * dx34)
        # intersection point
        return (n1 * dx34 - dx12 * n2) * d, (n1 * dy34 - dy12 * n2) * d

    output_poly = poly
    c1 = clip_poly[-1]
    # clip poly against each edge in clip_poly
    for c2 in clip_poly:
        # input is the clipped output from the previous run
        input_poly = output_poly
        # we build the new output from scratch
        output_poly = []
        clip_edge = (c1, c2)
        p1 = input_poly[-1]
        # go over each poly edge individually
        for p2 in input_poly:
            poly_edge = (p1, p2)
            # add (and implicitly remove) points depending on the four cases
            if is_inside(p2, clip_edge):
                if not is_inside(p1, clip_edge):
                    output_poly.append(compute_intersection(poly_edge, clip_edge))
                output_poly.append(p2)
            elif is_inside(p1, clip_edge):
                output_poly.append(compute_intersection(poly_edge, clip_edge))
            # go to next poly edge
            p1 = p2
        # no intersection
        if not output_poly:
            return []
        # go to next clip edge
        c1 = c2

    return output_poly