示例#1
0
    def _draw_edges(self, painter, topleft_point, bottomright_point):
        for edge in self._edges:
            edge_coords = edge.coordinates

            color = QColor(0x70, 0x70, 0x70)
            pen = QPen(color)
            pen.setWidth(1.5)
            painter.setPen(pen)

            for from_, to_ in zip(edge_coords, edge_coords[1:]):
                start_point = QPointF(*from_)
                end_point = QPointF(*to_)
                # optimization: don't draw edges that are outside of the current scope
                if (start_point.x() > bottomright_point.x() or start_point.y() > bottomright_point.y()) and \
                        (end_point.x() > bottomright_point.x() or end_point.y() > bottomright_point.y()):
                    continue
                elif (start_point.x() < topleft_point.x() or start_point.y() < topleft_point.y()) and \
                        (end_point.x() < topleft_point.x() or end_point.y() < topleft_point.y()):
                    continue
                painter.drawPolyline((start_point, end_point))

            # arrow
            # end_point = self.mapToScene(*edges[-1])
            end_point = (edge_coords[-1][0], edge_coords[-1][1])
            arrow = [
                QPointF(end_point[0] - 3, end_point[1]),
                QPointF(end_point[0] + 3, end_point[1]),
                QPointF(end_point[0], end_point[1] + 6)
            ]
            brush = QBrush(color)
            painter.setBrush(brush)
            painter.drawPolygon(arrow)
示例#2
0
 def mouseMoveEvent(self, event):
     """
     Mouse move event handler
     @param event:
     @type event:
     """
     modifiers = QApplication.keyboardModifiers()
     # mouse coordinates, relative to parent widget
     pos = self.mapToParent(event.pos())
     img = self.tool.layer.parentImage
     r = self.tool.resizingCoeff
     self.tool.targetQuad_old = self.tool.getTargetQuad(
     )  # TODO added 15/05/18 validate
     self.posRelImg = (pos - QPoint(img.xOffset, img.yOffset)) / r
     if modifiers == Qt.ControlModifier | Qt.AltModifier:
         if self.tool.isModified():
             dlgWarn("A transformation is in progress", "Reset first")
             return
         # update the new starting  position
         self.posRelImg_ori = self.posRelImg  # (pos - QPoint(img.xOffset, img.yOffset)) / r
         self.posRelImg_frozen = self.posRelImg
         self.tool.moveRotatingTool()
         self.tool.parent().repaint()
         return
     curimg = self.tool.layer.getCurrentImage()
     w, h = curimg.width(), curimg.height()
     s = w / self.tool.img.width()
     form = self.tool.getForm()
     if form.options['Free']:
         pass
     elif form.options['Rotation']:
         center = self.tool.getTargetQuad().boundingRect().center()
         v = QPointF(self.posRelImg.x() - center.x(),
                     self.posRelImg.y() - center.y())
         v0 = QPointF(self.posRelImg_frozen.x() - center.x(),
                      self.posRelImg_frozen.y() - center.y())
         theta = (np.arctan2(v.y(), v.x()) -
                  np.arctan2(v0.y(), v0.x())) * 180.0 / np.pi
         T = QTransform()  # self.tool.geoTrans_ori)
         T.translate(center.x(), center.y()).rotate(theta).translate(
             -center.x(), -center.y())
         q = T.map(self.tool.getFrozenQuad())
         for i, role in enumerate(
             ['topLeft', 'topRight', 'bottomRight', 'bottomLeft']):
             self.tool.btnDict[role].posRelImg = q.at(i)
     elif form.options['Translation']:
         # translation vector (coordinates are relative to the full size image)
         p = QPointF(self.posRelImg) - QPointF(self.posRelImg_frozen)
         T = QTransform()
         T.translate(p.x(), p.y())
         q = T.map(self.tool.getFrozenQuad())
         for i, role in enumerate(
             ['topLeft', 'topRight', 'bottomRight', 'bottomLeft']):
             self.tool.btnDict[role].posRelImg = q.at(i)
     self.tool.moveRotatingTool()
     self.tool.modified = True
     self.tool.layer.applyToStack()
     self.parent().repaint()
示例#3
0
    def _draw_edges(self, painter, topleft_point, bottomright_point):

        # draw edges
        if self._edges:
            for edge in self._edges:
                edge_coords = edge.coordinates

                if edge.sort == EdgeSort.BACK_EDGE:
                    # it's a back edge
                    # Honey
                    color = QColor(0xf9, 0xd5, 0x77)
                elif edge.sort == EdgeSort.TRUE_BRANCH:
                    # True branch
                    # Aqar
                    color = QColor(0x79, 0xcc, 0xcd)
                elif edge.sort == EdgeSort.FALSE_BRANCH:
                    # False branch
                    # Tomato
                    color = QColor(0xf1, 0x66, 0x64)
                else:
                    # Dark Gray
                    color = QColor(0x56, 0x5a, 0x5c)
                pen = QPen(color)
                pen.setWidth(2)
                painter.setPen(pen)

                for from_, to_ in zip(edge_coords, edge_coords[1:]):
                    start_point = QPointF(*from_)
                    end_point = QPointF(*to_)
                    # optimization: don't draw edges that are outside of the current scope
                    if (start_point.x() > bottomright_point.x() or start_point.y() > bottomright_point.y()) and \
                            (end_point.x() > bottomright_point.x() or end_point.y() > bottomright_point.y()):
                        continue
                    elif (start_point.x() < topleft_point.x() or start_point.y() < topleft_point.y()) and \
                            (end_point.x() < topleft_point.x() or end_point.y() < topleft_point.y()):
                        continue
                    painter.drawPolyline((start_point, end_point))

                # arrow
                # end_point = self.mapToScene(*edges[-1])
                end_point = (edge_coords[-1][0], edge_coords[-1][1])
                arrow = [
                    QPointF(end_point[0] - 3, end_point[1]),
                    QPointF(end_point[0] + 3, end_point[1]),
                    QPointF(end_point[0], end_point[1] + 6)
                ]
                brush = QBrush(color)
                painter.setBrush(brush)
                painter.drawPolygon(arrow)
    def __init__(self, center: QPointF):
        super(BezierGraphicsItem, self).__init__()
        self.setCursor(Qt.ArrowCursor)
        self.setZValue(-1)
        self.setFlags(QGraphicsItem.ItemIsMovable
                      | QGraphicsItem.ItemIsSelectable
                      | QGraphicsItem.ItemIsFocusable)
        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
        self._m_radius = float(0)
        self._m_centerPos = center
        self._m_textPos = QPointF(center.x() - 7, center.y() - 30)
        self._m_pointList = BezierPointItemList()

        self._m_pen_isSelected = QPen()
        self._m_pen_noSelected = QPen()

        self._m_noSelectedThickness = 2
        self._m_isSelectedThickness = 2

        self._m_pen_noSelectedColor = QColor(Qt.gray)
        self._m_pen_isSelectedColor = QColor(Qt.blue)

        self._m_pen_isSelected.setColor(self._m_pen_isSelectedColor)
        self._m_pen_noSelected.setColor(self._m_pen_noSelectedColor)

        self._m_pen_isSelected.setWidth(self._m_isSelectedThickness)
        self._m_pen_noSelected.setWidth(self._m_noSelectedThickness)
        self._m_graphicsType = GraphicsType.NoneType

        self.setPen(self._m_pen_noSelected)
示例#5
0
    def move_selected_copmonents__cmd(self, x, y):
        new_rel_pos = QPointF(x, y)

        # if one node item would leave the scene (f.ex. pos.x < 0), stop
        left = False
        for i in self.scene().selectedItems():
            new_pos = i.pos() + new_rel_pos
            if new_pos.x() - i.width / 2 < 0 or \
                    new_pos.x() + i.width / 2 > self.scene().width() or \
                    new_pos.y() - i.height / 2 < 0 or \
                    new_pos.y() + i.height / 2 > self.scene().height():
                left = True
                break

        if not left:
            # moving the items
            items_group = self.scene().createItemGroup(
                self.scene().selectedItems())
            items_group.moveBy(new_rel_pos.x(), new_rel_pos.y())
            self.scene().destroyItemGroup(items_group)

            # saving the command
            self.undo_stack.push(
                MoveComponents_Command(self,
                                       self.scene().selectedItems(),
                                       p_from=-new_rel_pos,
                                       p_to=QPointF(0, 0)))

        self.viewport().repaint()
示例#6
0
    def edgeAt(self, pos: QtCore.QPointF) -> Optional[str]:
        view = next(iter(self.scene().views()))
        dist = view.mapToScene(QtCore.QRect(0, 0, self.cursor_dist, 1)).boundingRect().width()

        edge = ""
        if abs(self.rect().top() - pos.y()) < dist:
            edge += "top"
        elif abs(self.rect().bottom() - pos.y()) < dist:
            edge += "bottom"
        if abs(self.rect().left() - pos.x()) < dist:
            edge += "left"
        elif abs(self.rect().right() - pos.x()) < dist:
            edge += "right"
        if edge == "":
            return None
        return edge
示例#7
0
def draw_text(painter: QPainter, x: float, y: float, flags, text: str):
    # Originally from
    # https://stackoverflow.com/questions/24831484/how-to-align-qpainter-drawtext-around-a-point-not-a-rectangle
    size = 32767.0
    corner = QPointF(x, y - size)
    if flags & Qt.AlignHCenter:
        corner.setX(corner.x() - size / 2.0)
    elif flags & Qt.AlignRight:
        corner.setX(corner.x() - size)
    if flags & Qt.AlignVCenter:
        corner.setY(corner.y() + size / 2.0)
    elif flags & Qt.AlignTop:
        corner.setY(corner.y() + size)
    else:
        flags |= Qt.AlignBottom
    rect = QRectF(corner.x(), corner.y(), size, size)
    painter.drawText(rect, int(flags), text)
示例#8
0
文件: drift.py 项目: djdt/pewpew
    def edgeAt(self, pos: QtCore.QPointF) -> Optional[str]:
        view = next(iter(self.scene().views()), None)
        if view is None:
            return None
        dist = (view.mapToScene(QtCore.QRect(0, 0, 10,
                                             1)).boundingRect().width())

        if abs(self.rect().left() - pos.x()) < dist:
            return "left"
        elif abs(self.rect().right() - pos.x()) < dist:
            return "right"
        elif abs(pos.y() - self.top) < dist:
            return "top" if self.trim_enabled else None
        elif abs(pos.y() - self.bottom) < dist:
            return "bottom" if self.trim_enabled else None
        else:
            return None
示例#9
0
 def mousePressEvent(self, e):
     self.clicked = True
     xt, yt = e.pos().x(), e.pos().y()
     p = QPointF(xt, yt)
     self.moving = None
     for p in [self.A, self.B, self.C]:
         if abs(xt - p.x()) + abs(yt - p.y()) < 15:
             self.moving = p
             break
 def drawText(self, painter, flags, text, boundingRect=0):
     size = 32767.0
     x, y = self.boundingRect().center()
     corner = QPointF(x, y - size)
     if flags & Qt.AlignHCenter:
         corner.setX(corner.x() - size / 2.0)
     elif flags & Qt.AlignRight:
         corner.setX(corner.x() - size)
     if flags & Qt.AlignVCenter:
         corner.setY(corner.y() + size / 2.0)
     elif flags & Qt.AlignTop:
         corner.setY(corner.y() + size)
     else:
         flags |= Qt.AlignBottom
     rect = QRectF(corner.x(), corner.y(), size, size)
     pen = painter.setPen(painter.brush().color().inverse())
     painter.save()
     painter.drawText(rect, flags, text, boundingRect)
     painter.restore()
示例#11
0
    def _add_points_for_line(self, start: QPointF, stop: QPointF):
        start_points = self._rect_for_point(start)
        stop_points = self._rect_for_point(stop)

        point_list = []

        if start.y() == stop.y():
            point_list.extend([
                start_points[0], stop_points[1], stop_points[2],
                start_points[3]
            ])
        elif start.y() < stop.y():
            point_list.extend(start_points[0:2])
            point_list.extend(stop_points[1:4])
            point_list.append(start_points[3])
        else:
            point_list.append(start_points[0])
            point_list.extend(stop_points[0:3])
            point_list.extend(start_points[2:4])

        self.screen_polygon = self.screen_polygon.united(
            QPolygonF.fromList(point_list))
示例#12
0
    def paint(self, painter, option, widget):
        pen = QPen(Qt.black, 1)
        if self._hover:
            pen.setColor(Qt.blue)
        if self.isSelected():
            pen.setColor(Qt.red)
            pen.setWidth(2)

        painter.setPen(pen)
        painter.drawEllipse(self.boundingRect())
        if self.state_type == StateType.FINAL:
            painter.drawEllipse(self.boundingRect().adjusted(7, 7, -7, -7))
        elif self.state_type == StateType.INITIAL:
            center = QPointF(self.boundingRect().center())
            center.setX(center.x() - (self.boundingRect().height() * 0.3))
            up = QPointF(self.boundingRect().topLeft())
            up.setY(up.y() + (self.boundingRect().height() * 0.3))
            down = QPointF(self.boundingRect().bottomLeft())
            down.setY(down.y() - (self.boundingRect().height() * 0.3))
            triangle = [center, up, down]
            painter.drawPolygon(triangle)

        painter.drawText(self.boundingRect(), Qt.AlignCenter, str(self.state_number))
示例#13
0
 def readFromStream(self, inStream):
     size = inStream.readInt32()
     count = inStream.readInt32()
     for point in self.childItems():
         self.scene().removeItem(point)
     self.fixedPoints = []
     for i in range(count):
         point = QPointF()
         inStream >> point
         self.fixedPoints.append(
             activeSplinePoint(point.x(), point.y(), parentItem=self))
     self.updatePath()
     self.updateLUTXY()
     return self
示例#14
0
 def tooltip(self, point: QPointF, state: bool):
     if not self._calloutEnabled:
         return
     if not self._tooltip:
         self._tooltip = Callout(self.chart())
     if state:
         self._tooltip.setText('X: {} \nY: {} '.format(
             computeAxisValue(self.chart().axisX(), point.x()),
             computeAxisValue(self.chart().axisY(), point.y())))
         self._tooltip.setAnchor(point)
         self._tooltip.setZValue(11)
         self._tooltip.updateGeometry()
         self._tooltip.show()
     else:
         self._tooltip.hide()
示例#15
0
 def infoDone():
     try:
         token = self.info.text().split(' ')
         if self.colorInfoFormat == 0:  # RGB
             r, g, b = [int(x) for x in token if x.isdigit()]
             pt = QPointF(*swatchImg.GetPoint(*rgb2hsB(r, g, b)[:2])) + offset
         elif self.colorInfoFormat == 1:  # CMYK
             c, m, y, k = [int(x) for x in token if x.isdigit()]
             pt = QPointF(*swatchImg.GetPoint(*rgb2hsB(*cmyk2rgb(c, m, y, k))[:2])) + offset
         elif self.colorInfoFormat == 2:  # HSV
             h, s, _ = [int(x) for x in token if x.isdigit()]
             if not 0 <= s <= 100:
                 raise ValueError
             pt = QPointF(*swatchImg.GetPoint(h, s / 100.0)) + offset
         else:
             raise ValueError
         self.workingMarker.setPos(pt.x(), pt.y())
     except ValueError:
         dlgWarn("Invalid color")
示例#16
0
    def moveTo_point(self, point: QPointF) -> None:
        """ 移动到指定坐标位置条目 """
        count: int = len(self.__listItem)
        for i in range(count):
            # 如果不是最后一个,则辨别指定项
            if i != (count - 1):
                # 辨别方法,如果不在两项之间,则不是指定项
                if self.__horizontal:
                    if not (
                        (point.x() >= self.__listItem[i][1].topLeft().x()) and
                        (point.x() < self.__listItem[i + 1][1].topLeft().x())):
                        continue
                else:
                    if not (
                        (point.y() >= self.__listItem[i][1].topLeft().y()) and
                        (point.y() < self.__listItem[i + 1][1].topLeft().y())):
                        continue

            self.__currentIndex = i
            self.__currentItem = self.__listItem[i][0]
            self.__targetRect = self.__listItem[i][1]

            if self.__horizontal:
                self.__targetLen = self.__targetRect.topLeft().x()
                self.__barLen = self.__barRect.topLeft().x()
            else:
                self.__targetLen = self.__targetRect.topLeft().y()
                self.__barLen = self.__barRect.topLeft().y()

            self.__isForward = (self.__targetLen > self.__barLen)
            distance: int = int(abs(self.__targetLen - self.__barLen))

            # 重新获取每次移动的步长
            self.__step = self.__initStep(int(distance))
            self.__timer.start()

            self.currentItemChanged.emit(self.__currentIndex,
                                         self.__currentItem)
            break
示例#17
0
 def test_drop_project_item_on_design_view(self):
     mime_data = QMimeData()
     item_type = next(iter(self.toolbox.item_factories))
     mime_data.setText(f"{item_type},spec")
     gv = self.toolbox.ui.graphicsView
     scene_pos = QPointF(44, 20)
     pos = gv.mapFromScene(scene_pos)
     event = QDropEvent(pos, Qt.CopyAction, mime_data, Qt.NoButton,
                        Qt.NoModifier)
     with mock.patch('PySide2.QtWidgets.QGraphicsSceneDragDropEvent.source'
                     ) as mock_drop_event_source, mock.patch.object(
                         self.toolbox, "project"), mock.patch.object(
                             self.toolbox, "show_add_project_item_form"
                         ) as mock_show_add_project_item_form:
         mock_drop_event_source.return_value = ProjectItemDragMixin()
         gv.dropEvent(event)
         mock_show_add_project_item_form.assert_called_once()
         mock_show_add_project_item_form.assert_called_with(item_type,
                                                            scene_pos.x(),
                                                            scene_pos.y(),
                                                            spec="spec")
     item_shadow = gv.scene().item_shadow
     self.assertTrue(item_shadow.isVisible())
     self.assertEqual(item_shadow.pos(), scene_pos)
示例#18
0
    def translate(self, *args):
        offset = QPointF(*args)

        for item in self:
            item.moveBy(offset.x(), offset.y())
示例#19
0
 def snapPos(self, pos: QtCore.QPointF) -> QtCore.QPointF:
     pixel = self.pixelSize()
     x = round(pos.x() / pixel.width()) * pixel.width()
     y = round(pos.y() / pixel.height()) * pixel.height()
     return QtCore.QPointF(x, y)
示例#20
0
class mixerForm(baseGraphicsForm):
    @classmethod
    def getNewWindow(cls,
                     targetImage=None,
                     axeSize=500,
                     layer=None,
                     parent=None):
        wdgt = mixerForm(axeSize=axeSize, layer=layer, parent=parent)
        wdgt.setWindowTitle(layer.name)
        return wdgt

    def __init__(self, targetImage=None, axeSize=500, layer=None, parent=None):
        super().__init__(parent=parent, targetImage=targetImage, layer=layer)
        self.setMinimumSize(axeSize, axeSize + 100)
        # color wheel size
        self.cwSize = axeSize * 0.95
        self.setAttribute(Qt.WA_DeleteOnClose)
        # options
        optionList = ['Monochrome', 'Luminosity']
        listWidget1 = optionsWidget(options=optionList,
                                    exclusive=False,
                                    changed=self.dataChanged,
                                    flow=optionsWidget.LeftToRight)
        listWidget1.setMaximumHeight(
            listWidget1.sizeHintForRow(0) +
            5)  # mandatory although sizePolicy is set to minimum !
        self.options = listWidget1.options
        # barycentric coordinate basis : the 3 base points form an equilateral triangle
        h = self.cwSize - 50
        s = h * 2 / np.sqrt(3)
        self.R, self.G, self.B = QPointF(10, h + 20), QPointF(
            10 + s, h + 20), QPointF(10 + s / 2, 20)
        # Conversion matrix from cartesian coordinates (x, y, 1) to barycentric coordinates (alpha, beta, gamma)
        self.M = np.array([[self.R.x(), self.G.x(),
                            self.B.x()], [self.R.y(),
                                          self.G.y(),
                                          self.B.y()], [1, 1, 1]])
        self.invM = np.linalg.inv(self.M)
        self.setBackgroundImage()
        # active points
        self.rPoint = activeMixerPoint(self.R.x(),
                                       self.R.y(),
                                       color=Qt.red,
                                       fillColor=Qt.white,
                                       grForm=self)
        self.rPoint.source = self.R
        self.gPoint = activeMixerPoint(self.G.x(),
                                       self.G.y(),
                                       color=Qt.green,
                                       fillColor=Qt.white,
                                       grForm=self)
        self.gPoint.source = self.G
        self.bPoint = activeMixerPoint(self.B.x(),
                                       self.B.y(),
                                       color=Qt.blue,
                                       fillColor=Qt.white,
                                       grForm=self)
        self.bPoint.source = self.B
        graphicsScene = self.scene()
        for point in [self.rPoint, self.gPoint, self.bPoint]:
            graphicsScene.addItem(point)
        gl = QVBoxLayout()
        gl.setAlignment(Qt.AlignTop)
        container = self.addCommandLayout(gl)
        self.values = QLabel()
        vh = QFontMetrics(self.values.font()).height()
        self.values.setMaximumSize(150, vh * 4)  # 4 lines
        gl.addWidget(self.values)
        gl.addWidget(listWidget1)
        # don't commute the 3 next lines !
        self.setDefaults()
        self.adjustSize()
        self.setViewportMargins(0, 0, 0, container.height())
        self.setWhatsThis("""<b>Channel Mixer</b><br>
                        The triangle vertices and the three control points correspond to the R, G, B channels.<br>
                        To <b>mix the channels</b>, drag the 3 control points inside the triangle.
                        The closer a control point is to a vertex, the greater the corresponding channel contribution. <br>
                        To obtain <b>monochrome images</b> only, check the option <i>Monochrome.</i><br>
                        To modify the <b>luminosity channel</b> only (volume mode), check the option <i>Luminosity.</i><br>
                        """)  # end of setWhatsThis

    def updateLayer(self):
        if self.options['Monochrome']:
            for p in [self.gPoint, self.bPoint]:
                p.setPos(self.rPoint.pos())
            self.scene().update()
        baryCoordR = self.invM @ [self.rPoint.x(), self.rPoint.y(), 1]
        baryCoordG = self.invM @ [self.gPoint.x(), self.gPoint.y(), 1]
        baryCoordB = self.invM @ [self.bPoint.x(), self.bPoint.y(), 1]
        self.mixerMatrix = np.vstack((baryCoordR, baryCoordG, baryCoordB))
        with np.printoptions(precision=2, suppress=True):
            self.values.setText(self.getChannelValues())
        self.layer.applyToStack()
        self.layer.parentImage.onImageChanged()

    def setDefaults(self):
        try:
            self.dataChanged.disconnect()
        except RuntimeError:
            pass
        self.mixerMatrix = np.identity(3, dtype=np.float)
        with np.printoptions(precision=2, suppress=True):
            self.values.setText(self.getChannelValues())
        self.dataChanged.connect(self.updateLayer)

    def setBackgroundImage(self):
        img = QImage(QSize(256, 256), QImage.Format_ARGB32)
        img.fill(QColor(100, 100, 100))
        a = np.arange(256)
        buf = np.meshgrid(a, a)
        buf1 = QImageBuffer(img)[:, :, :3][:, :, ::-1]
        buf1[:, :, 0], buf1[:, :, 1] = buf
        buf1[:, :, 2] = 1
        buf2 = np.tensordot(buf1, self.invM, axes=(-1, -1)) * 255
        np.clip(buf2, 0, 255, out=buf2)
        buf1[...] = buf2
        img = img.scaled(self.cwSize, self.cwSize)
        qp = QPainter(img)
        # draw edges
        qp.drawLine(self.R, self.G)
        qp.drawLine(self.G, self.B)
        qp.drawLine(self.B, self.R)
        # draw center
        b = (self.B + self.R + self.G) / 3.0
        qp.drawLine(b - QPointF(10, 0), b + QPointF(10, 0))
        qp.drawLine(b - QPointF(0, 10), b + QPointF(0, 10))
        qp.end()
        self.scene().addItem(QGraphicsPixmapItem(QPixmap.fromImage(img)))

    def getChannelValues(self):
        return "\n".join(
            ("         R      G      B",
             " R <- %.2f  %.2f  %.2f" % tuple(self.mixerMatrix[0]),
             " G <- %.2f  %.2f  %.2f" % tuple(self.mixerMatrix[1]),
             " B <- %.2f  %.2f  %.2f" % tuple(self.mixerMatrix[2])))
示例#21
0
 def _get_distance(pt0: QPointF, pt1: QPointF) -> float:
     d = (pt1.x() - pt0.x())**2 + (pt1.y() - pt0.y())**2
     return math.sqrt(d)
示例#22
0
class FDAI(QWidget):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.size = 800
        self.setMinimumSize(self.size, self.size)

        self.center = QPointF(self.size / 2, self.size / 2)
        self.orientation = quaternion.from_rotation_vector(
            0 * normalize(np.array([0, 1, 1])))
        self.data = FDAIData()

    def setOrientation(self, x, y, z, angle):
        """Should take IMU X, Y and Z angles"""
        axis = normalize(np.array([x, y, z]))
        angle = math.radians(angle)
        q = quaternion.from_rotation_vector(angle * axis)
        self.orientation = q
        self.update()

    def setRates(self, roll, pitch, yaw):
        """Takes omegas for roll, pitch and yaw"""
        pass

    def setErrorNeedles(self, error_x, error_y, error_z):
        pass

    def sizeHint(self):
        return QSize(self.size + 1, self.size + 1)

    def drawScale(self, painter):
        painter.setBrush(Qt.black)
        painter.setPen(Qt.black)
        r = int(round(self.size / 2))
        painter.drawEllipse(QPointF(r, r), r, r)
        painter.setBrush(Qt.white)
        painter.drawEllipse(QPointF(r, r), r - 26, r - 26)

        painter.setPen(Qt.white)
        pen = painter.pen()
        pen.setCapStyle(Qt.FlatCap)

        for i in range(72):
            angle = math.radians(i * 5.0)
            c = math.cos(angle)
            s = math.sin(angle)
            r1 = r - 25

            if i % 18 == 0:
                pen.setWidth(8)
                painter.setPen(pen)
                r2 = r - 8
            elif i % 6 == 0:
                pen.setWidth(4)
                painter.setPen(pen)
                r2 = r - 12
            elif i % 2 == 0:
                pen.setWidth(2)
                painter.setPen(pen)
                r2 = r - 16
            else:
                pen.setWidth(2)
                painter.setPen(pen)
                r2 = r - 20

            x1 = r + c * r1
            y1 = r + s * r1
            x2 = r + c * r2
            y2 = r + s * r2

            painter.drawLine(QPointF(x1, y1), QPointF(x2, y2))

    def drawBall(self, painter):
        painter.setPen(Qt.black)
        painter.drawEllipse(self.center, BALL_SCALE * R, BALL_SCALE * R)

        painter.setBrush(Qt.black)
        painter.setPen(Qt.NoPen)

        for p in self.data.get_visible_polygons(self.orientation):
            painter.setBrush(p.color)
            painter.drawPath(self.build_path(p.points, BALL_SCALE))

    def build_path(self, points, scale=1):
        path = QPainterPath()

        if len(points) > 0:
            p0 = self.projectPointToCanvas(points[0], scale)
            path.moveTo(p0)

            for p in points[1:]:
                cp = self.projectPointToCanvas(p, scale)
                path.lineTo(cp)
            path.lineTo(p0)

        return path

    def projectPointToCanvas(self, p, scale=1):
        return self.pointToCanvas(self.projectPoint(p), scale)

    def projectPoint(self, p):
        """
        World X is out of screen
        World Y is left to right
        World Z is bottom to top
        """
        return p[1:]

    def pointToCanvas(self, p, scale=1):
        """
        Input: projected world coordinates (2D)
        Input origin is in center of canvas
        Input first coordinate is left to right
        Input second coordinate is bottom to top
        Screen X is left to right
        Screen Y is top to bottom
        """
        return QPointF(self.center.x() + scale * p[0],
                       self.center.y() - scale * p[1])

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing, on=True)

        self.drawScale(painter)
        self.drawBall(painter)
        painter.end()
示例#23
0
    def connection_path(p1: QPointF, p2: QPointF):
        """Returns the nice looking QPainterPath of a connection for two given points."""

        path = QPainterPath()

        path.moveTo(p1)

        distance_x = abs(p1.x()) - abs(p2.x())
        distance_y = abs(p1.y()) - abs(p2.y())

        if ((p1.x() < p2.x() - 30)
                or math.sqrt((distance_x**2) +
                             (distance_y**2)) < 100) and (p1.x() < p2.x()):
            path.cubicTo(p1.x() + ((p2.x() - p1.x()) / 2), p1.y(),
                         p1.x() + ((p2.x() - p1.x()) / 2), p2.y(), p2.x(),
                         p2.y())
        elif p2.x() < p1.x() - 100 and abs(distance_x) / 2 > abs(distance_y):
            path.cubicTo(p1.x() + 100 + (p1.x() - p2.x()) / 10, p1.y(),
                         p1.x() + 100 + (p1.x() - p2.x()) / 10,
                         p1.y() - (distance_y / 2),
                         p1.x() - (distance_x / 2),
                         p1.y() - (distance_y / 2))
            path.cubicTo(p2.x() - 100 - (p1.x() - p2.x()) / 10,
                         p2.y() + (distance_y / 2),
                         p2.x() - 100 - (p1.x() - p2.x()) / 10, p2.y(), p2.x(),
                         p2.y())
        else:
            path.cubicTo(p1.x() + 100 + (p1.x() - p2.x()) / 3, p1.y(),
                         p2.x() - 100 - (p1.x() - p2.x()) / 3, p2.y(), p2.x(),
                         p2.y())
        return path
示例#24
0
class mixerForm(baseGraphicsForm):
    @classmethod
    def getNewWindow(cls,
                     targetImage=None,
                     axeSize=500,
                     layer=None,
                     parent=None):
        wdgt = mixerForm(axeSize=axeSize, layer=layer, parent=parent)
        wdgt.setWindowTitle(layer.name)
        return wdgt

    def __init__(self, targetImage=None, axeSize=500, layer=None, parent=None):
        super().__init__(parent=parent, targetImage=targetImage, layer=layer)
        self.setMinimumSize(axeSize, axeSize)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.options = None
        # barycentric coordinate basis : the 3 base points form an equilateral triangle
        self.R, self.G, self.B = QPointF(20,
                                         235), QPointF(235,
                                                       235), QPointF(128, 13)
        # Conversion matrix from cartesian coordinates (x, y, 1) to barycentric coordinates (alpha, beta, gamma)
        self.M = np.array([[self.R.x(), self.G.x(),
                            self.B.x()], [self.R.y(),
                                          self.G.y(),
                                          self.B.y()], [1, 1, 1]])
        self.invM = np.linalg.inv(self.M)
        self.setBackgroundImage()
        # active points
        self.rPoint = activeMixerPoint(20, 235)
        self.rPoint.source = self.R
        self.gPoint = activeMixerPoint(235, 235)
        self.gPoint.source = self.G
        self.bPoint = activeMixerPoint(128, 13)
        self.bPoint.source = self.B
        graphicsScene = self.scene()
        for point in [self.rPoint, self.gPoint, self.bPoint]:
            graphicsScene.addItem(point)
        self.setDefaults()
        self.setWhatsThis("""
                        <b>Channel Mixer</b><br>
                        To <b>mix the R, G, B channels</b>, drag the 3 control points inside the triangle.<br>
                        """)  # end of setWhatsThis

    def updateLayer(self):
        baryCoordR = self.invM @ [self.rPoint.x(), self.rPoint.y(), 1]
        baryCoordG = self.invM @ [self.gPoint.x(), self.gPoint.y(), 1]
        baryCoordB = self.invM @ [self.bPoint.x(), self.bPoint.y(), 1]
        self.mixerMatrix = np.vstack((baryCoordR, baryCoordG, baryCoordB))
        self.layer.applyToStack()
        self.layer.parentImage.onImageChanged()

    def setDefaults(self):
        try:
            self.dataChanged.disconnect()
        except RuntimeError:
            pass
        self.mixerMatrix = np.identity(3, dtype=np.float)
        self.dataChanged.connect(self.updateLayer)

    def setBackgroundImage(self):
        img = QImage(QSize(256, 256), QImage.Format_ARGB32)
        img.fill(QColor(100, 100, 100))
        a = np.arange(256)
        buf = np.meshgrid(a, a)
        buf1 = QImageBuffer(img)[:, :, :3][:, :, ::-1]
        buf1[:, :, 0], buf1[:, :, 1] = buf
        buf1[:, :, 2] = 1
        buf2 = np.tensordot(buf1, self.invM, axes=(-1, -1)) * 255
        np.clip(buf2, 0, 255, out=buf2)
        buf1[...] = buf2
        qp = QPainter(img)
        qp.drawLine(self.R, self.G)
        qp.drawLine(self.G, self.B)
        qp.drawLine(self.B, self.R)
        b = (self.B + self.R + self.G) / 3.0
        qp.drawLine(b - QPointF(10, 0), b + QPointF(10, 0))
        qp.drawLine(b - QPointF(0, 10), b + QPointF(0, 10))
        qp.end()
        self.scene().addItem(QGraphicsPixmapItem(QPixmap.fromImage(img)))
示例#25
0
class ConnectionIndicator(QGraphicsItem):
    """
	This class is used to show a potential wire connection if the user drags between two ports.
	"""

    PEN_WIDTH = 5
    BASE_COLOR = QColor(0, 0, 255)
    GOOD_COLOR = QColor(0, 255, 0)
    BAD_COLOR = QColor(255, 0, 0)

    def __init__(self, parent: 'ActionPipelineGraphics'):
        """
		Constructs a ConnectionIndicator class
		
		:param parent: The ActionPipelineGraphics class that the indicator belongs to.
		:type parent: ActionPipelineGraphics
		"""
        QGraphicsItem.__init__(self, parent)
        self._srcPoint = QPointF(0, 0)
        self._destPoint = QPointF(0, 0)
        self.setZValue(100)  # stack on top of all siblings
        self.color = ConnectionIndicator.BASE_COLOR

    def setColor(self, color: QColor) -> None:
        """
		Sets the color of the indicator.
		
		:param color: The color of the indicator
		:type color: QColor
		:return: None
		:rtype: NoneType
		"""
        self.color = color

    def setSrc(self, point: QPointF) -> None:
        """
		Sets the source position of the indicator.
		
		:param point: The point to set the source to.
		:type point: QPointF
		:return: None
		:rtype: NoneType
		"""
        self._srcPoint = point

    def setDest(self, point: QPointF) -> None:
        """
		Sets the destination position of the indicator.

		:param point: The point to set the destination to.
		:type point: QPointF
		:return: None
		:rtype: NoneType
		"""
        self._destPoint = point

    def boundingRect(self) -> QRectF:
        """
		Gets the bounding rectangle of the indicator.
		
		:return: The bounding rectangle of the indicator
		:rtype: QRectF
		"""
        x = min(self._srcPoint.x(),
                self._destPoint.x()) - ConnectionIndicator.PEN_WIDTH / 2
        y = min(self._srcPoint.y(),
                self._destPoint.y()) - ConnectionIndicator.PEN_WIDTH / 2
        width = abs(self._srcPoint.x() -
                    self._destPoint.x()) + ConnectionIndicator.PEN_WIDTH
        height = abs(self._destPoint.y() -
                     self._destPoint.y()) + ConnectionIndicator.PEN_WIDTH
        return QRectF(x, y, width, height)

    def paint(self, painter, options, widget):
        pen = QPen()
        pen.setColor(self.color)
        pen.setStyle(Qt.DashLine)
        pen.setCapStyle(Qt.RoundCap)
        pen.setWidth(ConnectionIndicator.PEN_WIDTH)
        painter.setPen(pen)
        painter.drawLine(self._srcPoint, self._destPoint)
示例#26
0
class wheel(QWidget):
    currentColorChanged = Signal(QColor)

    def __init__(self, parent=None):
        super(wheel, self).__init__(parent)
        self.setFixedSize(256, 256)

        # start, end angles for value arc
        self.s_ang, self.e_ang = 135, 225

        # offset angle and direction for color wheel
        self.o_ang, self.rot_d = 45, -1  # 1 for clock-wise, -1 for widdershins

        # other initializations
        self.pos = QPointF(-100, -100)
        self.vIdCen = QPointF(-100, -100)
        self.vIdAng = radians(self.s_ang)
        self.chPt = self.pos
        self.hue = self.sat = self.value = 255

        self.setup()
        self.pos = self.cWhBox.center()

        self._namedColorList = []
        self._namedColorPts = []
        self._showNames = False

        self.setMouseTracking(True)
        self.installEventFilter(self)

        self._startedTimer = False


##    def timerSpinner(self):
##        "won't this be fun"
##        self.o_ang -= 1; self.o_ang %= 360
##        stable = False
##
##        colWhl = QConicalGradient(self.cen, self.o_ang)
##        whl_cols = [Qt.red, Qt.magenta,
##                    Qt.blue, Qt.cyan, Qt.green,
##                    Qt.yellow, Qt.red]
##        for i, c in enumerate(whl_cols[::self.rot_d]):
##            colWhl.setColorAt(i / 6.0, c)
##
##        if stable:  # crosshairs stay on color
##            t = radians(self.hue + self.o_ang * -self.rot_d) * -self.rot_d
##            r = self.sat / 255.0 * self.cW_rad
##            x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y()
##            self.chPt = QPointF(x, y)
##        else:  # crosshairs stay on point
##            t = atan2(self.cen.y() - self.pos.y(), self.pos.x() - self.cen.x())
##            h = (int(degrees(t)) - self.o_ang) * -self.rot_d
##            self.hue = (h if h > 0 else h + 360) % 360
##            col = QColor(); col.setHsv(self.hue, self.sat, self.value)
##            self.currentColorChanged.emit(col)
##
##        self.cWhlBrush1 = QBrush(colWhl)
##        self.update()

    def resizeEvent(self, event):
        self.setup()  # re-construct the sizes
        self.setNamedColors(self._namedColorList)

    def getColor(self):
        col = QColor()
        col.setHsv(self.hue, self.sat, self.value)
        return col

    def setNamedColors(self, colorList):
        "sets list [(name, #html)] of named colors"
        self._namedColorList = colorList
        lst = []
        r2 = (self.vAoBox.width() + self.vAiBox.width()) / 4.0
        for i in self._namedColorList:
            h, s, v, a = QColor(i[1]).getHsv()

            t = radians(h + self.o_ang * -self.rot_d) * -self.rot_d
            r = s / 255.0 * self.cW_rad
            x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y()
            lst.append(QPointF(x, y))

            #t2 = ((v / 255.0) * self.ang_w + radians(self.e_ang) + 2 * pi) % (2 * pi)
            #x, y = r2 * cos(t2) + self.cen.x(), r2 * -sin(t2) + self.cen.y()
            #lst.append(QPointF(x, y))
        self._namedColorPts = lst

    def showNamedColors(self, flag=False):
        "show/hide location of named colors on color wheel"
        self._showNames = flag
        self.update()

    def setColor(self, color):  # saturation -> radius
        h, s, v, a = color.getHsv()  # hue -> angle
        self.hue, self.sat, self.value = h, s, v  # value -> side bar thingy

        t = radians(h + self.o_ang * -self.rot_d) * -self.rot_d
        r = s / 255.0 * self.cW_rad
        x, y = r * cos(t) + self.cen.x(), r * -sin(t) + self.cen.y()
        self.chPt = QPointF(x, y)  # hue, saturation

        self.vIdAng = t2 = (v / 255.0) * self.ang_w + radians(self.e_ang)
        self.vIdAng = t2 = t2 if t2 > 0 else t2 + 2 * pi
        r2 = self.vAoBox.width() / 2.0

        x, y = r2 * cos(t2) + self.cen.x(), r2 * -sin(t2) + self.cen.y()
        self.vIdCen, self.vIdAng = QPointF(x, y), t2  # value
        self.vIdBox.moveCenter(self.vIdCen)
        self.update()

    def eventFilter(self, source, event):
        if (event.type() == QEvent.MouseButtonPress
                or (event.type() == QEvent.MouseMove
                    and event.buttons() == Qt.LeftButton)):
            self.pos = pos = event.pos()

            t = atan2(self.cen.y() - pos.y(), pos.x() - self.cen.x())
            if self.colWhlPath.contains(pos):  # in the color wheel
                self.chPt = pos

                #if not self._startedTimer:
                #    self.timer = QTimer()
                #    self.timer.timeout.connect(self.timerSpinner)
                #    self.timer.start(30.303)
                #    self._startedTimer = True

                # hue -> mouse angle (same as t here)
                h = (int(degrees(t)) - self.o_ang) * -self.rot_d
                self.hue = (h if h > 0 else h + 360) % 360

                # saturation -> mouse radius (clipped to wheel radius)
                m_rad = sqrt((self.pos.x() - self.cen.x())**2 +
                             (self.pos.y() - self.cen.y())**2)
                self.sat = int(255 * min(m_rad / self.cW_rad, 1))

            if self.vInArcPath.contains(pos):  # in the value selection arc
                self.vIdAng = t if t > 0 else t + 2 * pi
                r2 = self.vAoBox.width() / 2.0

                x, y = r2 * cos(t) + self.cen.x(), r2 * -sin(t) + self.cen.y()
                self.vIdCen = QPointF(x, y)
                self.vIdBox.moveCenter(self.vIdCen)
                self.value = int(255 *
                                 (t - radians(self.e_ang)) / self.ang_w) % 256

            self.update()
            col = QColor()
            col.setHsv(self.hue, self.sat, self.value)
            self.currentColorChanged.emit(col)
        return QWidget.eventFilter(self, source, event)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(painter.Antialiasing)

        #painter.setBrush(QBrush(Qt.black, Qt.NoBrush))
        #painter.drawRect(self.winBox)  # border

        # value selector indicator
        painter.setBrush(QBrush(Qt.black, Qt.SolidPattern))
        painter.drawPie(self.vIdBox, 16 * (degrees(self.vIdAng) - 22.5), 720)

        # value selector arc
        painter.setClipPath(self.vArcPath)
        painter.setPen(Qt.NoPen)
        arc = QConicalGradient(self.cen, self.e_ang)
        color = QColor()
        color.setHsv(self.hue, self.sat, 255)
        arc.setColorAt(1 - (self.e_ang - self.s_ang) / 360.0, color)
        arc.setColorAt(1, Qt.black)
        arc.setColorAt(0, Qt.black)
        painter.setBrush(arc)
        painter.drawPath(self.vArcPath)
        painter.setClipPath(self.vArcPath, Qt.NoClip)

        # color wheel
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.cWhlBrush1)
        painter.drawEllipse(self.cWhBox)
        painter.setBrush(self.cWhlBrush2)
        painter.drawEllipse(self.cWhBox)

        # crosshairs
        painter.setClipPath(self.colWhlPath)
        painter.setBrush(QBrush(Qt.black, Qt.SolidPattern))
        chVert = QRectF(0, 0, 2, 20)
        chHort = QRectF(0, 0, 20, 2)
        chVert.moveCenter(self.chPt)
        chHort.moveCenter(self.chPt)
        painter.drawRect(chVert)
        painter.drawRect(chHort)

        # named color locations
        if self._showNames:
            painter.setClipPath(self.vArcPath, Qt.NoClip)
            painter.setPen(Qt.SolidLine)
            try:
                painter.drawPoints(*self._namedColorPts)  # PyQt
            except:
                painter.drawPoints(self._namedColorPts)  # PySide

    def setup(self):
        "sets bounds on value arc and color wheel"
        # bounding boxes
        self.winBox = QRectF(self.rect())
        self.vIoBox = QRectF()  # value indicator arc outer
        self.vIdBox = QRectF()  # value indicator box
        self.vAoBox = QRectF()  # value arc outer
        self.vAiBox = QRectF()  # value arc inner
        self.cWhBox = QRectF()  # color wheel

        self.vIdBox.setSize(QSizeF(15, 15))
        self.vIoBox.setSize(self.winBox.size())
        self.vAoBox.setSize(self.winBox.size() - self.vIdBox.size() / 2.0)
        self.vAiBox.setSize(self.vAoBox.size() - QSizeF(20, 20))
        self.cWhBox.setSize(self.vAiBox.size() - QSizeF(20, 20))

        # center - shifted to the right slightly
        x = self.winBox.width() - (self.vIdBox.width() +
                                   self.vAiBox.width()) / 2.0
        self.cen = QPointF(x, self.winBox.height() / 2.0)

        # positions and initial settings
        self.vAoBox.moveCenter(self.cen)
        self.vAiBox.moveCenter(self.cen)
        self.cWhBox.moveCenter(self.cen)
        self.vIdBox.moveCenter(self.vIdCen)

        self.cW_rad = self.cWhBox.width() / 2.0
        self.ang_w = radians(self.s_ang) - radians(self.e_ang)

        # gradients
        colWhl = QConicalGradient(self.cen, self.o_ang)
        whl_cols = [
            Qt.red, Qt.magenta, Qt.blue, Qt.cyan, Qt.green, Qt.yellow, Qt.red
        ]
        for i, c in enumerate(whl_cols[::self.rot_d]):
            colWhl.setColorAt(i / 6.0, c)

        rad = min(self.cWhBox.width() / 2.0, self.cWhBox.height() / 2.0)
        cWhlFade = QRadialGradient(self.cen, rad, self.cen)
        cWhlFade.setColorAt(0, Qt.white)
        cWhlFade.setColorAt(1, QColor(255, 255, 255, 0))

        self.cWhlBrush1 = QBrush(colWhl)
        self.cWhlBrush2 = QBrush(cWhlFade)

        # painter paths (arcs, wheel)
        rad = self.vAoBox.width() / 2.0
        x, y = rad * cos(radians(self.s_ang)), -rad * sin(radians(self.s_ang))
        x += self.cen.x()
        y += self.cen.y()

        self.vArcPath = QPainterPath(QPointF(x, y))  # value arc (for color)
        self.vArcPath.arcTo(self.vAoBox, self.s_ang, self.e_ang - self.s_ang)
        self.vArcPath.arcTo(self.vAiBox, self.e_ang, self.s_ang - self.e_ang)
        self.vArcPath.closeSubpath()

        self.vInArcPath = QPainterPath(QPointF(x, y))  # value arc (for mouse)
        self.vInArcPath.arcTo(self.vIoBox, self.s_ang, self.e_ang - self.s_ang)
        self.vInArcPath.arcTo(self.vAiBox, self.e_ang, self.s_ang - self.e_ang)
        self.vInArcPath.closeSubpath()

        self.colWhlPath = QPainterPath()
        self.colWhlPath.addEllipse(self.cWhBox)
示例#27
0
    def mapToData(self, pos: QtCore.QPointF) -> QtCore.QPoint:
        """Map a position to an image pixel coordinate."""
        pixel = self.pixelSize()

        pos -= self.rect.topLeft()
        return QtCore.QPoint(pos.x() / pixel.width(), pos.y() / pixel.height())
示例#28
0
    def sceneToGrid(pos: QPointF) -> QPoint:
        """Map a scene position to grid coordinates."""

        return QPoint(pos.x() // Plan.cellSize, pos.y() // Plan.cellSize)
示例#29
0
    def _autoPosition(self, pos: QtCore.QPointF):
        """
        Automatically positions the widget. Sets position just outside of
        the fullOpacityMargin so the widget initializes as semi-transparent.
        Tries to place widget to the lower right of the position.
        """

        # Get sizes
        parentSize: QtCore.QSizeF = self.parent().size()
        size: QtCore.QSizeF = self.size()

        # Margin around rect. Increase the fullOpacityMargin so the widget
        # starts out semi-transparent.
        margin = self._fullOpacityMargin + self._extraAutoMargin

        # Update opacity to reflect new cursor distance from the widget
        self._updateDistanceOpacity((margin**2 + margin**2)**(0.5))

        # Initialize fitting checks
        rightFit = False
        leftFit = False
        topFit = False
        bottomFit = False

        # Check if the widget could fit to the right of the position
        if pos.x() + margin + size.width() < parentSize.width():
            rightFit = True
        else:
            rightFit = False

        # Check if the widget could fit to the left of the position
        if pos.x() - margin - size.width() > 0:
            leftFit = True
        else:
            leftFit = False

        # Check if the widget could fit to the bottom of the position
        if pos.y() + margin + size.height() < parentSize.height():
            bottomFit = True
        else:
            bottomFit = False

        # Check if the widget could fit to the top of the position
        if pos.y() - margin - size.height() > 0:
            topFit = True
        else:
            topFit = False

        # Retreive geometry
        geo = self.geometry()

        # Favored position is below and to the right
        if (rightFit and bottomFit or rightFit and not topFit
                or not leftFit and not topFit):
            geo.moveTopLeft(QtCore.QPoint(pos.x() + margin, pos.y() + margin))

        # Above to the right
        elif rightFit and topFit or not leftFit and topFit:
            geo.moveBottomLeft(
                QtCore.QPoint(pos.x() + margin,
                              pos.y() - margin))

        # Below to the left
        elif leftFit and bottomFit or leftFit and not topFit:
            geo.moveTopRight(QtCore.QPoint(pos.x() - margin, pos.y() + margin))

        # Above to the left
        else:
            geo.moveBottomRight(
                QtCore.QPoint(pos.x() - margin,
                              pos.y() - margin))

        # Assign newly positioned geometry
        self.setGeometry(geo)
示例#30
0
class mixerForm(baseGraphicsForm):

    @classmethod
    def getNewWindow(cls, targetImage=None, axeSize=500, layer=None, parent=None):
        wdgt = mixerForm(axeSize=axeSize, layer=layer, parent=parent)
        wdgt.setWindowTitle(layer.name)
        return wdgt

    def __init__(self, targetImage=None, axeSize=500, layer=None, parent=None):
        super().__init__(parent=parent, targetImage=targetImage, layer=layer)
        self.setMinimumSize(axeSize, axeSize + 80)
        # color wheel size
        self.cwSize = axeSize * 0.95
        self.setAttribute(Qt.WA_DeleteOnClose)
        # options
        optionList = ['Monochrome']
        listWidget1 = optionsWidget(options=optionList, exclusive=False, changed=self.dataChanged)
        listWidget1.setMinimumWidth(listWidget1.sizeHintForColumn(0) + 5)
        listWidget1.setMinimumHeight(listWidget1.sizeHintForRow(0) * len(optionList) + 5)
        self.options = listWidget1.options
        # barycentric coordinate basis : the 3 base points form an equilateral triangle
        h = self.cwSize - 50
        s = h * 2 / np.sqrt(3)
        self.R, self.G, self.B = QPointF(10, h + 20), QPointF(10 + s, h + 20), QPointF(10 + s / 2, 20)
        # Conversion matrix from cartesian coordinates (x, y, 1) to barycentric coordinates (alpha, beta, gamma)
        self.M = np.array([[self.R.x(), self.G.x(), self.B.x()],
                           [self.R.y(), self.G.y(), self.B.y()],
                           [1,            1,           1      ]])
        self.invM = np.linalg.inv(self.M)
        self.setBackgroundImage()
        # active points
        self.rPoint = activeMixerPoint(self.R.x(), self.R.y(), color=Qt.red, fillColor=Qt.white)
        self.rPoint.source = self.R
        self.gPoint = activeMixerPoint(self.G.x(), self.G.y(), color=Qt.green, fillColor=Qt.white)
        self.gPoint.source = self.G
        self.bPoint = activeMixerPoint(self.B.x(), self.B.y(), color=Qt.blue, fillColor=Qt.white)
        self.bPoint.source = self.B
        graphicsScene = self.scene()
        for point in [self.rPoint, self.gPoint, self.bPoint]:
            graphicsScene.addItem(point)
        gl = QGridLayout()
        gl.addWidget(listWidget1, 0, 0, 2, 2)
        self.addCommandLayout(gl)
        self.setDefaults()
        self.setWhatsThis(
                        """<b>Channel Mixer</b><br>
                        To <b>mix the R, G, B channels</b>, drag the 3 control points inside the triangle.<br>
                        The triangle vertices and the control points correspond to channels.
                        The closer a control point is to a vertex, the greater the corresponding channel contribution.  
                        """
                        )  # end of setWhatsThis

    def updateLayer(self):
        baryCoordR = self.invM @ [self.rPoint.x(), self.rPoint.y(), 1]
        baryCoordG = self.invM @ [self.gPoint.x(), self.gPoint.y(), 1]
        baryCoordB = self.invM @ [self.bPoint.x(), self.bPoint.y(), 1]
        self.mixerMatrix = np.vstack((baryCoordR, baryCoordG, baryCoordB))
        self.layer.applyToStack()
        self.layer.parentImage.onImageChanged()

    def setDefaults(self):
        try:
            self.dataChanged.disconnect()
        except RuntimeError:
            pass
        self.mixerMatrix = np.identity(3, dtype=np.float)
        self.dataChanged.connect(self.updateLayer)

    def setBackgroundImage(self):
        img = QImage(QSize(256, 256), QImage.Format_ARGB32)
        img.fill(QColor(100, 100, 100))
        a = np.arange(256)
        buf = np.meshgrid(a, a)
        buf1 = QImageBuffer(img)[:, :, :3][:, :, ::-1]
        buf1[:, :, 0], buf1[:, :, 1] = buf
        buf1[:, :, 2] = 1
        buf2 = np.tensordot(buf1, self.invM, axes=(-1, -1)) * 255
        np.clip(buf2, 0, 255, out=buf2)
        buf1[...] = buf2
        img = img.scaled(self.cwSize, self.cwSize)
        qp = QPainter(img)
        # draw edges
        qp.drawLine(self.R, self.G)
        qp.drawLine(self.G, self.B)
        qp.drawLine(self.B, self.R)
        # draw center
        b = (self.B + self.R + self.G) / 3.0
        qp.drawLine(b-QPointF(10, 0), b + QPointF(10, 0))
        qp.drawLine(b - QPointF(0, 10), b + QPointF(0, 10))
        qp.end()
        self.scene().addItem(QGraphicsPixmapItem(QPixmap.fromImage(img)))