Пример #1
0
    def __save_atlas(self) -> None:
        """Saving all the atlas to image file.

        We should turn transparent background to white first.
        Then using QImage class to merge into one image.
        """
        count = self.structure_list.count()
        if count < 1:
            return

        lateral = self.__save_atlas_ask()
        if not lateral:
            return

        file_name = self.output_to("atlas image", qt_image_format)
        if not file_name:
            return

        width = self.structure_list.iconSize().width()
        image_main = QImage(QSize(
            lateral * width if count > lateral else count * width,
            ((count // lateral) + bool(count % lateral)) * width
        ), self.__atlas_image(0).format())
        image_main.fill(Qt.transparent)
        painter = QPainter(image_main)
        for row in range(count):
            image = self.__atlas_image(row)
            painter.drawImage(QPointF(row % lateral, row // lateral) * width, image)
        painter.end()
        pixmap = QPixmap.fromImage(image_main)
        pixmap.save(file_name)
        self.save_reply_box("Atlas", file_name)
Пример #2
0
 def paintEvent(self, event: QPaintEvent):
     painter = QPainter(self)
     painter.drawImage(self.rect(), self.image)
     if self.show_frame:
         painter.save()
         pen = QPen()
         pen.setWidth(2)
         pen.setColor(QColor("black"))
         painter.setPen(pen)
         rect = QRect(1, 1, self.width() - 2, self.height() - 2)
         painter.drawRect(rect)
         pen.setColor(QColor("white"))
         painter.setPen(pen)
         rect = QRect(3, 3, self.width() - 6, self.height() - 6)
         painter.drawRect(rect)
         painter.restore()
     if self.show_arrow:
         painter.save()
         triangle = QPolygonF()
         dist = 4
         point1 = QPoint(self.width() - self.triangle_width, 0)
         size = QSize(20, self.height() // 2)
         rect = QRect(point1, size)
         painter.fillRect(rect, QColor("white"))
         triangle.append(point1 + QPoint(dist, dist))
         triangle.append(point1 + QPoint(size.width() - dist, dist))
         triangle.append(point1 + QPoint(size.width() // 2,
                                         size.height() - dist))
         painter.setBrush(Qt.black)
         painter.drawPolygon(triangle, Qt.WindingFill)
         painter.restore()
Пример #3
0
    def paint(
        self,
        painter: QPainter,
        style: QStyleOptionViewItem,
        model: QModelIndex,
    ):
        style2 = QStyleOptionViewItem(style)

        cbar_rect = QRect(
            style.rect.x(),
            style.rect.y() + PADDING,
            style.rect.width() - TEXT_WIDTH,
            style.rect.height() - 2 * PADDING,
        )
        text_rect = QRect(
            style.rect.width() - TEXT_WIDTH,
            style.rect.y() + PADDING,
            style.rect.width(),
            style.rect.height() - 2 * PADDING,
        )
        style2.rect = text_rect
        super().paint(painter, style2, model)
        cbar = make_colorbar(ensure_colormap(model.data()), (18, 100))
        image = QImage(
            cbar,
            cbar.shape[1],
            cbar.shape[0],
            QImage.Format_RGBA8888,
        )
        painter.drawImage(cbar_rect, image)
Пример #4
0
    def _paint_inner_grid(self, painter: QPainter, rect: QRect,
                          colors) -> None:
        margin = 10
        job_nr = len(colors)
        grid_dim = math.ceil(math.sqrt(job_nr))
        k = 0

        colors_hash = hash(tuple([color.name() for color in colors]))
        if colors_hash not in self._image_cache:
            foreground_image = QImage(grid_dim, grid_dim, QImage.Format_ARGB32)
            foreground_image.fill(QColorConstants.Gray)

            for y in range(grid_dim):
                for x in range(grid_dim):
                    if k >= job_nr:
                        color = QColorConstants.Gray
                    else:
                        color = colors[k]
                    foreground_image.setPixel(x, y, color.rgb())
                    k += 1
            self._image_cache[colors_hash] = foreground_image
        else:
            foreground_image = self._image_cache[colors_hash]

        painter.drawImage(rect, foreground_image)
Пример #5
0
    def paintEvent(self, event):
        tic = time.perf_counter()
        painter = QPainter(self)
        rect = event.rect()
        painter.drawImage(rect, self.image, rect)
        painter.setPen(QColor.fromRgb(255, 0, 0))
        #painter.drawPoints(self.clicks)
        if self.drawBoxes:
            self.drawBoxes(painter)
        # Draw the center mark
        painter.setPen(QColor.fromRgb(255, 0, 0))
        painter.drawLine(self.center.x() - 20, self.center.y(),
                         self.center.x() + 20, self.center.y())
        painter.drawLine(self.center.x(),
                         self.center.y() - 20, self.center.x(),
                         self.center.y() + 20)

        # Draw the scale bar
        if self.scaleBar:
            painter.setPen(QColor.fromRgb(40, 40, 40))
            painter.setFont(QFont("Arial", 30))
            scaleRect = QRect(10, 420, 200, 30)
            painter.drawText(scaleRect, Qt.AlignCenter, "10 nm")
            pen = painter.pen()
            pen.setWidth(5)
            painter.setPen(pen)
            painter.drawLine(10, 460, 210, 460)

        toc = time.perf_counter()
Пример #6
0
 def __save_atlas(self) -> None:
     """Save function as same as type synthesis widget."""
     count = self.collection_list.count()
     if count < 1:
         return
     lateral, ok = QInputDialog.getInt(self, "Atlas",
                                       "The number of lateral:", 5, 1)
     if not ok:
         return
     file_name = self.output_to("atlas image", qt_image_format)
     if not file_name:
         return
     icon_size = self.collection_list.iconSize()
     width = icon_size.width()
     image = self.collection_list.item(0).icon().pixmap(icon_size).toImage()
     image_main = QImage(
         QSize(lateral if count > lateral else count,
               (count // lateral) + bool(count % lateral)) * width,
         image.format())
     image_main.fill(Qt.transparent)
     painter = QPainter(image_main)
     for row in range(count):
         image = self.collection_list.item(row).icon().pixmap(
             icon_size).toImage()
         painter.drawImage(
             QPointF(row % lateral, row // lateral) * width, image)
     painter.end()
     pixmap = QPixmap()
     pixmap.convertFromImage(image_main)
     pixmap.save(file_name)
     self.save_reply_box("Atlas", file_name)
Пример #7
0
    def paintEvent(self, event):
        super(DetailedProgress, self).paintEvent(event)
        if not self._current_progress:
            return

        painter = QPainter(self)
        width = self.width()
        height = self.height()
        aspect_ratio = float(width) / height
        nr_realizations = max([iens
                               for iens, _, _ in self._current_progress]) + 1
        fm_size = max(
            [len(progress) for _, progress, _ in self._current_progress])
        self.grid_height = math.ceil(math.sqrt(nr_realizations / aspect_ratio))
        self.grid_width = math.ceil(self.grid_height * aspect_ratio)
        sub_grid_size = math.ceil(math.sqrt(fm_size))
        cell_height = height / self.grid_height
        cell_width = width / self.grid_width

        foreground_image = QImage(self.grid_width * sub_grid_size,
                                  self.grid_height * sub_grid_size,
                                  QImage.Format_ARGB32)
        foreground_image.fill(QColor(0, 0, 0, 0))

        for index, (iens, progress, _) in enumerate(self._current_progress):
            y = int(iens / self.grid_width)
            x = int(iens - (y * self.grid_width))
            self.draw_window(x * sub_grid_size, y * sub_grid_size, progress,
                             foreground_image)
            painter.drawImage(self.contentsRect(), foreground_image)

        for index, (iens, progress,
                    state) in enumerate(self._current_progress):
            y = int(iens / self.grid_width)
            x = int(iens - (y * self.grid_width))

            painter.setPen(QColor(80, 80, 80))
            painter.drawText(int(x * cell_width), int(y * cell_height),
                             int(cell_width), int(cell_height),
                             int(Qt.AlignHCenter | Qt.AlignVCenter), str(iens))

            if iens == self.selected_realization:
                pen = QPen(QColor(240, 240, 240))
            elif (self.has_realization_failed(progress)):
                pen = QPen(QColor(*self.state_colors['Failure']))
            elif (state == JobStatusType.JOB_QUEUE_RUNNING):
                pen = QPen(QColor(*self.state_colors['Running']))
            else:
                pen = QPen(QColor(80, 80, 80))

            thickness = 4
            pen.setWidth(thickness)
            painter.setPen(pen)
            painter.drawRect(
                int(x * cell_width) + (thickness // 2),
                int(y * cell_height) + (thickness // 2),
                int(cell_width) - (thickness - 1),
                int(cell_height) - (thickness - 1))
Пример #8
0
 def paintEvent(self, event: QPaintEvent):
     painter = QPainter(self)
     start = 2 * self.checked.x() + self.checked.width()
     end = self.remove_btn.x() - self.checked.x()
     rect = self.rect()
     rect.setX(start)
     rect.setWidth(end - start)
     painter.drawImage(rect, self.image)
     super().paintEvent(event)
Пример #9
0
    def resizeEvent(self, event):
        old = QImage(self.m_image)

        width = max(self.geometry().width(), old.width())
        height = max(self.geometry().height(), old.height())

        if width > old.width() or height > old.height():
            self.m_image = QImage(width, height, QImage.Format_RGB32)
            self.m_image.fill(colorTable[self.m_backgroundColorIndex %
                                         len(colorTable)].rgba())
            p = QPainter(self.m_image)
            p.drawImage(0, 0, old)

        self.scheduleRender()
Пример #10
0
 def paint(self, painter: QPainter, style: QStyleOptionViewItem,
           model: QModelIndex):
     if model.data() not in image_dict:
         image_dict[model.data()] = create_colormap_image(
             model.data(), self.color_dict)
     rect = QRect(style.rect.x(),
                  style.rect.y() + 2, style.rect.width(),
                  style.rect.height() - 4)
     painter.drawImage(rect, image_dict[model.data()])
     if int(style.state & QStyle.State_HasFocus):
         painter.save()
         pen = QPen()
         pen.setWidth(5)
         painter.setPen(pen)
         painter.drawRect(rect)
         painter.restore()
Пример #11
0
    def paintEvent(self, a0: QPaintEvent) -> None:
        painter = QPainter(self)
        margin = 10
        width = self.width() - 2 * margin
        rect = QRect(margin, margin, width, self.height() - 2 * margin)
        painter.drawImage(rect, self.image)
        painter.save()

        for pos_factor in self.position_list:
            pos = width * pos_factor
            point = QPointF(pos + margin, self.height() / 2)
            painter.setBrush(QBrush(Qt.black))
            painter.drawEllipse(point, 5, 5)
            painter.setBrush(QBrush(Qt.white))
            painter.drawEllipse(point, 3, 3)

        painter.restore()
Пример #12
0
    def render(self):
        rect = QRect(QPoint(), self.geometry().size())
        self.m_backingStore.resize(rect.size())

        self.m_backingStore.beginPaint(QRegion(rect))

        device = self.m_backingStore.paintDevice()

        p = QPainter(device)
        p.drawImage(0, 0, self.m_image)

        font = QFont()
        font.setPixelSize(32)

        p.setFont(font)
        p.drawText(rect, 0, self.m_text)

        self.m_backingStore.endPaint()
        self.m_backingStore.flush(QRegion(rect))
 def paintEvent(self, event: QPaintEvent):
     outerRadius = min(self.width(), self.height())
     baseRect = QRectF(1, 1, outerRadius - 2, outerRadius - 2)
     buffer = QImage(outerRadius, outerRadius, QImage.Format_ARGB32_Premultiplied)
     p = QPainter(buffer)
     p.setRenderHint(QPainter.Antialiasing)
     self.rebuildDataBrushIfNeeded()
     self.drawBackground(p, buffer.rect())
     self.drawBase(p, baseRect)
     if self.m_value > 0:
         delta = (self.m_max - self.m_min) / (self.m_value - self.m_min)
     else:
         delta = 0
     self.drawValue(p, baseRect, self.m_value, delta)
     innerRect, innerRadius = self.calculateInnerRect(outerRadius)
     self.drawInnerBackground(p, innerRect)
     self.drawText(p, innerRect, innerRadius, self.m_value)
     p.end()
     painter = QPainter(self)
     painter.fillRect(baseRect, self.palette().window())
     painter.drawImage(0, 0, buffer)
Пример #14
0
def create_thumbnail(name='./.thumbnail',
                     model='tfm',
                     geometry=False,
                     chemistry=False,
                     background=None):
    if background is not None and os.path.exists(background):
        img = QImage(background)
        base = img.scaled(300, 300).scaled(128, 128, Qt.IgnoreAspectRatio)
    else:
        base = QImage(QSize(128, 128), QImage.Format_ARGB32)
        base.fill(Qt.white)

    painter = QPainter(base)

    # add images
    model = QImage(get_image_path(model + '.svg'))
    painter.drawImage(0, 128 - 24, model)

    if geometry:
        geo = QImage(get_image_path('geometry.svg'))
        painter.drawImage(24, 128 - 24, geo)

    if chemistry:
        geo = QImage(get_image_path('chemistry.svg'))
        painter.drawImage(24 * 2, 128 - 24, geo)

    base.save(name, "PNG")
    del painter
Пример #15
0
    def paintEvent(self, event: QtGui.QPaintEvent):
        bar_width = 30

        if self.image is None:
            return

        rect = self.rect()
        number_of_marks = self.number_of_marks(rect.height())
        image_rect = QRect(rect.topLeft(),
                           QSize(bar_width,
                                 rect.size().height()))
        painter = QPainter(self)
        old_font = painter.font()
        new_font = painter.font()
        new_font.setPointSizeF(new_font.pointSizeF() / 1.1)
        painter.setFont(new_font)
        painter.drawImage(image_rect, self.image)
        if self.range[1] == self.range[0]:
            painter.drawText(bar_width + 5, 20, f"{self.range[1]}")
            painter.drawText(bar_width + 5,
                             rect.size().height(), f"{self.range[1]}")
            painter.setFont(old_font)
            return
        start_prop = 1 - (self.round_range[0] -
                          self.range[0]) / (self.range[1] - self.range[0])
        end_prop = 1 - (self.round_range[1] - self.range[0]) / (self.range[1] -
                                                                self.range[0])
        for pos, val in zip(
                np.linspace(10 + end_prop * rect.size().height(),
                            start_prop * rect.size().height(),
                            number_of_marks),
                np.linspace(self.round_range[1],
                            self.round_range[0],
                            number_of_marks,
                            dtype=np.uint32),
        ):
            painter.drawText(bar_width + 5, int(pos), f"{val}")
        painter.setFont(old_font)
Пример #16
0
 def __structure_list_context_menu(self, point) -> None:
     """Context menu for the type synthesis results."""
     index = self.structure_list.currentIndex().row()
     self.to_collection.setEnabled(index > -1)
     self.copy_edges.setEnabled(index > -1)
     self.copy_image.setEnabled(index > -1)
     action = self.pop_menu_topo.exec_(self.structure_list.mapToGlobal(point))
     if not action:
         return
     clipboard = QApplication.clipboard()
     if action == self.to_collection:
         self.add_collection(self.answer[index].edges)
     elif action == self.copy_edges:
         clipboard.setText(str(self.answer[index].edges))
     elif action == self.copy_image:
         # Turn the transparent background to white
         image1 = self.__atlas_image()
         image2 = QImage(image1.size(), image1.format())
         image2.fill(Qt.white)
         painter = QPainter(image2)
         painter.drawImage(QPointF(0, 0), image1)
         painter.end()
         clipboard.setPixmap(QPixmap.fromImage(image2))
Пример #17
0
 def paintEvent(self, event: QPaintEvent):
     rect = event.rect()
     painter = QPainter(self)
     if self.parent().image is not None:
         parent: "ColorSelector" = self.parent()
         painter.drawImage(rect, parent.image)
Пример #18
0
    def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem',
              index: QtCore.QModelIndex) -> None:
        if not index.isValid():
            return
        if option.state & QStyle.State_Selected:
            pass
        if option.state & QStyle.State_MouseOver:
            pass

        item = index.model().data(index, Qt.UserRole)
        if isinstance(item, QVariant):
            return

        painter.setRenderHint(QPainter.Antialiasing, True)
        painter.setRenderHints(QPainter.SmoothPixmapTransform)

        value = item['value']
        type = item['type']
        x = option.rect.x()
        y = option.rect.y()
        w = option.rect.width()
        h = option.rect.height()
        if type == 'device_activity':
            painter.save()
            # 图标
            icon = QImage(ResourceLoader().icon_path(value['icon']))
            rect_icon = QRectF(x + 20, y + 13, 44, 44)
            painter.drawImage(rect_icon, icon)
            # 设备标签
            painter.setFont(ResourceLoader().qt_font_text_xs)
            rect = calculate_text_rect('设备',
                                       painter=painter,
                                       x=x + 70,
                                       y=y + 15)
            painter.drawText(rect, Qt.TextSingleLine, '设备')
            # 设备编号
            painter.setPen(ResourceLoader().qt_color_label_link)
            painter.setFont(ResourceLoader().qt_font_text_xs)
            rect = calculate_text_rect(value['device'],
                                       painter=painter,
                                       x=x + 110,
                                       y=y + 15)
            painter.drawText(rect, Qt.TextSingleLine, value['device'])
            # 活动内容
            painter.setPen(ResourceLoader().qt_color_sub_text)
            painter.setFont(ResourceLoader().qt_font_text_xss)
            content = value['content'] + ',' + toDateStr()
            rect = calculate_text_rect(content,
                                       painter=painter,
                                       x=x + 70,
                                       y=y + 40)
            painter.drawText(rect, Qt.TextSingleLine, content)
            # 绘制边框
            path = QPainterPath()
            path.addRoundedRect(QRectF(x + 4, y + 4, w - 8, h - 8), 4, 4)
            painter.strokePath(path,
                               QPen(ResourceLoader().qt_color_background, 1))

            painter.restore()
        elif type == 'load_more':
            # 绘制加载图标
            # painter.save()
            # painter.translate(x+16, y+16)
            # self.loading_rotate += 5
            # painter.rotate(self.loading_rotate%360)
            # icon = qtawesome.icon('mdi.loading', color=ResourceLoader().qt_color_sub_text)
            # icon_pixmap = icon.pixmap(QSize(32, 32))
            # painter.drawPixmap(QRect(-16, -16, 32, 32), icon_pixmap)
            # painter.restore()
            # 绘制加载信息
            painter.save()
            painter.setFont(ResourceLoader().qt_font_text_xs)
            painter.setPen(ResourceLoader().qt_color_sub_text)
            _rect = calculate_text_rect('~~~ 正在努力加载 ~~~', painter=painter)
            rect = calculate_middle_rect(option.rect,
                                         width=_rect.width(),
                                         height=_rect.height())
            painter.drawText(rect, Qt.TextSingleLine, '~~~ 正在努力加载 ~~~')
            painter.restore()
        elif type == 'no_more':
            painter.save()
            painter.setFont(ResourceLoader().qt_font_text_xs)
            painter.setPen(ResourceLoader().qt_color_sub_text)
            _rect = calculate_text_rect('--- 我是有底线的 ---', painter=painter)
            rect = calculate_middle_rect(option.rect,
                                         width=_rect.width(),
                                         height=_rect.height())
            painter.drawText(rect, Qt.TextSingleLine, '--- 我是有底线的 ---')
            painter.restore()
        else:
            self.initStyleOption(option, index)
            QStyledItemDelegate.paint(self, painter, option, index)
Пример #19
0
 def paintEvent(self, QPaintEvent):
     painter = QPainter(self)
     rect = self.rect()
     painter.drawImage(rect, self.image)
Пример #20
0
class BaseCanvas(QWidget, metaclass=QABCMeta):
    """The subclass can draw a blank canvas more easier."""
    @abstractmethod
    def __init__(self, parent: QWidget):
        """Set the parameters for drawing."""
        super(BaseCanvas, self).__init__(parent)
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        self.setFocusPolicy(Qt.StrongFocus)
        self.setMouseTracking(True)
        self.painter = QPainter()
        # Origin coordinate
        self.ox = self.width() / 2
        self.oy = self.height() / 2
        # Canvas zoom rate
        self.zoom = 1.
        # Joint size
        self.joint_size = 5
        # Canvas line width
        self.link_width = 3
        self.path_width = 3
        # Font size
        self.font_size = 15
        # Show point mark or dimension
        self.show_ticks = _TickMark.SHOW
        self.show_point_mark = True
        self.show_dimension = True
        # Path track
        self.path = _PathOption()
        # Path solving
        self.ranges: Dict[str, QRectF] = {}
        self.target_path: Dict[int, Sequence[_Coord]] = {}
        self.show_target_path = False
        # Background
        self.background = QImage()
        self.background_opacity = 1.
        self.background_scale = 1.
        self.background_offset = QPointF(0, 0)
        # Monochrome mode
        self.monochrome = False
        # Grab mode
        self.__grab_mode = False

    def switch_grab(self) -> None:
        """Start grab mode."""
        self.__grab_mode = not self.__grab_mode

    @staticmethod
    def zoom_factor(width: int, height: int, x_right: float, x_left: float,
                    y_top: float, y_bottom: float) -> float:
        """Calculate the zoom factor."""
        x_diff = x_left - x_right
        y_diff = y_top - y_bottom
        x_diff = x_diff if x_diff else 1.
        y_diff = y_diff if y_diff else 1.
        if width / x_diff < height / y_diff:
            return width / x_diff
        else:
            return height / y_diff

    @abstractmethod
    def paintEvent(self, event: QPaintEvent) -> None:
        """Using a QPainter under 'self',
        so just change QPen or QBrush before painting.
        """
        if not self.__grab_mode:
            self.painter.begin(self)
            self.painter.fillRect(event.rect(), QBrush(Qt.white))
        # Translation
        self.painter.translate(self.ox, self.oy)
        # Background
        if not self.background.isNull():
            rect = self.background.rect()
            self.painter.setOpacity(self.background_opacity)
            self.painter.drawImage(
                QRectF(
                    self.background_offset * self.zoom,
                    QSizeF(rect.width(), rect.height()) *
                    self.background_scale * self.zoom), self.background,
                QRectF(rect))
            self.painter.setOpacity(1)
        # Show frame
        pen = QPen(Qt.blue)
        pen.setWidth(1)
        self.painter.setPen(pen)
        self.painter.setFont(QFont("Arial", self.font_size))
        # Draw origin lines
        if self.show_ticks not in {_TickMark.SHOW, _TickMark.SHOW_NUM}:
            return
        pen.setColor(Qt.gray)
        self.painter.setPen(pen)
        x_l = -self.ox
        x_r = self.width() - self.ox
        self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0))
        y_t = self.height() - self.oy
        y_b = -self.oy
        self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t))

        def indexing(v: float) -> int:
            """Draw tick."""
            return int(v / self.zoom - v / self.zoom % 5)

        # Draw tick
        for x in range(indexing(x_l), indexing(x_r) + 1, 5):
            if x == 0:
                continue
            is_ten = x % 10 == 0
            end = QPointF(x * self.zoom, -10 if is_ten else -5)
            self.painter.drawLine(QPointF(x, 0) * self.zoom, end)
            if self.show_ticks == _TickMark.SHOW_NUM and is_ten:
                self.painter.drawText(end + QPointF(0, 3), f"{x}")
        for y in range(indexing(y_b), indexing(y_t) + 1, 5):
            if y == 0:
                continue
            is_ten = y % 10 == 0
            end = QPointF(10 if is_ten else 5, y * self.zoom)
            self.painter.drawLine(QPointF(0, y) * self.zoom, end)
            if self.show_ticks == _TickMark.SHOW_NUM and is_ten:
                self.painter.drawText(end + QPointF(3, 0), f"{-y}")
        # Please to call the "end" method when ending paint event.

    def draw_circle(self, p: QPointF, r: float) -> None:
        """Draw circle."""
        self.painter.drawEllipse(p, r, r)

    def draw_point(self,
                   i: int,
                   cx: float,
                   cy: float,
                   fixed: bool,
                   color: Optional[Tuple[int, int, int]],
                   mul: int = 1) -> None:
        """Draw a joint."""
        if self.monochrome or color is None:
            color = Qt.black
        else:
            color = QColor(*color)
        pen = QPen(color)
        pen.setWidth(2)
        self.painter.setPen(pen)
        x = cx * self.zoom
        y = cy * -self.zoom
        if fixed:
            # Draw a triangle below
            self.painter.drawPolygon(
                QPointF(x, y),
                QPointF(x - self.joint_size, y + 2 * self.joint_size),
                QPointF(x + self.joint_size, y + 2 * self.joint_size))
        r = self.joint_size
        for _ in range(1 if mul < 1 else mul):
            self.draw_circle(QPointF(x, y), r)
            r += 5
        if not self.show_point_mark:
            return
        pen.setColor(Qt.darkGray)
        pen.setWidth(2)
        self.painter.setPen(pen)
        text = f"[Point{i}]"
        if self.show_dimension:
            text += f":({cx:.02f}, {cy:.02f})"
        self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text)

    def draw_ranges(self) -> None:
        """Draw rectangle ranges."""
        pen = QPen()
        pen.setWidth(5)
        for i, (tag, rect) in enumerate(self.ranges.items()):
            range_color = QColor(color_num(i + 1))
            range_color.setAlpha(30)
            self.painter.setBrush(range_color)
            range_color.setAlpha(255)
            pen.setColor(range_color)
            self.painter.setPen(pen)
            cx = rect.x() * self.zoom
            cy = rect.y() * -self.zoom
            if rect.width():
                self.painter.drawRect(
                    QRectF(QPointF(cx, cy),
                           QSizeF(rect.width(), rect.height()) * self.zoom))
            else:
                self.draw_circle(QPointF(cx, cy), 3)
            range_color.setAlpha(255)
            pen.setColor(range_color)
            self.painter.setPen(pen)
            self.painter.drawText(QPointF(cx, cy) + QPointF(6, -6), tag)
            self.painter.setBrush(Qt.NoBrush)

    def draw_target_path(self) -> None:
        """Draw solving path."""
        pen = QPen()
        pen.setWidth(self.path_width)
        for i, n in enumerate(sorted(self.target_path)):
            path = self.target_path[n]
            if self.monochrome:
                line, dot = target_path_style(0)
            else:
                line, dot = target_path_style(i + 1)
            pen.setColor(line)
            self.painter.setPen(pen)
            if len(path) == 1:
                x, y = path[0]
                p = QPointF(x, -y) * self.zoom
                self.painter.drawText(p + QPointF(6, -6), f"P{n}")
                pen.setColor(dot)
                self.painter.setPen(pen)
                self.draw_circle(p, self.joint_size)
            else:
                painter_path = QPainterPath()
                for j, (x, y) in enumerate(path):
                    p = QPointF(x, -y) * self.zoom
                    self.draw_circle(p, self.joint_size)
                    if j == 0:
                        self.painter.drawText(p + QPointF(6, -6), f"P{n}")
                        painter_path.moveTo(p)
                    else:
                        x2, y2 = path[j - 1]
                        self.__draw_arrow(x, -y, x2, -y2, zoom=True)
                        painter_path.lineTo(p)
                pen.setColor(line)
                self.painter.setPen(pen)
                self.painter.drawPath(painter_path)
                for x, y in path:
                    pen.setColor(dot)
                    self.painter.setPen(pen)
                    self.draw_circle(
                        QPointF(x, -y) * self.zoom, self.joint_size)
        self.painter.setBrush(Qt.NoBrush)

    def __draw_arrow(self,
                     x1: float,
                     y1: float,
                     x2: float,
                     y2: float,
                     *,
                     zoom: bool = False,
                     text: str = '') -> None:
        """Front point -> Back point"""
        if zoom:
            x1 *= self.zoom
            y1 *= self.zoom
            x2 *= self.zoom
            y2 *= self.zoom
        a = atan2(y2 - y1, x2 - x1)
        x1 = (x1 + x2) / 2 - 7.5 * cos(a)
        y1 = (y1 + y2) / 2 - 7.5 * sin(a)
        first_point = QPointF(x1, y1)
        self.painter.drawLine(
            first_point,
            QPointF(x1 + 15 * cos(a + radians(20)),
                    y1 + 15 * sin(a + radians(20))))
        self.painter.drawLine(
            first_point,
            QPointF(x1 + 15 * cos(a - radians(20)),
                    y1 + 15 * sin(a - radians(20))))
        if not text:
            return
        # Font
        font = self.painter.font()
        font_copy = QFont(font)
        font.setBold(True)
        font.setPointSize(font.pointSize() + 8)
        self.painter.setFont(font)
        # Color
        pen = self.painter.pen()
        color = pen.color()
        pen.setColor(color.darker())
        self.painter.setPen(pen)
        self.painter.drawText(first_point, text)
        pen.setColor(color)
        self.painter.setPen(pen)
        self.painter.setFont(font_copy)

    def draw_curve(self, path: Sequence[_Coord]) -> None:
        """Draw path as curve."""
        if len(set(path)) < 2:
            return
        painter_path = QPainterPath()
        error = False
        for i, (x, y) in enumerate(path):
            if isnan(x):
                error = True
                self.painter.drawPath(painter_path)
                painter_path = QPainterPath()
            else:
                p = QPointF(x, -y) * self.zoom
                if i == 0:
                    painter_path.moveTo(p)
                    self.draw_circle(p, 2)
                    continue
                if error:
                    painter_path.moveTo(p)
                    error = False
                else:
                    painter_path.lineTo(p)
        self.painter.drawPath(painter_path)

    def draw_dot(self, path: Sequence[_Coord]) -> None:
        """Draw path as dots."""
        if len(set(path)) < 2:
            return
        for i, (x, y) in enumerate(path):
            if isnan(x):
                continue
            p = QPointF(x, -y) * self.zoom
            if i == 0:
                self.draw_circle(p, 2)
            else:
                self.painter.drawPoint(p)

    def solution_polygon(
            self, func: str, args: Sequence[str], target: str,
            pos: Sequence[VPoint]) -> Tuple[List[QPointF], QColor]:
        """Get solution polygon."""
        if func == 'PLLP':
            color = QColor(121, 171, 252)
            params = [args[0], args[-1]]
        elif func == 'PLAP':
            color = QColor(249, 84, 216)
            params = [args[0]]
        else:
            if func == 'PLPP':
                color = QColor(94, 255, 185)
            else:
                # PXY
                color = QColor(249, 175, 27)
            params = [args[0]]
        params.append(target)
        tmp_list = []
        for name in params:
            try:
                index = int(name.replace('P', ''))
            except ValueError:
                continue
            else:
                vpoint = pos[index]
                tmp_list.append(QPointF(vpoint.cx, -vpoint.cy) * self.zoom)
        return tmp_list, color

    def draw_solution(self, func: str, args: Sequence[str], target: str,
                      pos: Sequence[VPoint]) -> None:
        """Draw the solution triangle."""
        points, color = self.solution_polygon(func, args, target, pos)
        color.setAlpha(150)
        pen = QPen(color)
        pen.setWidth(self.joint_size)
        self.painter.setPen(pen)

        def draw_arrow(index: int, text: str) -> None:
            """Draw arrow."""
            self.__draw_arrow(points[-1].x(),
                              points[-1].y(),
                              points[index].x(),
                              points[index].y(),
                              text=text)

        draw_arrow(0, args[1])
        if func == 'PLLP':
            draw_arrow(1, args[2])
        color.setAlpha(30)
        self.painter.setBrush(QBrush(color))
        self.painter.drawPolygon(QPolygonF(points))
        self.painter.setBrush(Qt.NoBrush)

    @Slot(int)
    def set_show_ticks(self, show: int):
        """Set the appearance of tick mark."""
        self.show_ticks = _TickMark(show + 1)
        self.update()

    @Slot(bool)
    def set_monochrome_mode(self, monochrome: bool) -> None:
        """Set monochrome mode."""
        self.monochrome = monochrome
        self.update()
Пример #21
0
 def paint(self, painter: QPainter):
     bounding_rect = QRect(0, 0, self.width(), self.height())
     if not self._frame_image.isNull():
         draw_rect = self._frame_image.rect()
         draw_rect.moveCenter(bounding_rect.center())
         painter.drawImage(draw_rect, self._frame_image, self._frame_image.rect())