示例#1
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        ## Whether or not to draw the mosaic tiles
        self.shouldDrawMosaic = True
        ## True if we're in the processing of changing the soft motion limits.
        self.amSettingSafeties = False
        ## Position the mouse first clicked when setting safeties, or None if
        # we aren't setting safeties.
        self.firstSafetyMousePos = None
        ## Last seen mouse position
        self.lastMousePos = [0, 0]

        primitive_specs = wx.GetApp().Config['stage'].getlines('primitives', [])
        self._primitives = [Primitive.factory(spec) for spec in primitive_specs]

        hardLimits = cockpit.interfaces.stageMover.getHardLimits()
        self.minX, self.maxX = hardLimits[0]
        self.minY, self.maxY = hardLimits[1]
        ## X extent of the stage, in microns.
        stageWidth = self.maxX - self.minX
        ## Y extent of the stage, in microns.
        stageHeight = self.maxY - self.minY
        ## Max of X or Y stage extents.
        self.maxExtent = max(stageWidth, stageHeight)
        ## X and Y view extent.
        if stageHeight > stageWidth:
            self.viewExtent = 1.2 * stageHeight
            self.viewDeltaY = stageHeight * 0.1
        else:
            self.viewExtent = 1.05 * stageWidth
            self.viewDeltaY = stageHeight * 0.05
        # Push out the min and max values a bit to give us some room around
        # the stage to work with. In particular we need space below the display
        # to show our legend.
        self.centreX = ((self.maxX - self.minX) / 2) + self.minX
        self.centreY = ((self.maxY - self.minY) / 2) + self.minY
        self.minX = self.centreX - self.viewExtent / 2
        self.maxX = self.centreX + self.viewExtent / 2
        self.minY = self.centreY - self.viewExtent / 2 - self.viewDeltaY
        self.maxY = self.centreY + self.viewExtent / 2 - self.viewDeltaY

        ## Size of text to draw. I confess I don't really understand how this
        # corresponds to anything, but it seems to work out.
        self.textSize = .004

        self.Bind(wx.EVT_MOTION, self.OnMouseMotion)
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftClick)
        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDoubleClick)
        self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick)
        self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDoubleClick)
        # Bind context menu event to None to prevent main window context menu
        # being displayed in preference to our own.
        self.Bind(wx.EVT_CONTEXT_MENU, lambda event: None)
        events.subscribe("soft safety limit", self.onSafetyChange)
        events.subscribe('objective change', self.onObjectiveChange)
        self.SetToolTip(wx.ToolTip("Left double-click to move the stage. " +
                "Right click for gotoXYZ and double-click to toggle displaying of mosaic " +
                "tiles."))
示例#2
0
    def onPaint(self, event=None):
        if not self.shouldDraw:
            return
        try:
            if not self.haveInitedGL:
                self.initGL()
                self.haveInitedGL = True

            dc = wx.PaintDC(self)
            self.SetCurrent(self.context)
            width, height = self.GetClientSize()

            glViewport(0, 0, width, height)

            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

            squareOffsets = [(0, 0), (0, 1), (1, 1), (1, 0)]
            stepSizes = cockpit.interfaces.stageMover.getCurStepSizes()[:2]

            # Draw hard stage motion limits
            hardLimits = cockpit.interfaces.stageMover.getHardLimits()[:2]
            # Rearrange limits to (x, y) tuples.
            hardLimits = list(zip(hardLimits[0], hardLimits[1]))
            stageHeight = abs(hardLimits[1][0] - hardLimits[1][1])

            # Set up transform from stage to screen units
            glMatrixMode(GL_MODELVIEW)
            glLoadMatrixf(self.modelView())

            #Loop over objective offsets to draw limist in multiple colours.
            for obj in self.listObj:
                offset = self.objective.nameToOffset.get(obj)
                colour = self.objective.nameToColour.get(obj)
                glLineWidth(4)
                if obj is not self.objective.curObjective:
                    colour = (min(1, colour[0] + 0.7), min(1, colour[1] + 0.7),
                              min(1, colour[2] + 0.7))
                    glLineWidth(2)
                glEnable(GL_LINE_STIPPLE)
                glLineStipple(3, 0xAAAA)
                glColor3f(*colour)
                glBegin(GL_LINE_LOOP)
                for (xIndex, yIndex) in squareOffsets:
                    glVertex2f(hardLimits[xIndex][0] - offset[0],
                               hardLimits[yIndex][1] + offset[1])
                glEnd()
                glDisable(GL_LINE_STIPPLE)

                # Draw soft stage motion limits -- a dotted box, solid black
                # corners, and coordinates. If we're currently setting safeties,
                # then the second corner is the current mouse position.
                safeties = cockpit.interfaces.stageMover.getSoftLimits()[:2]
                x1, x2 = safeties[0]
                y1, y2 = safeties[1]
                if self.firstSafetyMousePos is not None:
                    x1, y1 = self.firstSafetyMousePos
                    x2, y2 = self.lastMousePos
                    if x1 > x2:
                        x1, x2 = x2, x1
                    if y1 > y2:
                        y1, y2 = y2, y1
                softLimits = [(x1, y1), (x2, y2)]

                # First the dotted green box.
                glEnable(GL_LINE_STIPPLE)
                glLineWidth(2)
                glLineStipple(3, 0x5555)
                glColor3f(0, 1, 0)
                glBegin(GL_LINE_LOOP)
                for (x, y) in [(x1, y1), (x1, y2), (x2, y2), (x2, y1)]:
                    glVertex2f(x - offset[0], y + offset[1])
                glEnd()
                glDisable(GL_LINE_STIPPLE)

                # Now the corners.
                glColor3f(0, 0, 0)
                glBegin(GL_LINES)
                for (vx, vy), (dx, dy) in [
                    (softLimits[0], (self.maxExtent * .1, 0)),
                    (softLimits[0], (0, self.maxExtent * .1)),
                    (softLimits[1], (-self.maxExtent * .1, 0)),
                    (softLimits[1], (0, -self.maxExtent * .1))
                ]:
                    secondVertex = [vx + dx, vy + dy]
                    glVertex2f(vx - offset[0], vy + offset[1])
                    glVertex2f(secondVertex[0] - offset[0],
                               secondVertex[1] + offset[1])
                glEnd()
                glLineWidth(1)
            # Now the coordinates. Only draw them if the soft limits aren't
            # the hard limits, to avoid clutter.
            if safeties != hardLimits:
                for i, (dx, dy) in enumerate([(4000, -700), (2000, 400)]):
                    x = softLimits[i][0]
                    y = softLimits[i][1]
                    self.drawTextAt((x + dx, y + dy),
                                    "(%d, %d)" % (x, y),
                                    size=self.textSize * .75)

            glDisable(GL_LINE_STIPPLE)

            # Draw device-specific primitives.
            # This uses vertex buffers with vertices in stage co-ordinates,
            # so need to update the modelview matrix to render them in the
            # right place.
            glEnable(GL_LINE_STIPPLE)
            glLineStipple(1, 0xAAAA)
            glColor3f(0.4, 0.4, 0.4)
            primitives = cockpit.interfaces.stageMover.getPrimitives()
            for p in primitives:
                if p not in self.primitives:
                    self.primitives[p] = Primitive.factory(p)
                self.primitives[p].render()
            glDisable(GL_LINE_STIPPLE)

            #Draw possibloe stage positions for current objective
            obj = self.objective.curObjective
            offset = self.objective.nameToOffset.get(obj)
            colour = self.objective.nameToColour.get(obj)
            glLineWidth(2)
            # Draw stage position
            motorPos = self.curStagePosition[:2]
            squareSize = self.maxExtent * .025
            glColor3f(*colour)
            glBegin(GL_LINE_LOOP)
            for (x, y) in squareOffsets:
                glVertex2f(
                    motorPos[0] - offset[0] + squareSize * x - squareSize / 2,
                    motorPos[1] + offset[1] + squareSize * y - squareSize / 2)
            glEnd()

            # Draw motion crosshairs
            glColor3f(1, 0, 0)
            glBegin(GL_LINES)
            for i, stepSize in enumerate(stepSizes):
                if stepSize is None:
                    # No step control along this axis.
                    continue
                offset = [0, 0]
                offset[i] = stepSize
                glVertex2f(motorPos[0] - offset[0], motorPos[1] - offset[1])
                glVertex2f(motorPos[0] + offset[0], motorPos[1] + offset[1])
            glEnd()

            # Draw direction of motion
            delta = motorPos - self.prevStagePosition[:2]

            if sum(numpy.fabs(delta)) > macroStageBase.MIN_DELTA_TO_DISPLAY:
                self.drawArrow((motorPos[0] - self.offset[0],
                                motorPos[1] + self.offset[1]),
                               delta, (0, 0, 1),
                               arrowSize=self.maxExtent * .1,
                               arrowHeadSize=self.maxExtent * .025)
                glLineWidth(1)

            # The crosshairs don't always draw large enough to show,
            # so ensure that at least one pixel in the middle
            # gets drawn.
            glBegin(GL_POINTS)
            glVertex2f(motorPos[0] - self.offset[0],
                       motorPos[1] + self.offset[1])
            glEnd()

            # Draw scale bar
            glColor3f(0, 0, 0)
            glLineWidth(1)
            glBegin(GL_LINES)
            yOffset = self.minY + 0.9 * (self.viewDeltaY + 0.5 *
                                         (self.viewExtent - stageHeight))
            glVertex2f(hardLimits[0][0], yOffset)
            glVertex2f(hardLimits[0][1], yOffset)
            # Draw notches in the scale bar every 1mm.
            for scaleX in range(int(hardLimits[0][0]),
                                int(hardLimits[0][1]) + 1000, 1000):
                width = self.viewExtent * .015
                if scaleX % 5000 == 0:
                    width = self.viewExtent * .025
                y1 = yOffset - width / 2
                y2 = yOffset + width / 2
                glVertex2f(scaleX, y1)
                glVertex2f(scaleX, y2)
            glEnd()
            glLineWidth(1)

            # Draw stage coordinates. Use a different color for the mover
            # currently under keypad control.
            coordsLoc = (self.maxX - self.viewExtent * .05,
                         self.minY + self.viewExtent * .1)
            allPositions = cockpit.interfaces.stageMover.getAllPositions()
            curControl = cockpit.interfaces.stageMover.getCurHandlerIndex()
            for axis in [0, 1]:
                step = stepSizes[axis]
                if stepSizes[axis] is None:
                    step = 0
                positions = [p[axis] for p in allPositions]
                self.drawStagePosition(
                    ['X:', 'Y:'][axis], positions, curControl, step,
                    (coordsLoc[0], coordsLoc[1] - axis * self.textLineHeight),
                    self.viewExtent * .25, self.viewExtent * .05,
                    self.textSize)

            events.publish('macro stage xy draw', self)

            glFlush()
            self.SwapBuffers()
            # Set the event, so our refreshWaiter() can update
            # our stage position info.
            self.drawEvent.set()
        except Exception as e:
            cockpit.util.logger.log.error(
                "Exception drawing XY macro stage: %s", e)
            cockpit.util.logger.log.error(traceback.format_exc())
            self.shouldDraw = False