Beispiel #1
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Beispiel #2
0
    def drawGrid(self):
        black_notes = [2,4,6,9,11]
        scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
        scale_bar.setPos(self.piano_width, 0)
        scale_bar.setBrush(QColor(100,100,100))
        clearpen = QPen(QColor(0,0,0,0))
        for i in range(self.end_octave - self.start_octave, self.start_octave - self.start_octave, -1):
            for j in range(self.notes_in_octave, 0, -1):
                scale_bar = QGraphicsRectItem(0, 0, self.grid_width, self.note_height, self.piano)
                scale_bar.setPos(self.piano_width, self.note_height * j + self.octave_height * (i - 1))
                scale_bar.setPen(clearpen)
                if j not in black_notes:
                    scale_bar.setBrush(QColor(120,120,120))
                else:
                    scale_bar.setBrush(QColor(100,100,100))

        measure_pen = QPen(QColor(0, 0, 0, 120), 3)
        half_measure_pen = QPen(QColor(0, 0, 0, 40), 2)
        line_pen = QPen(QColor(0, 0, 0, 40))
        for i in range(0, int(self.num_measures) + 1):
            measure = QGraphicsLineItem(0, 0, 0, self.piano_height + self.header_height - measure_pen.width(), self.header)
            measure.setPos(self.measure_width * i, 0.5 * measure_pen.width())
            measure.setPen(measure_pen)
            if i < self.num_measures:
                number = QGraphicsSimpleTextItem('%d' % (i + 1), self.header)
                number.setPos(self.measure_width * i + 5, 2)
                number.setBrush(Qt.white)
                for j in self.frange(0, self.time_sig[0]*self.grid_div/self.time_sig[1], 1.):
                    line = QGraphicsLineItem(0, 0, 0, self.piano_height, self.header)
                    line.setZValue(1.0)
                    line.setPos(self.measure_width * i + self.value_width * j, self.header_height)
                    if j == self.time_sig[0]*self.grid_div/self.time_sig[1] / 2.0:
                        line.setPen(half_measure_pen)
                    else:
                        line.setPen(line_pen)
Beispiel #3
0
    def initialize(self) -> None:
        """
        Method to initialize the display of this item

        :return: None
        """
        op = self.sceneBoundingRect().center()
        self.setTransformOriginPoint(op)
        self.setRotation(self.angle)
        cx, cy = self.center
        r1, r2 = self.height / 2, self.width / 2
        # Draw major axis
        major_axis = QGraphicsLineItem(-r2, 0, r2, 0)
        major_axis.setPos(cx, cy)
        major_axis.setParentItem(self)
        # Draw minor axis
        minor_axis = QGraphicsLineItem(-r1, 0, r1, 0)
        minor_axis.setPos(cx, cy)
        minor_axis.setParentItem(self)
        minor_axis.setRotation(90)
        rect = EditingRectangle(self.x, self.y, self.center[0], self.center[1],
                                self.width, self.height)
        rect.setTransformOriginPoint(rect.sceneBoundingRect().center())
        rect.setRotation(self.angle)
        self.indicators.extend([
            major_axis,
            minor_axis,
        ])
        self.edit_rect = rect
        self.rect = self.boundingRect()
        self.edit_rect.activate(False)
        self.setEnabled(False)
    def on_actItem_Line_triggered(self):  # 添加直线
        item = QGraphicsLineItem(-100, 0, 100, 0)  # x,y 为左上角的图元局部坐标,图元中心点为0,0
        item.setFlags(QGraphicsItem.ItemIsMovable
                      | QGraphicsItem.ItemIsSelectable
                      | QGraphicsItem.ItemIsFocusable)

        pen = QPen(Qt.red)
        pen.setWidth(3)
        item.setPen(pen)
        self.view.frontZ = self.view.frontZ + 1
        item.setZValue(self.view.frontZ)
        item.setPos(-50 + (QtCore.qrand() % 100), -50 + (QtCore.qrand() % 100))

        self.view.seqNum = self.view.seqNum + 1
        item.setData(self.view.ItemId, self.view.seqNum)  # //自定义数据,ItemId键
        item.setData(self.view.ItemDesciption, "直线")

        self.scene.addItem(item)
        self.scene.clearSelection()
        item.setSelected(True)
Beispiel #5
0
class painter(QGraphicsView):
    pixelSize = int(15 / narrowRatio)
    width = int(480 / narrowRatio)
    height = int(360 / narrowRatio)
    fontSize = int(15 / narrowRatio)
    anchorLineSize = int(100 / narrowRatio)
    ellipseRadius = int(8 / narrowRatio)
    textInterval = int(90 / narrowRatio)
    col = width / pixelSize
    line = height / pixelSize
    centerIndex = int(round(((line / 2 - 1) * col) + col / 2))
    frameCount = 0
    failedCount = 0
    baseZValue = 0
    mode = 1
    body = 1
    open_status = 0
    textLineHeight = fontSize + 10
    blurRaduis = 50  # Smoother improvement

    def __init__(self, dataThread):
        super(painter, self).__init__()
        self.dataThread = dataThread
        self.setFixedSize(self.width + 200, self.height + self.textLineHeight)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        # center het text item
        self.centerTextItem = QGraphicsTextItem()
        self.centerTextItem.setPos((self.width + 200) / 2 - self.fontSize, 0)
        self.centerTextItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.centerTextItem)
        # version text item
        self.versionTextItem = QGraphicsTextItem()
        self.versionTextItem.setPos(self.width * 0.8 - self.fontSize,
                                    self.height * 0.8 - self.fontSize)
        self.versionTextItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.versionTextItem)
        self.userCom = None

        # center anchor item
        centerX = self.width / 2
        centerY = self.height / 2
        self.ellipseItem = QGraphicsEllipseItem(0, 0, self.ellipseRadius * 2,
                                                self.ellipseRadius * 2)
        self.horLineItem = QGraphicsLineItem(0, 0, self.anchorLineSize, 0)
        self.verLineItem = QGraphicsLineItem(0, 0, 0, self.anchorLineSize)
        self.ellipseItem.setPos(centerX - self.ellipseRadius,
                                centerY - self.ellipseRadius)
        self.horLineItem.setPos(centerX - self.anchorLineSize / 2, centerY)
        self.verLineItem.setPos(centerX, centerY - self.anchorLineSize / 2)
        self.ellipseItem.setPen(QColor(Qt.white))
        self.horLineItem.setPen(QColor(Qt.white))
        self.verLineItem.setPen(QColor(Qt.white))
        self.ellipseItem.setZValue(self.baseZValue + 1)
        self.horLineItem.setZValue(self.baseZValue + 1)
        self.verLineItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.ellipseItem)
        self.scene.addItem(self.horLineItem)
        self.scene.addItem(self.verLineItem)
        # camera item
        self.cameraBuffer = QPixmap(self.width,
                                    self.height + self.textLineHeight)
        self.cameraItem = QGraphicsPixmapItem()
        if useBlur:
            self.gusBlurEffect = QGraphicsBlurEffect()
            self.gusBlurEffect.setBlurRadius(self.blurRaduis)
            self.cameraItem.setGraphicsEffect(self.gusBlurEffect)
        self.cameraItem.setPos(100, 0)
        self.cameraItem.setZValue(self.baseZValue)
        self.scene.addItem(self.cameraItem)
        # het text item
        self.hetTextBuffer = QPixmap(self.width + 200, self.textLineHeight)
        self.hetTextItem = QGraphicsPixmapItem()
        self.hetTextItem.setPos(0, self.height)
        self.hetTextItem.setZValue(self.baseZValue)
        self.scene.addItem(self.hetTextItem)
        # button item
        self.ctrlOpenButton = QPushButton('Open', self)
        self.ctrlOpenButton.clicked.connect(self.ctrlOpen)
        self.ctrlOpenButton.setGeometry(10, 30, 100, 40)

        self.EvaluateButton = QPushButton('None', self)
        self.EvaluateButton.clicked.connect(self.evaluate)
        self.EvaluateButton.setGeometry(10, 80, 100, 40)

        self.getOnePicButton = QPushButton('Get a frame', self)
        self.getOnePicButton.clicked.connect(self.ctrlSendone)
        self.getOnePicButton.setGeometry(10, 130, 100, 40)
        self.getOnePicButton.setEnabled(False)

        self.modeManualButton = QPushButton('Auto', self)
        self.modeManualButton.clicked.connect(self.modeManual)
        self.modeManualButton.setGeometry(10, 180, 100, 40)

        self.modeObjButton = QPushButton('Body', self)
        self.modeObjButton.clicked.connect(self.objBody)
        self.modeObjButton.setGeometry(10, 230, 100, 40)

        self.modeFpsButton = QPushButton('4FPS', self)
        self.modeFpsButton.clicked.connect(self.rate)
        self.modeFpsButton.setGeometry(10, 280, 100, 40)

        self.modeAutoButton = QPushButton('Get offset', self)
        self.modeAutoButton.clicked.connect(self.commonOffset)
        self.modeAutoButton.setGeometry(570, 30, 100, 40)

        self.modeAutoButton = QPushButton('Get version', self)
        self.modeAutoButton.clicked.connect(self.sysVer)
        self.modeAutoButton.setGeometry(570, 80, 100, 40)

        self.evaluate = 1
        self.evaluateButton = QPushButton('Evaluate', self)
        self.evaluateButton.clicked.connect(self.setEvaluate)
        self.evaluateButton.setGeometry(570, 120, 100, 40)

        self.serial_l = QLabel(self)

        self.serial_l.move(580, 250)
        self.serial_l.resize(60, 30)
        self.serial_l.setStyleSheet(
            "QLabel{color:rgb(0,0,0,255);background-color: rgb(255,255,255);font-size:16px;font-weight:normal;font-family:Arial;}"
        )
        self.serial_l.setText("Serial:")

        self.serialList = SerialComboBox(self)
        self.serialList.setCurrentIndex(0)
        self.serialList.setStyleSheet(
            "border-width: 1px;border-style: solid;border-color: rgb(255, 170, 0);"
        )
        self.serialList.currentIndexChanged.connect(self.serialChange)
        # self.evaluateButton.setGeometry(570,140,100,40)
        self.serialList.move(580, 280)
        self.serialList.resize(120, 30)
        self.serialList.addItem("Please select serial device")

    def checkSerial(self):
        reply = QMessageBox.information(self, 'No serial',
                                        "Please select serial device",
                                        QMessageBox.Yes)

        # portlist = SerialComboBox().get_port_list(self)
        # self.userCom = None
        # if portlist is not None:
        #     for port in portlist:
        #         print("port ",port)
        #         self.userCom = port
        #     if self.userCom is not None :
        #         self.dataThread.openSerial(self.userCom)
        #     else:
        #         reply = QMessageBox.information(self, '没有设置串口', "请选择串口" , QMessageBox.Yes)

    def serialChange(self, i):
        print("serialChange", i, self.serialList.currentText())
        if i > 0:
            self.userCom = self.serialList.currentText()
            self.dataThread.initSerialPort(self.userCom)

    def ctrlOpen(self):
        print("self.userCom", self.userCom)
        if self.userCom is None:
            self.checkSerial()
            return

        if self.open_status == 1:
            print('start send C command 0')
            self.open_status = 0

            self.ctrlOpenButton.setText("Open")
            self.dataThread.sendData('CMDC\0')
        else:
            print('start send C command 1')
            self.open_status = 1

            self.ctrlOpenButton.setText("Close")
            self.dataThread.sendData('CMDC\1')

    def evaluate(self):
        if self.userCom is None:
            self.checkSerial()
            return
        global evaluate_mode
        if evaluate_mode == "operate":
            print('start send E command 0')
            evaluate_mode = "evaluate"
            self.EvaluateButton.setText("Evaluate")
            self.dataThread.sendData('CMDE\1')
        else:
            print('start send E command 1')
            evaluate_mode = "operate"
            self.EvaluateButton.setText("Operate")
            self.dataThread.sendData('CMDE\0')

    def ctrlSendone(self):
        if self.userCom is None:
            self.checkSerial()
            return
        print('send a frame')
        self.dataThread.sendData('CMDC\2')

    def modeManual(self):
        if self.userCom is None:
            self.checkSerial()
            return
        if self.mode == 1:
            self.getOnePicButton.setEnabled(True)
            self.modeManualButton.setText("Manual")
            self.dataThread.sendData('CMDM\0')
            self.mode = 0
            print('mode: manual')
        else:

            self.getOnePicButton.setEnabled(False)
            self.modeManualButton.setText("Auto")
            self.dataThread.sendData('CMDM\1')
            print('mode: auto')
            self.mode = 1

    def modeAuto(self):
        if self.userCom is None:
            self.checkSerial()
            return
        print('mode: auto')
        self.dataThread.sendData('CMDM\1')

    def rate(self):
        if self.userCom is None:
            self.checkSerial()
            return
        global btn_index
        btn_index = (btn_index + 1) % 5
        print('FPS:', strButton[btn_index])
        self.modeFpsButton.setText(strButton[btn_index])
        self.dataThread.sendData(strFpsCmd[btn_index])  #'CMDF\0')

    def objBody(self):
        if self.userCom is None:
            self.checkSerial()
            return
        if self.body == 1:
            self.body = 0
            print('obj: Object')
            self.modeObjButton.setText("Object")
            self.dataThread.sendData('CMDO\0')
        else:
            self.body = 1
            print('obj: Human Body')
            self.modeObjButton.setText("Body")
            self.dataThread.sendData('CMDO\1')

    def uiUpdate(self):
        global evaluate_mode
        print("update UI ", evaluate_mode)
        if evaluate_mode == "operate":
            self.EvaluateButton.setText("Operate")
        elif evaluate_mode == "evaluate":
            self.EvaluateButton.setText("Evaluate")
        else:
            self.EvaluateButton.setText("None")

    def cmdUpdate(self):
        if self.userCom is None:
            self.checkSerial()
            return
        print("get evaluate status and version\n")
        time.sleep(0.1)
        self.dataThread.sendData('CMDE\2')
        time.sleep(0.1)
        self.dataThread.sendData('CMDV\0')
        time.sleep(0.1)
        self.dataThread.sendData('CMDT\1')

    def commonOffset(self):
        if self.userCom is None:
            self.checkSerial()
            return
        self.dataThread.sendData('CMDT\1')
        print("Get commonOffset")

    def sysVer(self):
        if self.userCom is None:
            self.checkSerial()
            return
        self.dataThread.sendData('CMDV\1')
        print("Get firmware version and calibration version.")

    def setEvaluate(self):
        if self.userCom is None:
            self.checkSerial()
            return
        if self.evaluate == 1:
            self.evaluate = 0
            self.evaluateButton.setText("Operate")
            self.dataThread.sendData('CMDE\0')
        else:
            self.evaluate = 1
            self.evaluateButton.setText("Evaluate")
            self.dataThread.sendData('CMDE\1')

    def draw(self):
        global minHue
        global maxHue
        global maxHet
        global minHet
        global device_commonOffset
        global evaluate_mode
        if len(displayData) == 0:
            return
        font = QFont()
        color = QColor()
        font.setPointSize(self.fontSize)
        #font.setFamily("Microsoft YaHei")
        font.setLetterSpacing(QFont.AbsoluteSpacing, 0)
        index = 0
        lock.acquire()
        frame = displayData.pop(0)
        lock.release()
        p = QPainter(self.cameraBuffer)
        p.fillRect(0, 0, self.width, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))
        # draw camera
        color = QColor()
        cneter = 0.0
        if chip == "90640":
            if self.centerIndex == 0:
                centerIndex = 12 * 32 + 16
            for yIndex in range(int(self.height / self.pixelSize)):
                for xIndex in range(int(self.width / self.pixelSize)):
                    color.setHsvF(frame[index] / 360, 1.0, 1.0)
                    p.fillRect(xIndex * self.pixelSize,
                               yIndex * self.pixelSize, self.pixelSize,
                               self.pixelSize, QBrush(color))
                    index = index + 1
            cneter = round(
                mapValue(frame[self.centerIndex], minHue, maxHue, minHet,
                         maxHet), 1)
        elif chip == "90621":
            if self.centerIndex == 0 or self.centerIndex >= 64:
                self.centerIndex = 2 * 16 + 8

            cneter = round(
                mapValue(frame[self.centerIndex], minHue, maxHue, minHet,
                         maxHet), 1)
            for yIndex in range(int(self.height / self.pixelSize / 6)):
                for xIndex in range(int(self.width / self.pixelSize / 2)):
                    color.setHsvF(frame[index] / 360, 1.0, 1.0)
                    p.fillRect(xIndex * self.pixelSize * 2,
                               yIndex * self.pixelSize * 2 + 160,
                               self.pixelSize * 2, self.pixelSize * 2,
                               QBrush(color))
                    index = index + 1
        elif chip == "90641":
            if self.centerIndex == 0 or self.centerIndex >= 192:
                self.centerIndex = 6 * 16 + 8

            cneter = round(
                mapValue(frame[self.centerIndex], minHue, maxHue, minHet,
                         maxHet), 1)
            for yIndex in range(int(self.height / self.pixelSize / 2)):
                for xIndex in range(int(self.width / self.pixelSize / 2)):
                    color.setHsvF(frame[index] / 360, 1.0, 1.0)
                    p.fillRect(xIndex * self.pixelSize * 2,
                               yIndex * self.pixelSize * 2, self.pixelSize * 2,
                               self.pixelSize * 2, QBrush(color))
                    index = index + 1
        else:
            print("Dsiplay Error: can't detect any chip type!")

        self.cameraItem.setPixmap(self.cameraBuffer)
        self.frameCount = self.frameCount + 1

        # draw text
        p = QPainter(self.hetTextBuffer)
        p.fillRect(0, 0, self.width + 200, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))

        version = self.dataThread.getID()
        p.setPen(QColor(Qt.white))
        p.setFont(font)
        p.drawText(0, self.fontSize, " max:" + '{:.2f}'.format(maxHet))
        p.drawText(self.textInterval, self.fontSize,
                   " min:" + '{:.2f}'.format(minHet))
        p.drawText(self.textInterval * 2, self.fontSize,
                   "offset:" + '{:.2f}'.format(device_commonOffset))
        p.drawText(self.textInterval * 3, self.fontSize,
                   "mode:" + detect_status)
        p.drawText(self.textInterval * 4, self.fontSize, evaluate_mode)
        p.drawText(self.textInterval * 5, self.fontSize,
                   "ID:" + str(version[0]))
        p.drawText(self.textInterval * 6, self.fontSize,
                   "ver:" + str(version[1] & 0xff))
        p.drawText(self.textInterval * 7, self.fontSize, chip)
        self.hetTextItem.setPixmap(self.hetTextBuffer)
        cneter = round(
            mapValue(frame[self.centerIndex], minHue, maxHue, minHet, maxHet),
            1)
        centerText = "<font color=white>%s</font>"
        self.centerTextItem.setFont(font)
        self.centerTextItem.setHtml(centerText % (str(cneter) + "°"))
        # draw version text
        self.versionTextItem.setFont(font)
Beispiel #6
0
class RecordsetWindow(QWidget):

    dataDisplayRequest = pyqtSignal(str, int)
    dataUpdateRequest = pyqtSignal(str, Base)

    def __init__(self, manager, recordset: list, parent=None):
        super().__init__(parent=parent)
        self.UI = Ui_frmRecordsets()
        self.UI.setupUi(self)

        # Internal lists
        self.sensors = {}           # List of sensors objects
        self.sensors_items = {}     # List of QAction corresponding to each sensors
        self.sensors_graphs = {}    # List of graph corresponding to each sensor graph
        self.sensors_location = []  # List of sensors location in this recordset
        self.sensors_blocks = {}    # Sensor blocks - each block of data for each sensor

        # Variables
        self.time_pixmap = False    # Flag used to check if we need to repaint the timeline or not
        self.zoom_level = 1         # Current timeview zoom level

        # Manually created UI objects
        self.time_bar = QGraphicsLineItem()         # Currently selected timestamp bar
        self.selection_rec = QGraphicsRectItem()    # Section rectangle
        self.sensors_menu = QMenu(self.UI.btnNewGraph)
        self.UI.btnNewGraph.setMenu(self.sensors_menu)

        # Data access informations
        self.dbMan = manager
        self.recordsets = recordset

        # Init temporal browser
        self.timeScene = QGraphicsScene()
        self.UI.graphTimeline.setScene(self.timeScene)
        self.UI.graphTimeline.fitInView(self.timeScene.sceneRect())
        self.UI.graphTimeline.time_clicked.connect(self.timeview_clicked)
        self.UI.graphTimeline.time_selected.connect(self.timeview_selected)
        self.UI.scrollTimeline.valueChanged.connect(self.timeview_scroll)

        # Init temporal sensor list
        self.timeSensorsScene = QGraphicsScene()
        self.UI.graphSensorsTimeline.setScene(self.timeSensorsScene)
        self.UI.graphSensorsTimeline.fitInView(self.timeSensorsScene.sceneRect(), Qt.KeepAspectRatio)

        # Update general informations about recordsets
        self.update_recordset_infos()

        # Load sensors for that recordset
        self.load_sensors()

        # Connect signals to slots
        self.UI.btnClearSelection.clicked.connect(self.on_timeview_clear_selection_requested)
        self.UI.btnTimeZoomSelection.clicked.connect(self.on_timeview_zoom_selection_requested)
        self.UI.btnZoomReset.clicked.connect(self.on_timeview_zoom_reset_requested)
        self.UI.btnDisplayTimeline.clicked.connect(self.on_timeview_show_hide_requested)
        self.UI.btnTileHorizontal.clicked.connect(self.tile_graphs_horizontally)
        self.UI.btnTileVertical.clicked.connect(self.tile_graphs_vertically)
        self.UI.btnTileAuto.clicked.connect(self.tile_graphs_auto)
        self.sensors_menu.triggered.connect(self.sensor_graph_selected)

        # Initial UI state
        self.UI.btnZoomReset.setEnabled(False)
        self.UI.btnTimeZoomSelection.setEnabled(False)
        self.UI.btnClearSelection.setEnabled(False)
        self.update_tile_buttons_state()

    def paintEvent(self, paint_event):
        if not self.time_pixmap:
            self.refresh_timeview()
            self.time_pixmap = True

    def resizeEvent(self, resize_event):
        if self.time_pixmap:
            self.refresh_timeview()

    def refresh_timeview(self):
        QGuiApplication.setOverrideCursor(Qt.BusyCursor)

        # Computes required timescene size
        min_width = self.UI.graphTimeline.width() - 5
        if len(self.recordsets) > 0:
            num_days = (self.get_recordset_end_day_date() - self.get_recordset_start_day_date()).days

            # Minimum size for days
            if num_days * 75 > min_width:
                min_width = num_days * 75 - 5

        # Resize timeScene correctly
        self.timeScene.clear()
        self.timeScene.setSceneRect(self.timeScene.itemsBoundingRect())
        self.timeScene.addLine(0, 80, min_width, 80, QPen(Qt.transparent))

        # Set background color
        back_brush = QBrush(Qt.lightGray)
        self.timeScene.setBackgroundBrush(back_brush)
        self.timeSensorsScene.setBackgroundBrush(back_brush)

        # Update display
        self.draw_dates()
        self.draw_sensors_names()
        self.draw_recordsets()
        self.draw_sensors()
        self.draw_grid()
        self.draw_timebar()

        # Adjust splitter sizes
        self.adjust_timeview_size()
        # self.UI.frmSensors.hide()

        QGuiApplication.restoreOverrideCursor()

    def adjust_timeview_size(self):
        self.UI.frameScrollSpacer.setFixedWidth(self.UI.graphTimeline.pos().x())
        if self.timeScene.itemsBoundingRect().width() * self.zoom_level > self.UI.graphTimeline.width():
            self.UI.scrollTimeline.setVisible(True)
            # self.UI.scrollTimeline.setMinimum(self.UI.graphTimeline.width()/2)
            self.UI.scrollTimeline.setMinimum(0)
            self.UI.scrollTimeline.setMaximum(self.timeScene.itemsBoundingRect().width() * self.zoom_level)
            self.UI.scrollTimeline.setPageStep(self.UI.graphTimeline.width()/2)
            self.UI.scrollTimeline.setSingleStep(self.UI.graphTimeline.width()/5)
        else:
            self.UI.scrollTimeline.setVisible(False)

    def load_sensors(self):

        # self.UI.lstSensors.clear()
        self.sensors = {}
        self.sensors_items = {}
        self.sensors_location = []
        self.sensors_menu.clear()

        if len(self.recordsets) > 0:
            for recordset in self.recordsets:
                for sensor in self.dbMan.get_sensors(recordset):
                    if sensor.location not in self.sensors_location:
                        self.sensors_location.append(sensor.location)
                        self.sensors_menu.addSection(sensor.location)
                    if sensor.id_sensor not in self.sensors:
                        self.sensors[sensor.id_sensor] = sensor
                        sensor_item = QAction(sensor.name)
                        sensor_item.setCheckable(True)
                        sensor_item.setProperty("sensor_id", sensor.id_sensor)
                        self.sensors_items[sensor.id_sensor] = sensor_item
                        self.sensors_menu.addAction(sensor_item)

            # Create sensors blocks for display
            self.load_sensors_blocks()
        else:
            self.UI.btnNewGraph.setEnabled(False)

    def update_recordset_infos(self):
        if len(self.recordsets) == 0:
            self.UI.lblTotalValue.setText("Aucune donnée.")
            self.UI.lblDurationValue.setText("Aucune donnée.")
            return

        start_time = self.recordsets[0].start_timestamp
        end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp

        # Coverage
        self.UI.lblTotalValue.setText(start_time.strftime('%d-%m-%Y %H:%M:%S') + " @ " + end_time.strftime(
                                                                                                '%d-%m-%Y %H:%M:%S'))

        # Duration
        # TODO: format better
        self.UI.lblDurationValue.setText(str(end_time - start_time))

        self.UI.lblCursorTime.setText(start_time.strftime('%d-%m-%Y %H:%M:%S'))

    def get_recordset_start_day_date(self):
        if len(self.recordsets) == 0:
            return None
        start_time = self.recordsets[0].start_timestamp
        start_time = (datetime(start_time.year, start_time.month, start_time.day, 0, 0, 0))
        return start_time

    def get_recordset_end_day_date(self):
        if len(self.recordsets) == 0:
            return None
        end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp
        end_time = (datetime(end_time.year, end_time.month, end_time.day, 0, 0, 0) + timedelta(days=1))
        return end_time

    def get_relative_timeview_pos(self, current_time):
        # start_time = self.recordsets[0].start_timestamp.timestamp()
        start_time = self.get_recordset_start_day_date().timestamp()
        # end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp.timestamp()
        end_time = self.get_recordset_end_day_date().timestamp()
        time_span = (end_time - start_time)  # Total number of seconds in recordsets
        # if type(current_time) is datetime:
        if isinstance(current_time, datetime):
            current_time = current_time.timestamp()

        if time_span > 0:
            # return ((current_time - start_time) / time_span) * self.UI.graphTimeline.width()
            return ((current_time - start_time) / time_span) * self.timeScene.width()
        else:
            return 0

    def get_time_from_timeview_pos(self, pos):
        if len(self.recordsets) == 0:
            return None;

        start_time = self.get_recordset_start_day_date().timestamp()
        end_time = self.get_recordset_end_day_date().timestamp()

        current_time = (pos / self.timeScene.width()) * (end_time - start_time) + start_time
        current_time = datetime.fromtimestamp(current_time)

        return current_time

    def draw_dates(self):
        if len(self.recordsets) == 0:
            return

        # Computations
        start_time = self.recordsets[0].start_timestamp
        end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp
        # time_span = (end_time - start_time).total_seconds()  # Total number of seconds in recordsets
        current_time = (datetime(start_time.year, start_time.month, start_time.day, 0, 0, 0) + timedelta(days=1))

        # Drawing tools
        black_pen = QPen(Qt.black)
        blue_brush = QBrush(Qt.darkBlue)

        # Date background
        self.timeScene.addRect(0, 0, self.timeScene.width(), 20, black_pen, blue_brush)
        self.timeSensorsScene.addRect(0, 0, self.timeSensorsScene.width(), 20, black_pen, blue_brush)

        # First date
        date_text = self.timeScene.addText(start_time.strftime("%d-%m-%Y"))
        date_text.setPos(0, 0)  # -5
        date_text.setDefaultTextColor(Qt.white)
        date_text.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)

        # Date separators
        while current_time <= end_time:
            pos = self.get_relative_timeview_pos(current_time)
            date_text = self.timeScene.addText(current_time.strftime("%d-%m-%Y"))
            date_text.setPos(pos, 0)  # -5
            date_text.setDefaultTextColor(Qt.white)
            date_text.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)
            current_time += timedelta(days=1)

        # self.UI.graphTimeline.fitInView(self.timeScene.sceneRect(), Qt.KeepAspectRatio)

    def draw_grid(self):
        if len(self.recordsets) == 0:
            return

        # Computations
        start_time = self.recordsets[0].start_timestamp
        end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp
        # time_span = (end_time - start_time).total_seconds()  # Total number of seconds in recordsets
        current_time = (datetime(start_time.year, start_time.month, start_time.day, 0, 0, 0) + timedelta(days=1))

        vgrid_pen = QPen(Qt.gray)
        hgrid_pen = QPen(Qt.black)
        vgrid_pen.setCosmetic(True)

        # Horizontal lines
        pos = 20
        # last_location = ""
        sensor_location_brush = QBrush(Qt.black)
        sensor_location_pen = QPen(Qt.transparent)
        for location in self.sensors_location:
            # Must create a new location line
            self.timeScene.addRect(0, pos, self.timeScene.width() - 1, 15, sensor_location_pen, sensor_location_brush)
            pos += 15
            sensors = self.get_sensors_for_location(location)
            for _ in sensors:
                self.timeScene.addLine(0, pos, self.timeScene.width() - 1, pos, hgrid_pen)
                self.timeSensorsScene.addLine(0, pos, self.timeSensorsScene.width(), pos, hgrid_pen)
                pos += 20

        # Final line
        self.timeScene.addLine(0, pos, self.timeScene.width() - 1, pos, hgrid_pen)
        self.timeSensorsScene.addLine(0, pos, self.timeSensorsScene.width() - 1, pos, hgrid_pen)

        # Date separators
        self.timeScene.addLine(0, 0, 0, self.timeScene.height(), vgrid_pen)

        # Other dates
        while current_time <= end_time:
            pos = self.get_relative_timeview_pos(current_time)
            self.timeScene.addLine(pos, 0, pos, self.timeScene.height(), vgrid_pen)
            current_time += timedelta(days=1)

    def draw_recordsets(self):
        recordset_brush = QBrush(QColor(212, 247, 192))  # Green
        recordset_pen = QPen(Qt.transparent)

        # Recording length
        for record in self.recordsets:
            start_pos = self.get_relative_timeview_pos(record.start_timestamp)
            end_pos = self.get_relative_timeview_pos(record.end_timestamp)
            span = end_pos - start_pos
            # print (str(span))
            self.timeScene.addRect(start_pos, 21, span, self.timeSensorsScene.height()-21, recordset_pen,
                                   recordset_brush)

        # self.UI.graphTimeline.update()
        return

    def draw_sensors_names(self):
        if len(self.sensors) == 0:
            return

        sensor_location_brush = QBrush(Qt.black)
        sensor_location_pen = QPen(Qt.transparent)

        # Sensor names
        pos = 20

        for location in self.sensors_location:
            # Must create a new location space for later
            pos += 15
            sensors = self.get_sensors_for_location(location)
            for sensor_id in sensors:
                sensor = self.sensors[sensor_id]
                # Sensor names
                label = self.timeSensorsScene.addText(sensor.name)
                label.setPos(0, pos)
                label.setDefaultTextColor(Qt.black)
                # label.setFont(QFont("Times", 10, QFont.Bold))
                pos += 20

        # Adjust size appropriately
        self.timeSensorsScene.setSceneRect(self.timeSensorsScene.itemsBoundingRect())
        self.UI.graphSensorsTimeline.setMaximumWidth(self.timeSensorsScene.itemsBoundingRect().width())

        # Sensor location background
        pos = 20
        for location in self.sensors_location:
            # Must create a new location line
            self.timeSensorsScene.addRect(0, pos, self.timeSensorsScene.width(), 15, sensor_location_pen,
                                          sensor_location_brush)
            label = self.timeSensorsScene.addText(location)
            label.setPos(0, pos)
            label.setDefaultTextColor(Qt.white)
            label.setFont(QFont("Times", 7))
            pos += 15
            sensors = self.get_sensors_for_location(location)
            for sensor_id in sensors:
                pos += 20

    def draw_sensors(self):
        if len(self.sensors) == 0:
            return

        sensor_brush = QBrush(Qt.darkGreen)
        sensor_pen = QPen(Qt.transparent)

        sensors_rects = self.create_sensors_rects()
        for _, rect in enumerate(sensors_rects):
            self.timeScene.addRect(rect, sensor_pen, sensor_brush)

        # Adjust size appropriately
        self.timeSensorsScene.setSceneRect(self.timeSensorsScene.itemsBoundingRect())
        self.UI.graphSensorsTimeline.setMaximumWidth(self.timeSensorsScene.itemsBoundingRect().width())
        # self.UI.graphSensorsTimeline.setMaximumHeight(self.timeSensorsScene.itemsBoundingRect().height())

    def load_sensors_blocks(self):
        # Create request tasks
        tasks = []
        for location in self.sensors_location:
            sensors = self.get_sensors_for_location(location)
            for sensor_id in sensors:
                for record in self.recordsets:
                    tasks.append(DBSensorTimesTask(title="Chargement des données temporelles", db_manager=self.dbMan,
                                                   sensor_id=sensor_id, recordset=record))

        QGuiApplication.setOverrideCursor(Qt.BusyCursor)
        process = BackgroundProcess(tasks)
        dialog = ProgressDialog(process, "Chargement")

        process.start()
        dialog.exec()
        QGuiApplication.restoreOverrideCursor()

        # Combine tasks results
        self.sensors_blocks = {}
        for task in tasks:
                for result in task.results:
                    if result['sensor_id'] not in self.sensors_blocks:
                        self.sensors_blocks[result['sensor_id']] = []
                    start_time = result['start_time']
                    end_time = result['end_time']
                    data = {"start_time": start_time, "end_time": end_time}
                    self.sensors_blocks[result['sensor_id']].append(data)

    def create_sensors_rects(self):
        rects = []
        pos = 20
        for location in self.sensors_location:
            # Must create a new location space for later
            pos += 15
            sensors = self.get_sensors_for_location(location)
            for sensor_id in sensors:
                # sensor = self.sensors[sensor_id]
                # for record in self.recordsets:
                #    datas = self.dbMan.get_all_sensor_data(sensor=sensor, recordset=record, channel=sensor.channels[0])
                #     for data in datas:
                #         start_pos = self.get_relative_timeview_pos(data.timestamps.start_timestamp)
                #         end_pos = self.get_relative_timeview_pos(data.timestamps.end_timestamp)
                #         span = max(end_pos - start_pos, 1)
                #         rects.append(QRectF(start_pos, pos + 3, span, 14))
                if sensor_id in self.sensors_blocks:
                    for block in self.sensors_blocks[sensor_id]:
                        start_pos = self.get_relative_timeview_pos(block['start_time'])
                        end_pos = self.get_relative_timeview_pos(block['end_time'])
                        span = max(end_pos - start_pos, 1)
                        rects.append(QRectF(start_pos, pos + 3, span, 14))
                pos += 20

        return rects

    def draw_timebar(self):
        line_pen = QPen(Qt.cyan)
        line_pen.setWidth(2)
        self.time_bar = self.timeScene.addLine(1, 21, 1, self.timeScene.height()-1, line_pen)
        # self.time_bar = self.timeScene.addLine(0, 1, 0, self.timeScene.height() - 1, line_pen)
        self.time_bar.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)

    def get_sensors_for_location(self, location):
        sensors_id = []
        for sensor in self.sensors.values():
            if sensor.location == location:
                sensors_id.append(sensor.id_sensor)

        return sensors_id

    @staticmethod
    def get_sensor_graph_type(sensor):
        if sensor.id_sensor_type == SensorType.ACCELEROMETER \
                or sensor.id_sensor_type == SensorType.GYROMETER \
                or sensor.id_sensor_type == SensorType.BATTERY \
                or sensor.id_sensor_type == SensorType.LUX \
                or sensor.id_sensor_type == SensorType.CURRENT \
                or sensor.id_sensor_type == SensorType.BAROMETER \
                or sensor.id_sensor_type == SensorType.MAGNETOMETER \
                or sensor.id_sensor_type == SensorType.TEMPERATURE \
                or sensor.id_sensor_type == SensorType.HEARTRATE \
                or sensor.id_sensor_type == SensorType.ORIENTATION \
                or sensor.id_sensor_type == SensorType.FSR:
            return GraphType.LINECHART

        if sensor.id_sensor_type == SensorType.GPS:
            return GraphType.MAP

        return GraphType.UNKNOWN

    @pyqtSlot(Sensor, datetime, datetime)
    def query_sensor_data(self, sensor: Sensor, start_time: datetime, end_time: datetime):
        timeseries = self.get_sensor_data(sensor, start_time, end_time)[0]

        if self.sensors_graphs[sensor.id_sensor]:
            graph_type = self.get_sensor_graph_type(sensor)
            graph_window = self.sensors_graphs[sensor.id_sensor]
            if graph_type == GraphType.LINECHART:
                series_id = 0
                for series in timeseries:
                    # Filter times that don't fit in the range
                    y_range = series['y']
                    x_range = series['x']
                    y_range = y_range[x_range >= start_time.timestamp()]
                    x_range = x_range[x_range >= start_time.timestamp()]
                    y_range = y_range[x_range <= end_time.timestamp()]
                    x_range = x_range[x_range <= end_time.timestamp()]
                    if len(x_range)>0 and len(y_range)>0:
                        graph_window.graph.update_data(x_range, y_range, series_id)
                    series_id += 1
        return

    @pyqtSlot(QAction)
    # @timing
    def sensor_graph_selected(self, sensor_item):
        sensor_id = sensor_item.property("sensor_id")
        sensor = self.sensors[sensor_id]
        sensor_label = sensor.name + " (" + sensor.location + ")"

        if sensor_item.isChecked():
            # Choose the correct display for each sensor
            graph_window = None
            timeseries, channel_data = self.get_sensor_data(sensor)  # Fetch all sensor data

            # Color map for curves
            colors = [Qt.blue, Qt.green, Qt.yellow, Qt.red]

            graph_type = self.get_sensor_graph_type(sensor)
            graph_window = GraphWindow(graph_type, sensor, self.UI.mdiArea)
            graph_window.setStyleSheet(self.styleSheet() + graph_window.styleSheet())

            if graph_type == GraphType.LINECHART:
                # Add series
                for series in timeseries:
                    graph_window.graph.add_data(series['x'], series['y'], color=colors.pop(),
                                                legend_text=series['label'])

                graph_window.graph.set_title(sensor_label)

            if graph_type == GraphType.MAP:
                for data in channel_data:
                    gps = GPSGeodetic()
                    gps.from_bytes(data.data)
                    if gps.latitude != 0 and gps.longitude != 0:
                        graph_window.graph.addPosition(data.timestamps.start_timestamp, gps.latitude / 1e7,
                                                       gps.longitude / 1e7)
                        graph_window.setCursorPositionFromTime(data.timestamps.start_timestamp)

            if graph_window is not None:
                self.UI.mdiArea.addSubWindow(graph_window).setWindowTitle(sensor_label)
                self.sensors_graphs[sensor.id_sensor] = graph_window
                # self.UI.displayContents.layout().insertWidget(0,graph)

                graph_window.show()
                QApplication.instance().processEvents()

                graph_window.aboutToClose.connect(self.graph_was_closed)
                graph_window.requestData.connect(self.query_sensor_data)
                graph_window.graph.cursorMoved.connect(self.graph_cursor_changed)
                graph_window.graph.selectedAreaChanged.connect(self.graph_selected_area_changed)
                graph_window.graph.clearedSelectionArea.connect(self.on_timeview_clear_selection_requested)
                graph_window.zoomAreaRequested.connect(self.graph_zoom_area)
                graph_window.zoomResetRequested.connect(self.graph_zoom_reset)

                self.UI.mdiArea.tileSubWindows()
        else:
            # Remove from display
            try:
                if self.sensors_graphs[sensor.id_sensor] is not None:
                    self.UI.mdiArea.removeSubWindow(self.sensors_graphs[sensor.id_sensor].parent())
                    self.sensors_graphs[sensor.id_sensor].hide()
                    del self.sensors_graphs[sensor.id_sensor]
                    self.UI.mdiArea.tileSubWindows()
            except KeyError:
                pass
        self.update_tile_buttons_state()

    # @timing
    def get_sensor_data(self, sensor, start_time=None, end_time=None):
        QGuiApplication.setOverrideCursor(Qt.BusyCursor)
        task = DBSensorAllDataTask("Chargement des données...", self.dbMan, sensor, start_time, end_time,
                                   self.recordsets)

        process = BackgroundProcess([task])
        dialog = ProgressDialog(process, "Traitement")

        process.start()
        dialog.exec()
        QGuiApplication.restoreOverrideCursor()

        return task.results['timeseries'], task.results['channel_data']

    def update_tile_buttons_state(self):
        if self.sensors_graphs.keys().__len__() > 1:
            self.UI.btnTileAuto.setEnabled(True)
            self.UI.btnTileHorizontal.setEnabled(True)
            self.UI.btnTileVertical.setEnabled(True)
        else:
            self.UI.btnTileAuto.setEnabled(False)
            self.UI.btnTileHorizontal.setEnabled(False)
            self.UI.btnTileVertical.setEnabled(False)

    @pyqtSlot(QObject)
    def graph_was_closed(self, graph):
        for sensor_id, sensor_graph in self.sensors_graphs.items():
            if sensor_graph == graph:
                # self.sensors_graphs[sensor_id] = None
                del self.sensors_graphs[sensor_id]
                self.sensors_items[sensor_id].setChecked(False)
                break

        self.UI.mdiArea.tileSubWindows()
        self.update_tile_buttons_state()

    @pyqtSlot(float)
    def graph_cursor_changed(self, timestamp):
        current_time = timestamp / 1000
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.setCursorPositionFromTime(current_time, False)

        pos = self.get_relative_timeview_pos(current_time)
        self.time_bar.setPos(pos,0)

        # Ensure time bar is visible if scrollable
        self.ensure_time_bar_visible(pos)

        self.UI.lblCursorTime.setText(datetime.fromtimestamp(current_time).strftime('%d-%m-%Y %H:%M:%S'))

    def ensure_time_bar_visible(self, pos):
        if self.UI.scrollTimeline.isVisible():
            max_visible_x = self.UI.graphTimeline.mapToScene(self.UI.graphTimeline.rect()).boundingRect().x() \
                            + self.UI.graphTimeline.mapToScene(self.UI.graphTimeline.rect()).boundingRect().width()
            min_visible_x = self.UI.graphTimeline.mapToScene(self.UI.graphTimeline.rect()).boundingRect().x()
            if pos < min_visible_x or pos > max_visible_x:
                self.UI.scrollTimeline.setValue(pos)

    @pyqtSlot(datetime, datetime)
    def graph_zoom_area(self, start_time, end_time):
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.zoomAreaRequestTime(start_time, end_time)

    @pyqtSlot()
    def graph_zoom_reset(self):
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.zoomResetRequest(False)

    @pyqtSlot(float, float)
    def graph_selected_area_changed(self, start_timestamp, end_timestamp):
        # Update timeview selection area
        start_pos = self.get_relative_timeview_pos(start_timestamp / 1000)
        end_pos = self.get_relative_timeview_pos(end_timestamp / 1000)
        self.timeview_selected(start_pos, end_pos)

        # Ensure time bar is visible if scrollable
        self.ensure_time_bar_visible(start_pos)

        # Update selection for each graph
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.setSelectionAreaFromTime(start_timestamp, end_timestamp)

    @pyqtSlot(int)
    def timeview_scroll(self, pos):
        self.UI.graphTimeline.centerOn(pos / self.zoom_level, 0)

    @pyqtSlot(float)
    def timeview_clicked(self, x):
        self.time_bar.setPos(x, 0)
        if len(self.recordsets)==0:
            return

        # Find time corresponding to that position
        timestamp = self.get_time_from_timeview_pos(x)
        self.UI.lblCursorTime.setText(timestamp.strftime('%d-%m-%Y %H:%M:%S'))

        for graph in self.sensors_graphs.values():
            if graph is not None:
                # try:
                graph.setCursorPositionFromTime(timestamp, False)
            # except AttributeError:
            #    continue

    @pyqtSlot(float, float)
    def timeview_selected(self, start_x, end_x):
        selection_brush = QBrush(QColor(153, 204, 255, 128))
        selection_pen = QPen(Qt.transparent)
        self.timeScene.removeItem(self.selection_rec)
        self.selection_rec = self.timeScene.addRect(start_x, 20, end_x-start_x, self.timeScene.height()-20,
                                                    selection_pen, selection_brush)

        self.UI.btnClearSelection.setEnabled(True)
        self.UI.btnTimeZoomSelection.setEnabled(True)

        # Update selection for each graph
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.setSelectionAreaFromTime(self.get_time_from_timeview_pos(start_x),
                                               self.get_time_from_timeview_pos(end_x))

    @pyqtSlot()
    def on_timeview_clear_selection_requested(self):
        self.timeScene.removeItem(self.selection_rec)
        self.UI.btnClearSelection.setEnabled(False)
        self.UI.btnTimeZoomSelection.setEnabled(False)

        # Clear all selected areas in graphs
        for graph in self.sensors_graphs.values():
            graph.clearSelectionArea()

    @pyqtSlot()
    def on_timeview_zoom_selection_requested(self):
        self.UI.graphTimeline.scale(1 / self.zoom_level, 1)
        # zoom_value = (self.timeScene.width() / (self.selection_rec.rect().width()))
        zoom_value = (self.UI.graphTimeline.width() / (self.selection_rec.rect().width()))
        self.zoom_level = zoom_value
        self.UI.graphTimeline.scale(zoom_value, 1)
        self.UI.btnZoomReset.setEnabled(True)
        self.adjust_timeview_size()
        # self.UI.graphTimeline.ensureVisible(self.selection_rec.rect(), 0, 0)
        # self.UI.graphTimeline.centerOn(self.selection_rec.rect().x() + self.selection_rec.rect().width() / 2, 0)
        self.UI.scrollTimeline.setValue((self.selection_rec.rect().x() + self.selection_rec.rect().width() / 2)
                                        * self.zoom_level)
        self.on_timeview_clear_selection_requested()

    @pyqtSlot()
    def on_timeview_zoom_reset_requested(self):
        self.UI.graphTimeline.scale(1 / self.zoom_level, 1)
        self.zoom_level = 1
        self.UI.btnZoomReset.setEnabled(False)
        self.adjust_timeview_size()
        self.UI.scrollTimeline.setValue(0)

    @pyqtSlot()
    def on_timeview_show_hide_requested(self):
        visible = not self.UI.frameTimeline.isVisible()
        self.UI.frameTimeline.setVisible(visible)
        self.UI.frameTimelineControls.setVisible(visible)
        # self.UI.lblCursorTime.setVisible(visible)

    @pyqtSlot()
    def on_process_recordset(self):
        # Display Process Window
        window = ProcessSelectWindow(self.dbMan, self.recordsets)
        window.setStyleSheet(self.styleSheet())

        if window.exec() == QDialog.Accepted:
            self.dataUpdateRequest.emit("result", window.processed_data)
            self.dataDisplayRequest.emit("result", window.processed_data.id_processed_data)

    @pyqtSlot()
    def tile_graphs_horizontally(self):
        self.tile_graphs(True)

    @pyqtSlot()
    def tile_graphs_vertically(self):
        self.tile_graphs(False)

    def tile_graphs(self, horizontal: bool):
        if self.UI.mdiArea.subWindowList() is None:
            return

        position = QPoint(0, 0)

        for window in self.UI.mdiArea.subWindowList():
            if horizontal:
                rect = QRect(0, 0, self.UI.mdiArea.width() / len(self.UI.mdiArea.subWindowList()),
                             self.UI.mdiArea.height())
            else:
                rect = QRect(0, 0, self.UI.mdiArea.width(),
                             self.UI.mdiArea.height() / len(self.UI.mdiArea.subWindowList()))
            window.setGeometry(rect)
            window.move(position)
            if horizontal:
                position.setX(position.x() + window.width())
            else:
                position.setY(position.y() + window.height())

    @pyqtSlot()
    def tile_graphs_auto(self):
        self.UI.mdiArea.tileSubWindows()
Beispiel #7
0
class painter(QGraphicsView):
    narrowRatio = int(sys.argv[4]) if len(sys.argv) >= 5 else 1
    useBlur = sys.argv[5] != "False" if len(sys.argv) >= 6 else True
    pixelSize = int(15 / narrowRatio)
    width = int(480 / narrowRatio)
    height = int(360 / narrowRatio)
    fontSize = int(30 / narrowRatio)
    anchorLineSize = int(100 / narrowRatio)
    ellipseRadius = int(8 / narrowRatio)
    textInterval = int(90 / narrowRatio)
    col = width / pixelSize
    line = height / pixelSize
    centerIndex = int(round(((line / 2 - 1) * col) + col / 2))
    frameCount = 0
    baseZValue = 0
    textLineHeight = fontSize + 10
    blurRaduis = 50  # Smoother improvement

    def __init__(self):
        super(painter, self).__init__()
        self.setFixedSize(self.width, self.height + self.textLineHeight)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        # center het text item
        self.centerTextItem = QGraphicsTextItem()
        self.centerTextItem.setPos(self.width / 2 - self.fontSize, 0)
        self.centerTextItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.centerTextItem)
        # center anchor item
        centerX = self.width / 2
        centerY = self.height / 2
        self.ellipseItem = QGraphicsEllipseItem(0, 0, self.ellipseRadius * 2,
                                                self.ellipseRadius * 2)
        self.horLineItem = QGraphicsLineItem(0, 0, self.anchorLineSize, 0)
        self.verLineItem = QGraphicsLineItem(0, 0, 0, self.anchorLineSize)
        self.ellipseItem.setPos(centerX - self.ellipseRadius,
                                centerY - self.ellipseRadius)
        self.horLineItem.setPos(centerX - self.anchorLineSize / 2, centerY)
        self.verLineItem.setPos(centerX, centerY - self.anchorLineSize / 2)
        self.ellipseItem.setPen(QColor(Qt.white))
        self.horLineItem.setPen(QColor(Qt.white))
        self.verLineItem.setPen(QColor(Qt.white))
        self.ellipseItem.setZValue(self.baseZValue + 1)
        self.horLineItem.setZValue(self.baseZValue + 1)
        self.verLineItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.ellipseItem)
        self.scene.addItem(self.horLineItem)
        self.scene.addItem(self.verLineItem)
        # camera item
        self.cameraBuffer = QPixmap(self.width,
                                    self.height + self.textLineHeight)
        self.cameraItem = QGraphicsPixmapItem()
        if self.useBlur:
            self.gusBlurEffect = QGraphicsBlurEffect()
            self.gusBlurEffect.setBlurRadius(self.blurRaduis)
            self.cameraItem.setGraphicsEffect(self.gusBlurEffect)
        self.cameraItem.setPos(0, 0)
        self.cameraItem.setZValue(self.baseZValue)
        self.scene.addItem(self.cameraItem)
        # het text item
        self.hetTextBuffer = QPixmap(self.width, self.textLineHeight)
        self.hetTextItem = QGraphicsPixmapItem()
        self.hetTextItem.setPos(0, self.height)
        self.hetTextItem.setZValue(self.baseZValue)
        self.scene.addItem(self.hetTextItem)

    def draw(self):
        if len(hetaData) == 0:
            return
        font = QFont()
        color = QColor()
        font.setPointSize(self.fontSize)
        font.setFamily("Microsoft YaHei")
        font.setLetterSpacing(QFont.AbsoluteSpacing, 0)
        index = 0
        lock.acquire()
        frame = hetaData.pop(0)
        lock.release()
        maxHet = frame["maxHet"]
        minHet = frame["minHet"]
        frame = frame["frame"]
        p = QPainter(self.cameraBuffer)
        p.fillRect(0, 0, self.width, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))
        # draw camera
        color = QColor()
        for yIndex in range(int(self.height / self.pixelSize)):
            for xIndex in range(int(self.width / self.pixelSize)):
                tempData = constrain(
                    mapValue(frame[index], minHet, maxHet, minHue, maxHue),
                    minHue, maxHue)
                color.setHsvF(tempData / 360, 1.0, 1.0)
                p.fillRect(xIndex * self.pixelSize, yIndex * self.pixelSize,
                           self.pixelSize, self.pixelSize, QBrush(color))
                index = index + 1
        self.cameraItem.setPixmap(self.cameraBuffer)
        # draw text
        p = QPainter(self.hetTextBuffer)
        p.fillRect(0, 0, self.width, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))
        hetDiff = maxHet - minHet
        bastNum = round(minHet)
        interval = round(hetDiff / 5)
        for i in range(5):
            hue = constrain(
                mapValue((bastNum + (i * interval)), minHet, maxHet, minHue,
                         maxHue), minHue, maxHue)
            color.setHsvF(hue / 360, 1.0, 1.0)
            p.setPen(color)
            p.setFont(font)
            p.drawText(i * self.textInterval, self.fontSize + 3,
                       str(bastNum + (i * interval)) + "°")
        self.hetTextItem.setPixmap(self.hetTextBuffer)
        # draw center het text
        cneter = round(frame[self.centerIndex], 1)
        centerText = "<font color=white>%s</font>"
        self.centerTextItem.setFont(font)
        self.centerTextItem.setHtml(centerText % (str(cneter) + "°"))
        self.frameCount = self.frameCount + 1
        print("picture->" + str(self.frameCount))
Beispiel #8
0
class RotaryDialHoverRegion(QGraphicsEllipseItem):
    def __init__(self, rect, parent=None):
        # setup DNA line
        super(QGraphicsEllipseItem, self).__init__(rect, parent)
        self._parent = parent
        self.setPen(QPen(Qt.NoPen))
        self.setBrush(_HOVER_BRUSH)
        self.setAcceptHoverEvents(True)

        # hover marker
        self._hoverLine = QGraphicsLineItem(-_ROTARY_DELTA_WIDTH/2, 0, _ROTARY_DELTA_WIDTH/2, 0, self)
        self._hoverLine.setPen(QPen(QColor(204, 0, 0), .5))
        self._hoverLine.hide()

        self._startPos = None
        self._startAngle = None  # save selection start
        self._clockwise = None
        self.dummy = RotaryDialDeltaItem(0, 0, parent)
        self.dummy.hide()

    def updateRect(self, rect):
        self.setRect(rect)

    def hoverEnterEvent(self, event):
        self.updateHoverLine(event)
        self._hoverLine.show()
    # end def

    def hoverMoveEvent(self, event):
        self.updateHoverLine(event)
    # end def

    def hoverLeaveEvent(self, event):
        self._hoverLine.hide()
    # end def

    def mousePressEvent(self, event):
        r = _RADIUS
        self.updateHoverLine(event)
        pos = self._hoverLine.pos()
        aX, aY, angle = self.snapPosToCircle(pos, r)
        if angle != None:
            self._startPos = QPointF(aX, aY)
            self._startAngle = self.updateHoverLine(event)
            self.dummy.updateAngle(self._startAngle, 0)
            self.dummy.show()
        # mark the start
        # f = QGraphicsEllipseItem(pX, pY, 2, 2, self)
        # f.setPen(QPen(Qt.NoPen))
        # f.setBrush(QBrush(QColor(204, 0, 0)))
    # end def

    def mouseMoveEvent(self, event):
        eventAngle = self.updateHoverLine(event)
        # Record initial direction before calling getSpanAngle
        if self._clockwise is None:
            self._clockwise = False if eventAngle > self._startAngle else True
        spanAngle = self.getSpanAngle(eventAngle)
        self.dummy.updateAngle(self._startAngle, spanAngle)
    # end def

    def mouseReleaseEvent(self, event):
        self.dummy.hide()
        endAngle = self.updateHoverLine(event)
        spanAngle = self.getSpanAngle(endAngle)
        old_angle = self._parent.virtualHelix().getProperty('eulerZ')
        new_angle = round((old_angle - spanAngle) % 360,0)
        self._parent.virtualHelix().setProperty('eulerZ', new_angle)

        # mark the end
        # x = self._hoverLine.x()
        # y = self._hoverLine.y()
        # f = QGraphicsEllipseItem(x, y, 6, 6, self)
        # f.setPen(QPen(Qt.NoPen))
        # f.setBrush(QBrush(QColor(204, 0, 0, 128)))
    # end def

    def updateHoverLine(self, event):
        """
        Moves red line to point (aX,aY) on RotaryDialLine closest to event.pos.
        Returns the angle of aX, aY, using the Qt arc coordinate system
        (0 = east, 90 = north, 180 = west, 270 = south).
        """
        r = _RADIUS
        aX, aY, angle = self.snapPosToCircle(event.pos(), r)
        if angle != None:
            self._hoverLine.setPos(aX, aY)
            self._hoverLine.setRotation(-angle)
        return angle
    # end def

    def snapPosToCircle(self, pos, radius):
        """Given x, y and radius, return x,y of nearest point on circle, and its angle"""
        pX = pos.x()
        pY = pos.y()
        cX = cY = radius
        vX = pX - cX
        vY = pY - cY
        magV = sqrt(vX*vX + vY*vY)
        if magV == 0:
            return (None, None, None)
        aX = cX + vX / magV * radius
        aY = cY + vY / magV * radius
        angle = (atan2(aY-cY, aX-cX))
        deg = -degrees(angle) if angle < 0 else 180+(180-degrees(angle))
        return (aX, aY, deg)
    # end def

    def getSpanAngle(self, angle):
        """
        Return the spanAngle angle by checking the initial direction of the selection.
        Selections that cross 0° must be handed as an edge case.
        """
        if self._clockwise: # spanAngle is negative
            if angle < self._startAngle:
                spanAngle = angle - self._startAngle
            else:
                spanAngle = -(self._startAngle + (360-angle))
        else: # counterclockwise, spanAngle is positive
            if angle > self._startAngle:
                spanAngle = angle - self._startAngle
            else:
                spanAngle = (360-self._startAngle) + angle
        return spanAngle
Beispiel #9
0
class painter(QGraphicsView):
    pixelSize = int(15 / narrowRatio)
    width = int(480 / narrowRatio)
    height = int(360 / narrowRatio)
    fontSize = int(30 / narrowRatio)
    anchorLineSize = int(100 / narrowRatio)
    ellipseRadius = int(8 / narrowRatio)
    textInterval = int(90 / narrowRatio)
    col = width / pixelSize
    line = height / pixelSize
    centerIndex = int(round(((line / 2 - 1) * col) + col / 2))
    frameCount = 0
    baseZValue = 0
    mode = 1
    body = 1
    open_status = 0
    textLineHeight = fontSize + 10
    blurRaduis = 50  # Smoother improvement

    def __init__(self, dataThread):
        super(painter, self).__init__()
        self.dataThread = dataThread
        self.setFixedSize(self.width, self.height + self.textLineHeight)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        # center het text item
        self.centerTextItem = QGraphicsTextItem()
        self.centerTextItem.setPos(self.width / 2 - self.fontSize, 0)
        self.centerTextItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.centerTextItem)
        # center anchor item
        centerX = self.width / 2
        centerY = self.height / 2
        self.ellipseItem = QGraphicsEllipseItem(0, 0, self.ellipseRadius * 2,
                                                self.ellipseRadius * 2)
        self.horLineItem = QGraphicsLineItem(0, 0, self.anchorLineSize, 0)
        self.verLineItem = QGraphicsLineItem(0, 0, 0, self.anchorLineSize)
        self.ellipseItem.setPos(centerX - self.ellipseRadius,
                                centerY - self.ellipseRadius)
        self.horLineItem.setPos(centerX - self.anchorLineSize / 2, centerY)
        self.verLineItem.setPos(centerX, centerY - self.anchorLineSize / 2)
        self.ellipseItem.setPen(QColor(Qt.white))
        self.horLineItem.setPen(QColor(Qt.white))
        self.verLineItem.setPen(QColor(Qt.white))
        self.ellipseItem.setZValue(self.baseZValue + 1)
        self.horLineItem.setZValue(self.baseZValue + 1)
        self.verLineItem.setZValue(self.baseZValue + 1)
        self.scene.addItem(self.ellipseItem)
        self.scene.addItem(self.horLineItem)
        self.scene.addItem(self.verLineItem)
        # camera item
        self.cameraBuffer = QPixmap(self.width,
                                    self.height + self.textLineHeight)
        self.cameraItem = QGraphicsPixmapItem()
        if useBlur:
            self.gusBlurEffect = QGraphicsBlurEffect()
            self.gusBlurEffect.setBlurRadius(self.blurRaduis)
            self.cameraItem.setGraphicsEffect(self.gusBlurEffect)
        self.cameraItem.setPos(0, 0)
        self.cameraItem.setZValue(self.baseZValue)
        self.scene.addItem(self.cameraItem)
        # het text item
        self.hetTextBuffer = QPixmap(self.width, self.textLineHeight)
        self.hetTextItem = QGraphicsPixmapItem()
        self.hetTextItem.setPos(0, self.height)
        self.hetTextItem.setZValue(self.baseZValue)
        self.scene.addItem(self.hetTextItem)
        # button item
        self.ctrlOpenButton = QPushButton('Open', self)
        self.ctrlOpenButton.clicked.connect(self.ctrl_open)
        self.ctrlOpenButton.setGeometry(10, 30, 100, 40)
        '''
        self.ctrlCloseButton = QPushButton('stop send',self)
        self.ctrlCloseButton.clicked.connect(self.ctrl_close)
        self.ctrlCloseButton.setGeometry(10,80,100,40)
        '''
        self.getOnePicButton = QPushButton('send a frame', self)
        self.getOnePicButton.clicked.connect(self.ctrl_sendone)
        self.getOnePicButton.setGeometry(10, 130, 100, 40)
        self.getOnePicButton.setEnabled(False)

        self.modeManualButton = QPushButton('Auto', self)
        self.modeManualButton.clicked.connect(self.mode_manual)
        self.modeManualButton.setGeometry(10, 180, 100, 40)

        self.modeObjButton = QPushButton('Body', self)
        self.modeObjButton.clicked.connect(self.obj_body)
        self.modeObjButton.setGeometry(10, 230, 100, 40)
        '''
        self.modeAutoButton = QPushButton('mode: auto',self)
        self.modeAutoButton.clicked.connect(self.mode_auto)
        self.modeAutoButton.setGeometry(10,230,100,40)
        '''
        self.modeFpsButton = QPushButton('3fps', self)
        self.modeFpsButton.clicked.connect(self.rate_0)
        self.modeFpsButton.setGeometry(10, 280, 100, 40)

        self.blackbodyEdit = QLineEdit()
        self.blackbodyEdit.setGeometry(270, 200, 100, 40)
        self.blackbodyEdit.setText('37')

        self.calibrateButton = QPushButton(calibrateStr[0], self)
        self.calibrateButton.clicked.connect(self.calibrate_handle)
        self.calibrateButton.setGeometry(370, 280, 100, 40)
        '''
        self.modeAutoButton = QPushButton('1fps',self)
        self.modeAutoButton.clicked.connect(self.rate_1)
        self.modeAutoButton.setGeometry(35,280,50,40)

        self.modeAutoButton = QPushButton('2fps',self)
        self.modeAutoButton.clicked.connect(self.rate_2)
        self.modeAutoButton.setGeometry(60,280,50,40)

        self.modeAutoButton = QPushButton('3fps',self)
        self.modeAutoButton.clicked.connect(self.rate_3)
        self.modeAutoButton.setGeometry(85,280,50,40)
        '''
        '''
        self.modeAutoButton = QPushButton('obj: common',self)
        self.modeAutoButton.clicked.connect(self.obj_common)
        self.modeAutoButton.setGeometry(370,80,100,40)
        '''
        # self.modeAutoButton = QPushButton('version',self)
        # self.modeAutoButton.clicked.connect(self.sys_ver)
        # self.modeAutoButton.setGeometry(370,230,100,40)

    def ctrl_open(self):
        if self.open_status == 1:
            print('start send C command 0')
            self.open_status = 0

            self.ctrlOpenButton.setText("Open")
            self.dataThread.send_data('CMDC\0')
        else:
            print('start send C command 1')
            self.open_status = 1

            self.ctrlOpenButton.setText("Close")
            self.dataThread.send_data('CMDC\1')

    '''
    def ctrl_close(self):
        print('stop send')
        self.dataThread.send_data('CMDC\0')
    '''

    def ctrl_sendone(self):
        print('send a frame')
        self.dataThread.send_data('CMDC\2')

    def mode_manual(self):
        if self.mode == 1:
            self.getOnePicButton.setEnabled(True)
            self.modeManualButton.setText("Manual")
            self.dataThread.send_data('CMDM\0')
            self.mode = 0
            print('mode: manual')
        else:

            self.getOnePicButton.setEnabled(False)
            self.modeManualButton.setText("Auto")
            self.dataThread.send_data('CMDM\1')
            print('mode: auto')
            self.mode = 1

    def mode_auto(self):
        print('mode: auto')
        self.dataThread.send_data('CMDM\1')

    def stop_calibration(self):
        global calibration_offset
        calibration_start = False
        self.calibrateButton.setText(calibrateStr[0])
        if (calibration_frame_count):
            reply = QMessageBox.information(self, '信息',
                                            '校准很久都不行,模组是否没有预热20分钟呢?',
                                            QMessageBox.Yes)
        else:
            reply = QMessageBox.information(self, '信息', '校准已完成',
                                            QMessageBox.Yes)

    def calibrate_handle(self):
        global calibration_start
        global calibration_max_list
        global blackbody_temperature
        if calibration_start:
            calibration_start = False
            self.calibrateButton.setText(calibrateStr[0])
        else:
            calibration_max_list.clear()
            blackbody_temperature = float(self.blackbodyEdit.text())
            calibration_start = True
            print(" blackbody_temperature ", blackbody_temperature)
            self.calibrateButton.setText(calibrateStr[1])

    def rate_0(self):
        global btn_index
        btn_index = (btn_index + 1) % 4
        print('FPS:', strButton[btn_index])
        self.modeFpsButton.setText(strButton[btn_index])
        self.dataThread.send_data(strFpsCmd[btn_index])  #'CMDF\0')

    '''
    def rate_1(self):
        print('FPS:1') 
        self.dataThread.send_data('CMDF\1')
    def rate_2(self):
        print('FPS:2') 
        self.dataThread.send_data('CMDF\2')
    def rate_3(self):
        print('FPS:3') 
        self.dataThread.send_data('CMDF\3')
    '''

    def obj_body(self):
        if self.body == 1:
            self.body = 0
            print('obj: Object')
            self.modeObjButton.setText("Object")
            self.dataThread.send_data('CMDO\0')
        else:
            self.body = 1
            print('obj: Human Body')
            self.modeObjButton.setText("Body")
            self.dataThread.send_data('CMDO\1')

    '''
    def obj_common(self):
        print('obj: common') 
        self.dataThread.send_data('CMDO\1')
    def sys_slp(self):
        print('sleep')
        self.dataThread.send_data('CMDS\1')
    '''

    def draw(self):
        if len(hetaData) == 0:
            return
        font = QFont()
        color = QColor()
        font.setPointSize(self.fontSize)
        font.setFamily("Microsoft YaHei")
        font.setLetterSpacing(QFont.AbsoluteSpacing, 0)
        index = 0
        lock.acquire()
        frame = hetaData.pop(0)
        lock.release()
        p = QPainter(self.cameraBuffer)
        p.fillRect(0, 0, self.width, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))
        # draw camera
        color = QColor()
        for yIndex in range(int(self.height / self.pixelSize)):
            for xIndex in range(int(self.width / self.pixelSize)):
                color.setHsvF(frame[index] / 360, 1.0, 1.0)
                p.fillRect(xIndex * self.pixelSize, yIndex * self.pixelSize,
                           self.pixelSize, self.pixelSize, QBrush(color))
                index = index + 1
        self.cameraItem.setPixmap(self.cameraBuffer)
        # draw text
        p = QPainter(self.hetTextBuffer)
        p.fillRect(0, 0, self.width, self.height + self.textLineHeight,
                   QBrush(QColor(Qt.black)))
        hetDiff = maxHet - minHet
        bastNum = round(minHet)
        interval = round(hetDiff / 5)
        for i in range(5):
            hue = constrain(
                mapValue((bastNum + (i * interval)), minHet, maxHet, minHue,
                         maxHue), minHue, maxHue)
            color.setHsvF(hue / 360, 1.0, 1.0)
            p.setPen(color)
            p.setFont(font)
            p.drawText(i * self.textInterval, self.fontSize + 3,
                       str(bastNum + (i * interval)) + "°")
        self.hetTextItem.setPixmap(self.hetTextBuffer)
        # draw center het text
        cneter = round(
            mapValue(frame[self.centerIndex], minHue, maxHue, minHet, maxHet),
            1)
        centerText = "<font color=white>%s</font>"
        self.centerTextItem.setFont(font)
        self.centerTextItem.setHtml(centerText % (str(cneter) + "°"))
        self.frameCount = self.frameCount + 1
        print("picture->" + str(self.frameCount))
Beispiel #10
0
 def _set_line(line: QGraphicsLineItem, x1, y1, x2, y2):
     """Helper to set `line` ends to (x1, y1) and (x2, y2)"""
     """setLine should set to 0,0 first, then call setPos. 
     Otherwise it messes the scene coordinate system."""
     line.setLine(0, 0, x2 - x1, y2 - y1)
     line.setPos(QPointF(x1, y1))