Beispiel #1
0
def rotatePoly(poly, angle):
    """Rotate polygon by the given angle around the origin."""
    
    unitX = (math.cos(angle), -math.sin(angle))
    unitY = (math.sin(angle),  math.cos(angle))
    result = Polygon()
    for point in poly:
        result.append((numpy.dot(point, unitX), numpy.dot(point, unitY)))
    return result
Beispiel #2
0
def rotatePoly(poly, angle):
    """Rotate polygon by the given angle around the origin."""

    unitX = (math.cos(angle), -math.sin(angle))
    unitY = (math.sin(angle), math.cos(angle))
    result = Polygon()
    for point in poly:
        result.append((numpy.dot(point, unitX), numpy.dot(point, unitY)))
    return result
Beispiel #3
0
def followEdge(crackConnectionImage, pos, direction):
    """Follow edge starting at `pos` in `direction` until
    crackConnectionImage[pos] has the CONN_NODE bit set, or until we
    arrive at `pos` again (self-loop).  Any CONN_MAYBE_NODE bits along
    the way are cleared."""
    pos = Point2D(pos[0], pos[1])
    vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5)
    result = Polygon([vPos])

    startPos = copy.copy(pos)
    while True:
        vPos += _dirVector[direction]
        result.append(vPos)
        pos += _dirOffset[direction]

        if pos == startPos:
            break

        connection = int(crackConnectionImage[pos])
        if connection & CONN_DIAG:
            if connection & CONN_DIAG_UPLEFT:
                turnLeft = direction in (DIR_NORTH, DIR_SOUTH)
            else:
                turnLeft = direction in (DIR_EAST, DIR_WEST)

            connection &= ~connections[(direction + 2) % 4]

            if turnLeft:
                direction = _turnLeft[direction]
            else:
                direction = _turnRight[direction]

            connection &= ~connections[direction]

            if not connection & CONN_ALL4:
                connection &= ~CONN_MAYBE_NODE

            crackConnectionImage[pos] = connection
            continue
        elif connection & CONN_NODE:
            break

        if connection & CONN_MAYBE_NODE:
            # we simply pass over it, but we do not want to start a
            # new edge here during further down in the process:
            crackConnectionImage[pos] = connection & ~CONN_MAYBE_NODE

        direction = _turnRight[direction]
        while connection & connections[direction] == 0:
            direction = _turnLeft[direction]

    return result, pos, connections[(direction + 2) % 4]
Beispiel #4
0
def followEdge(crackConnectionImage, pos, direction):
    """Follow edge starting at `pos` in `direction` until
    crackConnectionImage[pos] has the CONN_NODE bit set, or until we
    arrive at `pos` again (self-loop).  Any CONN_MAYBE_NODE bits along
    the way are cleared."""
    pos = Point2D(pos[0], pos[1])
    vPos = Vector2(pos[0] - 0.5, pos[1] - 0.5)
    result = Polygon([vPos])

    startPos = copy.copy(pos)
    while True:
        vPos += _dirVector[direction]
        result.append(vPos)
        pos += _dirOffset[direction]

        if pos == startPos:
            break

        connection = int(crackConnectionImage[pos])
        if connection & CONN_DIAG:
            if connection & CONN_DIAG_UPLEFT:
                turnLeft = direction in (DIR_NORTH, DIR_SOUTH)
            else:
                turnLeft = direction in (DIR_EAST, DIR_WEST)

            connection &= ~connections[(direction+2)%4]

            if turnLeft:
                direction = _turnLeft[direction]
            else:
                direction = _turnRight[direction]

            connection &= ~connections[direction]

            if not connection & CONN_ALL4:
                connection &= ~CONN_MAYBE_NODE
                
            crackConnectionImage[pos] = connection
            continue
        elif connection & CONN_NODE:
            break

        if connection & CONN_MAYBE_NODE:
            # we simply pass over it, but we do not want to start a
            # new edge here during further down in the process:
            crackConnectionImage[pos] = connection & ~CONN_MAYBE_NODE

        direction = _turnRight[direction]
        while connection & connections[direction] == 0:
            direction = _turnLeft[direction]

    return result, pos, connections[(direction+2)%4]
Beispiel #5
0
def shrinkPoly(poly, offset):
    assert poly[0] == poly[-1], "polygon should be closed"
    lines = [seg.line() for seg in polyLineSegments(poly)]
    for line in lines:
        line.dist -= offset
    i = 1
    while i < len(lines):
        if lines[i-1].isParallel(lines[i]):
            del lines[i]
        else:
            i += 1
    if lines[-1].isParallel(lines[0]):
        del lines[-1]
    result = Polygon([lines[i].intersect(lines[(i+1)%len(lines)])
                      for i in range(len(lines))])
    result.append(result[0])
    return result
Beispiel #6
0
def shrinkPoly(poly, offset):
    assert poly[0] == poly[-1], "polygon should be closed"
    lines = [seg.line() for seg in polyLineSegments(poly)]
    for line in lines:
        line.dist -= offset
    i = 1
    while i < len(lines):
        if lines[i - 1].isParallel(lines[i]):
            del lines[i]
        else:
            i += 1
    if lines[-1].isParallel(lines[0]):
        del lines[-1]
    result = Polygon([
        lines[i].intersect(lines[(i + 1) % len(lines)])
        for i in range(len(lines))
    ])
    result.append(result[0])
    return result
Beispiel #7
0
def _kochIteration(poly):
    result = Polygon()
    for i in range(len(poly)-1):
        segment = poly[i+1]-poly[i]
        smaller = segment/3
        left =  Vector2( smaller[0]*_kochCos - smaller[1]*_kochSin,
                         smaller[0]*_kochSin + smaller[1]*_kochCos)
        right = Vector2( smaller[0]*_kochCos + smaller[1]*_kochSin,
                        -smaller[0]*_kochSin + smaller[1]*_kochCos)
        p1 = poly[i] + smaller
        p2 = p1 + left
        p3 = p2 + right
        result.append(poly[i])
        result.append(p1)
        result.append(p2)
        result.append(p3)
    result.append(result[0])
    return result
Beispiel #8
0
def _kochIteration(poly):
    result = Polygon()
    for i in range(len(poly) - 1):
        segment = poly[i + 1] - poly[i]
        smaller = segment / 3
        left = Vector2(smaller[0] * _kochCos - smaller[1] * _kochSin,
                       smaller[0] * _kochSin + smaller[1] * _kochCos)
        right = Vector2(smaller[0] * _kochCos + smaller[1] * _kochSin,
                        -smaller[0] * _kochSin + smaller[1] * _kochCos)
        p1 = poly[i] + smaller
        p2 = p1 + left
        p3 = p2 + right
        result.append(poly[i])
        result.append(p1)
        result.append(p2)
        result.append(p3)
    result.append(result[0])
    return result
Beispiel #9
0
def kochCurve(level = 5):
    result = Polygon()
    p0 = Vector2(-0.5, -math.sqrt(1./12))
    result.append(p0)
    p1 = p0 + Vector2(_kochCos,  _kochSin)
    result.append(p1)
    p2 = p1 + Vector2(_kochCos, -_kochSin)
    result.append(p2)
    result.append(p0)
    for i in range(level):
        result = _kochIteration(result)
    return result
Beispiel #10
0
def kochCurve(level=5):
    result = Polygon()
    p0 = Vector2(-0.5, -math.sqrt(1. / 12))
    result.append(p0)
    p1 = p0 + Vector2(_kochCos, _kochSin)
    result.append(p1)
    p2 = p1 + Vector2(_kochCos, -_kochSin)
    result.append(p2)
    result.append(p0)
    for i in range(level):
        result = _kochIteration(result)
    return result
Beispiel #11
0
def outputMarkedShapes(delaunayMap, fe, skipInnerEdges = True,
                       regionDepth = 50, edgeDepth = 49,
                       capStyle = fig.CapStyle.Round, **kwargs):
    """IIRC, this assumes that delaunayMap contains only triangles.

    Contiguous thick parts of the alpha shape will be exported as
    single regions (as if removeInterior[Edges] had been used for
    alphaBetaMap or removeUnmarkedEdges, but without modifying
    `delaunayMap`).

    You may set `edgeDepth` to None to disable the output of edges.
    If lineWidth is not set explicitly, it then defaults to zero for
    faces."""

    # output all cells only once:
    edgeOutput = [False] * delaunayMap.maxEdgeLabel()
    faceOutput = [False] * delaunayMap.maxFaceLabel()

    faceAttr = dict(kwargs)
    if edgeDepth is None and not "lineWidth" in kwargs:
        faceAttr["lineWidth"] = 0
    faceAttr["depth"] = regionDepth
    faceAttr["fillStyle"] = fig.FillStyle.Solid
    faceAttr["capStyle"] = capStyle

    print "- exporting marked regions as filled polygons..."
    for triangle in delaunayMap.faceIter(skipInfinite = True):
        if not triangle.flag(ALPHA_MARK) or faceOutput[triangle.label()]:
            continue
        faceOutput[triangle.label()] = True

        contour = list(triangle.contour().phiOrbit())
        i = 0
        while i < len(contour):
            edgeOutput[contour[i].edgeLabel()] = skipInnerEdges
            neighbor = contour[i].rightFace()
            if neighbor.flag(ALPHA_MARK) and not faceOutput[neighbor.label()]:
                _ = contour[i].nextAlpha().nextPhi()
                contour.insert(i+1, contour[i].clone().nextPhi())
                faceOutput[neighbor.label()] = True
            else:
                i += 1

        contour = Polygon([dart[0] for dart in contour])
        contour.append(contour[0]) # close poly (for filling)
        i = 2
        while i < len(contour):
            if contour[i] == contour[i-2]:
                del contour[i-2]
                del contour[i-2]
                if i > 2:
                    i -= 1
            else:
                i += 1
        #print "  * %d points (area %s)" % (len(contour), contour.partialArea())
        fe.addClippedPoly(contour, **faceAttr)

    if "fillColor" in kwargs:
        del kwargs["fillColor"]
    if edgeDepth != None:
        print "- exporting remaining marked edges (depth %d)..." % edgeDepth
        for edge in delaunayMap.edgeIter():
            if not edge.flag(ALPHA_MARK) or edgeOutput[edge.label()]:
                continue

            dart = edge.dart()
            poly = Polygon(list(dart))
            edgeOutput[edge.label()] = True

            drawing = True
            while drawing:
                drawing = False
                dart.nextAlpha()
                for next in dart.sigmaOrbit():
                    outputEdge = next.edge()
                    if not outputEdge.flag(ALPHA_MARK) or edgeOutput[outputEdge.label()]:
                        continue

                    drawing = True
                    assert poly[-1] == next[0]
                    if len(outputEdge) == 2:
                        poly.append(next[1])
                    else:
                        poly.extend(Polygon(list(next)[1:]))
                    edgeOutput[outputEdge.label()] = True

                    dart = next
                    break

            # continue in the other direction:
            poly.reverse()
            dart = edge.dart().nextAlpha()

            drawing = True
            while drawing:
                drawing = False
                dart.nextAlpha()
                next = dart.clone()
                while next.nextSigma() != dart:
                    outputEdge = next.edge()
                    if not outputEdge.flag(ALPHA_MARK) or edgeOutput[outputEdge.label()]:
                        continue

                    drawing = True
                    assert poly[-1] == next[0]
                    poly.append(next[1])
                    edgeOutput[outputEdge.label()] = True

                    dart = next
                    break

            fe.addClippedPoly(
                poly, depth = edgeDepth, capStyle = capStyle, **kwargs)
Beispiel #12
0
def outputMarkedShapes(delaunayMap,
                       fe,
                       skipInnerEdges=True,
                       regionDepth=50,
                       edgeDepth=49,
                       capStyle=fig.CapStyle.Round,
                       **kwargs):
    """IIRC, this assumes that delaunayMap contains only triangles.

    Contiguous thick parts of the alpha shape will be exported as
    single regions (as if removeInterior[Edges] had been used for
    alphaBetaMap or removeUnmarkedEdges, but without modifying
    `delaunayMap`).

    You may set `edgeDepth` to None to disable the output of edges.
    If lineWidth is not set explicitly, it then defaults to zero for
    faces."""

    # output all cells only once:
    edgeOutput = [False] * delaunayMap.maxEdgeLabel()
    faceOutput = [False] * delaunayMap.maxFaceLabel()

    faceAttr = dict(kwargs)
    if edgeDepth is None and not "lineWidth" in kwargs:
        faceAttr["lineWidth"] = 0
    faceAttr["depth"] = regionDepth
    faceAttr["fillStyle"] = fig.FillStyle.Solid
    faceAttr["capStyle"] = capStyle

    print "- exporting marked regions as filled polygons..."
    for triangle in delaunayMap.faceIter(skipInfinite=True):
        if not triangle.flag(ALPHA_MARK) or faceOutput[triangle.label()]:
            continue
        faceOutput[triangle.label()] = True

        contour = list(triangle.contour().phiOrbit())
        i = 0
        while i < len(contour):
            edgeOutput[contour[i].edgeLabel()] = skipInnerEdges
            neighbor = contour[i].rightFace()
            if neighbor.flag(ALPHA_MARK) and not faceOutput[neighbor.label()]:
                _ = contour[i].nextAlpha().nextPhi()
                contour.insert(i + 1, contour[i].clone().nextPhi())
                faceOutput[neighbor.label()] = True
            else:
                i += 1

        contour = Polygon([dart[0] for dart in contour])
        contour.append(contour[0])  # close poly (for filling)
        i = 2
        while i < len(contour):
            if contour[i] == contour[i - 2]:
                del contour[i - 2]
                del contour[i - 2]
                if i > 2:
                    i -= 1
            else:
                i += 1
        #print "  * %d points (area %s)" % (len(contour), contour.partialArea())
        fe.addClippedPoly(contour, **faceAttr)

    if "fillColor" in kwargs:
        del kwargs["fillColor"]
    if edgeDepth != None:
        print "- exporting remaining marked edges (depth %d)..." % edgeDepth
        for edge in delaunayMap.edgeIter():
            if not edge.flag(ALPHA_MARK) or edgeOutput[edge.label()]:
                continue

            dart = edge.dart()
            poly = Polygon(list(dart))
            edgeOutput[edge.label()] = True

            drawing = True
            while drawing:
                drawing = False
                dart.nextAlpha()
                for next in dart.sigmaOrbit():
                    outputEdge = next.edge()
                    if not outputEdge.flag(ALPHA_MARK) or edgeOutput[
                            outputEdge.label()]:
                        continue

                    drawing = True
                    assert poly[-1] == next[0]
                    if len(outputEdge) == 2:
                        poly.append(next[1])
                    else:
                        poly.extend(Polygon(list(next)[1:]))
                    edgeOutput[outputEdge.label()] = True

                    dart = next
                    break

            # continue in the other direction:
            poly.reverse()
            dart = edge.dart().nextAlpha()

            drawing = True
            while drawing:
                drawing = False
                dart.nextAlpha()
                next = dart.clone()
                while next.nextSigma() != dart:
                    outputEdge = next.edge()
                    if not outputEdge.flag(ALPHA_MARK) or edgeOutput[
                            outputEdge.label()]:
                        continue

                    drawing = True
                    assert poly[-1] == next[0]
                    poly.append(next[1])
                    edgeOutput[outputEdge.label()] = True

                    dart = next
                    break

            fe.addClippedPoly(poly,
                              depth=edgeDepth,
                              capStyle=capStyle,
                              **kwargs)
Beispiel #13
0
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
Beispiel #14
0
    p1 = l1 * line.dir() + l3 * line.norm
    p2 = l1 * line.dir() + l4 * line.norm
    p3 = l2 * line.dir() + l4 * line.norm
    p4 = l2 * line.dir() + l3 * line.norm
    return Polygon([p1, p2, p3, p4, p1])

# --------------------------------------------------------------------

if __name__ == "__main__":
    import fig
    f = fig.File("cliptest.fig")
    cr = geomap.BoundingBox((0, 0), (4500, 4500))
    f.layer(1).remove()
    for o in f.findObjects(type = fig.PolylineBase, depth = 42):
        p = Polygon(o.points)
        if o.closed():
            p.append(p[0])
        pp = clipPoly(p, cr)
        for p in pp:
            no = fig.Polygon(p, p[0] == p[-1])
            no.depth = 1
            no.lineWidth = 3
            if no.closed():
                no.fillStyle = fig.FillStyle.Solid
                no.fillColor = f.getColor(0.5)
            else:
                no.forwardArrow = fig.Arrow()
            f.append(no)
    f.save(fig2dev = "eps")

Beispiel #15
0
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
Beispiel #16
0
    p1 = l1 * line.dir() + l3 * line.norm
    p2 = l1 * line.dir() + l4 * line.norm
    p3 = l2 * line.dir() + l4 * line.norm
    p4 = l2 * line.dir() + l3 * line.norm
    return Polygon([p1, p2, p3, p4, p1])


# --------------------------------------------------------------------

if __name__ == "__main__":
    import fig
    f = fig.File("cliptest.fig")
    cr = geomap.BoundingBox((0, 0), (4500, 4500))
    f.layer(1).remove()
    for o in f.findObjects(type=fig.PolylineBase, depth=42):
        p = Polygon(o.points)
        if o.closed():
            p.append(p[0])
        pp = clipPoly(p, cr)
        for p in pp:
            no = fig.Polygon(p, p[0] == p[-1])
            no.depth = 1
            no.lineWidth = 3
            if no.closed():
                no.fillStyle = fig.FillStyle.Solid
                no.fillColor = f.getColor(0.5)
            else:
                no.forwardArrow = fig.Arrow()
            f.append(no)
    f.save(fig2dev="eps")