Ejemplo n.º 1
0
class Viewer(QGraphicsView):
    def __init__(self, gridsize_label, position_label, help_label):
        QGraphicsView.__init__(self)

        self.gridsize_label = gridsize_label
        self.position_label = position_label
        self.help_label = help_label

        # Create a QGraphicsScene which this view looks at
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(QRectF())
        self.setScene(self.scene)

        # Customize QGraphicsView
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setInteractive(False)
        self.scale(1, -1)  # Flips around the Y axis
        # Use OpenGL http://ralsina.me/stories/BBS53.html
        #        self.setViewport(QtOpenGL.QGLWidget())
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.pen = QPen(QtCore.Qt.black, 0)
        self.portpen = QPen(PORT_COLOR, 3)
        self.portpen.setCosmetic(True)  # Makes constant width
        self.portfont = QtGui.QFont('Arial', pointSize=14)
        self.portfontcolor = PORT_COLOR
        self.subportpen = QPen(SUBPORT_COLOR, 3)
        self.subportpen.setCosmetic(True)  # Makes constant width
        self.subportfont = QtGui.QFont('Arial', pointSize=14)
        self.subportfontcolor = SUBPORT_COLOR

        # Tracking ports

        # Various status variables
        self._mousePressed = None
        self._rb_origin = QPoint()
        self.zoom_factor_total = 1

        # Grid variables
        self.gridpen = QPen(QtCore.Qt.black, 0)
        self.gridpen.setStyle(QtCore.Qt.DotLine)
        self.gridpen.setDashPattern([1, 4])
        self.gridpen.setColor(QtGui.QColor(0, 0, 0, 125))
        #        self.gridpen = QPen(QtCore.Qt.black, 1)
        #        self.gridpen.setCosmetic(True) # Makes constant width
        self.scene_polys = []

        self.initialize()

    def add_polygons(self, polygons, color='#A8F22A', alpha=1):
        qcolor = QColor()
        qcolor.setNamedColor(color)
        qcolor.setAlphaF(alpha)
        for points in polygons:
            qpoly = QPolygonF([QPointF(p[0], p[1]) for p in points])
            scene_poly = self.scene.addPolygon(qpoly)
            scene_poly.setBrush(qcolor)
            scene_poly.setPen(self.pen)
            self.scene_polys.append(scene_poly)
            # Update custom bounding box
            sr = scene_poly.sceneBoundingRect()
            if len(self.scene_polys) == 1:
                self.scene_xmin = sr.left()
                self.scene_xmax = sr.right()
                self.scene_ymin = sr.top()
                self.scene_ymax = sr.bottom()
            else:
                self.scene_xmin = min(self.scene_xmin, sr.left())
                self.scene_xmax = max(self.scene_xmax, sr.right())
                self.scene_ymin = min(self.scene_ymin, sr.top())
                self.scene_ymax = max(self.scene_ymax, sr.bottom())

    def reset_view(self):
        # The SceneRect controls how far you can pan, make it larger than
        # just the bounding box so middle-click panning works
        panning_rect = QRectF(self.scene_bounding_rect)
        panning_rect_center = panning_rect.center()
        panning_rect_size = max(panning_rect.width(),
                                panning_rect.height()) * 3
        panning_rect.setSize(QSizeF(panning_rect_size, panning_rect_size))
        panning_rect.moveCenter(panning_rect_center)
        self.setSceneRect(panning_rect)
        self.fitInView(self.scene_bounding_rect, Qt.KeepAspectRatio)
        self.zoom_view(0.8)

        self.update_grid()

    def add_port(self, port, is_subport=False):
        if (port.width is None) or (port.width == 0):
            x, y = port.midpoint
            cs = 1  # cross size
            pn = QPointF(x, y + cs)
            ps = QPointF(x, y - cs)
            pe = QPointF(x + cs, y)
            pw = QPointF(x - cs, y)
            qline1 = self.scene.addLine(QLineF(pn, ps))
            qline2 = self.scene.addLine(QLineF(pw, pe))
            port_shapes = [qline1, qline2]
        else:
            point1, point2 = port.endpoints
            point1 = QPointF(point1[0], point1[1])
            point2 = QPointF(point2[0], point2[1])
            qline = self.scene.addLine(QLineF(point1, point2))
            arrow_points = np.array([[0, 0], [10, 0], [6, 4], [6, 2], [0, 2]
                                     ]) / (40) * port.width
            arrow_qpoly = QPolygonF(
                [QPointF(p[0], p[1]) for p in arrow_points])
            port_scene_poly = self.scene.addPolygon(arrow_qpoly)
            port_scene_poly.setRotation(port.orientation)
            port_scene_poly.moveBy(port.midpoint[0], port.midpoint[1])
            port_shapes = [qline, port_scene_poly]
        qtext = self.scene.addText(str(port.name), self.portfont)
        port_items = port_shapes + [qtext]
        rad = port.orientation * np.pi / 180
        x, y = port.endpoints[0] * 1 / 4 + port.endpoints[
            1] * 3 / 4 + np.array([np.cos(rad), np.sin(rad)]) * port.width / 8
        #        x,y = port.midpoint[0], port.midpoint[1]
        #        x,y  = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2
        qtext.setPos(QPointF(x, y))
        qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)

        if not is_subport:
            [shape.setPen(self.portpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.portfontcolor)
            self.portitems += port_items
        else:
            [shape.setPen(self.subportpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.subportfontcolor)
            self.subportitems += port_items
#        self.portlabels.append(qtext)

    def add_aliases(self, aliases):
        for name, ref in aliases.items():
            qtext = self.scene.addText(str(name), self.portfont)
            x, y = ref.center
            qtext.setPos(QPointF(x, y))
            qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)
            self.aliasitems += [qtext]

    def set_port_visibility(self, visible=True):
        for item in self.portitems:
            item.setVisible(visible)
        self.ports_visible = visible

    def set_subport_visibility(self, visible=True):
        for item in self.subportitems:
            item.setVisible(visible)
        self.subports_visible = visible

    def set_alias_visibility(self, visible=True):
        for item in self.aliasitems:
            item.setVisible(visible)
        self.aliases_visible = visible

    def initialize(self):
        self.scene.clear()
        self.polygons = {}
        self.portitems = []
        self.subportitems = []
        self.aliasitems = []
        self.aliases_visible = True
        self.ports_visible = True
        self.subports_visible = True
        self.mouse_position = [0, 0]
        self.grid_size_snapped = 0
        self.setMouseTracking(True)
        self.scene_bounding_rect = None
        self.scene_polys = []
        self.scene_xmin = 0
        self.scene_xmax = 1
        self.scene_ymin = 0
        self.scene_ymax = 1

    def finalize(self):
        self.scene_bounding_rect = QRectF(
            QPointF(self.scene_xmin, self.scene_ymin),
            QPointF(self.scene_xmax, self.scene_ymax))
        # self.scene_center = [self.scene_bounding_rect.center().x(), self.scene_bounding_rect.center().y()]
        self.scene_size = [
            self.scene_bounding_rect.width(),
            self.scene_bounding_rect.height()
        ]
        self.create_grid()
        self.update_grid()

#==============================================================================
#   Grid creation
#==============================================================================

    def update_grid(self):
        grid_pixels = 50
        grid_snaps = [1, 2, 4]

        # Number of pixels in the viewer
        view_width, view_height = self.rect().width(), self.rect().height()
        # Rectangle of viewport in terms of scene coordinates
        r = self.mapToScene(self.rect()).boundingRect()
        width, height = r.width(), r.height()
        xmin, ymin, xmax, ymax = r.x(), r.y(), r.x() + width, r.y() + height

        grid_size = grid_pixels * (width / view_width)
        exponent = np.floor(np.log10(grid_size))
        digits = round(grid_size / 10**(exponent), 2)
        digits_snapped = min(grid_snaps, key=lambda x: abs(x - digits))
        grid_size_snapped = digits_snapped * 10**(exponent)

        # Starting coordinates for gridlines
        x = round((xmin - 2 * width) / grid_size_snapped) * grid_size_snapped
        y = round((ymin - 2 * height) / grid_size_snapped) * grid_size_snapped

        for gl in self.gridlinesx:
            gl.setLine(x, -1e10, x, 1e10)
            x += grid_size_snapped
        for gl in self.gridlinesy:
            gl.setLine(-1e10, y, 1e10, y)
            y += grid_size_snapped
        self.grid_size_snapped = grid_size_snapped
        self.update_gridsize_label()

    def update_gridsize_label(self):
        self.gridsize_label.setText('grid size = ' +
                                    str(self.grid_size_snapped))
        self.gridsize_label.move(QPoint(5, self.height() - 25))

    def update_mouse_position_label(self):
        self.position_label.setText(
            'X = %0.4f / Y = %0.4f' %
            (self.mouse_position[0], self.mouse_position[1]))
        self.position_label.move(QPoint(self.width() - 250,
                                        self.height() - 25))

    def update_help_label(self):
        self.help_label.setText('Press "?" key for help')
        self.help_label.move(QPoint(self.width() - 175, 0))

    def create_grid(self):
        self.gridlinesx = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(300)
        ]
        self.gridlinesy = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(300)
        ]
        self.update_grid()

#==============================================================================
#  Mousewheel zoom, taken from http://stackoverflow.com/a/29026916
#==============================================================================

    def wheelEvent(self, event):
        # Zoom Factor
        zoom_percentage = 1.4

        # Set Anchors
        self.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.setResizeAnchor(QGraphicsView.NoAnchor)

        # Save the scene pos
        oldPos = self.mapToScene(event.pos())

        # Zoom
        mousewheel_rotation = event.angleDelta().y(
        )  # Typically = 120 on most mousewheels
        zoom_factor = zoom_percentage**(mousewheel_rotation / 120)
        zoom_factor = np.clip(zoom_factor, 0.5, 2.0)

        # Check to make sure we're not overzoomed
        min_width = 0.01
        min_height = 0.01

        window_width = self.rect().width()
        window_height = self.rect().height()
        scene_upper_left_corner = self.mapToScene(QPoint(0, 0))
        scene_bottom_right_corner = self.mapToScene(
            QPoint(window_width, window_height))
        scene_width = (scene_bottom_right_corner - scene_upper_left_corner).x()
        scene_height = (scene_upper_left_corner -
                        scene_bottom_right_corner).y()

        max_width = self.scene_bounding_rect.width() * 3
        max_height = self.scene_bounding_rect.height() * 3

        if ((scene_width > max_width) and
            (scene_height > max_height)) and (zoom_factor < 1):
            pass
        elif ((scene_width < min_width) and
              (scene_height < min_height)) and (zoom_factor > 1):
            pass
        else:
            self.zoom_view(zoom_factor)

        # Get the new position and move scene to old position
        newPos = self.mapToScene(event.pos())
        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())

        self.update_grid()

    def zoom_view(self, zoom_factor):
        old_center = self.mapToScene(self.rect().center())
        self.scale(zoom_factor, zoom_factor)
        self.centerOn(old_center)
        self.zoom_factor_total *= zoom_factor

    def resizeEvent(self, event):
        super(QGraphicsView, self).resizeEvent(event)
        if self.scene_bounding_rect is not None:
            self.reset_view()
        self.update_gridsize_label()
        self.update_mouse_position_label()
        self.update_help_label()

    def mousePressEvent(self, event):
        super(QGraphicsView, self).mousePressEvent(event)
        #==============================================================================
        #  Zoom to rectangle, from
        #  https://wiki.python.org/moin/PyQt/Selecting%20a%20region%20of%20a%20widget
        #==============================================================================
        if event.button() == Qt.RightButton:
            self._mousePressed = Qt.RightButton
            self._rb_origin = QPoint(event.pos())
            self.rubberBand.setGeometry(QRect(self._rb_origin, QSize()))
            self.rubberBand.show()
        #==============================================================================
        # Mouse panning, taken from
        # http://stackoverflow.com/a/15043279
        #==============================================================================
        elif event.button() == Qt.MidButton:
            self._mousePressed = Qt.MidButton
            self._mousePressedPos = event.pos()
            self.setCursor(QtCore.Qt.ClosedHandCursor)
            self._dragPos = event.pos()

    def mouseMoveEvent(self, event):
        super(QGraphicsView, self).mouseMoveEvent(event)

        # # Useful debug
        # try:
        #     self.debug_label.setText(str(itemsBoundingRect_nogrid().width()))
        # except:
        #     print('Debug statement failed')

        # Update the X,Y label indicating where the mouse is on the geometry
        mouse_position = self.mapToScene(event.pos())
        self.mouse_position = [mouse_position.x(), mouse_position.y()]
        self.update_mouse_position_label()

        if not self._rb_origin.isNull(
        ) and self._mousePressed == Qt.RightButton:
            self.rubberBand.setGeometry(
                QRect(self._rb_origin, event.pos()).normalized())

        # Middle-click-to-pan
        if self._mousePressed == Qt.MidButton:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() - diff.y())


#            event.accept()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.RightButton:
            self.rubberBand.hide()
            rb_rect = QRect(self._rb_origin, event.pos())
            rb_center = rb_rect.center()
            rb_size = rb_rect.size()

            if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3:
                viewport_size = self.viewport().geometry().size()

                zoom_factor_x = abs(viewport_size.width() / rb_size.width())
                zoom_factor_y = abs(viewport_size.height() / rb_size.height())

                new_center = self.mapToScene(rb_center)

                zoom_factor = min(zoom_factor_x, zoom_factor_y)
                self.zoom_view(zoom_factor)
                self.centerOn(new_center)

            self.update_grid()

        if event.button() == Qt.MidButton:
            self.setCursor(Qt.ArrowCursor)
            self._mousePressed = None
            self.update_grid()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.reset_view()

        if event.key() == Qt.Key_F1:
            self.set_alias_visibility(not self.aliases_visible)

        if event.key() == Qt.Key_F2:
            self.set_port_visibility(not self.ports_visible)

        if event.key() == Qt.Key_F3:
            self.set_subport_visibility(not self.subports_visible)

        if event.key() == Qt.Key_Question:
            help_str = """
            Mouse control:
              Mousewheel: Zoom in and out
              Right-click & drag: Zoom to rectangle
              Middle-click & drag: Pan

            Keyboard shortcuts:
              Esc: Reset view
              F1: Show/hide alias names
              F2: Show/hide ports
              F3: Show/hide subports (ports in underlying references)
            """
            msg = QMessageBox.about(self, 'PHIDL Help', help_str)
            msg.raise_()
Ejemplo n.º 2
0
class Dashboard(QGraphicsView):

    # Parameters

    WINDOW_WIDTH = 800
    WINDOW_HEIGHT = 480
    INACTIVE_COLOR = QColor('#252525')
    OK_COLOR = Qt.green
    WARNING_COLOR = Qt.yellow
    DANGEROUS_COLOR = Qt.red
    TACHOMETER_GEARS_ARROW_COLOR = Qt.white
    TACHOMETER_GEARS_NUMBER_COLOR = Qt.black
    GEAR_NUMBER_COLOR = Qt.white
    TACHOMETER_SCALING = 100
    ACCELEROMETER_MIN_ANGEL = 10
    ACCELEROMETER_MAX_ANGEL = 350

    # Constructor

    def __init__(self, initMode: DriveMode) -> None:
        # Init values
        self.mode = initMode
        self.tachometerEngineRpm = 0  # 0 - 9000
        self.tachometerEngineLevel = DashboardLevel.inactive
        self.tachometerGearboxRpm = 0  # 0 - 9000
        self.tachometerGearboxLevel = DashboardLevel.inactive
        self.tachometerGear1Rpm = 0  # 0 - 9000
        self.tachometerGear2Rpm = 0  # 0 - 9000
        self.tachometerGear3Rpm = 0  # 0 - 9000
        self.tachometerGear4Rpm = 0  # 0 - 9000
        self.tachometerGear5Rpm = 0  # 0 - 9000
        self.accelerometerAngel = 0  # -180 - +180
        self.accelerometerValue = 0.0  # 0.0 - 1.0
        self.accelerometerLevel = DashboardLevel.inactive
        self.steeringWheelEncoderAngel = 0  # -7 - +7
        self.steeringWheelEncoderLevel = DashboardLevel.inactive
        self.turnLeftIndicatorLevel = DashboardLevel.inactive
        self.turnRightIndicatorLevel = DashboardLevel.inactive
        self.oilWarningIndicatorLevel = DashboardLevel.inactive
        self.watterWarningIndicatorLevel = DashboardLevel.inactive
        self.gearNumberValue = 0  # 0 - 5
        self.speedometerValue = 0  # 0 - 999
        self.speedometerLevel = DashboardLevel.inactive
        self.stopwatchMills = 0  # 0 - 99
        self.stopwatchSeconds = 0  # 0 - 59
        self.stopwatchMinutes = 0  # 0 - 59
        self.stopwatchHours = 0  # 0 - 9
        self.stopwatchLevel = DashboardLevel.inactive
        self.oilManometerValue = 0.0  # 0.0 - 9.99
        self.oilManometerLevel = DashboardLevel.inactive
        self.oilThermometerValue = 0  # 0 - 999
        self.oilThermometerLevel = DashboardLevel.inactive
        self.watterThermometerValue = 0  # 0 - 999
        self.watterThermometerLevel = DashboardLevel.inactive
        self.odometerValue = 0  # 0 - 9999
        self.odometerLevel = DashboardLevel.inactive
        # Init UI
        super(Dashboard, self).__init__()
        viewport = QOpenGLWidget()
        viewportFormat = QSurfaceFormat()
        viewportFormat.setSwapInterval(0)  # disable VSync
        viewportFormat.setSamples(2**8)
        viewportFormat.setDefaultFormat(viewportFormat)
        viewport.setFormat(viewportFormat)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setGeometry(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT)
        self.setStyleSheet("border: 0px")
        self.setWindowTitle("Dashboard")
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.scene = QGraphicsScene(0, 0, self.WINDOW_WIDTH,
                                    self.WINDOW_HEIGHT)
        self.setScene(self.scene)
        self.setViewport(viewport)
        self.setInteractive(False)
        self.levelPens = {
            DashboardLevel.inactive: QPen(self.INACTIVE_COLOR, 1,
                                          Qt.SolidLine),
            DashboardLevel.ok: QPen(self.OK_COLOR, 1, Qt.SolidLine),
            DashboardLevel.warning: QPen(self.WARNING_COLOR, 1, Qt.SolidLine),
            DashboardLevel.dangerous: QPen(self.DANGEROUS_COLOR, 1,
                                           Qt.SolidLine)
        }
        self.levelBrushes = {
            DashboardLevel.inactive: QBrush(self.INACTIVE_COLOR,
                                            Qt.SolidPattern),
            DashboardLevel.ok: QBrush(self.OK_COLOR, Qt.SolidPattern),
            DashboardLevel.warning: QBrush(self.WARNING_COLOR,
                                           Qt.SolidPattern),
            DashboardLevel.dangerous: QBrush(self.DANGEROUS_COLOR,
                                             Qt.SolidPattern)
        }
        # Helpers
        dirPath = os.path.dirname(os.path.abspath(__file__))
        inactivePen = self.levelPens[DashboardLevel.inactive]
        inactiveBrush = self.levelBrushes[DashboardLevel.inactive]

        def buildPolygonItem(origin: QPointF, polygon: List[QPointF]):
            return self.scene.addPolygon(
                QPolygonF([
                    QPointF(p.x() + origin.x(),
                            p.y() + origin.y()) for p in polygon
                ]), inactivePen, inactiveBrush)

        def makeNumberItems(origin: QPointF, polygon: Dict[str,
                                                           List[QPointF]]):
            return {k: buildPolygonItem(origin, p) for k, p in polygon.items()}

        # Add background
        self.backgroundPixmaps = {
            DriveMode.race:
            QPixmap(os.path.join(dirPath, "background_race.png")).scaled(
                self.WINDOW_WIDTH, self.WINDOW_HEIGHT),
            DriveMode.street:
            QPixmap(os.path.join(dirPath, "background_street.png")).scaled(
                self.WINDOW_WIDTH, self.WINDOW_HEIGHT)
        }
        logging.debug(
            f"[Dashboard.__init__] Loaded: backgroundPixmaps = {self.backgroundPixmaps}, initMode = {initMode}"
        )
        self.backgroundItem = QGraphicsPixmapItem()
        self.backgroundItem.setZValue(-1)
        self.scene.addItem(self.backgroundItem)
        # Add tachometer graphics
        self.tachometerEngineItems = \
            {k: self.scene.addPolygon(p, inactivePen, inactiveBrush)
             for k, p in PolygonsMapping.TACHOMETER_ENGINE.items()}
        self.tachometerGearboxItems = \
            {k: self.scene.addPolygon(p, inactivePen, inactiveBrush)
             for k, p in PolygonsMapping.TACHOMETER_GEARBOX.items()}
        self.tachometerGearsPens = {
            "A": QPen(self.TACHOMETER_GEARS_ARROW_COLOR, 1, Qt.SolidLine),
            "N": QPen(self.TACHOMETER_GEARS_NUMBER_COLOR, 1, Qt.SolidLine)
        }
        self.tachometerGearsBrushes = {
            "A": QBrush(self.TACHOMETER_GEARS_ARROW_COLOR, Qt.SolidPattern),
            "N": QBrush(self.TACHOMETER_GEARS_NUMBER_COLOR, Qt.SolidPattern)
        }

        def makeGearsTransforms(translate: QPointF, rotate: int):
            arrowTrans = QTransform()
            arrowTrans.translate(translate.x(), translate.y())
            arrowTrans.rotate(rotate)
            numberTrans = QTransform()
            numberTrans.translate(translate.x(), translate.y())
            return arrowTrans, numberTrans
        self.tachometerGearsTransforms = \
            {k: makeGearsTransforms(p[0], p[1]) for k, p in PolygonsMapping.TACHOMETER_GEARS["T"].items()}

        def tachometerGearsItem(gearNumber: int):
            (arrowTrans, numberTrans) = self.tachometerGearsTransforms[0]
            arrowItem = self.scene.addPolygon(
                PolygonsMapping.TACHOMETER_GEARS["A"], inactivePen,
                inactiveBrush)
            arrowItem.setTransform(arrowTrans)
            numberItem = buildPolygonItem(
                PolygonsMapping.TACHOMETER_GEARS["N"]["O"],
                PolygonsMapping.TACHOMETER_GEARS["N"]["P"][gearNumber])
            numberItem.setTransform(numberTrans)
            return arrowItem, numberItem

        self.tachometerGearsItems = {
            1: tachometerGearsItem(1),
            2: tachometerGearsItem(2),
            3: tachometerGearsItem(3),
            4: tachometerGearsItem(4),
            5: tachometerGearsItem(5)
        }

        # Add accelerometer graphics
        def makeEllipse(points: Tuple[QPointF, QPointF]):
            return self.scene.addEllipse(points[0].x(), points[0].y(),
                                         points[1].x() - points[0].x(),
                                         points[1].y() - points[0].y(),
                                         inactivePen, inactiveBrush)

        self.accelerometerCenterItem = makeEllipse(
            PolygonsMapping.ACCELEROMETER["C"])
        self.accelerometerSectorItem = makeEllipse(
            PolygonsMapping.ACCELEROMETER["S"])
        self.accelerometerSectorItem.setStartAngle(
            int((270 - (self.ACCELEROMETER_MIN_ANGEL / 2))) * 16)
        self.accelerometerSectorItem.setSpanAngle(
            self.ACCELEROMETER_MIN_ANGEL * 16)
        # Add steering wheel encoder graphics
        self.steeringWheelEncoderItems = \
            {k: self.scene.addPolygon(p, inactivePen, inactiveBrush)
             for k, p in PolygonsMapping.STEERING_WHEEL_ENCODER.items()}

        # Add turn indicator graphics
        def makeTurnIndicatorItem(initCoordinates: Dict[str, Any]):
            return buildPolygonItem(initCoordinates["C"], initCoordinates["P"])

        self.turnIndicatorLeftItem = makeTurnIndicatorItem(
            PolygonsMapping.TURN_INDICATOR["L"])
        self.turnIndicatorRightItem = makeTurnIndicatorItem(
            PolygonsMapping.TURN_INDICATOR["R"])

        # Add warning indicators graphics
        def makeWarningIndicatorItems(initCoordinates: Dict[str, Any]):
            return [
                buildPolygonItem(initCoordinates["C"], p)
                for p in initCoordinates["P"]
            ]

        self.oilWarningIndicatorItems = makeWarningIndicatorItems(
            PolygonsMapping.WARNING_INDICATORS["OIL"])
        self.watterWarningIndicatorItems = makeWarningIndicatorItems(
            PolygonsMapping.WARNING_INDICATORS["WATTER"])
        # Add gear number graphics
        self.gearNumberPen = QPen(self.GEAR_NUMBER_COLOR, 1, Qt.SolidLine)
        self.gearNumberBrush = QBrush(self.GEAR_NUMBER_COLOR, Qt.SolidPattern)
        self.gearNumberItems = makeNumberItems(
            PolygonsMapping.GEAR_NUMBER["C"], PolygonsMapping.GEAR_NUMBER["P"])
        # Add speedometer graphics
        self.speedometer001Items = makeNumberItems(
            PolygonsMapping.SPEEDOMETER[1], PolygonsMapping.SPEED_NUMBERS)
        self.speedometer010Items = makeNumberItems(
            PolygonsMapping.SPEEDOMETER[10], PolygonsMapping.SPEED_NUMBERS)
        self.speedometer100Items = makeNumberItems(
            PolygonsMapping.SPEEDOMETER[100], PolygonsMapping.SPEED_NUMBERS)
        # Add stopwatch graphics
        self.stopwatchMS01Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["MS01"],
            PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchMS10Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["MS10"],
            PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchS01Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["S01"], PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchS10Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["S10"], PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchM01Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["M01"], PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchM10Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["M10"], PolygonsMapping.STANDARD_NUMBERS)
        self.stopwatchH01Items = makeNumberItems(
            PolygonsMapping.STOPWATCH["H01"], PolygonsMapping.STANDARD_NUMBERS)
        # Add oil manometer graphics
        self.oilManometer0d01Items = makeNumberItems(
            PolygonsMapping.OIL_MANOMETER[0.01],
            PolygonsMapping.STANDARD_NUMBERS)
        self.oilManometer0d10Items = makeNumberItems(
            PolygonsMapping.OIL_MANOMETER[0.1],
            PolygonsMapping.STANDARD_NUMBERS)
        self.oilManometer1d00Items = makeNumberItems(
            PolygonsMapping.OIL_MANOMETER[1], PolygonsMapping.STANDARD_NUMBERS)
        # Add oil thermometer graphics
        self.oilThermometer001Items = makeNumberItems(
            PolygonsMapping.OIL_THERMOMETER[1],
            PolygonsMapping.STANDARD_NUMBERS)
        self.oilThermometer010Items = makeNumberItems(
            PolygonsMapping.OIL_THERMOMETER[10],
            PolygonsMapping.STANDARD_NUMBERS)
        self.oilThermometer100Items = makeNumberItems(
            PolygonsMapping.OIL_THERMOMETER[100],
            PolygonsMapping.STANDARD_NUMBERS)
        # Add watter thermometer graphics
        self.watterThermometer001Items = makeNumberItems(
            PolygonsMapping.WATTER_THERMOMETER[1],
            PolygonsMapping.STANDARD_NUMBERS)
        self.watterThermometer010Items = makeNumberItems(
            PolygonsMapping.WATTER_THERMOMETER[10],
            PolygonsMapping.STANDARD_NUMBERS)
        self.watterThermometer100Items = makeNumberItems(
            PolygonsMapping.WATTER_THERMOMETER[100],
            PolygonsMapping.STANDARD_NUMBERS)
        # Add odometer graphics
        self.watterOdometer0001Items = makeNumberItems(
            PolygonsMapping.ODOMETER[1], PolygonsMapping.STANDARD_NUMBERS)
        self.watterOdometer0010Items = makeNumberItems(
            PolygonsMapping.ODOMETER[10], PolygonsMapping.STANDARD_NUMBERS)
        self.watterOdometer0100Items = makeNumberItems(
            PolygonsMapping.ODOMETER[100], PolygonsMapping.STANDARD_NUMBERS)
        self.watterOdometer1000Items = makeNumberItems(
            PolygonsMapping.ODOMETER[1000], PolygonsMapping.STANDARD_NUMBERS)
        # Initial rendering
        self.renderBackground()
        self.renderTachometerScale(self.tachometerEngineItems,
                                   self.tachometerEngineRpm,
                                   self.tachometerEngineLevel)
        self.renderTachometerScale(self.tachometerGearboxItems,
                                   self.tachometerGearboxRpm,
                                   self.tachometerGearboxLevel)
        self.renderAccelerometer()
        self.renderSteeringWheelEncoder()
        self.renderTurnLeftIndicator()
        self.renderTurnRightIndicator()
        self.renderOilWarningIndicator()
        self.renderWatterWarningIndicator()
        self.renderGearNumber()
        self.renderSpeedometer()
        self.renderStopwatch()
        self.renderOilManometer()
        self.renderOilThermometer()
        self.renderWatterThermometer()
        self.renderOdometer()

    # Helpers

    def renderNumberHelper(self, number: int, items: Dict[str, QStandardItem],
                           level: DashboardLevel) -> None:
        def setLevel(p: QStandardItem, l: DashboardLevel):
            p.setPen(self.levelPens[l])
            p.setBrush(self.levelBrushes[l])

        if level != DashboardLevel.inactive:
            for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][0]:
                setLevel(items[s], level)
            for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][1]:
                setLevel(items[s], DashboardLevel.inactive)
        else:
            for _, p in items.items():
                setLevel(p, DashboardLevel.inactive)

    def renderTripleNumberHelper(self, value: int,
                                 items001: Dict[str, QStandardItem],
                                 items010: Dict[str, QStandardItem],
                                 items100: Dict[str, QStandardItem],
                                 level: DashboardLevel) -> None:
        v001 = value % 10
        v010 = (value % 100) // 10
        v100 = value // 100
        self.renderNumberHelper(v001, items001, level)
        self.renderNumberHelper(
            v010, items010,
            level if v010 > 0 or v100 > 0 else DashboardLevel.inactive)
        self.renderNumberHelper(v100, items100,
                                level if v100 > 0 else DashboardLevel.inactive)

    # Rendering

    def renderBackground(self) -> None:
        logging.debug(f"[Dashboard.renderBackground] For mode = {self.mode}")
        # Render background pixmap
        self.backgroundItem.setPixmap(self.backgroundPixmaps[self.mode])
        # Re-render all indicators
        self.renderTachometerScale(self.tachometerEngineItems,
                                   self.tachometerEngineRpm,
                                   self.tachometerEngineLevel)
        self.renderTachometerScale(self.tachometerGearboxItems,
                                   self.tachometerGearboxRpm,
                                   self.tachometerGearboxLevel)
        self.renderTachometerGear(1, self.tachometerGear1Rpm)
        self.renderTachometerGear(2, self.tachometerGear2Rpm)
        self.renderTachometerGear(3, self.tachometerGear3Rpm)
        self.renderTachometerGear(4, self.tachometerGear4Rpm)
        self.renderTachometerGear(5, self.tachometerGear5Rpm)
        self.renderAccelerometer()
        self.renderSteeringWheelEncoder()
        self.renderTurnLeftIndicator()
        self.renderTurnRightIndicator()
        self.renderOilWarningIndicator()
        self.renderWatterWarningIndicator()
        self.renderGearNumber()
        self.renderSpeedometer()
        self.renderStopwatch()
        self.renderOilManometer()
        self.renderOilThermometer()
        self.renderWatterThermometer()
        self.renderOdometer()

    def renderTachometerScale(self, items: Dict[int, QStandardItem], rpm: int,
                              level: DashboardLevel) -> None:
        segment = round(rpm / self.TACHOMETER_SCALING)
        for k, p in items.items():
            if k <= segment:
                p.setPen(self.levelPens[level])
                p.setBrush(self.levelBrushes[level])
            else:
                p.setPen(self.levelPens[DashboardLevel.inactive])
                p.setBrush(self.levelBrushes[DashboardLevel.inactive])

    def renderTachometerGear(self, gearNumber: int, rpm: int) -> None:
        (arrowItem, numberItem) = self.tachometerGearsItems[gearNumber]
        segment = ((rpm if rpm <= 8600 else 8600) // 200) * 2
        (arrowTrans, numberTrans) = self.tachometerGearsTransforms[segment]
        arrowItem.setTransform(arrowTrans)
        arrowItem.setPen(self.tachometerGearsPens["A"])
        arrowItem.setBrush(self.tachometerGearsBrushes["A"])
        numberItem.setTransform(numberTrans)
        numberItem.setPen(self.tachometerGearsPens["N"])
        numberItem.setBrush(self.tachometerGearsBrushes["N"])

    def renderAccelerometer(self) -> None:
        newPen = self.levelPens[self.accelerometerLevel]
        newBrush = self.levelBrushes[self.accelerometerLevel]
        self.accelerometerCenterItem.setPen(newPen)
        self.accelerometerCenterItem.setBrush(newBrush)
        self.accelerometerSectorItem.setPen(newPen)
        self.accelerometerSectorItem.setBrush(newBrush)
        span = ((self.ACCELEROMETER_MAX_ANGEL - self.ACCELEROMETER_MIN_ANGEL) * self.accelerometerValue)\
            + self.ACCELEROMETER_MIN_ANGEL
        startAngel = self.accelerometerAngel - (span / 2)
        correctedAngel = ((startAngel - 90) if startAngel >= 90 else
                          (270 + startAngel))
        self.accelerometerSectorItem.setStartAngle(int(correctedAngel) * 16)
        self.accelerometerSectorItem.setSpanAngle(int(span) * 16)

    def renderSteeringWheelEncoder(self) -> None:
        angel = self.steeringWheelEncoderAngel
        for k, p in self.steeringWheelEncoderItems.items():
            if (angel == 0 and k == 0) or (abs(k) <= abs(angel) and k != 0 and
                                           (k * angel) > 0):
                p.setPen(self.levelPens[self.steeringWheelEncoderLevel])
                p.setBrush(self.levelBrushes[self.steeringWheelEncoderLevel])
            else:
                p.setPen(self.levelPens[DashboardLevel.inactive])
                p.setBrush(self.levelBrushes[DashboardLevel.inactive])

    def renderTurnLeftIndicator(self) -> None:
        self.turnIndicatorLeftItem.setPen(
            self.levelPens[self.turnLeftIndicatorLevel])
        self.turnIndicatorLeftItem.setBrush(
            self.levelBrushes[self.turnLeftIndicatorLevel])

    def renderTurnRightIndicator(self) -> None:
        self.turnIndicatorRightItem.setPen(
            self.levelPens[self.turnRightIndicatorLevel])
        self.turnIndicatorRightItem.setBrush(
            self.levelBrushes[self.turnRightIndicatorLevel])

    def renderOilWarningIndicator(self) -> None:
        for p in self.oilWarningIndicatorItems:
            p.setPen(self.levelPens[self.oilWarningIndicatorLevel])
            p.setBrush(self.levelBrushes[self.oilWarningIndicatorLevel])

    def renderWatterWarningIndicator(self) -> None:
        for p in self.watterWarningIndicatorItems:
            p.setPen(self.levelPens[self.watterWarningIndicatorLevel])
            p.setBrush(self.levelBrushes[self.watterWarningIndicatorLevel])

    def renderGearNumber(self) -> None:
        for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][0]:
            segment = self.gearNumberItems[s]
            segment.setPen(self.gearNumberPen)
            segment.setBrush(self.gearNumberBrush)
        for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][1]:
            segment = self.gearNumberItems[s]
            segment.setPen(self.levelPens[DashboardLevel.inactive])
            segment.setBrush(self.levelBrushes[DashboardLevel.inactive])

    def renderSpeedometer(self) -> None:
        self.renderTripleNumberHelper(self.speedometerValue,
                                      self.speedometer001Items,
                                      self.speedometer010Items,
                                      self.speedometer100Items,
                                      self.speedometerLevel)

    def renderStopwatch(self) -> None:
        self.renderNumberHelper(self.stopwatchMills % 10,
                                self.stopwatchMS01Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchMills // 10,
                                self.stopwatchMS10Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchSeconds % 10,
                                self.stopwatchS01Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchSeconds // 10,
                                self.stopwatchS10Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchMinutes % 10,
                                self.stopwatchM01Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchMinutes // 10,
                                self.stopwatchM10Items, self.stopwatchLevel)
        self.renderNumberHelper(self.stopwatchHours, self.stopwatchH01Items,
                                self.stopwatchLevel)

    def renderOilManometer(self) -> None:
        intValue = int(self.oilManometerValue * 100)
        self.renderNumberHelper(intValue % 10, self.oilManometer0d01Items,
                                self.oilManometerLevel)
        self.renderNumberHelper((intValue % 100) // 10,
                                self.oilManometer0d10Items,
                                self.oilManometerLevel)
        self.renderNumberHelper(intValue // 100, self.oilManometer1d00Items,
                                self.oilManometerLevel)

    def renderOilThermometer(self) -> None:
        self.renderTripleNumberHelper(self.oilThermometerValue,
                                      self.oilThermometer001Items,
                                      self.oilThermometer010Items,
                                      self.oilThermometer100Items,
                                      self.oilThermometerLevel)

    def renderWatterThermometer(self) -> None:
        self.renderTripleNumberHelper(self.watterThermometerValue,
                                      self.watterThermometer001Items,
                                      self.watterThermometer010Items,
                                      self.watterThermometer100Items,
                                      self.watterThermometerLevel)

    def renderOdometer(self) -> None:
        v0001 = (self.odometerValue % 10)
        v0010 = (self.odometerValue % 100) // 10
        v0100 = (self.odometerValue % 1000) // 100
        v1000 = self.odometerValue // 1000

        def level(isActive: bool):
            return self.odometerLevel if isActive > 0 else DashboardLevel.inactive

        self.renderNumberHelper(v0001, self.watterOdometer0001Items,
                                self.odometerLevel)
        self.renderNumberHelper(v0010, self.watterOdometer0010Items,
                                level(v0010 > 0 or v0100 > 0 or v1000 > 0))
        self.renderNumberHelper(v0100, self.watterOdometer0100Items,
                                level(v0100 > 0 or v1000 > 0))
        self.renderNumberHelper(v1000, self.watterOdometer1000Items,
                                level(v1000 > 0))

    # Methods

    @pyqtSlot(DriveMode)
    def inMode(self, mode: DriveMode) -> None:
        logging.debug(f"[Dashboard.inMode] New mode = {mode}")
        # Store new state
        self.mode = mode
        # Redraw UI
        self.renderBackground()

    @pyqtSlot(int, DashboardLevel)
    def inTachometerEngine(self, rpm: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inTachometerEngine] New rpm = {rpm}, level = {level}")
        # Store new state
        self.tachometerEngineRpm = 0 if rpm < 0 else (
            9000 if rpm > 9000 else rpm)
        self.tachometerEngineLevel = level
        # Redraw UI
        self.renderTachometerScale(self.tachometerEngineItems,
                                   self.tachometerEngineRpm,
                                   self.tachometerEngineLevel)

    @pyqtSlot(int, DashboardLevel)
    def inTachometerGearbox(self, rpm: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inTachometerGearbox] New rpm = {rpm}, level = {level}"
        )
        # Store new state
        self.tachometerGearboxRpm = 0 if rpm < 0 else (
            9000 if rpm > 9000 else rpm)
        self.tachometerGearboxLevel = level
        # Redraw UI
        self.renderTachometerScale(self.tachometerGearboxItems,
                                   self.tachometerGearboxRpm,
                                   self.tachometerGearboxLevel)

    @pyqtSlot(int, int, int, int, int)
    def inTachometerGears(self, rpm1: int, rpm2: int, rpm3: int, rpm4: int,
                          rpm5: int) -> None:
        logging.debug(
            f"[Dashboard.inTachometerGears] New rpm1 = {rpm1}, rpm2 = {rpm2}, rpm3 = {rpm3}, "
            f"rpm4 = {rpm4}, rpm5 = {rpm5}")
        # Store new state
        self.tachometerGear1Rpm = 0 if rpm1 < 0 else (
            9000 if rpm1 > 9000 else rpm1)
        self.tachometerGear2Rpm = 0 if rpm2 < 0 else (
            9000 if rpm2 > 9000 else rpm2)
        self.tachometerGear3Rpm = 0 if rpm3 < 0 else (
            9000 if rpm3 > 9000 else rpm3)
        self.tachometerGear4Rpm = 0 if rpm4 < 0 else (
            9000 if rpm4 > 9000 else rpm4)
        self.tachometerGear5Rpm = 0 if rpm5 < 0 else (
            9000 if rpm5 > 9000 else rpm5)
        # Redraw UI
        self.renderTachometerGear(1, self.tachometerGear1Rpm)
        self.renderTachometerGear(2, self.tachometerGear2Rpm)
        self.renderTachometerGear(3, self.tachometerGear3Rpm)
        self.renderTachometerGear(4, self.tachometerGear4Rpm)
        self.renderTachometerGear(5, self.tachometerGear5Rpm)

    @pyqtSlot(int, float, DashboardLevel)
    def inAccelerometer(self, angel: int, value: float,
                        level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inAccelerometer] New angel = {angel}, value = {value}, level = {level}"
        )
        # Store new state
        self.accelerometerAngel = -180 if angel < -180 else (
            180 if angel > 180 else angel)
        self.accelerometerValue = 0.0 if value < 0.0 else (
            1.0 if value > 1.0 else value)
        self.accelerometerLevel = level
        # Redraw UI
        self.renderAccelerometer()

    @pyqtSlot(int, DashboardLevel)
    def inSteeringWheelEncoder(self, angel: int,
                               level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inSteeringWheelEncoder] New angel = {angel}, level = {level}"
        )
        # Store new state
        self.steeringWheelEncoderAngel = -7 if angel < -7 else (
            7 if angel > 7 else angel)
        self.steeringWheelEncoderLevel = level
        # Redraw UI
        self.renderSteeringWheelEncoder()

    @pyqtSlot(DashboardLevel)
    def inTurnLeftIndicator(self, level: DashboardLevel) -> None:
        logging.debug(f"[Dashboard.inTurnLeftIndicator] New level = {level}")
        # Store new state
        self.turnLeftIndicatorLevel = level
        # Redraw UI
        self.renderTurnLeftIndicator()

    @pyqtSlot(DashboardLevel)
    def inTurnRightIndicator(self, level: DashboardLevel) -> None:
        logging.debug(f"[Dashboard.inTurnRightIndicator] New level = {level}")
        # Store new state
        self.turnRightIndicatorLevel = level
        # Redraw UI
        self.renderTurnRightIndicator()

    @pyqtSlot(int)
    def inGearNumber(self, value: int) -> None:
        logging.debug(f"[Dashboard.inGearNumber] New value = {value}")
        # Store new state
        self.gearNumberValue = 0 if value < 0 else (5 if value > 5 else value)
        # Redraw UI
        self.renderGearNumber()

    @pyqtSlot(DashboardLevel)
    def inOilWarningIndicator(self, level: DashboardLevel) -> None:
        logging.debug(f"[Dashboard.inOilWarningIndicator] New level = {level}")
        # Store new state
        self.oilWarningIndicatorLevel = level
        # Redraw UI
        self.renderOilWarningIndicator()

    @pyqtSlot(DashboardLevel)
    def inWatterWarningIndicator(self, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inWatterWarningIndicator] New level = {level}")
        # Store new state
        self.watterWarningIndicatorLevel = level
        # Redraw UI
        self.renderWatterWarningIndicator()

    @pyqtSlot(int, DashboardLevel)
    def inSpeedometer(self, value: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inSpeedometer] New value = {value}, level = {level}")
        # Store new state
        self.speedometerValue = 0 if value < 0 else (
            999 if value > 999 else value)
        self.speedometerLevel = level
        # Redraw UI
        self.renderSpeedometer()

    @pyqtSlot(int, int, int, int, DashboardLevel)
    def inStopwatch(self, mills: int, seconds: int, minutes: int, hours: int,
                    level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inStopwatch] New mills = {mills}, seconds = {seconds}, minutes = {minutes}, "
            f"hours = {hours}, level = {level}")
        # Store new state
        self.stopwatchMills = 0 if mills < 0 else (99 if mills > 99 else mills)
        self.stopwatchSeconds = 0 if seconds < 0 else (
            59 if seconds > 59 else seconds)
        self.stopwatchMinutes = 0 if minutes < 0 else (
            59 if minutes > 59 else minutes)
        self.stopwatchHours = 0 if hours < 0 else (9 if hours > 9 else hours)
        self.stopwatchLevel = level
        # Redraw UI
        self.renderStopwatch()

    @pyqtSlot(float, DashboardLevel)
    def inOilManometer(self, value: float, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inOilManometer] New value = {value}, level = {level}")
        # Store new state
        self.oilManometerValue = 0.0 if value < 0.0 else (
            9.99 if value > 9.99 else value)
        self.oilManometerLevel = level
        # Redraw UI
        self.renderOilManometer()

    @pyqtSlot(int, DashboardLevel)
    def inOilThermometer(self, value: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inOilThermometer] New value = {value}, level = {level}"
        )
        # Store new state
        self.oilThermometerValue = 0 if value < 0 else (
            999 if value > 999 else value)
        self.oilThermometerLevel = level
        # Redraw UI
        self.renderOilThermometer()

    @pyqtSlot(int, DashboardLevel)
    def inWatterThermometer(self, value: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inWatterThermometer] New value = {value}, level = {level}"
        )
        # Store new state
        self.watterThermometerValue = 0 if value < 0 else (
            999 if value > 999 else value)
        self.watterThermometerLevel = level
        # Redraw UI
        self.renderWatterThermometer()

    @pyqtSlot(int, DashboardLevel)
    def inOdometer(self, value: int, level: DashboardLevel) -> None:
        logging.debug(
            f"[Dashboard.inOdometer] New value = {value}, level = {level}")
        # Store new state
        self.odometerValue = 0 if value < 0 else (
            9999 if value > 9999 else value)
        self.odometerLevel = level
        # Redraw UI
        self.renderOdometer()
Ejemplo n.º 3
0
class KineticsWidget(EditorWidgetBase):
    def __init__(self, *args):
        EditorWidgetBase.__init__(self, *args)
        self.setAcceptDrops(True)
        self.border = 10
        self.sceneContainer = QGraphicsScene(self)
        self.sceneContainer.setSceneRect(
            self.sceneContainer.itemsBoundingRect())
        self.sceneContainer.setBackgroundBrush(QtGui.QColor(
            230, 220, 219, 120))

        self.insertMenu = QMenu('&Insert')
        self._menus.append(self.insertMenu)
        self.insertMapper = QtCore.QSignalMapper(self)

        classlist = [
            'CubeMesh', 'CylMesh', 'Pool', 'Reac', 'Enz', 'MMenz',
            'StimulusTable', 'Table'
        ]
        insertMapper, actions = self.getInsertActions(classlist)

        for action in actions:
            self.insertMenu.addAction(action)

    def getToolBars(self):
        if not hasattr(self, '_insertToolBar'):
            self._insertToolBar = QtGui.QToolBar('Insert')
            self._toolBars.append(self._insertToolBar)
            for action in self.insertMenu.actions():
                button = MToolButton()
                button.setDefaultAction(action)
                self._insertToolBar.addWidget(button)
        return self._toolBars

    def sizeHint(self):
        return QtCore.QSize(800, 400)

    def updateModelView(self):
        #print "update model view",self.modelRoot
        if self.modelRoot == '/':
            m = moose.wildcardFind('/##[ISA=ChemCompt]')
        else:
            m = moose.wildcardFind(self.modelRoot + '/##[ISA=ChemCompt]')
        #print "111",self.modelRoot,m
        if not m:
            # when we want an empty GraphicView while creating new model,
            # then remove all the view and add an empty view
            if hasattr(self, 'view') and isinstance(self.view, QWidget):
                self.layout().removeWidget(self.view)
            self.view = GraphicalView(self.sceneContainer, self.border, self)
            self.layout().addWidget(self.view)
        else:
            # maxmium and minimum coordinates of the objects specified in kkit file.
            self.xmin = 0.0
            self.xmax = 1.0
            self.ymin = 0.0
            self.ymax = 1.0
            self.autoCordinatepos = {}
            self.sceneContainer.clear()
            # TODO: size will be dummy at this point, but I need the availiable size from the Gui
            self.size = QtCore.QSize(1024, 768)
            #self.size = QtCore.QSize(300,400)
            self.autocoordinates = False

            # pickled the color map file """
            colormap_file = open(
                os.path.join(config.settings[config.KEY_COLORMAP_DIR],
                             'rainbow2.pkl'), 'rb')
            self.colorMap = pickle.load(colormap_file)
            colormap_file.close()

            # Compartment and its members are setup """
            o, self.meshEntry, self.xmin, self.xmax, self.ymin, \
                    self.ymax, self.noPositionInfo = kkitOrdinateUtil.setupMeshObj(self.modelRoot)

            self.srcdesConnection = {}
            kkitOrdinateUtil.setupItem(self.modelRoot, self.srcdesConnection)
            if self.noPositionInfo:
                self.autocoordinates = True
                QMessageBox.warning(self, 'No coordinates found for the model',
                                    '\n Automatic layouting will be done')
                kkitOrdinateUtil.autoCoordinates(self.meshEntry,
                                                 self.srcdesConnection)

            # Scale factor to translate the x -y position to fit the Qt graphicalScene, scene width. """
            if self.xmax - self.xmin != 0:
                self.xratio = (self.size.width() - 10) / (self.xmax -
                                                          self.xmin)
            else:
                self.xratio = self.size.width() - 10

            if self.ymax - self.ymin:
                self.yratio = (self.size.height() - 10) / (self.ymax -
                                                           self.ymin)
            else:
                self.yratio = (self.size.height() - 10)

            #A map b/w moose compartment key with QGraphicsObject
            self.qGraCompt = {}

            #A map between mooseId of all the mooseObject (except compartment) with QGraphicsObject
            self.mooseId_GObj = {}

            self.border = 5
            self.arrowsize = 2
            self.iconScale = 1
            self.defaultComptsize = 5
            self.itemignoreZooming = False
            self.lineItem_dict = {}
            self.object2line = defaultdict(list)

            # Compartment and its members are put on the qgraphicsscene
            self.mooseObjOntoscene()

            # All the moose Object are connected for visualization
            self.drawLine_arrow(itemignoreZooming=False)
            if hasattr(self, 'view') and isinstance(self.view, QWidget):
                self.layout().removeWidget(self.view)
            self.view = GraphicalView(self.sceneContainer, self.border, self)
            hLayout = QtGui.QGridLayout(self)
            self.setLayout(hLayout)
            hLayout.addWidget(self.view)
            #self.layout().addWidget(self.view)

    def mooseObjOntoscene(self):
        #  All the compartments are put first on to the scene \
        #  Need to do: Check With upi if empty compartments exist
        for cmpt in sorted(self.meshEntry.keys()):
            self.createCompt(cmpt)
            self.qGraCompt[cmpt]

        for cmpt, memb in list(self.meshEntry.items()):
            for enzObj in memb.get('enzyme', []):
                enzinfo = enzObj.path + '/info'
                if enzObj.className == 'ZEnz':
                    enzItem = EnzItem(enzObj, self.qGraCompt[cmpt])
                else:
                    enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt])
                self.setupDisplay(enzinfo, enzItem, "enzyme")
                self.setupSlot(enzObj, enzItem)

        for cmpt, memb in list(self.meshEntry.items()):
            for poolObj in kkitOrdinateUtil.find_index(memb, 'pool'):
                poolinfo = poolObj.path + '/info'
                poolItem = PoolItem(poolObj, self.qGraCompt[cmpt])
                self.setupDisplay(poolinfo, poolItem, "pool")
                self.setupSlot(poolObj, poolItem)

            for cplxObj in kkitOrdinateUtil.find_index(memb, 'cplx'):
                cplxinfo = (cplxObj[0].parent).path + '/info'
                cplxItem = CplxItem(
                    cplxObj,
                    self.mooseId_GObj[element(cplxObj[0]).parent.getId()])
                self.setupDisplay(cplxinfo, cplxItem, "cplx")
                self.setupSlot(cplxObj, cplxItem)

            for reaObj in kkitOrdinateUtil.find_index(memb, 'reaction'):
                reainfo = reaObj.path + '/info'
                reaItem = ReacItem(reaObj, self.qGraCompt[cmpt])
                self.setupDisplay(reainfo, reaItem, "reaction")
                self.setupSlot(reaObj, reaItem)

            for tabObj in kkitOrdinateUtil.find_index(memb, 'table'):
                tabinfo = tabObj.path + '/info'
                tabItem = PoolItem(tabObj, self.qGraCompt[cmpt])
                self.setupDisplay(tabinfo, tabItem, "tab")
                self.setupSlot(tabObj, tabItem)
        # compartment's rectangle size is calculated depending on children
        for k, v in list(self.qGraCompt.items()):
            rectcompt = v.childrenBoundingRect()
            v.setRect(rectcompt.x() - 10,
                      rectcompt.y() - 10, (rectcompt.width() + 20),
                      (rectcompt.height() + 20))
            v.setPen(
                QtGui.QPen(Qt.QColor(66, 66, 66, 100), 5, Qt.Qt.SolidLine,
                           Qt.Qt.RoundCap, Qt.Qt.RoundJoin))
            v.cmptEmitter.connect(
                v.cmptEmitter,
                QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),
                self.positionChange)
            v.cmptEmitter.connect(
                v.cmptEmitter,
                QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),
                self.objectEditSlot)

    def createCompt(self, key):
        self.new_Compt = ComptItem(self, 0, 0, 0, 0, key)
        self.qGraCompt[key] = self.new_Compt
        self.new_Compt.setRect(10, 10, 10, 10)
        self.sceneContainer.addItem(self.new_Compt)

    def setupDisplay(self, info, graphicalObj, objClass):
        xpos, ypos = self.positioninfo(info)

        # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \
        #    we are not using these colors for displaying the object so just passing dummy color white

        if ((objClass == "reaction") or (objClass == "cplx")):
            textcolor, bgcolor = "white", "white"
        elif objClass == "tab":
            textcolor, bgcolor = getColor(info, self.colorMap)
        else:
            textcolor, bgcolor = getColor(info, self.colorMap)

        graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor)

    def positioninfo(self, iteminfo):
        if self.noPositionInfo:

            try:
                # kkit does exist item's/info which up querying for parent.path gives the information of item's parent
                x, y = self.autoCordinatepos[(element(iteminfo).parent).path]
            except:
                # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\
                # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\
                # type of the object (rea,pool,enz,cplx,tab) which I have already done.
                parent, child = posixpath.split(iteminfo)
                x, y = self.autoCordinatepos[parent]
            ypos = (y - self.ymin) * self.yratio
        else:
            x = float(element(iteminfo).getField('x'))
            y = float(element(iteminfo).getField('y'))
            #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \
            #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated
            ypos = -(y - self.ymin) * self.yratio
        xpos = (x - self.xmin) * self.xratio

        return (xpos, ypos)

    def setupSlot(self, mooseObj, qgraphicItem):
        self.mooseId_GObj[element(mooseObj).getId()] = qgraphicItem
        qgraphicItem.connect(
            qgraphicItem, QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),
            self.positionChange)
        qgraphicItem.connect(
            qgraphicItem,
            QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),
            self.objectEditSlot)

    def updateItemSlot(self, mooseObject):
        #This is overridden by derived classes to connect appropriate
        #slot for updating the display item.
        #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation
        changedItem = ''
        for item in list(self.sceneContainer.items()):
            if isinstance(item, PoolItem):
                if mooseObject.getId() == element(item.mobj).getId():
                    item.updateSlot()
                    #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted
                    self.positionChange(mooseObject)

    def positionChange(self, mooseObject):
        #If the item position changes, the corresponding arrow's are calculated
        if isinstance(element(mooseObject), CubeMesh):
            for k, v in list(self.qGraCompt.items()):
                mesh = mooseObject.path + '/mesh[0]'
                if k.path == mesh:
                    for rectChilditem in v.childItems():
                        self.updateArrow(rectChilditem)
        else:
            mobj = self.mooseId_GObj[mooseObject.getId()]
            self.updateArrow(mobj)
            for k, v in list(self.qGraCompt.items()):
                rectcompt = v.childrenBoundingRect()
                v.setRect(rectcompt.x() - 10,
                          rectcompt.y() - 10, (rectcompt.width() + 20),
                          (rectcompt.height() + 20))

    def emitItemtoEditor(self, mooseObject):
        #self.emit(QtCore.SIGNAL("itemPressed(PyQt_PyObject)"),mooseObject)
        self.editObject.emit(mooseObject.path)

    def drawLine_arrow(self, itemignoreZooming=False):
        for inn, out in list(self.srcdesConnection.items()):
            # self.srcdesConnection is dictionary which contains key,value \
            #    key is Enzyme or Reaction  and value [[list of substrate],[list of product]] (tuple)
            #    key is FuncBase and value is [list of pool] (list)

            #src = self.mooseId_GObj[inn]
            if isinstance(out, tuple):
                if len(out[0]) == 0:
                    print(inn.className + ':' + inn[0].name +
                          " doesn't output message")
                else:
                    src = self.mooseId_GObj[inn]
                    for items in (items for items in out[0]):
                        des = self.mooseId_GObj[element(items[0]).getId()]

                        self.lineCord(src, des, items, itemignoreZooming)
                if len(out[1]) == 0:
                    print(inn.className + ':' + inn[0].name +
                          " doesn't output message")
                else:
                    for items in (items for items in out[1]):
                        des = self.mooseId_GObj[element(items[0]).getId()]
                        self.lineCord(src, des, items, itemignoreZooming)

            elif isinstance(out, list):
                if len(out) == 0:
                    print("Func pool doesn't have sumtotal")
                else:
                    src = self.mooseId_GObj[element(inn).getId()]
                    for items in (items for items in out):
                        des = self.mooseId_GObj[element(items[0]).getId()]
                        self.lineCord(src, des, items, itemignoreZooming)

    def lineCord(self, src, des, type_no, itemignoreZooming):
        endtype = type_no[1]
        line = 0
        if (src == "") and (des == ""):
            print("Source or destination is missing or incorrect")
            return
        srcdes_list = [src, des, endtype, line]
        arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale)
        self.drawLine(srcdes_list, arrow)

        while (type_no[2] > 1 and line <= (type_no[2] - 1)):
            srcdes_list = [src, des, endtype, line]
            arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale)
            self.drawLine(srcdes_list, arrow)
            line = line + 1

        if type_no[2] > 5:
            print("Higher order reaction will not be displayed")

    def drawLine(self, srcdes_list, arrow):
        src = srcdes_list[0]
        des = srcdes_list[1]
        endtype = srcdes_list[2]
        line = srcdes_list[3]
        source = element(
            next((k for k, v in list(self.mooseId_GObj.items()) if v == src),
                 None))
        for l, v, o in self.object2line[src]:
            if v == des and o == line:
                l.setPolygon(arrow)
                arrowPen = l.pen()
                arrowPenWidth = self.arrowsize * self.iconScale
                arrowPen.setColor(l.pen().color())
                arrowPen.setWidth(arrowPenWidth)
                l.setPen(arrowPen)
                return

        qgLineitem = self.sceneContainer.addPolygon(arrow)
        pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap,
                         Qt.Qt.RoundJoin)
        pen.setWidth(self.arrowsize)
        #pen.setCosmetic(True)
        # Green is default color moose.ReacBase and derivatives - already set above
        if isinstance(source, EnzBase):
            if ((endtype == 's') or (endtype == 'p')):
                pen.setColor(QtCore.Qt.red)
            elif (endtype != 'cplx'):
                p1 = (next(
                    (k
                     for k, v in list(self.mooseId_GObj.items()) if v == src),
                    None))
                pinfo = p1.path + '/info'
                color, bgcolor = getColor(pinfo, self.colorMap)
                pen.setColor(color)
        elif isinstance(source, moose.PoolBase):
            pen.setColor(QtCore.Qt.blue)
        elif isinstance(source, moose.StimulusTable):
            pen.setColor(QtCore.Qt.yellow)
        self.lineItem_dict[qgLineitem] = srcdes_list
        self.object2line[src].append((qgLineitem, des, line))
        self.object2line[des].append((qgLineitem, src, line))
        qgLineitem.setPen(pen)

    def updateArrow(self, qGTextitem):
        #if there is no arrow to update then return
        if qGTextitem not in self.object2line:
            return
        listItem = self.object2line[qGTextitem]
        for ql, va, order in self.object2line[qGTextitem]:
            srcdes = []
            srcdes = self.lineItem_dict[ql]
            # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz,
            # if yes then need to check if cplx is connected to any mooseObject,
            # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated
            if (type(srcdes[0]) == EnzItem):
                self.cplxUpdatearrow(srcdes[0])
            elif (type(srcdes[1]) == EnzItem):
                self.cplxUpdatearrow(srcdes[1])

            # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided
            arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale)
            ql.setPolygon(arrow)

    def cplxUpdatearrow(self, srcdes):
        # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz)
        #And cplxItem is passed for updatearrow

        #Note: Here at this point enzItem has just one child which is cplxItem and childItems returns, PyQt5.QtGui.QGraphicsEllipseItem,CplxItem
        #Assuming CplxItem is always[1], but still check if not[0], if something changes in structure one need to keep an eye.
        if (srcdes.childItems()[1], CplxItem):
            self.updateArrow(srcdes.childItems()[1])
        else:
            self.updateArrow(srcdes.childItems()[0])

    def keyPressEvent(self, event):
        # key1 = event.key() # key event does not distinguish between capital and non-capital letters
        key = event.text().toAscii().toHex()
        if key == '41':  # 'A' fits the view to iconScale factor
            itemignoreZooming = False
            self.updateItemTransformationMode(itemignoreZooming)
            self.view.fitInView(
                self.sceneContainer.itemsBoundingRect().x() - 10,
                self.sceneContainer.itemsBoundingRect().y() - 10,
                self.sceneContainer.itemsBoundingRect().width() + 20,
                self.sceneContainer.itemsBoundingRect().height() + 20,
                Qt.Qt.IgnoreAspectRatio)
            self.drawLine_arrow(itemignoreZooming=False)

        elif (key == '2e'):  # '.' key, lower case for '>' zooms in
            self.view.scale(1.1, 1.1)

        elif (key == '2c'):  # ',' key, lower case for '<' zooms in
            self.view.scale(1 / 1.1, 1 / 1.1)

        elif (key == '3c'):  # '<' key. zooms-in to iconScale factor
            self.iconScale *= 0.8
            self.updateScale(self.iconScale)

        elif (key == '3e'):  # '>' key. zooms-out to iconScale factor
            self.iconScale *= 1.25
            self.updateScale(self.iconScale)

        elif (key == '61'
              ):  # 'a' fits the view to initial value where iconscale=1
            self.iconScale = 1
            self.updateScale(self.iconScale)
            self.view.fitInView(
                self.sceneContainer.itemsBoundingRect().x() - 10,
                self.sceneContainer.itemsBoundingRect().y() - 10,
                self.sceneContainer.itemsBoundingRect().width() + 20,
                self.sceneContainer.itemsBoundingRect().height() + 20,
                Qt.Qt.IgnoreAspectRatio)

    def updateItemTransformationMode(self, on):
        for v in list(self.sceneContainer.items()):
            if (not isinstance(v, ComptItem)):
                #if ( isinstance(v, PoolItem) or isinstance(v, ReacItem) or isinstance(v, EnzItem) or isinstance(v, CplxItem) ):
                if isinstance(v, KineticsDisplayItem):
                    v.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations,
                              on)

    def updateScale(self, scale):
        for item in list(self.sceneContainer.items()):
            if isinstance(item, KineticsDisplayItem):
                item.refresh(scale)
                #iteminfo = item.mobj.path+'/info'
                #xpos,ypos = self.positioninfo(iteminfo)
                xpos = item.scenePos().x()
                ypos = item.scenePos().y()

                if isinstance(item, ReacItem) or isinstance(
                        item, EnzItem) or isinstance(item, MMEnzItem):
                    item.setGeometry(xpos, ypos,
                                     item.gobj.boundingRect().width(),
                                     item.gobj.boundingRect().height())
                elif isinstance(item, CplxItem):
                    item.setGeometry(item.gobj.boundingRect().width() / 2,
                                     item.gobj.boundingRect().height(),
                                     item.gobj.boundingRect().width(),
                                     item.gobj.boundingRect().height())
                elif isinstance(item, PoolItem):
                    item.setGeometry(
                        xpos, ypos,
                        item.gobj.boundingRect().width() +
                        PoolItem.fontMetrics.width('  '),
                        item.gobj.boundingRect().height())
                    item.bg.setRect(
                        0, 0,
                        item.gobj.boundingRect().width() +
                        PoolItem.fontMetrics.width('  '),
                        item.gobj.boundingRect().height())

        self.drawLine_arrow(itemignoreZooming=False)
        for k, v in list(self.qGraCompt.items()):
            rectcompt = v.childrenBoundingRect()
            comptPen = v.pen()
            comptWidth = self.defaultComptsize * self.iconScale
            comptPen.setWidth(comptWidth)
            v.setPen(comptPen)
            v.setRect(rectcompt.x() - comptWidth,
                      rectcompt.y() - comptWidth,
                      (rectcompt.width() + 2 * comptWidth),
                      (rectcompt.height() + 2 * comptWidth))
Ejemplo n.º 4
0
class Screenshot(QGraphicsView):
    """ Main Class """

    screen_shot_grabed = pyqtSignal(QImage)
    widget_closed = pyqtSignal()

    def __init__(self, flags=constant.DEFAULT, parent=None):
        """
        flags: binary flags. see the flags in the constant.py
        """
        super().__init__(parent)

        # Init
        self.penColorNow = QColor(PENCOLOR)
        self.penSizeNow = PENSIZE
        self.fontNow = QFont('Sans')
        self.clipboard = QApplication.clipboard()

        self.drawListResult = [
        ]  # draw list that sure to be drew, [action, coord]
        self.drawListProcess = None  # the process to the result
        self.selectedArea = QRect(
        )  # a QRect instance which stands for the selected area
        self.selectedAreaRaw = QRect()
        self.mousePosition = MousePosition.OUTSIDE_AREA  # mouse position
        self.screenPixel = None
        self.textRect = None

        self.mousePressed = False
        self.action = ACTION_SELECT
        self.mousePoint = self.cursor().pos()

        self.startX, self.startY = 0, 0  # the point where you start
        self.endX, self.endY = 0, 0  # the point where you end
        self.pointPath = QPainterPath(
        )  # the point mouse passes, used by draw free line
        self.itemsToRemove = [
        ]  # the items that should not draw on screenshot picture
        self.textPosition = None

        # result
        self.target_img = None

        # Init window
        self.getscreenshot()
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)

        self.setMouseTracking(True)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setContentsMargins(0, 0, 0, 0)
        self.setStyleSheet("QGraphicsView { border-style: none; }")

        self.tooBar = MyToolBar(flags, self)
        self.tooBar.trigger.connect(self.changeAction)

        self.penSetBar = None
        if flags & constant.RECT or flags & constant.ELLIPSE or flags & constant.LINE or flags & constant.FREEPEN \
                or flags & constant.ARROW or flags & constant.TEXT:
            self.penSetBar = PenSetWidget(self)
            self.penSetBar.penSizeTrigger.connect(self.changePenSize)
            self.penSetBar.penColorTrigger.connect(self.changePenColor)
            self.penSetBar.fontChangeTrigger.connect(self.changeFont)

        self.textInput = TextInput(self)
        self.textInput.inputChanged.connect(self.textChange)
        self.textInput.cancelPressed.connect(self.cancelInput)
        self.textInput.okPressed.connect(self.okInput)

        self.graphicsScene = QGraphicsScene(0, 0, self.screenPixel.width(),
                                            self.screenPixel.height())

        self.show()
        self.setScene(self.graphicsScene)
        self.windowHandle().setScreen(QGuiApplication.screenAt(QCursor.pos()))
        self.scale = self.get_scale()
        # self.setFixedSize(self.screenPixel.width(), self.screenPixel.height())
        self.setGeometry(QGuiApplication.screenAt(QCursor.pos()).geometry())
        self.showFullScreen()
        self.redraw()

        QShortcut(QKeySequence('ctrl+s'),
                  self).activated.connect(self.saveScreenshot)
        QShortcut(QKeySequence('esc'), self).activated.connect(self.close)

    @staticmethod
    def take_screenshot(flags):
        loop = QEventLoop()
        screen_shot = Screenshot(flags)
        screen_shot.show()
        screen_shot.widget_closed.connect(loop.quit)

        loop.exec()
        img = screen_shot.target_img
        return img

    def getscreenshot(self):
        screen = QGuiApplication.screenAt(QCursor.pos())
        self.screenPixel = screen.grabWindow(0)

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.action is None:
            self.action = ACTION_SELECT

        self.startX, self.startY = event.x(), event.y()

        if self.action == ACTION_SELECT:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.mousePressed = True
                self.selectedArea = QRect()
                self.selectedArea.setTopLeft(QPoint(event.x(), event.y()))
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.mousePosition == MousePosition.INSIDE_AREA:
                self.mousePressed = True
            else:
                pass
        elif self.action == ACTION_MOVE_SELECTED:
            if self.mousePosition == MousePosition.OUTSIDE_AREA:
                self.action = ACTION_SELECT
                self.selectedArea = QRect()
                self.selectedArea.setTopLeft(QPoint(event.x(), event.y()))
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            self.mousePressed = True
        elif self.action in DRAW_ACTION:
            self.mousePressed = True
            if self.action == ACTION_FREEPEN:
                self.pointPath = QPainterPath()
                self.pointPath.moveTo(QPoint(event.x(), event.y()))
            elif self.action == ACTION_TEXT:
                if self.textPosition is None:
                    self.textPosition = QPoint(event.x(), event.y())
                    self.textRect = None
                    self.redraw()

    def mouseMoveEvent(self, event: QMouseEvent):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.mousePoint = QPoint(event.globalPos().x(), event.globalPos().y())

        if self.action is None:
            self.action = ACTION_SELECT

        if not self.mousePressed:
            point = QPoint(event.x(), event.y())
            self.detectMousePosition(point)
            self.setCursorStyle()
            self.redraw()
        else:
            self.endX, self.endY = event.x(), event.y()

            # if self.mousePosition != OUTSIDE_AREA:
            #    self.action = ACTION_MOVE_SELECTED

            if self.action == ACTION_SELECT:
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedArea = QRect(self.selectedAreaRaw)

                if self.mousePosition == MousePosition.INSIDE_AREA:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    if 0 <= moveToX <= self.screenPixel.width(
                    ) - 1 - self.selectedArea.width():
                        self.selectedArea.moveLeft(moveToX)
                    if 0 <= moveToY <= self.screenPixel.height(
                    ) - 1 - self.selectedArea.height():
                        self.selectedArea.moveTop(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.selectedAreaRaw = QRect(self.selectedArea)
                    self.startX, self.startY = event.x(), event.y()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    if moveToX <= self.selectedArea.right():
                        self.selectedArea.setLeft(moveToX)
                        self.selectedArea = self.selectedArea.normalized()
                        self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    self.selectedArea.setRight(moveToX)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_UP_SIDE:
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTop(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottom(moveToY)
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTopLeft(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottomRight(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER:
                    moveToX = event.x(
                    ) - self.startX + self.selectedArea.right()
                    moveToY = event.y() - self.startY + self.selectedArea.top()
                    self.selectedArea.setTopRight(QPoint(moveToX, moveToY))
                    self.selectedArea = self.selectedArea.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:
                    moveToX = event.x() - self.startX + self.selectedArea.left(
                    )
                    moveToY = event.y(
                    ) - self.startY + self.selectedArea.bottom()
                    self.selectedArea.setBottomLeft(QPoint(moveToX, moveToY))
                    self.redraw()
                else:
                    pass
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
                pass
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), False)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               False)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              False)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                y1, y2 = event.x(), event.y()
                rect = self.selectedArea.normalized()
                if y1 <= rect.left():
                    y1 = rect.left()
                elif y1 >= rect.right():
                    y1 = rect.right()

                if y2 <= rect.top():
                    y2 = rect.top()
                elif y2 >= rect.bottom():
                    y2 = rect.bottom()

                self.pointPath.lineTo(y1, y2)
                self.drawFreeLine(self.pointPath, False)
                self.redraw()

    def mouseReleaseEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() != Qt.LeftButton:
            return

        if self.mousePressed:
            self.mousePressed = False
            self.endX, self.endY = event.x(), event.y()

            if self.action == ACTION_SELECT:
                self.selectedArea.setBottomRight(QPoint(event.x(), event.y()))
                self.selectedAreaRaw = QRect(self.selectedArea)
                self.action = ACTION_MOVE_SELECTED
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedAreaRaw = QRect(self.selectedArea)
                self.redraw()
                # self.action = None
            elif self.action == ACTION_RECT:
                self.drawRect(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_ELLIPSE:
                self.drawEllipse(self.startX, self.startY, event.x(),
                                 event.y(), True)
                self.redraw()
            elif self.action == ACTION_ARROW:
                self.drawArrow(self.startX, self.startY, event.x(), event.y(),
                               True)
                self.redraw()
            elif self.action == ACTION_LINE:
                self.drawLine(self.startX, self.startY, event.x(), event.y(),
                              True)
                self.redraw()
            elif self.action == ACTION_FREEPEN:
                self.drawFreeLine(self.pointPath, True)
                self.redraw()

    def detectMousePosition(self, point):
        """
        :type point: QPoint
        :param point: the mouse position you want to check
        :return:
        """
        if self.selectedArea == QRect():
            self.mousePosition = MousePosition.OUTSIDE_AREA
            return

        if self.selectedArea.left() - ERRORRANGE <= point.x(
        ) <= self.selectedArea.left() and (self.selectedArea.top() - ERRORRANGE
                                           <= point.y() <=
                                           self.selectedArea.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER
        elif self.selectedArea.right() <= point.x() <= self.selectedArea.right(
        ) + ERRORRANGE and (self.selectedArea.top() - ERRORRANGE <= point.y()
                            <= self.selectedArea.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER
        elif self.selectedArea.left() - ERRORRANGE <= point.x(
        ) <= self.selectedArea.left() and (
                self.selectedArea.bottom() <= point.y() <=
                self.selectedArea.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER
        elif self.selectedArea.right() <= point.x() <= self.selectedArea.right(
        ) + ERRORRANGE and (self.selectedArea.bottom() <= point.y() <=
                            self.selectedArea.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER
        elif -ERRORRANGE <= point.x() - self.selectedArea.left() <= 0 and (
                self.selectedArea.topLeft().y() < point.y() <
                self.selectedArea.bottomLeft().y()):
            self.mousePosition = MousePosition.ON_THE_LEFT_SIDE
        elif 0 <= point.x() - self.selectedArea.right() <= ERRORRANGE and (
                self.selectedArea.topRight().y() < point.y() <
                self.selectedArea.bottomRight().y()):
            self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE
        elif -ERRORRANGE <= point.y() - self.selectedArea.top() <= 0 and (
                self.selectedArea.topLeft().x() < point.x() <
                self.selectedArea.topRight().x()):
            self.mousePosition = MousePosition.ON_THE_UP_SIDE
        elif 0 <= point.y() - self.selectedArea.bottom() <= ERRORRANGE and (
                self.selectedArea.bottomLeft().x() < point.x() <
                self.selectedArea.bottomRight().x()):
            self.mousePosition = MousePosition.ON_THE_DOWN_SIDE
        elif not self.selectedArea.contains(point):
            self.mousePosition = MousePosition.OUTSIDE_AREA
        else:
            self.mousePosition = MousePosition.INSIDE_AREA

    def setCursorStyle(self):
        if self.action in DRAW_ACTION:
            self.setCursor(Qt.CrossCursor)
            return

        if self.mousePosition == MousePosition.ON_THE_LEFT_SIDE or \
                        self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:

            self.setCursor(Qt.SizeHorCursor)
        elif self.mousePosition == MousePosition.ON_THE_UP_SIDE or \
                        self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:

            self.setCursor(Qt.SizeVerCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER or \
                        self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:

            self.setCursor(Qt.SizeFDiagCursor)
        elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER or \
                        self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:

            self.setCursor(Qt.SizeBDiagCursor)
        elif self.mousePosition == MousePosition.OUTSIDE_AREA:
            self.setCursor(Qt.ArrowCursor)
        elif self.mousePosition == MousePosition.INSIDE_AREA:
            self.setCursor(Qt.OpenHandCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
            pass

    def drawMagnifier(self):
        # First, calculate the magnifier position due to the mouse position
        watchAreaWidth = 16
        watchAreaHeight = 16
        watchAreaPixmap = QPixmap()

        cursor_pos = self.mousePoint

        watchArea = QRect(
            QPoint(cursor_pos.x() - watchAreaWidth / 2,
                   cursor_pos.y() - watchAreaHeight / 2),
            QPoint(cursor_pos.x() + watchAreaWidth / 2,
                   cursor_pos.y() + watchAreaHeight / 2))
        if watchArea.left() < 0:
            watchArea.moveLeft(0)
            watchArea.moveRight(watchAreaWidth)
        if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width(
        ):
            watchArea.moveRight(self.screenPixel.width() - 1)
            watchArea.moveLeft(watchArea.right() - watchAreaWidth)
        if self.mousePoint.y() - watchAreaHeight / 2 < 0:
            watchArea.moveTop(0)
            watchArea.moveBottom(watchAreaHeight)
        if self.mousePoint.y(
        ) + watchAreaHeight / 2 >= self.screenPixel.height():
            watchArea.moveBottom(self.screenPixel.height() - 1)
            watchArea.moveTop(watchArea.bottom() - watchAreaHeight)

        # tricks to solve the hidpi impact on QCursor.pos()
        watchArea.setTopLeft(
            QPoint(watchArea.topLeft().x() * self.scale,
                   watchArea.topLeft().y() * self.scale))
        watchArea.setBottomRight(
            QPoint(watchArea.bottomRight().x() * self.scale,
                   watchArea.bottomRight().y() * self.scale))
        watchAreaPixmap = self.screenPixel.copy(watchArea)

        # second, calculate the magnifier area
        magnifierAreaWidth = watchAreaWidth * 10
        magnifierAreaHeight = watchAreaHeight * 10
        fontAreaHeight = 40

        cursorSize = 24
        magnifierArea = QRectF(
            QPoint(QCursor.pos().x() + cursorSize,
                   QCursor.pos().y() + cursorSize),
            QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth,
                   QCursor.pos().y() + cursorSize + magnifierAreaHeight))
        if magnifierArea.right() >= self.screenPixel.width():
            magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth -
                                   cursorSize / 2)
        if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height(
        ):
            magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight -
                                  cursorSize / 2 - fontAreaHeight)

        # third, draw the watch area to magnifier area
        watchAreaScaled = watchAreaPixmap.scaled(
            QSize(magnifierAreaWidth * self.scale,
                  magnifierAreaHeight * self.scale))
        magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled)
        magnifierPixmap.setOffset(magnifierArea.topLeft())

        # then draw lines and text
        self.graphicsScene.addRect(QRectF(magnifierArea),
                                   QPen(QColor(255, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()),
                   QPointF(magnifierArea.center().x(),
                           magnifierArea.bottom())),
            QPen(QColor(0, 255, 255), 2))
        self.graphicsScene.addLine(
            QLineF(QPointF(magnifierArea.left(),
                           magnifierArea.center().y()),
                   QPointF(magnifierArea.right(),
                           magnifierArea.center().y())),
            QPen(QColor(0, 255, 255), 2))

        # get the rgb of mouse point
        pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint))

        # draw information
        self.graphicsScene.addRect(
            QRectF(
                magnifierArea.bottomLeft(),
                magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)),
            Qt.black, QBrush(Qt.black))
        rgbInfo = self.graphicsScene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(),
                                           pointRgb.blue()))
        rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5))
        rgbInfo.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selectedArea.normalized()
        sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) +
                        QPoint(0, fontAreaHeight / 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))

    def get_scale(self):
        return self.devicePixelRatio()

    def saveScreenshot(self,
                       clipboard=False,
                       fileName='screenshot.png',
                       picType='png'):
        fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1)
        selected = QRect(self.selectedArea)
        if selected.left() < 0:
            selected.setLeft(0)
        if selected.right() >= self.width():
            selected.setRight(self.width() - 1)
        if selected.top() < 0:
            selected.setTop(0)
        if selected.bottom() >= self.height():
            selected.setBottom(self.height() - 1)

        source = (fullWindow & selected)
        source.setTopLeft(
            QPoint(source.topLeft().x() * self.scale,
                   source.topLeft().y() * self.scale))
        source.setBottomRight(
            QPoint(source.bottomRight().x() * self.scale,
                   source.bottomRight().y() * self.scale))
        image = self.screenPixel.copy(source)
        image.setDevicePixelRatio(1)

        if clipboard:
            QGuiApplication.clipboard().setImage(QImage(image),
                                                 QClipboard.Clipboard)
        else:
            image.save(fileName, picType, 10)
        self.target_img = image
        self.screen_shot_grabed.emit(QImage(image))

    def redraw(self):
        self.graphicsScene.clear()

        # draw screenshot
        self.graphicsScene.addPixmap(self.screenPixel)

        # prepare for drawing selected area
        rect = QRectF(self.selectedArea)
        rect = rect.normalized()

        topLeftPoint = rect.topLeft()
        topRightPoint = rect.topRight()
        bottomLeftPoint = rect.bottomLeft()
        bottomRightPoint = rect.bottomRight()
        topMiddlePoint = (topLeftPoint + topRightPoint) / 2
        leftMiddlePoint = (topLeftPoint + bottomLeftPoint) / 2
        bottomMiddlePoint = (bottomLeftPoint + bottomRightPoint) / 2
        rightMiddlePoint = (topRightPoint + bottomRightPoint) / 2

        # draw the picture mask
        mask = QColor(0, 0, 0, 155)

        if self.selectedArea == QRect():
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       self.screenPixel.height(),
                                       QPen(Qt.NoPen), mask)
        else:
            self.graphicsScene.addRect(0, 0, self.screenPixel.width(),
                                       topRightPoint.y(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(0, topLeftPoint.y(), topLeftPoint.x(),
                                       rect.height(), QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                topRightPoint.x(), topRightPoint.y(),
                self.screenPixel.width() - topRightPoint.x(), rect.height(),
                QPen(Qt.NoPen), mask)
            self.graphicsScene.addRect(
                0, bottomLeftPoint.y(), self.screenPixel.width(),
                self.screenPixel.height() - bottomLeftPoint.y(),
                QPen(Qt.NoPen), mask)

        # draw the toolBar
        if self.action != ACTION_SELECT:
            spacing = 5
            # show the toolbar first, then move it to the correct position
            # because the width of it may be wrong if this is the first time it shows
            self.tooBar.show()

            dest = QPointF(rect.bottomRight() -
                           QPointF(self.tooBar.width(), 0) -
                           QPointF(spacing, -spacing))
            if dest.x() < spacing:
                dest.setX(spacing)
            pen_set_bar_height = self.penSetBar.height(
            ) if self.penSetBar is not None else 0
            if dest.y() + self.tooBar.height(
            ) + pen_set_bar_height >= self.height():
                if rect.top() - self.tooBar.height(
                ) - pen_set_bar_height < spacing:
                    dest.setY(rect.top() + spacing)
                else:
                    dest.setY(rect.top() - self.tooBar.height() -
                              pen_set_bar_height - spacing)

            self.tooBar.move(dest.toPoint())

            if self.penSetBar is not None:
                self.penSetBar.show()
                self.penSetBar.move(dest.toPoint() +
                                    QPoint(0,
                                           self.tooBar.height() + spacing))

                if self.action == ACTION_TEXT:
                    self.penSetBar.showFontWidget()
                else:
                    self.penSetBar.showPenWidget()
        else:
            self.tooBar.hide()

            if self.penSetBar is not None:
                self.penSetBar.hide()

        # draw the list
        for step in self.drawListResult:
            self.drawOneStep(step)

        if self.drawListProcess is not None:
            self.drawOneStep(self.drawListProcess)
            if self.action != ACTION_TEXT:
                self.drawListProcess = None

        if self.selectedArea != QRect():
            self.itemsToRemove = []

            # draw the selected rectangle
            pen = QPen(QColor(0, 255, 255), 2)
            self.itemsToRemove.append(self.graphicsScene.addRect(rect, pen))

            # draw the drag point
            radius = QPoint(3, 3)
            brush = QBrush(QColor(0, 255, 255))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topLeftPoint - radius, topLeftPoint + radius), pen,
                    brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topMiddlePoint - radius, topMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(topRightPoint - radius, topRightPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(leftMiddlePoint - radius, leftMiddlePoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(rightMiddlePoint - radius,
                           rightMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomLeftPoint - radius, bottomLeftPoint + radius),
                    pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomMiddlePoint - radius,
                           bottomMiddlePoint + radius), pen, brush))
            self.itemsToRemove.append(
                self.graphicsScene.addEllipse(
                    QRectF(bottomRightPoint - radius,
                           bottomRightPoint + radius), pen, brush))

        # draw the textedit
        if self.textPosition is not None:
            textSpacing = 50
            position = QPoint()
            if self.textPosition.x() + self.textInput.width(
            ) >= self.screenPixel.width():
                position.setX(self.textPosition.x() - self.textInput.width())
            else:
                position.setX(self.textPosition.x())

            if self.textRect is not None:
                if self.textPosition.y() + self.textInput.height(
                ) + self.textRect.height() >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height() -
                                  self.textRect.height())
                else:
                    position.setY(self.textPosition.y() +
                                  self.textRect.height())
            else:
                if self.textPosition.y() + self.textInput.height(
                ) >= self.screenPixel.height():
                    position.setY(self.textPosition.y() -
                                  self.textInput.height())
                else:
                    position.setY(self.textPosition.y())

            self.textInput.move(position)
            self.textInput.show()
            # self.textInput.getFocus()

        # draw the magnifier
        if self.action == ACTION_SELECT:
            self.drawMagnifier()
            if self.mousePressed:
                self.drawSizeInfo()

        if self.action == ACTION_MOVE_SELECTED:
            self.drawSizeInfo()

    # deal with every step in drawList
    def drawOneStep(self, step):
        """
        :type step: tuple
        """
        if step[0] == ACTION_RECT:
            self.graphicsScene.addRect(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ELLIPSE:
            self.graphicsScene.addEllipse(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ARROW:
            arrow = QPolygonF()

            linex = float(step[1] - step[3])
            liney = float(step[2] - step[4])
            line = sqrt(pow(linex, 2) + pow(liney, 2))

            # in case to divided by 0
            if line == 0:
                return

            sinAngel = liney / line
            cosAngel = linex / line

            # sideLength is the length of bottom side of the body of an arrow
            # arrowSize is the size of the head of an arrow, left and right
            # sides' size is arrowSize, and the bottom side's size is arrowSize / 2
            sideLength = step[5].width()
            arrowSize = 8
            bottomSize = arrowSize / 2

            tmpPoint = QPointF(step[3] + arrowSize * sideLength * cosAngel,
                               step[4] + arrowSize * sideLength * sinAngel)

            point1 = QPointF(step[1] + sideLength * sinAngel,
                             step[2] - sideLength * cosAngel)
            point2 = QPointF(step[1] - sideLength * sinAngel,
                             step[2] + sideLength * cosAngel)
            point3 = QPointF(tmpPoint.x() - sideLength * sinAngel,
                             tmpPoint.y() + sideLength * cosAngel)
            point4 = QPointF(tmpPoint.x() - bottomSize * sideLength * sinAngel,
                             tmpPoint.y() + bottomSize * sideLength * cosAngel)
            point5 = QPointF(step[3], step[4])
            point6 = QPointF(tmpPoint.x() + bottomSize * sideLength * sinAngel,
                             tmpPoint.y() - bottomSize * sideLength * cosAngel)
            point7 = QPointF(tmpPoint.x() + sideLength * sinAngel,
                             tmpPoint.y() - sideLength * cosAngel)

            arrow.append(point1)
            arrow.append(point2)
            arrow.append(point3)
            arrow.append(point4)
            arrow.append(point5)
            arrow.append(point6)
            arrow.append(point7)
            arrow.append(point1)

            self.graphicsScene.addPolygon(arrow, step[5], step[6])
        elif step[0] == ACTION_LINE:
            self.graphicsScene.addLine(
                QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_FREEPEN:
            self.graphicsScene.addPath(step[1], step[2])
        elif step[0] == ACTION_TEXT:
            textAdd = self.graphicsScene.addSimpleText(step[1], step[2])
            textAdd.setPos(step[3])
            textAdd.setBrush(QBrush(step[4]))
            self.textRect = textAdd.boundingRect()

    # draw the size information on the top left corner
    def drawSizeInfo(self):
        sizeInfoAreaWidth = 200
        sizeInfoAreaHeight = 30
        spacing = 5
        rect = self.selectedArea.normalized()
        sizeInfoArea = QRect(rect.left(),
                             rect.top() - spacing - sizeInfoAreaHeight,
                             sizeInfoAreaWidth, sizeInfoAreaHeight)

        if sizeInfoArea.top() < 0:
            sizeInfoArea.moveTopLeft(rect.topLeft() + QPoint(spacing, spacing))
        if sizeInfoArea.right() >= self.screenPixel.width():
            sizeInfoArea.moveTopLeft(rect.topLeft() -
                                     QPoint(spacing, spacing) -
                                     QPoint(sizeInfoAreaWidth, 0))
        if sizeInfoArea.left() < spacing:
            sizeInfoArea.moveLeft(spacing)
        if sizeInfoArea.top() < spacing:
            sizeInfoArea.moveTop(spacing)

        self.itemsToRemove.append(
            self.graphicsScene.addRect(QRectF(sizeInfoArea), Qt.white,
                                       QBrush(Qt.black)))

        sizeInfo = self.graphicsScene.addSimpleText('  {0} x {1}'.format(
            rect.width() * self.scale,
            rect.height() * self.scale))
        sizeInfo.setPos(sizeInfoArea.topLeft() + QPoint(0, 2))
        sizeInfo.setPen(QPen(QColor(255, 255, 255), 2))
        self.itemsToRemove.append(sizeInfo)

    def drawRect(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_RECT,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawEllipse(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized()
        resultRect = rect & tmpRect
        tmp = [
            ACTION_ELLIPSE,
            resultRect.topLeft().x(),
            resultRect.topLeft().y(),
            resultRect.bottomRight().x(),
            resultRect.bottomRight().y(),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawArrow(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_ARROW, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow)),
            QBrush(QColor(self.penColorNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawLine(self, x1, x2, y1, y2, result):
        rect = self.selectedArea.normalized()
        if y1 <= rect.left():
            y1 = rect.left()
        elif y1 >= rect.right():
            y1 = rect.right()

        if y2 <= rect.top():
            y2 = rect.top()
        elif y2 >= rect.bottom():
            y2 = rect.bottom()

        tmp = [
            ACTION_LINE, x1, x2, y1, y2,
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def drawFreeLine(self, pointPath, result):
        tmp = [
            ACTION_FREEPEN,
            QPainterPath(pointPath),
            QPen(QColor(self.penColorNow), int(self.penSizeNow))
        ]
        if result:
            self.drawListResult.append(tmp)
        else:
            self.drawListProcess = tmp

    def textChange(self):
        if self.textPosition is None:
            return
        self.text = self.textInput.getText()
        self.drawListProcess = [
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ]
        self.redraw()

    def undoOperation(self):
        if len(self.drawListResult) == 0:
            self.action = ACTION_SELECT
            self.selectedArea = QRect()
            self.selectedAreaRaw = QRect()
            self.tooBar.hide()
            if self.penSetBar is not None:
                self.penSetBar.hide()
        else:
            self.drawListResult.pop()
        self.redraw()

    def saveOperation(self):
        filename = QFileDialog.getSaveFileName(self, 'Save file',
                                               './screenshot.png',
                                               '*.png;;*.jpg')
        if len(filename[0]) == 0:
            return
        else:
            self.saveScreenshot(False, filename[0], filename[1][2:])
            self.close()

    def close(self):
        self.widget_closed.emit()
        super().close()
        self.tooBar.close()
        if self.penSetBar is not None:
            self.penSetBar.close()

    def saveToClipboard(self):
        QApplication.clipboard().setText('Test in save function')

        self.saveScreenshot(True)
        self.close()

    # slots
    def changeAction(self, nextAction):
        QApplication.clipboard().setText('Test in changeAction function')

        if nextAction == ACTION_UNDO:
            self.undoOperation()
        elif nextAction == ACTION_SAVE:
            self.saveOperation()
        elif nextAction == ACTION_CANCEL:
            self.close()
        elif nextAction == ACTION_SURE:
            self.saveToClipboard()

        else:
            self.action = nextAction

        self.setFocus()

    def changePenSize(self, nextPenSize):
        self.penSizeNow = nextPenSize

    def changePenColor(self, nextPenColor):
        self.penColorNow = nextPenColor

    def cancelInput(self):
        self.drawListProcess = None
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def okInput(self):
        self.text = self.textInput.getText()
        self.drawListResult.append([
            ACTION_TEXT,
            str(self.text),
            QFont(self.fontNow),
            QPoint(self.textPosition),
            QColor(self.penColorNow)
        ])
        self.textPosition = None
        self.textRect = None
        self.textInput.hide()
        self.textInput.clearText()
        self.redraw()

    def changeFont(self, font):
        self.fontNow = font
Ejemplo n.º 5
0
class MonitorGraphicsView(QGraphicsView, AllowDrop):
    monitorWin = None

    SIZE = (50.0, 50.0)
    FULLSPEED = 512 * 1024 # 512 in kb/s

    _progressText = None
    _speedsPolygon = None
    _speedsPen = None
    _speedsBrush = None

    def __init__(self, parent = None):
        super().__init__(parent)
        self.monitorWin = parent
        if self.monitorWin:
            self.monitorWin.sigTaskUpdating.connect(self.slotTaskUpdate)

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, self.SIZE[0], self.SIZE[1])
        self.setScene(self.scene)

        self._speedsPen = QPen(Qt.white)

        gradient = QLinearGradient(0, 0, self.SIZE[0], self.SIZE[1])
        gradient.setColorAt(0.0, Qt.darkGreen)
        gradient.setColorAt(1.0, Qt.yellow)
        self._speedsBrush = QBrush(gradient)

        # add elements to the scene
        self._speedsPolygon = self.scene.addPolygon(QPolygonF(),
                                                    self._speedsPen,
                                                    self._speedsBrush)
        self._progressText = self.scene.addText("")
        self._progressText.setPos(10, 0)

        self.setupDropSupport()

    def mousePressEvent(self, qMouseEvent):
        self.monitorWin.mousePressEvent(qMouseEvent)

    def mouseMoveEvent(self, qMouseEvent):
        self.monitorWin.mouseMoveEvent(qMouseEvent)

    def mouseReleaseEvent(self, qMouseEvent):
        self.monitorWin.mouseReleaseEvent(qMouseEvent)

    def _setSpeeds(self, speeds):
        polygon = QPolygonF()
        polygon.append(QPointF(0, self.SIZE[1])) # start the polygon

        nSamples = len(speeds)
        xPerSample = self.SIZE[0] / nSamples

        for i, speed in enumerate(speeds):
            y = self._translateSpeedToPosY(speed)
            polygon.append(QPointF(xPerSample * i, y))
            polygon.append(QPointF(xPerSample * (i+1), y))
        polygon.append(QPointF(*self.SIZE)) # close the polygon

        self._speedsPolygon.setPolygon(polygon)

    def _setProgress(self, process): # 10000 means 100%
        if process is None:
            self._progressText.setPlainText("")
        else:
            self._progressText.setPlainText("{:.1f}%".format(process / 100))

    def _translateSpeedToPosY(self, speed):
        return self.SIZE[1] * (1.0 - speed / self.FULLSPEED)

    @pyqtSlot(dict)
    def slotTaskUpdate(self, task):
        if task:
            self._setProgress(task["progress"])
            self._setSpeeds(task["speeds"])
        else:
            self._setProgress(None)
            self._setSpeeds([0.0])
Ejemplo n.º 6
0
 def paint(self, scene: QtWidgets.QGraphicsScene):
     poly = QtGui.QPolygonF(self.points)
     scene.addPolygon(poly, self.color, self.inner_color)
Ejemplo n.º 7
0
class TableViewWidget(QGraphicsView):
    g_table_view = None
    g_detect_size = 200
    g_detect_text = "position"
    #g_detect_text = "quality"
    #g_detect_text = "none"
    g_rplidar_remanence = False
    g_rplidar_plot_life_ms = 1000


    def __init__(self, parent = None, ihm_type='pc'):
        super(TableViewWidget, self).__init__(parent)
        if ihm_type=='pc':
            #self.setFixedSize(900,600)
            self.setFixedSize(960,660)
        elif ihm_type=='pc-mini':
            #self.setFixedSize(600,400)
            self.setFixedSize(640,440)
        else:
            #self.setFixedSize(225,150)
            self.setFixedSize(240,165)
        #self.setSceneRect(QRectF(0,-1500,2000,3000))
        self.setSceneRect(QRectF(-100,-1600,2200,3200))
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        
        self._robots = {}
        self._waypoints = []

        redium = QColor.fromCmykF(0,1,1,0.1)
        greenium = QColor.fromCmykF(0.7,0,0.9,0)
        blueium = QColor.fromCmykF(0.9,0.4,0,0)
        goldenium = QColor('white')
        yellow = QColor.fromCmykF(0,0.25,1,0)
        purple = QColor.fromCmykF(0.5,0.9,0,0.05)
        background = QColor(40,40,40)
        darker = QColor(20,20,20)

#        big_robot_poly = QPolygonF([
#            QPointF(-135,-151),
#            QPointF(60,-151),
#            QPointF(170,-91),
#            QPointF(170,-45),
#            QPointF(111,-40),
#            QPointF(111,40),
#            QPointF(170,45),
#            QPointF(170,91),
#            QPointF(60,151),
#            QPointF(-135,151)
#            ])

        little_robot_poly = QPolygonF([
            QPointF(  50,   0),
            QPointF( 100,  85),
            QPointF(  65, 115),
            QPointF( -65, 115),
            QPointF(-100,  85),
            QPointF(-100, -85),
            QPointF( -65,-115),
            QPointF(  65,-115),
            QPointF( 100, -85)
            ])

        #self._scene = QGraphicsScene(QRectF(0,-1500,2000,3000))
        self._scene = QGraphicsScene(QRectF(-100,-1600,2200,3200))

#        self._big_robot = self._scene.addPolygon(big_robot_poly, QPen(), QBrush(QColor('red')))
#        self._big_robot.setZValue(1)
        #self._robots['little'] = Robot(self._scene)
        self._little_robot = self._scene.addPolygon(little_robot_poly, QPen(), QBrush(QColor('red')))
        self._little_robot.setZValue(1)
        #self._friend_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('green')))
        self._friend_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white')))
        self._friend_robot.setZValue(1)
        self._friend_robot.setPos(-1 * 1000, -1 * 1000)
        if os.name == 'nt':
            self._friend_robot_text = self._scene.addText("0123456", QFont("Calibri",80));
        else:
            self._friend_robot_text = self._scene.addText("0123456", QFont("System",40));
        self._friend_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40)
        self._friend_robot_text.setRotation(-90)
        self._friend_robot_text.setTransform(QTransform(1.0, 0.0, 0.0,  0.0, -1.0, 0.0,   0.0, 0.0, 1.0))
        self._friend_robot_text.setZValue(1)
        #self._adv1_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('white')))
        self._adv1_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white')))
        self._adv1_robot.setZValue(1)
        self._adv1_robot.setPos(-1 * 1000, -1 * 1000)
        if os.name == 'nt':
            self._adv1_robot_text = self._scene.addText("0", QFont("Calibri",80));
        else:
            self._adv1_robot_text = self._scene.addText("0", QFont("System",40));
        self._adv1_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40)
        self._adv1_robot_text.setRotation(-90)
        self._adv1_robot_text.setTransform(QTransform(1.0, 0.0, 0.0,  0.0, -1.0, 0.0,   0.0, 0.0, 1.0))
        self._adv1_robot_text.setZValue(1)
        #self._adv2_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('blue')))
        self._adv2_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white')))
        self._adv2_robot.setZValue(1)
        self._adv2_robot.setPos(-1 * 1000, -1 * 1000)
        if os.name == 'nt':
            self._adv2_robot_text = self._scene.addText("0", QFont("Calibri",80));
        else:
            self._adv2_robot_text = self._scene.addText("0", QFont("System",40));
        self._adv2_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40)
        self._adv2_robot_text.setRotation(-90)
        self._adv2_robot_text.setTransform(QTransform(1.0, 0.0, 0.0,  0.0, -1.0, 0.0,   0.0, 0.0, 1.0))
        self._adv2_robot_text.setZValue(1)
        self.setScene(self._scene)

        self.rotate(90)
        if ihm_type=='pc':
            self.scale(0.3, -0.3)
        elif ihm_type=='pc-mini':
            self.scale(0.2, -0.2)
        else:
            self.scale(0.075, -0.075)

        #self._scene.addRect(QRectF(0,-1500,2000,3000),QPen(), QBrush(background))

        f=open("widgets/table_2020_600x400.png","rb")
        my_buff=f.read()
        test_img_pixmap2 = QPixmap()
        test_img_pixmap2.loadFromData(my_buff)
        #self.setPixmap(test_img_pixmap2)
        self._bg_img = QGraphicsPixmapItem(test_img_pixmap2)
        self._bg_img.setTransform(QTransform(1.0, 0.0, 0.0,  0.0, -1.0, 0.0,   0.0, 0.0, 0.2))
        self._bg_img.setRotation(-90)
        self._bg_img.setPos(0, -1500)
        self._scene.addItem(self._bg_img);

        # Scenario 2020

        #Port principal "bleu"
        self._scene.addRect(QRectF(500,-1120,570,20),QPen(), QBrush(blueium))
        self._scene.addRect(QRectF(500,-1500,30,400),QPen(), QBrush(greenium))
        self._scene.addRect(QRectF(1070,-1500,30,400),QPen(), QBrush(redium))

        #Port secondaire "bleu"
        self._scene.addRect(QRectF(1700,150,20,300),QPen(), QBrush(blueium))
        self._scene.addRect(QRectF(1700,150,300,100),QPen(), QBrush(greenium))
        self._scene.addRect(QRectF(1700,350,300,100),QPen(), QBrush(redium))

        #Bouees cote "bleu"
        self._scene.addEllipse(QRectF(1200-35,-1200-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(1080-35,-1050-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(510-35,-1050-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(400-35,-1200-35,70,70),QPen(), QBrush(redium))

        self._scene.addEllipse(QRectF(100-35,-830-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(400-35,-550-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(800-35,-400-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(1200-35,-230-35,70,70),QPen(), QBrush(greenium))

        self._scene.addEllipse(QRectF(1650-35,-435-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(1650-35,-165-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(1955-35,-495-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(1955-35,-105-35,70,70),QPen(), QBrush(greenium))

        #Port principal "jaune"
        self._scene.addRect(QRectF(500,1100,570,20),QPen(), QBrush(yellow))
        self._scene.addRect(QRectF(500,1100,30,400),QPen(), QBrush(redium))
        self._scene.addRect(QRectF(1070,1100,30,400),QPen(), QBrush(greenium))

        #Port secondaire "jaune"
        self._scene.addRect(QRectF(1700,-450,20,300),QPen(), QBrush(yellow))
        self._scene.addRect(QRectF(1700,-450,300,100),QPen(), QBrush(greenium))
        self._scene.addRect(QRectF(1700,-250,300,100),QPen(), QBrush(redium))

        #Bouees cote "jaune"
        self._scene.addEllipse(QRectF(1200-35,1200-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(1080-35,1050-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(510-35,1050-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(400-35,1200-35,70,70),QPen(), QBrush(greenium))

        self._scene.addEllipse(QRectF(100-35,830-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(400-35,550-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(800-35,400-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(1200-35,230-35,70,70),QPen(), QBrush(redium))

        self._scene.addEllipse(QRectF(1650-35,435-35,70,70),QPen(), QBrush(redium))
        self._scene.addEllipse(QRectF(1650-35,165-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(1955-35,495-35,70,70),QPen(), QBrush(greenium))
        self._scene.addEllipse(QRectF(1955-35,105-35,70,70),QPen(), QBrush(redium))

        #dbg_plt_sz = 3
        #self._scene.addEllipse(1000 - dbg_plt_sz, 0 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white')))

        self._points = []
        #self.setSceneRect(QRectF(0,-150,200,300))

        self._traj_segm_l = []

        self._debug_edit_mode = False
        self._debug_edit_point_l = []

#        self._big_robot_x = 0
#        self._big_robot_y = 0
        self._little_robot_x = 0
        self._little_robot_y = 0

        self.last_plot_ts = 0
        self.plot_graph_l = []
        
        self._plot_items = []

        TableViewWidget.g_table_view = self
        
    def set_strategy(self, strategy):
        greenium = QColor.fromCmykF(0.7,0,0.9,0)
        #greenium.setAlphaF(0.2)
        for id_, pos in strategy['strategy']['map']['waypoints'].items():
            wp = self._scene.addEllipse(QRectF(pos[0]-10,pos[1]-10,20,20),QPen(), QBrush(greenium))
            self._waypoints.append(wp)
        for id_, pose in strategy['strategy']['map']['poses'].items():
            p = strategy['strategy']['map']['waypoints'][pose[0]]
            path = QPainterPath()
            cos_ = math.cos(pose[1] * math.pi / 180)
            sin_ = math.sin(pose[1] * math.pi / 180)
            l = 40
            w = 20
            path.moveTo(p[0] + l * cos_, p[1] + l * sin_)
            path.lineTo(p[0] -l * cos_ + w * sin_, p[1] - l * sin_ - w * cos_)
            path.lineTo(p[0] -l * cos_ - w * sin_, p[1] - l * sin_ + w * cos_)
            path.closeSubpath()
            itm = self._scene.addPath(path, QPen(), QBrush(greenium))
            
        for id_, area in strategy['strategy']['map']['areas'].items():
            path = QPainterPath()
            v = area['vertices'][0]
            path.moveTo(v[0], v[1])
            for v in area['vertices'][1:]: 
                path.lineTo(v[0], v[1])
            path.closeSubpath()
            itm = self._scene.addPath(path, QPen(), QBrush(greenium))
            self._waypoints.append(wp)


    def add_points(self, points):
        for p in points:
            pt = self._scene.addEllipse(p[0]-10, p[1]-10, 20, 20,  QPen(), QBrush(QColor('grey')))
            pt.setZValue(1)
            self._points.append((pt, p))

    def sizeHint(self):
        return QSize(600,400)

    def set_client(self, client):
        self._client = client
        self._client.propulsion_telemetry.connect(self.update_telemetry)
        self._client.rplidar_plot.connect(self.update_plots)
        self._client.rplidar_robot_detection.connect(self.update_other_robots)
        
    def update_telemetry(self, telemetry):
#        self._big_robot.setPos(telemetry.x * 1000, telemetry.y * 1000)
#        self._big_robot.setRotation(telemetry.yaw * 180 / math.pi)
#        self._big_robot_x = telemetry.x * 1000
#        self._big_robot_y = telemetry.y * 1000
        self._little_robot.setPos(telemetry.pose.position.x * 1000, telemetry.pose.position.y * 1000)
        self._little_robot.setRotation(telemetry.pose.yaw * 180 / math.pi)
        self._little_robot_x = telemetry.pose.position.x * 1000
        self._little_robot_y = telemetry.pose.position.y * 1000

    def update_plots(self, my_plot):
        dbg_plt_sz = 1
        for i in self._plot_items:
            self._scene.removeItem(i)
        self._plot_items = []
            
        #self.last_plot_ts = my_plot.timestamp
        for pt in my_plot.points:
            itm = self._scene.addEllipse(pt.x * 1000 - dbg_plt_sz, pt.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('red')),4), QBrush(QColor('red')))
            self._plot_items.append(itm)
        return
        my_plot_ellipse = self._scene.addEllipse(my_plot.x * 1000 - dbg_plt_sz, my_plot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('red')),4), QBrush(QColor('red')))
        self.plot_graph_l.append((my_plot,my_plot_ellipse))
        for rec in self.plot_graph_l:
            if (self.last_plot_ts-rec[0].timestamp>TableViewWidget.g_rplidar_plot_life_ms):
                rec_ellipse = rec[1]
                self._scene.removeItem(rec_ellipse)
                self.plot_graph_l.remove(rec)

    def update_other_robots(self, other_robot):
        dbg_plt_sz = 3
        if (other_robot.id == 0):
            self._friend_robot.setPos(other_robot.x * 1000, other_robot.y * 1000)
            if (TableViewWidget.g_detect_text == "quality"):
                self._friend_robot_text.setPlainText("%d"%other_robot.samples)
            elif (TableViewWidget.g_detect_text == "position"):
                self._friend_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000))
            else:
                self._friend_robot_text.setPlainText("")
            self._friend_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40)
            if TableViewWidget.g_rplidar_remanence:
                self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white')))
        elif (other_robot.id == 1):
            self._adv1_robot.setPos(other_robot.x * 1000, other_robot.y * 1000)
            if (TableViewWidget.g_detect_text == "quality"):
                self._adv1_robot_text.setPlainText("%d"%other_robot.samples)
            elif (TableViewWidget.g_detect_text == "position"):
                self._adv1_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000))
            else:
                self._adv1_robot_text.setPlainText("")
            self._adv1_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40)
            if TableViewWidget.g_rplidar_remanence:
                self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white')))
        elif (other_robot.id == 2):
            self._adv2_robot.setPos(other_robot.x * 1000, other_robot.y * 1000)
            if (TableViewWidget.g_detect_text == "quality"):
                self._adv2_robot_text.setPlainText("%d"%other_robot.samples)
            elif (TableViewWidget.g_detect_text == "position"):
                self._adv2_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000))
            else:
                self._adv2_robot_text.setPlainText("")
            self._adv2_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40)
            if TableViewWidget.g_rplidar_remanence:
                self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white')))

    def debug_set_start(self, _new_x, _new_y):
        self.debug_start_x = _new_x
        self.debug_start_y = _new_y
        self.debug_cur_x = _new_x
        self.debug_cur_y = _new_y
        if self._debug_edit_mode:
            self._debug_edit_point_l.append((_new_x,_new_y))

    def debug_line_to(self, _new_x, _new_y):
        my_segm = self._scene.addLine(self.debug_cur_x, self.debug_cur_y, _new_x, _new_y, QPen(QColor(255,255,255)));
        self._traj_segm_l.append(my_segm)
        self.debug_cur_x = _new_x
        self.debug_cur_y = _new_y

    def debug_clear_lines(self):
        for l in self._traj_segm_l:
            self._scene.removeItem(l)
        self._traj_segm_l = []

    def debug_start_edit(self, _new_x, _new_y):
        self.debug_clear_lines()
        self._debug_edit_mode = True
        self.debug_start_x = _new_x
        self.debug_start_y = _new_y
        self.debug_cur_x = _new_x
        self.debug_cur_y = _new_y
        self._debug_edit_point_l = [(_new_x,_new_y)]

    def debug_start_edit_rel(self):
        self.debug_clear_lines()
        self._debug_edit_mode = True
        self.debug_start_x = self._little_robot_x
        self.debug_start_y = self._little_robot_y
        self.debug_cur_x = self._little_robot_x
        self.debug_cur_y = self._little_robot_y
        self._debug_edit_point_l = [(self._little_robot_x,self._little_robot_y)]

    def debug_stop_edit(self):
        self._debug_edit_mode = False
        return self._debug_edit_point_l

    def mousePressEvent(self, event):
        print ("pix:<{},{}>".format(event.x(),event.y()))
        #realY = 3000.0*(event.x()-450.0)/900.0
        #realX = 2000.0*(event.y())/600.0
        realY = 3200.0*(event.x()-480.0)/960.0
        realX = 2200.0*(event.y()-30.0)/660.0
        print ("real:<{},{}>".format(realX,realY))
        if self._debug_edit_mode:
            self._debug_edit_point_l.append((realX,realY))
            self.debug_line_to(realX, realY)
Ejemplo n.º 8
0
class Viewer(QGraphicsView):
    def __init__(self):
        QGraphicsView.__init__(self)

        self.setGeometry(QRect(100, 100, 800, 600))
        self.setWindowTitle("PIHDL Graphics Window")

        # Create a QGraphicsScene which this view looks at
        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(QRectF())
        self.setScene(self.scene)

        # Customize QGraphicsView
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setInteractive(False)
        self.scale(1, -1)  # Flips around the Y axis
        # Use OpenGL http://ralsina.me/stories/BBS53.html
        #        self.setViewport(QtOpenGL.QGLWidget())
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.pen = QPen(QtCore.Qt.black, 0)
        self.portpen = QPen(PORT_COLOR, 3)
        self.portpen.setCosmetic(True)  # Makes constant width
        self.portfont = QtGui.QFont('Arial', pointSize=14)
        self.portfontcolor = PORT_COLOR
        self.subportpen = QPen(SUBPORT_COLOR, 3)
        self.subportpen.setCosmetic(True)  # Makes constant width
        self.subportfont = QtGui.QFont('Arial', pointSize=14)
        self.subportfontcolor = SUBPORT_COLOR

        # Tracking ports

        # Various status variables
        self._mousePressed = None
        self._rb_origin = QPoint()
        self.zoom_factor_total = 1

        # Grid variables
        self.gridpen = QPen(QtCore.Qt.black, 0)
        self.gridpen.setStyle(QtCore.Qt.DotLine)
        self.gridpen.setDashPattern([1, 4])
        self.gridpen.setColor(QtGui.QColor(0, 0, 0, 125))
        #        self.gridpen = QPen(QtCore.Qt.black, 1)
        #        self.gridpen.setCosmetic(True) # Makes constant width
        #        self.gridlinesx = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)]
        #        self.gridlinesy = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)]

        self.initialize()

    def itemsBoundingRect_nogrid(self):
        self.remove_grid()
        r = self.scene.itemsBoundingRect()
        self.create_grid()
        return r

    def add_polygons(self, polygons, color='#A8F22A', alpha=1):
        qcolor = QColor()
        qcolor.setNamedColor(color)
        qcolor.setAlphaF(alpha)
        for points in polygons:
            qpoly = QPolygonF([QPointF(p[0], p[1]) for p in points])
            scene_poly = self.scene.addPolygon(qpoly)
            scene_poly.setBrush(qcolor)
            scene_poly.setPen(self.pen)

        sr = self.itemsBoundingRect_nogrid()
        ymax = sr.top()
        xmin = sr.left()
        width = sr.width()
        height = sr.height()
        self.scene.setSceneRect(
            QRectF(xmin - 2 * width, ymax - 2 * height, width * 5, height * 5))

    def reset_view(self):
        self.fitInView(self.itemsBoundingRect_nogrid(), Qt.KeepAspectRatio)
        self.update_grid()

    def add_port(self, port, is_subport=False):
        if (port.width is None) or (port.width == 0):
            x, y = port.midpoint
            cs = 1  # cross size
            pn = QPointF(x, y + cs)
            ps = QPointF(x, y - cs)
            pe = QPointF(x + cs, y)
            pw = QPointF(x - cs, y)
            qline1 = self.scene.addLine(QLineF(pn, ps))
            qline2 = self.scene.addLine(QLineF(pw, pe))
            port_shapes = [qline1, qline2]
        else:
            point1, point2 = port.endpoints
            point1 = QPointF(point1[0], point1[1])
            point2 = QPointF(point2[0], point2[1])
            qline = self.scene.addLine(QLineF(point1, point2))
            arrow_points = np.array([[0, 0], [10, 0], [6, 4], [6, 2], [0, 2]
                                     ]) / (40) * port.width
            arrow_qpoly = QPolygonF(
                [QPointF(p[0], p[1]) for p in arrow_points])
            port_scene_poly = self.scene.addPolygon(arrow_qpoly)
            port_scene_poly.setRotation(port.orientation)
            port_scene_poly.moveBy(port.midpoint[0], port.midpoint[1])
            port_shapes = [qline, port_scene_poly]
        qtext = self.scene.addText(str(port.name), self.portfont)
        port_items = port_shapes + [qtext]
        rad = port.orientation * np.pi / 180
        x, y = port.endpoints[0] * 1 / 4 + port.endpoints[
            1] * 3 / 4 + np.array([np.cos(rad), np.sin(rad)]) * port.width / 8
        #        x,y = port.midpoint[0], port.midpoint[1]
        #        x,y  = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2
        qtext.setPos(QPointF(x, y))
        qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)

        if not is_subport:
            [shape.setPen(self.portpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.portfontcolor)
            self.portitems += port_items
        else:
            [shape.setPen(self.subportpen) for shape in port_shapes]
            qtext.setDefaultTextColor(self.subportfontcolor)
            self.subportitems += port_items
#        self.portlabels.append(qtext)

    def add_aliases(self, aliases):
        for name, ref in aliases.items():
            qtext = self.scene.addText(str(name), self.portfont)
            x, y = ref.center
            qtext.setPos(QPointF(x, y))
            qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations)
            self.aliasitems += [qtext]

#        x,y = port.midpoint[0], port.midpoint[1]
#        x,y  = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2

    def set_port_visibility(self, visible=True):
        for item in self.portitems:
            item.setVisible(visible)
        self.ports_visible = visible

    def set_subport_visibility(self, visible=True):
        for item in self.subportitems:
            item.setVisible(visible)
        self.subports_visible = visible

    def set_alias_visibility(self, visible=True):
        for item in self.aliasitems:
            item.setVisible(visible)
        self.aliases_visible = visible

    def initialize(self):
        self.scene.clear()
        self.polygons = {}
        self.portitems = []
        self.subportitems = []
        self.aliasitems = []
        self.aliases_visible = True
        self.ports_visible = True
        self.subports_visible = True

        self.create_grid()
        self.update_grid()

#==============================================================================
#   Grid creation
#==============================================================================

    def update_grid(self):
        grid_pixels = 50
        grid_snaps = [1, 2, 4]

        # Number of pixels in the viewer
        view_width, view_height = self.rect().width(), self.rect().height()
        # Rectangle of viewport in terms of scene coordinates
        r = self.mapToScene(self.rect()).boundingRect()
        width, height = r.width(), r.height()
        xmin, ymin, xmax, ymax = r.x(), r.y(), r.x() + width, r.y() + height

        grid_size = grid_pixels * (width / view_width)
        exponent = np.floor(np.log10(grid_size))
        digits = round(grid_size / 10**(exponent), 2)
        digits_snapped = min(grid_snaps, key=lambda x: abs(x - digits))
        grid_size_snapped = digits_snapped * 10**(exponent)

        # Starting coordinates for gridlines
        x = round((xmin - 2 * width) / grid_size_snapped) * grid_size_snapped
        y = round((ymin - 2 * height) / grid_size_snapped) * grid_size_snapped
        #        print('\n xmin = %s, xmax = %s, ymin = %s, ymax = %s' % (xmin, xmax, ymin, ymax))
        #        print('Starting at x = %s' % x)
        #        print('Starting at y = %s' % y)
        for gl in self.gridlinesx:
            gl.setLine(x, -1e10, x, 1e10)
            x += grid_size_snapped
        for gl in self.gridlinesy:
            gl.setLine(-1e10, y, 1e10, y)
            y += grid_size_snapped

    def create_grid(self):
        self.gridlinesx = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(200)
        ]
        self.gridlinesy = [
            self.scene.addLine(-10, -10, 10, 10, self.gridpen)
            for n in range(200)
        ]
        self.update_grid()

    def remove_grid(self):
        for gl in self.gridlinesx + self.gridlinesy:
            self.scene.removeItem(gl)
        self.gridlinesx == []
        self.gridlinesy == []

#==============================================================================
#  Mousewheel zoom, taken from http://stackoverflow.com/a/29026916
#==============================================================================

    def wheelEvent(self, event):
        # Zoom Factor
        zoom_percentage = 1.4

        # Set Anchors
        self.setTransformationAnchor(QGraphicsView.NoAnchor)
        self.setResizeAnchor(QGraphicsView.NoAnchor)

        # Save the scene pos
        oldPos = self.mapToScene(event.pos())

        # Zoom
        mousewheel_rotation = event.angleDelta().y(
        )  # Typically = 120 on most mousewheels
        zoom_factor = zoom_percentage**(mousewheel_rotation / 120)
        zoom_factor = np.clip(zoom_factor, 0.5, 2.0)

        # Check to make sure we're not overzoomed
        actual_rect = self.mapToScene(self.rect())
        bbox_size = actual_rect[0] - actual_rect[2]
        actual_width = abs(bbox_size.x())
        actual_height = abs(bbox_size.y())
        max_width = abs(self.scene.sceneRect().x() * 3)
        max_height = abs(self.scene.sceneRect().y() * 3)
        min_width = 1
        min_height = 1
        if ((actual_width > max_width) or
            (actual_height > max_height)) and (zoom_factor < 1):
            pass
        elif ((actual_width < min_width) or
              (actual_height < min_height)) and (zoom_factor > 1):
            pass
        else:
            self.zoom_view(zoom_factor)

        # Get the new position and move scene to old position
        newPos = self.mapToScene(event.pos())
        delta = newPos - oldPos
        self.translate(delta.x(), delta.y())

        self.update_grid()

    def zoom_view(self, zoom_factor):
        self.scale(zoom_factor, zoom_factor)
        self.zoom_factor_total *= zoom_factor

    def mousePressEvent(self, event):
        #==============================================================================
        #  Zoom to rectangle, from
        #  https://wiki.python.org/moin/PyQt/Selecting%20a%20region%20of%20a%20widget
        #==============================================================================
        if event.button() == Qt.RightButton:
            self._mousePressed = Qt.RightButton
            self._rb_origin = QPoint(event.pos())
            self.rubberBand.setGeometry(QRect(self._rb_origin, QSize()))
            self.rubberBand.show()
        #==============================================================================
        # Mouse panning, taken from
        # http://stackoverflow.com/a/15043279
        #==============================================================================
        elif event.button() == Qt.MidButton:
            self._mousePressed = Qt.MidButton
            self._mousePressedPos = event.pos()
            self.setCursor(QtCore.Qt.ClosedHandCursor)
            self._dragPos = event.pos()

    def mouseMoveEvent(self, event):
        if not self._rb_origin.isNull(
        ) and self._mousePressed == Qt.RightButton:
            self.rubberBand.setGeometry(
                QRect(self._rb_origin, event.pos()).normalized())

        if self._mousePressed == Qt.MidButton:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() - diff.y())


#            event.accept()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.RightButton:
            self.rubberBand.hide()
            rb_rect = QRect(self._rb_origin, event.pos())
            rb_center = rb_rect.center()
            rb_size = rb_rect.size()

            if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3:
                viewport_size = self.viewport().geometry().size()

                zoom_factor_x = abs(viewport_size.width() / rb_size.width())
                zoom_factor_y = abs(viewport_size.height() / rb_size.height())

                new_center = self.mapToScene(rb_center)

                zoom_factor = min(zoom_factor_x, zoom_factor_y)
                self.zoom_view(zoom_factor)
                self.centerOn(new_center)

            self.update_grid()

        if event.button() == Qt.MidButton:
            self.setCursor(Qt.ArrowCursor)
            self._mousePressed = None
            self.update_grid()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.reset_view()

        if event.key() == Qt.Key_F1:
            self.set_alias_visibility(not self.aliases_visible)

        if event.key() == Qt.Key_F2:
            self.set_port_visibility(not self.ports_visible)

        if event.key() == Qt.Key_F3:
            self.set_subport_visibility(not self.subports_visible)
Ejemplo n.º 9
0
    def init_graphicsView(self):
        """ 
            graphicsView 初始化 :
            1、画出基站矩阵
            2、画出角点位置,将角点按顺时针连接
        """
        global scene
        scene = QGraphicsScene()
        self.graphicsView.setScene(scene)
        
        anchor = np.zeros((4,3), dtype=float) # anchor_1.x = 3.75  # 单位:米

        for i in range(4):
            anchor[i][0] = np.float(self.anchorTable.item(i,1).text()) * 100 # 取 anchorTable 其中 cell 的值
            anchor[i][1] = np.float(self.anchorTable.item(i,2).text()) * 100
            anchor[i][2] = np.float(self.anchorTable.item(i,3).text()) * 100

        # -------- 画出基站的四个顶点 ---------#
        anchor_brush = QBrush(QColor.fromRgb(120, 50, 255))
        for i in range(4):
            scene.addEllipse(
                anchor[i][0]-8, anchor[i][1]-8, 15, 15, brush=anchor_brush)

        origin_x = anchor[0][0]
        origin_y = anchor[0][1]
        axis_x = anchor[1][0]
        axis_y = anchor[2][1]
        
        # ------- 画出 基站区域 --------#
        scene.addLine(origin_x, origin_y, axis_x,  anchor[1][1], pen=QPen(Qt.green))
        scene.addLine(origin_x, origin_y,  anchor[2][0], axis_y, pen=QPen(Qt.green))

        # ------- 画出x, y 轴 ---------#
        scene.addLine(origin_x, origin_y, axis_x + 20, origin_y, pen=QPen(Qt.red, 4))
        scene.addLine(origin_x, origin_y, origin_x, axis_y + 20, pen=QPen(Qt.red, 4))

        triangle_0 = [
            QPoint(origin_x - 10, axis_y+ 20),
            QPoint(origin_x, axis_y +30),
            QPoint(origin_x + 10 , axis_y+ 20)
        ] # Y轴顶上三角形

        triangle_1 = [
            QPoint(axis_x + 20, origin_y - 10),
            QPoint(axis_x + 30, origin_y),
            QPoint(axis_x + 20, origin_y + 10)
        ] # X轴顶上三角形

        scene.addPolygon(QPolygonF(triangle_0), pen=QPen(Qt.red, 4), brush=QBrush(Qt.red, Qt.SolidPattern))
        scene.addPolygon(QPolygonF(triangle_1), pen=QPen(Qt.red, 4), brush=QBrush(Qt.red, Qt.SolidPattern))

        # ------ 再画出所有角点------- # 
        row_count = self.vertexTable.rowCount()
        vertex = np.zeros((row_count,3), dtype=float) 
        # print("row count: " + str(row_count))

        for i in range(row_count):
            vertex[i][0] = np.float(self.vertexTable.item(i,1).text()) / 10  # 取 vertexrTable 其中 cell 的值
            vertex[i][1] = np.float(self.vertexTable.item(i,2).text()) / 10
            vertex[i][2] = np.float(self.vertexTable.item(i,3).text()) / 10

        vertex_brush = QBrush(QColor.fromRgb(250, 244, 8)) # 红(250) 绿(244) 蓝(8)
        for i in range(row_count):
            scene.addEllipse(
                vertex[i][0]-4, vertex[i][1]-4, 8, 8, brush=vertex_brush)
            if i != row_count -1 :
                scene.addLine(vertex[i][0], vertex[i][1], vertex[i+1][0], vertex[i+1][1], pen=QPen(Qt.blue))
            else:
                scene.addLine(vertex[i][0], vertex[i][1], vertex[0][0], vertex[0][1], pen=QPen(Qt.blue))

        # 再画出砖块
        global brick_width, brick_height
        brick_width = int(self.brick_width_textEdit.toPlainText()) / 10  # 砖长:300mm
        brick_height = int(self.brick_length_textEdit.toPlainText()) / 10
        self.brick_gap = int(self.brick_gap_textEdit.toPlainText()) / 10 # 砖间隙:5mm

        global height_num, width_num
        height_num = np.int(axis_y/brick_height)
        width_num = np.int(axis_x/brick_width)

        return axis_x, axis_y # 返回长宽
Ejemplo n.º 10
0
class MyWin(QtWidgets.QMainWindow):
    osc_ip = "127.0.0.1"
    osc_port = 9023
    osc_client = SimpleUDPClient(osc_ip, osc_port)  # Create client

    streams = resolve_stream('name', 'EEG')
    # first resolve an EEG stream on the lab network
    print("looking for an EEG stream...")
    # create a new inlet to read from the stream
    inlet = StreamInlet(streams[0])
    timer = QtCore.QTimer()
    plot_timer = QtCore.QTimer()
    active_channels = [
    ]  # array of "active" channels - used for averaged signal
    samp_rate = 500  # sampling rate
    n_points = 0  # number of obtained points
    buffer_size = 0.5  # seconds, size of buffer
    buffer_vals = np.zeros(int(buffer_size * samp_rate))

    buffer_channels = []
    for i in range(24):
        buffer_channels.append(np.zeros(int(buffer_size * samp_rate)))

    fdb = open("delta_band.csv", "w")
    ftb = open("theta_band.csv", "w")
    fab = open("alpha_band.csv", "w")
    fbb = open("beta_band.csv", "w")
    fgb = open("gamma_band.csv", "w")
    fhgb = open("hgamma_band.csv", "w")
    timestmp = 0

    num_active_chan = 24
    average_val = 0  # averaged value - used for relative power and attention estimation
    for i in range(24):
        active_channels.append(1)

    attention_estimation_points = 5  # number of points for attention estimation
    relpower_arrays_size = 20  # size of array for storing relative power values
    theta_relpower = []
    beta_relpower = []
    alpharelpow = 0
    gammarelpow = 0
    attention_val = 0

    attention_source_ind = 0  # for average
    alpha_source_ind = 0  # for average
    attention_val_fromchannel = 0
    alpha_val_fromchannel = 0
    theta_relpower_fromchan = []
    beta_relpower_fromchan = []

    polygon = QPolygonF()

    #plotting variables
    size = 50
    x_vec = np.linspace(0, 50, size + 1)[0:-1]
    y_vec = np.random.randn(len(x_vec))
    line1 = []

    # for motor imagery
    motor_imagery_out = 0  # positive values reflect left hand imagery, negative values right hand
    n_output_integrate = 8  # how many motor imagery classifier outputs to integrate
    pred_buffer = np.zeros(n_output_integrate + 1)
    motor_imagery_out_save = []  # for debugging

    # set filter coefficients
    sfreq = 500  # or user already existing variable that specifies the sampling rate
    b_bp, a_bp = butter(2, np.array([8, 30]) / sfreq * 2, 'bandpass')
    zi_previous_bp = []
    for i in range(24):
        zi_previous_bp.append(lfilter_zi(b_bp, a_bp))
    zi_previous_bp = np.array(zi_previous_bp)

    b_pred, a_pred = butter(2,
                            np.array([0.15]) / (sfreq /
                                                (sfreq * buffer_size)) * 2,
                            'lowpass')  # adapted to sampling rate of buffer
    zi_previous_pred = lfilter_zi(b_pred, a_pred)

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setGeometry(500, 200, 900, 580)
        self.ui.pushButton.clicked.connect(self.startprocessing)
        self.ui.pushButton.setGeometry(QtCore.QRect(50, 510, 120, 28))
        self.ui.pushButton_2.clicked.connect(self.ext)
        self.ui.pushButton_2.setGeometry(QtCore.QRect(740, 510, 70, 28))
        self.ui.pushButton_3.clicked.connect(
            partial(self.update_allchans, True))
        self.ui.pushButton_5.clicked.connect(self.drawturtle)
        self.ui.pushButton_5.setVisible(False)
        self.ui.pushButton_6.clicked.connect(self.startdrawstream)
        self.ui.pushButton_6.setText("Plot Average signal")
        self.ui.pushButton_6.setGeometry(QtCore.QRect(180, 510, 140, 28))
        self.ui.pushButton_4.clicked.connect(
            partial(self.update_allchans, False))
        self.ui.doubleSpinBox.setValue(self.buffer_size)
        self.ui.comboBox.currentIndexChanged.connect(
            self.on_attentionsource_box_changed)
        self.ui.comboBox_2.currentIndexChanged.connect(
            self.on_alphasource_box_changed)

        self.scene = QGraphicsScene(self)
        self.scene.setBackgroundBrush(QBrush(QColor(0, 0, 0, 255)))
        self.ui.graphicsView.setScene(self.scene)
        self.ui.graphicsView.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.ui.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.ui.graphicsView.setFrameStyle(0)
        self.back_brush = QBrush(Qt.gray)
        self.shape_brush = QBrush(Qt.darkGreen)
        self.pen = QPen(Qt.green)
        self.ui.graphicsView.setBackgroundBrush(self.back_brush)
        self.drawshapes()

        self.ui.checkBox.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_2.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_3.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_4.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_5.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_6.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_7.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_8.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_9.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_10.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_11.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_12.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_13.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_14.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_15.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_16.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_17.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_18.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_19.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_20.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_21.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_22.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_23.stateChanged.connect(self.update_activechannels)
        self.ui.checkBox_24.stateChanged.connect(self.update_activechannels)

        self.timer.timeout.connect(self.updatedata)
        self.plot_timer.timeout.connect(self.drawstream)

    def on_attentionsource_box_changed(self, value):
        self.attention_source_ind = value

    def on_alphasource_box_changed(self, value):
        self.alpha_source_ind = value

    def drawshapes(self):
        # self.scene.addEllipse(20,20,200,200,self.pen,self.shape_brush)
        self.scene.clear()
        self.polygon.clear()
        x = y = t = 0
        npoints = int(self.attention_val * 10) + 3
        radius = int(self.attention_val * 10) * 15 + 20
        for i in range(npoints):
            t = 2 * math.pi * (float(i) / npoints + 0.5)
            x = 100 + math.cos(t) * radius
            y = 100 + math.sin(t) * radius
            self.polygon.append(QPointF(x, y))
        self.scene.addPolygon(
            self.polygon, self.pen,
            QColor(random.randint(0, 255), random.randint(0, 255),
                   random.randint(0, 255), int(100 + self.attention_val * 10)))

    def on_liveplot_close(self, event):
        self.plot_timer.stop()

    def live_plotter(self,
                     x_vec,
                     y1_data,
                     line1,
                     identifier='',
                     pause_time=0.1):
        if line1 == []:
            # this is the call to matplotlib that allows dynamic plotting
            #plt.ion()
            fig = plt.figure(figsize=(9, 2))
            fig.canvas.mpl_connect('close_event', self.on_liveplot_close)
            ax = fig.add_subplot(111)
            # create a variable for the line so we can later update it
            line1, = ax.plot(x_vec, y1_data, '-o', alpha=0.8)
            #update plot label/title
            plt.ylabel('Raw Value')
            plt.xticks([])
            plt.title('{}'.format(identifier))
            plt.show()

        # after the figure, axis, and line are created, we only need to update the y-data
        line1.set_ydata(y1_data)
        # adjust limits if new data goes beyond bounds
        #if np.min(y1_data)<=line1.axes.get_ylim()[0] or np.max(y1_data)>=line1.axes.get_ylim()[1]:
        plt.ylim([
            np.min(y1_data) - np.std(y1_data),
            np.max(y1_data) + np.std(y1_data)
        ])
        # this pauses the data so the figure/axis can catch up - the amount of pause can be altered above
        plt.pause(pause_time)
        # return line so we can update it again in the next iteration
        return line1

    def startprocessing(self):
        self.timer.start(1)

    def startdrawstream(self):
        self.line1 = []
        self.plot_timer.start(10)

    def drawstream(self):
        self.y_vec[-1] = self.average_val
        self.line1 = self.live_plotter(self.x_vec, self.y_vec, self.line1,
                                       "Average raw signal")
        self.y_vec = np.append(self.y_vec[1:], 0.0)

    def drawturtle(self):
        import turtle
        MINIMUM_BRANCH_LENGTH = 5

        def build_tree(t, branch_length, shorten_by, angle):
            if branch_length > MINIMUM_BRANCH_LENGTH:
                t.speed(int(self.alpharelpow * 100) + 1)
                t.forward(branch_length)
                new_length = branch_length - shorten_by
                t.left(angle)
                build_tree(t, new_length, shorten_by, angle)
                t.right(angle * 2)
                build_tree(t, new_length, shorten_by, angle)
                t.left(angle)
                t.backward(branch_length)

        tree = turtle.Turtle()
        # tree.speed(100)
        tree.hideturtle()
        tree.setheading(90)
        tree.color('green')
        build_tree(tree, 50, 5, 30)
        turtle.mainloop()

    def update_allchans(self, flag):
        self.ui.checkBox.setChecked(flag)
        self.ui.checkBox_2.setChecked(flag)
        self.ui.checkBox_3.setChecked(flag)
        self.ui.checkBox_4.setChecked(flag)
        self.ui.checkBox_5.setChecked(flag)
        self.ui.checkBox_6.setChecked(flag)
        self.ui.checkBox_7.setChecked(flag)
        self.ui.checkBox_8.setChecked(flag)
        self.ui.checkBox_9.setChecked(flag)
        self.ui.checkBox_10.setChecked(flag)
        self.ui.checkBox_11.setChecked(flag)
        self.ui.checkBox_12.setChecked(flag)
        self.ui.checkBox_13.setChecked(flag)
        self.ui.checkBox_14.setChecked(flag)
        self.ui.checkBox_15.setChecked(flag)
        self.ui.checkBox_16.setChecked(flag)
        self.ui.checkBox_17.setChecked(flag)
        self.ui.checkBox_18.setChecked(flag)
        self.ui.checkBox_19.setChecked(flag)
        self.ui.checkBox_20.setChecked(flag)
        self.ui.checkBox_21.setChecked(flag)
        self.ui.checkBox_22.setChecked(flag)
        self.ui.checkBox_23.setChecked(flag)
        self.ui.checkBox_24.setChecked(flag)
        self.update_activechannels()

    def update_activechannels(self):
        self.active_channels[0] = self.ui.checkBox.isChecked()
        self.active_channels[1] = self.ui.checkBox_2.isChecked()
        self.active_channels[2] = self.ui.checkBox_3.isChecked()
        self.active_channels[3] = self.ui.checkBox_4.isChecked()
        self.active_channels[4] = self.ui.checkBox_5.isChecked()
        self.active_channels[5] = self.ui.checkBox_6.isChecked()
        self.active_channels[6] = self.ui.checkBox_7.isChecked()
        self.active_channels[7] = self.ui.checkBox_8.isChecked()
        self.active_channels[8] = self.ui.checkBox_9.isChecked()
        self.active_channels[9] = self.ui.checkBox_10.isChecked()
        self.active_channels[10] = self.ui.checkBox_11.isChecked()
        self.active_channels[11] = self.ui.checkBox_12.isChecked()
        self.active_channels[12] = self.ui.checkBox_13.isChecked()
        self.active_channels[13] = self.ui.checkBox_14.isChecked()
        self.active_channels[14] = self.ui.checkBox_15.isChecked()
        self.active_channels[15] = self.ui.checkBox_16.isChecked()
        self.active_channels[16] = self.ui.checkBox_17.isChecked()
        self.active_channels[17] = self.ui.checkBox_18.isChecked()
        self.active_channels[18] = self.ui.checkBox_19.isChecked()
        self.active_channels[19] = self.ui.checkBox_20.isChecked()
        self.active_channels[20] = self.ui.checkBox_21.isChecked()
        self.active_channels[21] = self.ui.checkBox_22.isChecked()
        self.active_channels[22] = self.ui.checkBox_23.isChecked()
        self.active_channels[23] = self.ui.checkBox_24.isChecked()
        self.num_active_chan = sum(self.active_channels)

    def bandpower(self, data, sf, band, window_sec=None, relative=False):
        """Compute the average power of the signal x in a specific frequency band.
            https://raphaelvallat.com/bandpower.html
        Parameters
        ----------
        data : 1d-array
            Input signal in the time-domain.
        sf : float
            Sampling frequency of the data.
        band : list
            Lower and upper frequencies of the band of interest.
        window_sec : float
            Length of each window in seconds.
            If None, window_sec = (1 / min(band)) * 2
        relative : boolean
            If True, return the relative power (= divided by the total power of the signal).
            If False (default), return the absolute power.

        Return
        ------
        bp : float
            Absolute or relative band power.
        """
        from scipy.signal import welch
        from scipy.integrate import simps
        band = np.asarray(band)
        low, high = band

        # Define window length
        if window_sec is not None:
            nperseg = window_sec * sf
        else:
            nperseg = (2 / low) * sf

        # Compute the modified periodogram (Welch)
        freqs, psd = welch(data, sf, nperseg=nperseg)

        # Frequency resolution
        freq_res = freqs[1] - freqs[0]

        # Find closest indices of band in frequency vector
        idx_band = np.logical_and(freqs >= low, freqs <= high)

        # Integral approximation of the spectrum using Simpson's rule.
        bp = simps(psd[idx_band], dx=freq_res)

        if relative and simps(psd, dx=freq_res) > 0:
            bp /= simps(psd, dx=freq_res)
        else:
            return 0
        return bp

    def apply_csp_lda_online(self):
        # retrieve data
        signal_tmp = np.array(self.buffer_channels)

        # filter incoming signal (and use previous filter state)
        for i in range(24):
            signal_tmp[i, ], self.zi_previous_bp[i, ] = lfilter(
                self.b_bp,
                self.a_bp,
                signal_tmp[i, ],
                axis=-1,
                zi=self.zi_previous_bp[i, ])

        # scale signal (depending on input; signal range should be around +-25 µV)
        signal_tmp = signal_tmp / 10**6

        # bring data into right format
        signal_tmp = np.expand_dims(
            signal_tmp, 0
        )  # dimensions for CSP: epochs x channels x samples (1,24,n_samples_integrate)

        # load CSP+LDA from training (pre-allocate this to class MyWin? self.csp = ...)
        csp = load('csp_stored.joblib')
        lda = load('lda_stored.joblib')

        # apply CSP filters + LDA
        fea_tmp = csp.transform(signal_tmp)
        pred_tmp = lda.decision_function(fea_tmp)

        # put in array for prediction values
        # pred_cont.append(list(pred_tmp))
        # pred_cont = pred_cont[-n_output_integrate:] # only keep last values in buffer
        self.pred_buffer[:self.n_output_integrate] = self.pred_buffer[
            -self.n_output_integrate:]  # shift to the left by one
        self.pred_buffer[
            self.n_output_integrate] = pred_tmp  # add prediction of this loop
        # (actually, the buffer for the prediction output is not needed if we just low-pass filter but let´s keep it for now in case we switch to a moving average)

        # low-pass filter classifier outputs
        self.motor_imagery_out, self.zi_previous_pred = lfilter(
            self.b_pred,
            self.a_pred,
            pred_tmp,
            axis=-1,
            zi=self.zi_previous_pred)
        print(self.motor_imagery_out)
        self.osc_client.send_message("/motor_imagery", self.motor_imagery_out)
        self.motor_imagery_out_save.append(
            self.motor_imagery_out)  # for debugging

    def update_freqbandspower_allchans(self):
        win_sec = self.buffer_size

        self.fdb.write("{0:4.1f}".format(self.timestmp) + ',')
        self.ftb.write("{0:4.1f}".format(self.timestmp) + ',')
        self.fab.write("{0:4.1f}".format(self.timestmp) + ',')
        self.fbb.write("{0:4.1f}".format(self.timestmp) + ',')
        self.fgb.write("{0:4.1f}".format(self.timestmp) + ',')
        self.fhgb.write("{0:4.1f}".format(self.timestmp) + ',')

        for i in range(24):
            db_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                    [0.5, 4], win_sec, True)
            tb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                    [4, 8], win_sec, True)
            ab_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                    [8, 12], win_sec, True)
            bb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                    [12, 27], win_sec, True)
            gb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                    [27, 60], win_sec, True)
            hgb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate,
                                     [60, self.samp_rate / 2], win_sec, True)
            endch = ','
            if (i == 23):
                endch = ''
            self.fdb.write("{0:4.3f}".format(db_rel) + endch)
            self.ftb.write("{0:4.3f}".format(tb_rel) + endch)
            self.fab.write("{0:4.3f}".format(ab_rel) + endch)
            self.fbb.write("{0:4.3f}".format(bb_rel) + endch)
            self.fgb.write("{0:4.3f}".format(gb_rel) + endch)
            self.fhgb.write("{0:4.3f}".format(hgb_rel) + endch)
            if i == self.alpha_source_ind - 1:
                self.alpha_val_fromchannel = ab_rel
                self.ui.progressBar_3.setValue(
                    round(self.alpha_val_fromchannel * 100))
                self.ui.lineEdit_32.setText(
                    str(int(self.alpha_val_fromchannel * 100)) + "%")
            if i == self.attention_source_ind - 1:
                self.update_attention_fromchan(tb_rel, bb_rel)
            #print("{0:4.2f},{1:4.2f},{2:4.2f},{3:4.2f},{4:4.2f},{5:4.2f}".format(db_rel, tb_rel, ab_rel, bb_rel, gb_rel, hgb_rel))

        self.fdb.write('\n')
        self.ftb.write('\n')
        self.fab.write('\n')
        self.fbb.write('\n')
        self.fgb.write('\n')
        self.fhgb.write('\n')
        self.fdb.flush()
        self.ftb.flush()
        self.fab.flush()
        self.fbb.flush()
        self.fgb.flush()
        self.fhgb.flush()

    def update_freqbandspower(self):
        if self.num_active_chan == 0:
            return

        win_sec = self.buffer_size

        db_rel = self.bandpower(self.buffer_vals, self.samp_rate, [0.5, 4],
                                win_sec, True)
        tb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [4, 8],
                                win_sec, True)
        ab_rel = self.bandpower(self.buffer_vals, self.samp_rate, [8, 12],
                                win_sec, True)
        bb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [12, 27],
                                win_sec, True)
        gb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [27, 60],
                                win_sec, True)
        hgb_rel = self.bandpower(self.buffer_vals, self.samp_rate,
                                 [60, self.samp_rate / 2], win_sec, True)
        sum_rel = db_rel + tb_rel + ab_rel + bb_rel + gb_rel + hgb_rel
        self.alpharelpow = ab_rel
        self.gammarelpow = gb_rel
        # print("{0:4.2f},{1:4.2f},{2:4.2f},{3:4.2f},{4:4.2f},{5:4.2f},{6:4.2f}".format(db_rel, tb_rel, ab_rel, bb_rel,
        #                                                                              gb_rel, hgb_rel, sum_rel))

        self.update_attention(tb_rel, bb_rel)

        self.ui.progressBar.setValue(round(db_rel * 100))
        self.ui.lineEdit_30.setText(str(int(db_rel * 100)) + "%")
        self.ui.progressBar_2.setValue(round(tb_rel * 100))
        self.ui.lineEdit_31.setText(str(int(tb_rel * 100)) + "%")

        if self.alpha_source_ind == 0:
            self.ui.progressBar_3.setValue(round(ab_rel * 100))
            self.ui.lineEdit_32.setText(str(int(ab_rel * 100)) + "%")
        self.ui.progressBar_4.setValue(round(bb_rel * 100))
        self.ui.lineEdit_33.setText(str(int(bb_rel * 100)) + "%")
        self.ui.progressBar_5.setValue(round(gb_rel * 100))
        self.ui.lineEdit_34.setText(str(int(gb_rel * 100)) + "%")
        self.ui.progressBar_6.setValue(round(hgb_rel * 100))
        self.ui.lineEdit_35.setText(str(int(hgb_rel * 100)) + "%")
        # self.buffer_vals = np.zeros(self.samp_rate)

    def update_rawchannels(self, sample, timestamp):
        self.ui.lineEdit.setText(str(round(sample[0])))
        self.ui.lineEdit_2.setText(str(round(sample[1])))
        self.ui.lineEdit_3.setText(str(round(sample[2])))
        self.ui.lineEdit_4.setText(str(round(sample[3])))
        self.ui.lineEdit_5.setText(str(round(sample[4])))
        self.ui.lineEdit_6.setText(str(round(sample[5])))
        self.ui.lineEdit_7.setText(str(round(sample[6])))
        self.ui.lineEdit_8.setText(str(round(sample[7])))
        self.ui.lineEdit_9.setText(str(round(sample[8])))
        self.ui.lineEdit_10.setText(str(round(sample[9])))
        self.ui.lineEdit_11.setText(str(round(sample[10])))
        self.ui.lineEdit_12.setText(str(round(sample[11])))
        self.ui.lineEdit_13.setText(str(round(sample[12])))
        self.ui.lineEdit_14.setText(str(round(sample[13])))
        self.ui.lineEdit_15.setText(str(round(sample[14])))
        self.ui.lineEdit_16.setText(str(round(sample[15])))
        self.ui.lineEdit_17.setText(str(round(sample[16])))
        self.ui.lineEdit_18.setText(str(round(sample[17])))
        self.ui.lineEdit_19.setText(str(round(sample[18])))
        self.ui.lineEdit_20.setText(str(round(sample[19])))
        self.ui.lineEdit_21.setText(str(round(sample[20])))
        self.ui.lineEdit_22.setText(str(round(sample[21])))
        self.ui.lineEdit_23.setText(str(round(sample[22])))
        self.ui.lineEdit_24.setText(str(round(sample[23])))

        self.ui.lineEdit_25.setText(str(round(sample[24])))
        self.ui.lineEdit_26.setText(str(round(sample[25])))
        self.ui.lineEdit_27.setText(str(round(sample[26])))
        self.osc_client.send_message("/gyro/x", round(sample[24]))
        self.osc_client.send_message("/gyro/y", round(sample[25]))
        self.osc_client.send_message("/gyro/z", round(sample[26]))

        self.ui.lineEdit_28.setText(str(round(timestamp)))
        self.osc_client.send_message("/timestamp", round(timestamp))

    def update_attention_fromchan(self, tb_rel, bb_rel):
        self.theta_relpower_fromchan.append(tb_rel)
        self.beta_relpower_fromchan.append(bb_rel)
        if len(self.theta_relpower_fromchan) == self.relpower_arrays_size:
            self.theta_relpower_fromchan.pop(0)
            self.beta_relpower_fromchan.pop(0)

        if len(self.theta_relpower_fromchan
               ) < self.attention_estimation_points:
            if bb_rel < 0.01:
                bb_rel = 0.01
            self.attention_val_fromchannel = (1 - tb_rel / bb_rel)
        else:
            thetv = 0
            betav = 0
            for i in range(self.attention_estimation_points):
                thetv += self.theta_relpower_fromchan[
                    len(self.theta_relpower_fromchan) - i - 1]
                betav += self.beta_relpower_fromchan[
                    len(self.beta_relpower_fromchan) - i - 1]
            thetv /= self.attention_estimation_points
            betav /= self.attention_estimation_points
            self.attention_val_fromchannel = (1 - thetv / betav)

        if self.attention_val_fromchannel > 1:
            self.attention_val_fromchannel = 1
        elif self.attention_val_fromchannel < 0:
            self.attention_val_fromchannel = 0

        #print(self.attention_val_fromchannel)

    def update_attention(self, tb_rel, bb_rel):
        if self.num_active_chan == 0:
            return

        self.theta_relpower.append(tb_rel)
        self.beta_relpower.append(bb_rel)
        if len(self.theta_relpower) == self.relpower_arrays_size:
            self.theta_relpower.pop(0)
            self.beta_relpower.pop(0)

        if len(self.theta_relpower) < self.attention_estimation_points:
            if bb_rel < 0.01:
                bb_rel = 0.01
            self.attention_val = (1 - tb_rel / bb_rel)
        else:
            thetv = 0
            betav = 0
            for i in range(self.attention_estimation_points):
                thetv += self.theta_relpower[len(self.theta_relpower) - i - 1]
                betav += self.beta_relpower[len(self.beta_relpower) - i - 1]
            thetv /= self.attention_estimation_points
            betav /= self.attention_estimation_points
            self.attention_val = (1 - thetv / betav)
        #print(self.attention_val)

        if self.attention_val > 1:
            self.attention_val = 1
        elif self.attention_val < 0:
            self.attention_val = 0
        if self.attention_source_ind == 0:
            self.ui.progressBar_7.setValue(round(self.attention_val * 100))
            self.osc_client.send_message("/eeg/attention",
                                         int(self.attention_val * 100))
        else:
            self.ui.progressBar_7.setValue(
                round(self.attention_val_fromchannel * 100))
            self.osc_client.send_message(
                "/eeg/attention", int(self.attention_val_fromchannel * 100))
        #print(int(self.attention_val * 100))

        if self.alpha_source_ind == 0:
            self.osc_client.send_message("/eeg/alpha",
                                         int(self.alpharelpow * 100))
        else:
            self.osc_client.send_message("/eeg/alpha",
                                         int(self.alpha_val_fromchannel * 100))
        #print(int(self.alpharelpow * 100))

        self.osc_client.send_message("/eeg/gamma", int(self.gammarelpow * 100))

    def updatedata(self):
        sample, timestamp = self.inlet.pull_sample()
        self.timestmp = timestamp

        self.average_val = 0
        for i in range(24):
            if self.active_channels[i] == 1:
                self.average_val += sample[i]
            self.buffer_channels[i][self.n_points] = sample[i]

        if self.num_active_chan > 0:
            self.average_val /= self.num_active_chan
        else:
            self.average_val = 0

        self.buffer_vals[self.n_points] = self.average_val
        self.n_points += 1

        self.osc_client.send_message("/eeg/raw", self.average_val)

        if self.n_points == self.buffer_size * self.samp_rate:
            self.update_rawchannels(sample, timestamp)
            self.update_freqbandspower()
            self.update_freqbandspower_allchans()
            self.apply_csp_lda_online()
            self.drawshapes()
            self.ui.lineEdit_29.setText(str(round(self.average_val)))
            self.n_points = 0
            self.buffer_size = self.ui.doubleSpinBox.value()
            self.buffer_vals = np.zeros(int(self.buffer_size * self.samp_rate))
            for i in range(24):
                self.buffer_channels[i] = np.zeros(
                    int(self.buffer_size * self.samp_rate))

    def ext(self):
        """ exit the application """
        self.plot_timer.stop()
        self.timer.stop()
        self.fdb.close()
        self.ftb.close()
        self.fab.close()
        self.fbb.close()
        self.fgb.close()
        self.fhg.close()
        sys.exit()
class view(QGraphicsView):
    def __init__(self):
        super().__init__()
        self.title = "mainWindow"
        self.top = 0
        self.left = 0
        self.width = 1400
        self.height = 800
        self.scene = QGraphicsScene(0, 0, self.width, self.height)
        self.container_margin = 120
        self.container_max_height = 0
        self.rel_width = 70 * 2
        self.rel_height = 40 * 2
        self.r_atr_h = 30
        self.r_atr_w = 80
        self.r_atr_line = 50
        self.rel_pen = QPen(Qt.black, 3, Qt.SolidLine)
        self.rel_Brush = QBrush(QColor(255, 204, 153), Qt.SolidPattern)
        self.level = 100
        # self.setBackgroundBrush(QBrush(Qt.darkGray,Qt.CrossPattern))
        self.InitWindow()

    def InitWindow(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setScene(self.scene)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setRenderHint(QPainter.Antialiasing)
        self.setRenderHint(QPainter.TextAntialiasing)

    def add_Ens(self, e_list):
        self.item_list = []
        self.data = e_list

        for i in range(0, len(e_list)):
            self.item_list.append(
                ContainerItem(e_list[i], QPointF(500, 500), self.scene))
            if self.item_list[-1].container_height > self.container_max_height:
                self.container_max_height = self.item_list[-1].container_height
        cur_x = self.item_list[0].attribute_width / 2
        cur_y = self.container_max_height
        self.level = cur_y + self.item_list[0].entity_height + self.rel_height
        for j in range(0, len(self.item_list)):
            self.item_list[j].en_shape.setPos(cur_x, cur_y)
            cur_x += self.item_list[0].container_width + self.container_margin
            if (cur_x + self.item_list[0].container_width >
                    self.scene.width()):
                self.width += self.item_list[0].container_width
                self.scene.setSceneRect(QRectF(0, 0, self.width, self.height))
                # self.gen.widget().setGeometry(self.width-self.gen.widget().width(), self.height-self.gen.widget().height(), self.gen.widget().width(), self.gen.widget().height())
        for k in range(0, len(e_list)):
            for n in range(0, len(e_list[k].relations)):
                if (self.get_index(e_list[k].relations[n].getTargetEntity(
                        e_list[k])) >= k):
                    start = self.item_list[k].en_shape.x(
                    ) + self.item_list[k].entity_width
                    self.add_relation(start, e_list[k].relations[n])
                    self.item_list[k].connect_relation(
                        start, self.level, e_list[k].relations[n].p_type1)

                    self.item_list[self.get_index(
                        e_list[k].relations[n].getTargetEntity(
                            e_list[k]))].connect_relation(
                                start + self.rel_width, self.level,
                                e_list[k].relations[n].p_type1)
                    self.level += self.rel_height + 10
                    if (self.level + self.rel_height / 2 >=
                            self.scene.height()):
                        self.height = self.level + self.rel_height / 2
                        self.scene.setSceneRect(
                            QRectF(0, 0, self.width, self.height))

    def get_data(self):
        return self.data

    def add_relation(self, x, r):
        if (len(r.attrib_list) != 0):
            self.level += self.rel_height / 2 + self.r_atr_h * (
                len(r.attrib_list) - 1) + self.r_atr_line

        Qpoints = [
            QPointF(x, self.level),
            QPointF(x + self.rel_width / 2, self.level + self.rel_height / 2),
            QPointF(x + self.rel_width, self.level),
            QPointF(x + self.rel_width / 2, self.level - self.rel_height / 2)
        ]
        rel_shape = self.scene.addPolygon(QPolygonF(Qpoints), self.rel_pen,
                                          self.rel_Brush)
        rel_name = self.scene.addWidget(QLineEdit())
        left_p = self.scene.addWidget(QLineEdit())
        right_p = self.scene.addWidget(QLineEdit())
        #rel_name.setParentItem(rel_shape)
        rel_name.setGeometry(QRectF(0, 0, self.rel_width / 2, 3))
        left_p.setGeometry(QRectF(0, 0, 0, 0))
        right_p.setGeometry(QRectF(0, 0, 0, 0))
        left_p.widget().setFixedWidth(43)
        right_p.widget().setFixedWidth(43)
        rel_name.setPos(x + self.rel_width / 4,
                        self.level - rel_name.widget().height() / 2)
        left_p.setPos(x - left_p.widget().width(),
                      self.level - left_p.widget().height())
        right_p.setPos(x + self.rel_width,
                       self.level - right_p.widget().height())
        rel_name.widget().setText(r.name)
        left_p.widget().setText(r.p_ratio1)
        right_p.widget().setText(r.p_ratio2)
        rel_name.widget().editingFinished.connect(
            partial(self.mod, "n", r, rel_name.widget()))
        left_p.widget().editingFinished.connect(
            partial(self.mod, "l", r, left_p.widget()))
        right_p.widget().editingFinished.connect(
            partial(self.mod, "r", r, right_p.widget()))
        atr_step = ((self.rel_width - 2 * right_p.widget().width() - 10) /
                    (len(r.attrib_list) - 1)) if len(r.attrib_list) > 1 else 0
        ten = (Qpoints[0].y() - Qpoints[3].y()) / (Qpoints[0].x() -
                                                   Qpoints[3].x())
        for i in range(len(r.attrib_list)):
            first_pt = QPointF(
                Qpoints[0].x() + i * atr_step + right_p.widget().width() + 10,
                self.get_y_line(
                    Qpoints[0].x() + i * atr_step + right_p.widget().width() +
                    10, Qpoints[0], ten))
            if (first_pt.x() > Qpoints[3].x()):
                first_pt.setY(
                    self.get_y_line(first_pt.x(), Qpoints[3], -1 * ten))

            atr_line = self.scene.addLine(
                first_pt.x(), first_pt.y(), first_pt.x(),
                Qpoints[3].y() - self.r_atr_line - i * self.r_atr_h)
            elip_pt = QPointF(first_pt.x() - self.r_atr_w / 2,
                              atr_line.line().y2() - self.r_atr_h)
            atr_elipse = self.scene.addEllipse(
                QRectF(0, 0, self.r_atr_w, self.r_atr_h), self.rel_pen,
                self.rel_Brush)
            txt = []
            txt.append(self.scene.addWidget(QLineEdit(r.attrib_list[i].name)))
            atr_elipse.setPos(elip_pt)
            txt[-1].setPos(elip_pt.x() + self.rel_width * 0.25,
                           elip_pt.y() + self.r_atr_h * 0.125)
            txt[-1].widget().setFixedWidth(self.r_atr_w * 0.5)
            txt[-1].widget().setFixedHeight(self.r_atr_h * 0.75)
            txt[-1].widget().editingFinished.connect(
                partial(self.mod, "c", r, txt[-1].widget(), i))

    def get_y_line(self, x, p1, ten):
        return (x - p1.x()) * ten + p1.y()

    def get_index(self, id):
        for i in range(0, len(self.item_list)):
            if (id == self.item_list[i].entity.id):
                return i

    def mod(self, type, r, w, child=-1):
        if type == "n":
            r.name = w.text()
        elif type == 'l':
            r.p_ratio1 = w.text()
        elif type == 'r':
            r.p_ratio2 = w.text()
        elif type == 'c':
            r.attrib_list[child].name = w.text()
Ejemplo n.º 12
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.line_edit = QLineEdit()
        data = dict(json.load(open('description.json')))
        self.conditions = dict(
            (key, data[key])
            for key in data.keys())  # { состояние :{{переходы}, {координаты},
        for key in self.conditions.keys(
        ):  # флаг(конечное состояние), объекты на сцене, текст сигналов},...}
            self.conditions[key]["scene_items"] = []
            self.conditions[key]["text"] = {}
        self.signals = {}  # входные сигналы
        self.setGeometry(0, 0, 1000, 650)
        self.scene = QGraphicsScene()
        self.scene.setSceneRect(0, 0, 1000, 570)
        self.view = QGraphicsView(self.scene, self)
        self.view.show()
        self.configure_scene()

    def configure_scene(self):
        self.add_jump()
        self.add_conditions()
        self.add_signals()
        self.line_edit.setGeometry(50, 500, 800, 50)
        self.line_edit.textChanged.connect(self.slot)
        self.scene.addWidget(self.line_edit)

    def slot(self):  # слот при изменения
        machine = Machine.Machine(self.line_edit.text())
        current_condition = machine.start()
        machine = Machine.Machine(self.line_edit.text()[:-1])
        prev_condition = machine.start()
        for key in self.conditions.keys():
            self.change_color_of_circle(key, QColor(192, 192, 192))
            for k in self.conditions[key]["text"]:
                self.conditions[key]["text"][k].setDefaultTextColor(
                    QColor(0, 0, 0))
        if current_condition[0]:
            self.change_color_of_circle(current_condition[1],
                                        QColor(50, 205, 50))
            if current_condition[1] in self.conditions[
                    prev_condition[1]]["text"].keys():
                self.conditions[prev_condition[1]]["text"][
                    current_condition[1]].setDefaultTextColor(
                        QColor(50, 205, 50))
        else:
            self.change_color_of_circle(current_condition[1],
                                        QColor(255, 50, 50))

    def change_color_of_circle(self, cond, color):
        for item in self.conditions[cond]["scene_items"]:
            item.setBrush(color)

    def add_conditions(self):  # добавляет состояния автомата
        for key in self.conditions.keys():
            x = int(self.conditions[key]["coord"]['x'])
            y = int(self.conditions[key]["coord"]['y'])
            r = int(self.conditions[key]["coord"]['r'])
            self.paint_circle(x, y, r, key)
        for item in self.conditions['s0'][
                "scene_items"]:  # закрашиваем начальное состояние
            item.setBrush(QColor(50, 205, 50))

    def paint_circle(self, x, y, r, name):  # добавляет круг на сцену
        ell = QGraphicsEllipseItem(
            x - r // 2, y - r // 2, r,
            r)  # поправка смещения(в qt x,y - правый левый угол)
        ell.setBrush(QColor(192, 192, 192))
        self.scene.addItem(ell)
        self.conditions[name]["scene_items"].append(ell)
        if self.conditions[name]["is_final"] == 'yes':
            ell = QGraphicsEllipseItem(x - r // 2 + r // 10,
                                       y - r // 2 + r // 10, r - r // 5,
                                       r - r // 5)
            ell.setBrush(QColor(192, 192, 192))
            self.scene.addItem(ell)
            self.conditions[name]["scene_items"].append(ell)
        text_item = QGraphicsTextItem(name)
        text_item.moveBy(x - 11, y - 12)
        self.scene.addItem(text_item)

    def add_jump(self):  # добавляет переходы
        for key in self.conditions.keys():  # цикл по всем состояниям
            exist_jumps = []
            r1 = int(self.conditions[key]["coord"]['r'])
            x1 = int(self.conditions[key]["coord"]['x'])
            y1 = int(self.conditions[key]["coord"]['y'])
            for state in self.conditions[key]["jump"].values(
            ):  # цикл по всем переходам из текущего состояния
                r2 = int(self.conditions[state]["coord"]['r'])
                x2 = int(self.conditions[state]["coord"]['x'])
                y2 = int(self.conditions[state]["coord"]['y'])
                if key == state and state not in exist_jumps:
                    self.add_arc(x1, y1, r1)
                    exist_jumps.append(state)
                elif state not in exist_jumps:
                    self.add_arrow(x1, y1, x2, y2, r2)
                    exist_jumps.append(state)
            if self.conditions[key][
                    "is_final"] == 'start':  # начальное состояние
                self.add_arrow(x1, y1 - 1.5 * r1, x1, y1, r1)

    def add_arrow(self, x1, y1, x2, y2,
                  r):  # добавляет стрелки [(x1,y1) ---> (x2,y2)
        polygon = QPolygonF()
        polygon.append(QPoint(x1, y1))
        arrow_length = 30 + r // 2  # длина стрелки
        ostr = 0.1  # острота стрелки
        x = x2 - x1
        y = y2 - y1
        angle = math.atan2(y, x)
        new__x2 = x2 - r / 2 * math.cos(angle)  # координаты с учетом радиуса
        new__y2 = y2 - r / 2 * math.sin(angle)
        polygon.append(QPoint(new__x2, new__y2))
        arrow__x = x2 - arrow_length * math.cos(angle - ostr)
        arrow__y = y2 - arrow_length * math.sin(angle - ostr)
        polygon.append(QPoint(arrow__x, arrow__y))
        arrow__x = x2 - arrow_length * math.cos(angle + ostr)
        arrow__y = y2 - arrow_length * math.sin(angle + ostr)
        polygon.append(QPoint(arrow__x, arrow__y))
        polygon.append(QPoint(new__x2, new__y2))
        self.scene.addPolygon(polygon, QPen(), QBrush(Qt.black))

    def add_triangle(self, x, y, l):
        polygon = QPolygonF()
        polygon.append(QPoint(x, y))
        polygon.append(QPoint(x + l // 2, y - l))
        polygon.append(QPoint(x - l // 2, y - l))
        polygon.append(QPoint(x, y))
        self.scene.addPolygon(polygon, QPen(), QBrush(Qt.black))

    def add_arc(self, x, y,
                r):  # x,y - центр окружности, к которой строится дуга
        ell = QGraphicsEllipseItem(x - r // 4, y - r / 1.1, r - r // 2,
                                   r + r // 2)
        ell.setStartAngle(0)
        ell.setSpanAngle(2900)
        self.scene.addItem(ell)
        self.add_triangle(x - r // 4.4, y - r // 2.28, r // 4)

    def add_signals(
            self):  # добавление сигналов для перехода в другое состояние
        for cond in self.conditions.keys():
            text = {}
            for key in self.conditions[cond]["jump"].keys():
                if self.conditions[cond]["jump"][key] not in text.keys(
                ):  # если нет ключа - добавляем запись
                    text[self.conditions[cond]["jump"][key]] = key + ','
                else:  # если ключ есть - перезаписываем строку
                    text[self.conditions[cond]["jump"][key]] += key + ','
            for k in text.keys():
                if k == cond:  # переход в это же состояние
                    x = int(self.conditions[cond]["coord"]["x"])
                    y = int(self.conditions[cond]["coord"]["y"])
                    r = int(self.conditions[cond]["coord"]["r"])
                    self.add_text(cond, k, text[k][:-1], x + r // 5, y - r)
                else:
                    x1 = int(self.conditions[cond]["coord"]["x"])
                    y1 = int(self.conditions[cond]["coord"]["y"])
                    x2 = int(self.conditions[k]["coord"]["x"])
                    y2 = int(self.conditions[k]["coord"]["y"])
                    self.add_text(cond, k, text[k][:-1], (x1 + x2) // 2,
                                  (y1 + y2) // 2 - 30)

    # добавляет текст на сцену и в conditions сохраняет объекты этого текста
    def add_text(self, key, cond, text, x,
                 y):  # key - к какому состоянию привязать текст не сцене
        text_item = QGraphicsTextItem(text)  # cond куда произойдет переход
        text_item.moveBy(x, y)
        f = QFont("Times", 15)
        text_item.setFont(f)
        self.scene.addItem(text_item)
        self.conditions[key]["text"][cond] = text_item
Ejemplo n.º 13
0
class MonitorGraphicsView(QGraphicsView, AllowDrop):
    monitorWin = None

    SIZE = (50.0, 50.0)
    FULLSPEED = 512 * 1024  # 512 in kb/s

    _progressText = None
    _speedsPolygon = None
    _speedsPen = None
    _speedsBrush = None

    def __init__(self, parent=None):
        super().__init__(parent)
        self.monitorWin = parent
        if self.monitorWin:
            self.monitorWin.sigTaskUpdating.connect(self.slotTaskUpdate)

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, self.SIZE[0], self.SIZE[1])
        self.setScene(self.scene)

        self._speedsPen = QPen(Qt.white)

        gradient = QLinearGradient(0, 0, self.SIZE[0], self.SIZE[1])
        gradient.setColorAt(0.0, Qt.darkGreen)
        gradient.setColorAt(1.0, Qt.yellow)
        self._speedsBrush = QBrush(gradient)

        # add elements to the scene
        self._speedsPolygon = self.scene.addPolygon(QPolygonF(),
                                                    self._speedsPen,
                                                    self._speedsBrush)
        self._progressText = self.scene.addText("")
        self._progressText.setPos(10, 0)

        self.setupDropSupport()

    def mousePressEvent(self, qMouseEvent):
        self.monitorWin.mousePressEvent(qMouseEvent)

    def mouseMoveEvent(self, qMouseEvent):
        self.monitorWin.mouseMoveEvent(qMouseEvent)

    def mouseReleaseEvent(self, qMouseEvent):
        self.monitorWin.mouseReleaseEvent(qMouseEvent)

    def _setSpeeds(self, speeds):
        polygon = QPolygonF()
        polygon.append(QPointF(0, self.SIZE[1]))  # start the polygon

        nSamples = len(speeds)
        xPerSample = self.SIZE[0] / nSamples

        for i, speed in enumerate(speeds):
            y = self._translateSpeedToPosY(speed)
            polygon.append(QPointF(xPerSample * i, y))
            polygon.append(QPointF(xPerSample * (i + 1), y))
        polygon.append(QPointF(*self.SIZE))  # close the polygon

        self._speedsPolygon.setPolygon(polygon)

    def _setProgress(self, process):  # 10000 means 100%
        if process is None:
            self._progressText.setPlainText("")
        else:
            self._progressText.setPlainText("{:.1f}%".format(process / 100))

    def _translateSpeedToPosY(self, speed):
        return self.SIZE[1] * (1.0 - speed / self.FULLSPEED)

    @pyqtSlot(dict)
    def slotTaskUpdate(self, task):
        if task:
            self._setProgress(task["progress"])
            self._setSpeeds(task["speeds"])
        else:
            self._setProgress(None)
            self._setSpeeds([0.0])
Ejemplo n.º 14
0
class Paint(QGraphicsView):
    '''
 La clase Paint recive dos parámetros en el constructor una imagen y el nombre de dicha imágen
 '''
    def __init__(self, img=None, img_name=None):
        '''
  Esta clase hereda atributos y métodos de la clase QgraphicsView
  La clase QgraphicsView permite añadir una escena y en dicha escena
  se pueden hacer los dibujos.
  '''
        QGraphicsView.__init__(self)
        self.setSceneRect(
            QRectF(self.viewport().rect())
        )  #El Tamaño de la escena va a tener el tamaño de la pantalla original que es Dialogo
        self.scene = QGraphicsScene()  #Creamos un objeto tipo QgraphicsScene
        self.isObject = None  #Esta variable inicialmente nula, permite controlar las opciones de que dibujo queremos realizar
        self.startX = None  #Al momento de dibujar, esta variable guarda las cordenadas en x del primer clic
        self.startY = None  #Al momento de dibujar, esta variable guarda las cordenadas en y del primer clic
        self.pointPolygon = None  #Es una tubla de puntos del poligono en x e y
        self.arrayPolygon = [
        ]  #Es una lista con cada una de las tuplas de las coordenadas del poligono
        self.puntosX = []  #Es una lista que guarda solo los puntos de x
        self.puntosY = []  #Es una lista que guarda solo los puntos de y
        self.img_name = img_name

        self.pixi = img.scaled(
            638, 478)  #Reescalamos la imágen al tamaño de nuestra pantalla
        self.scene.addPixmap(self.pixi)  #añadimos la imágen a la escena
        self.setScene(self.scene)  #enviamso la escena al GraphicsVie

    '''
 Esta función nos permite seleccionar que tipo de dibujo queremos hacer
 '''

    def paintObject(self, e):
        if self.isObject != None:
            object = self.isObject
            if object == 1:  #Line
                pen = QPen(Qt.red)
                self.scene.addItem(
                    self.scene.addLine(self.startX, self.startY, e.x(), e.y(),
                                       pen))
                self.setScene(self.scene)
            elif object == 2:  #Rect
                '''
    Solo podemos dibujar un rectangulo para hacer un solo recorte, por eso cada vez que dibujemos
    uno preguntamos si ya hay algún rectangulo en la escena, si es así lo borramos
    '''
                for self.item in self.scene.items():

                    x = isinstance(self.item, QGraphicsRectItem)
                    if x:
                        self.scene.removeItem(self.item)

                pen = QPen(Qt.red)
                brush = QBrush()
                self.scene.addItem(
                    self.scene.addRect(self.startX, self.startY,
                                       e.x() - self.startX,
                                       e.y() - self.startY, pen, brush))
                self.region = (
                    self.startX, self.startY, e.x(), e.y()
                )  #éste es el rectangulo que obtendremos al recortar
                self.img = Image.open(
                    self.img_name)  #Abrimos la misma imágen que ya teniamos
                self.img_resized = self.img.resize(
                    (638, 478)
                )  #La redimensionamos, si no hacemos esto, al momento de recortar, no se obtendra la imagen requerida
                self.img_recortada = self.img_resized.crop(
                    self.region)  #Hacemos el recorte
                self.setScene(self.scene)  #Enviamos el rectangulo a la escena

            elif object == 3:  #Ellipse
                pen = QPen(Qt.red)
                brush = QBrush()
                self.scene.addItem(
                    self.scene.addEllipse(self.startX, self.startY,
                                          e.x() - self.startX,
                                          e.y() - self.startY, pen, brush))
                self.setScene(self.scene)

    def paintPolygon(self, e):
        if self.isObject != None:
            object = self.isObject
            if object == 4:  #Polygon
                self.pointPolygon = QPointF(e.x(), e.y())
                self.puntosX.append(e.x())
                self.puntosY.append(e.y())
                self.arrayPolygon.append(self.pointPolygon)
                pen = QPen(Qt.green)
                brush = QBrush(Qt.green, Qt.Dense4Pattern)
                self.scene.addItem(
                    self.scene.addPolygon(QPolygonF(self.arrayPolygon), pen,
                                          brush))
                self.setScene(self.scene)

    '''
 Esta funcion captura el evento de clickear
 '''

    def mousePressEvent(self, event):
        e = QPointF(self.mapToScene(event.pos()))
        self.startX = e.x()
        self.startY = e.y()

    '''
 Esta función actualiza las coordenadas en x e y
 '''

    def mouseReleaseEvent(self, event):
        e = QPointF(self.mapToScene(event.pos()))
        self.paintObject(e)
        self.paintPolygon(e)

    '''
 Esta función captura el evento de movimiento del mouse
 '''

    def mouseMoveEvent(self, event):
        e = QPointF(self.mapToScene(event.pos()))
Ejemplo n.º 15
0
    def __init__(self, state, device):
        super().__init__()

        self.state = state
        self.invalidated = False

        self.cnt = 0
        self.acc_values = (0, 0, 0, 0, 0, 0, 0)

        self.network = QNetworkAccessManager()

        view = QGraphicsView()
        view.setRenderHint(QPainter.Antialiasing)
        scene = QGraphicsScene()
        scene.addPixmap(QPixmap("chair.png").scaledToWidth(150))
        pen = QPen(QColor.fromRgb(0x28, 0x30, 0x39), 3)
        self.sonic = scene.addRect(QRectF(65, 20, 20, 10), pen,
                                   QBrush(Qt.white))
        self.lback = scene.addEllipse(QRectF(30, 50, 20, 20), pen,
                                      QBrush(Qt.white))
        self.rback = scene.addEllipse(QRectF(100, 50, 20, 20), pen,
                                      QBrush(Qt.white))
        self.lhip = scene.addPolygon(
            QPolygonF([
                QPointF(30, 170),
                QPointF(50, 170),
                QPointF(50, 160),
                QPointF(30, 160)
            ]), pen, QBrush(Qt.white))
        self.rhip = scene.addPolygon(
            QPolygonF([
                QPointF(100, 170),
                QPointF(120, 170),
                QPointF(120, 160),
                QPointF(100, 160)
            ]), pen, QBrush(Qt.white))
        self.lthigh = scene.addEllipse(QRectF(30, 200, 20, 10), pen,
                                       QBrush(Qt.white))
        self.rthigh = scene.addEllipse(QRectF(100, 200, 20, 10), pen,
                                       QBrush(Qt.white))
        self.displays = [
            self.lhip, self.lthigh, self.lback, self.rhip, self.rthigh,
            self.rback, self.sonic
        ]

        view.setScene(scene)
        view.setFixedWidth(150)
        view.setMinimumHeight(400)
        view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.setWindowTitle("센서 조정")
        self.setWindowIcon(QIcon('icon.png'))
        self.setGeometry(300, 300, 560, 600)

        self.label = QLabel()
        self.label.setProperty("class", "big")
        self.label.setAlignment(Qt.AlignHCenter)

        movie = QMovie("loader.gif")
        movie.start()
        busy_label = QLabel()
        busy_label.setMovie(movie)
        busy_label.setAlignment(Qt.AlignHCenter)

        layout = QVBoxLayout()
        layout.addStretch(1)
        layout.addWidget(self.label)
        layout.addWidget(view)
        layout.setAlignment(view, Qt.AlignHCenter)
        layout.addWidget(busy_label)
        layout.addStretch(1)
        layout.setContentsMargins(50, 50, 50, 50)
        layout.setSpacing(20)

        frame = QWidget()
        frame.setLayout(layout)
        frame.setProperty("class", "frame")

        main_layout = QVBoxLayout()
        main_layout.addWidget(frame)
        main_layout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(main_layout)
        self.setProperty("class", "root")
        self.setContentsMargins(0, 0, 0, 0)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.device_changed(device.is_connected())
        device.connectedChanged.connect(self.device_changed)
        device.updateNumber.connect(self.sensor_update)