Exemple #1
0
class Spline(QGraphicsPathItem):
    """Class that describes a spline"""
    def __init__(self, points, color):
        self.setKnotPoints(points)

        if color == 'y':
            self.setPen(QPen(Qt.yellow, 2))
        elif color == "r":
            self.setPen(QPen(Qt.red, 2))
        else:
            self.setPen(QPen(Qt.blue, 2))

    def setKnotPoints(self, knotPoints):
        """KnotPoints is a list of points"""

        p1 = QPointF(knotPoints[0][0], knotPoints[1][0])
        self.path = QPainterPath(p1)
        super(Spline, self).__init__(self.path)

        self.points = self.interpolate(knotPoints)
        for i in range(0, len(self.points[0])):
            self.path.lineTo(self.points[0][i], self.points[1][i])

        self.setPath(self.path)
        self.path.closeSubpath()
        self.knotPoints = knotPoints

    def interpolate(self, pts):
        """Interpolates the spline points at 500 points along spline"""
        pts = np.array(pts)
        tck, u = splprep(pts, u=None, s=0.0, per=1)
        u_new = np.linspace(u.min(), u.max(), 500)
        x_new, y_new = splev(u_new, tck, der=0)

        return (x_new, y_new)

    def update(self, pos, idx):
        """Updates the stored spline everytime it is moved
        Args:
            pos: new points coordinates
            idx: index on spline of updated point
        """

        if idx == len(self.knotPoints[0]) + 1:
            self.knotPoints[0].append(pos.x())
            self.knotPoints[1].append(pos.y())
        else:
            self.knotPoints[0][idx] = pos.x()
            self.knotPoints[1][idx] = pos.y()
        self.points = self.interpolate(self.knotPoints)
        for i in range(0, len(self.points[0])):
            self.path.setElementPositionAt(i, self.points[0][i],
                                           self.points[1][i])
        self.setPath(self.path)
Exemple #2
0
class Spline(QGraphicsPathItem):
    def __init__(self, points, color):
        self.setKnotPoints(points)
        if color == 'y':
            self.setPen(QPen(Qt.yellow, 2))
        else:
            self.setPen(QPen(Qt.red, 2))

    def setKnotPoints(self, knotPoints):
        """KnotPoints is a list of points"""
        p1 = QPointF(knotPoints[0][0], knotPoints[1][0])
        self.path = QPainterPath(p1)
        super(Spline, self).__init__(self.path)

        self.points = self.interpolate(knotPoints)
        for i in range(0, len(self.points[0])):
            self.path.lineTo(self.points[0][i], self.points[1][i])
        self.setPath(self.path)
        self.path.closeSubpath()
        self.knotPoints = knotPoints

    def interpolate(self, pts):
        pts = np.array(pts)
        tck, u = splprep(pts, u=None, s=0.0, per=1)
        u_new = np.linspace(u.min(), u.max(), 500)
        x_new, y_new = splev(u_new, tck, der=0)
        return (x_new, y_new)

    def update(self, pos, idx):
        self.knotPoints[0][idx] = pos.x()
        self.knotPoints[1][idx] = pos.y()
        self.points = self.interpolate(self.knotPoints)
        for i in range(0, len(self.points[0])):
            self.path.setElementPositionAt(i, self.points[0][i],
                                           self.points[1][i])
        self.setPath(self.path)
Exemple #3
0
class Canvas(QWidget):
    def __init__(self, parent=None):
        super(Canvas, self).__init__(parent)

        self.is_enable_knee_control = False

        # 画像専用のレイヤであるかを制御する
        # 1度Trueになったら2度とFalseにならないことを意図する
        self.is_picture_canvas = False
        self.picture_file_name = ""
        self.image = QImage()

        # マウストラック有効化
        self.setMouseTracking(True)

        # マウス移動で出る予測線とクリックして出る本線を描画するときに区別する
        self.is_line_prediction = False

        # イベント同士の競合を防ぐ
        self.event_Locker = False

        self.rounded_polygon = RoundedPolygon(10000)

        self.existing_paths = []  # 確定したパスを保存
        self.recorded_points = []  # 確定した点を保存(実験の記録用)
        self.clicked_points = []  # 今描いている線の制御点を記録
        self.cursor_position = QPointF()
        self.cursor_position_mousePressed = QPointF()
        self.knee_position = QPointF()
        self.knee_position_mousePressed = QPointF()
        self.current_drawing_mode = OperationMode.DRAWING_POINTS
        self.current_knee_operation_mode = OperationMode.NONE

        self.__line_color = []
        self.current_line_color = QColor()

        self.nearest_path = QPainterPath()
        self.nearest_distance = 50.0
        self.nearest_index = 0
        self.is_dragging = False

        self.pen_width = 2

        self.show()

    def set_experiment_controller(self, excontroller):
        self.experiment_controller = excontroller

    def mousePressEvent(self, event: QMouseEvent):
        if self.current_drawing_mode == OperationMode.DRAWING_POINTS:
            # 制御点の追加
            if event.button() == Qt.LeftButton:
                self.clicked_points.append(event.pos())
                # print(self.clickedPoints)

            # 直前の制御点の消去
            if event.button() == Qt.RightButton:
                if len(self.clicked_points) > 0:
                    self.clicked_points.pop()
                self.update()

        elif self.current_drawing_mode == OperationMode.MOVING_POINTS:
            if event.button() == Qt.LeftButton:
                self.is_dragging = True
                if self.is_enable_knee_control:
                    self.recode_knee_and_cursor_position()

                self.cursor_position = event.pos()
                self.update()

    def mouseMoveEvent(self, event: QMouseEvent):
        self.experiment_controller.current_mouse_position = event.pos()
        self.experiment_controller.record_frame(
            self.current_drawing_mode, self.current_knee_operation_mode)
        if self.current_drawing_mode == OperationMode.DRAWING_POINTS:
            self.clicked_points.append(event.pos())
            self.is_line_prediction = True
            self.update()

        elif self.current_drawing_mode == OperationMode.MOVING_POINTS:
            print(self.nearest_distance)
            self.cursor_position = event.pos()
            if self.is_dragging:
                self.move_point()
            self.update()

    def mouseReleaseEvent(self, event: QMouseEvent):
        self.is_dragging = False

    def paintEvent(self, event: QPaintEvent):
        # if not self.event_Locker:
        painter = QPainter(self)

        if self.is_picture_canvas:
            painter.drawImage(QRect(0, 0, 600, 600), self.image)

        else:
            # すでに確定されているパスの描画
            if len(self.existing_paths) > 0:
                for i in range(len(self.existing_paths)):
                    print("linecolor {}: {}".format(
                        i, self.__line_color[i].hue()))
                    painter.setPen(QPen(self.__line_color[i], self.pen_width))
                    painter.drawPath(self.existing_paths[i])

            if self.current_drawing_mode == OperationMode.DRAWING_POINTS:
                #  現在描いているパスの描画
                if len(self.clicked_points) > 3:
                    painter.setPen(
                        QPen(self.current_line_color, self.pen_width))
                    # print(self.clickedPoints)
                    # クリックした点まで線を伸ばすため、終点を一時的にリストに入れている
                    self.clicked_points.append(
                        self.clicked_points[len(self.clicked_points) - 1])
                    painter_path = self.rounded_polygon.get_path(
                        self.clicked_points)

                    # 設置した点の描画
                    painter.setPen(Qt.black)
                    for i in range(len(self.clicked_points)):
                        painter.drawEllipse(self.clicked_points[i], 2, 2)
                    painter.setPen(
                        QPen(self.current_line_color, self.pen_width))
                    # 現在のマウス位置での予告線
                    if self.is_line_prediction:
                        self.clicked_points.pop()
                        self.is_line_prediction = False
                    painter.drawPath(painter_path)
                    self.clicked_points.pop()

                # 線が描けない時
                else:
                    # 現在のマウス位置での予告線
                    if self.is_line_prediction:
                        painter.setPen(Qt.red)
                        for i in range(len(self.clicked_points)):
                            painter.drawEllipse(self.clicked_points[i], 2, 2)
                        if not len(self.clicked_points) == 0:
                            self.clicked_points.pop()
                        self.is_line_prediction = False

                    # 予告線でもない場合は単に点を書く
                    else:
                        for i in range(len(self.clicked_points)):
                            painter.drawEllipse(self.clicked_points[i], 2, 2)

            # 制御点を移動するとき
            elif self.current_drawing_mode == OperationMode.MOVING_POINTS:
                # すでに確定されているパスの制御点の描画
                self.nearest_distance = 50.0
                painter.setPen(Qt.black)
                for path in self.existing_paths:
                    for i in range(path.elementCount()):
                        control_point = QPointF(
                            path.elementAt(i).x,
                            path.elementAt(i).y)
                        painter.drawEllipse(control_point, 3, 3)

                        # 現在のカーソル位置から最も近い点と、その点が属するpathを記録、更新
                        # if not self.is_dragging & self.is_enable_knee_control:
                        distance = math.sqrt(
                            (control_point.x() - self.cursor_position.x())**2 +
                            (control_point.y() - self.cursor_position.y())**2)
                        if distance < self.nearest_distance:
                            self.nearest_distance = distance
                            self.nearest_path = path
                            self.nearest_index = i

                # 一定の距離未満かつ最も近い点を赤く描画
                if self.nearest_distance < 20:
                    painter.setPen(QPen(Qt.red, self.pen_width))
                    nearest_control_point = QPointF(
                        self.nearest_path.elementAt(self.nearest_index).x,
                        self.nearest_path.elementAt(self.nearest_index).y)
                    painter.drawEllipse(nearest_control_point, 3, 3)

    def move_point(self):
        if self.is_enable_knee_control:
            if self.nearest_distance < 20 or self.is_dragging:
                self.nearest_path.setElementPositionAt(
                    self.nearest_index, self.cursor_position.x(),
                    self.cursor_position.y())

                amount_of_change = QPointF(
                    self.cursor_position.x() +
                    (self.knee_position.x() -
                     self.knee_position_mousePressed.x()),
                    self.cursor_position.y() -
                    (self.knee_position.y() -
                     self.knee_position_mousePressed.y()))
                self.nearest_path.setElementPositionAt(self.nearest_index,
                                                       amount_of_change.x(),
                                                       amount_of_change.y())

        else:
            if self.nearest_distance < 20:
                self.nearest_path.setElementPositionAt(
                    self.nearest_index, self.cursor_position.x(),
                    self.cursor_position.y())

    def set_knee_position(self, x, y):
        self.knee_position.setX(x)
        self.knee_position.setY(y)

        if self.is_dragging:
            if self.current_drawing_mode == OperationMode.MOVING_POINTS:
                self.move_point()
                self.update()

    def set_line_color(self, color):
        self.current_line_color = color

    def recode_knee_and_cursor_position(self):
        self.knee_position_mousePressed.setX(self.knee_position.x())
        self.knee_position_mousePressed.setY(self.knee_position.y())
        self.cursor_position_mousePressed = self.cursor_position

    def fix_path(self):
        # パスを確定
        if self.is_line_prediction and not len(self.clicked_points) == 0:
            self.clicked_points.pop()
        # クリックした点まで線を伸ばすため、終点をリストに入れている
        if len(self.clicked_points) > 0:
            self.clicked_points.append(
                self.clicked_points[len(self.clicked_points) - 1])
            painter_path = self.rounded_polygon.get_path(self.clicked_points)

            # 線と色を記録
            self.existing_paths.append(painter_path)
            self.__line_color.append(self.current_line_color)
            for i in range(len(self.__line_color)):
                print("{}, {}".format(i, self.__line_color[i].value()))
            self.clicked_points.pop()
            self.recorded_points.append(self.clicked_points)

            # 点をリセット
            self.clicked_points = []
            self.update()

    def delete_last_path(self):
        if len(self.existing_paths) > 0:
            self.existing_paths.pop()
            self.__line_color.pop()
            self.update()

    def switch_visible(self, is_visible: bool):
        palette = self.palette()
        if is_visible:
            palette.setColor(QPalette.Background, QColor(255, 255, 255, 120))
        else:
            palette.setColor(QPalette.Background, QColor(255, 255, 255, 255))
        self.setPalette(palette)

    def operation_mode_changed(self, to_drawing: OperationMode,
                               to_knee: OperationMode):
        self.current_drawing_mode = to_drawing
        self.current_knee_operation_mode = to_knee
        self.fix_path()

    def set_picture_file_name(self, picture_file_name: str):
        self.is_picture_canvas = True
        self.picture_file_name = picture_file_name
        self.update()

    def set_enable_knee_control(self, is_enable_knee_control):
        self.is_enable_knee_control = is_enable_knee_control

    def load_picture(self, image: QImage):
        self.image = image
        self.is_picture_canvas = True
        self.update()