Пример #1
0
def cdtFromPSLG(pslg, onlyInner = False):
    """cdtFromPSLG(pslg, onlyInner) -> GeoMap

    Return a CDT for the given planar straight line graph.  `pslg`
    should be a GeoMap whose node positions are simple input points
    and edges define constraint segments.

    FIXME: ATM, this function may crash if the input contains
    duplicate points (e.g. within the same edge).  This is due to a
    limitation of the triangle module, i.e. J. Shewchuck's code.
    """
#     return constrainedDelaunayMap(
#         list(pslg.edgeIter()), pslg.imageSize(),
#         [node.position() for node in pslg.nodeIter() if node.isIsolated()],
#         onlyInner = False)

    points = []
    segments = []
    holes = []

    nodes = [None] * pslg.maxNodeLabel()
    for node in pslg.nodeIter():
        nodes[node.label()] = len(points)
        points.append(node.position())

    for edge in pslg.edgeIter():
        l = len(points)
        edgeSegments = [(l+i-1, l+i) for i in range(len(edge)-1)]
        edgeSegments[0] = (nodes[edge.startNodeLabel()], edgeSegments[0][1])
        edgeSegments[-1] = (edgeSegments[-1][0], nodes[edge.endNodeLabel()])
        points.extend(edge[1:-1])
#         for i in range(1, len(edge)-1):
#             assert edge[i] not in points, "%s[%d] = ..%s,%s,%s,.. is already present!" % (
#                 edge, i, edge[i-1], edge[i], edge[i+1])
#             points.append(edge[i])
        segments.extend(edgeSegments)

    for face in pslg.faceIter(skipInfinite = True):
        if face.flag(OUTER_FACE):
            # FIXME: re-use available scanlines for face:
            holes.append(_pointInHole(contourPoly(face.contour())))

    print "- performing Constrained Delaunay Triangulation..."
    print "  (%d points, %s segments, %d holes)" % (
        len(points), len(segments), len(holes))
    nodePositions, edgeData = triangle.constrainedDelaunay(
        points, segments, onlyInner, holes)

    print "- storing result in a GeoMap..."
    result = _delaunayMapFromData(nodePositions, edgeData, pslg.imageSize())

    for edge in result.edgeIter():
        if edgeData[edge.label()][2]:
            edge.setFlag(CONTOUR_SEGMENT)

    result.face(0).setFlag(OUTER_FACE)
    for holePoint in holes:
        result.faceAt(holePoint).setFlag(OUTER_FACE)

    return result
Пример #2
0
def cdtFromPSLG(pslg, onlyInner = False):
    """cdtFromPSLG(pslg, onlyInner) -> GeoMap

    Return a CDT for the given planar straight line graph.  `pslg`
    should be a GeoMap whose node positions are simple input points
    and edges define constraint segments.

    FIXME: ATM, this function may crash if the input contains
    duplicate points (e.g. within the same edge).  This is due to a
    limitation of the triangle module, i.e. J. Shewchuck's code.
    """
#     return constrainedDelaunayMap(
#         list(pslg.edgeIter()), pslg.imageSize(),
#         [node.position() for node in pslg.nodeIter() if node.isIsolated()],
#         onlyInner = False)

    points = []
    segments = []
    holes = []

    nodes = [None] * pslg.maxNodeLabel()
    for node in pslg.nodeIter():
        nodes[node.label()] = len(points)
        points.append(node.position())

    for edge in pslg.edgeIter():
        l = len(points)
        edgeSegments = [(l+i-1, l+i) for i in range(len(edge)-1)]
        edgeSegments[0] = (nodes[edge.startNodeLabel()], edgeSegments[0][1])
        edgeSegments[-1] = (edgeSegments[-1][0], nodes[edge.endNodeLabel()])
        points.extend(edge[1:-1])
#         for i in range(1, len(edge)-1):
#             assert edge[i] not in points, "%s[%d] = ..%s,%s,%s,.. is already present!" % (
#                 edge, i, edge[i-1], edge[i], edge[i+1])
#             points.append(edge[i])
        segments.extend(edgeSegments)

    for face in pslg.faceIter(skipInfinite = True):
        if face.flag(OUTER_FACE):
            # FIXME: re-use available scanlines for face:
            holes.append(_pointInHole(contourPoly(face.contour())))

    print "- performing Constrained Delaunay Triangulation..."
    print "  (%d points, %s segments, %d holes)" % (
        len(points), len(segments), len(holes))
    nodePositions, edgeData = triangle.constrainedDelaunay(
        points, segments, onlyInner, holes)

    print "- storing result in a GeoMap..."
    result = _delaunayMapFromData(nodePositions, edgeData, pslg.imageSize())

    for edge in result.edgeIter():
        if edgeData[edge.label()][2]:
            edge.setFlag(CONTOUR_SEGMENT)

    result.face(0).setFlag(OUTER_FACE)
    for holePoint in holes:
        result.faceAt(holePoint).setFlag(OUTER_FACE)

    return result
Пример #3
0
def faceCDTMap(face, imageSize,
               simplifyEpsilon = None,
               resample = None,
               onlyInner = True):
    """USAGE: dlm = faceCDTMap(face, mapSize)

    `face` should be a GeoMap.Face object, and all its contours will
    be extracted.  `mapSize` is used to initialize the GeoMap with the
    resulting edges.

    Optional keyword parameters:

    simplifyEpsilon
      If given, each contour polygon is simplified by calling
      simplifyPolygon with this epsilon as parameter (default None ->
      don't use simplifyPolygon).

    markContour
      If True(default), the point list is expected to be a sorted
      list, and edges between successive entries are marked as contour
      edges (an exception is raised if such a connection is
      missing). A `jumpPoints` list is used to mark multiple
      contours.

    onlyInner
      If True(default), all edges outside (left) of the marked contour
      are removed in a post-processing step.  (This has no effect if
      `markContour` is False.)"""

    polygons = [contourPoly(c) for c in face.contours()]
    if resample:
        polygons = [geomap.resamplePolygon(p, resample) for p in polygons]
    if simplifyEpsilon != None:
        polygons = [geomap.simplifyPolygon(p, simplifyEpsilon) for p in polygons]

    if triangle:
        result = constrainedDelaunayMap(polygons, imageSize)
    else:
        result = fakedConstrainedDelaunayMap(polygons, imageSize)

    return result
Пример #4
0
def faceCDTMap(face, imageSize,
               simplifyEpsilon = None,
               resample = None,
               onlyInner = True):
    """USAGE: dlm = faceCDTMap(face, mapSize)

    `face` should be a GeoMap.Face object, and all its contours will
    be extracted.  `mapSize` is used to initialize the GeoMap with the
    resulting edges.
      
    Optional keyword parameters:

    simplifyEpsilon
      If given, each contour polygon is simplified by calling
      simplifyPolygon with this epsilon as parameter (default None ->
      don't use simplifyPolygon).

    markContour
      If True(default), the point list is expected to be a sorted
      list, and edges between successive entries are marked as contour
      edges (an exception is raised if such a connection is
      missing). A `jumpPoints` list is used to mark multiple
      contours.

    onlyInner
      If True(default), all edges outside (left) of the marked contour
      are removed in a post-processing step.  (This has no effect if
      `markContour` is False.)"""

    polygons = [contourPoly(c) for c in face.contours()]
    if resample:
        polygons = [geomap.resamplePolygon(p, resample) for p in polygons]
    if simplifyEpsilon != None:
        polygons = [geomap.simplifyPolygon(p, simplifyEpsilon) for p in polygons]

    if triangle:
        result = constrainedDelaunayMap(polygons, imageSize)
    else:
        result = fakedConstrainedDelaunayMap(polygons, imageSize)

    return result
Пример #5
0
    def addMapFaces(self,
                    geomap,
                    faceMeans=None,
                    similarity=None,
                    returnFaces=False,
                    container=True,
                    **attr):
        """fe.addMapFaces(geomap, faceMeans, ...)

        Adds and returns fig.Polygons for all map faces (or -parts,
        see addClippedPoly).  Clipping closed polygons should work
        nowadays, too."""

        import maputils

        def getGray(face):
            faceColor = faceMeans[face.label()]
            return self.f.gray(int(faceColor))

        def getRGB(face):
            faceColor = faceMeans[face.label()]
            return self.f.getColor(map(int, tuple(faceColor)), similarity)

        if not faceMeans:
            if not hasattr(geomap, "faceMeans"):
                raise ValueError(
                    "addMapFaces: need faceMeans for proper coloring")
            faceMeans = geomap.faceMeans

        if hasattr(faceMeans, "bands"):
            getFaceColor = getGray
            if faceMeans.bands() == 3:
                getFaceColor = getRGB
        else:
            getFaceColor = lambda face: faceMeans[face.label()]

        if container == True:
            container = self.f

        attr = dict(attr)
        attr["lineWidth"] = attr.get("lineWidth", 0)
        attr["fillStyle"] = attr.get("fillStyle", fig.FillStyle.Solid)

        compound = fig.Compound(container)
        if returnFaces:
            result = []
        else:
            result = compound

        todo = [geomap.face(0)]
        # +1 because the first iteration will not add any objects:
        currentDepth = attr.get("depth", 100) + 1
        while todo:
            thisLayer = todo
            todo = []
            for face in thisLayer:
                if face.area() > 0:
                    color = getFaceColor(face)
                    if color is not None:
                        thisattr = dict(attr)
                        thisattr["fillColor"] = getFaceColor(face)
                        thisattr["depth"] = currentDepth
                        parts = self.addClippedPoly(contourPoly(
                            face.contour()),
                                                    container=compound,
                                                    **thisattr)

                        if returnFaces:
                            result.extend([(face, part) for part in parts])

                for anchor in face.holeContours():
                    todo.extend(maputils.holeComponent(anchor))

            currentDepth -= 1

        return result
Пример #6
0
def addMapOverlay(fe, overlay, skipBorder=False, **attr):
    qtColor2figColor = figexport.qtColor2figColor

    # FIXME: str(type(overlay)).contains(...) instead?
    if isinstance(overlay, ROISelector):
        color = qtColor2figColor(overlay.color, fe.f)
        return fe.addROIRect(overlay.roi, penColor=color, **attr)
    elif isinstance(overlay, (MapNodes, MapEdges, MapFaces)):
        oldScale, oldOffset, oldROI = fe.scale, fe.offset, fe.roi

        if isinstance(overlay, MapFaces):
            zoom = overlay.edgeOverlay._zoom
        else:
            zoom = overlay._zoom
        extraZoom = float(zoom) / overlay.viewer.zoomFactor()
        fe.scale *= extraZoom
        fe.roi = BoundingBox(fe.roi.begin() / extraZoom,
                             fe.roi.end() / extraZoom)
        map = overlay._map()

        if isinstance(overlay, MapNodes):
            radius = overlay.origRadius
            if not overlay.relativeRadius:
                radius /= float(overlay._zoom)
            color = qtColor2figColor(overlay.color, fe.f)

            result = fe.addMapNodes(map,
                                    radius,
                                    fillColor=color,
                                    lineWidth=0,
                                    **attr)
        elif isinstance(overlay, MapEdges):
            attr = dict(attr)
            if overlay.width:
                attr["lineWidth"] = overlay.width

            if overlay.colors:
                result = fig.Compound(fe.f)
                for edge in map.edgeIter():
                    edgeColor = overlay.colors[edge.label()]
                    if edgeColor:
                        fe.addClippedPoly(edge,
                                          penColor=qtColor2figColor(
                                              edgeColor, fe.f),
                                          container=result,
                                          **attr)
            elif overlay.color:
                result = fe.addMapEdges(map,
                                        skipBorder=skipBorder,
                                        penColor=qtColor2figColor(
                                            overlay.color, fe.f),
                                        **attr)
            else:
                result = fig.Compound(fe.f)

            if overlay.protectedColor:
                attr["penColor"] = \
                    qtColor2figColor(overlay.protectedColor, fe.f)
                attr["lineWidth"] = overlay.protectedWidth or overlay.width
                it = skipBorder and maputils.nonBorderEdges(map) \
                     or map.edgeIter()
                for edge in it:
                    if edge.flag(flag_constants.ALL_PROTECTION):
                        fe.addClippedPoly(edge, container=result, **attr)
        else:  # isinstance(overlay, MapFaces)
            attr = dict(attr)
            if overlay.color:
                if overlay.width:
                    attr["lineWidth"] = overlay.width
                attr["penColor"] = qtColor2figColor(overlay.color, fe.f)
            if overlay.fillColor:
                attr["fillColor"] = qtColor2figColor(overlay.fillColor, fe.f)
                attr["fillStyle"] = fig.FillStyle.Solid
            result = fig.Compound(fe.f)
            for face in map.faceIter():
                if face.flag(overlay.flags):
                    if face.holeCount:
                        assert not overlay.fillColor or not overlay.color, "FIXME: cannot currently export filled+stroked polygons with holes"
                    if not overlay.color:
                        wholePoly = list(contourPoly(face.contour()))
                        back = wholePoly[0]
                        assert wholePoly[-1] == back
                        for dart in face.holeContours():
                            wholePoly.extend(contourPoly(dart))
                            wholePoly.append(back)
                        fe.addClippedPoly(wholePoly, container=result, **attr)
                    else:
                        for dart in face.contours():
                            fe.addClippedPoly(contourPoly(dart),
                                              container=result,
                                              **attr)

        fe.scale, fe.offset, fe.roi = oldScale, oldOffset, oldROI
        return result
    else:
        return figexport.addStandardOverlay(fe, overlay, **attr)
Пример #7
0
# which ATM leads to overlapping edges after border closing. That
# violates some assumptions and would lead to errors if we actually
# worked with that Map.
map = GeoMap(maxima2, [], Size2D(39, 39))
maputils.addFlowLinesToMap(flowlines2, map)
assert map.checkConsistency(), "graph inconsistent"
map.sortEdgesEventually(stepDist = 0.2, minDist = 0.05)
map.splitParallelEdges()
map.initializeMap()
assert map.checkConsistency(), "map inconsistent"
assert maputils.checkLabelConsistency(map), "map.labelImage() inconsistent"

# merge faces so that survivor has a hole:
hole = map.faceAt((16,17))
assert hole.contains((16,17))
assert contourPoly(hole.contour()).contains((16,17))

dart = hole.contour()
while True:
    while dart.startNode().hasMinDegree(3):
        face = maputils.removeEdge(dart.clone().prevSigma())
    if dart.nextPhi() == hole.contour():
        break

assert face.holeCount() > 0 # should have hole
for p in [(3, 24), (10, 15), (13, 21)]: # in region, but not within hole
    assert face.contains(p)

for p in [(16, 17), (13, 17)]: # in hole
    assert not face.contains(p)
    assert hole.contains(p)
Пример #8
0
# which ATM leads to overlapping edges after border closing. That
# violates some assumptions and would lead to errors if we actually
# worked with that Map.
map = GeoMap(maxima2, [], Size2D(39, 39))
maputils.addFlowLinesToMap(flowlines2, map)
assert map.checkConsistency(), "graph inconsistent"
map.sortEdgesEventually(stepDist=0.2, minDist=0.05)
map.splitParallelEdges()
map.initializeMap()
assert map.checkConsistency(), "map inconsistent"
assert maputils.checkLabelConsistency(map), "map.labelImage() inconsistent"

# merge faces so that survivor has a hole:
hole = map.faceAt((16, 17))
assert hole.contains((16, 17))
assert contourPoly(hole.contour()).contains((16, 17))

dart = hole.contour()
while True:
    while dart.startNode().hasMinDegree(3):
        face = maputils.removeEdge(dart.clone().prevSigma())
    if dart.nextPhi() == hole.contour():
        break

assert face.holeCount() > 0  # should have hole
for p in [(3, 24), (10, 15), (13, 21)]:  # in region, but not within hole
    assert face.contains(p)

for p in [(16, 17), (13, 17)]:  # in hole
    assert not face.contains(p)
    assert hole.contains(p)
Пример #9
0
def addMapOverlay(fe, overlay, skipBorder = False, **attr):
    qtColor2figColor = figexport.qtColor2figColor

    # FIXME: str(type(overlay)).contains(...) instead?
    if isinstance(overlay, ROISelector):
        color = qtColor2figColor(overlay.color, fe.f)
        return fe.addROIRect(overlay.roi, penColor = color, **attr)
    elif isinstance(overlay, (MapNodes, MapEdges, MapFaces)):
        oldScale, oldOffset, oldROI = fe.scale, fe.offset, fe.roi

        if isinstance(overlay, MapFaces):
            zoom = overlay.edgeOverlay._zoom
        else:
            zoom = overlay._zoom
        extraZoom = float(zoom) / overlay.viewer.zoomFactor()
        fe.scale *= extraZoom
        fe.roi = BoundingBox(fe.roi.begin() / extraZoom,
                             fe.roi.end() / extraZoom)
        map = overlay._map()

        if isinstance(overlay, MapNodes):
            radius = overlay.origRadius
            if not overlay.relativeRadius:
                radius /= float(overlay._zoom)
            color = qtColor2figColor(overlay.color, fe.f)

            result = fe.addMapNodes(map, radius,
                                    fillColor = color, lineWidth = 0, **attr)
        elif isinstance(overlay, MapEdges):
            attr = dict(attr)
            if overlay.width:
                attr["lineWidth"] = overlay.width

            if overlay.colors:
                result = fig.Compound(fe.f)
                for edge in map.edgeIter():
                    edgeColor = overlay.colors[edge.label()]
                    if edgeColor:
                        fe.addClippedPoly(edge,
                            penColor = qtColor2figColor(edgeColor, fe.f),
                            container = result, **attr)
            elif overlay.color:
                result = fe.addMapEdges(
                    map, skipBorder = skipBorder,
                    penColor = qtColor2figColor(overlay.color, fe.f),
                    **attr)
            else:
                result = fig.Compound(fe.f)

            if overlay.protectedColor:
                attr["penColor"] = \
                    qtColor2figColor(overlay.protectedColor, fe.f)
                attr["lineWidth"] = overlay.protectedWidth or overlay.width
                it = skipBorder and maputils.nonBorderEdges(map) \
                     or map.edgeIter()
                for edge in it:
                    if edge.flag(flag_constants.ALL_PROTECTION):
                        fe.addClippedPoly(edge, container = result, **attr)
        else: # isinstance(overlay, MapFaces)
            attr = dict(attr)
            if overlay.color:
                if overlay.width:
                    attr["lineWidth"] = overlay.width
                attr["penColor"] = qtColor2figColor(overlay.color, fe.f)
            if overlay.fillColor:
                attr["fillColor"] = qtColor2figColor(overlay.fillColor, fe.f)
                attr["fillStyle"] = fig.FillStyle.Solid
            result = fig.Compound(fe.f)
            for face in map.faceIter():
                if face.flag(overlay.flags):
                    if face.holeCount:
                        assert not overlay.fillColor or not overlay.color, "FIXME: cannot currently export filled+stroked polygons with holes"
                    if not overlay.color:
                        wholePoly = list(contourPoly(face.contour()))
                        back = wholePoly[0]
                        assert wholePoly[-1] == back
                        for dart in face.holeContours():
                            wholePoly.extend(contourPoly(dart))
                            wholePoly.append(back)
                        fe.addClippedPoly(wholePoly,
                                          container = result, **attr)
                    else:
                        for dart in face.contours():
                            fe.addClippedPoly(contourPoly(dart),
                                              container = result, **attr)

        fe.scale, fe.offset, fe.roi = oldScale, oldOffset, oldROI
        return result
    else:
        return figexport.addStandardOverlay(fe, overlay, **attr)
Пример #10
0
    def addMapFaces(self, geomap, faceMeans = None, similarity = None,
                    returnFaces = False, container = True, **attr):
        """fe.addMapFaces(geomap, faceMeans, ...)

        Adds and returns fig.Polygons for all map faces (or -parts,
        see addClippedPoly).  Clipping closed polygons should work
        nowadays, too."""

        import maputils

        def getGray(face):
            faceColor = faceMeans[face.label()]
            return self.f.gray(int(faceColor))

        def getRGB(face):
            faceColor = faceMeans[face.label()]
            return self.f.getColor(map(int, tuple(faceColor)), similarity)

        if not faceMeans:
            if not hasattr(geomap, "faceMeans"):
                raise ValueError("addMapFaces: need faceMeans for proper coloring")
            faceMeans = geomap.faceMeans

        if hasattr(faceMeans, "bands"):
            getFaceColor = getGray
            if faceMeans.bands() == 3:
                getFaceColor = getRGB
        else:
            getFaceColor = lambda face: faceMeans[face.label()]

        if container == True:
            container = self.f

        attr = dict(attr)
        attr["lineWidth"] = attr.get("lineWidth", 0)
        attr["fillStyle"] = attr.get("fillStyle", fig.FillStyle.Solid)

        compound = fig.Compound(container)
        if returnFaces:
            result = []
        else:
            result = compound

        todo = [geomap.face(0)]
        # +1 because the first iteration will not add any objects:
        currentDepth = attr.get("depth", 100) + 1
        while todo:
            thisLayer = todo
            todo = []
            for face in thisLayer:
                if face.area() > 0:
                    color = getFaceColor(face)
                    if color is not None:
                        thisattr = dict(attr)
                        thisattr["fillColor"] = getFaceColor(face)
                        thisattr["depth"] = currentDepth
                        parts = self.addClippedPoly(
                            contourPoly(face.contour()),
                            container = compound, **thisattr)

                        if returnFaces:
                            result.extend([(face, part) for part in parts])

                for anchor in face.holeContours():
                    todo.extend(maputils.holeComponent(anchor))

            currentDepth -= 1

        return result