Exemplo n.º 1
0
    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.painter = QPainter()

        # Origin coordinate.
        self.ox = self.width() / 2
        self.oy = self.height() / 2
        # Canvas zoom rate.
        self.rate = 2.
        self.zoom = 2. * self.rate
        # Joint size.
        self.joint_size = 3
        # Canvas line width.
        self.link_width = 3
        self.path_width = 3
        # Font size.
        self.font_size = 15
        # Show point mark or dimension.
        self.show_point_mark = True
        self.show_dimension = True
        # Path track.
        self.Path = _Path()
        # Path solving.
        self.target_path = {}
        self.show_target_path = False
        # Background
        self.background = QImage()
        self.background_opacity = 1.
        self.background_scale = 1
        self.background_offset = QPointF(0, 0)
Exemplo n.º 2
0
 def paintEvent(self, event):
     """Using a QPainter under 'self',
     so just change QPen or QBrush before painting.
     """
     self.painter = QPainter()
     self.painter.begin(self)
     self.painter.fillRect(event.rect(), QBrush(Qt.white))
     self.painter.translate(self.ox, self.oy)
     #Draw origin lines.
     pen = QPen(Qt.gray)
     pen.setWidth(1)
     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))
     #Draw tick.
     Indexing = lambda v: int(v/self.zoom - (v/self.zoom)%5)
     for x in range(Indexing(x_l), Indexing(x_r)+1, 5):
         self.painter.drawLine(
             QPointF(x*self.zoom, 0),
             QPointF(x*self.zoom, -10 if x%10==0 else -5)
         )
     for y in range(Indexing(y_b), Indexing(y_t)+1, 5):
         self.painter.drawLine(
             QPointF(0, y*self.zoom),
             QPointF(10 if y%10==0 else 5, y*self.zoom)
         )
     """Please to call the "end" method when ending paint event.
Exemplo n.º 3
0
 def Topologic_result_context_menu(self, point):
     """Context menu for the type synthesis results."""
     index = self.Topologic_result.currentIndex().row()
     self.add_collection.setEnabled(index>-1)
     self.copy_edges.setEnabled(index>-1)
     self.copy_image.setEnabled(index>-1)
     action = self.popMenu_topo.exec_(self.Topologic_result.mapToGlobal(point))
     if not action:
         return
     clipboard = QApplication.clipboard()
     if action==self.add_collection:
         self.addCollection(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(QColor(Qt.white).rgb())
         painter = QPainter(image2)
         painter.drawImage(QPointF(0, 0), image1)
         painter.end()
         pixmap = QPixmap()
         pixmap.convertFromImage(image2)
         clipboard.setPixmap(pixmap)
Exemplo n.º 4
0
 def on_save_atlas_clicked(self):
     """Save function as same as type synthesis widget."""
     count = self.collection_list.count()
     if not count:
         return
     lateral, ok = QInputDialog.getInt(self, "Atlas",
                                       "The number of lateral:", 5, 1, 10)
     if not ok:
         return
     fileName = self.outputTo("Atlas image", Qt_images)
     if not fileName:
         return
     icon_size = self.collection_list.iconSize()
     width = icon_size.width()
     image_main = QImage(
         QSize(lateral * width if count > lateral else count * width,
               ((count // lateral) + bool(count % lateral)) * width),
         self.collection_list.item(0).icon().pixmap(
             icon_size).toImage().format())
     image_main.fill(QColor(Qt.white).rgb())
     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 * width, row // lateral * width), image)
     painter.end()
     pixmap = QPixmap()
     pixmap.convertFromImage(image_main)
     pixmap.save(fileName, format=QFileInfo(fileName).suffix())
     self.saveReplyBox("Atlas", fileName)
Exemplo n.º 5
0
    def __save_atlas(self):
        """Save function as same as type synthesis widget."""
        count = self.collection_list.count()
        if not count:
            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_main = QImage(
            QSize(lateral * width if count > lateral else count * width,
                  ((count // lateral) + bool(count % lateral)) * width),
            self.collection_list.item(0).icon().pixmap(
                icon_size).toImage().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 * width, row // lateral * width), image)
        painter.end()
        pixmap = QPixmap()
        pixmap.convertFromImage(image_main)
        pixmap.save(file_name)
        self.save_reply_box("Atlas", file_name)
Exemplo n.º 6
0
    def __save_atlas(self):
        """Saving all the atlas to image file.

        We should turn transparent background to white first.
        Then using QImage class to merge into one image.
        """
        file_name = ""
        lateral = 0
        if self.save_edges_auto.isChecked():
            lateral, ok = QInputDialog.getInt(self, "Atlas",
                                              "The number of lateral:", 5, 1,
                                              10)
            if not ok:
                return
            file_name = self.outputTo("Atlas image", qt_image_format)
            if file_name:
                reply = QMessageBox.question(
                    self, "Type synthesis", "Do you want to Re-synthesis?",
                    (QMessageBox.Yes | QMessageBox.YesToAll
                     | QMessageBox.Cancel), QMessageBox.Yes)
                if reply == QMessageBox.Yes:
                    self.__structure_synthesis()
                elif reply == QMessageBox.YesToAll:
                    self.__structure_synthesis_all()
        count = self.structure_list.count()
        if not count:
            return
        if not lateral:
            lateral, ok = QInputDialog.getInt(self, "Atlas",
                                              "The number of lateral:", 5, 1,
                                              10)
            if not ok:
                return
        if not file_name:
            file_name = self.outputTo("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(QColor(Qt.white).rgb())
        painter = QPainter(image_main)
        for row in range(count):
            image = self.__atlas_image(row)
            painter.drawImage(
                QPointF(row % lateral * width, row // lateral * width), image)
        painter.end()
        pixmap = QPixmap()
        pixmap.convertFromImage(image_main)
        pixmap.save(file_name, format=QFileInfo(file_name).suffix())
        self.saveReplyBox("Atlas", file_name)
Exemplo n.º 7
0
def to_graph(graph: Graph,
             width: int,
             engine: Union[str, Dict[int, Tuple[float, float]]],
             node_mode: bool = False,
             except_node: int = None) -> QIcon:
    """Draw a generalized chain graph."""
    pos: Pos = engine_picker(graph, engine, node_mode)
    width_bound = -float('inf')
    for x, y in pos.values():
        if abs(x) > width_bound:
            width_bound = x
        if abs(y) > width_bound:
            width_bound = y
    width_bound *= 2.2
    image = QImage(QSize(int(width_bound), int(width_bound)),
                   QImage.Format_ARGB32_Premultiplied)
    image.fill(Qt.transparent)
    painter = QPainter(image)
    painter.translate(image.width() / 2, image.height() / 2)
    pen = QPen()
    r = width_bound / 50
    pen.setWidth(int(r))
    painter.setPen(pen)

    # Draw edges.
    if node_mode:
        for l1, l2 in graph.edges:
            if except_node in {l1, l2}:
                pen.setColor(color_qt('Gray'))
            else:
                pen.setColor(color_qt('Black'))
            painter.setPen(pen)

            painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]),
                             QPointF(pos[l2][0], -pos[l2][1]))
    else:
        painter.setBrush(QBrush(QColor(226, 219, 190, 150)))
        for link in graph.nodes:
            if link == except_node:
                pen.setColor(color_qt('Gray'))
            else:
                pen.setColor(color_qt('Black'))
            painter.setPen(pen)

            painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1])
                                              for n, edge in edges_view(graph)
                                              if link in edge],
                                             as_qpoint=True))

    # Draw nodes.
    for k, (x, y) in pos.items():
        if node_mode:
            color = color_num(len(list(graph.neighbors(k))) - 1)
            if k == except_node:
                color.setAlpha(150)
        else:
            if except_node in dict(edges_view(graph))[k]:
                color = color_qt('Green')
            else:
                color = color_qt('Blue')
        pen.setColor(color)
        painter.setPen(pen)
        painter.setBrush(QBrush(color))
        painter.drawEllipse(QPointF(x, -y), r, r)
    painter.end()
    icon = QIcon(QPixmap.fromImage(image).scaledToWidth(width))
    return icon
Exemplo n.º 8
0
def graph(G: Graph,
          width: int,
          engine: [str, Dict[int, Tuple[float, float]]],
          node_mode: bool = False,
          except_node: int = None) -> QIcon:
    """Draw a linkage graph."""
    try:
        pos = engine_picker(G, engine, node_mode)
    except EngineError as e:
        raise e
    width_ = -inf
    for x, y in pos.values():
        if abs(x) > width_:
            width_ = x
        if abs(y) > width_:
            width_ = y
    width_ *= 2 * 1.2
    image = QImage(QSize(width_, width_), QImage.Format_ARGB32_Premultiplied)
    image.fill(Qt.transparent)
    painter = QPainter(image)
    painter.translate(image.width() / 2, image.height() / 2)
    pen = QPen()
    r = width_ / 50
    pen.setWidth(r)
    painter.setPen(pen)
    if node_mode:
        for l1, l2 in G.edges:
            painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]),
                             QPointF(pos[l2][0], -pos[l2][1]))
    else:
        painter.setBrush(QBrush(QColor(226, 219, 190, 150)))
        for link in G.nodes:
            if link == except_node:
                continue
            #Distance sorted function from canvas
            painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1])
                                              for n, edge in edges_view(G)
                                              if link in edge]))
    for k, (x, y) in pos.items():
        if node_mode:
            color = colorNum(len(list(G.neighbors(k))) - 1)
        else:
            if except_node in tuple(G.edges)[k]:
                color = colorQt('Green')
            else:
                color = colorQt('Blue')
        pen.setColor(color)
        painter.setPen(pen)
        painter.setBrush(QBrush(color))
        painter.drawEllipse(QPointF(x, -y), r, r)
    painter.end()
    icon = QIcon(QPixmap.fromImage(image).scaledToWidth(width))
    return icon
Exemplo n.º 9
0
class BaseCanvas(QWidget):

    """The subclass can draw a blank canvas more easier."""

    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.painter = QPainter()

        # Origin coordinate.
        self.ox = self.width() / 2
        self.oy = self.height() / 2
        # Canvas zoom rate.
        self.rate = 2.
        self.zoom = 2. * self.rate
        # Joint size.
        self.joint_size = 3
        # Canvas line width.
        self.link_width = 3
        self.path_width = 3
        # Font size.
        self.font_size = 15
        # Show point mark or dimension.
        self.show_point_mark = True
        self.show_dimension = True
        # Path track.
        self.Path = _Path()
        # Path solving.
        self.target_path = {}
        self.show_target_path = False
        # Background
        self.background = QImage()
        self.background_opacity = 1.
        self.background_scale = 1
        self.background_offset = QPointF(0, 0)

    def paintEvent(self, event):
        """Using a QPainter under 'self',
        so just change QPen or QBrush before painting.
        """
        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)
            img_origin: QPointF = self.background_offset * self.zoom
            self.painter.drawImage(
                QRectF(img_origin, QSizeF(
                    rect.width() * self.background_scale * self.zoom,
                    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.
        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):
            """Draw tick."""
            return int(v / self.zoom - v / self.zoom % 5)

        for x in range(indexing(x_l), indexing(x_r) + 1, 5):
            self.painter.drawLine(
                QPointF(x, 0) * self.zoom,
                QPointF(x * self.zoom, -10 if x % 10 == 0 else -5)
            )
        for y in range(indexing(y_b), indexing(y_t) + 1, 5):
            self.painter.drawLine(
                QPointF(0, y) * self.zoom,
                QPointF(10 if y % 10 == 0 else 5, y * self.zoom)
            )
        # Please to call the "end" method when ending paint event.
        # self.painter.end()

    def drawPoint(
        self,
        i: int,
        cx,
        cy,
        fix: bool,
        color: QColor
    ):
        """Draw a joint."""
        pen = QPen(color)
        pen.setWidth(2)
        self.painter.setPen(pen)
        x = cx * self.zoom
        y = cy * -self.zoom
        if fix:
            bottom = y + 20
            width = 10
            # Draw a triangle below.
            self.painter.drawPolygon(
                QPointF(x, y),
                QPointF(x - width, bottom),
                QPointF(x + width, bottom)
            )
            r = self.joint_size * 2
        else:
            r = self.joint_size
        self.painter.drawEllipse(QPointF(x, y), r, r)

        if not self.show_point_mark:
            return
        pen.setColor(Qt.darkGray)
        pen.setWidth(2)
        self.painter.setPen(pen)
        text = f"[{i}]" if type(i) == str else f"[Point{i}]"
        if self.show_dimension:
            text += f":({cx:.02f}, {cy:.02f})"
        self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text)

    def drawTargetPath(self):
        """Draw solving path."""
        pen = QPen()
        pen.setWidth(self.path_width)
        for i, name in enumerate(sorted(self.target_path)):
            path = self.target_path[name]
            road, dot, brush = target_path_style(i)
            pen.setColor(road)
            self.painter.setPen(pen)
            self.painter.setBrush(brush)
            if len(path) == 1:
                x, y = path[0]
                p = QPointF(x, -y) * self.zoom
                self.painter.drawText(p + QPointF(6, -6), name)
                pen.setColor(dot)
                self.painter.setPen(pen)
                self.painter.drawEllipse(p, self.joint_size, self.joint_size)
            else:
                painter_path = QPainterPath()
                for j, (x, y) in enumerate(path):
                    p = QPointF(x, -y) * self.zoom
                    self.painter.drawEllipse(p, self.joint_size, self.joint_size)
                    if j == 0:
                        self.painter.drawText(p + QPointF(6, -6), name)
                        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(road)
                self.painter.setPen(pen)
                self.painter.drawPath(painter_path)
                for x, y in path:
                    pen.setColor(dot)
                    self.painter.setPen(pen)
                    p = QPointF(x, -y) * self.zoom
                    self.painter.drawEllipse(p, self.joint_size, 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 = ''
    ):
        """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 drawCurve(self, path: Sequence[Tuple[float, float]]):
        """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:
                x *= self.zoom
                y *= -self.zoom
                if i == 0:
                    painter_path.moveTo(x, y)
                    self.painter.drawEllipse(QPointF(x, y), self.joint_size, self.joint_size)
                    continue
                if error:
                    painter_path.moveTo(x, y)
                    error = False
                else:
                    painter_path.lineTo(x, y)
        self.painter.drawPath(painter_path)

    def drawDot(self, path: Sequence[Tuple[float, float]]):
        """Draw path as dots."""
        if len(set(path)) <= 2:
            return
        for x, y in path:
            if isnan(x):
                continue
            self.painter.drawPoint(QPointF(x, -y) * self.zoom)

    def solutionPolygon(
        self,
        func: str,
        args: Sequence[str],
        target: str,
        pos: Union[Tuple[VPoint, ...], Dict[int, Tuple[float, float]]]
    ) -> 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:
                x, y = pos[index]
                tmp_list.append(QPointF(x, -y) * self.zoom)
        return tmp_list, color

    def drawSolution(
        self,
        func: str,
        args: Sequence[str],
        target: str,
        pos: Union[Tuple[VPoint, ...], Dict[int, Tuple[float, float]]]
    ):
        """Draw the solution triangle."""
        points, color = self.solutionPolygon(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):
            """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)
Exemplo n.º 10
0
class BaseCanvas(QWidget):
    
    """The subclass can draw a blank canvas more easier."""
    
    def __init__(self, parent=None):
        super(BaseCanvas, self).__init__(parent)
        self.setSizePolicy(QSizePolicy(
            QSizePolicy.Expanding,
            QSizePolicy.Expanding
        ))
        #Origin coordinate.
        self.ox = self.width()/2
        self.oy = self.height()/2
        #Canvas zoom rate.
        self.rate = 2
        self.zoom = 2 * self.rate
        #Canvas line width.
        self.linkWidth = 3
        self.pathWidth = 3
        #Font size.
        self.fontSize = 10
        #Show point mark or dimension.
        self.showPointMark = True
        self.showDimension = True
        #Path track.
        self.Path = Path()
        #Path solving.
        self.targetPath = {}
        self.showTargetPath = False
    
    def paintEvent(self, event):
        """Using a QPainter under 'self',
        so just change QPen or QBrush before painting.
        """
        self.painter = QPainter()
        self.painter.begin(self)
        self.painter.fillRect(event.rect(), QBrush(Qt.white))
        self.painter.translate(self.ox, self.oy)
        #Draw origin lines.
        pen = QPen(Qt.gray)
        pen.setWidth(1)
        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))
        #Draw tick.
        Indexing = lambda v: int(v/self.zoom - (v/self.zoom)%5)
        for x in range(Indexing(x_l), Indexing(x_r)+1, 5):
            self.painter.drawLine(
                QPointF(x*self.zoom, 0),
                QPointF(x*self.zoom, -10 if x%10==0 else -5)
            )
        for y in range(Indexing(y_b), Indexing(y_t)+1, 5):
            self.painter.drawLine(
                QPointF(0, y*self.zoom),
                QPointF(10 if y%10==0 else 5, y*self.zoom)
            )
        """Please to call the "end" method when ending paint event.
        
        self.painter.end()
        """
    
    def drawFrame(self):
        """Draw a outer frame."""
        positive_x = self.width() - self.ox
        positive_y = -self.oy
        negative_x = -self.ox
        negative_y = self.height() - self.oy
        self.painter.drawLine(
            QPointF(negative_x, positive_y),
            QPointF(positive_x, positive_y)
        )
        self.painter.drawLine(
            QPointF(negative_x, negative_y),
            QPointF(positive_x, negative_y)
        )
        self.painter.drawLine(
            QPointF(negative_x, positive_y),
            QPointF(negative_x, negative_y)
        )
        self.painter.drawLine(
            QPointF(positive_x, positive_y),
            QPointF(positive_x, negative_y)
        )
    
    def drawPoint(self,
        i: int,
        cx,
        cy,
        fix: bool,
        color: QColor
    ):
        """Draw a joint."""
        pen = QPen(color)
        pen.setWidth(2)
        self.painter.setPen(pen)
        x = cx*self.zoom
        y = cy*-self.zoom
        if fix:
            bottom = y + 20
            width = 10
            #Draw a triangle below.
            self.painter.drawPolygon(
                QPointF(x, y),
                QPointF(x - width, bottom),
                QPointF(x + width, bottom)
            )
            self.painter.drawEllipse(QPointF(x, y), width, width)
        else:
            self.painter.drawEllipse(QPointF(x, y), 5, 5)
        if not self.showPointMark:
            return
        pen.setColor(Qt.darkGray)
        pen.setWidth(2)
        self.painter.setPen(pen)
        self.painter.setFont(QFont("Arial", self.fontSize))
        text = "[{}]".format(i) if type(i)==str else "[Point{}]".format(i)
        if self.showDimension:
            text += ":({:.02f}, {:.02f})".format(cx, cy)
        self.painter.drawText(QPointF(x+6, y-6), text)
    
    def drawTargetPath(self):
        """Draw solving path."""
        pen = QPen()
        pen.setWidth(self.pathWidth)
        for i, name in enumerate(sorted(self.targetPath)):
            path = self.targetPath[name]
            Pen, Dot, Brush = colorPath(i)
            pen.setColor(Pen)
            self.painter.setPen(pen)
            self.painter.setBrush(Brush)
            if len(path)>1:
                pointPath = QPainterPath()
                for i, (x, y) in enumerate(path):
                    x *= self.zoom
                    y *= -self.zoom
                    self.painter.drawEllipse(QPointF(x, y), 4, 4)
                    if i==0:
                        self.painter.drawText(QPointF(x+6, y-6), name)
                        pointPath.moveTo(x, y)
                    else:
                        x2, y2 = path[i-1]
                        self.drawArrow(x, y, x2*self.zoom, y2*-self.zoom)
                        pointPath.lineTo(QPointF(x, y))
                self.painter.drawPath(pointPath)
                for x, y in path:
                    pen.setColor(Dot)
                    self.painter.setPen(pen)
                    self.painter.drawEllipse(
                        QPointF(x*self.zoom, y*-self.zoom), 3, 3
                    )
            elif len(path)==1:
                x = path[0][0]*self.zoom
                y = path[0][1]*-self.zoom
                self.painter.drawText(QPointF(x+6, y-6), name)
                pen.setColor(Dot)
                self.painter.setPen(pen)
                self.painter.drawEllipse(QPointF(x, y), 3, 3)
        self.painter.setBrush(Qt.NoBrush)
    
    def drawArrow(self, x1: float, y1: float, x2: float, y2: float):
        """Front point -> Back point"""
        a = atan2(y2 - y1, x2 - x1)
        x1 = (x1 + x2) / 2 - 7.5*cos(a)
        y1 = (y1 + y2) / 2 - 7.5*sin(a)
        self.painter.drawLine(
            QPointF(x1, y1),
            QPointF(x1 + 15*cos(a + radians(20)), y1 + 15*sin(a + radians(20)))
        )
        self.painter.drawLine(
            QPointF(x1, y1),
            QPointF(x1 + 15*cos(a - radians(20)), y1 + 15*sin(a - radians(20)))
        )
    
    def drawCurve(self, path):
        pointPath = QPainterPath()
        for i, (x, y) in enumerate(path):
            if isnan(x):
                continue
            else:
                if i==0:
                    pointPath.moveTo(x*self.zoom, y*-self.zoom)
                else:
                    pointPath.lineTo(QPointF(x*self.zoom, y*-self.zoom))
        self.painter.drawPath(pointPath)
    
    def drawDot(self, path):
        for x, y in path:
            if isnan(x):
                continue
            else:
                self.painter.drawPoint(QPointF(x*self.zoom, y*-self.zoom))
Exemplo n.º 11
0
def to_graph(
    g: Graph,
    width: int,
    engine: Union[str, Pos],
    node_mode: bool,
    show_label: bool,
    monochrome: bool,
    *,
    except_node: Optional[int] = None
) -> QIcon:
    """Draw a generalized chain graph."""
    pos: Pos = engine_picker(g, engine, node_mode)
    if not pos:
        pixmap = QPixmap(width, width)
        pixmap.fill(Qt.transparent)
        return QIcon(pixmap)

    width_bound = -float('inf')
    for x, y in pos.values():
        if abs(x) > width_bound:
            width_bound = x
        if abs(y) > width_bound:
            width_bound = y
    width_bound *= 2.5
    image = QImage(
        QSize(int(width_bound), int(width_bound)),
        QImage.Format_ARGB32_Premultiplied
    )
    image.fill(Qt.transparent)
    painter = QPainter(image)
    painter.translate(image.width() / 2, image.height() / 2)
    pen = QPen()
    r = int(width_bound / 50)
    pen.setWidth(r)
    painter.setPen(pen)
    _font.setPixelSize(r * 6)
    painter.setFont(_font)

    # Draw edges.
    if node_mode:
        for l1, l2 in g.edges:
            if except_node in {l1, l2}:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawLine(
                QPointF(pos[l1][0], -pos[l1][1]),
                QPointF(pos[l2][0], -pos[l2][1])
            )
    else:
        if monochrome:
            color = QColor(Qt.darkGray)
        else:
            color = QColor(226, 219, 190)
        color.setAlpha(150)
        painter.setBrush(QBrush(color))
        for link in g.nodes:
            if link == except_node:
                pen.setColor(Qt.gray)
            else:
                pen.setColor(Qt.black)
            painter.setPen(pen)

            painter.drawPolygon(*convex_hull([
                (pos[n][0], -pos[n][1])
                for n, edge in edges_view(g) if link in edge
            ], as_qpoint=True))

    # Draw nodes.
    for k, (x, y) in pos.items():
        if node_mode:
            color = color_num(len(list(g.neighbors(k))) - 1)
            if k == except_node:
                color.setAlpha(150)
        else:
            if monochrome:
                color = Qt.black
            elif except_node in dict(edges_view(g))[k]:
                color = color_qt('Green')
            else:
                color = color_qt('Blue')
        pen.setColor(color)
        painter.setPen(pen)
        painter.setBrush(QBrush(color))
        point = QPointF(x, -y)
        painter.drawEllipse(point, r, r)
        if show_label:
            pen.setColor(Qt.darkMagenta)
            painter.setPen(pen)
            painter.drawText(point, str(k))
    painter.end()
    return QIcon(QPixmap.fromImage(image).scaledToWidth(width))
Exemplo n.º 12
0
class BaseCanvas(QWidget):
    """The subclass can draw a blank canvas more easier."""
    def __init__(self, parent=None):
        super(BaseCanvas, self).__init__(parent)
        self.setSizePolicy(
            QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
        #Origin coordinate.
        self.ox = self.width() / 2
        self.oy = self.height() / 2
        #Canvas zoom rate.
        self.rate = 2
        self.zoom = 2 * self.rate
        #Joint size.
        self.jointsize = 5
        #Canvas line width.
        self.linkWidth = 3
        self.pathWidth = 3
        #Font size.
        self.fontSize = 15
        #Show point mark or dimension.
        self.showPointMark = True
        self.showDimension = True
        #Path track.
        self.Path = Path()
        #Path solving.
        self.targetPath = {}
        self.showTargetPath = False

    def paintEvent(self, event):
        """Using a QPainter under 'self',
        so just change QPen or QBrush before painting.
        """
        self.painter = QPainter()
        self.painter.begin(self)
        self.painter.fillRect(event.rect(), QBrush(Qt.white))
        self.painter.translate(self.ox, self.oy)
        #Draw origin lines.
        pen = QPen(Qt.gray)
        pen.setWidth(1)
        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))
        #Draw tick.
        Indexing = lambda v: int(v / self.zoom - (v / self.zoom) % 5)
        for x in range(Indexing(x_l), Indexing(x_r) + 1, 5):
            self.painter.drawLine(
                QPointF(x * self.zoom, 0),
                QPointF(x * self.zoom, -10 if x % 10 == 0 else -5))
        for y in range(Indexing(y_b), Indexing(y_t) + 1, 5):
            self.painter.drawLine(
                QPointF(0, y * self.zoom),
                QPointF(10 if y % 10 == 0 else 5, y * self.zoom))
        """Please to call the "end" method when ending paint event.
        
        self.painter.end()
        """

    def __drawPoint(self, i: int, cx, cy, fix: bool, color: QColor):
        """Draw a joint."""
        pen = QPen(color)
        pen.setWidth(2)
        self.painter.setPen(pen)
        x = cx * self.zoom
        y = cy * -self.zoom
        if fix:
            bottom = y + 20
            width = 10
            #Draw a triangle below.
            self.painter.drawPolygon(QPointF(x, y), QPointF(x - width, bottom),
                                     QPointF(x + width, bottom))
            self.painter.drawEllipse(QPointF(x, y), width, width)
        else:
            self.painter.drawEllipse(QPointF(x, y), self.jointsize,
                                     self.jointsize)
        if not self.showPointMark:
            return
        pen.setColor(Qt.darkGray)
        pen.setWidth(2)
        self.painter.setPen(pen)
        self.painter.setFont(QFont("Arial", self.fontSize))
        text = "[{}]".format(i) if type(i) == str else "[Point{}]".format(i)
        if self.showDimension:
            text += ":({:.02f}, {:.02f})".format(cx, cy)
        self.painter.drawText(QPointF(x + 6, y - 6), text)

    def __drawTargetPath(self):
        """Draw solving path."""
        pen = QPen()
        pen.setWidth(self.pathWidth)
        for i, name in enumerate(sorted(self.targetPath)):
            path = self.targetPath[name]
            Pen, Dot, Brush = colorPath(i)
            pen.setColor(Pen)
            self.painter.setPen(pen)
            self.painter.setBrush(Brush)
            if len(path) > 1:
                pointPath = QPainterPath()
                for j, (x, y) in enumerate(path):
                    x *= self.zoom
                    y *= -self.zoom
                    self.painter.drawEllipse(QPointF(x, y), RADIUS, RADIUS)
                    if j == 0:
                        self.painter.drawText(QPointF(x + 6, y - 6), name)
                        pointPath.moveTo(x, y)
                    else:
                        x2, y2 = path[j - 1]
                        self.__drawArrow(x, y, x2 * self.zoom, y2 * -self.zoom)
                        pointPath.lineTo(QPointF(x, y))
                self.painter.drawPath(pointPath)
                for x, y in path:
                    pen.setColor(Dot)
                    self.painter.setPen(pen)
                    self.painter.drawEllipse(
                        QPointF(x * self.zoom, y * -self.zoom), RADIUS, RADIUS)
            elif len(path) == 1:
                x = path[0][0] * self.zoom
                y = path[0][1] * -self.zoom
                self.painter.drawText(QPointF(x + 6, y - 6), name)
                pen.setColor(Dot)
                self.painter.setPen(pen)
                self.painter.drawEllipse(QPointF(x, y), RADIUS, RADIUS)
        self.painter.setBrush(Qt.NoBrush)

    def __drawArrow(self, x1: float, y1: float, x2: float, y2: float):
        """Front point -> Back point"""
        a = atan2(y2 - y1, x2 - x1)
        x1 = (x1 + x2) / 2 - 7.5 * cos(a)
        y1 = (y1 + y2) / 2 - 7.5 * sin(a)
        self.painter.drawLine(
            QPointF(x1, y1),
            QPointF(x1 + 15 * cos(a + radians(20)),
                    y1 + 15 * sin(a + radians(20))))
        self.painter.drawLine(
            QPointF(x1, y1),
            QPointF(x1 + 15 * cos(a - radians(20)),
                    y1 + 15 * sin(a - radians(20))))

    def __drawCurve(self, path: Sequence[Tuple[float, float]]):
        """Draw path as curve."""
        pointPath = QPainterPath()
        error = False
        for i, (x, y) in enumerate(path):
            if isnan(x):
                error = True
                self.painter.drawPath(pointPath)
                pointPath = QPainterPath()
            else:
                x *= self.zoom
                y *= -self.zoom
                if i == 0:
                    pointPath.moveTo(x, y)
                    self.painter.drawEllipse(QPointF(x, y), RADIUS, RADIUS)
                    continue
                if error:
                    pointPath.moveTo(x, y)
                    error = False
                else:
                    pointPath.lineTo(x, y)
        self.painter.drawPath(pointPath)

    def __drawDot(self, path: Sequence[Tuple[float, float]]):
        """Draw path as dots."""
        for x, y in path:
            if isnan(x):
                continue
            self.painter.drawPoint(QPointF(x * self.zoom, y * -self.zoom))

    def __drawSolution(self, func: str, args: Tuple[str], target: str,
                       pos: TypeVar('Coords', Tuple[VPoint],
                                    Dict[int, Tuple[float, float]])):
        """Draw the solution triangle."""
        if func == 'PLLP':
            color = QColor(121, 171, 252)
            params = [args[0], args[-1]]
        elif func == 'PLAP':
            color = QColor(249, 84, 216)
            params = [args[0]]
        elif func == 'PLPP':
            color = QColor(94, 255, 185)
            params = [args[0]]
        params.append(target)
        pen = QPen()
        pen.setColor(color)
        pen.setWidth(RADIUS)
        self.painter.setPen(pen)

        def drawArrow(n: int) -> bool:
            """Draw arrow and return True if done."""
            try:
                x, y = pos[int(params[-1].replace('P', ''))]
                x2, y2 = pos[int(params[n].replace('P', ''))]
            except ValueError:
                return False
            else:
                self.__drawArrow(x * self.zoom, y * -self.zoom, x2 * self.zoom,
                                 y2 * -self.zoom)
                return True

        if not drawArrow(0):
            return
        if func == 'PLLP':
            if not drawArrow(1):
                return
        color.setAlpha(30)
        self.painter.setBrush(QBrush(color))
        qpoints = []
        for name in params:
            x, y = pos[int(name.replace('P', ''))]
            qpoints.append(QPointF(x * self.zoom, y * -self.zoom))
        self.painter.drawPolygon(*qpoints)
        self.painter.setBrush(Qt.NoBrush)
Exemplo n.º 13
0
    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        painter.fillRect(event.rect(), QBrush(Qt.white))
        painter.translate(self.width() / 2, self.height() / 2)

        if not self.parama['profile']:
            painter.end()
            return

        pen = QPen()

        # center circle
        pen.setColor(Qt.red)
        pen.setWidth(3)
        pen.setStyle(Qt.SolidLine)
        painter.setPen(pen)
        r = 10
        painter.drawEllipse(QPointF(0, 0), r, r)

        # Base circle
        if self.show_base:
            pen.setColor(Qt.cyan)
            pen.setWidth(3)
            pen.setStyle(Qt.DashLine)
            painter.setPen(pen)
            r = self.parama['rb'] * self.parama['rate']
            painter.drawEllipse(QPointF(0, 0), r, r)

        # rotate
        rotate = QTransform()
        rotate.translate(0, 0)
        rotate.rotate(self.rotate)

        # profile
        pen.setColor(Qt.blue)
        pen.setWidth(5)
        pen.setStyle(Qt.SolidLine)
        painter.setPen(pen)
        path_profile = QPainterPath()
        path_profile.moveTo(
            QPoint(self.parama['profile'][0]['Rx'] * self.parama['rate'],
                   self.parama['profile'][0]['Ry'] * self.parama['rate']))
        for i in range(len(self.parama['profile'])):
            e = self.parama['profile'][i]
            x = e['Rx'] * self.parama['rate']
            y = e['Ry'] * self.parama['rate']
            path_profile.lineTo(QPointF(x, y))
        painter.drawPath(rotate.map(path_profile))
        # route
        if self.show_cutter_route:
            pen.setColor(Qt.green)
            pen.setWidth(3)
            pen.setStyle(Qt.DashLine)
            painter.setPen(pen)
            painterpath_route = QPainterPath()
            painterpath_route.moveTo(
                QPoint(
                    self.parama['cutter_route'][0]['Rx'] * self.parama['rate'],
                    self.parama['cutter_route'][0]['Ry'] *
                    self.parama['rate']))
            for i in range(len(self.parama['cutter_route']) - self.rotate):
                e = self.parama['cutter_route'][i]
                x = e['Rx'] * self.parama['rate']
                y = e['Ry'] * self.parama['rate']
                painterpath_route.lineTo(QPointF(x, y))
            painter.drawPath(rotate.map(painterpath_route))
        # roll
        pen.setColor(Qt.darkGray)
        pen.setWidth(3)
        pen.setStyle(Qt.SolidLine)
        painter.setPen(pen)
        r = self.parama['rc'] * self.parama['rate']
        last_point = QPointF(
            self.parama['cutter_route'][-self.rotate]['Rx'] *
            self.parama['rate'],
            self.parama['cutter_route'][-self.rotate]['Ry'] *
            self.parama['rate'])
        path_roll = QPainterPath()
        path_roll.addEllipse(last_point, r, r)
        painter.drawPath(rotate.map(path_roll))
        painter.end()