def checkPolygons(map): clean = True for edge in map.edgeIter(): l, pa = edge.length(), edge.partialArea() p = Polygon(edge) p.invalidateProperties() if abs(l - p.length()) > 1e-6: print "edge %d: length wrong (was %s, is %s)" % ( edge.label(), l, p.length()) clean = False if abs(pa - p.partialArea()) > 1e-6: print "edge %d: partial area wrong (was %s, is %s)" % ( edge.label(), pa, p.partialArea()) clean = False return clean
def checkPolygons(map): clean = True for edge in map.edgeIter(): l, pa = edge.length(), edge.partialArea() p = Polygon(edge) p.invalidateProperties() if abs(l - p.length()) > 1e-6: print "edge %d: length wrong (was %s, is %s)" % (edge.label(), l, p.length()) clean = False if abs(pa - p.partialArea()) > 1e-6: print "edge %d: partial area wrong (was %s, is %s)" % ( edge.label(), pa, p.partialArea()) clean = False return clean
def clipPoly(polygon, clipRect, closeAtBorder = None): """clipPoly(polygon, clipRect) Clips away those parts of polygon which are not in clipRect. Returns a list of polygons (since the polygon may leave clipRect, enter again, leave, ...). Polygon segments crossing clipRect's borders are cut, such that the resulting polyons get new endpoints exactly on the border.""" result = [] # print "clipPoly(%s..%s)" % (clipRect.begin(), clipRect.end()) # print list(polygon) if closeAtBorder is None: closeAtBorder = (polygon[0] == polygon[-1]) x1, y1 = clipRect.begin() x2, y2 = clipRect.end() part = None startBorder = None parts = [] relPos = None for i, p in enumerate(polygon): prevRP = relPos relPos = 0 if p[0] < x1: relPos |= LEFT elif p[0] > x2: relPos |= RIGHT if p[1] < y1: relPos |= TOP elif p[1] > y2: relPos |= BOTTOM if relPos: # outside if not i: # incomplete first segment continue if prevRP & relPos: # complete segment outside continue # calculate leaving intersection diff = polygon[i-1] - p l = -1.0 if relPos & LEFT: l = max(l, (x1 - p[0]) / diff[0]) endBorder = LEFT if relPos & RIGHT: l = max(l, (x2 - p[0]) / diff[0]) endBorder = RIGHT if relPos & TOP: nl = (y1 - p[1]) / diff[1] if nl > l: l = nl endBorder = TOP if relPos & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl > l: l = nl endBorder = BOTTOM ip = p + l * diff if prevRP: # segment may cross cliprect, calc. start intersection pl = 2.0 if prevRP & LEFT: pl = min(pl, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: pl = min(pl, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: npl = (y1 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = TOP if prevRP & BOTTOM: npl = (y2 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = BOTTOM if pl <= l: # we never crossed the clipRect continue pip = p + pl * diff part = Polygon([pip, ip]) else: part.append(ip) if part.length(): parts.append((startBorder, part, endBorder)) part = None continue if not part: part = Polygon() if i: # calculate entering intersection: diff = polygon[i-1] - p l = 2.0 if prevRP & LEFT: l = min(l, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: l = min(l, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: nl = (y1 - p[1]) / diff[1] if nl < l: l = nl startBorder = TOP if prevRP & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl < l: l = nl startBorder = BOTTOM ip = p + l * diff part.append(ip) part.append(p) if part and part.length(): parts.append((startBorder, part, None)) if not parts: return [] if not polygon.closed(): return [p[1] for p in parts] # if polygon[0] (== polygon[-1]) is inside clipRect, we may # need to join the first and last part here: if parts[0][1][0] == parts[-1][1][-1]: assert parts[0][0] is None and parts[-1][-1] is None # polygon is entirely within clipRect: if len(parts) == 1: return [parts[0][1]] parts[-1][1].extend(parts[0][1]) parts[0] = (parts[-1][0], parts[-1][1], parts[0][2]) del parts[-1] if not closeAtBorder: return [p[1] for p in parts] # compose counterclockwise list of intersection points at clip border: sides = ( ([(-p[1][-1][0], p[1], True ) for p in parts if p[2] == TOP] + [(-p[1][ 0][0], p[1], False) for p in parts if p[0] == TOP]), ([( p[1][-1][1], p[1], True ) for p in parts if p[2] == LEFT] + [( p[1][ 0][1], p[1], False) for p in parts if p[0] == LEFT]), ([( p[1][-1][0], p[1], True ) for p in parts if p[2] == BOTTOM] + [( p[1][ 0][0], p[1], False) for p in parts if p[0] == BOTTOM]), ([(-p[1][-1][1], p[1], True ) for p in parts if p[2] == RIGHT] + [(-p[1][ 0][1], p[1], False) for p in parts if p[0] == RIGHT])) # counterclockwise list of corner positions: corners = (clipRect.begin(), clipRect.begin()+(0, clipRect.size()[1]), clipRect.end(), clipRect.begin()+(clipRect.size()[0], 0)) isCCW = polygon.partialArea() > 0 # bookkeeping about mergings (always use the most current polygon) merged = {} def mergeRoot(poly): while True: result = merged.get(poly, poly) if result is poly: break poly = result return result lastPoly = None prevPoly = None prevOutside = None for side, end in zip(sides, corners): for _, poly, outside in sorted(side): # assert outside != prevOutside; prevOutside = outside if outside == isCCW: prevPoly = poly else: if prevPoly == None: lastPoly = poly continue prevPoly = mergeRoot(prevPoly) if prevPoly == poly: poly.append(poly[0]) result.append(poly) else: prevPoly.extend(poly) merged[poly] = prevPoly prevPoly = None if prevPoly: mergeRoot(prevPoly).append(end) if lastPoly: lastPoly.append(lastPoly[0]) if lastPoly.length(): result.append(lastPoly) return result
def clipPoly(polygon, clipRect, closeAtBorder=None): """clipPoly(polygon, clipRect) Clips away those parts of polygon which are not in clipRect. Returns a list of polygons (since the polygon may leave clipRect, enter again, leave, ...). Polygon segments crossing clipRect's borders are cut, such that the resulting polyons get new endpoints exactly on the border.""" result = [] # print "clipPoly(%s..%s)" % (clipRect.begin(), clipRect.end()) # print list(polygon) if closeAtBorder is None: closeAtBorder = (polygon[0] == polygon[-1]) x1, y1 = clipRect.begin() x2, y2 = clipRect.end() part = None startBorder = None parts = [] relPos = None for i, p in enumerate(polygon): prevRP = relPos relPos = 0 if p[0] < x1: relPos |= LEFT elif p[0] > x2: relPos |= RIGHT if p[1] < y1: relPos |= TOP elif p[1] > y2: relPos |= BOTTOM if relPos: # outside if not i: # incomplete first segment continue if prevRP & relPos: # complete segment outside continue # calculate leaving intersection diff = polygon[i - 1] - p l = -1.0 if relPos & LEFT: l = max(l, (x1 - p[0]) / diff[0]) endBorder = LEFT if relPos & RIGHT: l = max(l, (x2 - p[0]) / diff[0]) endBorder = RIGHT if relPos & TOP: nl = (y1 - p[1]) / diff[1] if nl > l: l = nl endBorder = TOP if relPos & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl > l: l = nl endBorder = BOTTOM ip = p + l * diff if prevRP: # segment may cross cliprect, calc. start intersection pl = 2.0 if prevRP & LEFT: pl = min(pl, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: pl = min(pl, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: npl = (y1 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = TOP if prevRP & BOTTOM: npl = (y2 - p[1]) / diff[1] if npl < pl: pl = npl startBorder = BOTTOM if pl <= l: # we never crossed the clipRect continue pip = p + pl * diff part = Polygon([pip, ip]) else: part.append(ip) if part.length(): parts.append((startBorder, part, endBorder)) part = None continue if not part: part = Polygon() if i: # calculate entering intersection: diff = polygon[i - 1] - p l = 2.0 if prevRP & LEFT: l = min(l, (x1 - p[0]) / diff[0]) startBorder = LEFT if prevRP & RIGHT: l = min(l, (x2 - p[0]) / diff[0]) startBorder = RIGHT if prevRP & TOP: nl = (y1 - p[1]) / diff[1] if nl < l: l = nl startBorder = TOP if prevRP & BOTTOM: nl = (y2 - p[1]) / diff[1] if nl < l: l = nl startBorder = BOTTOM ip = p + l * diff part.append(ip) part.append(p) if part and part.length(): parts.append((startBorder, part, None)) if not parts: return [] if not polygon.closed(): return [p[1] for p in parts] # if polygon[0] (== polygon[-1]) is inside clipRect, we may # need to join the first and last part here: if parts[0][1][0] == parts[-1][1][-1]: assert parts[0][0] is None and parts[-1][-1] is None # polygon is entirely within clipRect: if len(parts) == 1: return [parts[0][1]] parts[-1][1].extend(parts[0][1]) parts[0] = (parts[-1][0], parts[-1][1], parts[0][2]) del parts[-1] if not closeAtBorder: return [p[1] for p in parts] # compose counterclockwise list of intersection points at clip border: sides = (([(-p[1][-1][0], p[1], True) for p in parts if p[2] == TOP] + [(-p[1][0][0], p[1], False) for p in parts if p[0] == TOP]), ([(p[1][-1][1], p[1], True) for p in parts if p[2] == LEFT] + [(p[1][0][1], p[1], False) for p in parts if p[0] == LEFT]), ([(p[1][-1][0], p[1], True) for p in parts if p[2] == BOTTOM] + [(p[1][0][0], p[1], False) for p in parts if p[0] == BOTTOM]), ([(-p[1][-1][1], p[1], True) for p in parts if p[2] == RIGHT] + [(-p[1][0][1], p[1], False) for p in parts if p[0] == RIGHT])) # counterclockwise list of corner positions: corners = (clipRect.begin(), clipRect.begin() + (0, clipRect.size()[1]), clipRect.end(), clipRect.begin() + (clipRect.size()[0], 0)) isCCW = polygon.partialArea() > 0 # bookkeeping about mergings (always use the most current polygon) merged = {} def mergeRoot(poly): while True: result = merged.get(poly, poly) if result is poly: break poly = result return result lastPoly = None prevPoly = None prevOutside = None for side, end in zip(sides, corners): for _, poly, outside in sorted(side): # assert outside != prevOutside; prevOutside = outside if outside == isCCW: prevPoly = poly else: if prevPoly == None: lastPoly = poly continue prevPoly = mergeRoot(prevPoly) if prevPoly == poly: poly.append(poly[0]) result.append(poly) else: prevPoly.extend(poly) merged[poly] = prevPoly prevPoly = None if prevPoly: mergeRoot(prevPoly).append(end) if lastPoly: lastPoly.append(lastPoly[0]) if lastPoly.length(): result.append(lastPoly) return result