Example #1
0
    def __init__(self, dart, costMeasure, parent, name=None):
        self.__base.__init__(self, parent)
        if name:
            self.setObjectName(name)

        self.dart = dart
        self.costMeasure = costMeasure

        self.ui = Ui_DartNavigator()
        self.ui.setupUi(self)
        self.connect(self.ui.nextPhiButton, QtCore.SIGNAL("clicked()"),
                     self.nextPhi)
        self.connect(self.ui.prevPhiButton, QtCore.SIGNAL("clicked()"),
                     self.prevPhi)
        self.connect(self.ui.nextAlphaButton, QtCore.SIGNAL("clicked()"),
                     self.nextAlpha)
        self.connect(self.ui.nextSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.nextSigma)
        self.connect(self.ui.prevSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.prevSigma)

        self.connect(self.ui.continuousCheckBox,
                     QtCore.SIGNAL("toggled(bool)"), self.toggleContinuous)

        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"),
                     self.highlightNext)

        self._darthighlighter = DartHighlighter(parent.map, parent.viewer)
        self.updateLabel()
Example #2
0
    def __init__(self, dart, costMeasure, parent, name = None):
        self.__base.__init__(self, parent)
        if name:
            self.setObjectName(name)

        self.dart = dart
        self.costMeasure = costMeasure

        self.ui = Ui_DartNavigator()
        self.ui.setupUi(self)
        self.connect(self.ui.nextPhiButton, QtCore.SIGNAL("clicked()"),
                     self.nextPhi)
        self.connect(self.ui.prevPhiButton, QtCore.SIGNAL("clicked()"),
                     self.prevPhi)
        self.connect(self.ui.nextAlphaButton, QtCore.SIGNAL("clicked()"),
                     self.nextAlpha)
        self.connect(self.ui.nextSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.nextSigma)
        self.connect(self.ui.prevSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.prevSigma)

        self.connect(self.ui.continuousCheckBox, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleContinuous)

        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"),
                     self.highlightNext)

        self._darthighlighter = DartHighlighter(parent.map, parent.viewer)
        self.updateLabel()
Example #3
0
class DartNavigator(QtGui.QDialog):
    __base = QtGui.QDialog

    def __init__(self, dart, costMeasure, parent, name = None):
        self.__base.__init__(self, parent)
        if name:
            self.setObjectName(name)

        self.dart = dart
        self.costMeasure = costMeasure

        self.ui = Ui_DartNavigator()
        self.ui.setupUi(self)
        self.connect(self.ui.nextPhiButton, QtCore.SIGNAL("clicked()"),
                     self.nextPhi)
        self.connect(self.ui.prevPhiButton, QtCore.SIGNAL("clicked()"),
                     self.prevPhi)
        self.connect(self.ui.nextAlphaButton, QtCore.SIGNAL("clicked()"),
                     self.nextAlpha)
        self.connect(self.ui.nextSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.nextSigma)
        self.connect(self.ui.prevSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.prevSigma)

        self.connect(self.ui.continuousCheckBox, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleContinuous)

        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"),
                     self.highlightNext)

        self._darthighlighter = DartHighlighter(parent.map, parent.viewer)
        self.updateLabel()

    def closeEvent(self, e):
        self._darthighlighter.highlight(None)
        self.__base.closeEvent(self, e)
        if e.isAccepted():
            self.deleteLater() # like QtCore.Qt.WDestructiveClose ;-)

    def highlightNext(self):
        self.activePerm()
        self.updateLabel()

    def setDart(self, dart):
        self.dart = dart
        self.updateLabel()

    def toggleContinuous(self, onoff):
        if onoff:
            self.timer.start(1200)
        else:
            self.timer.stop()
        self.ui.nextPhiButton.setToggleButton(onoff)
        self.ui.prevPhiButton.setToggleButton(onoff)
        self.ui.nextAlphaButton.setToggleButton(onoff)
        self.ui.nextSigmaButton.setToggleButton(onoff)
        self.ui.prevSigmaButton.setToggleButton(onoff)

    def moveDart(self, perm):
        perm()
        self.updateLabel()
        self.activePerm = perm

    def nextPhi(self):
        self.moveDart(self.dart.nextPhi)

    def prevPhi(self):
        self.moveDart(self.dart.prevPhi)

    def nextAlpha(self):
        self.moveDart(self.dart.nextAlpha)

    def nextSigma(self):
        self.moveDart(self.dart.nextSigma)

    def prevSigma(self):
        self.moveDart(self.dart.prevSigma)

    def updateLabel(self):
        self._darthighlighter.highlight(self.dart.label())
        dartDesc = "Dart %d, length %.1f, partial area %.1f, %d points" % (
            self.dart.label(), self.dart.edge().length(),
            self.dart.partialArea(), len(self.dart))
        if self.costMeasure:
            dartDesc += "\nassociated cost: %s" % self.costMeasure(self.dart)
        self.ui.dartLabel.setText(dartDesc)
        for node, nodeLabel in ((self.dart.startNode(), self.ui.startNodeLabel),
                                (self.dart.endNode(), self.ui.endNodeLabel)):
            nodeLabel.setText(
                "Node %d (deg. %d)\nat %s" % (
                node.label(), node.degree(), node.position()))
        if self.dart.map().mapInitialized():
            leftFace = self.dart.leftFace()
            rightFace = self.dart.rightFace()
            self.ui.faceLabel.setText(
                """Left: %s\nRight: %s""" % (str(leftFace)[8:-1], str(rightFace)[8:-1]))
        self.setWindowTitle("DartNavigator(%d)" % (self.dart.label(), ))
        self.emit(QtCore.SIGNAL('updateDart'), self.dart)
Example #4
0
    def __init__(self,
                 map,
                 preparedImage=None,
                 immediateShow=True,
                 faceMeans=None):
        self.__base.__init__(self)

        self.tool = None
        self._togglingGUI = False
        self._faceMeans = None  # temp. needed (for _enableImageActions)

        self.ui = Ui_DisplaySettings()
        self.ui.setupUi(self)

        # for backward compatibility:
        if hasattr(preparedImage, "imageSize") and hasattr(map, "width"):
            map, preparedImage = preparedImage, map
        elif preparedImage is None:
            preparedImage = map.labelImage()
            if preparedImage is None:
                preparedImage = vigra.ScalarImage(map.imageSize())

        self.viewer = None  # setImage would norm. pass the image on
        if hasattr(preparedImage, "orig"):
            self.images = {
                "original": preparedImage.view,
                "colored": preparedImage.orig,
                "bi": preparedImage.bi.gm,
            }
            preparedImage = preparedImage.view
        else:
            self.images = {}
            # auto-detects role colored/original:
            self.setImage(preparedImage, normalize=False)

        self.image = preparedImage
        self.viewer = VigraQt.OverlayViewer(self)
        self.setCentralWidget(self.viewer)
        self._setImage(self.image, normalize=False)
        self.viewer.autoZoom()

        # convenience:
        self.addOverlay = self.viewer.addOverlay
        self.removeOverlay = self.viewer.removeOverlay
        #        self.overlays = self.viewer.overlays

        self.map = map
        if not faceMeans and hasattr(map, "faceMeans"):
            faceMeans = map.faceMeans
        self.setFaceMeans(faceMeans)
        self._attachedHooks = None

        self._normalizeStates = [False, False, True, True, False]
        if self.image.channels == 3:
            self._backgroundMode = 1
            self.ui.displayColoredAction.setChecked(True)
        else:
            self._backgroundMode = 0
            self.ui.displayOriginalAction.setChecked(True)
        self._enableImageActions()

        self.connect(self.ui.backgroundGroup,
                     QtCore.SIGNAL("selected(QAction*)"),
                     self.setBackgroundMode)
        self.connect(self.ui.nodeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNodeDisplay)
        self.connect(self.ui.edgeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleEdgeDisplay)
        self.connect(self.ui.normalizeAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNormalize)
        self.connect(self.ui.mapCleanupAction, QtCore.SIGNAL("activated()"),
                     self.cleanupMap)
        self.connect(self.ui.paintbrushAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activatePaintbrush)
        self.connect(self.ui.scissorsAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateScissors)
        self.connect(self.ui.navigateAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateNavigator)

        self.setWindowTitle("Map Display")

        self.edgeOverlay = MapEdges(self.viewer)
        self.edgeOverlay.setMap(map)
        self.edgeOverlay.setPen(QtCore.Qt.red)
        #                                    protectedColor = QtCore.Qt.green,
        #                                    protectedWidth = 2)
        self.viewer.addOverlay(self.edgeOverlay)
        self.edgeOverlay.visible = self.ui.edgeDisplayAction.isChecked()
        # self.nodeOverlay = MapNodes(map, QtCore.Qt.blue)
        # self.viewer.addOverlay(self.nodeOverlay)
        # self.nodeOverlay.visible = self.ui.nodeDisplayAction.isChecked()
        self._dh = DartHighlighter(map, self.viewer)
        self.dn = None

        if immediateShow:
            self.show()
Example #5
0
class MapDisplay(QtGui.QMainWindow):
    __base = QtGui.QMainWindow

    # actually, this has only documenting effect; since this inherits
    # PyQt widgets, any attribute may be used:
    __slots__ = ("tool", "viewer", "images", "image", "map", "nodeOverlay",
                 "edgeOverlay", "addOverlay", "removeOverlay", "_togglingGUI",
                 "_backgroundMode", "_normalizeStates", "_faceMeans",
                 "_attachedHooks", "dn", "_dh")

    def __init__(self,
                 map,
                 preparedImage=None,
                 immediateShow=True,
                 faceMeans=None):
        self.__base.__init__(self)

        self.tool = None
        self._togglingGUI = False
        self._faceMeans = None  # temp. needed (for _enableImageActions)

        self.ui = Ui_DisplaySettings()
        self.ui.setupUi(self)

        # for backward compatibility:
        if hasattr(preparedImage, "imageSize") and hasattr(map, "width"):
            map, preparedImage = preparedImage, map
        elif preparedImage is None:
            preparedImage = map.labelImage()
            if preparedImage is None:
                preparedImage = vigra.ScalarImage(map.imageSize())

        self.viewer = None  # setImage would norm. pass the image on
        if hasattr(preparedImage, "orig"):
            self.images = {
                "original": preparedImage.view,
                "colored": preparedImage.orig,
                "bi": preparedImage.bi.gm,
            }
            preparedImage = preparedImage.view
        else:
            self.images = {}
            # auto-detects role colored/original:
            self.setImage(preparedImage, normalize=False)

        self.image = preparedImage
        self.viewer = VigraQt.OverlayViewer(self)
        self.setCentralWidget(self.viewer)
        self._setImage(self.image, normalize=False)
        self.viewer.autoZoom()

        # convenience:
        self.addOverlay = self.viewer.addOverlay
        self.removeOverlay = self.viewer.removeOverlay
        #        self.overlays = self.viewer.overlays

        self.map = map
        if not faceMeans and hasattr(map, "faceMeans"):
            faceMeans = map.faceMeans
        self.setFaceMeans(faceMeans)
        self._attachedHooks = None

        self._normalizeStates = [False, False, True, True, False]
        if self.image.channels == 3:
            self._backgroundMode = 1
            self.ui.displayColoredAction.setChecked(True)
        else:
            self._backgroundMode = 0
            self.ui.displayOriginalAction.setChecked(True)
        self._enableImageActions()

        self.connect(self.ui.backgroundGroup,
                     QtCore.SIGNAL("selected(QAction*)"),
                     self.setBackgroundMode)
        self.connect(self.ui.nodeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNodeDisplay)
        self.connect(self.ui.edgeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleEdgeDisplay)
        self.connect(self.ui.normalizeAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNormalize)
        self.connect(self.ui.mapCleanupAction, QtCore.SIGNAL("activated()"),
                     self.cleanupMap)
        self.connect(self.ui.paintbrushAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activatePaintbrush)
        self.connect(self.ui.scissorsAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateScissors)
        self.connect(self.ui.navigateAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateNavigator)

        self.setWindowTitle("Map Display")

        self.edgeOverlay = MapEdges(self.viewer)
        self.edgeOverlay.setMap(map)
        self.edgeOverlay.setPen(QtCore.Qt.red)
        #                                    protectedColor = QtCore.Qt.green,
        #                                    protectedWidth = 2)
        self.viewer.addOverlay(self.edgeOverlay)
        self.edgeOverlay.visible = self.ui.edgeDisplayAction.isChecked()
        # self.nodeOverlay = MapNodes(map, QtCore.Qt.blue)
        # self.viewer.addOverlay(self.nodeOverlay)
        # self.nodeOverlay.visible = self.ui.nodeDisplayAction.isChecked()
        self._dh = DartHighlighter(map, self.viewer)
        self.dn = None

        if immediateShow:
            self.show()

    def __del__(self):
        # delete tool (which may reference the viewer & map)
        self.setTool(None)

    def _dartNavigatorDestroyed(self, dn):
        """HACK: this is needed because of the deleteLater()..."""
        # FIXME: cannot reliably detect identity of half-destructed
        # object anymore:
        #if dn is self.dn:
        self.dn = None

    def _labelImage(self):
        result = self.map.labelImage()
        if result is None:
            result = maputils.drawLabelImage(self.map)
        return result

    def setMap(self, map):
        attached = self.detachHooks()

        self.setTool(None)
        self.map = map
        self.edgeOverlay.setMap(map)
        #self.nodeOverlay.setMap(map)
        self._dh.setMap(map)

        updatedDisplayImage = None
        if self._backgroundMode == 3:
            updatedDisplayImage = self._labelImage()

        self._faceMeans = None
        if hasattr(map, "faceMeans"):
            self.setFaceMeans(map.faceMeans)
            if self._backgroundMode == 4:
                updatedDisplayImage = \
                    self._faceMeans.regionImage(self._labelImage())
        self._enableImageActions()

        if updatedDisplayImage:
            self._setImage(updatedDisplayImage,
                           self._normalizeStates[self._backgroundMode])

        if attached:
            self.attachHooks()

        self.viewer.update()

    def setFaceMeans(self, faceMeans):
        self._faceMeans = faceMeans
        self._enableImageActions()

    def _adjustSize(self):
        pass  # don't change window size out of a sudden

    def statusMessage(self, msg):
        # workaround - don't know why connecting the PYSIGNAL directly
        # does not work (maybe QtCore.SIGNAL("captionChanged(QString)")
        # would work?)
        self.statusBar().showMessage(msg)

    def currentRole(self):
        return ("original", "colored", "bi", "labels",
                "faceMeans")[self._backgroundMode]

    def setBackgroundMode(self, mode):
        if type(mode) != int:
            mode = [
                self.ui.displayOriginalAction, self.ui.displayColoredAction,
                self.ui.displayBIAction, self.ui.displayLabelsAction,
                self.ui.displayMeansAction
            ].index(mode)

        displayImage = None
        if mode == 0:
            displayImage = self.images["original"]
        elif mode == 1:
            displayImage = self.images["colored"]
        elif mode == 2:
            displayImage = self.images["bi"]
        elif mode == 3:
            displayImage = self._labelImage()
        elif mode == 4:
            displayImage = self._faceMeans.regionImage(self._labelImage())
        else:
            sys.stderr.write("Unknown background mode %d!\n" % mode)
            return

        self.image = displayImage
        self._backgroundMode = mode
        normalize = self._normalizeStates[mode]
        if self.ui.normalizeAction.isChecked() != normalize:
            self.ui.normalizeAction.setChecked(normalize)
        else:
            self._setImage(self.image, normalize)

    def toggleNodeDisplay(self, onoff):
        return  # TEMP
        if self.nodeOverlay.visible != onoff:
            self.nodeOverlay.visible = onoff
            self.viewer.update()

    def toggleEdgeDisplay(self, onoff):
        if self.edgeOverlay.visible != onoff:
            self.edgeOverlay.visible = onoff
            self.viewer.update()

    def toggleNormalize(self, normalize):
        self._normalizeStates[self._backgroundMode] = normalize
        self._setImage(self.image, normalize)

    def attachHooks(self):
        return
        self.nodeOverlay.attachHooks()
        self.edgeOverlay.attachHooks()
        self._attachedHooks = (self.map.addMergeFacesCallbacks(
            None, self._postMergeFacesHook),
                               self.map.addRemoveBridgeCallbacks(
                                   self._preRemoveBridgeHook,
                                   self._postRemoveBridgeHook))

    def detachHooks(self):
        """Detaches / removes callbacks from the map's hooks.
        Returns True if successful, False if already detached."""
        return
        results = (self.nodeOverlay.detachHooks(),
                   self.edgeOverlay.detachHooks())

        if self._attachedHooks:
            for h in self._attachedHooks:
                h.disconnect()
            self._attachedHooks = None

            if results == (True, True):
                return True
        else:
            if results == (False, False):
                return False

    def _redisplayROIImage(self, roi):
        roi &= Rect2D(self.map.imageSize())
        roiImage = self._labelImage().subImage(roi)
        if self._backgroundMode > 3:
            roiImage = self._faceMeans.regionImage(roiImage)
        # FIXME: use global normalization here
        self.viewer.replaceROI(roiImage.toPNM(vigra.BYTE),
                               QtCore.QPoint(*roi.upperLeft()))

    def _postMergeFacesHook(self, survivor):
        if self._backgroundMode < 3:
            return
        if survivor.label():
            self._redisplayROIImage(intPos(survivor.boundingBox()))

    def _preRemoveBridgeHook(self, dart):
        if self._backgroundMode >= 3:
            self._bridgeROI = intPos(dart.edge().boundingBox())
        return True

    def _postRemoveBridgeHook(self, dart):
        if self._backgroundMode < 3:
            return
        self._redisplayROIImage(self._bridgeROI)

    def showEvent(self, e):
        self.attachHooks()
        return self.__base.showEvent(self, e)

    def hideEvent(self, e):
        self.detachHooks()
        return self.__base.hideEvent(self, e)

    def showMarkedEdges(self,
                        colorMarked=QtCore.Qt.green,
                        colorUnmarked=None,
                        markFlags=flag_constants.ALL_PROTECTION):
        edgeColors = [None] * self.map.maxEdgeLabel()
        for edge in self.map.edgeIter():
            if edge.flag(markFlags):
                edgeColors[edge.label()] = colorMarked
            else:
                edgeColors[edge.label()] = colorUnmarked
        self.edgeOverlay.colors = edgeColors
        self.viewer.update()

    def showAllEdges(self):
        self.edgeOverlay.colors = None
        self.viewer.update()

    def setTool(self, tool=None):
        """Deactivates and destroys old tool, activates/sets new one
        if tool != None.  `tool` can be either a tool object or

        1 for the MapSearcher tool
        2 for the ActivatePaintbrush
        3 for the IntelligentScissors
        4 for the SeedSelector"""

        if self._togglingGUI:
            return  # no recursion please
        if self.tool:
            self.tool.disconnectViewer()
            if self.tool.parent() == self:
                self.tool.deleteLater()
            self.tool = None

        if tool == 1:
            self.tool = tools.MapSearcher(self.map, self)
        elif tool == 2:
            self.tool = tools.ActivePaintbrush(self.map, self)
        elif tool == 3:
            if self.edgeOverlay.color == QtCore.Qt.red:
                self.edgeOverlay.color = QtCore.Qt.black
            self.nodeOverlay.visible = False
            self.tool = tools.IntelligentScissors(self.map, self.edgeOverlay,
                                                  self)
            if self._faceMeans:
                tools.activeCostMeasure = \
                    statistics.HyperbolicInverse(self._faceMeans.faceMeanDiff)
        elif tool == 4:
            self.tool = tools.SeedSelector(map=self.map, parent=self)
        elif hasattr(tool, "disconnectViewer"):
            self.tool = tool
        elif tool != None:
            print "setTool: invalid argument, tool deactivated now."
            print "  give 1 for MapSearcher, 2 for ActivePaintbrush, 3 for IntelligentScissors, 4 for SeedSelector"
            tool = 0
        self._togglingGUI = True
        self.ui.scissorsAction.setChecked(tool == 3)
        self.ui.paintbrushAction.setChecked(tool == 2)
        self.ui.navigateAction.setChecked(tool == 1)
        self._togglingGUI = False

    def activateScissors(self, onoff=True):
        self.setTool(onoff and 3 or None)

    def activatePaintbrush(self, onoff=True):
        self.setTool(onoff and 2 or None)

    def activateNavigator(self, onoff=True):
        self.setTool(onoff and 1 or None)

    def cleanupMap(self):
        removeCruft(self.map, 7)

    def createDartNavigator(self, dart, costMeasure, parent):
        """Factory for DartNavigator, allows to use more specialized
        dart navigators in subclasses."""
        self.dn = DartNavigator(dart, costMeasure, self)

    def navigate(self, dart, center=True, costMeasure=None, new=False):
        if type(dart) == int:
            dart = self.map.dart(dart)
        elif hasattr(dart, "anchor"):
            dart = dart.anchor()
        elif hasattr(dart, "contours"):
            dart = list(dart.contours())
        if new or not self.dn:
            self.createDartNavigator(dart, costMeasure, self)
            self.connect(self.dn, QtCore.SIGNAL("destroyed(QObject*)"),
                         self._dartNavigatorDestroyed)
        else:
            if costMeasure:
                self.dn.costMeasure = costMeasure
            self.dn.setDart(dart)
        self.dn.show()
        if center:
            if isinstance(dart, (list, tuple)):
                dart = dart[0]
            self.viewer.center = dart[0]
            self.viewer.optimizeUpperLeft()

    def _enableImageActions(self):
        self.ui.displayBIAction.setEnabled("bi" in self.images)
        self.ui.displayOriginalAction.setEnabled("original" in self.images)
        self.ui.displayColoredAction.setEnabled("colored" in self.images)
        self.ui.displayLabelsAction.setEnabled(True)
        self.ui.displayMeansAction.setEnabled(bool(self._faceMeans))

    def _setImage(self, image, normalize):
        self.image = image
        if hasattr(image, 'qimage'):
            qImage = image.qimage(normalize)
        else:
            qImage = qimage2ndarray.array2qimage(image, normalize)
        self.viewer.setImage(qImage)

    def setImage(self, image, normalize=None, role=None):
        """Replace displayed background image.  You may pass role as
        one of ('original', 'colored', 'bi') to replace one of the
        predefined image slots (keyboard shortcuts 1-5)."""
        if role == None:
            if image.channels == 3:
                self.images["original"] = vigra.transformImage(
                    #                    image, "\l x: RGB2Lab(x)")[0]
                    image,
                    "\l x: norm(x)/%r" % math.sqrt(3))
                role = "colored"
            else:
                role = "original"
        self.images[role] = image
        self._enableImageActions()
        if normalize == None:
            normalize = self._normalizeStates[self._backgroundMode]
        if self.viewer and role == self.currentRole():
            self._setImage(image, normalize)

    def highlight(self, darts):
        """highlight(darts)
        Highlight the given darts (can be any iterable returning labels
        or Dart objects)."""
        self._dh.highlight(darts)

    def saveFig(self,
                basepath,
                roi=None,
                scale=None,
                bgFilename=None,
                faceMeans=False,
                similarity=None,
                skipBorder=False):
        """Saves an XFig file as <basepath>.fig (and the pixel background
        as <basepath>_bg.png if `bgFilename` is not given) and returns
        the FigExporter object.

        If `roi` is not None, it determines the ROI to be saved.
        `roi` can be a BoundingBox or Rect2D object, a string like
        "10,10-40,30" (see fig.parseGeometry) or a tuple usable as
        Rect2D constructor arguments.  You can also specify `roi` =
        True to export the visible image region.

        scale is the size of a pixel in fig units (450 = 1cm) and
        defaults to a size resulting in approx. 20cm width of the
        output file.

        If bgFilename is given, it is supposed to be a background
        filename for the picture box in the XFig file, or False if no
        background is desired."""
        def addMapOverlayWithoutBorder(*args, **kwargs):
            kwargs["skipBorder"] = True
            return addMapOverlay(*args, **kwargs)

        overlayHandler = \
            skipBorder and addMapOverlayWithoutBorder or addMapOverlay

        if bgFilename == None and faceMeans:
            bgFilename = False

        fe = figexport.exportImageWindow(self.viewer,
                                         basepath,
                                         roi=roi,
                                         scale=scale,
                                         bgFilename=bgFilename,
                                         overlayHandler=overlayHandler)

        if faceMeans in (None, True):
            faceMeans = self._faceMeans

        if faceMeans:
            fe.addMapFaces(self.map, faceMeans, similarity, depth=900)
            fe.f.save()

        return fe

    def saveEPS(self, basepath, *args, **kwargs):
        """display.saveEPS(basepath, roi = None, scale = None)

        Saves an XFig file as <basepath>.fig (see saveFig()
        documentation for details) and calls fig2dev to create an
        additional <basepath>.eps.

        Returns the final filename (result of calling fig.File.fig2dev)."""

        fe = self.saveFig(basepath, *args, **kwargs)
        return fe.f.fig2dev(lang="eps")

    def savePDF(self, basepath, *args, **kwargs):
        """display.savePDF(basepath, roi = None, scale = None)

        Saves an XFig file as <basepath>.fig (see saveFig()
        documentation for details) and calls fig2dev to create an
        additional <basepath>.pdf.

        Returns the final filename (result of calling fig.File.fig2dev)."""

        fe = self.saveFig(basepath, *args, **kwargs)
        return fe.f.fig2dev(lang="pdf")
Example #6
0
    def __init__(self, map, preparedImage = None, immediateShow = True,
                 faceMeans = None):
        self.__base.__init__(self)

        self.tool = None
        self._togglingGUI = False
        self._faceMeans = None # temp. needed (for _enableImageActions)

        self.ui = Ui_DisplaySettings()
        self.ui.setupUi(self)

        # for backward compatibility:
        if hasattr(preparedImage, "imageSize") and hasattr(map, "width"):
            map, preparedImage = preparedImage, map
        elif preparedImage is None:
            preparedImage = map.labelImage()
            if preparedImage is None:
                preparedImage = vigra.ScalarImage(map.imageSize())

        self.viewer = None # setImage would norm. pass the image on
        if hasattr(preparedImage, "orig"):
            self.images = {
                "original" : preparedImage.view,
                "colored" : preparedImage.orig,
                "bi" : preparedImage.bi.gm,
                }
            preparedImage = preparedImage.view
        else:
            self.images = {}
            # auto-detects role colored/original:
            self.setImage(preparedImage, normalize = False)

        self.image = preparedImage
        self.viewer = VigraQt.OverlayViewer(self)
        self.setCentralWidget(self.viewer)
        self._setImage(self.image, normalize = False)
        self.viewer.autoZoom()

        # convenience:
        self.addOverlay = self.viewer.addOverlay
        self.removeOverlay = self.viewer.removeOverlay
#        self.overlays = self.viewer.overlays

        self.map = map
        if not faceMeans and hasattr(map, "faceMeans"):
            faceMeans = map.faceMeans
        self.setFaceMeans(faceMeans)
        self._attachedHooks = None

        self._normalizeStates = [False, False, True, True, False]
        if self.image.channels == 3:
            self._backgroundMode = 1
            self.ui.displayColoredAction.setChecked(True)
        else:
            self._backgroundMode = 0
            self.ui.displayOriginalAction.setChecked(True)
        self._enableImageActions()

        self.connect(self.ui.backgroundGroup, QtCore.SIGNAL("selected(QAction*)"),
                     self.setBackgroundMode)
        self.connect(self.ui.nodeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNodeDisplay)
        self.connect(self.ui.edgeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleEdgeDisplay)
        self.connect(self.ui.normalizeAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNormalize)
        self.connect(self.ui.mapCleanupAction, QtCore.SIGNAL("activated()"),
                     self.cleanupMap)
        self.connect(self.ui.paintbrushAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activatePaintbrush)
        self.connect(self.ui.scissorsAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateScissors)
        self.connect(self.ui.navigateAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateNavigator)

        self.setWindowTitle("Map Display")

        self.edgeOverlay = MapEdges(self.viewer)
        self.edgeOverlay.setMap(map)
        self.edgeOverlay.setPen(QtCore.Qt.red)
#                                    protectedColor = QtCore.Qt.green,
#                                    protectedWidth = 2)
        self.viewer.addOverlay(self.edgeOverlay)
        self.edgeOverlay.visible = self.ui.edgeDisplayAction.isChecked()
        # self.nodeOverlay = MapNodes(map, QtCore.Qt.blue)
        # self.viewer.addOverlay(self.nodeOverlay)
        # self.nodeOverlay.visible = self.ui.nodeDisplayAction.isChecked()
        self._dh = DartHighlighter(map, self.viewer)
        self.dn = None

        if immediateShow:
            self.show()
Example #7
0
class MapDisplay(QtGui.QMainWindow):
    __base = QtGui.QMainWindow

    # actually, this has only documenting effect; since this inherits
    # PyQt widgets, any attribute may be used:
    __slots__ = ("tool", "viewer", "images", "image",
                 "map", "nodeOverlay", "edgeOverlay",
                 "addOverlay", "removeOverlay",
                 "_togglingGUI", "_backgroundMode", "_normalizeStates",
                 "_faceMeans", "_attachedHooks",
                 "dn", "_dh")

    def __init__(self, map, preparedImage = None, immediateShow = True,
                 faceMeans = None):
        self.__base.__init__(self)

        self.tool = None
        self._togglingGUI = False
        self._faceMeans = None # temp. needed (for _enableImageActions)

        self.ui = Ui_DisplaySettings()
        self.ui.setupUi(self)

        # for backward compatibility:
        if hasattr(preparedImage, "imageSize") and hasattr(map, "width"):
            map, preparedImage = preparedImage, map
        elif preparedImage is None:
            preparedImage = map.labelImage()
            if preparedImage is None:
                preparedImage = vigra.ScalarImage(map.imageSize())

        self.viewer = None # setImage would norm. pass the image on
        if hasattr(preparedImage, "orig"):
            self.images = {
                "original" : preparedImage.view,
                "colored" : preparedImage.orig,
                "bi" : preparedImage.bi.gm,
                }
            preparedImage = preparedImage.view
        else:
            self.images = {}
            # auto-detects role colored/original:
            self.setImage(preparedImage, normalize = False)

        self.image = preparedImage
        self.viewer = VigraQt.OverlayViewer(self)
        self.setCentralWidget(self.viewer)
        self._setImage(self.image, normalize = False)
        self.viewer.autoZoom()

        # convenience:
        self.addOverlay = self.viewer.addOverlay
        self.removeOverlay = self.viewer.removeOverlay
#        self.overlays = self.viewer.overlays

        self.map = map
        if not faceMeans and hasattr(map, "faceMeans"):
            faceMeans = map.faceMeans
        self.setFaceMeans(faceMeans)
        self._attachedHooks = None

        self._normalizeStates = [False, False, True, True, False]
        if self.image.channels == 3:
            self._backgroundMode = 1
            self.ui.displayColoredAction.setChecked(True)
        else:
            self._backgroundMode = 0
            self.ui.displayOriginalAction.setChecked(True)
        self._enableImageActions()

        self.connect(self.ui.backgroundGroup, QtCore.SIGNAL("selected(QAction*)"),
                     self.setBackgroundMode)
        self.connect(self.ui.nodeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNodeDisplay)
        self.connect(self.ui.edgeDisplayAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleEdgeDisplay)
        self.connect(self.ui.normalizeAction, QtCore.SIGNAL("toggled(bool)"),
                     self.toggleNormalize)
        self.connect(self.ui.mapCleanupAction, QtCore.SIGNAL("activated()"),
                     self.cleanupMap)
        self.connect(self.ui.paintbrushAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activatePaintbrush)
        self.connect(self.ui.scissorsAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateScissors)
        self.connect(self.ui.navigateAction, QtCore.SIGNAL("toggled(bool)"),
                     self.activateNavigator)

        self.setWindowTitle("Map Display")

        self.edgeOverlay = MapEdges(self.viewer)
        self.edgeOverlay.setMap(map)
        self.edgeOverlay.setPen(QtCore.Qt.red)
#                                    protectedColor = QtCore.Qt.green,
#                                    protectedWidth = 2)
        self.viewer.addOverlay(self.edgeOverlay)
        self.edgeOverlay.visible = self.ui.edgeDisplayAction.isChecked()
        # self.nodeOverlay = MapNodes(map, QtCore.Qt.blue)
        # self.viewer.addOverlay(self.nodeOverlay)
        # self.nodeOverlay.visible = self.ui.nodeDisplayAction.isChecked()
        self._dh = DartHighlighter(map, self.viewer)
        self.dn = None

        if immediateShow:
            self.show()

    def __del__(self):
        # delete tool (which may reference the viewer & map)
        self.setTool(None)

    def _dartNavigatorDestroyed(self, dn):
        """HACK: this is needed because of the deleteLater()..."""
        # FIXME: cannot reliably detect identity of half-destructed
        # object anymore:
        #if dn is self.dn:
        self.dn = None

    def _labelImage(self):
        result = self.map.labelImage()
        if result is None:
            result = maputils.drawLabelImage(self.map)
        return result

    def setMap(self, map):
        attached = self.detachHooks()

        self.setTool(None)
        self.map = map
        self.edgeOverlay.setMap(map)
        #self.nodeOverlay.setMap(map)
        self._dh.setMap(map)

        updatedDisplayImage = None
        if self._backgroundMode == 3:
            updatedDisplayImage = self._labelImage()

        self._faceMeans = None
        if hasattr(map, "faceMeans"):
            self.setFaceMeans(map.faceMeans)
            if self._backgroundMode == 4:
                updatedDisplayImage = \
                    self._faceMeans.regionImage(self._labelImage())
        self._enableImageActions()

        if updatedDisplayImage:
            self._setImage(updatedDisplayImage,
                           self._normalizeStates[self._backgroundMode])

        if attached:
            self.attachHooks()

        self.viewer.update()

    def setFaceMeans(self, faceMeans):
        self._faceMeans = faceMeans
        self._enableImageActions()

    def _adjustSize(self):
        pass # don't change window size out of a sudden

    def statusMessage(self, msg):
        # workaround - don't know why connecting the PYSIGNAL directly
        # does not work (maybe QtCore.SIGNAL("captionChanged(QString)")
        # would work?)
        self.statusBar().showMessage(msg)

    def currentRole(self):
        return ("original", "colored", "bi", "labels", "faceMeans")[
            self._backgroundMode]

    def setBackgroundMode(self, mode):
        if type(mode) != int:
            mode = [self.ui.displayOriginalAction,
                    self.ui.displayColoredAction,
                    self.ui.displayBIAction,
                    self.ui.displayLabelsAction,
                    self.ui.displayMeansAction].index(mode)

        displayImage = None
        if mode == 0:
            displayImage = self.images["original"]
        elif mode == 1:
            displayImage = self.images["colored"]
        elif mode == 2:
            displayImage = self.images["bi"]
        elif mode == 3:
            displayImage = self._labelImage()
        elif mode == 4:
            displayImage = self._faceMeans.regionImage(self._labelImage())
        else:
            sys.stderr.write("Unknown background mode %d!\n" % mode)
            return

        self.image = displayImage
        self._backgroundMode = mode
        normalize = self._normalizeStates[mode]
        if self.ui.normalizeAction.isChecked() != normalize:
            self.ui.normalizeAction.setChecked(normalize)
        else:
            self._setImage(self.image, normalize)

    def toggleNodeDisplay(self, onoff):
        return # TEMP
        if self.nodeOverlay.visible != onoff:
            self.nodeOverlay.visible = onoff
            self.viewer.update()

    def toggleEdgeDisplay(self, onoff):
        if self.edgeOverlay.visible != onoff:
            self.edgeOverlay.visible = onoff
            self.viewer.update()

    def toggleNormalize(self, normalize):
        self._normalizeStates[self._backgroundMode] = normalize
        self._setImage(self.image, normalize)

    def attachHooks(self):
        return
        self.nodeOverlay.attachHooks()
        self.edgeOverlay.attachHooks()
        self._attachedHooks = (
            self.map.addMergeFacesCallbacks(None, self._postMergeFacesHook),
            self.map.addRemoveBridgeCallbacks(self._preRemoveBridgeHook,
                                              self._postRemoveBridgeHook))

    def detachHooks(self):
        """Detaches / removes callbacks from the map's hooks.
        Returns True if successful, False if already detached."""
        return
        results = (self.nodeOverlay.detachHooks(),
                   self.edgeOverlay.detachHooks())

        if self._attachedHooks:
            for h in self._attachedHooks:
                h.disconnect()
            self._attachedHooks = None

            if results == (True, True):
                return True
        else:
            if results == (False, False):
                return False

    def _redisplayROIImage(self, roi):
        roi &= Rect2D(self.map.imageSize())
        roiImage = self._labelImage().subImage(roi)
        if self._backgroundMode > 3:
            roiImage = self._faceMeans.regionImage(roiImage)
        # FIXME: use global normalization here
        self.viewer.replaceROI(roiImage.toPNM(vigra.BYTE),
                               QtCore.QPoint(*roi.upperLeft()))

    def _postMergeFacesHook(self, survivor):
        if self._backgroundMode < 3:
            return
        if survivor.label():
            self._redisplayROIImage(intPos(survivor.boundingBox()))

    def _preRemoveBridgeHook(self, dart):
        if self._backgroundMode >= 3:
            self._bridgeROI = intPos(dart.edge().boundingBox())
        return True

    def _postRemoveBridgeHook(self, dart):
        if self._backgroundMode < 3:
            return
        self._redisplayROIImage(self._bridgeROI)

    def showEvent(self, e):
        self.attachHooks()
        return self.__base.showEvent(self, e)

    def hideEvent(self, e):
        self.detachHooks()
        return self.__base.hideEvent(self, e)

    def showMarkedEdges(self, colorMarked = QtCore.Qt.green, colorUnmarked = None,
                        markFlags = flag_constants.ALL_PROTECTION):
        edgeColors = [None] * self.map.maxEdgeLabel()
        for edge in self.map.edgeIter():
            if edge.flag(markFlags):
                edgeColors[edge.label()] = colorMarked
            else:
                edgeColors[edge.label()] = colorUnmarked
        self.edgeOverlay.colors = edgeColors
        self.viewer.update()

    def showAllEdges(self):
        self.edgeOverlay.colors = None
        self.viewer.update()

    def setTool(self, tool = None):
        """Deactivates and destroys old tool, activates/sets new one
        if tool != None.  `tool` can be either a tool object or

        1 for the MapSearcher tool
        2 for the ActivatePaintbrush
        3 for the IntelligentScissors
        4 for the SeedSelector"""

        if self._togglingGUI:
            return # no recursion please
        if self.tool:
            self.tool.disconnectViewer()
            if self.tool.parent() == self:
                self.tool.deleteLater()
            self.tool = None

        if tool == 1:
            self.tool = tools.MapSearcher(self.map, self)
        elif tool == 2:
            self.tool = tools.ActivePaintbrush(self.map, self)
        elif tool == 3:
            if self.edgeOverlay.color == QtCore.Qt.red:
                self.edgeOverlay.color = QtCore.Qt.black
            self.nodeOverlay.visible = False
            self.tool = tools.IntelligentScissors(
                self.map, self.edgeOverlay, self)
            if self._faceMeans:
                tools.activeCostMeasure = \
                    statistics.HyperbolicInverse(self._faceMeans.faceMeanDiff)
        elif tool == 4:
            self.tool = tools.SeedSelector(map = self.map, parent = self)
        elif hasattr(tool, "disconnectViewer"):
            self.tool = tool
        elif tool != None:
            print "setTool: invalid argument, tool deactivated now."
            print "  give 1 for MapSearcher, 2 for ActivePaintbrush, 3 for IntelligentScissors, 4 for SeedSelector"
            tool = 0
        self._togglingGUI = True
        self.ui.scissorsAction.setChecked(tool == 3)
        self.ui.paintbrushAction.setChecked(tool == 2)
        self.ui.navigateAction.setChecked(tool == 1)
        self._togglingGUI = False

    def activateScissors(self, onoff = True):
        self.setTool(onoff and 3 or None)

    def activatePaintbrush(self, onoff = True):
        self.setTool(onoff and 2 or None)

    def activateNavigator(self, onoff = True):
        self.setTool(onoff and 1 or None)

    def cleanupMap(self):
        removeCruft(self.map, 7)

    def createDartNavigator(self, dart, costMeasure, parent):
        """Factory for DartNavigator, allows to use more specialized
        dart navigators in subclasses."""
        self.dn = DartNavigator(dart, costMeasure, self)

    def navigate(self, dart, center = True, costMeasure = None, new = False):
        if type(dart) == int:
            dart = self.map.dart(dart)
        elif hasattr(dart, "anchor"):
            dart = dart.anchor()
        elif hasattr(dart, "contours"):
            dart = list(dart.contours())
        if new or not self.dn:
            self.createDartNavigator(dart, costMeasure, self)
            self.connect(self.dn, QtCore.SIGNAL("destroyed(QObject*)"),
                         self._dartNavigatorDestroyed)
        else:
            if costMeasure:
                self.dn.costMeasure = costMeasure
            self.dn.setDart(dart)
        self.dn.show()
        if center:
            if isinstance(dart, (list, tuple)):
                dart = dart[0]
            self.viewer.center = dart[0]
            self.viewer.optimizeUpperLeft()

    def _enableImageActions(self):
        self.ui.displayBIAction.setEnabled("bi" in self.images)
        self.ui.displayOriginalAction.setEnabled("original" in self.images)
        self.ui.displayColoredAction.setEnabled("colored" in self.images)
        self.ui.displayLabelsAction.setEnabled(True)
        self.ui.displayMeansAction.setEnabled(bool(self._faceMeans))

    def _setImage(self, image, normalize):
        self.image = image
        if hasattr(image, 'qimage'):
            qImage = image.qimage(normalize)
        else:
            qImage = qimage2ndarray.array2qimage(image, normalize)
        self.viewer.setImage(qImage)

    def setImage(self, image, normalize = None, role = None):
        """Replace displayed background image.  You may pass role as
        one of ('original', 'colored', 'bi') to replace one of the
        predefined image slots (keyboard shortcuts 1-5)."""
        if role == None:
            if image.channels == 3:
                self.images["original"] = vigra.transformImage(
#                    image, "\l x: RGB2Lab(x)")[0]
                    image, "\l x: norm(x)/%r" % math.sqrt(3))
                role = "colored"
            else:
                role = "original"
        self.images[role] = image
        self._enableImageActions()
        if normalize == None:
            normalize = self._normalizeStates[self._backgroundMode]
        if self.viewer and role == self.currentRole():
            self._setImage(image, normalize)

    def highlight(self, darts):
        """highlight(darts)
        Highlight the given darts (can be any iterable returning labels
        or Dart objects)."""
        self._dh.highlight(darts)

    def saveFig(self, basepath, roi = None, scale = None,
                bgFilename = None, faceMeans = False, similarity = None,
                skipBorder = False):
        """Saves an XFig file as <basepath>.fig (and the pixel background
        as <basepath>_bg.png if `bgFilename` is not given) and returns
        the FigExporter object.

        If `roi` is not None, it determines the ROI to be saved.
        `roi` can be a BoundingBox or Rect2D object, a string like
        "10,10-40,30" (see fig.parseGeometry) or a tuple usable as
        Rect2D constructor arguments.  You can also specify `roi` =
        True to export the visible image region.

        scale is the size of a pixel in fig units (450 = 1cm) and
        defaults to a size resulting in approx. 20cm width of the
        output file.

        If bgFilename is given, it is supposed to be a background
        filename for the picture box in the XFig file, or False if no
        background is desired."""

        def addMapOverlayWithoutBorder(*args, **kwargs):
            kwargs["skipBorder"] = True
            return addMapOverlay(*args, **kwargs)

        overlayHandler = \
            skipBorder and addMapOverlayWithoutBorder or addMapOverlay

        if bgFilename == None and faceMeans:
            bgFilename = False

        fe = figexport.exportImageWindow(
            self.viewer, basepath, roi = roi, scale = scale,
            bgFilename = bgFilename,
            overlayHandler = overlayHandler)

        if faceMeans in (None, True):
            faceMeans = self._faceMeans

        if faceMeans:
            fe.addMapFaces(
                self.map, faceMeans, similarity, depth = 900)
            fe.f.save()

        return fe

    def saveEPS(self, basepath, *args, **kwargs):
        """display.saveEPS(basepath, roi = None, scale = None)

        Saves an XFig file as <basepath>.fig (see saveFig()
        documentation for details) and calls fig2dev to create an
        additional <basepath>.eps.

        Returns the final filename (result of calling fig.File.fig2dev)."""

        fe = self.saveFig(basepath, *args, **kwargs)
        return fe.f.fig2dev(lang = "eps")

    def savePDF(self, basepath, *args, **kwargs):
        """display.savePDF(basepath, roi = None, scale = None)

        Saves an XFig file as <basepath>.fig (see saveFig()
        documentation for details) and calls fig2dev to create an
        additional <basepath>.pdf.

        Returns the final filename (result of calling fig.File.fig2dev)."""

        fe = self.saveFig(basepath, *args, **kwargs)
        return fe.f.fig2dev(lang = "pdf")
Example #8
0
class DartNavigator(QtGui.QDialog):
    __base = QtGui.QDialog

    def __init__(self, dart, costMeasure, parent, name=None):
        self.__base.__init__(self, parent)
        if name:
            self.setObjectName(name)

        self.dart = dart
        self.costMeasure = costMeasure

        self.ui = Ui_DartNavigator()
        self.ui.setupUi(self)
        self.connect(self.ui.nextPhiButton, QtCore.SIGNAL("clicked()"),
                     self.nextPhi)
        self.connect(self.ui.prevPhiButton, QtCore.SIGNAL("clicked()"),
                     self.prevPhi)
        self.connect(self.ui.nextAlphaButton, QtCore.SIGNAL("clicked()"),
                     self.nextAlpha)
        self.connect(self.ui.nextSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.nextSigma)
        self.connect(self.ui.prevSigmaButton, QtCore.SIGNAL("clicked()"),
                     self.prevSigma)

        self.connect(self.ui.continuousCheckBox,
                     QtCore.SIGNAL("toggled(bool)"), self.toggleContinuous)

        self.timer = QtCore.QTimer(self)
        self.connect(self.timer, QtCore.SIGNAL("timeout()"),
                     self.highlightNext)

        self._darthighlighter = DartHighlighter(parent.map, parent.viewer)
        self.updateLabel()

    def closeEvent(self, e):
        self._darthighlighter.highlight(None)
        self.__base.closeEvent(self, e)
        if e.isAccepted():
            self.deleteLater()  # like QtCore.Qt.WDestructiveClose ;-)

    def highlightNext(self):
        self.activePerm()
        self.updateLabel()

    def setDart(self, dart):
        self.dart = dart
        self.updateLabel()

    def toggleContinuous(self, onoff):
        if onoff:
            self.timer.start(1200)
        else:
            self.timer.stop()
        self.ui.nextPhiButton.setToggleButton(onoff)
        self.ui.prevPhiButton.setToggleButton(onoff)
        self.ui.nextAlphaButton.setToggleButton(onoff)
        self.ui.nextSigmaButton.setToggleButton(onoff)
        self.ui.prevSigmaButton.setToggleButton(onoff)

    def moveDart(self, perm):
        perm()
        self.updateLabel()
        self.activePerm = perm

    def nextPhi(self):
        self.moveDart(self.dart.nextPhi)

    def prevPhi(self):
        self.moveDart(self.dart.prevPhi)

    def nextAlpha(self):
        self.moveDart(self.dart.nextAlpha)

    def nextSigma(self):
        self.moveDart(self.dart.nextSigma)

    def prevSigma(self):
        self.moveDart(self.dart.prevSigma)

    def updateLabel(self):
        self._darthighlighter.highlight(self.dart.label())
        dartDesc = "Dart %d, length %.1f, partial area %.1f, %d points" % (
            self.dart.label(), self.dart.edge().length(),
            self.dart.partialArea(), len(self.dart))
        if self.costMeasure:
            dartDesc += "\nassociated cost: %s" % self.costMeasure(self.dart)
        self.ui.dartLabel.setText(dartDesc)
        for node, nodeLabel in ((self.dart.startNode(),
                                 self.ui.startNodeLabel),
                                (self.dart.endNode(), self.ui.endNodeLabel)):
            nodeLabel.setText("Node %d (deg. %d)\nat %s" %
                              (node.label(), node.degree(), node.position()))
        if self.dart.map().mapInitialized():
            leftFace = self.dart.leftFace()
            rightFace = self.dart.rightFace()
            self.ui.faceLabel.setText(
                """Left: %s\nRight: %s""" %
                (str(leftFace)[8:-1], str(rightFace)[8:-1]))
        self.setWindowTitle("DartNavigator(%d)" % (self.dart.label(), ))
        self.emit(QtCore.SIGNAL('updateDart'), self.dart)