def computeHull (points):
    """
    Compute the convex hull for given points and return as polygon.
    Returned polygon is in 'counter-clockwise' fashion, with the 
    interior "to the left" of each edge.
    """
    # sort by x coordinate (and if ==, by y coordinate). 
    n = len(points)
    
    points = sorted(points, key=lambda pt:[pt.x(), pt.y()])
    if n < 3:
        return Polygon(points)
        
    # Compute upper hull by starting with rightmost two points
    upper = Polygon ([points[-1], points[-2]])
    for i in range(n-3, -1, -1):
        upper.add (points[i].x(), points[i].y())

        while upper.numPoints() >=3 and lastThreeNonLeft(upper):
            upper.remove(-2)

    # Compute lower hull by starting with leftmost two points
    lower = Polygon ([points[0], points[1]])
    for i in range(2, n):
        lower.add (points[i].x(), points[i].y())

        while lower.numPoints() >=3 and lastThreeNonLeft(lower):
            lower.remove(-2)
                
    # Merge into upper (skip first and last to avoid duplication) and return.
    upper.remove(-1)
    upper.remove(0)
    for pt in upper:
        lower.add(pt.x(), pt.y())

    return lower
示例#2
0
def convexIntersect(p, q):
    """
    Compute and return polygon resulting from the intersection of
    two convext polygons, p and q.
    """
    intersection = Polygon()
    pn = p.numEdges()
    qn = q.numEdges()
    k = 1
    inside = None              # can't know inside until intersection
    first = None               # remember 1st intersection to know when to stop
    firstp = pe = p.edges()[0] # get first edge of p and q
    firstq = qe = q.edges()[0]
    while k < 2*(pn + qn):
        pt = pe.intersect(qe)
        if pt is not None:
            if first == None:
                first = pt
            elif pt == first:
                # stop when find first intersection again
                break

            intersection.add(pt.x(), pt.y())
            if inhalfplane(pe.tail(), qe):
                inside = p
            else:
                inside = q

        # Identify relationship between edges; either we advance
        # p or we advance q, based on whether p's current edge
        # is aiming at qe (or vice versa).
        advancep = advanceq = False

        if (aim(pe,qe) and aim(qe,pe)) or (not aim(pe,qe) and not aim(qe,pe)):
            if inside is p:
                advanceq = True
            elif inside is q:
                advancep = True
            else:
                # no intersection yet. Choose based on
                # which one is "outside"
                if inhalfplane(pe.tail(), qe):
                    advanceq = True
                else:
                    advancep = True
        elif aim(pe, qe):
            advancep = True
        elif aim(qe, pe):
            advanceq = True

##        if aim(pe, qe):
##            if aim(qe, pe):
##                if inside is p:
##                    advanceq = True
##                elif inside is q:
##                    advancep = True
##                else:
##                    advancep = True    # arbitrary pick
##            else:
##                advancep = True
##        else:
##            if aim(qe, pe):
##                advanceq = True
##            else:
##                if inside is p:
##                    advanceq = True
##                elif inside is q:
##                    advancep = True
##                else:
##                    advancep = True    # arbitrary pick

        if advancep:
            if inside is p:
                intersection.add(pe.tail().x(), pe.tail().y())
            pe = pe.next()
        elif advanceq:
            if inside is q:
                intersection.add(qe.tail().x(), qe.tail().y())
            qe = qe.next()

        k += 1
            
    if intersection.numPoints() == 0:
        if containedWithin(firstp.tail(), q):
            return p
        elif containedWithin(firstq.tail(), p):
            return q
        else:
            return None

    # Return computed intersection
    return intersection