Esempio n. 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
Esempio n. 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
Esempio n. 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]
Esempio n. 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]
Esempio n. 5
0
def smallestBoundingBox(ch):
    """Determine rotated bbox from convex hull"""
    # FIXME: use rotating calipers for O(N) instead of O(N^2)!
    assert ch.closed()
    bboxes = []
    for seg in polyLineSegments(ch):
        line = seg.line()
        norm = line.norm
        dir = line.dir()
        dists = []
        positions = []
        for p in ch:
            dists.append(numpy.dot(norm, p))
            positions.append(numpy.dot(dir, p))
        l1 = min(positions)
        l2 = max(positions)
        l3 = min(dists)
        l4 = max(dists)
        area = (l2 - l1) * (l4 - l3)
        bboxes.append((area, line, l1, l2, l3, l4))
    bboxes.sort()
    _, line, l1, l2, l3, l4 = bboxes[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])
Esempio n. 6
0
def subsetDigitization(poly, shift=None, size=None):
    """Sample poly with a regular grid at integer coordinates starting
    from (0,0) to the given size (which should be a Size2D object)."""

    if size == None:
        size = poly.boundingBox().size()
        size = (int(math.ceil(size[0])) + 2, int(math.ceil(size[1])) + 2)
        if not shift:
            shift = (0, 0)
        shift = numpy.asarray(shift) + (1, 1) - poly.boundingBox().begin()
        poly = Polygon(poly + shift)

    result = vigra.GrayImage(size)
    for p in vigra.meshIter(size):
        result[p] = poly.contains((p[0], p[1])) and 1 or 0
    return result
Esempio n. 7
0
    def addEdge(self,
                points,
                simplifyEpsilon=0.5,
                container=True,
                figClass=fig.Polygon,
                **attr):
        """fe.addEdge(points, simplifyEpsilon, ...)

        Adds and returns exactly one fig.Polygon object representing
        the given points.  You will probably want to use
        addClippedPoly() instead.

        If simplifyEpsilon (default: 0.5) is not None, simplifyPolygon
        is called on the *scaled* polygon (i.e. the default is to
        simplify the polygon to 0.5 fig units, which are integer
        anyways)."""

        if container == True:
            container = self.f
        o = self.offset + attr.get('offset', (0, 0))
        if self.roi:
            o -= self.roi.begin()
        pp = Polygon([(o + point) * self.scale for point in points])
        if simplifyEpsilon:
            pp = simplifyPolygon(pp, simplifyEpsilon)
        fp = figClass([intPos(v) for v in pp], closed=pp[0] == pp[-1])
        for a in attr:
            if a != "offset":
                setattr(fp, a, attr[a])
        container.append(fp)
        return fp
Esempio n. 8
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
Esempio n. 9
0
def subsetDigitization(poly, shift = None, size = None):
    """Sample poly with a regular grid at integer coordinates starting
    from (0,0) to the given size (which should be a Size2D object)."""

    if size == None:
        size = poly.boundingBox().size()
        size = (int(math.ceil(size[0]))+2,
                int(math.ceil(size[1]))+2)
        if not shift:
            shift = (0, 0)
        shift = numpy.asarray(shift) + (1, 1) - poly.boundingBox().begin()
        poly = Polygon(poly + shift)

    result = vigra.GrayImage(size)
    for p in vigra.meshIter(size):
        result[p] = poly.contains((p[0], p[1])) and 1 or 0
    return result
Esempio n. 10
0
    def addClippedPoly(self, polygon, **attr):
        """fe.addClippedPoly(polygon, ...)

        Adds and returns exactly fig.Polygon objects for each part of
        the given polygon which is in the clipping range.  Again, note
        the possibility of setting properties (depth, penColor,
        lineStyle, lineWidth, ...) on all resulting objects via
        keyword arguments (cf. documentation of the FigExporter
        class).

        If simplifyEpsilon (default: 0.5) is not None, simplifyPolygon
        is called on the *scaled* polygon (i.e. the default is to
        simplify the polygon to 0.5 fig units, which are integer
        anyways)."""

        if "fillColor" in attr and not "fillStyle" in attr:
            attr["fillStyle"] = fig.FillStyle.Solid

        # no ROI to clip to?
        if not self.roi:
            return [self.addEdge(polygon, **attr)]

        if type(polygon) != Polygon:
            if not isinstance(polygon, list):
                polygon = Polygon(list(polygon))
            else:
                polygon = Polygon(polygon)

        clipRect = BoundingBox(self.roi)
        o = self.offset + attr.get('offset', (0,0))
        clipRect.moveBy(-o)

        # handle all-or-none cases:
        if not clipRect.intersects(polygon.boundingBox()):
            return []
        if clipRect.contains(polygon.boundingBox()):
            return [self.addEdge(polygon, **attr)]

        # general case: perform clipping, add parts one-by-one:
        result = [] # fig.Compound(container) - I dont't dare grouping here..
        closeAtBorder = (
            attr.get("fillStyle", fig.FillStyle.None) != fig.FillStyle.None)
        for part in clipPoly(polygon, clipRect, closeAtBorder):
            if part.length(): # don't add zero-length polygons
                result.append(self.addEdge(part, **attr))
        return result
Esempio n. 11
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
Esempio n. 12
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
Esempio n. 13
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
Esempio n. 14
0
    def addROIRect(self, roi=None, container=True, **attr):
        """fe.addROIRect(roi, depth = 85, ...)

        Adds a rectangle around the given roi (ignoring fe.offset).
        If roi == None (default), the roi of the FigExporter itself is used.
        The fig.PolyBox object is returned."""

        assert roi or self.roi, "addROIRect(): no ROI given!?"

        if container == True:
            container = self.f

        if isinstance(roi, Rect2D):
            roi = BoundingBox(roi)
            roi.moveBy((-0.5, -0.5))

        if roi is None:
            roi = self.roi
            assert not isinstance(roi, Rect2D)
            roi = BoundingBox(roi)
            roi.moveBy(-self.offset)  # BAAH!  What a bad design (self.roi)
        elif self.roi and not self.roi.contains(roi):
            sys.stderr.write("WARNING: addROIRect: ROI out of bounds!\n")
            poly = Polygon([
                roi.begin(),
                roi.begin() + (0, roi.size()[1]),
                roi.end(),
                roi.begin() + (roi.size()[0], 0),
                roi.begin()
            ])
            result = self.addClippedPoly(poly, container=container, **attr)
            if result:
                assert len(result) == 1
                return result[0]
            return

        roi = BoundingBox(roi)
        roi.moveBy(self.offset)
        if self.roi:
            roi.moveBy(-self.roi.begin())

        if "fillColor" in attr and not "fillStyle" in attr:
            attr["fillStyle"] = fig.FillStyle.Solid

        result = fig.PolyBox(roi.begin()[0] * self.scale,
                             roi.begin()[1] * self.scale,
                             roi.end()[0] * self.scale,
                             roi.end()[1] * self.scale)
        container.append(result)
        for a in attr:
            setattr(result, a, attr[a])
        return result
Esempio n. 15
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
Esempio n. 16
0
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
Esempio n. 17
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
Esempio n. 18
0
def euclideanPath(crackPoly, closed = None):
    """Return tangent-driven Euclidean Path for the given `crackPoly`.
    If the polygon is not `closed` (default/None: auto-detect), the
    first and last points will not be changed (no tangent known)."""

    fc = freeman(crackPoly)
    if closed == None:
        closed = crackPoly[-1] == crackPoly[0]
    result = Polygon(crackPoly)
    if closed:
        eo = offset2(fc, 0, closed)
        result[0] += eo
        result[-1] += eo
    for i in range(1, len(result)-1):
        result[i] += offset2(fc, i, closed)
    return result
Esempio n. 19
0
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
Esempio n. 20
0
    def addClippedPoly(self, polygon, **attr):
        """fe.addClippedPoly(polygon, ...)

        Adds and returns exactly fig.Polygon objects for each part of
        the given polygon which is in the clipping range.  Again, note
        the possibility of setting properties (depth, penColor,
        lineStyle, lineWidth, ...) on all resulting objects via
        keyword arguments (cf. documentation of the FigExporter
        class).

        If simplifyEpsilon (default: 0.5) is not None, simplifyPolygon
        is called on the *scaled* polygon (i.e. the default is to
        simplify the polygon to 0.5 fig units, which are integer
        anyways)."""

        if "fillColor" in attr and not "fillStyle" in attr:
            attr["fillStyle"] = fig.FillStyle.Solid

        # no ROI to clip to?
        if not self.roi:
            return [self.addEdge(polygon, **attr)]

        if type(polygon) != Polygon:
            if not isinstance(polygon, list):
                polygon = Polygon(list(polygon))
            else:
                polygon = Polygon(polygon)

        clipRect = BoundingBox(self.roi)
        o = self.offset + attr.get('offset', (0, 0))
        clipRect.moveBy(-o)

        # handle all-or-none cases:
        if not clipRect.intersects(polygon.boundingBox()):
            return []
        if clipRect.contains(polygon.boundingBox()):
            return [self.addEdge(polygon, **attr)]

        # general case: perform clipping, add parts one-by-one:
        result = []  # fig.Compound(container) - I dont't dare grouping here..
        closeAtBorder = (attr.get("fillStyle", fig.FillStyle.None) !=
                         fig.FillStyle.None)
        for part in clipPoly(polygon, clipRect, closeAtBorder):
            if part.length():  # don't add zero-length polygons
                result.append(self.addEdge(part, **attr))
        return result
Esempio n. 21
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
Esempio n. 22
0
    def polygon(self):
        """path.polygon() -> Polygon

        Returns a polygon containing all points of this path."""

        return Polygon(list(self.points()))
Esempio n. 23
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")
Esempio n. 24
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)
Esempio n. 25
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
Esempio n. 26
0
    _, line, l1, l2, l3, l4 = bboxes[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")
Esempio n. 27
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)