Ejemplo n.º 1
0
class ImageView(QGraphicsView):
    def __init__(self, mode):
        # parameter
        self.mode = mode

        # create scene
        self.scene = QGraphicsScene()
        super().__init__(self.scene)
        self.setScene(self.scene)

        # use in draw sequence
        # - items : Scene 에 추가된 item list
        # - 임시 item 들은 obj에 관리된다.
        self.items = []
        self.obj = {}  # View 출력을 위한 임시 저장장소
        self._object_reset()

        self.rect_p0 = None
        self.rect_p1 = None
        self.select = []

        # use in data load
        self.image = None
        self.pixmap = None
        self.image_item = None
        self.metadata = None

        # use in key event
        self._zoom = 0
        self.KEY_SHIFT = False
        self.KEY_ALT = False
        self.KEY_CTRL = False
        self.KEY_MOUSE_LEFT = False

        # backup
        self.last_mask = None
        self.last_polygon = None

        # QGraphicsView setting
        self.setDragMode(self.mode.VIEW_DRAG_MODE)
        self.setMouseTracking(True)

        # remove scrollbar option
        if not self.mode.SCROLLBAR_VIEW:
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def load_image(self, image, metadata):
        self.reset()
        self.image = image

        # Qimage 를 가져온다.
        image = self.image.get_image()

        # pixmap data 생성
        pixmap = QPixmap(image)

        self.pixmap = pixmap
        self.image_item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(self.image_item)

        self._load_metadata(metadata)

    def refresh(self):
        """ 현재 작업중인 임시 정보를 모두 삭제하고, 현재 설정값을 재설정한다.

        """
        # Object 초기화
        self._object_reset()

        # Mode 설정
        self.setDragMode(self.mode.VIEW_DRAG_MODE)

        # Data Reset
        self.rect_p0 = None
        self.rect_p1 = None
        self.select.clear()

        # Key 초기화
        self.KEY_SHIFT = False
        self.KEY_ALT = False
        self.KEY_MOUSE_LEFT = False

        # Mask Draw
        self._mask_draw()

        # update
        self._update()

    def reset(self):
        """ 이미지 정보를 포함하여 모든 정보를 삭제한다.

        """
        # Scene 에 표시되는 물체들을 제거한다.
        self._delete_items(self.items)
        self.scene.removeItem(self.image_item)

        # backup 초기화
        self.last_mask = None
        self.last_polygon = None

        # image 정보 초기화
        self.image = None
        self.pixmap = None
        self.image_item = None
        self.metadata = None

        # refresh
        self.refresh()

    def restore(self):
        print('restore')
        if self.last_mask is not None and self.image is not None:
            self.image.restore_mask(self.last_mask)
            if self.last_polygon is not None:
                self._polygon_delete(self.last_polygon)
            print('1')

            self.last_mask = None
            self.last_polygon = None
            self._mask_draw()

    def callback_selected(self, e, item):
        """ Image Item 객체가 선택되었을 때, View 에 직접 호출 할 수 있는 함수

            Image Item 객체의 event 함수에서 호출된다.
        """
        pass

    def callback_polygon_double_click(self, polygon_item):
        if self.KEY_CTRL and self.mode.CURRENT == 0:
            # delete polygon
            # 1. remove text item
            if polygon_item.text_item is not None:
                self.items.remove(polygon_item.text_item)
                self.scene.removeItem(polygon_item.text_item)

            # 2. remove polygon
            self.items.remove(polygon_item)
            self.scene.removeItem(polygon_item)
        elif self.KEY_CTRL:
            print('2')
            self._polygon_delete(polygon_item)

    def callback_polygon_hover_enter(self, polygon_item):
        if self.mode.CURRENT == 0:
            self.setDragMode(QGraphicsView.NoDrag)

    def callback_polygon_hover_move(self, polygon_item):
        if self.mode.CURRENT == 0:
            self.setDragMode(QGraphicsView.NoDrag)

    def callback_polygon_hover_leave(self, polygon_item):
        if self.mode.CURRENT == 0:
            self.setDragMode(self.mode.VIEW_DRAG_MODE)

    def _load_metadata(self, metadata):
        """ Image Annotation 을 읽어와 View 에 출력한다.


     """
        self.metadata = metadata
        polygons = metadata.out_polygons_to_list()
        for polygon in polygons:
            [attribute, x, y, id] = polygon
            assert len(x) == len(y), "Invalid polygon information in metadata"
            qpol = QPolygonF()
            for idx in range(len(x)):
                qpol.append(QPointF(x[idx], y[idx]))

            self._polygon_draw(qpol, attribute, id)

    def _update(self):
        pass

    def _delete_items(self, items):
        for item in items:
            self.scene.removeItem(item)
        items.clear()

    def _object_reset(self):
        """ Object 를 초기화한다.

            obj Dictionary 에는 view 그리기에 필요한 임시값들이 저장되어있다.
        """
        # polygon : 현재 작성중인 polygon 좌표들을 QPointF list 형태로 가지고 있는다.
        if 'polygon' not in self.obj:
            self.obj['polygon'] = []
        else:
            self.obj['polygon'].clear()

        # lines : View 에 출력되는 직선들이다.
        if 'lines' not in self.obj:
            self.obj['lines'] = []
        else:
            self._delete_items(self.obj['lines'])
            self.obj['lines'].clear()

        # mask : magicwand mask
        if 'mask' in self.obj and self.obj['mask'] is not None:
            self.scene.removeItem(self.obj['mask'])
        self.obj['mask'] = None

        # paint sign
        if 'paint' in self.obj and self.obj['paint'] is not None:
            self.scene.removeItem(self.obj['paint'])
        self.obj['paint'] = None

    def _polygon_check(self, polygon_list):
        """ polygon 의 시작 위치와 종료 위치를 이용하여 생성 조건을 반환한다.

        """
        if polygon_list is None or len(polygon_list) < 3:
            return False

        # 거리 계산
        dx = polygon_list[-1].x() - polygon_list[0].x()
        dy = polygon_list[-1].y() - polygon_list[0].y()
        d = dx * dx + dy * dy

        if d < self.mode.POLYGON_END_THRESHOLD:
            # 마지막 위치 수정
            del (polygon_list[-1])
            polygon_list.append(polygon_list[0])
            return True
        else:
            return False

    def _polygon_draw(self, polygon, attribute, id=-1):
        """ polygon 을 그린다.

            polygon 객체를 인수로 받아서 scene 에 추가한다.
        """
        # Call by Value
        attribute = attribute.copy()

        pen = QPen(self.mode.DRAW_PEN_COLOR, 3)
        if attribute['name'] in self.mode.POLYGON_BRUSH_COLOR:
            brush = QBrush(self.mode.POLYGON_BRUSH_COLOR[attribute['name']])
        else:
            brush = QBrush(self.mode.DRAW_BRUSH_COLOR)

        # polygon_item 생성
        polygon_item = PolygonItem(self, polygon, attribute, id)
        polygon_item.setPen(pen)
        polygon_item.setBrush(brush)

        # scene 에 추가
        self.items.append(polygon_item)
        self.scene.addItem(polygon_item)

        # polygon location
        self._polygon_location(polygon_item)

        # QGraphicPolygonItem 반환
        return polygon_item

    def _polygon_location(self, polygon_item):
        polygon = polygon_item.polygon
        attribute = polygon_item.attribute

        # Set text location
        text_locate, compare_list_y = [], []

        for i in range(len(polygon) - 1):
            compare_list_y.append(polygon[i].toPoint().y())
        top_of_polygon_y = min(compare_list_y)
        index = compare_list_y.index(top_of_polygon_y)

        text_locate.append(polygon[index].toPoint().x())
        text_locate.append(polygon[index].toPoint().y())
        text_locate[0] = text_locate[0] - 5
        text_locate[1] = text_locate[1] - 5

        # add text item
        if 'name' not in attribute:
            attribute['name'] = 'none'
        item = self.scene.addText(attribute['name'], QFont('Arial', 10))
        self.items.append(item)
        polygon_item.text_item = item
        item.setPos(text_locate[0], text_locate[1])

    def _polygon_add_info(self, polygon_item):
        """ polygon 을 metadata 에 추가한다.

        """
        region_attribute = polygon_item.attribute
        polygon = polygon_item.polygon

        xs = []
        ys = []
        for point in polygon:
            xs.append(int(point.x()))
            ys.append(int(point.y()))
        polygon_item.id = self.metadata.add_polygon(region_attribute, xs, ys)

    def _polygon_delete(self, polygon_item):
        # delete polygon
        # 1. remove metadata
        print('0')
        print(polygon_item.id)
        self.metadata.delete_polygon(polygon_item.id)

        # 2. remove text item
        if polygon_item.text_item is not None:
            self.items.remove(polygon_item.text_item)
            self.scene.removeItem(polygon_item.text_item)

        # 3. remove polygon
        self.items.remove(polygon_item)
        self.scene.removeItem(polygon_item)

    def _mask_draw(self):
        if self.image is None:
            return

        # QBitmap 생성
        bitmap = self.image.get_mask()

        # QPixmap 생성
        pixmap = QPixmap(self.pixmap)
        pixmap.fill(self.mode.DRAW_MASK_COLOR)

        # pixmap 에 Mask를 씌운다.
        pixmap.setMask(bitmap)

        # Item 생성 및 추가
        if self.obj['mask'] is not None:
            self.scene.removeItem(self.obj['mask'])
        self.obj['mask'] = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(self.obj['mask'])

    def _mask_reset(self):
        # Reset Mask
        if self.image is not None:
            self.image.reset_mask()

    def _paint_draw_sign(self, x, y):
        # draw paint sign
        brush = QBrush(self.mode.DRAW_MASK_COLOR
                       ) if self.mode.DRAW_PAINT_MODE else QBrush(
                           QColor(255, 255, 255, 50))
        pen = QPen(QColor(0, 0, 0), 3)

        # Item 생성 및 추가
        width = self.mode.DRAW_PAINT_WIDTH
        if self.obj['paint'] is not None:
            self.scene.removeItem(self.obj['paint'])
        self.obj['paint'] = QGraphicsEllipseItem(int(x - width / 2),
                                                 int(y - width / 2), width,
                                                 width)
        self.obj['paint'].setBrush(brush)
        self.obj['paint'].setPen(pen)
        self.scene.addItem(self.obj['paint'])

    def _draw_sequence_press(self, pos, out_of_range):
        """ view 에 item 들을 그린다.

            mode 로 view 에 그리는 방법을 다르게 설정 할 수 있다.
            press, move, release sequence 함수들은 서로 의존적이다.
            mousePressEvent 에서 호출된다.
        """
        if out_of_range:
            return

        last_pos = self.rect_p0
        self.rect_p0 = pos

        # Mode 1. polygon draw
        if self.mode.CURRENT == 1:
            # 새로운 위치를 지정 및 기억한다.
            polygon_list = self.obj['polygon']
            polygon_list.append(pos)

            # 조건을 확인하여 polygon 을 그린다.
            if self._polygon_check(polygon_list):
                # polygon list 를 이용하여 QPolygonF 객체 생성
                polygon = QPolygonF([QPointF(point) for point in polygon_list])

                # polygon 을 그린다.
                polygon_item = self._polygon_draw(
                    polygon, self.mode.POLYGON_CURRENT_ATTRIBUTE)

                # metadata 추가 / id  할당
                self._polygon_add_info(polygon_item)

                # polygon list 정보 삭제
                polygon_list.clear()

                # lines 삭제
                self._delete_items(self.obj['lines'])

                # 좌표 초기화
                self.rect_p0 = None
                self.rect_p1 = None

            elif self.rect_p1 != None:
                # 임시 표시 직선을 그린다.
                pen = QPen(self.mode.DRAW_PEN_COLOR, self.mode.DRAW_PEN_WIDTH) if not out_of_range \
                    else QPen(self.mode.DRAW_PEN_COLOR_WARNNING, self.mode.DRAW_PEN_WIDTH)

                line = QLineF(self.rect_p0.x(), self.rect_p0.y(), last_pos.x(),
                              last_pos.y())
                self.obj['lines'].insert(0, self.scene.addLine(line, pen))

        # Mode 2. Magic Wand
        elif self.mode.CURRENT == 2:
            # option 설정
            if self.KEY_SHIFT and self.KEY_ALT:
                option = 'and'
            elif self.KEY_SHIFT:
                option = 'or'
            elif self.KEY_SHIFT:
                option = 'sub'
            else:
                option = 'select'

            # 현재 point mask 생성
            self.image.set_tolerance(self.mode.DRAW_MASK_TOLERANCE)
            self.image.set_mask(int(pos.x()), int(pos.y()), option=option)

            # mask 를 그린다.
            self._mask_draw()

        # Mode 3. Paint
        elif self.mode.CURRENT == 3:
            # paint or erase
            if self.mode.DRAW_PAINT_MODE:
                self.image.paint_mask(int(pos.x()), int(pos.y()),
                                      self.mode.DRAW_PAINT_WIDTH)
            else:
                self.image.erase_mask(int(pos.x()), int(pos.y()),
                                      self.mode.DRAW_PAINT_WIDTH)
            self._mask_draw()
            self._paint_draw_sign(int(pos.x()), int(pos.y()))

    def _draw_sequence_move(self, pos, out_of_range):
        """ view 에 item 들을 그린다.

            mouseMoveEvent 에서 호출된다.
        """

        # polygon draw
        if self.mode.CURRENT == 1:
            if self.rect_p0 is None:
                return
            else:
                self.rect_p1 = pos

            # QPen 선택
            pen = QPen(self.mode.DRAW_PEN_COLOR, self.mode.DRAW_PEN_WIDTH) if not out_of_range \
                else QPen(self.mode.DRAW_PEN_COLOR_WARNNING, self.mode.DRAW_PEN_WIDTH)

            # 마지막에 그렸던 직선 삭제
            if len(self.obj['lines']) > 0:
                self.scene.removeItem(self.obj['lines'][-1])
                del (self.obj['lines'][-1])

            # 새로운 직선을 그린다
            line = QLineF(self.rect_p0.x(), self.rect_p0.y(), self.rect_p1.x(),
                          self.rect_p1.y())
            self.obj['lines'].append(self.scene.addLine(line, pen))

        elif self.mode.CURRENT == 3 and not out_of_range:
            # paint or erase
            if self.KEY_MOUSE_LEFT:
                if self.mode.DRAW_PAINT_MODE:
                    self.image.paint_mask(int(pos.x()), int(pos.y()),
                                          self.mode.DRAW_PAINT_WIDTH)
                else:
                    self.image.erase_mask(int(pos.x()), int(pos.y()),
                                          self.mode.DRAW_PAINT_WIDTH)

                self._mask_draw()
            self._paint_draw_sign(int(pos.x()), int(pos.y()))

    def _mouse_check(self, e):
        """ 현재 좌표와 좌표가 이미지 위에 위치하는지 여부를 반환한다.

            Image 가 할당된 이후에 호출될 수 있어야 한다.
            QMouseEvent 가 주어져야한다.
        """
        assert self.image_item is not None, "No image to check"

        # 마우스 위치를 Scene 좌표로 변환한다.
        pos = self.mapToScene(e.pos())

        # 변환된 Scene 좌표를 item 좌표로 변환한다.
        pos = self.image_item.mapFromScene(pos)

        # image item 좌표 범위를 QRectF 클래스로 받아온다.
        rect = self.image_item.boundingRect()

        # 좌표와 좌표 위치 정보 반환.
        return pos, not rect.contains(pos)

    def keyPressEvent(self, e):
        super().keyPressEvent(e)
        if self.image is None:
            return

        if e.key() == Qt.Key_Escape:
            self.last_mask = self.image.backup_mask()
            self._mask_reset()
            self.refresh()
        if e.key() == Qt.Key_Shift:
            self.KEY_SHIFT = True
            self.mode.DRAW_PAINT_MODE = not self.mode.DRAW_PAINT_MODE
        if e.key() == Qt.Key_Alt:
            self.KEY_ALT = True
        if e.key() == Qt.Key_Control:
            self.KEY_CTRL = True
        if e.key() == Qt.Key_Space and self.image is not None:
            # Mask To Polygon (with backup)
            self.last_mask = self.image.backup_mask()
            polygon = self.image.get_polygon()
            if polygon is not None:
                polygon_item = self._polygon_draw(
                    polygon, self.mode.POLYGON_CURRENT_ATTRIBUTE)
                self._polygon_add_info(polygon_item)
                self.last_polygon = polygon_item

                self._mask_reset()
                self.refresh()

    def keyReleaseEvent(self, e):
        if e.key() == Qt.Key_Shift:
            self.KEY_SHIFT = False
        if e.key() == Qt.Key_Alt:
            self.KEY_ALT = False
        if e.key() == Qt.Key_Control:
            self.KEY_CTRL = False

    def showEvent(self, e):
        self._update()
        super().showEvent(e)

    def wheelEvent(self, e):
        if self.KEY_CTRL:
            if self.mode.CURRENT == 3:
                pos, out_of_range = self._mouse_check(e)
                if not out_of_range:
                    # pain wheel
                    self._paint_draw_sign(int(pos.x()), int(pos.y()))
            return

        # zoom in / out 구현
        if e.angleDelta().y() > 0 and self._zoom < 10:
            self.scale(1.25, 1.25)
            self._zoom += 1
        elif e.angleDelta().y() < 0 and self._zoom > -10:
            self.scale(0.8, 0.8)
            self._zoom -= 1

    def mousePressEvent(self, e):
        # QGraphicsView.ScrollHandDrag middle mouse
        super().mousePressEvent(e)

        if self.KEY_CTRL:
            return

        # 좌표와 정보를 받아온다.
        if self.image_item is not None:
            pos, out_of_range = self._mouse_check(e)
        else:
            return

        # Reset Mask
        if self.mode.CURRENT not in [0, 2, 3]:
            self._mask_reset()
            self._mask_draw()

        # Left Button
        if e.button() == Qt.LeftButton:
            self.KEY_MOUSE_LEFT = True

            # 좌표를 이용하여 view 를 그린다.
            self._draw_sequence_press(pos, out_of_range)

    def mouseMoveEvent(self, e):
        super().mouseMoveEvent(e)

        # Left Button
        if self.image_item is not None:
            # 좌표와 정보를 받아온다.
            pos, out_of_range = self._mouse_check(e)

            # 좌표를 이용하여 view 를 그린다.
            self._draw_sequence_move(pos, out_of_range)

    def mouseReleaseEvent(self, e):
        super().mouseReleaseEvent(e)

        # 좌표와 정보를 받아온다.
        if self.image_item is not None:
            pos, out_of_range = self._mouse_check(e)
        else:
            return

        # Left Button
        if e.button() == Qt.LeftButton:
            self.KEY_MOUSE_LEFT = False
Ejemplo n.º 2
0
class HorizonApp(QtWidgets.QMainWindow, design.Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.initScene()

    def initScene(self):
        self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene(0, 0, 1033, 579)
        self.graphicsView.setScene(self.scene)
        self.scene.setBackgroundBrush(Qt.white)
        self.pen = QPen()
        self.pen.setWidth(1)
        self.pen.setColor(Qt.black)

        self.displayButton.clicked.connect(self.prepareForDrawing)

    def FloatHorizon(self, borders_x, x_step, borders_z, z_step, f, angles):
        global top, bottom
        # Инициализируем начальными значениями массивы горизонтов.
        top = [0] * WIDTH  # Верхний.
        bottom = [HEIGHT] * WIDTH  # Нижний.

        x_start = borders_x[0]
        x_end = borders_x[1]

        z_start = borders_z[0]
        z_end = borders_z[1]

        x_left, y_left = -1, -1
        x_right, y_right = -1, -1

        z = z_end
        while z >= z_start - z_step / 2:

            x_prev = x_start
            y_prev = f(x_start, z)
            x_prev, y_prev = transform(x_prev, y_prev, z, angles)

            flag_prev = Visible(x_prev, y_prev)
            #
            x_left, y_left = Side(x_prev, y_prev, x_left, y_left, self)
            x = x_start
            while x <= x_end + x_step / 2:
                y_curr = f(x, z)
                x_curr, y_curr = transform(x, y_curr, z, angles)
                # Проверка видимости текущей точки.
                flag_curr = Visible(x_curr, y_curr)
                # Равенство флагов означает, что обе точки находятся
                # Либо выше верхнего горизонта, либо ниже нижнего,
                # Либо обе невидимы.
                if flag_curr == flag_prev:
                    # Если текущая вершина выше верхнего горизонта
                    # Или ниже нижнего (Предыдущая такая же)
                    if flag_curr != 0:
                        # Значит отображаем отрезок от предыдущей до текущей.
                        self.scene.addLine(x_prev, y_prev, x_curr, y_curr)
                        Horizon(x_prev, y_prev, x_curr, y_curr)
                    # flag_curr == 0 означает, что и flag_prev == 0,
                    # А значит часть от flag_curr до flag_prev невидима. Ничего не делаем.
                else:
                    # Если видимость изменилась, то
                    # Вычисляем пересечение.
                    if flag_curr == 0:
                        if flag_prev == 1:
                            # Сегмент "входит" в верхний горизонт.
                            # Ищем пересечение с верхним горизонтом.
                            xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                  y_curr, top)
                        else:  # flag_prev == -1 (flag_prev нулю (0) не может быть равен, т.к. мы обработали это выше).
                            # Сегмент "входит" в нижний горизонт.
                            # Ищем пересечение с нижним горизонтом.
                            xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                  y_curr, bottom)
                        # Отображаем сегмент, от предыдущий точки, до пересечения.
                        self.scene.addLine(x_prev, y_prev, xi, yi)
                        Horizon(x_prev, y_prev, xi, yi)
                    else:
                        if flag_curr == 1:
                            if flag_prev == 0:
                                # Сегмент "выходит" из верхнего горизонта.
                                # Ищем пересечение с верхним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, top)
                                # Отображаем сегмент от пересечения до текущей точки.
                                self.scene.addLine(xi, yi, x_curr, y_curr)
                                Horizon(xi, yi, x_curr, y_curr)
                            else:  # flag_prev == -1
                                # Сегмент начинается с точки, ниже нижнего горизонта
                                # И заканчивается в точке выше верхнего горизонта.
                                # Нужно искать 2 пересечения.
                                # Первое пересечение с нижним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, bottom)
                                # Отображаем сегмент от предыдущей то пересечения.
                                self.scene.addLine(x_prev, y_prev, xi, yi)
                                Horizon(x_prev, y_prev, xi, yi)
                                # Второе пересечение с верхним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, top)
                                # Отображаем сегмент от пересечения до текущей.
                                self.scene.addLine(xi, yi, x_curr, y_curr)
                                Horizon(xi, yi, x_curr, y_curr)
                        else:  # flag_curr == -1
                            if flag_prev == 0:
                                # Сегмент "выходит" из нижнего горизонта.
                                # Ищем пересечение с нижним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, bottom)
                                self.scene.addLine(xi, yi, x_curr, y_curr)
                                Horizon(xi, yi, x_curr, y_curr)
                            else:
                                # Сегмент начинается с точки, выше верхнего горизонта
                                # И заканчивается в точке ниже нижнего горизонта.
                                # Нужно искать 2 пересечения.
                                # Первое пересечение с верхним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, top)
                                # Отображаем сегмент от предыдущей до пересечения.
                                self.scene.addLine(x_prev, y_prev, xi, yi)
                                Horizon(x_prev, y_prev, xi, yi)
                                # Ищем второе пересечение с нижним горизонтом.
                                xi, yi = Intersection(x_prev, y_prev, x_curr,
                                                      y_curr, bottom)
                                # Отображаем сегмент от пересечения до текущей.
                                self.scene.addLine(xi, yi, x_curr, y_curr)
                                Horizon(xi, yi, x_curr, y_curr)
                x_prev, y_prev = x_curr, y_curr
                flag_prev = flag_curr
                x += x_step
            x_right, y_right = Side(x_prev, y_prev, x_right, y_right, self)
            z -= z_step

    def prepareForDrawing(self):
        self.scene.clear()
        bordersForX = [self.xFrom.value(), self.xTo.value()]
        stepForX = self.xStep.value()

        bordersForX = [self.zFrom.value(), self.zTo.value()]
        stepForZ = self.zStep.value()

        angles = [
            self.rotateX.value(),
            self.rotateY.value(),
            self.rotateZ.value()
        ]

        function = checkFunc(self)

        self.FloatHorizon(bordersForX, stepForX, bordersForX, stepForZ,
                          function, angles)
class CircuitDiagramView(QGraphicsView):
	mousePress = pyqtSignal(tuple, tuple, name='mousePress')
	mouseMove = pyqtSignal(tuple, tuple, name='mouseMove')
	mouseRelease = pyqtSignal(tuple, tuple, name='mouseRelease')

	def __init__(self, parent=None):
		QGraphicsView.__init__(self, parent)

		self._model = None
		self.controller = None

		self.setAcceptDrops(True)

		# setup & render circuit diagram grid
		self.scene = QGraphicsScene()
		self.setScene(self.scene)

		self._shouldShowSelection = False
		self._selection = None
		self._dragging = False
		self.mousePosition = None
		self.draggingStart = None

		self.render()

	@property
	def shouldShowSelection(self):
		return self._shouldShowSelection

	@shouldShowSelection.setter
	def shouldShowSelection(self, value):
		if self.shouldShowSelection is not value and value is not None:
			self._shouldShowSelection = value
			self.render()		

	@property
	def model(self):
		return self._model

	@model.setter
	def model(self, value):
		self._model = value
		self.model.modelChanged.connect(self.render)

	@property
	def selection(self):
		return self._selection

	@selection.setter
	def selection(self, value):
		if self.selection is not value:
			self._selection = value
			self.render()	

	@property
	def dragging(self):
		return self._dragging

	@dragging.setter
	def dragging(self, value):
		self._dragging = value
		self.render()

	def componentTypeToImageName(self, componentType):
		dictionary = {
			ComponentType.Battery: "assets/battery.png",
			ComponentType.Resistor: "assets/resistor.png",
			ComponentType.Voltmeter: "assets/voltmeter.png",
			ComponentType.Ammeter: "assets/ammeter.png",
			ComponentType.Switch: "assets/switch-off.png",
			ComponentType.Bulb: "assets/bulb-off.png",
			ComponentType.Button: "assets/button-off.png",
		}

		return dictionary[componentType]

	def componentToImage(self, component):
		if component.type == ComponentType.Wire:
			image = QPixmap("assets/icon.png").scaled(self.blockSideLength, self.blockSideLength)
			if component.numberOfConnections() == 1:
				image = QPixmap("assets/wire-top.png").scaled(self.blockSideLength, self.blockSideLength)
				if component.connections[Direction.Right] is not None:
					image = image.transformed(QtGui.QTransform().rotate(90))
				elif component.connections[Direction.Bottom] is not None:
					image = image.transformed(QtGui.QTransform().rotate(180))
				elif component.connections[Direction.Left] is not None:
					image = image.transformed(QtGui.QTransform().rotate(270))
			elif component.numberOfConnections() == 2:
				if component.connections[Direction.Left] is not None and component.connections[Direction.Right] is not None:
					image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength)
				elif component.connections[Direction.Top] is not None and component.connections[Direction.Bottom] is not None:
					image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90))
				elif component.connections[Direction.Top] is not None and component.connections[Direction.Right] is not None:
					image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength)
				elif component.connections[Direction.Top] is not None and component.connections[Direction.Left] is not None:
					image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(270))
				elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Right] is not None:
					image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90))
				elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Left] is not None:
					image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(180))
			elif component.numberOfConnections() == 3:
				image = QPixmap("assets/wire-left-top-right.png").scaled(self.blockSideLength, self.blockSideLength)
				if component.connections[Direction.Left] is None:
					image = image.transformed(QtGui.QTransform().rotate(90))
				elif component.connections[Direction.Top] is None:
					image = image.transformed(QtGui.QTransform().rotate(180))
				elif component.connections[Direction.Right] is None:
					image = image.transformed(QtGui.QTransform().rotate(270))
			return image
		else:
			imageName = "assets/wire-right.png"
		
			if component.type == ComponentType.Bulb:
				if component.isOn():
					imageName = "assets/bulb-on.png"
				else:
					imageName = "assets/bulb-off.png"
			elif component.type == ComponentType.Switch:
				if component.closed:
					imageName = "assets/switch-on.png"
				else:
					imageName = "assets/switch-off.png"
			elif component.type == ComponentType.Button:
				if component.closed:
					imageName = "assets/button-on.png"
				else:
					imageName = "assets/button-off.png"
			else:
				imageName = self.componentTypeToImageName(component.type)
			
			return QPixmap(imageName).scaled(self.blockSideLength, self.blockSideLength)

	def mouseCoordinatesToBlockIndex(self, x, y):
		if self.model is None or x < self.startingX or y < self.startingY or x > self.startingX + self.model.gridSize * self.blockSideLength or y > self.startingY + self.model.gridSize * self.blockSideLength:
			return (-1, -1)
		else:
			return (int((x - self.startingX) / self.blockSideLength), int((y - self.startingY) / self.blockSideLength))

	def blockIndexToCoordinate(self, x, y):
		return (self.startingX + self.blockSideLength * x, self.startingY + self.blockSideLength * y)

	def mousePressEvent(self, event):
		index = self.mouseCoordinatesToBlockIndex(event.x(), event.y())
		self.mousePress.emit(index, (event.x(), event.y()))

	def dragEnterEvent(self, event):
		event.acceptProposedAction()

	def dragMoveEvent(self, event):
		index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y())
		self.mouseMove.emit(index, (event.pos().x(), event.pos().y()))

	def dropEvent(self, event):
		event.acceptProposedAction()
		index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y())
		self.mouseRelease.emit(index, (event.pos().x(), event.pos().y()))
		
	def mouseMoveEvent(self, event):
		self.mousePosition = (event.x(), event.y())
		if self.dragging:
			self.render()
		index = self.mouseCoordinatesToBlockIndex(event.x(), event.y())
		self.mouseMove.emit(index, (event.pos().x(), event.pos().y()))

	def mouseReleaseEvent(self, event):
		index = self.mouseCoordinatesToBlockIndex(event.x(), event.y())
		self.mouseRelease.emit(index, (event.pos().x(), event.pos().y()))

	def resizeEvent(self, event):
		self.render()

	def render(self):
		if self.model is not None:
			self.scene.clear()
			self.renderCircuitDiagramGrid() 
			self.renderComponents() 

	def renderComponents(self):
		if self.model is not None:
			for component in self.model.components:
				pixmap = self.componentToImage(component)
				pixmapItem = self.scene.addPixmap(pixmap)
				offset = self.blockIndexToCoordinate(component.position[0],component.position[1])
				pixmapItem.setOffset(offset[0],offset[1])
				pixmapItem.setTransformationMode(Qt.SmoothTransformation)
		
				if component is self.selection:
					if self.dragging:
						renderPosition = (self.startingX + self.selection.position[0] * self.blockSideLength + self.mousePosition[0] - self.draggingStart[0], self.startingY + self.selection.position[1] * self.blockSideLength + self.mousePosition[1] - self.draggingStart[1])
						pixmapItem.setOffset(renderPosition[0], renderPosition[1])
					elif self.shouldShowSelection:
						pen = QPen(QBrush(QColor(0,0,255,100)), 2, Qt.DashLine)
						self.scene.addRect(self.startingX + component.position[0] * self.blockSideLength, self.startingY + component.position[1] * self.blockSideLength, self.blockSideLength, self.blockSideLength, pen)
				if component.type is ComponentType.Ammeter:
					font = QFont("Arial", self.blockSideLength/3.5)
					reading = self.scene.addText(str("%.2f" % component.current) + "A", font)
					offset = self.blockIndexToCoordinate(component.position[0],component.position[1])
					reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4)
				elif component.type is ComponentType.Voltmeter:
					font = QFont("Arial", self.blockSideLength/3.5)
					reading = self.scene.addText(str("%.2f" % component.voltage) + "V", font)
					offset = self.blockIndexToCoordinate(component.position[0],component.position[1])
					reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4)

	def renderCircuitDiagramGrid(self):
		pen = QPen(QBrush(QColor(200,200,200,255)), 1)
		pen2 = QPen(QBrush(QColor(100,100,100,255)), 3)
		width = self.width()
		height = self.height()
		self.blockSideLength = width / (self.model.gridSize + 2) if width < height else height / (self.model.gridSize + 2)

		# draw vertical lines
		currentX = width / 2
		self.startingX = currentX - (self.model.gridSize / 2) * self.blockSideLength
		while currentX - self.blockSideLength >= 0:
			currentX -= self.blockSideLength
		
		while currentX < width:
			self.scene.addLine(currentX, 1, currentX, height - 1, pen)
			
			currentX += self.blockSideLength

		# draw horizontal lines
		currentY = height / 2
		self.startingY = currentY - (self.model.gridSize / 2) * self.blockSideLength
		while currentY - self.blockSideLength >= 0:
			currentY -= self.blockSideLength
		while currentY < height:
			self.scene.addLine(1, currentY, width - 1, currentY, pen)
			currentY += self.blockSideLength

		self.scene.addLine(self.startingX, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, pen2)
		self.scene.addLine(self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2)
		self.scene.addLine(self.startingX, self.startingY, self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, pen2)
		self.scene.addLine(self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2)
Ejemplo n.º 4
0
class QImageViewer(QGraphicsView):
    # Mouse button signals emit image scene (x, y) coordinates.
    # !!! For image (row, column) matrix indexing, row = y and column = x.
    leftMouseButtonPressed = pyqtSignal(float, float)
    leftMouseButtonReleased = pyqtSignal(float, float)

    def __init__(self, widget):
        super(QImageViewer, self).__init__()

        self.mainWindow = utils.get_app()

        # Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView.
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        # Store a local handle to the scene's current image pixmap.
        self._pixmapHandle = None

        # Image aspect ratio mode.
        # !!! ONLY applies to full image. Aspect ratio is always ignored when zooming.
        #   Qt.IgnoreAspectRatio: Scale image to fit viewport.
        #   Qt.KeepAspectRatio: Scale image to fit inside viewport, preserving aspect ratio.
        #   Qt.KeepAspectRatioByExpanding: Scale image to fill the viewport, preserving aspect ratio.
        self.aspectRatioMode = Qt.KeepAspectRatioByExpanding

        # Scroll bar behaviour.
        #   Qt.ScrollBarAlwaysOff: Never shows a scroll bar.
        #   Qt.ScrollBarAlwaysOn: Always shows a scroll bar.
        #   Qt.ScrollBarAsNeeded: Shows a scroll bar only when zoomed.
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # Flags for enabling/disabling mouse interaction.
        self.KeyControl = False
        self.isPanning = False

        # Cursor settings
        cursorbit = QBitmap(
            QPixmap(utils.get_path(["iconImages", "CursorBit.png"])))
        cursormask = QBitmap(
            QPixmap(utils.get_path(["iconImages", "CursorMask.png"])))
        self.crossHair = QCursor(cursorbit, cursormask, -1, -1)
        #        self.setCursor(self.crossHair)

        # Mouse coordinate updates
        self.setMouseTracking(True)
        self.digitizerOn = False

        # Ty edit: anchor at mouse position
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        #self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)

        # Ty edit: record the zoom, pan, and others
        self.InitialFrame = True
        self.Zoom_recorder = 0
        GlobalData.currentFrame = 1
        GlobalData.totalFrames = 0

        self.ViewRectX = 0
        self.ViewRectY = 0
        self.ViewRectWidth = 0
        self.ViewRectHeight = 0

        # Ty keypoint drawing initialization
        self.SceneSize = 4.5
        self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder
        self.BoxDrawer = QPen(Qt.green)
        self.BoxDrawer.setWidth(0.01)
        self.BoxFill = QBrush(Qt.green)
        self.key_points = []

        # Ty draw trail lines initialization
        self.displayLineOn = False
        self.LineDrawer = QPen(Qt.green)
        self.LineWidth = (4 / 5)**self.Zoom_recorder
        self.LineDrawer.setWidth(self.LineWidth)
        self.LinePath = []

    def hasImage(self):
        """ Returns whether or not the scene contains an image pixmap.
        """
        return self._pixmapHandle is not None

    def clearImage(self):
        """ Removes the current image pixmap from the scene if it exists.
        """
        if self.hasImage():
            self.scene.removeItem(self._pixmapHandle)
            self._pixmapHandle = None

    def pixmap(self):
        """ Returns the scene's current image pixmap as a QPixmap, or else None if no image exists.
        :rtype: QPixmap | None
        """
        if self.hasImage():
            return self._pixmapHandle.pixmap()
        return None

    def image(self):
        """ Returns the scene's current image pixmap as a QImage, or else None if no image exists.
        :rtype: QImage | None
        """
        if self.hasImage():
            return self._pixmapHandle.pixmap().toImage()
        return None

    def setImage(self, fileName):
        """ Set the scene's current image pixmap to the input QImage or QPixmap.
        Raises a RuntimeError if the input image has type other than QImage or QPixmap.
        :type image: QImage | QPixmap
        """
        image = QImage(fileName)
        if type(image) is QPixmap:
            pixmap = image
        elif type(image) is QImage:
            pixmap = QPixmap.fromImage(image)
        else:
            raise RuntimeError(
                "ImageViewer.setImage: Argument must be a QImage or QPixmap.")
        if self.hasImage():
            self._pixmapHandle.setPixmap(pixmap)
        else:
            self._pixmapHandle = self.scene.addPixmap(pixmap)

        self.setSceneRect(QRectF(
            pixmap.rect()))  # Set scene size to image size.
        self.updateViewer()
        self.mainWindow.ShowFrame.setText(
            'frame:%3d' % GlobalData.currentFrame)  ##put framenumber as text
        self.mainWindow.qtSceneViewer.setImage(fileName)

    def updateViewer(self):
        """ Show current zoom (if showing entire image, apply current aspect ratio mode).
        """
        if not self.hasImage():
            return
        if self.InitialFrame:
            self.fitInView(
                self.sceneRect(), self.aspectRatioMode
            )  # Show entire image (use current aspect ratio mode).
            self.GetFrame()
            self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox(
                self.ViewRectX, self.ViewRectY, self.ViewRectWidth,
                self.ViewRectHeight)

    def GetFrame(self):
        Rect = self.rect()
        Rect = self.mapToScene(Rect)
        self.ViewRectX = Rect[0].x()
        self.ViewRectY = Rect[0].y()
        RectD = Rect[2] - Rect[0]
        self.ViewRectWidth = RectD.x()
        self.ViewRectHeight = RectD.y()

    def wheelEvent(
            self,
            event):  #need to have the setting on Qt.KeepAspectRatioByExpanding
        if event.angleDelta().y() < 0 and self.KeyControl is True:
            factor = 4 / 5
            self.Zoom_recorder -= 1
        elif event.angleDelta().y() > 0 and self.KeyControl is True:
            factor = 5 / 4
            self.Zoom_recorder += 1
        else:
            factor = 1

        if factor != 1 and self.KeyControl is True:
            self.scale(factor, factor)
            self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder
            self.LineWidth = (4 / 5)**self.Zoom_recorder
            self.GetFrame()
            self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox(
                self.ViewRectX, self.ViewRectY, self.ViewRectWidth,
                self.ViewRectHeight)

            self.draw_key_points()
            self.draw_line_path()

    def Zoom_large(self):
        factor = 9 / 8
        self.Zoom_recorder += 1
        self.scale(factor, factor)
        factor = 1
        self.GetFrame()
        self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox(
            self.ViewRectX, self.ViewRectY, self.ViewRectWidth,
            self.ViewRectHeight)
        self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder
        self.LineWidth = (4 / 5)**self.Zoom_recorder

        self.draw_key_points()
        self.draw_line_path()

    def Zoom_small(self):
        factor = 8 / 9
        self.Zoom_recorder -= 1
        self.scale(factor, factor)
        factor = 1
        self.GetFrame()
        self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox(
            self.ViewRectX, self.ViewRectY, self.ViewRectWidth,
            self.ViewRectHeight)
        self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder
        self.LineWidth = (4 / 5)**self.Zoom_recorder

        self.draw_key_points()
        self.draw_line_path()

    def mouseMoveEvent(self, event):
        scenePos = self.mapToScene(event.pos())
        self.sX = int(round(scenePos.x()))
        self.sY = int(round(scenePos.y()))
        self.mainWindow.CursorXY.setText('x:%4d y:%4d ' %
                                         (self.sX, GlobalData.imgHeight -
                                          self.sY))  ##put coordinate as text

        QGraphicsView.mouseMoveEvent(self, event)
        if self.isPanning is True and self.mouseLeftPress is True:
            self.GetFrame()
            self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox(
                self.ViewRectX, self.ViewRectY, self.ViewRectWidth,
                self.ViewRectHeight)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouseLeftPress = True
            if self.KeyControl:
                self.setDragMode(QGraphicsView.ScrollHandDrag)
                self.isPanning = True

            if self.digitizerOn is True and self.KeyControl is False:
                self.add_coordinate(self.sX, self.sY)

                if self.mainWindow.AutoNextMode.autoNextMode == 0:
                    pass
                if self.mainWindow.AutoNextMode.autoNextMode == 1:
                    self.next_frame()
                if self.mainWindow.AutoNextMode.autoNextMode == 2:
                    self.prev_frame()
                if self.mainWindow.AutoNextMode.autoNextMode == 3:
                    self.mainWindow.visableItemsLayout.selectNextItem()
        QGraphicsView.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        QGraphicsView.mouseReleaseEvent(self, event)
        if event.button() == Qt.LeftButton:
            self.setDragMode(QGraphicsView.NoDrag)
            self.mouseLeftPress = False
            self.isPanning = False

        self.leftMouseButtonReleased.emit(self.sX, self.sY)

    def next_frame(self):
        # Frame increment
        if GlobalData.currentFrame == GlobalData.totalFrames:
            pass
        else:
            GlobalData.currentFrame += 1
            self.setImage(
                os.path.join(GlobalData.videoPath,
                             str(GlobalData.currentFrame) + ".jpg"))
            self.mainWindow.Slider.setValue(GlobalData.currentFrame)
            self.draw_key_points()

    def prev_frame(self):
        # Frame decrement
        if GlobalData.currentFrame == 1:
            pass
        else:
            GlobalData.currentFrame -= 1
            self.setImage(
                os.path.join(GlobalData.videoPath,
                             str(GlobalData.currentFrame) + ".jpg"))
            self.mainWindow.Slider.setValue(GlobalData.currentFrame)
            self.draw_key_points()

    def slider_frame(self):
        GlobalData.currentFrame = self.mainWindow.Slider.value()
        self.setImage(
            os.path.join(GlobalData.videoPath,
                         str(GlobalData.currentFrame) + ".jpg"))
        self.draw_key_points()

    def draw_key_points(self):
        if self.mainWindow.video_file_loaded == True and self.mainWindow.freezeAllEdite == False:
            # Grab all points references at the current frame
            if self.key_points:
                for reference in self.key_points:
                    self.scene.removeItem(reference)
            self.key_points = []
            for subject in GlobalData.global_subject_list:
                for part in subject.parts:
                    if part.checked == True:
                        x = part.x[GlobalData.currentFrame - 1]
                        y = part.y[GlobalData.currentFrame - 1]
                        reference = self.add_key_point(x, y)
                        if reference == None:
                            continue
                        else:
                            reference.setVisible(True)
                        self.key_points.append(reference)

    def add_coordinate(self, x, y):
        selected_items = self.mainWindow.visableItemsLayout._visable_items.selectedItems(
        )
        if len(selected_items) > 0:
            first_item = selected_items[0]
            parent_item = first_item.parent()
            # If the selected item is a child, then we can add coordinates
            if parent_item != None:
                subject_found = [
                    subject for subject in GlobalData.global_subject_list
                    if subject.name == parent_item.text(0)
                ]
                part_found = [
                    part for part in subject_found[0].parts
                    if part.name == first_item.text(0)
                ]
                item = recordItem(subject_found[0].name, part_found[0].name,
                                  part_found[0].x[GlobalData.currentFrame - 1],
                                  part_found[0].y[GlobalData.currentFrame - 1])
                part_found[0].x[GlobalData.currentFrame - 1] = x
                part_found[0].y[GlobalData.currentFrame - 1] = y
                self.draw_key_points()
                self.draw_line_path()
                updateRecord(item)
                self.mainWindow.Undo_action.setEnabled(True)
                self.mainWindow.Redo_action.setEnabled(False)

    def add_key_point(self, x, y):
        if None in (x, y):
            reference = None
        else:
            reference = self.scene.addRect(x - self.ViewSize,
                                           y - self.ViewSize,
                                           2 * self.ViewSize,
                                           2 * self.ViewSize, self.BoxDrawer,
                                           self.BoxFill)
        return reference

    def draw_line_path(self):
        if self.LinePath:
            for segment in self.LinePath:
                self.scene.removeItem(segment)

        if self.displayLineOn:
            self.LinePath = []
            self.LineDrawer.setWidth(self.LineWidth)
            #We will draw the object that is checked in the tree widget

            selected_items = self.mainWindow.visableItemsLayout._visable_items.selectedItems(
            )
            if len(selected_items) > 0:
                first_item = selected_items[0]
                parent_item = first_item.parent()
                # If the selected item is a child, then we can add coordinates
                if parent_item != None:
                    subject_found = [
                        subject for subject in GlobalData.global_subject_list
                        if subject.name == parent_item.text(0)
                    ]
                    part_found = [
                        part for part in subject_found[0].parts
                        if part.name == first_item.text(0)
                    ]
                    for i in range(GlobalData.totalFrames - 1):
                        if None in (part_found[0].x[i], part_found[0].y[i],
                                    part_found[0].x[i + 1],
                                    part_found[0].y[i + 1]):
                            continue
                        else:
                            segment = self.scene.addLine(
                                part_found[0].x[i], part_found[0].y[i],
                                part_found[0].x[i + 1], part_found[0].y[i + 1],
                                self.LineDrawer)
                            self.LinePath.append(segment)

    def keyPressEvent(self, event):
        #present in both mainWindow and QtImageViewer
        if event.key() == Qt.Key_Control:
            self.KeyControl = True

        if event.key() == Qt.Key_Down:
            self.mainWindow.visableItemsLayout.selectNextItem()

        if event.key() == Qt.Key_Up:
            self.mainWindow.visableItemsLayout.selectPreviousItem()

    def keyReleaseEvent(self, event):
        #present in both mainWindow and QtImageViewer
        if event.key() == Qt.Key_Control:
            self.KeyControl = False
Ejemplo n.º 5
0
if __name__ == '__main__':
    logInstance = Logger()
    logInstance.addLogger(loggers.StreamLogger([0]))
    setLoggerInstance(logInstance)

    log("Setting up window...")
    app = QApplication(sys.argv)
    #ex = GoWindow()
    #app.exec_()
    #log("Done!")
    w = Window(500, 500, "test", processingLoop=loop)

    # create a scene
    scene = QGraphicsScene()

    scene.addLine(10, 10, 500, 500)
    g = Grid(10, 10, 10, 10)
    scene.addItem(g)

    #scene.addRect(150,0,40,20, QPen(), QBrush(QColor(30,60,120)))

    elem = GUIElement()
    scene.addItem(elem)

    w.addScene(scene)
    w.setScene(0)

    app.exec_()
    #w.display()
Ejemplo n.º 6
0
class Spectrum(QWidget):
    """Plot the power spectrum for a specified channel.

    Attributes
    ----------
    parent : instance of QMainWindow
        the main window.
    x_limit : tuple or list
        2 values specifying the limit on x-axis
    y_limit : tuple or list
        2 values specifying the limit on y-axis
    log : bool
        log-transform the data or not
    idx_chan : instance of QComboBox
        the element with the list of channel names.
    idx_x_min : instance of QLineEdit
        value with min x value
    idx_x_max : instance of QLineEdit
        value with max x value
    idx_y_min : instance of QLineEdit
        value with min y value
    idx_y_max : instance of QLineEdit
        value with max y value
    idx_log : instance of QCheckBox
        widget that defines if log should be used or not
    idx_fig : instance of QGraphicsView
        the view with the power spectrum
    scene : instance of QGraphicsScene
        the scene with GraphicsItems

    Notes
    -----
    If data contains NaN, it doesn't create any spectrum (feature or bug?).
    """
    def __init__(self, parent):
        super().__init__()
        self.parent = parent

        self.config = ConfigSpectrum(self.display_window)

        self.selected_chan = None
        self.idx_chan = None
        self.idx_fig = None
        self.scene = None

        self.create()

    def create(self):
        """Create empty scene for power spectrum."""
        self.idx_chan = QComboBox()
        self.idx_chan.activated.connect(self.display_window)

        self.idx_fig = QGraphicsView(self)
        self.idx_fig.scale(1, -1)

        layout = QVBoxLayout()
        layout.addWidget(self.idx_chan)
        layout.addWidget(self.idx_fig)
        self.setLayout(layout)

        self.resizeEvent(None)

    def show_channame(self, chan_name):
        self.selected_chan = self.idx_chan.currentIndex()

        self.idx_chan.clear()
        self.idx_chan.addItem(chan_name)
        self.idx_chan.setCurrentIndex(0)

    def update(self):
        """Add channel names to the combobox."""
        self.idx_chan.clear()
        for chan_name in self.parent.traces.chan:
            self.idx_chan.addItem(chan_name)

        if self.selected_chan is not None:
            self.idx_chan.setCurrentIndex(self.selected_chan)
            self.selected_chan = None

    def display_window(self):
        """Read the channel name from QComboBox and plot its spectrum.

        This function is necessary it reads the data and it sends it to
        self.display. When the user selects a smaller chunk of data from the
        visible traces, then we don't need to call this function.
        """
        if self.idx_chan.count() == 0:
            self.update()

        chan_name = self.idx_chan.currentText()
        lg.debug('Power spectrum for channel ' + chan_name)

        if chan_name:
            trial = 0
            data = self.parent.traces.data(trial=trial, chan=chan_name)
            self.display(data)
        else:
            self.scene.clear()

    def display(self, data):
        """Make graphicsitem for spectrum figure.

        Parameters
        ----------
        data : ndarray
            1D vector containing the data only

        This function can be called by self.display_window (which reads the
        data for the selected channel) or by the mouse-events functions in
        traces (which read chunks of data from the user-made selection).
        """
        value = self.config.value
        self.scene = QGraphicsScene(value['x_min'], value['y_min'],
                                    value['x_max'] - value['x_min'],
                                    value['y_max'] - value['y_min'])
        self.idx_fig.setScene(self.scene)

        self.add_grid()
        self.resizeEvent(None)

        s_freq = self.parent.traces.data.s_freq
        f, Pxx = welch(data, fs=s_freq, nperseg=int(min(
            (s_freq, len(data)))))  # force int

        freq_limit = (value['x_min'] <= f) & (f <= value['x_max'])

        if self.config.value['log']:
            Pxx_to_plot = log(Pxx[freq_limit])
        else:
            Pxx_to_plot = Pxx[freq_limit]

        self.scene.addPath(Path(f[freq_limit], Pxx_to_plot),
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))

    def add_grid(self):
        """Add axis and ticks to figure.

        Notes
        -----
        I know that visvis and pyqtgraphs can do this in much simpler way, but
        those packages create too large a padding around the figure and this is
        pretty fast.

        """
        value = self.config.value

        # X-AXIS
        # x-bottom
        self.scene.addLine(value['x_min'], value['y_min'],
                           value['x_min'], value['y_max'],
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # at y = 0, dashed
        self.scene.addLine(value['x_min'], 0, value['x_max'], 0,
                           QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine))
        # ticks on y-axis
        y_high = int(floor(value['y_max']))
        y_low = int(ceil(value['y_min']))
        x_length = (value['x_max'] - value['x_min']) / value['x_tick']
        for y in range(y_low, y_high):
            self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # Y-AXIS
        # left axis
        self.scene.addLine(value['x_min'], value['y_min'],
                           value['x_max'], value['y_min'],
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # larger ticks on x-axis every 10 Hz
        x_high = int(floor(value['x_max']))
        x_low = int(ceil(value['x_min']))
        y_length = (value['y_max'] - value['y_min']) / value['y_tick']
        for x in range(x_low, x_high, 10):
            self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # smaller ticks on x-axis every 10 Hz
        y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2
        for x in range(x_low, x_high, 5):
            self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))

    def resizeEvent(self, event):
        """Fit the whole scene in view.

        Parameters
        ----------
        event : instance of Qt.Event
            not important

        """
        value = self.config.value
        self.idx_fig.fitInView(value['x_min'], value['y_min'],
                               value['x_max'] - value['x_min'],
                               value['y_max'] - value['y_min'])

    def reset(self):
        """Reset widget as new"""
        self.idx_chan.clear()
        if self.scene is not None:
            self.scene.clear()
        self.scene = None
Ejemplo n.º 7
0
class myWindow(QtWidgets.QWidget, Ui_MainWindow):
    def __init__(self):
        super(myWindow, self).__init__()
        self.setupUi(self)
        self.Ui_init()
        myWindow.setWindowFlags(self, QtCore.Qt.WindowStaysOnTopHint)

    def Ui_init(self):
        # 传递界面类
        self.fupin = fupinWindow()
        self.shiyan = shiyanWindow()
        self.conn = connectWindow()
        self.busy = busyWindow()
        # 菜单栏初始化
        self.printAction1 = QAction(self.tr("退出"), self)
        self.menu.addAction(self.printAction1)
        self.printAction1.triggered.connect(lambda: self.tuichu())
        self.printAction2 = QAction(self.tr("幅频显示"), self)
        self.printAction3 = QAction(self.tr("点对点时延"), self)
        self.menu_2.addAction(self.printAction2)
        self.menu_2.addAction(self.printAction3)
        self.printAction2.triggered.connect(lambda: self.showFupin())
        self.fupin.backsignal1.connect(lambda: self.showmain())
        self.printAction3.triggered.connect(lambda: self.showShiyan())
        self.shiyan.backsignal2.connect(lambda: self.showmain())
        self.busy.backsignal5.connect(self.busy_backsignal5)
        self.printAction4 = QAction(self.tr("参数设置"), self)
        self.menu_3.addAction(self.printAction4)
        self.printAction4.triggered.connect(lambda: self.showConnect())
        self.conn.backsignal3.connect(self.context_unit)
        self.conn.backsignal4.connect(lambda: self.showmain())
        # 窗口底部图标简介
        pix1 = QPixmap(':/myIcons/绿.jpg').scaledToWidth(18).scaledToHeight(18)
        self.label_2.setPixmap(pix1)
        pix2 = QPixmap(':/myIcons/红.jpg').scaledToWidth(20).scaledToHeight(20)
        self.label_4.setPixmap(pix2)
        # 参数
        self.old = 2
        self.error = True
        self.connectError = False
        #  拓扑显示初始化
        self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 1920, 1080)
        self.graphicsView.setScene(self.graphicsView.scene)
        self.graphicsView.setAlignment(QtCore.Qt.AlignLeft
                                       | QtCore.Qt.AlignTop)
        self.graphicsView.setSceneRect(0, 0, 3840,
                                       1160)  # fix scene size 500 500
        self.graphicsView.setRenderHint(QPainter.Antialiasing)  ##设置视图的抗锯齿渲染模式。
        self.scene = QGraphicsScene()
        self.graphicsView.setScene(self.scene)
        # 拓扑显示控制按钮
        self.pushButton_3.clicked.connect(lambda: self.startShow())
        # 联机按钮
        self.pushButton.clicked.connect(lambda: self.connect())
        # 默认显示之前的页面
        global topoList_A, topoList_B, topoList_C, oldNodeList
        getTopoA = "select * from oldTopo_A"
        getTopoB = "select * from oldTopo_B"
        getTopoC = "select * from oldTopo_C"
        topoList_A = self.getTopo(getTopoA)
        oldNodeList.extend(topoList_A)
        topoList_B = self.getTopo(getTopoB)
        oldNodeList.extend(topoList_B)
        topoList_C = self.getTopo(getTopoC)
        oldNodeList.extend(topoList_C)
        self.initialization(oldNodeList)
        #开始测量按钮
        self.pushButton_4.clicked.connect(lambda: self.startMeasure())
        self.pushButton_3.setEnabled(False)
        self.pushButton_4.setEnabled(False)
        self.printAction2.setEnabled(False)
        self.printAction3.setEnabled(False)
        # 线程
        self.startM = Qmeasure()
        self.startM.endflag.connect(self.changeUI)
        self.topo = QTopo()
        self.topo.endflag.connect(self.newToposhow)
        self.countnum = Qcount()
        self.countnum.count.connect(self.showcount)
        self.counttopo = Qcounttopo()
        self.counttopo.count.connect(self.showcounttopo)
        self.step = 0
        self.progressBar.setValue(self.step)
        #选项框
        self.comboBox.currentIndexChanged.connect(self.btnStateChange)
        readConfigurationFile("Serial").setCon("serial_or_udp", "1")
        # myconfig = configparser.ConfigParser()
        # myconfig.read('config.ini')
        # myconfig.set("Serial", "serial_or_udp", "1")
        # myconfig.write(open("config.ini", "w+"))

    '''
        页面跳转的方法
        showmain():显示主页面
        tuichu():退出程序
        showFupin():显示幅频页面
        showShiyan():显示时延页面
        showBusy():显示繁忙页面
        context_unit():将参数设置页面中设置的参数返回主页面中
    '''

    # 显示主页面
    def showmain(self):
        self.setVisible(1)

    # 退出应用
    def tuichu(self):
        self.close()

    # 显示幅频曲线界面
    def showFupin(self):
        self.fupin.cancelbt()
        self.setVisible(0)  # 隐藏主界面
        self.fupin.setVisible(1)

    # 显示时延界面
    def showShiyan(self):
        self.shiyan.cancelbt()
        self.shiyan.textEdit.clear()
        self.setVisible(0)
        self.shiyan.setVisible(1)

    def showConnect(self):
        self.setVisible(0)
        self.conn.setVisible(1)
        # print(context)
    def showBusy(self):
        self.setVisible(0)
        self.busy.setVisible(1)

    def context_unit(self, i1, i2, i3, i4, i5):
        global paraList
        paraList = []
        paraList.append(i1)
        paraList.append(i2)
        paraList.append(i3)
        paraList.append(i4)
        paraList.append(i5)
        self.setVisible(1)

    #选项框状态修改
    def btnStateChange(self):
        s1 = str(self.comboBox.currentText())
        if s1 == '串口':
            readConfigurationFile("Serial").setCon("serial_or_udp", "1")
        else:
            readConfigurationFile("Serial").setCon("serial_or_udp", "0")

    '''
        测量过程中主页面显示函数
        根据标志位flag=1时,将测量按钮设为禁用状态,当测量结束后并调用拓扑发现算法,恢复测量到的网络拓扑结构
        标志位flag!=1时,则表明测量过程中出现错误,要想重新测量则将测量按钮激活,否则的话退出程序
    '''

    # 测量过程中主页面显示的逻辑
    def changeUI(self, flag):
        if flag == 1:
            self.pushButton_3.setEnabled(True)
            self.printAction2.setEnabled(True)
            self.printAction3.setEnabled(True)
            self.pushButton_4.setText('启动测量')
            self.pushButton_4.setDisabled(False)
            end = QMessageBox.information(self, "测量结束提示框", "结束测量,是否开始显示",
                                          QMessageBox.Yes | QMessageBox.No,
                                          QMessageBox.Yes)
            if end == QMessageBox.Yes:
                # time.sleep(1)
                QApplication.processEvents()
                self.topo.start()
                self.counttopo.start()
                self.pushButton_4.setText('正在计算拓扑')
                self.pushButton_4.setDisabled(True)
                self.pushButton_3.setEnabled(False)
                self.pushButton.setEnabled(False)
                self.printAction2.setEnabled(False)
                self.printAction3.setEnabled(False)
        else:
            start = QMessageBox.information(self, "测量错误提示框", "是否重新测量?",
                                            QMessageBox.Yes | QMessageBox.No,
                                            QMessageBox.Yes)
            if start == QMessageBox.Yes:
                self.pushButton_3.setEnabled(True)
                self.printAction2.setEnabled(True)
                self.printAction3.setEnabled(True)
                self.pushButton_4.setText('启动测量')
                self.pushButton_4.setDisabled(False)
            else:
                self.tuichu()

    '''
        拓扑计算完成后的拓扑显示函数
        计算完成后将菜单栏中的“时延测量”、“幅频显示”选项的状态激活
        若是计算过程中出错则直接退出程序 
    '''

    # 拓扑计算完成后的拓扑显示函数
    def newToposhow(self, flag):
        if flag == 1:
            self.pushButton_4.setText('计算完成')
            self.pushButton_4.setDisabled(False)
            self.pushButton_3.setDisabled(False)
            self.pushButton.setEnabled(False)
            self.printAction2.setEnabled(True)
            self.printAction3.setEnabled(True)
            logging.info('计算完成')
            time.sleep(1)
            global topoList_A, topoList_B, topoList_C, newNodeList
            getTopoA = "select * from newTopo_A"
            getTopoB = "select * from newTopo_B"
            getTopoC = "select * from newTopo_C"
            topoList_A = self.getTopo(getTopoA)
            newNodeList.extend(topoList_A)
            topoList_B = self.getTopo(getTopoB)
            newNodeList.extend(topoList_B)
            topoList_C = self.getTopo(getTopoC)
            newNodeList.extend(topoList_C)
            self.initialization(newNodeList)
            self.pushButton_4.setText('启动测量')
            self.old = 1
            self.pushButton_3.setText("当前拓扑")
            QApplication.processEvents()
            logging.info('拓扑已显示')
        else:
            start = QMessageBox.information(self, "计算错误提示框", "拓扑计算出错,退出!",
                                            QMessageBox.Yes, QMessageBox.Yes)
            if start == QMessageBox.Yes:
                self.tuichu()

    '''
        设置进度条值的函数
        showcount():将已测量节点数目线程返回的数值处理后,设置进度条的值
        showcounttopo():将拓扑计算算法过程的线程返回数值处理后,设置进度条的值
    '''

    def showcount(self, connect_num):
        self.step = (connect_num / num) * 85
        self.progressBar.setValue(int(self.step))
        self.label_6.setText('已经测量了 %d 个点' % connect_num)

    def showcounttopo(self, measure_num):
        self.step = measure_num + 85
        self.progressBar.setValue(self.step)
        if self.step < 100:
            self.label_6.setText("正在计算拓扑")
        else:
            self.label_6.setText("测量完成")

    '''
        系统繁忙页面返回信号的槽函数
        若是选择重新发送操作选项,则是直接返回主页面
        若是选择取消操作选项,则是调用接口程序
    '''

    # 系统繁忙
    def busy_backsignal5(self, num):
        if num == 1:
            # 重新发送操作
            self.setVisible(1)
        else:
            self.setVisible(1)

    def settreeflag(self, flag):
        global tree_flag
        tree_flag = flag

    '''
        主页面显示函数
        (1)节点目录和节点信息目录清空
        (2)查询数据库节点信息,设置节点目录treeWidget和节点信息目录tableWidget中的信息
        (3)调用isclick函数,点击节点目录treeWidget中的节点,会在节点信息目录tableWidget中显示相应的节点信息
        (4)调用topo_show函数,显示恢复的网络拓扑
    '''

    # 默认显示之前的页面
    def initialization(self, nodelist):
        logging.info('页面初始化开始')
        global reallist
        reallist = self.getRealNode(nodelist)
        self.treeWidget.clear()
        self.tableWidget.clear()
        # 树状目录初始化
        self.treeWidget.setColumnCount(1)
        self.treeWidget.setColumnWidth(0, 50)
        self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        groupname = 'root'
        root1 = self.creategroup(groupname, reallist)
        root1.setExpanded(False)
        # 设置树状结构最外层节点的图标显示
        i = 0
        while i < self.treeWidget.topLevelItemCount():
            self.treeWidget.topLevelItem(i).setIcon(0,
                                                    QIcon(':/myIcons/房.jpg'))
            i = i + 1
        # 表格初始化
        self.tableWidget.setRowCount(1)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setHorizontalHeaderLabels(['名字', '与父节点的距离'])
        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        QTableWidget.resizeColumnsToContents(self.tableWidget)
        QTableWidget.resizeRowsToContents(self.tableWidget)
        self.treeWidget.itemClicked.connect(self.isclick)
        # 显示拓扑
        t1 = threading.Thread(target=self.topo_show(topoList_A, topoList_B,
                                                    topoList_C),
                              name='function')
        t1.start()
        logging.info('页面初始化完成')

    '''
        联机函数
        调用接口程序,根据接口程序返回的标志位flag进行相应的操作
        flag=1,则表示联机成功,并调用connectEnd()函数
        flag=-1,则表示系统繁忙,并调用showBusy()函数
        flag!=1且flag!=-1,则表示联机出错,并调用connectEnd()函数,退出程序
        
    '''

    # 联机函数
    def connect(self):
        logging.info('联机开始')
        global num
        # 根据设定的参数来进行联机操作
        (flag, num) = ser.build_order()
        flag = 1
        if flag == 1:
            self.connectError = False
            self.connectEnd()
        elif flag == -1:
            self.showBusy()
        else:
            self.connectError = True
            self.connectEnd()

    '''
        联机是否成功函数
        connectError= True,则表示联机出错,退出程序
        connectError= False,则表示联机成功,将联机按钮状态设为禁用,其余按钮设为激活状态
    '''

    def connectEnd(self):
        if self.connectError:
            QMessageBox.information(self, "联机出错提示框", "组网未成功",
                                    QMessageBox.Yes | QMessageBox.No,
                                    QMessageBox.Yes)
            time.sleep(2)
            # 模拟退出页面
            self.tuichu()
        else:
            QMessageBox.information(self, "联机成功提示框", "联机成功",
                                    QMessageBox.Yes | QMessageBox.No,
                                    QMessageBox.Yes)  #20200120 by e
            self.pushButton.setEnabled(False)
            self.pushButton.setText('已联机')
            self.pushButton_3.setDisabled(False)
            # self.old=2
            self.pushButton_3.setText('历史拓扑')
            self.pushButton_4.setEnabled(True)
            self.printAction2.setEnabled(True)
            self.printAction3.setEnabled(True)
            self.comboBox.setDisabled(True)
            QApplication.processEvents()
        logging.info('联机完成')

    '''
        拓扑切换函数,根据self.old值显示拓扑图
    '''

    #拓扑控制按钮
    def startShow(self):
        logging.info('拓扑切换开始')
        if self.old == 1:
            global topoList_A, topoList_B, topoList_C, oldNodeList
            getTopoA = "select * from oldTopo_A"
            getTopoB = "select * from oldTopo_B"
            getTopoC = "select * from oldTopo_C"
            topoList_A = self.getTopo(getTopoA)
            oldNodeList.extend(topoList_A)
            topoList_B = self.getTopo(getTopoB)
            oldNodeList.extend(topoList_B)
            topoList_C = self.getTopo(getTopoC)
            oldNodeList.extend(topoList_C)
            self.initialization(oldNodeList)
            QApplication.processEvents()
            self.pushButton_3.setText("历史拓扑")
            self.old = 2
        elif self.old == 2:
            getTopoA = "select * from newTopo_A"
            getTopoB = "select * from newTopo_B"
            getTopoC = "select * from newTopo_C"
            topoList_A = self.getTopo(getTopoA)
            newNodeList.extend(topoList_A)
            topoList_B = self.getTopo(getTopoB)
            newNodeList.extend(topoList_B)
            topoList_C = self.getTopo(getTopoC)
            newNodeList.extend(topoList_C)
            self.initialization(newNodeList)
            QApplication.processEvents()
            self.pushButton_3.setText("当前拓扑")
            self.old = 1
        logging.info('拓扑切换完成')

    '''
        节点目录创建分组函数、节点点击和节点信息显示联动函数
    '''

    # 节点目录创建分组
    def creategroup(self, groupname, childList):
        group = QTreeWidgetItem(self.treeWidget)
        num_child = len(childList)
        j = 0
        while j < num_child:
            dict1 = childList[j].getName()
            child = QTreeWidgetItem()
            child.setText(0, dict1)
            child.setIcon(0, QIcon(':/myIcons/绿.jpg'))
            child.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter)
            j = j + 1
            group.addChild(child)
        group.setText(0, groupname)
        return group

    # 节点点击和拓扑显示联动
    def isclick(self, item, column):
        # 最小的节点,输出节点信息
        global reallist
        if item.child(0) is None:
            for i in range(0, len(reallist)):
                if item.text(column) == reallist[i].getName():
                    newItem1 = QTableWidgetItem(reallist[i].getName())
                    self.tableWidget.setItem(0, 0, newItem1)
                    newItem2 = QTableWidgetItem(str(reallist[i].getLength()))
                    self.tableWidget.setItem(0, 1, newItem2)
                    break
        else:
            newItem1 = QTableWidgetItem(reallist[0].getName())
            self.tableWidget.setItem(0, 0, newItem1)
            newItem2 = QTableWidgetItem(str(reallist[0].getLength()))
            self.tableWidget.setItem(0, 1, newItem2)

    # 开始测量页面显示的槽函数,调用接口程序并将已测量节点数目返回主页面
    def startMeasure(self):
        logging.info('重新测量开始')
        # 弹出参数设置页面
        logging.info('参数设置')
        # 测量开始提示框
        start = QMessageBox.information(self, "测量开始提示框", "是否开始测量?",
                                        QMessageBox.Yes | QMessageBox.No,
                                        QMessageBox.Yes)
        if start == QMessageBox.Yes:
            self.startM.start()
            self.countnum.start()
            self.pushButton_4.setText('正在测量')
            self.pushButton_4.setDisabled(True)
            self.pushButton_3.setEnabled(False)
            self.pushButton.setEnabled(False)
            self.printAction2.setEnabled(False)
            self.printAction3.setEnabled(False)
        logging.info('重新测量结束')

    # 重新测量
    def reMeasure(self):
        logging.info('重新测量页面开始显示')
        global topoList_A, topoList_B, topoList_C, newNodeList, newRealList
        getTopoA = "select * from newTopo_A"
        getTopoB = "select * from newTopo_B"
        getTopoC = "select * from newTopo_C"
        topoList_A = self.getTopo(getTopoA)
        newNodeList.extend(topoList_A)
        topoList_B = self.getTopo(getTopoB)
        newNodeList.extend(topoList_B)
        topoList_C = self.getTopo(getTopoC)
        newNodeList.extend(topoList_C)
        newRealList = self.getRealNode(newNodeList)
        self.treeWidget.clear()
        self.tableWidget.clear()
        logging.info('节点信息显示')
        # 树状目录初始化
        self.treeWidget.setColumnCount(1)
        self.treeWidget.setColumnWidth(0, 50)
        self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        groupname = 'root'
        root1 = self.creategroup(groupname, newRealList)
        root1.setExpanded(False)
        # 设置树状结构最外层节点的图标显示
        self.treeWidget.topLevelItem(0).setIcon(0, QIcon(':/myIcons/房.jpg'))
        # 表格初始化
        self.tableWidget.setRowCount(1)
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setHorizontalHeaderLabels(['名字', '与父节点的距离'])
        self.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        QTableWidget.resizeColumnsToContents(self.tableWidget)
        QTableWidget.resizeRowsToContents(self.tableWidget)
        self.treeWidget.itemClicked.connect(self.newisclick)
        logging.info('节点信息显示完成')
        self.graphicsView.setScene(self.graphicsView.scene)
        self.graphicsView.setAlignment(QtCore.Qt.AlignLeft
                                       | QtCore.Qt.AlignTop)
        self.graphicsView.setSceneRect(0, 0, 3840,
                                       1160)  # fix scene size 500 500
        self.graphicsView.setRenderHint(QPainter.Antialiasing)  ##设置视图的抗锯齿渲染模式。
        self.scene = QGraphicsScene()
        self.graphicsView.setScene(self.scene)
        logging.info('拓扑显示')
        t1 = threading.Thread(target=self.topo_show(topoList_A, topoList_B,
                                                    topoList_C),
                              name='function')
        t1.start()
        logging.info('重新测量页面完成显示')

    # 节点点击和拓扑显示联动
    def newisclick(self, item, column):
        # 最小的节点,输出节点信息
        global newRealList
        if item.child(0) is None:
            for i in range(0, len(newRealList)):
                if item.text(column) == newRealList[i].getName():
                    newItem1 = QTableWidgetItem(newRealList[i].getName())
                    self.tableWidget.setItem(0, 0, newItem1)
                    newItem2 = QTableWidgetItem(newRealList[i].getLength())
                    self.tableWidget.setItem(0, 1, newItem2)
                    break
        else:
            newItem1 = QTableWidgetItem(newRealList[0].getName())
            self.tableWidget.setItem(0, 0, newItem1)
            newItem2 = QTableWidgetItem(newRealList[0].getLength())
            self.tableWidget.setItem(0, 1, newItem2)

    '''
        处理读取到的数据库信息的函数
        getTopo():读取数据库中的内容,并将数据库中每一行的数据使用Node对象存储起来,将全部数据使用list数据类型存储
        getRoot():获取getTopo()函数返回的list数据类型中的root节点
        getRealNode():获取getTopo()函数返回的list数据类型中的真实节点,返回list数据类型
    '''

    def getTopo(self, sql):
        newList = []
        IDListNew = {}
        try:
            results = Sqlite().select(sql)
            for row in results:
                node = Node()
                IDListNew[row[0]] = node
                newList.append(node)
            for row in results:
                n = IDListNew.get(row[0])
                if row[1] != None:
                    n.setName(row[1])
                if row[2] != None:
                    n.setFather(IDListNew.get(row[2]))
                    n.setLength(row[3])
                if row[4] != None:
                    n.setFirstChild(IDListNew.get(row[4]))
                if row[5] != None:
                    n.setRightBrother(IDListNew.get(row[5]))
                if row[6] == 1:
                    n.setisVirtualNode(True)
        except:
            print("No Data")
        return newList

    def getRoot(self, List: list):
        node = Node()
        for n in List:
            if n.getFather() == None:
                node = n
                break
        return node

    def getRealNode(self, List: list):
        RealNodeList = []
        for node in List:
            if node.getisVirtualNode():
                continue
            RealNodeList.append(node)
        return RealNodeList

    def create_icon(self, type, x, y):
        ccoimage = QImage('../Interface/cco.png')
        steimage = QImage('../Interface/ste.png')
        vimage = QImage('../Interface/v.png')
        if type == "cco":
            ret = QGraphicsPixmapItem(QPixmap.fromImage(ccoimage))
        elif type == "ste":
            ret = QGraphicsPixmapItem(QPixmap.fromImage(steimage))
        else:
            ret = QGraphicsPixmapItem(QPixmap.fromImage(vimage))
        ret.setPos(x, y)
        self.scene.addItem(ret)
        return ret

    def topo_show(self, ListA: list, ListB: list, ListC: list):
        sip.delete(self.graphicsView.scene)
        # self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 800, 600)
        self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 1500, 1000)
        self.graphicsView.setScene(self.graphicsView.scene)
        self.graphicsView.setAlignment(QtCore.Qt.AlignHCenter
                                       | QtCore.Qt.AlignVCenter)
        # self.graphicsView.setSceneRect(0, 0, 1600, 1200)  # fix scene size 500 500
        self.graphicsView.setSceneRect(0, 0, 3000,
                                       1800)  # fix scene size 500 500
        self.graphicsView.setRenderHint(QPainter.Antialiasing)  ##设置视图的抗锯齿渲染模式。
        self.scene = QGraphicsScene()
        self.graphicsView.setScene(self.scene)
        root_nodeA = self.getRoot(ListA)
        root_nodeB = self.getRoot(ListB).getFirstChild()
        root_nodeC = self.getRoot(ListC).getFirstChild()
        color_A = QPen(Qt.green)
        ymax_A = self.single_topo(ListA, 0, 0, 0, root_nodeA, color_A)
        yby = ymax_A - 80
        color_B = QPen(Qt.darkCyan)
        ymax_B = self.single_topo(ListB, 10, yby, ymax_A, root_nodeB, color_B)
        ycy = ymax_B - 80
        color_C = QPen(Qt.cyan)
        self.single_topo(ListC, 20, ycy, ymax_B, root_nodeC, color_C)
        self.graphicsView.centerOn(0, 00)
        printer_pixmap = QPrinter(QPrinter.HighResolution)
        printer_pixmap.setPageSize(QPrinter.A4)
        printer_pixmap.setOutputFormat(QPrinter.PdfFormat)
        time_str = datetime.datetime.now().strftime('%Y%m%d-%H_%M_%S')
        pngname = '../backup/topo/' + time_str + '.pdf'
        printer_pixmap.setOutputFileName(pngname)
        outputimg = QPixmap(3840, 1160)
        outputimg.fill(Qt.white)
        self.graphicsView.viewport().render(outputimg)
        painter_pixmap = QPainter()
        painter_pixmap.begin(printer_pixmap)
        rect = painter_pixmap.viewport()
        multiple = 3 * rect.width() / outputimg.width()
        painter_pixmap.scale(multiple, multiple)
        painter_pixmap.drawPixmap(0, 0, outputimg)
        painter_pixmap.end()

    def single_topo(self, List: list, xm, ym, ymax, root_node: Node, color):
        MIN = float(readConfigurationFile("Topo").getCon("min_dely"))
        threshold = MIN + 0.1
        icon_width = 32
        toponodes = []
        toponodes.append(root_node)
        icons = []
        icon_count = 0
        index_y = []
        if len(List) == 0:
            return 0
        for node in toponodes:
            (y, x) = topo_picture().icon_locate(node, icon_width, icon_width,
                                                100, 100)
            y = y + ym
            x = x - xm
            index_y.append(y)
            if node == root_node:
                if xm == 0:
                    x = x - 10
                    y = y - 10
                    iconi = self.create_icon("cco", x, y)
                    icons.append(iconi)
                    iconi.setPos(x, y)
                    icon_count = icon_count + 1
                    self.root_name = QGraphicsTextItem(str(node.getName()))
                    self.root_name.setDefaultTextColor(Qt.black)
                    # self.name.setDefaultTextColor(QColor(0, 160, 230))
                    self.root_name.setPos(QPointF(x, y + icon_width / 2 + 7))
                    self.scene.addItem(self.root_name)
                else:
                    self.scene.addRect(x + icon_width / 2 - 4,
                                       y + icon_width / 2 - 4, 8, 8,
                                       QPen(Qt.blue), QBrush(Qt.darkBlue))
            else:
                xp = x + icon_width / 2
                yp = y + icon_width / 2
                node_father = None
                node_graFather = None
                fx = 0
                fy = 0
                if node is not None:
                    node_father = node.getFather()
                if node_father is not None:
                    node_graFather = node_father.getFather()
                if node_graFather is not None:
                    if node_graFather.getisVirtualNode(
                    ) and node_father.getisVirtualNode():
                        if float(node_father.getLength()) < threshold:
                            if node_graFather.getLength() is not None:
                                while node_graFather.getFather(
                                ) is not None and float(
                                        node_graFather.getLength() < threshold
                                ):
                                    if node_graFather.getFather(
                                    ).getisVirtualNode():
                                        node_graFather = node_graFather.getFather(
                                        )
                                    else:
                                        break
                            (fy, fx) = topo_picture().icon_locate(
                                node_graFather, icon_width, icon_width, 100,
                                100)
                        else:
                            (fy, fx) = topo_picture().icon_locate(
                                node_father, icon_width, icon_width, 100, 100)
                    else:
                        (fy, fx) = topo_picture().icon_locate(
                            node_father, icon_width, icon_width, 100, 100)
                else:
                    (fy,
                     fx) = topo_picture().icon_locate(node_father, icon_width,
                                                      icon_width, 100, 100)
                fxp = fx + icon_width / 2 - xm
                fyp = fy + icon_width / 2 + ym
                ky = fyp - yp
                kx = fxp - xp
                if ky != 0:
                    k = kx / ky
                if float(node.getLength()) > threshold:
                    self.scene.addLine(xp, yp, fxp, fyp, color)
                elif float(node.getLength()
                           ) <= threshold and node.getisVirtualNode() == False:
                    self.scene.addLine(xp, yp, fxp, fyp, color)
                elif float(node.getLength()) <= threshold and node.getFather(
                ).getFather() is None:
                    self.scene.addLine(xp, yp, fxp, fyp, color)
                if ky == 0 or k == 0:
                    if float(node.getLength()) > threshold:
                        self.length = Decimal(node.getLength())
                        self.length = self.length.quantize(
                            Decimal('1'), ROUND_UP)
                        self.context = QGraphicsTextItem(str(self.length))
                        self.context.setDefaultTextColor(Qt.black)
                        self.font = QFont()
                        self.font.setPixelSize(10)
                        self.context.setFont(self.font)
                        self.context.setPos(
                            QPointF((xp + fxp - icon_width) / 2,
                                    (yp + fyp - icon_width) / 2))
                        self.scene.addItem(self.context)
                    elif float(node.getLength(
                    )) <= threshold and node.getisVirtualNode() == False:
                        self.length = Decimal(node.getLength())
                        self.length = self.length.quantize(
                            Decimal('1'), ROUND_UP)
                        self.context = QGraphicsTextItem(str(self.length))
                        self.context.setDefaultTextColor(Qt.black)
                        self.font = QFont()
                        self.font.setPixelSize(10)
                        self.context.setFont(self.font)
                        self.context.setPos(
                            QPointF((xp + fxp - icon_width) / 2,
                                    (yp + fyp - icon_width) / 2))
                        self.scene.addItem(self.context)
                    elif node.getFather().getFather() is None:
                        self.length = Decimal(node.getLength())
                        self.length = self.length.quantize(
                            Decimal('1'), ROUND_UP)
                        self.context = QGraphicsTextItem(str(self.length))
                        self.context.setDefaultTextColor(Qt.black)
                        self.font = QFont()
                        self.font.setPixelSize(10)
                        self.context.setFont(self.font)
                        self.context.setPos(
                            QPointF((xp + fxp - icon_width) / 2,
                                    (yp + fyp - icon_width) / 2))
                        self.scene.addItem(self.context)

                else:
                    if node.getisVirtualNode() == False:
                        self.length = Decimal(node.getLength())
                        self.length = self.length.quantize(
                            Decimal('1'), ROUND_UP)
                        self.context = QGraphicsTextItem(str(self.length))
                        self.context.setDefaultTextColor(Qt.black)
                        self.font = QFont()
                        self.font.setPixelSize(10)
                        self.context.setFont(self.font)
                        self.context.setPos(
                            QPointF((xp + fxp - icon_width) / 2,
                                    (yp + fyp - icon_width) / 2))
                        self.scene.addItem(self.context)
                    elif node.getisVirtualNode() and float(
                            node.getLength()) > threshold:
                        self.length = Decimal(node.getLength())
                        self.length = self.length.quantize(
                            Decimal('1'), ROUND_UP)
                        self.context = QGraphicsTextItem(str(self.length))
                        self.context.setDefaultTextColor(Qt.black)
                        self.font = QFont()
                        self.font.setPixelSize(10)
                        self.context.setFont(self.font)
                        self.context.setPos(
                            QPointF((xp + fxp - icon_width) / 2,
                                    (yp + fyp - icon_width) / 2))
                        self.scene.addItem(self.context)
                if node.getisVirtualNode():
                    if float(node.getLength()) > threshold:
                        self.scene.addRect(x + icon_width / 2 - 4,
                                           y + icon_width / 2 - 4, 8, 8,
                                           QPen(Qt.blue), QBrush(Qt.darkBlue))
                    elif float(
                            node.getLength()
                    ) <= threshold and node_father.getisVirtualNode() == False:
                        self.scene.addRect(x + icon_width / 2 - 4,
                                           y + icon_width / 2 - 4, 8, 8,
                                           QPen(Qt.blue), QBrush(Qt.darkBlue))
                else:
                    iconi = self.create_icon("ste", x, y)
                    icons.append(iconi)
                    iconi.setPos(x, y)
                    # 添加真实节点的名字
                    self.name = QGraphicsTextItem(str(node.getName()[-4:]))
                    self.name.setDefaultTextColor(Qt.black)
                    self.name.setPos(QPointF(x, y + icon_width / 2 + 7))
                    self.scene.addItem(self.name)
            child = node.getFirstChild()
            while child is not None:
                for node_child in List:
                    if child == node_child:
                        toponodes.append(node_child)
                child = child.getRightBrother()

        if xm != 0:
            fxp1 = 100 + icon_width / 2 - xm
            fyp1 = 100 + icon_width / 2
            xp1 = fxp1
            yp1 = fyp1 + ymax - xm
            self.scene.addLine(fxp1, fyp1, xp1, yp1, color)
            self.length = Decimal(node.getLength())
            self.length = self.length.quantize(Decimal('1'), ROUND_UP)
            self.context = QGraphicsTextItem(str(self.length))
            self.font = QFont()
            self.font.setPixelSize(10)
            self.context.setFont(self.font)
            self.context.setDefaultTextColor(Qt.black)
            self.context.setPos(QPointF(xp1, (yp1 + fyp1) / 2))
            self.scene.addItem(self.context)
        ymax = max(index_y)
        return ymax
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
class SchedulerGUI(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent=parent)
        self.setupUi(self)

        self.schedule = sampleSchedule()

        self.activatedColumns = {}

        for key in self.schedule.columns:
            self.activatedColumns[key] = True

        self.lang = 'en'

        self.restore_buttons = []
        self.restoreAllButton.clicked.connect(self.restoreAllColumns)

        self.translateDict = {}
        for widget in self.centralwidget.findChildren((QPushButton, QLabel)):
            langDict = {}

            for l in languages:
                langDict[l] = trans(widget.text(), l)
            key = widget

            self.translateDict[key] = langDict

        self.translateWidgets()

        self.language0Button.clicked.connect(partial(self.changeLang, 'en'))
        self.language1Button.clicked.connect(partial(self.changeLang, 'ru'))
        self.language2Button.clicked.connect(partial(self.changeLang, 'de'))

        self.drawAlarm = QTimer()
        self.drawAlarm.timeout.connect(self.drawAlarmFunc)
        self.drawAlarm.start(0.3)

    def closeEvent(self, event):
        quit()

    def resizeEvent(self, event):
        self.draw()

    def drawAlarmFunc(self):
        self.drawAlarm.stop()
        self.draw()

    def draw(self):
        self.scheduleScene = QGraphicsScene()
        self.activatedScene = QGraphicsScene()

        self.w = self.scheduleView.width()
        self.h = Y_SIDE * 24
        self.h_a = self.activatedView.height()

        self.gridPen = QPen(QtCore.Qt.gray)

        for i in range(0, 24):
            self.scheduleScene.addLine(0, i * Y_SIDE, self.w, i * Y_SIDE)

        self.drawTimeTapes()

        cols = self.getActivatedColumns()

        if (len(cols) > 0):
            self.drawColumns(cols)

        self.scheduleView.setScene(self.scheduleScene)
        self.activatedView.setScene(self.activatedScene)

    def drawTimeTapes(self):
        for i in range(0, len(self.schedule.timeTapes)):
            self.scheduleScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h)

            self.activatedScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i,
                                        self.h_a)

            l = QLabel(self.schedule.timeTapes[i].name)
            l.move(WIDTH_TL * i, 0)
            self.activatedScene.addWidget(l)

            for j in range(0, 24):
                l = QLabel(self.schedule.timeTapes[i].labels[j])
                l.move(WIDTH_TL * i, Y_SIDE * j)
                self.scheduleScene.addWidget(l)

    def drawColumns(self, cols):
        x_offset = WIDTH_TL * len(self.schedule.timeTapes)

        act_col_width = (self.w - x_offset) / len(cols)

        self.deactivateButtons = []
        for i in range(0, len(cols)):
            self.scheduleScene.addLine(x_offset + act_col_width * i, 0,
                                       x_offset + act_col_width * i, self.h)
            self.activatedScene.addLine(x_offset + act_col_width * i, 0,
                                        x_offset + act_col_width * i, self.h_a)

            b = QPushButton(cols[i].name[self.lang])
            b.move(x_offset + act_col_width * i, 0)
            b.clicked.connect(partial(self.deactivateColumn, cols[i].abr))
            b.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
            b.resize(act_col_width, self.h_a)
            b = self.activatedScene.addWidget(b)

            for event in cols[i].events:
                self.drawEvent(event, x_offset, act_col_width, i)

    def drawEvent(self, event, x_offset, col_width, x_loc):
        t0_f = timeStrToFloat(event.t0)
        t1_f = timeStrToFloat(event.t1)

        length = (t1_f - t0_f) * (self.h / 24)

        space = QtCore.QSizeF(col_width, length)

        ### Checks maximum font size if level
        font_size = MAX_EVENT_FONT_PT

        l_title = QLabel(event.title[self.lang])
        l_time = QLabel(' (' + event.t0 + ' - ' + event.t1 + ')')

        l_time.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))
        l_title.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))

        title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \
            l_time.fontMetrics().boundingRect(l_time.text()).width()
        title_height = l_title.fontMetrics().boundingRect(
            l_title.text()).height()

        while (title_height > length
               or title_width > col_width) and font_size > MIN_EVENT_FONT_PT:
            font_size -= 1

            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))
            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))

            title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \
                        l_time.fontMetrics().boundingRect(l_time.text()).width()
            title_height = l_title.fontMetrics().boundingRect(
                l_title.text()).height()

        font_size_level = font_size
        over_height_level = title_height - length
        over_width_level = title_width - col_width

        ### Checks maximum font size ifstacked
        font_size = MAX_EVENT_FONT_PT

        l_title = QLabel(event.title[self.lang])
        l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

        l_time.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))
        l_title.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))

        title_width = max(
            l_title.fontMetrics().boundingRect(l_title.text()).width(),
            l_time.fontMetrics().boundingRect(l_time.text()).width())
        title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \
            l_time.fontMetrics().boundingRect(l_time.text()).height()

        while (title_height > length
               or title_width > col_width) and font_size > MIN_EVENT_FONT_PT:
            font_size -= 1

            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))
            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))

            title_width = max(
                l_title.fontMetrics().boundingRect(l_title.text()).width(),
                l_time.fontMetrics().boundingRect(l_time.text()).width())
            title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \
                    l_time.fontMetrics().boundingRect(l_time.text()).height()

        font_size_stacked = font_size
        over_height_stacked = title_height - length
        over_width_stacked = title_width - col_width

        ### Doesn't draw labels if there is no way to fit them in the available
        #space
        if ((over_width_level > 0 or over_height_level > 0) and \
        (over_width_stacked > 0 or over_height_stacked > 0)):
            r = QtCore.QRectF(
                QtCore.QPointF(x_offset + x_loc * col_width,
                               t0_f * (self.h / 24)), space)

            pen = QtGui.QPen(QtCore.Qt.red)
            brush = QtGui.QBrush(QtCore.Qt.red)
            self.scheduleScene.addRect(r, pen, brush)

            return

        ### Sets font and arrangement to the better layout
        if font_size_level > font_size_stacked:
            level = True
        elif font_size_level < font_size_stacked:
            level = False
        else:
            if over_width_level <= 0 and over_height_level <= 0:
                level = True
            elif over_width_level > col_width:
                level = False
            elif over_height_stacked > 0:
                level = True
            else:
                level = False

        if level:
            l_title = QLabel(event.title[self.lang])
            l_time = QLabel(' (' + event.t0 + ' - ' + event.t1 + ')')

            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level,
                            QtGui.QFont.Normal))
            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level,
                            QtGui.QFont.Bold))

            l_title.move(x_offset + x_loc * col_width, t0_f * (self.h / 24))
            l_time.move(x_offset + x_loc * col_width + \
                        l_title.fontMetrics().boundingRect(l_title.text()).width(), t0_f * (self.h/24))
        else:
            l_title = QLabel(event.title[self.lang])
            l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked,
                            QtGui.QFont.Normal))
            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked,
                            QtGui.QFont.Bold))

            l_title.move(x_offset + x_loc * col_width, t0_f * (self.h / 24))
            l_time.move(x_offset + x_loc * col_width, t0_f * (self.h/24) + \
                        l_title.fontMetrics().boundingRect(l_title.text()).height())

        r = QtCore.QRectF(
            QtCore.QPointF(x_offset + x_loc * col_width, t0_f * (self.h / 24)),
            space)

        pen = QtGui.QPen(QtCore.Qt.blue)
        brush = QtGui.QBrush(QtCore.Qt.blue)
        self.scheduleScene.addRect(r, pen, brush)

        self.scheduleScene.addWidget(l_title)
        self.scheduleScene.addWidget(l_time)

    def getActivatedColumns(self):
        cols = []

        for key in self.schedule.columns:
            if self.activatedColumns[key]:
                cols.append(self.schedule.columns[key])

        cols = sorted(cols, key=lambda x: x.abr)
        return cols

    def getDeactivatedColumns(self):
        cols = []

        for key in self.schedule.columns:
            if not self.activatedColumns[key]:
                cols.append(self.schedule.columns[key])

        cols = sorted(cols, key=lambda x: x.abr)
        return cols

    def deactivateColumn(self, key):
        b = QPushButton(RESTORE[self.lang] + ' ' +
                        self.schedule.columns[key].name[self.lang])
        b.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        #b.setMinimumSize(20,1)
        self.restoreButtonLayout.insertWidget(-1, b)
        b.clicked.connect(partial(self.activateColumn, key, b))
        self.restore_buttons.append(b)

        self.activatedColumns[key] = False
        self.draw()

    def activateColumn(self, key, b):
        self.activatedColumns[key] = True
        self.draw()
        b.deleteLater()
        self.restore_buttons.remove(b)

    def restoreAllColumns(self):
        for key in self.activatedColumns:
            self.activatedColumns[key] = True
        for b in self.restore_buttons:
            b.deleteLater()
        self.restore_buttons = []
        self.draw()

    def translateWidgets(self):
        for widget in self.centralwidget.findChildren((QPushButton, QLabel)):
            try:
                widget.setText(self.translateDict[widget][self.lang])
            except KeyError:
                langDict = {}

                for l in languages:
                    langDict[l] = trans(widget.text(), l)
                    key = widget

                self.translateDict[key] = langDict

                widget.setText(self.translateDict[widget][self.lang])

    def changeLang(self, lang):
        self.lang = lang
        self.translateWidgets()
        self.drawAlarm.start(1)
Ejemplo n.º 10
0
class QGraphView(QGraphicsView):
    def __init__(self, centralwidget, graph: Graph):
        super().__init__(centralwidget)
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.rightButtonPressed = False
        self.leftButtonPressed = True
        self.startPos = QPointF()
        self.endPos = None
        self.edge_from = None
        self.moveVertex = None
        self.isVertex = None
        self.i = 0
        self.setRenderHint(QPainter.Antialiasing)

        self.pen = QPen(QColor(0, 0, 0), 3)
        self.greenPen = QPen(QColor(68, 191, 46), 3)
        self.pathPen = QPen(QColor(68, 133, 255), 3)
        self.pathBrush = QBrush(QColor(68, 133, 255))

        self.graph = graph
        self.graph.signals.update.connect(self.drawGraph)

    def mouseDoubleClickEvent(self, event: QMouseEvent):
        # print('double click')
        # только левая кнопка мыши
        pos = QPointF(self.mapToScene(event.pos()))
        if event.button() == 1:
            # получаем имя вершины
            name = self.graph.get_new_vertex_name()
            # преобразум коодинаты в координаты сцены
            # добавляем вершину в граф
            self.graph.add_vertex(name, pos.x(), pos.y())
        elif event.button() == 2:
            item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform())
            if item is None:
                return
            if type(item) is QGraphicsLineItem or type(item) is GraphicsEdge or 'node' in item.group().__dict__:
                if self.graph.oriented:
                    context_menu = QMenu(self)
                    change_orient = context_menu.addAction("Изменить направление")
                    action = context_menu.exec_(self.mapToGlobal(event.pos()))
                    if action == change_orient:
                        if type(item) is GraphicsEdge:
                            d = item.__dict__
                        else:
                            d = item.group().__dict__
                        self.graph.change_orient(d['v_from'].name, d['v_to'].name, d['weight'], d['node'])
            elif type(item) is QGraphicsEllipseItem or type(item) is QGraphicsSimpleTextItem:
                context_menu = QMenu(self)
                add_loop = context_menu.addAction("Добавить петлю")
                delete_loop = context_menu.addAction("Удалить петлю")
                delete_vertex = context_menu.addAction("Удалить вершину")
                action = context_menu.exec_(self.mapToGlobal(event.pos()))
                if action == delete_vertex:
                    self.graph.del_vertex(item.group().v.name)
                    self.drawGraph()
                if action == add_loop:
                    print(item.group().v.name)
                    self.graph.add_edge(item.group().v.name, item.group().v.name)
                if action == delete_loop:
                    self.graph.del_edge(item.group().v.name, item.group().v.name)

    def mousePressEvent(self, event: QMouseEvent):
        if event.button() == 2:
            self.rightButtonPressed = True
            item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform())
            if item:
                if type(item) is QGraphicsLineItem:
                    pass
                elif type(item) is GraphicsVertex:
                    self.startPos = self.mapToScene(event.pos())
                    self.edge_from = item.v.name
                elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem and not type(item) is GraphicsEdge:
                    if 'v' in item.group().__dict__:
                        self.startPos = self.mapToScene(event.pos())
                        self.edge_from = item.group().v.name
        elif event.button() == 1:
            self.leftButtonPressed = True
            item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform())
            if item:
                if type(item) is QGraphicsLineItem:
                    pass
                elif type(item) is GraphicsEdge:
                    self.moveVertex = item.node
                    self.setCursor(Qt.ClosedHandCursor)
                elif type(item) is GraphicsVertex:
                    self.moveVertex = item.v
                    self.setCursor(Qt.ClosedHandCursor)
                elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem and not type(item) is GraphicsEdge:
                    if type(item.group()) is GraphicsVertex:
                        self.moveVertex = item.group().v
                    else:
                        self.moveVertex = item.group().node
                    self.setCursor(Qt.ClosedHandCursor)

    def mouseMoveEvent(self, event: QMouseEvent):
        self.drawGraph()
        if self.rightButtonPressed and self.edge_from is not None:
            self.endPos = self.mapToScene(event.pos())
            self.scene.addLine(self.startPos.x(), self.startPos.y(), self.endPos.x(), self.endPos.y())
            # self.isVertex = True
        elif self.leftButtonPressed and self.moveVertex is not None:
            pos = QPointF(self.mapToScene(event.pos()))
            self.moveVertex.x = pos.x()
            self.moveVertex.y = pos.y()

    def mouseReleaseEvent(self, event: QMouseEvent):
        if event.button() == 2 and self.edge_from is not None:
            self.rightButtonPressed = False
            if type(self.scene.items()[0]) == QGraphicsLineItem:
                self.scene.removeItem(self.scene.items()[0])
            item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform())
            if item:
                if type(item) is QGraphicsLineItem:
                    pass
                elif type(item) is GraphicsVertex:
                    edge_to = item.v.name
                    if edge_to == 'node':
                        return
                    if edge_to != self.edge_from:
                        self.graph.add_edge(self.edge_from, edge_to)
                elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem:
                    if type(item.group()) is GraphicsEdge:
                        return
                    edge_to = item.group().v.name
                    if edge_to == 'node':
                        return
                    if edge_to != self.edge_from:
                        self.graph.add_edge(self.edge_from, edge_to)
            self.edge_from = None

        elif event.button() == 1:
            self.leftButtonPressed = False
            self.moveVertex = None
            self.setCursor(Qt.ArrowCursor)

    def drawGraph(self, simple: bool = False):
        if simple:
            self.simpleDrawGraph()
            return

        # очищаем сцену
        self.scene.clear()

        # рисуем ребра
        for v_from, to_dict in self.graph.vertexes.items():
            v_from = self.graph.vertexes_coordinates[v_from]
            for v_to, to_list in to_dict.items():
                v_to = self.graph.vertexes_coordinates[v_to]
                try:
                    for weight, node in to_list:
                        # key = f'{v_from.name}_{v_to.name}'
                        # if key in self.graph.edge_path and self.graph.edge_path[key] == weight:
                        #     pen = self.pathPen
                        # elif self.graph.oriented:
                        #     pen = self.greenPen
                        # else:
                        #     pen = self.pen

                        # if v_from is v_to:
                        #     pen = QPen(QBrush(QColor(255, 0, 0)), 3)
                        #     ellipse = QGraphicsEllipseItem(v_from.x - 30, v_from.y - 30, 30, 30)
                        #     ellipse.setPen(pen)
                        #     self.scene.addItem(ellipse)
                        # else:
                        # print(self.graph.oriented)
                        if self.graph.oriented:
                            key = f'{v_from.name}_{v_to.name}'
                            if (key, node) in self.graph.edge_path.items():
                                pen = self.pathPen
                            else:
                                pen = self.greenPen
                            self.scene.addLine(v_from.x, v_from.y, node.x, node.y, self.pen)
                            self.scene.addLine(node.x, node.y, v_to.x, v_to.y, pen)

                            # self.scene.addItem(line1)
                            # self.scene.addItem(line2)
                            self.scene.addItem(GraphicsEdge(v_from, v_to, node, self.graph.oriented, weight))
                        elif int(v_from.name) > int(v_to.name):
                            key = f'{v_from.name}_{v_to.name}'
                            rev_key = f'{v_to.name}_{v_from.name}'
                            if (key in self.graph.edge_path and self.graph.edge_path[key] == weight)\
                                    or (rev_key in self.graph.edge_path and self.graph.edge_path[rev_key] == weight):
                                pen = self.pathPen
                            else:
                                pen = self.pen
                            self.scene.addLine(v_from.x, v_from.y, node.x, node.y, pen)
                            self.scene.addLine(node.x, node.y, v_to.x, v_to.y, pen)

                            # self.scene.addItem(line1)
                            # self.scene.addItem(line2)
                            self.scene.addItem(GraphicsEdge(v_from, v_to, node, self.graph.oriented, weight))

                except TypeError as e:
                    # print(e)
                    self.graph.restore()
                    self.drawGraph()
                except Exception as e:
                    print(e)
                    exit(-2)

        # рисуем вершины
        for v in self.graph.vertexes_coordinates.values():
            self.scene.addItem(GraphicsVertex(v))

    def simpleDrawGraph(self):
        self.scene.clear()
        for v_from, to_dict in self.graph.vertexes.items():
            v_from = self.graph.vertexes_coordinates[v_from]
            for v_to, to_list in to_dict.items():
                v_to = self.graph.vertexes_coordinates[v_to]
                for weight, node in to_list:
                    self.scene.addLine(v_from.x, v_from.y, v_to.x, v_to.y)

        # рисуем вершины
        for v in self.graph.vertexes_coordinates.values():
            self.scene.addItem(GraphicsVertex(v))
Ejemplo n.º 11
0
class mainWindow(QtWidgets.QMainWindow):
    SCENE_WIDTH = 1070
    SCENE_HEIGHT = 751

    LINE_COLOR = QColorConstants.Black
    CUTTED_LINE_COLOR = QColorConstants.Magenta
    CUTTER_COLOR = QColorConstants.Red

    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        uic.loadUi("mainwindow.ui", self)
        self.scene = QGraphicsScene(0, 0, self.SCENE_WIDTH, self.SCENE_HEIGHT)
        self.main_scene.setScene(self.scene)

        self.lines = []
        self.ctrl_pressed = False
        self.adding_cutter = False  # If False then adding line on screen, otherwise adding cutter rectangle

        self.curr_line = []
        self.line_preview = None

        self.current_cutter = []
        self.cutter_preview = None

        self.cutter: Cutter = None

        self.add_line_btn.clicked.connect(self.addLineBtnHandler)
        self.clean_btn.clicked.connect(self.cleanScreen)
        self.add_cutter_btn.clicked.connect(self.addCutterBtnHandler)
        self.cut_btn.clicked.connect(self.cutBtnHandler)

        self.main_scene.setMouseTracking(True)
        self.main_scene.viewport().installEventFilter(self)

    def addLineBtnHandler(self):
        p1 = QPoint(self.x0_spin.value(), self.y0_spin.value())
        p2 = QPoint(self.x1_spin.value(), self.y1_spin.value())

        self.addLine(p1, p2)

    def addCutterBtnHandler(self):
        self.__delCutter()
        self.adding_cutter = True

    def cutBtnHandler(self):
        if self.cutter:
            xl = self.cutter.topLeft().x()
            yu = self.cutter.topLeft().y()
            xr = self.cutter.bottomRight().x()
            yd = self.cutter.bottomRight().y()

            for i in self.lines:
                p1 = [i.p1().x(), i.p1().y()]
                p2 = [i.p2().x(), i.p2().y()]

                visible, p1, p2 = simple_cut(xl, xr, yd, yu, p1, p2)

                if visible:
                    self.scene.addLine(p1[0], p1[1], p2[0], p2[1],
                                       self.CUTTED_LINE_COLOR)

    def eventFilter(self, source, event):
        if event.type(
        ) == QEvent.MouseMove and source is self.main_scene.viewport():
            self.__previewCutter(event.pos())
            self.__previewLine(event.pos())

        return QWidget.eventFilter(self, source, event)

    def mousePressEvent(self, a0: QtGui.QMouseEvent):
        but = a0.button()
        x = a0.x()
        y = a0.y()
        borders = self.main_scene.geometry().getCoords()
        if borders[0] <= x < borders[2] and borders[1] <= y < borders[3]:
            x -= borders[0]
            y -= borders[1]
        else:
            return

        if a0.buttons() == Qt.LeftButton:
            pos = QPoint(x, y)
            self.__drawLineHandler(pos)
            self.__drawCutterHandler(pos)

    def addLine(self, p1: QPoint, p2: QPoint):
        l = Line(p1, p2)
        self.lines.append(l)
        self.__drawLine(l)

    def addCutter(self, p1: QPoint, p2: QPoint):
        c = Cutter(p1, p2)
        self.cutter = c
        self.__drawCutter(c)

    def keyPressEvent(self, event):
        key = event.key()
        if key == Qt.Key_Control:
            self.ctrl_pressed = True

    def keyReleaseEvent(self, event):
        key = event.key()
        if key == Qt.Key_Control:
            self.ctrl_pressed = False

    def __drawLine(self, l: Line):
        lp = l.p1()
        rp = l.p2()

        l.setSceneItem(
            self.scene.addLine(lp.x(), lp.y(), rp.x(), rp.y(),
                               self.LINE_COLOR))

    def __drawCutter(self, c: Cutter):
        tl = c.topLeft()
        br = c.bottomRight()

        c.setSceneItem(
            self.scene.addRect(tl.x(), tl.y(),
                               br.x() - tl.x(),
                               br.y() - tl.y(), self.CUTTER_COLOR))

    def __drawLineHandler(self, p: QPoint):
        if self.adding_cutter == False:
            if len(self.curr_line) == 0 or not self.ctrl_pressed:
                self.curr_line.append(p)
            elif self.ctrl_pressed:
                line_start = self.curr_line[0]

                dx = p.x() - line_start.x()
                dy = p.y() - line_start.y()

                if abs(dy) > abs(dx):
                    self.curr_line.append(QPoint(line_start.x(), p.y()))
                else:
                    self.curr_line.append(QPoint(p.x(), line_start.y()))

            if len(self.curr_line) == 2:
                p1, p2 = self.curr_line

                self.addLine(p1, p2)
                self.curr_line.clear()
                self.scene.removeItem(self.line_preview)

    def __drawCutterHandler(self, p: QPoint):
        if self.adding_cutter:
            self.current_cutter.append(p)

            if len(self.current_cutter) == 2:
                v1, v2 = self.current_cutter
                self.addCutter(v1, v2)
                self.current_cutter.clear()
                self.scene.removeItem(self.cutter_preview)

                self.adding_cutter = False

    def __previewLine(self, p: QPoint):
        if len(self.curr_line) == 1:
            line_start = self.curr_line[0]

            if self.line_preview:
                self.scene.removeItem(self.line_preview)

            if self.ctrl_pressed:
                dx = p.x() - line_start.x()
                dy = p.y() - line_start.y()

                if abs(dy) >= abs(dx):
                    right_p = QPoint(line_start.x(), p.y())
                else:
                    right_p = QPoint(p.x(), line_start.y())

                self.line_preview = self.scene.addLine(line_start.x(),
                                                       line_start.y(),
                                                       right_p.x(),
                                                       right_p.y(),
                                                       self.LINE_COLOR)
            else:
                self.line_preview = self.scene.addLine(line_start.x(),
                                                       line_start.y(), p.x(),
                                                       p.y(), self.LINE_COLOR)

    def __previewCutter(self, p: QPoint):
        if len(self.current_cutter) == 1:
            lu_p = self.current_cutter[0]
            rd_p = p

            x_l = lu_p.x()
            x_r = rd_p.x()

            y_u = lu_p.y()
            y_d = rd_p.y()

            if self.cutter_preview:
                self.scene.removeItem(self.cutter_preview)

            if x_l > x_r:
                x_l, x_r = x_r, x_l
            if y_u > y_d:
                y_u, y_d = y_d, y_u

            self.cutter_preview = self.scene.addRect(x_l, y_u, x_r - x_l,
                                                     y_d - y_u,
                                                     self.CUTTER_COLOR)

    def __delCutter(self):
        if self.cutter is not None:
            self.scene.removeItem(self.cutter.sceneItem())
            self.current_cutter.clear()

    def cleanScreen(self):
        self.lines.clear()
        self.curr_line.clear()
        self.current_cutter.clear()

        self.line_preview = None
        self.cutter_preview = None
        self.cutter = None

        self.adding_cutter = False

        self.scene.clear()
Ejemplo n.º 12
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.º 13
0
class SchedulerGUI(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent=parent)
        self.setStyleSheet(MAIN_WINDOW_CSS)
        self.setupUi(self)

        self.scheduleFolder = sampleSchedule()
        self.schedule = self.scheduleFolder.schedulers[
            self.calendarWidget.selectedDate()]

        self.schedule.events[62].customGUI = MeasureWidget

        self.activatedColumns = {}

        for key in self.scheduleFolder.columns:
            self.activatedColumns[key] = True

        self.lang = 'en'

        self.restore_buttons = {}
        self.restoreAllButton.clicked.connect(self.restoreAllColumns)

        self.translateDict = {}
        for widget in self.centralwidget.findChildren((QPushButton)):
            langDict = {}

            for l in languages:
                langDict[l] = trans(widget.text(), l)
            key = widget

            self.translateDict[key] = langDict

        self.translateWidgets()

        self.language0Button.clicked.connect(partial(self.changeLang, 'en'))
        self.language1Button.clicked.connect(partial(self.changeLang, 'ru'))
        self.language2Button.clicked.connect(partial(self.changeLang, 'de'))
        self.language3Button.clicked.connect(partial(self.changeLang, 'ja'))
        self.language4Button.clicked.connect(partial(self.changeLang, 'fr'))
        self.language5Button.clicked.connect(partial(self.changeLang, 'it'))

        self.language0Button.setIcon(QtGui.QIcon('flags/United-States.png'))
        self.language1Button.setIcon(QtGui.QIcon('flags/Russia.png'))
        self.language2Button.setIcon(QtGui.QIcon('flags/Germany.png'))
        self.language3Button.setIcon(QtGui.QIcon('flags/Japan.png'))
        self.language4Button.setIcon(QtGui.QIcon('flags/France.png'))
        self.language5Button.setIcon(QtGui.QIcon('flags/Italy.png'))

        self.drawAlarm = QTimer()
        self.drawAlarm.timeout.connect(self.drawAlarmFunc)
        self.drawAlarm.start(0.3)

        self.calendarWidget.setNavigationBarVisible(False)
        self.calendarWidget.setStyleSheet(CALENDAR_CSS)

        self.calendarWidget.clicked.connect(self.updateDisplayedDate)
        self.calendarWidget.currentPageChanged.connect(self.updateNavBarDate)
        self.calendarWidget.selectionChanged.connect(self.updateDisplayedDate)
        self.updateDisplayedDate()
        self.updateNavBarDate()

        self.nextMonthButton.clicked.connect(self.calendarWidget.showNextMonth)
        self.prevMonthButton.clicked.connect(
            self.calendarWidget.showPreviousMonth)

        self.nextDayButton.clicked.connect(self.selectNextDate)
        self.prevDayButton.clicked.connect(self.selectPrevDate)
        self.todayButton.clicked.connect(self.selectToday)

        navBarWidgets = [
            self.prevMonthButton, self.displayedCalendarLabel,
            self.nextMonthButton
        ]

        for widget in self.centralwidget.findChildren(QPushButton):
            #if widget not in navBarWidgets:
            widget.setStyleSheet(MAIN_BUTTONS_CSS)

        weekendFormat = QTextCharFormat()
        weekendFormat.setForeground(QBrush(Qt.black, Qt.SolidPattern))
        self.calendarWidget.setWeekdayTextFormat(Qt.Saturday, weekendFormat)
        self.calendarWidget.setWeekdayTextFormat(Qt.Sunday, weekendFormat)

        self.customGUIs = {}

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_A:
            self.selectPrevDate()
        elif event.key() == QtCore.Qt.Key_D:
            self.selectNextDate()

    def closeEvent(self, event):
        quit()

    def resizeEvent(self, event):
        self.draw()

    def eventClicked(self, event):
        '''
        try:
            self.dockWidget.deleteLater()
        except AttributeError:
            pass
        '''
        if event.customGUI != None:
            self.dockWidget = event.customGUI(self)
        else:
            self.dockWidget = DefaultEvent(self)

        self.dockWidget.setAllowedAreas(Qt.RightDockWidgetArea
                                        | Qt.NoDockWidgetArea)
        self.dockWidget.setMinimumWidth(450)

        self.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)

        self.dockWidgetEvent = event
        self.updateEventPopupText()

    def updateEventPopupText(self):
        try:
            timeText = self.dockWidgetEvent.t0 + ' - ' + self.dockWidgetEvent.t1 + ' (GMT)'
            self.dockWidget.timeLabel.setText(timeText)
            self.dockWidget.titleLabel.setText(
                self.dockWidgetEvent.title[self.lang])
            self.dockWidget.summaryLabel.setText(
                self.dockWidgetEvent.summary[self.lang])
            self.dockWidget.descriptionLabel.setText(
                self.dockWidgetEvent.description[self.lang])
            self.dockWidget.setWindowTitle(
                self.dockWidgetEvent.title[self.lang])
        except AttributeError:
            pass

    def selectNextDate(self):
        date = self.calendarWidget.selectedDate()
        self.calendarWidget.setSelectedDate(date.addDays(1))

    def selectPrevDate(self):
        date = self.calendarWidget.selectedDate()
        self.calendarWidget.setSelectedDate(date.addDays(-1))

    def selectToday(self):
        self.calendarWidget.setSelectedDate(QDate.currentDate())
        self.calendarWidget.showToday()

    def updateNavBarDate(self):
        month = MONTH[self.calendarWidget.monthShown()][self.lang]
        year = self.calendarWidget.yearShown()
        self.displayedCalendarLabel.setText(month + " " + str(year))

    def updateDisplayedDate(self):
        self.dateLabel.setText(
            self.dateToStr(self.calendarWidget.selectedDate()))

        try:
            self.schedule = self.scheduleFolder.schedulers[
                self.calendarWidget.selectedDate()]
        except KeyError:
            self.schedule = Scheduler([])

        self.draw()

    def dateToStr(self, date):
        month = MONTH[date.month()][self.lang]
        year = date.year()
        day = date.day()

        return month + " " + str(day) + " " + str(year)

    def drawAlarmFunc(self):
        self.drawAlarm.stop()
        self.draw()

    def draw(self, w=-1):
        self.scheduleScene = QGraphicsScene()
        self.activatedScene = QGraphicsScene()

        if w == -1:
            self.w = self.scheduleView.width()
        else:
            self.w = w
        self.h = Y_SIDE * 24
        self.h_a = self.activatedView.height()

        self.gridPen = QPen(GRID_COLOR)

        for i in range(0, 24):
            self.scheduleScene.addLine(0, i * Y_SIDE, self.w, i * Y_SIDE)

        self.drawTimeTapes()

        cols = self.getActivatedColumns()

        x_offset = WIDTH_TL * len(self.scheduleFolder.timeTapes)

        if (len(cols) > 0):
            col_width = (self.w - x_offset) / len(cols)
            col_positions = self.drawColumns(cols, x_offset, col_width)

            for i in range(0, len(self.schedule.events)):
                try:
                    pos = col_positions[self.schedule.events[i].column_abr]

                    self.drawEvent(self.schedule.events[i], col_width, pos)
                except KeyError:
                    pass

        t_now = QTime.currentTime().hour() + QTime.currentTime().minute() / 60
        self.gridPen = QPen(Qt.green)
        self.gridPen.setWidth(2)
        self.scheduleScene.addLine(0, t_now * (self.h / 24), self.w,
                                   t_now * (self.h / 24), self.gridPen)
        t_fast_return = t_now + 40 / 60
        self.gridPen = QPen(Qt.red)
        self.gridPen.setWidth(2)
        self.scheduleScene.addLine(0, t_fast_return * (self.h / 24), self.w,
                                   t_fast_return * (self.h / 24), self.gridPen)

        self.scheduleView.setScene(self.scheduleScene)
        self.activatedView.setScene(self.activatedScene)

    def drawTimeTapes(self):
        for i in range(0, len(self.scheduleFolder.timeTapes)):
            self.scheduleScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h)

            self.activatedScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i,
                                        self.h_a)

            l = QLabel(self.scheduleFolder.timeTapes[i].name)
            l.move(WIDTH_TL * i + TT_X_BUFFER, TT_Y_BUFFER)
            l.setStyleSheet(TIME_TAPE_CSS)
            self.activatedScene.addWidget(l)

            for j in range(0, 24):
                l = QLabel(self.scheduleFolder.timeTapes[i].labels[j])
                l.move(WIDTH_TL * i + TT_X_BUFFER, Y_SIDE * j + TT_Y_BUFFER)
                l.setStyleSheet(TIME_TAPE_CSS)
                self.scheduleScene.addWidget(l)

    def drawColumns(self, cols, x_offset, col_width):

        col_positions = {}

        self.deactivateButtons = []
        for i in range(0, len(cols)):
            self.scheduleScene.addLine(x_offset + col_width * i, 0,
                                       x_offset + col_width * i, self.h)
            '''
            self.activatedScene.addLine(x_offset + col_width * i, 0, 
                                        x_offset + col_width * i, self.h_a)
            '''

            b = QPushButton(cols[i].name['en'])
            b.move(x_offset + col_width * i + COLUMN_BUTTON_X_BUFFER + 1, 0)
            b.clicked.connect(partial(self.deactivateColumn, cols[i].abr))
            b.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
            b.setStyleSheet(MAIN_BUTTONS_CSS)
            b.resize(col_width - COLUMN_BUTTON_X_BUFFER * 2, self.h_a - 2)

            b = self.activatedScene.addWidget(b)

            col_positions[cols[i].abr] = x_offset + col_width * i

        return col_positions

    def drawEvent(self, event, col_width, x_loc):

        t0_f = timeStrToFloat(event.t0)
        t1_f = timeStrToFloat(event.t1)

        length = (t1_f - t0_f) * (self.h / 24)

        space = QtCore.QSizeF(col_width - PEN_WIDTH, length - PEN_WIDTH)
        r = QtCore.QRectF(QtCore.QPointF(x_loc + 1,
                                         t0_f * (self.h / 24) + 1), space)

        pen = QPen(QtCore.Qt.black)
        pen.setWidth(PEN_WIDTH)
        brush = QBrush(event.color)

        ### Checks maximum font size if level
        font_size = MAX_EVENT_FONT_PT

        l_title = QLabel(event.title[self.lang] + "  ")
        l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

        l_time.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))
        l_title.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))

        title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \
            l_time.fontMetrics().boundingRect(l_time.text()).width() + W_BUFFER
        title_height = l_title.fontMetrics().boundingRect(
            l_title.text()).height() + H_BUFFER

        while (title_height > length
               or title_width > col_width) and font_size > MIN_EVENT_FONT_PT:
            font_size -= FONT_STEP

            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))
            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))

            title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \
                        l_time.fontMetrics().boundingRect(l_time.text()).width() + W_BUFFER
            title_height = l_title.fontMetrics().boundingRect(
                l_title.text()).height() + H_BUFFER

        font_size_level = font_size
        over_height_level = title_height - length
        over_width_level = title_width - col_width

        ### Checks maximum font size if stacked
        font_size = MAX_EVENT_FONT_PT

        l_title = QLabel(event.title[self.lang])
        l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

        l_time.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))
        l_title.setFont(
            QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))

        title_width = max(
            l_title.fontMetrics().boundingRect(l_title.text()).width(),
            l_time.fontMetrics().boundingRect(
                l_time.text()).width()) + W_BUFFER
        title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \
            l_time.fontMetrics().boundingRect(l_time.text()).height() + H_BUFFER

        while (title_height > length
               or title_width > col_width) and font_size > MIN_EVENT_FONT_PT:
            font_size -= FONT_STEP

            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))
            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal))

            title_width = max(
                l_title.fontMetrics().boundingRect(l_title.text()).width(),
                l_time.fontMetrics().boundingRect(
                    l_time.text()).width()) + W_BUFFER
            title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \
                    l_time.fontMetrics().boundingRect(l_time.text()).height() + H_BUFFER

        font_size_stacked = font_size
        over_height_stacked = title_height - length
        over_width_stacked = title_width - col_width

        ### Checks if it can draw the event without the time label if it is too big
        if ((over_width_level > 0 or over_height_level > 0) and \
        (over_width_stacked > 0 or over_height_stacked > 0)):
            font_size = MAX_EVENT_FONT_PT

            l_title = QLabel(event.title[self.lang])

            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold))

            title_width = l_title.fontMetrics().boundingRect(
                l_title.text()).width() + W_BUFFER
            title_height = l_title.fontMetrics().boundingRect(
                l_title.text()).height() + H_BUFFER

            while (title_height > length or
                   title_width > col_width) and font_size > MIN_EVENT_FONT_PT:
                font_size -= FONT_STEP

                l_title.setFont(
                    QtGui.QFont(DEFAULT_EVENT_FONT, font_size,
                                QtGui.QFont.Bold))

                title_width = l_title.fontMetrics().boundingRect(
                    l_title.text()).width() + W_BUFFER
                title_height = l_title.fontMetrics().boundingRect(
                    l_title.text()).height() + H_BUFFER

            font_size_level = font_size
            over_height_level = title_height - length
            over_width_level = title_width - col_width

            if (over_height_level > 0 or over_width_level > 0):
                l_title = QLabel('')
                l_time = QLabel('')
            else:
                l_title = QLabel(event.title[self.lang] + " ")
                l_title.setFont(
                    QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level,
                                QtGui.QFont.Bold))
                l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER)
                l_time = QLabel('')

            r = RectEvent(r)
            r.setInfo(self, event)
            r.setPen(pen)
            r.setBrush(brush)
            self.scheduleScene.addItem(r)

            l_title.setStyleSheet(EVENT_LABEL_CSS)
            l_time.setStyleSheet(EVENT_LABEL_CSS)

            self.scheduleScene.addWidget(l_title)
            self.scheduleScene.addWidget(l_time)

            return

        ### Sets font and arrangement to the better layout
        if font_size_level > font_size_stacked:
            level = True
        elif font_size_level < font_size_stacked:
            level = False
        else:
            if over_width_level <= 0 and over_height_level <= 0:
                level = True
            elif over_width_level > col_width:
                level = False
            elif over_height_stacked > 0:
                level = True
            else:
                level = False

        if level:
            l_title = QLabel(event.title[self.lang] + "  ")
            l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level,
                            QtGui.QFont.Normal))
            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level,
                            QtGui.QFont.Bold))

            l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER)
            l_time.move(x_loc + X_BUFFER + \
                        l_title.fontMetrics().boundingRect(l_title.text()).width(),
                        t0_f * (self.h/24) + Y_BUFFER)
        else:
            l_title = QLabel(event.title[self.lang])
            l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')')

            l_time.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked,
                            QtGui.QFont.Normal))
            l_title.setFont(
                QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked,
                            QtGui.QFont.Bold))

            l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER)
            l_time.move(x_loc + X_BUFFER, t0_f * (self.h/24) + Y_BUFFER + STACKED_BUFFER + \
                        l_title.fontMetrics().boundingRect(l_title.text()).height())

        r = RectEvent(r)
        r.setInfo(self, event)
        r.setPen(pen)
        r.setBrush(brush)
        self.scheduleScene.addItem(r)

        l_title.setStyleSheet(EVENT_LABEL_CSS)
        l_time.setStyleSheet(EVENT_LABEL_CSS)

        self.scheduleScene.addWidget(l_title)
        self.scheduleScene.addWidget(l_time)

    def getActivatedColumns(self):
        cols = []

        for key in self.scheduleFolder.columns:
            if self.activatedColumns[key]:
                cols.append(self.scheduleFolder.columns[key])

        cols = sorted(cols, key=lambda x: x.abr)
        return cols

    def getDeactivatedColumns(self):
        cols = []

        for key in self.scheduleFolder.columns:
            if not self.activatedColumns[key]:
                cols.append(self.scheduleFolder.columns[key])

        cols = sorted(cols, key=lambda x: x.abr)
        return cols

    def deactivateColumn(self, key):
        b = QPushButton(RESTORE[self.lang] + ' ' +
                        self.scheduleFolder.columns[key].name[self.lang])
        b.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        #b.setMinimumSize(20,1)
        b.setStyleSheet(MAIN_BUTTONS_CSS)
        self.restoreButtonLayout.insertWidget(-1, b)
        b.clicked.connect(partial(self.activateColumn, key, b))
        self.restore_buttons[b] = key

        self.activatedColumns[key] = False
        self.draw()

    def activateColumn(self, key, b):
        self.activatedColumns[key] = True
        self.draw()
        b.deleteLater()
        del self.restore_buttons[b]

    def restoreAllColumns(self):
        for key in self.activatedColumns:
            self.activatedColumns[key] = True
        for b in self.restore_buttons:
            b.deleteLater()
        self.restore_buttons = {}
        self.draw()

    def translateWidgets(self):
        restoreButs = list(self.restoreButtonLayout.itemAt(i).widget() \
                           for i in range(1,self.restoreButtonLayout.count()))

        for widget in self.centralwidget.findChildren(QPushButton):
            if widget not in restoreButs:
                try:
                    widget.setText(self.translateDict[widget][self.lang])
                except KeyError:
                    langDict = {}

                    for l in languages:
                        langDict[l] = trans(widget.text(), l)
                        key = widget

                    self.translateDict[key] = langDict

                    widget.setText(self.translateDict[widget][self.lang])
            else:
                key = self.restore_buttons[widget]
                widget.setText(RESTORE[self.lang] + ' ' +
                               self.scheduleFolder.columns[key].name['en'])

    def changeLang(self, lang):
        self.lang = lang
        self.translateWidgets()
        self.drawAlarm.start(1)
        self.updateDisplayedDate()
        self.updateNavBarDate()
        self.updateEventPopupText()
Ejemplo n.º 14
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.selected_area = 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.items_to_remove = [
        ]  # 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.graphics_scene = QGraphicsScene(0, 0, self.screenPixel.width(),
                                             self.screenPixel.height())

        self.show()
        self.setScene(self.graphics_scene)
        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.selected_area = QRect()
                self.selected_area.setTopLeft(QPoint(event.x(), event.y()))
                self.selected_area.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.selected_area = QRect()
                self.selected_area.setTopLeft(QPoint(event.x(), event.y()))
                self.selected_area.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.detect_mouse_position(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.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selected_area = QRect(self.selectedAreaRaw)

                if self.mousePosition == MousePosition.INSIDE_AREA:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    if 0 <= move_to_x <= self.screenPixel.width(
                    ) - 1 - self.selected_area.width():
                        self.selected_area.moveLeft(move_to_x)
                    if 0 <= move_to_y <= self.screenPixel.height(
                    ) - 1 - self.selected_area.height():
                        self.selected_area.moveTop(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.selectedAreaRaw = QRect(self.selected_area)
                    self.startX, self.startY = event.x(), event.y()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    if move_to_x <= self.selected_area.right():
                        self.selected_area.setLeft(move_to_x)
                        self.selected_area = self.selected_area.normalized()
                        self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    self.selected_area.setRight(move_to_x)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_UP_SIDE:
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTop(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE:
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottom(move_to_y)
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTopLeft(QPoint(move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottomRight(
                        QPoint(move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.right()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.top()
                    self.selected_area.setTopRight(QPoint(
                        move_to_x, move_to_y))
                    self.selected_area = self.selected_area.normalized()
                    self.redraw()
                elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER:
                    move_to_x = event.x(
                    ) - self.startX + self.selected_area.left()
                    move_to_y = event.y(
                    ) - self.startY + self.selected_area.bottom()
                    self.selected_area.setBottomLeft(
                        QPoint(move_to_x, move_to_y))
                    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.selected_area.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.selected_area.setBottomRight(QPoint(event.x(), event.y()))
                self.selectedAreaRaw = QRect(self.selected_area)
                self.action = ACTION_MOVE_SELECTED
                self.redraw()
            elif self.action == ACTION_MOVE_SELECTED:
                self.selectedAreaRaw = QRect(self.selected_area)
                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 detect_mouse_position(self, point):
        """
        :type point: QPoint
        :param point: the mouse position you want to check
        :return:
        """
        if self.selected_area == QRect():
            self.mousePosition = MousePosition.OUTSIDE_AREA
            return

        if self.selected_area.left() - ERRORRANGE <= point.x(
        ) <= self.selected_area.left() and (
                self.selected_area.top() - ERRORRANGE <= point.y() <=
                self.selected_area.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER
        elif self.selected_area.right() <= point.x(
        ) <= self.selected_area.right() + ERRORRANGE and (
                self.selected_area.top() - ERRORRANGE <= point.y() <=
                self.selected_area.top()):
            self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER
        elif self.selected_area.left() - ERRORRANGE <= point.x(
        ) <= self.selected_area.left() and (
                self.selected_area.bottom() <= point.y() <=
                self.selected_area.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER
        elif self.selected_area.right() <= point.x(
        ) <= self.selected_area.right() + ERRORRANGE and (
                self.selected_area.bottom() <= point.y() <=
                self.selected_area.bottom() + ERRORRANGE):
            self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER
        elif -ERRORRANGE <= point.x() - self.selected_area.left() <= 0 and (
                self.selected_area.topLeft().y() < point.y() <
                self.selected_area.bottomLeft().y()):
            self.mousePosition = MousePosition.ON_THE_LEFT_SIDE
        elif 0 <= point.x() - self.selected_area.right() <= ERRORRANGE and (
                self.selected_area.topRight().y() < point.y() <
                self.selected_area.bottomRight().y()):
            self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE
        elif -ERRORRANGE <= point.y() - self.selected_area.top() <= 0 and (
                self.selected_area.topLeft().x() < point.x() <
                self.selected_area.topRight().x()):
            self.mousePosition = MousePosition.ON_THE_UP_SIDE
        elif 0 <= point.y() - self.selected_area.bottom() <= ERRORRANGE and (
                self.selected_area.bottomLeft().x() < point.x() <
                self.selected_area.bottomRight().x()):
            self.mousePosition = MousePosition.ON_THE_DOWN_SIDE
        elif not self.selected_area.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
        watch_area_width = 16
        watch_area_height = 16

        cursor_pos = self.mousePoint

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

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

        # second, calculate the magnifier area
        magnifier_area_width = watch_area_width * 10
        magnifier_area_height = watch_area_height * 10
        font_area_height = 40

        cursor_size = 24
        magnifier_area = QRectF(
            QPoint(QCursor.pos().x() + cursor_size,
                   QCursor.pos().y() + cursor_size),
            QPoint(QCursor.pos().x() + cursor_size + magnifier_area_width,
                   QCursor.pos().y() + cursor_size + magnifier_area_height))
        if magnifier_area.right() >= self.screenPixel.width():
            magnifier_area.moveLeft(QCursor.pos().x() - magnifier_area_width -
                                    cursor_size / 2)
        if magnifier_area.bottom(
        ) + font_area_height >= self.screenPixel.height():
            magnifier_area.moveTop(QCursor.pos().y() - magnifier_area_height -
                                   cursor_size / 2 - font_area_height)

        # third, draw the watch area to magnifier area
        watch_area_scaled = watch_area_pixmap.scaled(
            QSize(magnifier_area_width * self.scale,
                  magnifier_area_height * self.scale))
        magnifier_pixmap = self.graphics_scene.addPixmap(watch_area_scaled)
        magnifier_pixmap.setOffset(magnifier_area.topLeft())

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

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

        # draw information
        self.graphics_scene.addRect(
            QRectF(
                magnifier_area.bottomLeft(),
                magnifier_area.bottomRight() +
                QPoint(0, font_area_height + 30)), Qt.black, QBrush(Qt.black))
        rgb_info = self.graphics_scene.addSimpleText(
            ' Rgb: ({0}, {1}, {2})'.format(point_rgb.red(), point_rgb.green(),
                                           point_rgb.blue()))
        rgb_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 5))
        rgb_info.setPen(QPen(QColor(255, 255, 255), 2))

        rect = self.selected_area.normalized()
        size_info = self.graphics_scene.addSimpleText(
            ' Size: {0} x {1}'.format(rect.width() * self.scale,
                                      rect.height() * self.scale))
        size_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 15) +
                         QPoint(0, font_area_height / 2))
        size_info.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.selected_area)
        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)

        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.graphics_scene.clear()

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

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

        top_left_point = rect.topLeft()
        top_right_point = rect.topRight()
        bottom_left_point = rect.bottomLeft()
        bottom_right_point = rect.bottomRight()
        top_middle_point = (top_left_point + top_right_point) / 2
        left_middle_point = (top_left_point + bottom_left_point) / 2
        bottom_middle_point = (bottom_left_point + bottom_right_point) / 2
        right_middle_point = (top_right_point + bottom_right_point) / 2

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

        if self.selected_area == QRect():
            self.graphics_scene.addRect(0, 0, self.screenPixel.width(),
                                        self.screenPixel.height(),
                                        QPen(Qt.NoPen), mask)
        else:
            self.graphics_scene.addRect(0, 0, self.screenPixel.width(),
                                        top_right_point.y(), QPen(Qt.NoPen),
                                        mask)
            self.graphics_scene.addRect(0, top_left_point.y(),
                                        top_left_point.x(), rect.height(),
                                        QPen(Qt.NoPen), mask)
            self.graphics_scene.addRect(
                top_right_point.x(), top_right_point.y(),
                self.screenPixel.width() - top_right_point.x(), rect.height(),
                QPen(Qt.NoPen), mask)
            self.graphics_scene.addRect(
                0, bottom_left_point.y(), self.screenPixel.width(),
                self.screenPixel.height() - bottom_left_point.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.selected_area != QRect():
            self.items_to_remove = []

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

            # draw the drag point
            radius = QPoint(3, 3)
            brush = QBrush(QColor(0, 255, 255))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_left_point - radius, top_left_point + radius),
                    pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_middle_point - radius,
                           top_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(top_right_point - radius, top_right_point + radius),
                    pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(left_middle_point - radius,
                           left_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(right_middle_point - radius,
                           right_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_left_point - radius,
                           bottom_left_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_middle_point - radius,
                           bottom_middle_point + radius), pen, brush))
            self.items_to_remove.append(
                self.graphics_scene.addEllipse(
                    QRectF(bottom_right_point - radius,
                           bottom_right_point + 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.graphics_scene.addRect(
                QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_ELLIPSE:
            self.graphics_scene.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.graphics_scene.addPolygon(arrow, step[5], step[6])
        elif step[0] == ACTION_LINE:
            self.graphics_scene.addLine(
                QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])),
                step[5])
        elif step[0] == ACTION_FREEPEN:
            self.graphics_scene.addPath(step[1], step[2])
        elif step[0] == ACTION_TEXT:
            textAdd = self.graphics_scene.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.selected_area.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.items_to_remove.append(
            self.graphics_scene.addRect(QRectF(sizeInfoArea), Qt.white,
                                        QBrush(Qt.black)))

        sizeInfo = self.graphics_scene.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.items_to_remove.append(sizeInfo)

    def drawRect(self, x1, x2, y1, y2, result):
        rect = self.selected_area.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.selected_area.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.selected_area.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.selected_area.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.selected_area = 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.º 15
0
class InitialPoseDialog(QDialog, Ui_PoseDialog):
    data_manager = None
    image = None
    y_line = 0
    y_top_line = 0
    y_lower_line = 0
    landmark_size = 2
    lines = None
    middle_idx = 0
    pose_model = None

    def __init__(self, data_manager):
        super(InitialPoseDialog, self).__init__()
        self.setupUi(self)
        self.setAttribute(Qt.WA_DeleteOnClose)

        assert isinstance(data_manager, DataManager)
        self.data_manager = data_manager
        self.pose_model = InitialPoseModel(data_manager)

        self.scene = QGraphicsScene()
        self.graphicsView.setScene(self.scene)

        self.image = Filter.crop_image(self.data_manager.radiographs[0].image)

        self.findButton.clicked.connect(self.find_jaw_divider)
        self.openButton.clicked.connect(self._open_radiograph)

        self._redraw()

    def find_jaw_divider(self):
        self.y_top_line, self.y_lower_line = self.pose_model._find_jaw_separation_line(self.pose_model._crop_image_sides(self.image))

        upper_jaw_image = self.pose_model.crop_upper_jaw(self.image, self.y_top_line)
        lower_jaw_image = self.pose_model.crop_lower_jaw(self.image, self.y_lower_line)

        # Filter the image
        upper_jaw_image = Filter.process_image(upper_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6)
        lower_jaw_image = Filter.process_image(lower_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6)

        upper_jaw_image = self.pose_model._convert_to_binary_image(upper_jaw_image)
        lower_jaw_image = self.pose_model._convert_to_binary_image(lower_jaw_image)

        upper_lines = self.pose_model._find_hough_lines(upper_jaw_image, threshold=15)
        lower_lines = self.pose_model._find_hough_lines(lower_jaw_image, threshold=15)

        # Filter out lines
        upper_lines = self.pose_model._filter_lines(upper_lines, upper_jaw_image.shape, line_offset=6, max_line_gap=90)
        lower_lines = self.pose_model._filter_lines(lower_lines, lower_jaw_image.shape, line_offset=2, max_line_gap=60)

        self.image = lower_jaw_image
        self.lines = lower_lines
        self._redraw()

    def _open_radiograph(self):
        file_dialog = QFileDialog(self)
        file_dialog.setDirectory("./data/Radiographs")
        file_dialog.setFileMode(QFileDialog.ExistingFile)
        file_dialog.setNameFilter("Radiograph (*.tif)")
        if file_dialog.exec_() and len(file_dialog.selectedFiles()) == 1:
            radiograph = Radiograph()
            radiograph.path_to_img = file_dialog.selectedFiles()[0]
            #self.image = radiograph.image
            #crop_translation = -Filter.get_cropping_region(radiograph.image).left_top
            self.image = Filter.crop_image(radiograph.image)
            self.lines = None
            self._redraw()

    def _redraw(self, normalize=False):
        self.scene.clear()

        img = self.image.copy()

        if normalize:
            img = (img / img.max()) * 255

        # Draw image
        qimg = toQImage(img.astype(np.uint8))
        self.scene.addPixmap(QPixmap.fromImage(qimg))

        # Add jaws divider
        self.scene.addLine(QLineF(0, self.y_line, self.image.shape[1], self.y_line), pen=QPen(QColor.fromRgb(255, 0, 0)))
        self.scene.addLine(QLineF(0, self.y_top_line, self.image.shape[1], self.y_top_line), pen=QPen(QColor.fromRgb(255, 0, 0)))
        self.scene.addLine(QLineF(0, self.y_lower_line, self.image.shape[1], self.y_lower_line), pen=QPen(QColor.fromRgb(255, 0, 0)))


        # Add image center
        self.scene.addEllipse(self.image.shape[0]/2 - self.landmark_size, self.image.shape[1]/2 - self.landmark_size,
                             self.landmark_size * 2, self.landmark_size * 2,
                             pen=QPen(QColor.fromRgb(255, 0, 0)), brush=QBrush(QColor.fromRgb(255, 0, 0)))

        # Draw Hough lines
        if self.lines is not None:
            #for x1,y1,x2,y2 in self.lines[0]:
            for i, line_param in enumerate(self.lines):
                    rho,theta = line_param
                    a = np.cos(theta)
                    b = np.sin(theta)
                    x0 = a*rho
                    y0 = b*rho
                    x1 = int(x0 + 200*(-b))
                    y1 = int(y0 + 200*(a))
                    x2 = int(x0 - 200*(-b))
                    y2 = int(y0 - 200*(a))
                    self.scene.addLine(QLineF(x1, y1, x2, y2), pen=QPen(QColor.fromRgb(0, 255, 0)))
Ejemplo n.º 16
0
class MapPainter(object):
    def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit):
        super().__init__()
        self.view = view
        self.displayCities = displayCities
        self.displayConnections = displayConnections
        self.displayBestUnit = displayBestUnit
        self.problemMap = None
        self.bestUnit = None

        self.scene = QGraphicsScene(parent)
        self.resizeScene()

        self.view.setScene(self.scene)
        self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)

    def resizeScene(self):
        height = self.view.size().height()
        width = self.view.size().width()
        self.scene.setSceneRect(0.0, 0.0, width, height)

    def setProblemMap(self, problemMap):
        self.problemMap = problemMap

    def setBestUnit(self, unit):
        self.bestUnit = unit

    def setDisplayCities(self, enabled = False):
        self.displayCities = bool(enabled)

    def setDisplayConnections(self, enabled = False):
        self.displayConnections = bool(enabled)

    def setDisplayBestUnit(self, enabled = False):
        self.displayBestUnit = bool(enabled)

    def repaint(self):
        if self.problemMap is None:
            return

        self.scene.clear()
        self.resizeScene()
        height = self.scene.height()
        width = self.scene.width()

        if self.displayCities:
            cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern)
            cityPen = QPen(cityBrush, 5.0)
            for city in self.problemMap.cities:
                x = width * city.positionX
                y = height * city.positionY
                self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush)

        if self.displayConnections:
            connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern)
            connectionPen = QPen(connectionBrush, 1.0)
            for city in self.problemMap.cities:
                for neighbour in city.connections:
                    x = width * city.positionX
                    y = height * city.positionY
                    x2 = width * self.problemMap.cities[neighbour].positionX
                    y2 = height * self.problemMap.cities[neighbour].positionY
                    self.scene.addLine(x, y, x2, y2, connectionPen)

        if self.displayBestUnit and self.bestUnit is not None:
            bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern)
            bestUnitPen = QPen(bestUnitBrush, 2.0)
            for i in range(-1, len(self.bestUnit.path)-1):
                currCity = self.problemMap.cities[self.bestUnit.path[i]]
                nextCity = self.problemMap.cities[self.bestUnit.path[i+1]]
                x = width * currCity.positionX
                y = height * currCity.positionY
                x2 = width * nextCity.positionX
                y2 = height * nextCity.positionY
                self.scene.addLine(x, y, x2, y2, bestUnitPen)

        self.view.fitInView(self.scene.sceneRect())
class Pyqt5_Serial(QtWidgets.QMainWindow, Ui_MainWindow):
    # 声明信号
    serial_signal = pyqtSignal(int, int)

    def __init__(self, parent=None):
        super(Pyqt5_Serial, self).__init__(parent=parent)
        self.setupUi(self)
        self.init()
        self.setWindowTitle("UWB串口助手")
        self.serial_uwb = serial.Serial()
        self.port_check()

        otherClass = MyDynamicMplCanvas()  # 信号和槽,传送数据给QDialoge
        self.serial_signal.connect(otherClass.robot_position)
        self.serial_signal.emit(0, 0)

        self.graphicsView.scale(1, -1)  # x轴倒转
        self.graphics()

    def init(self):
        # 串口检测按钮
        self.s1__box_1.clicked.connect(self.port_check)
        # 串口信息显示
        # self.s1__box_2.currentTextChanged.connect(self.port_info)
        # 打开串口按钮
        self.open_serial_button.clicked.connect(self.port_open)
        # 关闭串口按钮
        self.close_serial_button.clicked.connect(self.port_close)
        # 接受数据定时器
        self.timer_receive = QTimer(self)
        self.timer_receive.timeout.connect(self.data_receive)

    def port_check(self):
        """ 检测所有串口 """
        self.Com_Dict = {}  # 将所有串口信息存储在字典中
        port_list = list(serial.tools.list_ports.comports())
        self.s1__box_2.clear()
        for port in port_list:
            self.Com_Dict["%s" % port[0]] = "%s" % port[1]
            self.s1__box_2.addItem(port[0])
        if len(self.Com_Dict) == 0:
            self.open_serial_button.setEnabled(False)

    def port_open(self):
        """ 打开串口 """
        # self.serial_uwb.port = "COM3"  #串口号
        self.serial_uwb.port = self.s1__box_2.currentText()
        self.serial_uwb.baudrate = int(115200)  # 波特率
        self.serial_uwb.bytesize = int(8)  # 数据位
        self.serial_uwb.parity = "N"  # 奇偶性,即校验位
        self.serial_uwb.stopbits = int(1)  # 停止位

        # sudo chmod a+rw /dev/ttyACM0 给予权限

        try:
            self.serial_uwb.open()
        except:
            QMessageBox.critical(self, "Port Error", "此串口不能打开!")
            return None

        # 打开串口接收定时器,周期为2ms
        self.timer_receive.start(200)

        if self.serial_uwb.isOpen():
            self.open_serial_button.setEnabled(False)
            self.close_serial_button.setEnabled(True)

    def port_close(self):
        """ 关闭串口 """
        self.timer_receive.stop()
        try:
            self.serial_uwb.close()
        except:
            pass
        self.open_serial_button.setEnabled(True)
        self.close_serial_button.setEnabled(False)

    def data_receive(self):

        otherClass = MyDynamicMplCanvas()  # 信号和槽,传送数据给QDialoge
        """ 数据接收 """
        try:
            num = self.serial_uwb.inWaiting()
        except:
            self.port_close()
            return None
        if num > 0:
            serial_data = self.serial_uwb.read(num)
            unicode_data = serial_data.decode('iso-8859-1')
            # print(unicode_data)
            # return unicode_data

            data_lines = unicode_data.split('\r\n')  # 列表

            for line in data_lines:
                data = line.split()
                if len(data) == 10:
                    # print(data)
                    if (data[0] == 'ma'):  # 表示基站0到基站x的距离
                        if (
                                data[1] != '0e'
                        ):  # MASK=e(0000 1111)表示 RANGE0,RANGE1,RANGE2,RANGE3 都有效
                            print("ma's Range 只有 " + data[1] + " 工作。")
                            # break
                        else:
                            # 16进制转为10进制,距离单位:mm
                            # range_0 = int(data[2],16) range_0没有'ma'对应的操作说明
                            # self.serial__receive_text.insertPlainText(unicode_data)
                            range_1 = int(data[3], 16)
                            range_2 = int(data[4], 16)
                            # range_3 = int(data[5],16)
                            # print("基站0到基站1的距离:%d"%(range_1)+",基站0到基站2的距离:%d"%(range_2)+",基站0到基站3的距离:%d"%(range_3))

                    else:  # data[0] == 'mc' or 'mr' :表示标签x到基站y的距离
                        if (data[1] != '07'
                            ):  # MASK=7(0000 0111)表示 RANGE0,RANGE1,RANGE2 都有效
                            print("mc's Range 只有 " + data[1] + " 工作。")
                            # break
                        else:
                            # 16进制转为10进制,距离单位:mm
                            range_0 = int(data[2], 16)
                            range_1 = int(data[3], 16)
                            range_2 = int(data[4], 16)
                            # range_3 = int(data[5],16)
                            # print("标签x到基站0的距离:%d" % (range_0) +
                            #       ",标签x到基站1的距离:%d" % (range_1) +
                            #       ",标签x到基站2的距离:%d" % (range_2))

                            anchor_0 = np.array([0, 0], dtype=np.int64)
                            anchor_1 = np.array([7500, 0], dtype=np.int64)
                            anchor_2 = np.array([0, 5000], dtype=np.int64)
                            tag_position = self.getLocation(
                                anchor_0, anchor_1, anchor_2, range_0, range_1,
                                range_2)
                            # if (tag_position[0]-anchor_2[0])**2 + (tag_position[1]-anchor_2[1])**2 > range_2:

                            if tag_position[1] != -1:
                                # print("标签坐标X:%f" %
                                #       tag_position[0] + ",Y:%f" % tag_position[1])
                                self.graphics(
                                    [tag_position[0], tag_position[1]])

                                self.serial_signal.connect(
                                    otherClass.robot_position)
                                self.serial_signal.emit(
                                    tag_position[0], tag_position[1])

        else:
            pass

    def getLocation(self, anchor_0, anchor_1, anchor_2, range_0, range_1,
                    range_2):
        """ 根据trilateration 计算标签的坐标 """
        tag_position = np.array([0, 0], dtype=np.int64)
        tag_position[0] = int(
            (range_0**2 - range_1**2 + anchor_1[0]**2) / (2 * anchor_1[0]))
        distance = range_0**2 - tag_position[0]**2
        # print(type(distance))
        if distance > 0:
            tag_position[1] = np.sqrt(distance)
        else:
            tag_position[1] = -1

        return tag_position

        # ValueError: cannot convert float NaN to integer #17

    def graphics(self, newPos=[0, 0]):
        """ qt绘图 """
        axis_x = 750
        axis_y = 500

        # self.rect = QRectF(0,0,w-10,h-10)
        # self.scene = QGraphicsScene(self.rect)
        self.scene = QGraphicsScene()

        self.graphicsView.setScene(self.scene)

        self.scene.addRect(0, 0, axis_x, axis_y)

        self.scene.addEllipse(0 - 8,
                              0 - 8,
                              15,
                              15,
                              brush=QBrush(QColor.fromRgb(120, 50, 255)))
        self.scene.addEllipse(0 - 8,
                              axis_y - 8,
                              15,
                              15,
                              brush=QBrush(QColor.fromRgb(120, 50, 255)))
        self.scene.addEllipse(axis_x - 8,
                              0 - 8,
                              15,
                              15,
                              brush=QBrush(QColor.fromRgb(120, 50, 255)))
        self.scene.addEllipse(axis_x - 8,
                              axis_y - 8,
                              15,
                              15,
                              brush=QBrush(QColor.fromRgb(120, 50, 255)))

        self.scene.addLine(0,
                           0,
                           axis_x,
                           0,
                           pen=QPen(QColor.fromRgb(255, 0, 0)))
        self.scene.addLine(0,
                           0,
                           0,
                           axis_y,
                           pen=QPen(QColor.fromRgb(255, 0, 0)))

        self.anchor_0 = np.array([0, 0], dtype=np.int64)
        self.anchor_1 = np.array([axis_x, 0], dtype=np.int64)
        self.anchor_2 = np.array([0, axis_y], dtype=np.int64)

        brick_width = 1000 / 10  # 砖长:300mm
        brick_height = 1000 / 10
        self.brick_gap = 50 / 10  # 砖间隙:5mm

        global height_num, width_num
        height_num = np.int(self.anchor_2[1] / brick_height)
        width_num = np.int(self.anchor_1[0] / brick_width)

        global bricks  # 全局
        bricks = np.zeros((width_num * height_num, 5),
                          dtype=int)  # 可利用json数据类型
        """ 砖摆放,从x,y轴出发 """
        for j in range(height_num):
            for i in range(width_num):

                self.brick_x = i * (self.brick_gap + brick_width)
                self.brick_y = j * (self.brick_gap + brick_height)

                bricks[i + j] = [i, j, self.brick_x, self.brick_y,
                                 0]  # 填写每一块砖的信息
                # print(bricks[i+j])

                rectangle_item = QGraphicsRectItem(self.brick_x, self.brick_y,
                                                   brick_width, brick_height)
                # Add the patch to the Axes
                # currentAxis.add_patch(self.rectangle)
                self.scene.addItem(rectangle_item)

        robot_item = QGraphicsEllipseItem(newPos[0] / 10, newPos[1] / 10, 10,
                                          10)
        robot_item.setBrush(QBrush(QColor.fromRgb(0, 255, 255)))
        self.scene.addItem(robot_item)

    def wheelEvent(self, event):
        """
            Zoom in or out of the view.
        """
        zoomInFactor = 1.25
        zoomOutFactor = 1 / zoomInFactor

        # Save the scene pos
        oldPos = self.graphicsView.mapToScene(event.pos())
        # print("oldPos:%d" %oldPos[0])

        # Zoom
        if event.angleDelta().y() > 0:
            zoomFactor = zoomInFactor
        else:
            zoomFactor = zoomOutFactor
        self.graphicsView.scale(zoomFactor, zoomFactor)

        # Get the new position
        newPos = self.graphicsView.mapToScene(event.pos())

        # Move scene to old position
        delta = newPos - oldPos
        self.graphicsView.translate(delta.x(), delta.y())
Ejemplo n.º 18
0
class GraphCanvas(QGraphicsView):
    def __init__(self, width, height):
        QGraphicsView.__init__(self)
        self.width, self.height = width, height
        self.setGeometry(0, 0, width, height)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene(0, 0, width, height - 80)
        self.setScene(self.scene)
        self.chrisSteps = {
            1: "self.colorMST",
            2: "self.colorOddVertices",
            3: "self.oddVSubGraph",
            4: "self.perfectMatching",
            5: "self.eulerian",
            6: "self.hamiltonian"
        }
        self.delay = 2000

    def drawGraph(self, verticesNb):
        self.scene.clear()
        blackPen = QPen(Qt.black)
        blackPen.setWidth(3)
        vertices = []
        self.graphicVertices = []
        self.verticesNb = verticesNb

        for i in range(verticesNb):
            y = (self.height / 10 + self.width / 2) - sin(
                radians(i * 360 / verticesNb)) * (self.width / 2 - 20)
            x = self.width / 2 + cos(radians(
                i * 360 / verticesNb)) * (self.width / 2 - 20)
            self.graphicVertices.append(
                self.scene.addEllipse(x - 15, y - 15, 30, 30, blackPen))
            j = i + 1
            for j in range(i):
                self.scene.addLine(x, y, vertices[j][0], vertices[j][1])
            vertices.append((x, y))

        self.scene.update()
        return vertices

    def drawStep(self, edges, color="black"):
        self.scene.clear()
        pen = QPen(eval("Qt." + color))
        pen.setWidth(3)
        self.drawVertices()
        for e in edges:
            self.scene.addLine(e[0][0], e[0][1], e[1][0], e[1][1], pen)

        self.scene.update()

    def colorSubTour(self, subTours, step):
        print("hello")
        self.scene.clear()
        pen = QPen()
        pen.setWidth(2)
        self.drawVertices()
        for subTour in subTours:
            pen.setColor(
                QColor(randint(0, 255), randint(0, 255), randint(0, 255)))
            for i in range(len(subTour) - 1):
                self.scene.addLine(subTour[i][0], subTour[i][1],
                                   subTour[i + 1][0], subTour[i + 1][1], pen)
            self.scene.addLine(subTour[-1][0], subTour[-1][1], subTour[0][0],
                               subTour[0][1], pen)
        if not step:
            QtTest.QTest.qWait(self.delay)

    def drawVertices(self):
        pen = QPen(Qt.black)
        pen.setWidth(2)
        for i in range(self.verticesNb):
            y = (self.height / 10 + self.width / 2) - sin(
                radians(i * 360 / self.verticesNb)) * (self.width / 2 - 20)
            x = self.width / 2 + cos(radians(
                i * 360 / self.verticesNb)) * (self.width / 2 - 20)
            ellipse = self.scene.addEllipse(x - 15, y - 15, 30, 30, pen)

#################################################################################################################
#
#												CHRISTOFIDES
#
#################################################################################################################

    def updateChristofides(self, step, *args):
        if not step:
            QtTest.QTest.qWait(self.delay)
        print("args[0] " + str(args[0]))
        step = self.chrisSteps[args[0]]
        args = args[1:]
        eval(step + "(*args)")

    def colorMST(self, MST):
        self.MST = MST
        self.drawEdges(MST, Qt.blue)

    def colorOddVertices(self, oddVertices):
        self.oVertices = []
        brush = QBrush()
        brush.setStyle(Qt.SolidPattern)
        brush.setColor(Qt.cyan)
        for vertice in oddVertices:
            self.oVertices.append(vertice)
            self.graphicVertices[vertice].setBrush(brush)

    def oddVSubGraph(self, vertices):
        pen = QPen()
        pen.setWidth(2)
        pen.setColor(Qt.cyan)
        self.scene.clear()
        self.drawGraph(self.verticesNb)
        self.colorOddVertices(self.oVertices)
        for i in range(len(self.oVertices)):
            for j in range(i, len(self.oVertices)):
                self.scene.addLine(vertices[self.oVertices[i]][0],
                                   vertices[self.oVertices[i]][1],
                                   vertices[self.oVertices[j]][0],
                                   vertices[self.oVertices[j]][1], pen)

    def perfectMatching(self, PM):
        self.PM = PM
        self.drawEdges(PM, Qt.red)

    def eulerian(self, PM):
        self.scene.clear()
        self.drawGraph(self.verticesNb)
        self.drawEdges(self.PM, Qt.red)
        self.drawEdges(self.MST, Qt.blue)
        QtTest.QTest.qWait(2000)
        eulerian = self.PM + self.MST
        self.drawEdges(eulerian, Qt.magenta)

    def hamiltonian(self, edges):
        self.scene.clear()
        self.drawGraph(self.verticesNb)
        self.drawEdges(edges, Qt.green)

    def drawEdges(self, edges, color=Qt.black):
        pen = QPen()
        pen.setWidth(2)
        pen.setColor(color)
        for edge in edges:
            self.scene.addLine(edge[0][0], edge[0][1], edge[1][0], edge[1][1],
                               pen)
        self.scene.update()

    # def drawGraph(self,vertices,edges):
    # 	for vertice in vertices:

    def updateDelay(self, delay):
        self.delay = delay
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.º 20
0
class RecordsetWindow(QWidget):

    #sensorsColor = ['e0c31e', '14148c', '006325', '6400aa', '14aaff', 'ae32a0', '80c342', '868482']

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

        self.sensors = {}
        self.sensors_items = {}
        self.sensors_graphs = {}

        self.time_pixmap = False

        self.time_bar = None

        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(),
                                        Qt.KeepAspectRatio)
        self.UI.graphTimeline.time_clicked.connect(self.timeview_clicked)
        """blackBrush = QBrush(Qt.black)
        blueBrush = QBrush(Qt.blue)
        blackPen = QPen(Qt.black)
        self.timeScene.addRect(100, 0, 80, 100, blackPen, blueBrush)
        rectangle = self.timeScene.addRect(100, 0, 80, 100, blackPen, blackBrush)
        rectangle.setFlag(QGraphicsItem.ItemIsMovable)"""

        # Update general informations about recordsets
        self.update_recordset_infos()

        # Load sensors for that recordset
        self.load_sensors()

        self.UI.lstSensors.itemChanged.connect(self.sensor_current_changed)

    def paintEvent(self, QPaintEvent):
        if not self.time_pixmap:
            self.draw_recordsets()
            self.draw_sensors()
            self.draw_dates()
            self.draw_timebar()
            self.time_pixmap = True

    def load_sensors(self):
        self.UI.lstSensors.clear()
        self.sensors = {}
        self.sensors_items = {}

        # Create sensor colors
        used_colors = []
        #colors = QColor.colorNames()
        colors = [
            'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgreen', 'darkgrey',
            'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange',
            'darkorchid', 'darkred', 'darksalmon', 'darkseagreen',
            'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise',
            'darkviolet'
        ]

        # Filter "bad" colors for sensors
        """colors.remove("white")
        colors.remove("black")
        colors.remove("transparent")
        colors.remove("red")
        colors.remove("green")"""

        # shuffle(colors)
        color_index = 0

        if len(self.recordsets) > 0:
            for sensor in self.dbMan.get_sensors(self.recordsets[0]):
                self.sensors[sensor.id_sensor] = sensor

        for sensor in self.sensors.values():
            index = -1
            location_item = self.UI.lstSensors.findItems(
                sensor.location, Qt.MatchExactly)
            if len(location_item) == 0:
                item = QListWidgetItem(sensor.location)
                item.setFlags(Qt.NoItemFlags)
                self.UI.lstSensors.addItem(item)
            else:
                index = self.UI.lstSensors.indexFromItem(
                    location_item[0]).row()

            # Check if sensor is already there under that location item
            sensor_name = sensor.name + " (" + sensor.hw_name + ")"
            present = False
            if index != -1:
                for i in range(index, self.UI.lstSensors.count()):
                    if self.UI.lstSensors.item(i).text() == sensor_name:
                        present = True
                        break

            if not present:
                item = QListWidgetItem(QIcon(':/OpenIMU/icons/sensor.png'),
                                       sensor_name)
                item.setCheckState(Qt.Unchecked)
                item.setForeground(QColor(colors[color_index]))
                item.setData(Qt.UserRole, sensor.id_sensor)
                #self.sensors_colors.append(colors[color_index])
                self.sensors_items[sensor.id_sensor] = item
                color_index += 1
                if color_index >= len(colors):
                    color_index = 0

                if index == -1:
                    self.UI.lstSensors.addItem(item)
                else:
                    self.UI.lstSensors.insertItem(index + 2, item)

    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(str(start_time) + " @ " + str(end_time))

        # Duration
        self.UI.lblDurationValue.setText(str(end_time - start_time))

        self.UI.lblCursorTime.setText(str(start_time))

    def get_relative_timeview_pos(self, current_time):
        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
        return (((current_time -
                  self.recordsets[0].start_timestamp).total_seconds()) /
                time_span) * self.UI.graphTimeline.width()

    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
        whitePen = QPen(Qt.white)
        blackPen = QPen(Qt.black)
        blackBrush = QBrush(Qt.black)

        # Date background rectangle
        self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(),
                               self.UI.graphTimeline.height() / 4, blackPen,
                               blackBrush)

        # First date
        date_text = self.timeScene.addText(start_time.strftime("%d-%m-%Y"))
        date_text.setPos(0, -5)
        date_text.setDefaultTextColor(Qt.white)
        self.timeScene.addLine(0, 0, 0, self.UI.graphTimeline.height(),
                               whitePen)

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

    def draw_recordsets(self):
        greenBrush = QBrush(QColor(212, 247, 192))
        transPen = QPen(Qt.transparent)

        # Empty rectangle (background)
        self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(),
                               self.UI.graphTimeline.height(), transPen,
                               QBrush(Qt.red))
        self.timeScene.setBackgroundBrush(QBrush(Qt.red))

        # 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
            self.timeScene.addRect(start_pos, 0, span,
                                   self.UI.graphTimeline.height(), transPen,
                                   greenBrush)

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

        bar_height = (3 *
                      (self.UI.graphTimeline.height() / 4)) / len(self.sensors)
        # for sensor in self.sensors:
        i = 0
        for sensor in self.sensors.values():
            sensorBrush = QBrush(
                self.sensors_items[sensor.id_sensor].foreground())
            sensorPen = QPen(Qt.transparent)
            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.start_timestamp)
                    end_pos = self.get_relative_timeview_pos(
                        data.end_timestamp)
                    span = max(end_pos - start_pos, 1)
                    self.timeScene.addRect(
                        start_pos,
                        i * bar_height + (self.UI.graphTimeline.height() / 4),
                        span, bar_height, sensorPen, sensorBrush)
            i += 1

    def draw_timebar(self):
        self.time_bar = self.timeScene.addLine(0, 0, 0,
                                               self.timeScene.height(),
                                               QPen(Qt.cyan))

    @pyqtSlot(QListWidgetItem)
    def sensor_current_changed(self, item):
        sensor = self.sensors[item.data(Qt.UserRole)]
        timeseries = []
        # Color map
        colors = [Qt.red, Qt.green, Qt.darkBlue]

        if item.checkState() == Qt.Checked:
            # Choose the correct display for each sensor

            channels = self.dbMan.get_all_channels(sensor=sensor)
            for channel in channels:
                # Will get all data (converted to floats)
                channel_data = []
                for record in self.recordsets:
                    channel_data += self.dbMan.get_all_sensor_data(
                        recordset=record,
                        convert=True,
                        sensor=sensor,
                        channel=channel)

            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:

                timeseries.append(self.create_data_timeseries(channel_data))
                timeseries[-1]['label'] = channel.label

                graph = IMUChartView()
                # graph.add_test_data()
                # Add series
                for series in timeseries:
                    graph.add_data(series['x'],
                                   series['y'],
                                   color=colors.pop(),
                                   legend_text=series['label'])

                graph.set_title(item.text())
                self.UI.mdiArea.addSubWindow(graph).setWindowTitle(item.text())
                graph.show()

                self.sensors_graphs[sensor.id_sensor] = graph
                graph.aboutToClose.connect(self.graph_was_closed)
                graph.cursorMoved.connect(self.graph_cursor_changed)

                self.tile_graphs_vertically()

            if sensor.id_sensor_type == SensorType.GPS:
                graph = GPSView(self.UI.mdiArea)

                for data in channel_data:
                    gps = GPSGeodetic()
                    gps.from_bytes(data.data)
                    if gps.latitude != 0 and gps.longitude != 0:
                        graph.addPosition(data.start_timestamp,
                                          gps.latitude / 1e7,
                                          gps.longitude / 1e7)
                        graph.setCursorPositionFromTime(data.start_timestamp)
                    # print (gps)

                self.UI.mdiArea.addSubWindow(graph).setWindowTitle(item.text())
                graph.show()
                self.sensors_graphs[sensor.id_sensor] = graph
                graph.aboutToClose.connect(self.graph_was_closed)
                graph.cursorMoved.connect(self.graph_cursor_changed)

        else:
            # Remove from display
            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] = None

    @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
                self.sensors_items[sensor_id].setCheckState(Qt.Unchecked)
                break

        # self.tile_graphs_vertically()

    @pyqtSlot(datetime)
    def graph_cursor_changed(self, timestamp):
        for graph in self.sensors_graphs.values():
            if graph is not None:
                graph.setCursorPositionFromTime(timestamp, False)

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

    @pyqtSlot(int)
    def timeview_clicked(self, x):
        self.time_bar.setPos(x, 0)

        # Find time corresponding to that position
        timestamp = (x / self.timeScene.width()) * (
            self.recordsets[len(self.recordsets) - 1].end_timestamp - self.
            recordsets[0].start_timestamp) + self.recordsets[0].start_timestamp
        self.UI.lblCursorTime.setText(str(timestamp))

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

    @timing
    def create_data_timeseries(self, sensor_data_list: list):

        time_values = []
        data_values = []

        for sensor_data in sensor_data_list:
            # print('sensor_data', sensor_data)
            # Will get a dict with keys:  time, values
            vals = sensor_data.to_time_series()
            # print('vals is length', len(vals))
            time_values.append(vals['time'])
            data_values.append(vals['values'])

        # print('time_values length', len(time_values))
        # print('data_values length', len(data_values))

        # Concat vectors
        time_array = np.concatenate(time_values)
        data_array = np.concatenate(data_values)

        # Test, remove first time
        # time_array = time_array - time_array[0]

        # print('time_array_shape, data_array_shape', time_array.shape, data_array.shape)
        # return data
        return {'x': time_array, 'y': data_array}

    def tile_graphs_horizontally(self):

        if self.UI.mdiArea.subWindowList() is None:
            return

        position = QPoint(0, 0)

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

    def tile_graphs_vertically(self):

        if self.UI.mdiArea.subWindowList() is None:
            return

        position = QPoint(0, 0)

        for window in self.UI.mdiArea.subWindowList():
            rect = QRect(
                0, 0, self.UI.mdiArea.width(),
                self.UI.mdiArea.height() /
                len(self.UI.mdiArea.subWindowList()))
            window.setGeometry(rect)
            window.move(position)
            position.setY(position.y() + window.height())
Ejemplo n.º 21
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.º 22
0
class DijkstraGui(QMainWindow, Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)

        # event
        self.btnGenerate.clicked.connect(self.btnGenerate_Clicked)
        self.btnFind.clicked.connect(self.btnFind_Clicked)
        self.cbxShowSteps.stateChanged.connect(self.cbxShowSteps_Clicked)
        self.lineEditPoint.textChanged.connect(self.lineEditPoint_TextChanged)
        self.lineEditLine.textChanged.connect(self.lineEditLine_TextChanged)

        self.countPoints = self.lineEditPoint.text()
        self.countLines = self.lineEditLine.text()

        self.RADIUS = 20
        self.RADIUS2 = self.RADIUS * 2
        self.RADIUS3 = self.RADIUS + 3
        self.SIZE = 150
        self.countPoint, self.countLine, self.countStep, self.maxStep = 0, 0, 0, 0
        self.newDistance, self.listSteps, self.listPath = [], [], []
        self.points = [QPoint(0, 0) for i in range(20)]
        self.listLine = [QPoint(0, 0) for i in range(400)]
        self.distance = np.empty((20, 20), dtype=object)
        self.lines = np.empty((20, 20), dtype=Pair)
        self.start, self.end = -1, -1
        self.isDone, self.isFounded = False, False
        self.chooseState = 0
        self.textChoose = [
            'vuongdq85', 'Choose point start...', 'Choose point end...'
        ]

        pen = QPen(Qt.black, 2)
        penStart = QPen(Qt.darkGreen, 4)
        penDest = QPen(Qt.darkRed, 4)

        pencil = QPen(Qt.red, 4)

        # draw canvas
        self.scene = QGraphicsScene()
        self.scene.addLine(400, 100, 100, 100, pencil)
        self.graphicsViewPaint.setScene(self.scene)

        #
        self.reset()
        self.generate()

    # func event
    def btnGenerate_Clicked(self):
        print("btnGenerate")
        print("Point: {0}".format(self.countPoints))
        print("Line: {0}".format(self.countLines))

        self.reset()
        ok = False

        try:
            self.countPoints = int(self.lineEditPoint.text())
            self.countLines = int(self.lineEditLine.text())
            if ((0 < self.countPoints and self.countPoints <= 20)
                    and (0 < self.countLines and self.countLines <= 380)):
                ok = True
        except Exception as ex:
            pass

        print(ok)

        if ok:
            self.generate()
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Wrong amount of points")
            msg.setWindowTitle("Error")
            msg.exec_()

    def btnFind_Clicked(self):
        print("btnFind")

    def cbxShowSteps_Clicked(self, int):
        if (self.cbxShowSteps.isChecked()):
            print("cbxShowSteps Checked")
        else:
            print("cbxShowSteps unChecked")

    def lineEditPoint_TextChanged(self):
        self.countPoints = self.lineEditPoint.text()

    def lineEditLine_TextChanged(self):
        self.countLines = self.lineEditLine.text()

    def graphicsViewPaint_draw(self):
        self.scene.addEllipse(400, 100, 100, 100)
        self.graphicsViewPaint.setScene(self.scene)

    def generate(self):
        print('generate')

        array = np.zeros(20, dtype=np.int64)

        k = 0
        count = 20
        region = 0
        for i in range(0, int(self.countPoints)):
            for j in range(0, int(self.countPoints)):
                self.distance[i, j] = 0
                if (i != j):
                    self.listLine[k] = QPoint(i, j)
                    k = k + 1

            n = rd.randint(0, count - 1)
            region = array[n]
            count = count - 1
            array[n] = array[count]
            p = self.randomInRegion(region)
            self.points[i] = p

        for i in range(0, int(self.countLines)):
            n = rd.randint(0, k)
            p = self.listLine[n]
            k = k - 1
            self.listLine[n] = self.listLine[k]
            self.distance[p.x()][p.y()] = self.calDistance(
                self.points[p.x()], self.points[p.y()])
            px1 = self.points[p.x()].x()
            px2 = self.points[p.y()].x()
            py1 = self.points[p.x()].y()
            py2 = self.points[p.y()].y()

            try:
                offsetX = (px2 -
                           px1) * self.RADIUS3 / self.distance[p.x()][p.x()]
                offsetY = (py2 -
                           py1) * self.RADIUS3 / self.distance[p.x()][p.x()]
            except ZeroDivisionError as e:
                pass
            finally:
                self.lines[p.x(),
                           p.y()] = Pair(QPoint(px1 + offsetX, py1 + offsetY),
                                         QPoint(px2 - offsetX, py2 - offsetY))

        for i in range(0, int(self.countPoints)):
            for j in range(0, int(self.countPoints)):
                if self.distance[i, j] != 0:
                    self.scene.addLine(self.lines[i, j].first,
                                       self.lines[i, j].second)

        self.graphicsViewPaint.setScene(self.scene)

    def randomInRegion(self, region):
        minX = region % 5 * self.SIZE + self.RADIUS
        maxX = minX + self.SIZE - self.RADIUS2
        minY = region / 5 * self.SIZE + self.RADIUS
        maxY = minY + self.SIZE - self.RADIUS2
        return QPoint(rd.randint(minX, maxX), rd.randint(minY, maxY))

    def calDistance(self, p1, p2):
        x = p1.x() - p2.x()
        y = p1.y() - p2.y()
        return int(math.sqrt(x * x + y * y))

    def reset(self):
        self.start, self.end = -1, -1

        self.listPath = list()
        self.chooseState = 0
        self.lblStatus.setText(self.textChoose[self.chooseState])
        self.lblPointStart.setText('Point start: ')
        self.lblPointEnd.setText('Point end: ')
        self.lblSteps.setText('Steps: ')
        self.lblNodes.setText('Nodes: ')

        self.isFouded = False
        self.isDone = False
Ejemplo n.º 23
0
class AMANDisplay(QGraphicsView):
    def __init__(self):
        super(AMANDisplay, self).__init__()
        self.setGeometry(0, 0, 500, 600)
        self.setStyleSheet("background-color:#233370")
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene(0, 0, 500, 600)

        # Timeline boundaries
        pen = QPen(QColor("white"))
        brush = QBrush(QColor("#233370"))
        self.scene.addLine(220, 0, 220, 600, pen)
        self.scene.addLine(280, 0, 280, 600, pen)
        self.scene.addLine(0, 30, 500, 30, pen)

        timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush)
        timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True)

        # Timeline scale
        self.timeline = QGraphicsItemGroup()
        self.timeline.setParentItem(timelinebox)
        self.timeticks = []
        for i in range(40):
            y = 15 * i
            w = 6
            if i % 5 == 0:
                w = 10
                self.timeticks.append(self.scene.addText("%02d" % (40 - i), QFont("Courier", 10)))
                self.timeticks[-1].setPos(240, y - 10)
                self.timeticks[-1].setDefaultTextColor(QColor("white"))
                self.timeline.addToGroup(self.timeticks[-1])
            self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen))
            self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen))

        self.lrwy = self.scene.addText("18R", QFont("Arial", 20, 50))
        self.lrwy.setPos(1, 1)
        self.lrwy.setDefaultTextColor(QColor("white"))
        # Finalize
        self.setScene(self.scene)
        self.show()

    def update(self, simt, data):
        # data has: ids, iafs, eats, etas, delays, rwys, spdratios

        # First delete old labels
        for (key,) in self.aircraft.keys:
            if key not in data.ids:
                # del label
                del self.aircraft[key]

        for i in len(data.ids):
            if data.ids[i] not in self.aircraft:
                # self.aircraft[data.ids[i]] = QLabel()
                pass

            # Generate the new label text and position
            newtext = "<font color=Red>bla</font>"  # veranderen
            lbl = self.aircraft[data.ids[i]]
            lbl.setText(newtext)
            lbl.move(posx, posy)  # move in pixels
Ejemplo n.º 24
0
Archivo: gui.py Proyecto: herstky/DES
class ApplicationWindow(QMainWindow):
    class State(Enum):
        running = 1
        idle = 2
        placing_module = 3
        drawing_stream = 4
        placing_readout = 5
        drawing_readout = 6
        dragging_joint = 7

    running = State.running
    idle = State.idle
    placing_module = State.placing_module
    drawing_stream = State.drawing_stream
    placing_readout = State.placing_readout
    drawing_readout = State.drawing_readout
    dragging_joint_line = State.dragging_joint

    def __init__(self):
        super(ApplicationWindow, self).__init__()
        self.initUI()
 
    def initUI(self):
        self.mouse_x = 0
        self.mouse_y = 0
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.state = ApplicationWindow.idle
        self.scene = QGraphicsScene(self)
        self.ui.graphicsView.setScene(self.scene) 
        self.setWindowTitle('Flow Modeler')
        self.show()

        self.views = []
        self.simulation = Simulation(self)
       
        self.timer = QTimer()
        self.timer.setInterval(100)
        self.timer.timeout.connect(self.simulation.run)

        self.ui.actionStart.triggered.connect(self.run_sim)
        self.ui.actionStop.triggered.connect(self.stop_sim)
        self.ui.actionSource.triggered.connect(self.create_source_slot)
        self.ui.actionTank.triggered.connect(self.create_tank_slot)
        self.ui.actionPump.triggered.connect(self.create_pump_slot)
        self.ui.actionSink.triggered.connect(self.create_sink_slot)
        self.ui.actionSplitter.triggered.connect(self.create_splitter_slot)
        self.ui.actionHydrocyclone.triggered.connect(self.create_hydrocyclone_slot)
        self.ui.actionJoiner.triggered.connect(self.create_joiner_slot)
        self.ui.actionReadout.triggered.connect(self.create_readout)
        self.ui.actionFiberReadout.triggered.connect(self.create_fiber_readout)

        self.setMouseTracking(True)
        self.ui.centralwidget.setMouseTracking(True)
        self.ui.graphicsView.setMouseTracking(True)
        self.installEventFilter(self)
        self.ui.graphicsView.viewport().installEventFilter(self)

        screen = QGuiApplication.primaryScreen()
        screen_width = screen.geometry().width()
        screen_height = screen.geometry().height()

        self.scene.setSceneRect(QRectF(0, 0, screen_width, screen_height))

        self.floating_model = None
        self.floating_line = None

    def map_from_global_to_scene(self, pos):
        pos = self.ui.graphicsView.parent().mapFromParent(pos)
        pos = self.ui.graphicsView.mapFromParent(pos)
        pos = self.ui.graphicsView.mapToScene(pos)
        return pos

    @property
    def mouse_scene_pos(self):
        return self.map_from_global_to_scene(QPoint(self.mouse_x, self.mouse_y))

    def offset_point(self, point, dx, dy):
        return QPoint(point.x() + dx, point.y() + dy)

    def remove_floating_objects(self):
        try:
            self.views.remove(self.floating_model.view)
        except Exception:
            pass
        self.floating_model = None

        try:
            self.scene.removeItem(self.floating_line)
        except Exception:
            pass
        self.floating_line = None

    # Processes mouse events. Override of parent method.
    def eventFilter(self, source, event):
        if event.type() == QEvent.HoverMove and source is self:                  
            self.mouse_x = event.pos().x()
            self.mouse_y = event.pos().y()

            graphics_view_parent = self.ui.graphicsView.parent()
            mapped_event_pos = graphics_view_parent.mapFromParent(event.pos())
            inbounds = mapped_event_pos.x() >= 0 and \
                       mapped_event_pos.y() >= 0 and \
                       mapped_event_pos.x() < self.ui.graphicsView.width() and \
                       mapped_event_pos.y() < self.ui.graphicsView.height()

            if inbounds and self.state is ApplicationWindow.placing_module:
                width = self.floating_model.view.graphics_item.pixmap().width()
                height = self.floating_model.view.graphics_item.pixmap().height()
                self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width, -height))
            elif inbounds and self.state is self.placing_readout:
                width = self.floating_model.view.graphics_item.rect().width()
                height = self.floating_model.view.graphics_item.rect().height()
                self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2))
            elif inbounds and self.state is ApplicationWindow.drawing_stream:
                p1 = self.floating_line.line().p1()
                p2 = self.mouse_scene_pos
                self.floating_line.setLine(QLineF(p1, p2))
            elif inbounds and self.state is ApplicationWindow.drawing_readout:
                p1 = self.floating_line.mapToScene(self.floating_line.line().p1()) 

                width = self.floating_model.view.graphics_item.rect().width()
                height = self.floating_model.view.graphics_item.rect().height()

                self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2))
                p1 = self.floating_line.mapFromScene(p1)
                p2 = self.floating_line.mapFromScene(self.mouse_scene_pos)
                self.floating_line.setLine(QLineF(p1, p2))
            elif inbounds and self.state is ApplicationWindow.dragging_joint_line:
                self.floating_model.view.set_joint_line(self.mouse_scene_pos)

        elif event.type() == QEvent.MouseButtonRelease:
            scene_pos = self.map_from_global_to_scene(event.pos())
            if self.state is ApplicationWindow.idle:
                pass
            elif self.state is ApplicationWindow.dragging_joint_line:
                self.state = ApplicationWindow.idle
                self.floating_model = None

        return super(ApplicationWindow, self).eventFilter(source, event)

    def mousePressEvent(self, event):
        scene_pos = self.map_from_global_to_scene(event.pos())
        if self.state is ApplicationWindow.idle:
            stream = self.check_for_click_collisions(scene_pos)
            if stream:
                self.state = ApplicationWindow.dragging_joint_line
                self.floating_model = stream
        elif self.state is ApplicationWindow.placing_module:
            self.place_module()
        elif self.state is ApplicationWindow.drawing_stream:
            self.complete_stream(scene_pos)
        elif self.state is ApplicationWindow.drawing_readout:
            self.complete_readout(scene_pos)
        elif self.state is ApplicationWindow.placing_readout:
            self.start_readout(scene_pos)

    def run_sim(self):
        self.state = ApplicationWindow.running
        self.timer.start()

    def stop_sim(self):
        self.state = ApplicationWindow.idle
        self.timer.stop()

    def check_for_click_collisions(self, pos):
        for stream in self.simulation.streams:
            if stream.view.check_for_joint_line_collision(pos):
                return stream
        return None

    @pyqtSlot()
    def create_source_slot(self):
        volume_fractions = {}
        for species in Event.registered_species:
            if species.name == 'fiber':
                volume_fractions[species] = 0.01
            elif species.name == 'water':
                volume_fractions[species] = 0.99

        self.add_module(Source(self, 'Source', 1000, volume_fractions))

    @pyqtSlot()
    def create_tank_slot(self):
        volume_fractions = {}
        for species in Event.registered_species:
            if species.name == 'fiber':
                volume_fractions[species] = 0.00014
            elif species.name == 'water':
                volume_fractions[species] = 0.99986

        self.add_module(Tank(self, 'Tank', 0, volume_fractions))

    @pyqtSlot()
    def create_pump_slot(self):
        self.add_module(Pump(self))

    @pyqtSlot()
    def create_sink_slot(self):
        self.add_module(Sink(self))

    @pyqtSlot()
    def create_splitter_slot(self):
        self.add_module(Splitter(self))

    @pyqtSlot()
    def create_hydrocyclone_slot(self):
        self.add_module(Hydrocyclone(self))

    @pyqtSlot()
    def create_joiner_slot(self):
        self.add_module(Joiner(self))
            
    def add_module(self, module):
        self.state = self.placing_module
        module.view.add_to_scene(self.scene)
        width = module.view.graphics_item.pixmap().width()
        height = module.view.graphics_item.pixmap().height()
        module.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width, -height))
        self.floating_model = module

    def place_module(self):
        self.state = self.idle
        self.floating_model = None

    def socket_clicked(self, graphics_item, event):
        scene_pos = graphics_item.mapToScene(event.pos())
        if self.state == ApplicationWindow.idle:
            self.create_stream(scene_pos)
        elif self.state == ApplicationWindow.drawing_stream:
            self.complete_stream(scene_pos)

    def create_stream(self, pos):
        self.floating_model = Stream(self)
        
        line = QLineF(pos, pos)
        self.floating_line = self.scene.addLine(line)
        self.floating_line.setZValue(-1)
        for colliding_item in self.scene.collidingItems(self.floating_line):
            for view in self.views:
                if isinstance(view.model, Socket) and view.graphics_item is colliding_item:
                    self.floating_model.add_socket(view.model)
                    self.state = self.drawing_stream
                    width = colliding_item.boundingRect().width()
                    height = colliding_item.boundingRect().height()
                    p1 = self.offset_point(colliding_item.scenePos(), width / 2 - 1, height / 2 - 1)
                    p2 = pos
                    pen = QPen()
                    pen.setWidth(2)
                    self.floating_line.setPen(pen)
                    self.floating_line.setLine(QLineF(p1, p2))  
                    
        if self.state is not ApplicationWindow.drawing_stream:
            self.state = self.idle
            self.floating_model.cleanup()
            self.remove_floating_objects()

    def complete_stream(self, pos):
        self.state = self.idle
        line = QLineF(pos, pos)
        test_line_item = self.scene.addLine(line)
        self.floating_model.view.graphics_item = None
        completed = False
        for colliding_item in self.scene.collidingItems(test_line_item):
            for view in self.views:
                if isinstance(view.model, Socket) and view.graphics_item is colliding_item:             
                    if not self.floating_model.add_socket(view.model):
                        continue

                    p1 = QPointF(colliding_item.scenePos().x() + colliding_item.boundingRect().width() / 2 - 1, 
                                 colliding_item.scenePos().y() + colliding_item.boundingRect().height() / 2 - 1)
                    p2 = self.floating_line.line().p1()
                    self.scene.removeItem(self.floating_line)
                    self.floating_line.setLine(QLineF(p1, p2)) 
                    self.floating_model.view.graphics_item = self.floating_line
                    self.floating_model.view.set_lines(self.floating_line.line())
                    self.floating_model.view.snap_line()
                    self.floating_model = None
                    self.floating_line = None
                    completed = True

        self.scene.removeItem(test_line_item)

        # If second socket to stream was not succesfully added
        if not completed:
            self.state = ApplicationWindow.idle

            # Remove initial socket made
            self.floating_model.cleanup()
            self.remove_floating_objects()
    
    @pyqtSlot()
    def create_readout(self):
        self.state = self.placing_readout
        self.floating_model = Readout(self)
        self.scene.addItem(self.floating_model.view.graphics_item)
   
        width = self.floating_model.view.graphics_item.rect().width()
        height = self.floating_model.view.graphics_item.rect().height()

        self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2))

    @pyqtSlot()
    def create_fiber_readout(self):
        self.state = self.placing_readout
        self.floating_model = FiberReadout(self)
        self.scene.addItem(self.floating_model.view.graphics_item)
   
        width = self.floating_model.view.graphics_item.rect().width()
        height = self.floating_model.view.graphics_item.rect().height()

        self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2))

    def start_readout(self, pos):
        for colliding_item in self.scene.collidingItems(self.floating_model.view.graphics_item):
            if self.state is ApplicationWindow.idle:
                break
            for view in self.views:
                if type(view.model) is Stream and isinstance(view, StreamView) and colliding_item in view.line_items:
                    # If stream already has a Readout, cancel creation of new Readout.
                    if not self.floating_model.connect_to_stream(view.model):
                        self.state = ApplicationWindow.idle
                        break
                    else:
                        self.state = self.drawing_readout

                    self.floating_line = self.scene.addLine(QLineF())
                    self.floating_line.setParentItem(self.floating_model.view.graphics_item)
                    p1 = p2 = pos
                    angle = colliding_item.line().angle()
                    
                    # snap readout line to colliding line item
                    if angle == 0.0 or angle == 180.0: 
                        p1.setY(colliding_item.line().y1())
                        self.floating_model.view.orientation = ReadoutView.Orientation.vertical
                    elif angle == 90.0 or angle == 270.0: 
                        p1.setX(colliding_item.line().x1())
                        self.floating_model.view.orientation = ReadoutView.Orientation.horizontal
                    p1 = self.floating_line.mapFromScene(p1)
                    p2 = self.floating_line.mapFromScene(p2)

                    pen = QPen()
                    pen.setWidth(2)
                    self.floating_line.setLine(QLineF(p1, p2))
                    self.floating_line.setPen(pen)
                    self.floating_line.setZValue(-1)

        if self.state is not ApplicationWindow.drawing_readout:
            self.state = self.idle
            self.floating_model.cleanup()
            self.remove_floating_objects()

    def complete_readout(self, pos):
        self.state = self.idle
        rect_graphics_item = self.floating_model.view.graphics_item
        line_graphics_item = self.floating_line

        if self.floating_model.view.orientation is ReadoutView.Orientation.horizontal:
            p1 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y1())
            p2 = QPoint(line_graphics_item.line().x2(), line_graphics_item.line().y1())
        else:
            p1 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y1())
            p2 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y2())

        width = rect_graphics_item.rect().width()
        height = rect_graphics_item.rect().height()

        p1 = rect_graphics_item.mapToScene(p1)
        p2 = rect_graphics_item.mapToScene(p2)
        rect_graphics_item.setPos(QPoint(p2.x() - width / 2 - 1, p2.y() - height / 2 - 1))

        p1 = rect_graphics_item.mapFromScene(p1)
        p2 = rect_graphics_item.mapFromScene(p2)
        line_graphics_item.setLine(QLineF(p1, p2)) 
        
        self.floating_model.view.init_text()

        self.floating_model = None
        self.floating_line = None
Ejemplo n.º 25
0
class Spectrum(QWidget):
    """Plot the power spectrum for a specified channel.

    Attributes
    ----------
    parent : instance of QMainWindow
        the main window.
    x_limit : tuple or list
        2 values specifying the limit on x-axis
    y_limit : tuple or list
        2 values specifying the limit on y-axis
    log : bool
        log-transform the data or not
    idx_chan : instance of QComboBox
        the element with the list of channel names.
    idx_x_min : instance of QLineEdit
        value with min x value
    idx_x_max : instance of QLineEdit
        value with max x value
    idx_y_min : instance of QLineEdit
        value with min y value
    idx_y_max : instance of QLineEdit
        value with max y value
    idx_log : instance of QCheckBox
        widget that defines if log should be used or not
    idx_fig : instance of QGraphicsView
        the view with the power spectrum
    scene : instance of QGraphicsScene
        the scene with GraphicsItems

    Notes
    -----
    If data contains NaN, it doesn't create any spectrum (feature or bug?).
    """
    def __init__(self, parent):
        super().__init__()
        self.parent = parent

        self.config = ConfigSpectrum(self.display_window)

        self.selected_chan = None
        self.idx_chan = None
        self.idx_fig = None
        self.scene = None

        self.create()

    def create(self):
        """Create empty scene for power spectrum."""
        self.idx_chan = QComboBox()
        self.idx_chan.activated.connect(self.display_window)

        self.idx_fig = QGraphicsView(self)
        self.idx_fig.scale(1, -1)

        layout = QVBoxLayout()
        layout.addWidget(self.idx_chan)
        layout.addWidget(self.idx_fig)
        self.setLayout(layout)

        self.resizeEvent(None)

    def show_channame(self, chan_name):
        self.selected_chan = self.idx_chan.currentIndex()

        self.idx_chan.clear()
        self.idx_chan.addItem(chan_name)
        self.idx_chan.setCurrentIndex(0)

    def update(self):
        """Add channel names to the combobox."""
        self.idx_chan.clear()
        for chan_name in self.parent.traces.chan:
            self.idx_chan.addItem(chan_name)

        if self.selected_chan is not None:
            self.idx_chan.setCurrentIndex(self.selected_chan)
            self.selected_chan = None

    def display_window(self):
        """Read the channel name from QComboBox and plot its spectrum.

        This function is necessary it reads the data and it sends it to
        self.display. When the user selects a smaller chunk of data from the
        visible traces, then we don't need to call this function.
        """
        if self.idx_chan.count() == 0:
            self.update()

        chan_name = self.idx_chan.currentText()
        lg.info('Power spectrum for channel ' + chan_name)

        if chan_name:
            trial = 0
            data = self.parent.traces.data(trial=trial, chan=chan_name)
            self.display(data)
        else:
            self.scene.clear()

    def display(self, data):
        """Make graphicsitem for spectrum figure.

        Parameters
        ----------
        data : ndarray
            1D vector containing the data only

        This function can be called by self.display_window (which reads the
        data for the selected channel) or by the mouse-events functions in
        traces (which read chunks of data from the user-made selection).
        """
        value = self.config.value
        self.scene = QGraphicsScene(value['x_min'], value['y_min'],
                                    value['x_max'] - value['x_min'],
                                    value['y_max'] - value['y_min'])
        self.idx_fig.setScene(self.scene)

        self.add_grid()
        self.resizeEvent(None)

        s_freq = self.parent.traces.data.s_freq
        f, Pxx = welch(data, fs=s_freq,
                       nperseg=int(min((s_freq, len(data)))))  # force int

        freq_limit = (value['x_min'] <= f) & (f <= value['x_max'])

        if self.config.value['log']:
            Pxx_to_plot = log(Pxx[freq_limit])
        else:
            Pxx_to_plot = Pxx[freq_limit]

        self.scene.addPath(Path(f[freq_limit], Pxx_to_plot),
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))

    def add_grid(self):
        """Add axis and ticks to figure.

        Notes
        -----
        I know that visvis and pyqtgraphs can do this in much simpler way, but
        those packages create too large a padding around the figure and this is
        pretty fast.

        """
        value = self.config.value

        # X-AXIS
        # x-bottom
        self.scene.addLine(value['x_min'], value['y_min'],
                           value['x_min'], value['y_max'],
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # at y = 0, dashed
        self.scene.addLine(value['x_min'], 0,
                           value['x_max'], 0,
                           QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine))
        # ticks on y-axis
        y_high = int(floor(value['y_max']))
        y_low = int(ceil(value['y_min']))
        x_length = (value['x_max'] - value['x_min']) / value['x_tick']
        for y in range(y_low, y_high):
            self.scene.addLine(value['x_min'], y,
                               value['x_min'] + x_length, y,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # Y-AXIS
        # left axis
        self.scene.addLine(value['x_min'], value['y_min'],
                           value['x_max'], value['y_min'],
                           QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # larger ticks on x-axis every 10 Hz
        x_high = int(floor(value['x_max']))
        x_low = int(ceil(value['x_min']))
        y_length = (value['y_max'] - value['y_min']) / value['y_tick']
        for x in range(x_low, x_high, 10):
            self.scene.addLine(x, value['y_min'],
                               x, value['y_min'] + y_length,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))
        # smaller ticks on x-axis every 10 Hz
        y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2
        for x in range(x_low, x_high, 5):
            self.scene.addLine(x, value['y_min'],
                               x, value['y_min'] + y_length,
                               QPen(QColor(LINE_COLOR), LINE_WIDTH))

    def resizeEvent(self, event):
        """Fit the whole scene in view.

        Parameters
        ----------
        event : instance of Qt.Event
            not important

        """
        value = self.config.value
        self.idx_fig.fitInView(value['x_min'],
                               value['y_min'],
                               value['x_max'] - value['x_min'],
                               value['y_max'] - value['y_min'])

    def reset(self):
        """Reset widget as new"""
        self.idx_chan.clear()
        if self.scene is not None:
            self.scene.clear()
        self.scene = None
Ejemplo n.º 26
0
class ViewWindow(QMainWindow):  # QWidget):
    def __init__(self):
        super().__init__()
        self.pilorig = None
        self.savedImg = None
        self.controlPanel = None
        self.dirName, self.fileName = '', ''
        self.dirFileNames = []
        self.fileIdx = -1
        self.ctrl = None  # transformation control widget
        self.locator = None  # locator rectangle widget
        self.locator1 = None  # locator 1st point
        self.locator2 = None  # locator 2nd point
        self.scale = (1, 1)
        self.show_histogram = False
        # usage of QGraphicsScene and QGraphicsView is taken from
        # https://stackoverflow.com/questions/50851587/undo-functionality-for-qpainter-drawellipse-function
        self.gv = None
        self.scene = None
        self.scaledPixmap = None
        self.histogram = []
        self.initUI()

    def initUI(self):
        self.setWindowTitle("PyQT Tuts!")
        transforms.editWindow = self

        bar = self.menuBar()
        makeMenu(bar, FILE_MENU, self)
        menu = bar.actions()[2].menu()
        menu.addSeparator()
        addAction(menu, self, 'Show &Histogram', self.toggleHistogram,
                  'Ctrl+H', 'Show/hide histogram')

        menu = bar.actions()[1].menu()
        menu.addSeparator()
        for item in transforms.getTransforms():
            addAction(menu, self, item[0], item[2], item[3],
                      item[4])  # item[1] (Icon is ignored, todo: add support)

        menu = bar.actions()[0].menu()
        menu.addSeparator()
        addAction(menu, self, '&Next', self.onNextBtn, 'Ctrl+N', 'Next image')
        addAction(menu, self, '&Prev', self.onPrevBtn, 'Ctrl+P', 'Prev image')
        addAction(menu, self, '&Save', self.onSaveImg, 'Ctrl+S', 'Save image')

        layout1 = QVBoxLayout()

        self.gv = QGraphicsView()
        self.scene = QGraphicsScene()
        self.gv.setScene(self.scene)
        self.gv.installEventFilter(self)
        layout1.addWidget(self.gv)

        panel = QWidget(self)
        self.controlPanel = QHBoxLayout()
        panel.setLayout(self.controlPanel)
        layout1.addWidget(panel)

        center = QWidget()
        center.setLayout(layout1)
        self.setCentralWidget(center)

    def toggleHistogram(self):
        self.show_histogram = not self.show_histogram
        self.make_histogram()

    def eventFilter(self, obj, event):
        if obj == self.gv and event.type() == QEvent.MouseButtonPress:
            p = self.gv.mapToScene(event.pos())
            self.setLocation(p)
        return QWidget.eventFilter(self, obj, event)

    def setLocation(self, pos):
        if self.locator2 is not None:
            self.locator1 = None
            self.locator2 = None
        if self.locator1:
            self.locator2 = (pos.x(), pos.y())
            self.drawLocator()
        else:
            self.locator1 = (pos.x(), pos.y())

    def drawLocator(self):
        if self.locator:
            self.scene.removeItem(self.locator)
            self.locator = None
        pen = QPen(Qt.red, 3)
        self.locator = self.scene.addRect(self.locator1[0], self.locator1[1],
                                          self.locator2[0] - self.locator1[0],
                                          self.locator2[1] - self.locator1[1],
                                          pen)
        print('locator', self.locator1, self.locator2)
        self.gv.update()  # self.label.update() #QApplication.processEvents()

    def resizeEvent(self, event):
        QWidget.resizeEvent(self, event)
        self.sizeImage()

    def openImage(self, fileName):
        self.setWindowTitle(fileName)
        self.dirName = os.path.dirname(fileName)
        self.fileName = os.path.basename(fileName)
        self.dirFileNames = list(imgFiles(self.dirName))
        self.fileIdx = self.dirFileNames.index(self.fileName)
        if fileName:
            self.pilorig = PIL.Image.open(fileName)
            self.sizeImage()

    def fullFileName(self):
        if self.fileName:
            return os.path.join(self.dirName, self.fileName)
        else:
            return None

    def showImage(self, fileName):
        self.openImage(fileName)
        self.show()

    def updateImage(self, pilImage):
        self.pilorig = pilImage
        self.sizeImage()

    def sizeImage(self):
        orig = pil2pixmap(self.pilorig)
        if self.pilorig:
            if self.scaledPixmap:
                self.scene.removeItem(self.scaledPixmap)
                self.scaledPixmap = None
            if self.locator:
                self.scene.removeItem(self.locator)
                self.locator = None

            pixmap = orig.scaled(self.gv.width(),
                                 self.gv.height(),
                                 Qt.KeepAspectRatio,
                                 transformMode=Qt.SmoothTransformation)
            self.scaledPixmap = self.scene.addPixmap(pixmap)

            self.scale = (orig.size().width() / pixmap.size().width(),
                          orig.size().height() / pixmap.size().height())
            self.make_histogram()

    def absLocatorRect(self):
        return [
            self.locator1[0] * self.scale[0], self.locator1[1] * self.scale[1],
            self.locator2[0] * self.scale[0], self.locator2[1] * self.scale[1]
        ]

    def nextFileName(self):
        if self.fileIdx < len(self.dirFileNames) - 1:
            return os.path.join(self.dirName,
                                self.dirFileNames[self.fileIdx + 1])
        else:
            return None

    def prevFileName(self):
        if self.fileIdx > 0:
            return os.path.join(self.dirName,
                                self.dirFileNames[self.fileIdx - 1])
        else:
            return None

    def onNextBtn(self):
        fn = self.nextFileName()
        if fn:
            self.openImage(os.path.join(self.dirName, fn))

    #@staticmethod
    def onPrevBtn(self):
        fn = self.prevFileName()
        if fn:
            self.openImage(os.path.join(self.dirName, fn))

    def onSaveImg(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(
            self,
            "Save as ...",
            os.path.join(self.dirName, self.fileName),
            "All Files (*);;Jpeg Files(*.jpg)",
            options=options)
        if fileName:
            print(fileName)
            self.pilorig.save(fileName)

    def make_histogram(self):  # should it be a ShowWin class method?
        #self.canvas.delete('histogram')
        for it in self.histogram:
            self.scene.removeItem(it)
        del self.histogram[:]
        if not self.show_histogram:
            return

        img = self.pilorig
        if not img:
            return
        h = img.convert("L").histogram()
        maxVal = 1
        for i in range(0, len(h)):
            if h[i] > maxVal:
                maxVal = h[i]
        _X = float(img.size[1])
        x = 100 if _X > 100 else _X

        penGray = QPen(Qt.gray, 3)
        penRed = QPen(Qt.red, 3)

        for i in range(0, len(h)):
            if h[i] == maxVal:
                pen = penRed
            else:
                pen = penGray
            self.histogram.append(
                self.scene.addLine(i, x, i, x - x * h[i] / maxVal, pen))

        self.histogram.append(self.scene.addRect(0, 0, len(h), x, penGray))
        self.gv.update()

    # support transformation plugins
    def controlImg(self, checkCtrl=True):
        if checkCtrl and not self.ctrl:
            return None
        else:
            return self.savedImg

    def setCtrl(self, ctrl):
        if ctrl and self.ctrl:
            return  # do not allow two control panels
        if self.ctrl and not ctrl:
            self.ctrl.setParent(None)
        self.ctrl = ctrl
        if ctrl:
            self.controlPanel.addWidget(ctrl)
            self.savedImg = self.pilorig

    def unsetCtrl(self):
        if self.ctrl:
            self.ctrl.setParent(None)
            self.ctrl = None
Ejemplo n.º 27
0
 def paint(self, scene: QtWidgets.QGraphicsScene):
     for i in range(1, len(self.points)):
         scene.addLine(QtCore.QLineF(self.points[i - 1], self.points[i]),
                       self.color)
Ejemplo n.º 28
0
class MyWidget(QtWidgets.QWidget):
    text_updater = QtCore.pyqtSignal(str)   # Signal to update text display

    # Initialise the GUI
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)
        self.parent = parent
        self.text = QtWidgets.QTextEdit()
        self.scene = QGraphicsScene()
        self.view = MyView(self.scene)
        self.view.setRenderHint(QPainter.Antialiasing)
        self.sigpins = {}
        self.measure_text()
        self.scene.addRect(0, 0, *FRAME_SIZE, pen=FRAME_PEN, brush=FRAME_BRUSH)
        self.draw_rect(BOARD_GPOS, BOARD_GSIZE, BOARD_PEN, BOARD_BRUSH)
        self.draw_pin_labels(BOARD_GPOS, BOARD_GSIZE)
        self.draw_part_pins(BOARD_GPOS, BOARD_GSIZE, BOARDPINS, PIN_SIZE, True)
        self.draw_rect(SEGDISP_GPOS, SEGDISP_GSIZE, SEGDISP_PEN, SEGDISP_BRUSH)
        self.draw_part_pins(SEGDISP_GPOS, SEGDISP_GSIZE, SEG_IDENTS, SMALLPIN_SIZE, True)
        self.draw_part_segs(SEGDISP_GPOS)
        self.draw_button()
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.view, 30)
        layout.addWidget(self.text, 10)
        self.setLayout(layout)
        self.text_updater.connect(self.update_text)
        sys.stdout = self

    # Convert x,y grid position to graphics position
    def grid_pos(self, gpos):
        return gpos[0]*GRID_PITCH + GRID_ADJ[0], gpos[1]*GRID_PITCH + GRID_ADJ[1]

    # Convert w,h grid size to graphics size
    def grid_size(self, gsize):
        return gsize[0]*GRID_PITCH, gsize[1]*GRID_PITCH

    # Add rectangle to grid, given top-left corner
    def draw_rect(self, gpos, gsize, pen=Qt.gray, brush=Qt.darkGray):
        x,y = self.grid_pos(gpos)
        w,h = self.grid_size(gsize)
        rect = self.scene.addRect(0, 0, w, h, pen, brush)
        rect.setPos(x-GRID_PITCH/2.0, y-GRID_PITCH/2.0)
        return rect

    # Add circle to grid, given centre
    def draw_circle(self, gpos, size, pen, brush=PIN_ON_BRUSH):
        size *= GRID_PITCH
        x,y = self.grid_pos(gpos)
        p = self.scene.addEllipse(0, 0, size, size, pen, brush)
        p.setPos(x-size/2.0, y-size/2.0)
        return p

    # Measure text for positioning
    def measure_text(self, txt="ABCD"):
        fm = QFontMetrics(LABEL_FONT)
        self.label_wd, self.label_ht = fm.width(txt)*LABEL_SCALE, fm.height()*LABEL_SCALE

    # Add labels to part
    def draw_pin_labels(self, gpos, gsize):
        for n, id in enumerate(BOARDPINS):
            gx = gpos[0] + n%20
            gy = gpos[1] + (0 if n<20 else gsize[1]-3)
            self.draw_label((gx, gy), id)

    # Add text label to grid
    def draw_label(self, gpos, text, font=LABEL_FONT):
        x,y = self.grid_pos(gpos)
        size = self.label_wd, self.label_ht
        txt = self.scene.addText(text, font)
        txt.setScale(LABEL_SCALE)
        txt.setTransformOriginPoint(size[0], size[1]/2.0)
        txt.setRotation(90)
        txt.setPos(x+LABEL_OSET[0]-size[0]/2.0, y+LABEL_OSET[1])

    # Add pins to a part
    def draw_part_pins(self, gpos, gsize, pins, pinsize=PIN_SIZE, animate=False):
        for n, name in enumerate(pins):
            gx = gpos[0] + n%gsize[0]
            gy = gpos[1] + (0 if n<gsize[0] else gsize[1]-1)
            p = self.draw_pin((gx, gy), pinsize)
            if animate:
                self.add_pin_signal(name, p)

    # Add signal to animation list
    def add_pin_signal(self, name, pin):
        if name not in self.sigpins:
            self.sigpins[name] = []
        self.sigpins[name].append(pin)

    # Add pin to graphics display
    def draw_pin(self, gpos, pinsize):
        p = self.draw_circle(gpos, pinsize, PIN_ON_PEN, PIN_ON_BRUSH)
        p.setOpacity(PIN_OFF_OPACITY)
        return p

    # Add segments to 7-segment display
    def draw_part_segs(self, gpos):
        x2 = y2 = None
        self.segments = []
        for line in SEG_LINES:
            x1, y1 = self.grid_pos((line[0]+gpos[0], line[1]+gpos[1]))
            if x2 is not None:
                seg = self.scene.addLine(x1, y1, x2, y2, SEG_PEN)
                seg.setOpacity(PIN_OFF_OPACITY)
                self.segments.append(seg)
            x2, y2 = x1, y1
        self.segments.insert(5, self.segments.pop(0))  # Re-order to segment A first
        dpos = SEG_DP_OSET[0]+gpos[0], SEG_DP_OSET[1]+gpos[1]
        dp = self.draw_circle(dpos, SEG_DP_SIZE, SEG_DP_PEN)
        dp.setOpacity(PIN_OFF_OPACITY)
        self.segments.append(dp)
        for n, seg in enumerate(self.segments):
            bitnum = SEG_BITNUM[chr(n + ord('a'))]
            self.add_pin_signal("%s%u" % (SEGPORT, bitnum), seg)

    # Draw pushbutton
    def draw_button(self):
        self.draw_rect(BUTTON_GPOS, BUTTON_GSIZE, BUTTON_OFF_PEN, BUTTON_OFF_BRUSH)
        gx, gy = BUTTON_GPOS[0]+BUTTON_GSIZE[0]/4, BUTTON_GPOS[1]+BUTTON_GSIZE[1]/4
        p = self.draw_circle((gx, gy), BUTTON_GSIZE[0], BUTTON_OFF_PEN, BUTTON_ON_BRUSH)
        p.setOpacity(PIN_OFF_OPACITY)
        self.add_pin_signal(BUTTON_PIN, p)
        return p

    # Set port pins on/off states
    # Space-delimited 'name=value' with 16 bit hex value, e.g. 'PA=12C PB=D3E4'
    def set_ports(self, s):
        data = str(s).split(' ')
        for d in data:
            name,eq,num = d.partition('=')
            if eq and num is not None:
                val = int(num, 16)
                print("Port %s = %X" % (name, val))
                for i in range(0, 16):
                    self.set_pin("%s%u=%X" % (name, i, (val>>i)&1))

    # Set pin (or segment) on/off state
    # Format is 'name=value', e.g.  'PA10=1'
    def set_pin(self, s):
        name, eq, num = s.partition('=')
        if eq and name in self.sigpins:
            val = int(num, 16)
            for p in self.sigpins[name]:
                if int(p.opacity()) != val:
                    p.setOpacity(PIN_ON_OPACITY if val else PIN_OFF_OPACITY)

    # Handler to update graphics display
    def update_graph(self, s):
        self.set_ports(s)

    # Handler to update text display
    def update_text(self, text):
        disp = self.text.textCursor()           # Move cursor to end
        disp.movePosition(QTextCursor.End)
        text = str(text).replace("\r", "")      # Eliminate CR
        while text:
            head,sep,text = text.partition("\n")# New line on LF
            disp.insertText(head)
            if sep:
                disp.insertBlock()
        self.text.ensureCursorVisible()    # Scroll if necessary

    # Handle sys.stdout.write: update text display
    def write(self, text):
        self.text_updater.emit(str(text))
    def flush(self):
        pass
Ejemplo n.º 29
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.º 30
0
class AMANDisplay(QGraphicsView):
    def __init__(self):
        super(AMANDisplay, self).__init__()
        self.setGeometry(0, 0, 500, 600)
        self.setStyleSheet('background-color:#233370')
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scene = QGraphicsScene(0, 0, 500, 600)

        # Timeline boundaries
        pen = QPen(QColor('white'))
        brush = QBrush(QColor('#233370'))
        self.scene.addLine(220, 0, 220, 600, pen)
        self.scene.addLine(280, 0, 280, 600, pen)
        self.scene.addLine(0, 30, 500, 30, pen)

        timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush)
        timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True)

        # Timeline scale
        self.timeline = QGraphicsItemGroup()
        self.timeline.setParentItem(timelinebox)
        self.timeticks = []
        for i in range(40):
            y = 15 * i
            w = 6
            if i % 5 == 0:
                w = 10
                self.timeticks.append(
                    self.scene.addText('%02d' % (40 - i), QFont('Courier',
                                                                10)))
                self.timeticks[-1].setPos(240, y - 10)
                self.timeticks[-1].setDefaultTextColor(QColor('white'))
                self.timeline.addToGroup(self.timeticks[-1])
            self.timeline.addToGroup(
                self.scene.addLine(220, y, 220 + w, y, pen))
            self.timeline.addToGroup(
                self.scene.addLine(280 - w, y, 280, y, pen))

        self.lrwy = self.scene.addText('18R', QFont('Arial', 20, 50))
        self.lrwy.setPos(1, 1)
        self.lrwy.setDefaultTextColor(QColor('white'))
        # Finalize
        self.setScene(self.scene)
        self.show()

    def update(self, simt, data):
        # data has: ids, iafs, eats, etas, delays, rwys, spdratios

        # First delete old labels
        for key, in self.aircraft.keys:
            if key not in data.ids:
                # del label
                del self.aircraft[key]

        for i in len(data.ids):
            if data.ids[i] not in self.aircraft:
                # self.aircraft[data.ids[i]] = QLabel()
                pass

            # Generate the new label text and position
            newtext = '<font color=Red>bla</font>'  # veranderen
            lbl = self.aircraft[data.ids[i]]
            lbl.setText(newtext)
            lbl.move(posx, posy)  # move in pixels
Ejemplo n.º 31
0
class MainWindow(QMainWindow):
    """Main window class of our UI"""
    def __init__(self, g):
        """Constructor"""
        super(MainWindow, self).__init__()

        self.g = g

        # Load user interface from UI-file

        uic.loadUi('exed1.ui', self)

        self.init_scene()

    def calc_bounding_box(self):
        """Calc geometry bounding box"""

        self.max_x = -1e300
        self.max_y = -1e300
        self.min_x = 1e300
        self.min_y = 1e300

        for p in self.g.points.values():
            if p[0][0] > self.max_x:
                self.max_x = p[0][0]
            if p[0][0] < self.min_x:
                self.min_x = p[0][0]
            if p[0][1] > self.max_y:
                self.max_y = p[0][1]
            if p[0][1] < self.min_y:
                self.min_y = p[0][1]

        self.bw = self.max_x - self.min_x
        self.bh = self.max_y - self.min_y
        self.hs = (self.bw + self.bh) * 0.5 * 0.075

    def init_scene(self):
        """Setup scene"""
        self.scene = QGraphicsScene()
        self.green_brush = QBrush(Qt.green)
        self.gray_brush = QBrush(Qt.gray)
        self.white_brush = QBrush(Qt.white)
        self.pen = QPen(Qt.gray)
        self.pen.setWidth(4)
        self.pen.setCosmetic(True)
        self.line_pen = QPen(Qt.red)
        self.line_pen.setWidth(4)
        self.line_pen.setCosmetic(True)

        self.calc_bounding_box()

        for c in self.g.curves.values():
            if c[0] == 'Spline':
                i0 = c[1][0]
                i1 = c[1][1]
                p0 = self.g.points[i0][0]
                p1 = self.g.points[i1][0]
                gi = self.scene.addLine(p0[0], p0[1], p1[0], p1[1], self.pen)

        for p in self.g.points.values():
            gi = QGraphicsEllipseItem(-self.hs / 2, -self.hs / 2, self.hs,
                                      self.hs)
            gi.setBrush(self.white_brush)
            gi.setPen(self.pen)
            gi.setPos(p[0][0], p[0][1])
            gi.setFlag(QGraphicsItem.ItemIsMovable)
            gi.setFlag(QGraphicsItem.ItemIsSelectable)
            self.scene.addItem(gi)
            #gi = self.scene.addEllipse(-self.hs/2, -self.hs/2, self.hs, self.hs, self.pen, self.white_brush)

        print(self.scene.sceneRect())

        #self.scene.setSceneRect(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y)

        self.graphics_view.setScene(self.scene)
        #self.graphics_view.fitInView(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y)
        self.graphics_view.scale(200.0, 200.0)

        #ellipse = self.scene.addEllipse(20,20, 200,200, self.pen, self.greenBrush)
        #rect = self.scene.addRect(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y, self.pen)

        #ellipse.setFlag(QGraphicsItem.ItemIsMovable)
        #rect.setFlag(QGraphicsItem.ItemIsMovable)
        #ellipse.setFlag(QGraphicsItem.ItemIsSelectable)

        self.scene.focusItemChanged.connect(self.on_focus_item_changed)
        self.scene.selectionChanged.connect(self.on_selection_changed)

    def on_focus_item_changed(self, new_focus_item, old_focus_item, reason):
        print("on_focus_item_changed", new_focus_item, reason)

    def on_selection_changed(self):
        if len(self.scene.selectedItems()) > 0:
            print("on_selection_changed", self.scene.selectedItems()[0].pos())

    def on_item_mouse_move(self):
        print("on_item_mouse_move")
Ejemplo n.º 32
0
class BoardGUI(QWidget):
    """cointain the graphical representation of the Board"""

    # ratio of bordersize compared to the size of one base square
    borderRatio = 0.8
    baseRectRatio = 14/15  # 12/13 for normal ratio but looks weird
    stoneScale = 0.46

    # siganl
    stoneClicked = pyqtSignal(tuple)

    def __init__(self, parent, game):
        super().__init__()

        self.initUI(game)

    def initUI(self, game):
        self.board = game.currentBoard
        self.game = game

        self.showCoords = True
        self.scene = QGraphicsScene()

        # grid containing coordinates for the scene
        self.grid = []
        self.drawGrid()

        # initialize and set layout + view
        self.view = QGraphicsView(self.scene)
        self.view.setMouseTracking(True)
        self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
        self.setMouseTracking(True)
        box = QHBoxLayout()
        box.addWidget(self.view)
        self.setLayout(box)

        # stones for all positions are created and listed in self.pos dict
        self.createPosition()
        self.makeCoords()  # has to be called after drawGrid!

    def resizeEvent(self, e):
        self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio)

    def boardWidth(self):
        """returns the max width fitting into widget"""
        width = self.contentsRect().width()*0.95
        height = self.contentsRect().height()*0.95

        return min(width, height*self.baseRectRatio)

    def boardHeight(self):
        """returns the max width fitting into widget """
        return self.boardWidth()*(1/self.baseRectRatio)

    def makeGrid(self):
        """
        returns coords [[(x, y)]] for the Grid according
         to current window mesures
        """
        # set scenesize to window size
        self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight())
        denom = self.board.size + 2*self.borderRatio
        baseWidth = self.boardWidth() / denom
        baseHeight = self.boardHeight() / denom

        leftOffset = 0.5*baseWidth  # (self.contentsRect().width()-self.boardWidth())/2
        topOffset = 0  # (self.contentsRect().height()-self.boardHeight())/2

        partionWidth = [leftOffset+(self.borderRatio+x)*baseWidth
                        for x in range(self.board.size)]
        partionHeight = [topOffset+(self.borderRatio+x)*baseHeight
                         for x in range(self.board.size)]

        grid = [[(x, y) for x in partionWidth] for y in partionHeight]
        self.grid = grid
        self.baseWidth = baseWidth

    def drawGrid(self):
        """draws the background grid"""
        self.makeGrid()
        for line in self.grid:
            self.scene.addLine(*line[0], *line[-1])
        for (pointT, pointB) in zip(self.grid[0], self.grid[-1]):
            self.scene.addLine(*pointT, *pointB)
        self.drawHoshis()

    def makeCoords(self):
        """ draws Coordinates """
        xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
        yLabels = list(range(1, 26))
        botGrid = []
        leftGrid = []
        # generate pixel coordinates grids
        for n in range(self.board.size):
            (xBot, yBot) = self.grid[self.board.size-1][n]
            yBot += self.baseWidth*0.4/self.baseRectRatio
            xBot -= self.baseWidth*0.1
            botGrid.append((xBot, yBot))
            (xLeft, yLeft) = self.grid[n][0]
            xLeft -= self.baseWidth*1.2
            yLeft -= self.baseWidth*0.3/self.baseRectRatio
            leftGrid.append((xLeft, yLeft))
        # generate Text items and add them to group
        self.coordGroup = QGraphicsItemGroup()
        for n in range(self.board.size):
            leftText = QGraphicsSimpleTextItem(str(yLabels[n]))
            leftText.setPos(*leftGrid[n])
            self.coordGroup.addToGroup(leftText)
            bottomText = QGraphicsSimpleTextItem(xLabels[n])
            bottomText.setPos(*botGrid[n])
            self.coordGroup.addToGroup(bottomText)
        # draw coordinates and update visibility according to self.showCoords
        self.scene.addItem(self.coordGroup)
        self.updateCoords()

    def updateCoords(self):
        """ slot that updates the visibility os the coordiantes. """
        self.coordGroup.setVisible(self.showCoords)

    def setCoordVis(self, visibility):
        """ set the self.showCoords boolean """
        self.showCoords = visibility
        self.updateCoords()

    def drawHoshis(self):
        """ Draws Hoshi dots"""
        hoshis = []
        rad = self.baseWidth*0.15
        for (x, y) in self.board.getHoshis():
            hoshis.append(self.grid[x][y])
        for point in hoshis:
            (x, y) = point
            self.scene.addEllipse(x-rad, y-rad, rad*2.0, rad*2.0,
                                  QPen(), QBrush(Qt.SolidPattern))

    def updatePosition(self):
        """
        sets the colors for all stones in self.pos according
        to the status in self.board
        """
        for (x, y) in self.pos:
            color = self.game.currentBoard.getPosition(x, y)
            self.pos[(x, y)].setMark(None)
            self.pos[(x, y)].setColor(color)
        lastMove = self.game.currentBoard.lastMove
        if lastMove:
            self.pos[lastMove].setMark(GoMarks.circel)
        ko = self.game.currentBoard.ko
        if ko:
            self.pos[ko].setMark(GoMarks.square)

    def createPosition(self):
        """
        Creates the self.pos dictionary containing all possible stones on the
        board initialized as empty stones

        also connects a signal form each stone to ???
        """
        self.pos = {}
        radius = self.stoneScale*self.baseWidth
        for row in range(self.board.size):
            for col in range(self.board.size):
                (x, y) = self.grid[row][col]
                newStone = Stone(x, y, radius)
                self.pos[(row, col)] = newStone
                self.scene.addItem(newStone)
        self.updatePosition()
        self.connecting()

    def connecting(self):
        for key in self.pos:
            self.pos[key].clicked.connect(lambda key=key: self.resend(key))

    def resend(self, pos):
        """
        emits the captured signal again,
        with (int, in) parameter for stone clicked
        """
        self.stoneClicked.emit(pos)
Ejemplo n.º 33
0
class Editor(QWidget):
    def __init__(self, song):
        super().__init__()

        self.initUI(song)

    def initUI(self, song):
        self.songLenInBeats = 100
        self.songBeatsPBar = 4
        self.reverse = 1
        self.pixPSec = 1000.0
        self.disp8 = True
        self.disp12 = False
        self.disp16 = True
        self.disp24 = False
        self.disp32 = False
        self.disp48 = False
        self.disp64 = False
        self.spectrogramDisplay = True
        self.cursorExists = False
        self.framecount = 0
        self.timeOutLength = 17

        self.timer = QTimer()
        self.editorTheme = self.getTheme()
        self.boxw = self.editorTheme['BoxWidth']
        self.topLayout = QVBoxLayout()
        self.topLayout.setContentsMargins(0, 0, 0, 0)

        self.song = song
        self.song.pos = 0
        self.setLayout(self.topLayout)
        self.gs = QGraphicsScene()
        self.gv = QGraphicsView(self.gs)
        self.drawBG()
        self.song = song
        #        self.drawArrowDemo()
        self.boxes = []
        self.topLayout.addWidget(self.gv)

    def update(self, song, level):
        self.gs.clear()
        print(self.song.pos)
        self.song = song
        self.cursorExists = False
        self.song.pos = 0
        self.play(0)
        self.pause()
        self.updatescreen()

        if self.spectrogramDisplay:
            self.spectrogramPixMap = QPixmap(spectrogram_dir + song.audioFile +
                                             '.png')
            width = self.spectrogramPixMap.width()
            height = self.spectrogramPixMap.height()

            self.spectrogramPixMap = self.gs.addPixmap(self.spectrogramPixMap)
            self.spectrogramPixMap.setRotation(90)
            self.spectrogramPixMap.setTransform(QTransform().scale(
                -1, (self.song.lengthInSeconds * self.pixPSec) / width))
        self.drawGrid(self.song.levels[level])
        self.drawArrowDemo(self.song.levels[level])
        #self.play(0)

    def levelSelected(self, level):
        print("Selected ", level)
        if level in self.song.levels:
            print('switching')
            self.update(self.song, level)
        else:
            print('creating new level')

    def play(self, pos):
        self.timer.timeout.connect(self.updatescreen)
        self.timer.start(self.timeOutLength)
        self.song.playSong(pos)

    def pause(self):
        self.timer.stop()
        self.song.pauseSong()

    def keyPressEvent(self, event):
        key = event.key()
        shiftPressed = event.modifiers() == Qt.ShiftModifier
        ctrlPressed = event.modifiers() == Qt.ControlModifier
        altPressed = event.modifiers() == Qt.AltModifier
        restart = self.song.isPlaying

        if key == Qt.Key_Space:
            if self.song.isPlaying:
                self.pause()
            else:
                self.play(self.song.pos / 1000)
        elif key == Qt.Key_BracketRight:
            restart = self.song.isPlaying
            self.pause()
            if ctrlPressed:
                self.song.pos += 10000
            elif shiftPressed:
                self.song.pos += 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos += 100

            if not (self.song.pos > self.song.lengthInSeconds * 1000):
                if restart:
                    self.play(self.song.pos / 1000)
                else:
                    self.play(self.song.pos / 1000)
                    self.pause()
            else:
                self.song.pos = self.song.lengthInSeconds * 1000 - 1
                self.play(self.song.pos / 1000)
                self.pause()
            self.updatescreen()
        elif key == Qt.Key_BracketLeft:
            self.pause()
            if ctrlPressed:
                self.song.pos -= 10000
            elif shiftPressed:
                self.song.pos -= 1000
            elif altPressed:
                self.song.pos -= 10
            else:
                self.song.pos -= 100
            if self.song.pos < 0:
                self.song.pos = 0
            if restart:
                self.play(self.song.pos / 1000)
            else:
                self.play(self.song.pos / 1000)
                self.pause()
            self.updatescreen()
        elif key == Qt.Key_BraceRight:
            restart = self.song.isPlaying
            self.pause()
            if ctrlPressed:
                self.song.pos += 10000
            elif shiftPressed:
                self.song.pos += 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos += 200

            if not (self.song.pos > self.song.lengthInSeconds * 1000):
                if restart:
                    self.play(self.song.pos / 1000)
                else:
                    self.play(self.song.pos / 1000)
                    self.pause()
            else:
                self.song.pos = self.song.lengthInSeconds * 1000 - 1
                self.play(self.song.pos / 1000)
                self.pause()

            self.updatescreen()
        elif key == Qt.Key_BraceLeft:
            self.pause()
            if ctrlPressed:
                self.song.pos -= 10000
            elif shiftPressed:
                self.song.pos -= 1000
            elif altPressed:
                self.song.pos += 10
            else:
                self.song.pos -= 200
            if self.song.pos < 0:
                self.song.pos = 0
            if restart:
                self.play(self.song.pos / 1000)
            else:
                self.play(self.song.pos / 1000)
                self.pause()

            self.updatescreen()

    def updatescreen(self):
        self.song.updatePos()

        if self.song.isPlaying:
            self.framecount += 1
            curTime = time.time()
            if (curTime - self.song.time > 1):
                print('FPS: ', self.framecount)
                self.framecount = 0
                self.song.time = curTime

        if self.cursorExists:
            self.gs.removeItem(self.cursorLine)
        ypos = (self.song.pos / 1000.0 * self.pixPSec)
        self.gv.centerOn(0, ypos)
        self.cursorLine = self.gs.addLine(0, ypos, 1000, ypos,
                                          self.editorTheme['GridMeasure'])
        self.cursorExists = True
        self.cursor = True
        if self.song.pos < 0:
            self.song.pos = 0
            self.gv.centerOn(0, 0)
            self.pause()

    def drawArrowDemo(self, level):

        boxRotation = [180, 0, 90, 270, 225, 135, 315, 45, 0]

        for beatBox in level.notes:
            if beatBox.type == 0:
                if beatBox.cutDirection == 8:
                    notePixmap = QPixmap(graphics_dir + 'redcircle.png')
                else:
                    notePixmap = QPixmap(graphics_dir + 'redarrow.png')
            elif beatBox.type == 1:
                if beatBox.cutDirection == 8:
                    notePixmap = QPixmap(graphics_dir + 'bluecircle.png')
                else:
                    notePixmap = QPixmap(graphics_dir + 'bluearrow.png')
            else:
                notePixmap = QPixmap(graphics_dir + 'mine.png')

            notePixmap = notePixmap.scaled(40, 40)
            noteBox = NoteBox()
            noteBox.setPixmap(notePixmap)
            noteBox.setBox(beatBox)
            box = self.gs.addItem(noteBox)
            print(type(noteBox))
            noteBox.setTransformOriginPoint(20, 20)
            noteBox.setRotation(boxRotation[beatBox.cutDirection])
            boxy = (level.beatToSec(beatBox.time) * self.pixPSec -
                    (self.reverse * 20)) * self.reverse

            boxx = 40 * beatBox.lineIndex + 170 * beatBox.lineLayer
            noteBox.setPos(boxx, boxy)
            self.boxes.append(noteBox)

    def drawBG(self):
        self.gs.setBackgroundBrush(self.editorTheme['BG'])

    def drawGrid(self, level):
        #DEBUG need to through a clear grid in here

        self.drawGridConstantTime(level)

    def drawGridConstantBeat(self):
        pass

    def drawGridConstantTime(self, level):

        # DONT FORGET TO ADD REVERSE SCROLL

        #        self.disp192 = True
        self.noteLayer1 = self.gs.createItemGroup([])
        self.noteLayer2 = self.gs.createItemGroup([])
        self.noteLayer3 = self.gs.createItemGroup([])
        self.obstacleLayer = self.gs.createItemGroup([])
        self.eventLayer = self.gs.createItemGroup([])
        width = self.editorTheme['BoxWidth'] * 4
        spacing = self.editorTheme['LaneSpacing']
        self.noteLayer1Values = LayerValue(0, 0, width)
        self.noteLayer2Values = LayerValue((width + spacing), 0, width)
        self.noteLayer3Values = LayerValue((width + spacing) * 2, 0, width)
        self.obstacleLayerValues = LayerValue((width + spacing) * 3, 0, width)
        self.eventLayerValues = LayerValue((width + spacing) * 4, 0, width)

        self.drawGridLaneConstantTime(self.noteLayer1, self.noteLayer1Values,
                                      level)
        self.drawGridLaneConstantTime(self.noteLayer2, self.noteLayer2Values,
                                      level)
        self.drawGridLaneConstantTime(self.noteLayer3, self.noteLayer3Values,
                                      level)
        self.drawGridLaneConstantTime(self.obstacleLayer,
                                      self.obstacleLayerValues, level)
        self.drawGridLaneConstantTime(self.eventLayer, self.eventLayerValues,
                                      level)

    def drawGridLaneConstantTime(self, lane, values, level):
        #debug songlen not a int need to address leftover time
        for beat in range(int(self.song.lengthInBeats)):
            if beat % self.song.beatsPerBar == 0:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, self.editorTheme['GridMeasure']))
            else:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat)) *
                        self.pixPSec, self.editorTheme['Grid4']))
            if self.disp8:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, self.editorTheme['Grid8']))
            if self.disp16:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, self.editorTheme['Grid16']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, self.editorTheme['Grid16']))
            if self.disp32:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .125)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .375)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .625)) *
                        self.pixPSec, self.editorTheme['Grid32']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .875)) *
                        self.pixPSec, self.editorTheme['Grid32']))
            if self.disp64:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .0625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .0625)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .1875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .1875)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .3125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .3125)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .4375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .4375)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5625)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5625)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .6875)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .6875)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .8125)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .8125)) *
                        self.pixPSec, self.editorTheme['Grid64']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .9375)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .9375)) *
                        self.pixPSec, self.editorTheme['Grid64']))
            if self.disp12:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 3)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 3)) *
                        self.pixPSec, self.editorTheme['Grid12']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 2 / 3)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 2 / 3)) *
                        self.pixPSec, self.editorTheme['Grid12']))
            if self.disp24:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 6)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 6)) *
                        self.pixPSec, self.editorTheme['Grid24']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .5)) *
                        self.pixPSec, self.editorTheme['Grid24']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 6)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 6)) *
                        self.pixPSec, self.editorTheme['Grid24']))
            if self.disp48:
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 1 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .25)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 5 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 7 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 7 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + .75)) *
                        self.pixPSec, self.editorTheme['Grid48']))
                lane.addToGroup(
                    self.gs.addLine(
                        values.x + self.editorTheme['GridLineWidth'],
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 11 / 12)) *
                        self.pixPSec, values.x + values.w -
                        self.editorTheme['GridLineWidth'] * 2,
                        self.reverse *
                        (self.song.offset + level.beatToSec(beat + 11 / 12)) *
                        self.pixPSec, self.editorTheme['Grid48']))
        lane.addToGroup(
            self.gs.addLine(
                values.x, values.y, values.x,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .25, values.y, values.x + values.w * .25,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .5, values.y, values.x + values.w * .5,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w * .75, values.y, values.x + values.w * .75,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))
        lane.addToGroup(
            self.gs.addLine(
                values.x + values.w, values.y, values.x + values.w,
                self.reverse *
                (self.song.offset + level.beatToSec(self.song.lengthInBeats)) *
                self.pixPSec, self.editorTheme['GridLayer1Vert']))

    def getTheme(self):
        return {
            'BoxWidth': 60,
            'LaneSpacing': 20,
            'BG': QBrush(QColor(0, 0, 0), Qt.SolidPattern),
            'GridLayer1Vert': QPen(QBrush(QColor(255, 255, 255)), 1,
                                   Qt.SolidLine),
            'GridLayer1BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridLayer2Vert': QPen(Qt.white, Qt.SolidLine),
            'GridLayer2BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridLayer3Vert': QPen(Qt.white, Qt.SolidLine),
            'GridLayer3BG': QBrush(Qt.black, Qt.SolidPattern),
            'GridObs': QPen(Qt.blue, Qt.SolidLine),
            'GridObsBG': QBrush(Qt.black, Qt.SolidPattern),
            'GridEventVert': QPen(Qt.red, Qt.SolidLine),
            'GridEventBG': QBrush(Qt.black, Qt.SolidPattern),
            'GridMeasure': QPen(QBrush(QColor(255, 0, 0)), 2, Qt.SolidLine),
            'Grid4': QPen(QBrush(QColor(255, 255, 255)), 2, Qt.DashLine),
            'Grid8': QPen(QBrush(QColor(0, 150, 255)), 2, Qt.DotLine),
            'Grid12': QPen(QBrush(QColor(100, 255, 50)), 2, Qt.DotLine),
            'Grid16': QPen(QBrush(QColor(255, 255, 50)), 2, Qt.DotLine),
            'Grid24': QPen(QBrush(QColor(150, 100, 255)), 2, Qt.DotLine),
            'Grid32': QPen(QBrush(QColor(0, 255, 150)), 2, Qt.DotLine),
            'Grid48': QPen(QBrush(QColor(255, 100, 150)), 2, Qt.DotLine),
            'Grid64': QPen(QBrush(QColor(150, 200, 100)), 2, Qt.DotLine),
            #                    'Grid192': QPen(Qt.red,Qt.SolidLine),
            'GridLineWidth': 1
        }