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
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