コード例 #1
0
ファイル: abstractslicetool.py プロジェクト: hadim/cadnano2.5
    def findNearestPoint(self, part_item, target_scenepos):
        """
        Args:
            part_item (TYPE): Description
            target_scenepos (TYPE): Description
        """
        li = self._line_item
        pos = li.mapFromScene(target_scenepos)

        line = li.line()
        mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos)

        # Check if the click happened on the origin VH
        if mouse_point_vec.length() < self._RADIUS:
            # return part_item.mapFromScene(target_scenepos)
            return None

        angle_min = 9999
        direction_min = None
        for vector in self.vectors:
            angle_new = mouse_point_vec.angleTo(vector)
            if angle_new < angle_min:
                direction_min = vector
                angle_min = angle_new
        if direction_min is not None:
            li.setLine(direction_min)
            return part_item.mapFromItem(li, direction_min.p2())
        else:
            print("default point")
            line.setP2(pos)
            li.setLine(line)
            return part_item.mapFromItem(li, pos)
コード例 #2
0
ファイル: guide.py プロジェクト: Axel-Erfurt/pyqt5
    def move(self, item, dest, moveSpeed):
        walkLine = QLineF(item.getGuidedPos(), dest)
        if moveSpeed >= 0 and walkLine.length() > moveSpeed:
            # The item is too far away from it's destination point so we move
            # it towards it instead.
            dx = walkLine.dx()
            dy = walkLine.dy()

            if abs(dx) > abs(dy):
                # Walk along x-axis.
                if dx != 0:
                    d = moveSpeed * dy / abs(dx)

                    if dx > 0:
                        s = moveSpeed
                    else:
                        s = -moveSpeed

                    dest.setX(item.getGuidedPos().x() + s)
                    dest.setY(item.getGuidedPos().y() + d)
            else:
                # Walk along y-axis.
                if dy != 0:
                    d = moveSpeed * dx / abs(dy)

                    if dy > 0:
                        s = moveSpeed
                    else:
                        s = -moveSpeed

                    dest.setX(item.getGuidedPos().x() + d)
                    dest.setY(item.getGuidedPos().y() + s)

        item.setGuidedPos(dest)
コード例 #3
0
ファイル: gridextras.py プロジェクト: cadnano/cadnano2.5
    def setActive5p(self, is_active, neighbor_item=None):
        """Summary

        Args:
            is_active (TYPE): Description
            neighbor_item (None, optional): Description
        """
        phos = self.phos_item
        bond = self.bond_3p
        if bond is None:
            return
        if not self.is_active5p and is_active:
            self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX + 10)
            self.is_active5p = True
            if neighbor_item is not None:
                n_scene_pos = neighbor_item.scenePos()
                p2 = self.mapFromScene(n_scene_pos)
                bline = bond.line()
                test = QLineF(bline.p1(), p2)
                # angle = test.angleTo(bline) + self.theta0 if self.is_fwd else -bline.angleTo(test) + self.theta0
                angle = -bline.angleTo(test) + self.theta0 if self.is_fwd else test.angleTo(bline) + self.theta0
            else:
                p2 = self._active_p2_3p
                angle = -90 if self.is_fwd else 90
            self.animate(phos, 'rotation', 300, self.theta0, angle)
            self.animate(bond, 'bondp2', 300, self._default_p2_3p, p2)
        elif self.is_active5p:
            self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX)
            self.is_active5p = False
            self.animate(phos, 'rotation', 300, phos.rotation(), self.theta0)
            self.animate(bond, 'bondp2', 300, bond.line().p2(), self._default_p2_3p)
コード例 #4
0
ファイル: inclusion.py プロジェクト: gitter-badger/eddy
 def image(cls, **kwargs):
     """
     Returns an image suitable for the palette.
     :rtype: QPixmap
     """
     # INITIALIZATION
     pixmap = QPixmap(kwargs['w'], kwargs['h'])
     pixmap.fill(Qt.transparent)
     painter = QPainter(pixmap)
     # INIT THE LINE
     p1 = QPointF(((kwargs['w'] - 54) / 2), kwargs['h'] / 2)
     p2 = QPointF(((kwargs['w'] - 54) / 2) + 54 - 2, kwargs['h'] / 2)
     line = QLineF(p1, p2)
     # CLACULATE HEAD COORDS
     angle = line.angle()
     p1 = QPointF(line.p2().x() + 2, line.p2().y())
     p2 = p1 - QPointF(sin(angle + M_PI / 3.0) * 8, cos(angle + M_PI / 3.0) * 8)
     p3 = p1 - QPointF(sin(angle + M_PI - M_PI / 3.0) * 8, cos(angle + M_PI - M_PI / 3.0) * 8)
     # INITIALIZE HEAD
     head = QPolygonF([p1, p2, p3])
     # DRAW EDGE LINE
     painter.setRenderHint(QPainter.Antialiasing)
     painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
     painter.drawLine(line)
     # DRAW EDGE HEAD
     painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
     painter.setBrush(QColor(0, 0, 0))
     painter.drawPolygon(head)
     return pixmap
コード例 #5
0
ファイル: Gantt.py プロジェクト: MaximeCheramy/simso-gui
    def plot_vert_line_graph(self, qp, x_line, color, c, arrow_up=False,
                             arrow_down=False):
        if x_line < self._start_date or x_line > self._end_date:
            return

        x_line -= self._start_date

        qp.save()
        qp.setPen(color)
        qp.setBrush(color)
        qp.setRenderHint(QPainter.Antialiasing)
        arrowSize = 2.0
        x, y = self.origGraph(c)
        line = QLineF(x + self.convX(x_line), y + 10, x + self.convX(x_line),
                      y + 50)
        qp.drawLine(line)
        if arrow_up:
            arrowP1 = line.p1() + QPointF(arrowSize, arrowSize * 3)
            arrowP2 = line.p1() + QPointF(-arrowSize, arrowSize * 3)
            qp.drawLine(line.p1(), arrowP1)
            qp.drawLine(line.p1(), arrowP2)
        if arrow_down:
            arrowP1 = line.p2() + QPointF(arrowSize, - arrowSize * 3)
            arrowP2 = line.p2() + QPointF(-arrowSize, - arrowSize * 3)
            qp.drawLine(line.p2(), arrowP1)
            qp.drawLine(line.p2(), arrowP2)
        qp.restore()
コード例 #6
0
ファイル: instance_of.py プロジェクト: gitter-badger/eddy
    def image(cls, **kwargs):
        """
        Returns an image suitable for the palette.
        :rtype: QPixmap
        """
        # INITIALIZATION
        pixmap = QPixmap(kwargs['w'], kwargs['h'])
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        # INITIALIZE EDGE LINE
        pp1 = QPointF(((kwargs['w'] - 52) / 2), kwargs['h'] / 2)
        pp2 = QPointF(((kwargs['w'] - 52) / 2) + 52 - 2, kwargs['h'] / 2)
        line = QLineF(pp1, pp2)
        # CALCULATE HEAD COORDINATES
        angle = radians(line.angle())
        p1 = QPointF(line.p2().x() + 2, line.p2().y())
        p2 = p1 - QPointF(sin(angle + M_PI / 3.0) * 8, cos(angle + M_PI / 3.0) * 8)
        p3 = p1 - QPointF(sin(angle + M_PI - M_PI / 3.0) * 8, cos(angle + M_PI - M_PI / 3.0) * 8)
        # INITIALIZE EDGE HEAD
        head = QPolygonF([p1, p2, p3])
        # DRAW THE POLYGON
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(line)
        # DRAW HEAD
        painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        painter.setBrush(QColor(0, 0, 0))
        painter.drawPolygon(head)
        # DRAW THE TEXT ON TOP OF THE EDGE
        space = 2 if Platform.identify() is Platform.Darwin else 0
        painter.setFont(Font('Arial', 9, Font.Light))
        painter.drawText(pp1.x() + space, (kwargs['h'] / 2) - 4, 'instanceOf')

        return pixmap
コード例 #7
0
ファイル: guideline.py プロジェクト: Axel-Erfurt/pyqt5
    def __init__(self, line_or_point, follows=None):
        super(GuideLine, self).__init__(follows)

        if isinstance(line_or_point, QLineF):
            self.line = line_or_point
        elif follows is not None:
            self.line = QLineF(self.prevGuide.endPos(), line_or_point)
        else:
            self.line = QLineF(QPointF(0, 0), line_or_point)
コード例 #8
0
ファイル: collidingmice.py プロジェクト: Axel-Erfurt/pyqt5
    def timerEvent(self):
        # Don't move too far away.
        lineToCenter = QLineF(QPointF(0, 0), self.mapFromScene(0, 0))
        if lineToCenter.length() > 150:
            angleToCenter = math.acos(lineToCenter.dx() / lineToCenter.length())
            if lineToCenter.dy() < 0:
                angleToCenter = Mouse.TwoPi - angleToCenter;
            angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) + Mouse.Pi / 2)

            if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4:
                # Rotate left.
                self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2]
            elif angleToCenter >= Mouse.Pi and angleToCenter < (Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4):
                # Rotate right.
                self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2]
        elif math.sin(self.angle) < 0:
            self.angle += 0.25
        elif math.sin(self.angle) > 0:
            self.angle -= 0.25

        # Try not to crash with any other mice.
        dangerMice = self.scene().items(QPolygonF([self.mapToScene(0, 0),
                                                         self.mapToScene(-30, -50),
                                                         self.mapToScene(30, -50)]))

        for item in dangerMice:
            if item is self:
                continue
        
            lineToMouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0))
            angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length())
            if lineToMouse.dy() < 0:
                angleToMouse = Mouse.TwoPi - angleToMouse
            angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) + Mouse.Pi / 2)

            if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2:
                # Rotate right.
                self.angle += 0.5
            elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi - Mouse.Pi / 2):
                # Rotate left.
                self.angle -= 0.5

        # Add some random movement.
        if len(dangerMice) > 1 and (qrand() % 10) == 0:
            if qrand() % 1:
                self.angle += (qrand() % 100) / 500.0
            else:
                self.angle -= (qrand() % 100) / 500.0

        self.speed += (-50 + qrand() % 100) / 100.0

        dx = math.sin(self.angle) * 10
        self.mouseEyeDirection = 0.0 if qAbs(dx / 5) < 1 else dx / 5

        self.setRotation(self.rotation() + dx)
        self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
コード例 #9
0
ファイル: guideline.py プロジェクト: Axel-Erfurt/pyqt5
class GuideLine(Guide):
    def __init__(self, line_or_point, follows=None):
        super(GuideLine, self).__init__(follows)

        if isinstance(line_or_point, QLineF):
            self.line = line_or_point
        elif follows is not None:
            self.line = QLineF(self.prevGuide.endPos(), line_or_point)
        else:
            self.line = QLineF(QPointF(0, 0), line_or_point)

    def length(self):
        return self.line.length()

    def startPos(self):
        return QPointF(self.line.p1().x() * self.scaleX,
                self.line.p1().y() * self.scaleY)

    def endPos(self):
        return QPointF(self.line.p2().x() * self.scaleX,
                self.line.p2().y() * self.scaleY)

    def guide(self, item, moveSpeed):
        frame = item.guideFrame - self.startLength
        endX = (self.line.p1().x() + (frame * self.line.dx() / self.length())) * self.scaleX
        endY = (self.line.p1().y() + (frame * self.line.dy() / self.length())) * self.scaleY
        pos = QPointF(endX, endY)
        self.move(item, pos, moveSpeed)
コード例 #10
0
ファイル: breaks.py プロジェクト: atmelino/CNCMaker
 def intersectLineGeometry(self, lineGeo, breakShape):
     """
     Try to break lineGeo with the given breakShape. Will return the intersection points of lineGeo with breakShape.
     """
     # TODO geos should be abs
     intersections = []
     line = QLineF(lineGeo.Ps.x, lineGeo.Ps.y, lineGeo.Pe.x, lineGeo.Pe.y)
     for breakGeo in breakShape.geos.abs_iter():
         if isinstance(breakGeo, LineGeo):
             breakLine = QLineF(breakGeo.Ps.x, breakGeo.Ps.y, breakGeo.Pe.x, breakGeo.Pe.y)
             intersection = QPointF(0, 0)  # values do not matter
             res = line.intersect(breakLine, intersection)
             if res == QLineF.BoundedIntersection:
                 intersections.append(Point(intersection.x(), intersection.y()))
     return intersections
コード例 #11
0
ファイル: base.py プロジェクト: gitter-badger/eddy
    def intersection(self, line):
        """
        Returns the intersection of the shape with the given line (in scene coordinates).
        :type line: QLineF
        :rtype: QPointF
        """
        intersection = QPointF()
        path = self.painterPath()
        polygon = self.mapToScene(path.toFillPolygon(self.transform()))

        for i in range(0, polygon.size() - 1):
            polyline = QLineF(polygon[i], polygon[i + 1])
            if polyline.intersect(line, intersection) == QLineF.BoundedIntersection:
                return intersection

        return None
コード例 #12
0
ファイル: uiMethods.py プロジェクト: anthrotype/trufont
def rotateUIPointAroundRefLine(x1, y1, x2, y2, pt):
    """
    Given three points p1, p2, pt this rotates pt around p2 such that p1,p2 and
    p1,pt are collinear.
    """
    line = QLineF(pt.x, pt.y, x2, y2)
    p2p_l = line.length()
    line.setP1(QPointF(x1, y1))
    p1p2_l = line.length()
    if not p1p2_l:
        return
    line.setLength(p1p2_l + p2p_l)
    pt.x = line.x2()
    pt.y = line.y2()
コード例 #13
0
ファイル: elasticnodes.py プロジェクト: heylenz/python27
    def paint(self, painter, option, widget):
        if not self.source or not self.dest:
            return

        # Draw the line itself.
        line = QLineF(self.sourcePoint, self.destPoint)

        if line.length() == 0.0:
            return

        painter.setPen(QPen(Qt.black, 1, Qt.SolidLine, Qt.RoundCap,
                Qt.RoundJoin))
        painter.drawLine(line)

        # Draw the arrows if there's enough room.
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = Edge.TwoPi - angle

        sourceArrowP1 = self.sourcePoint + QPointF(math.sin(angle + Edge.Pi / 3) * self.arrowSize,
                                                          math.cos(angle + Edge.Pi / 3) * self.arrowSize)
        sourceArrowP2 = self.sourcePoint + QPointF(math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize,
                                                          math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize);   
        destArrowP1 = self.destPoint + QPointF(math.sin(angle - Edge.Pi / 3) * self.arrowSize,
                                                      math.cos(angle - Edge.Pi / 3) * self.arrowSize)
        destArrowP2 = self.destPoint + QPointF(math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize,
                                                      math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize)

        painter.setBrush(Qt.black)
        painter.drawPolygon(QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]))
        painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2]))
コード例 #14
0
    def setWedgeGizmo(self, neighbor_virtual_helix: int,
                            neighbor_virtual_helix_item: GridVirtualHelixItemT):
        """Adds a WedgeGizmo to oriented toward the specified neighbor vhi.

        Called by NucleicAcidPartItem _refreshVirtualHelixItemGizmos, in between
        with beginAddWedgeGizmos and endAddWedgeGizmos.

        Args:
            neighbor_virtual_helix: the id_num of neighboring virtual helix
            neighbor_virtual_helix_item:
            the neighboring virtual helix item
        """
        wg_dict = self.wedge_gizmos
        nvhi = neighbor_virtual_helix_item

        nvhi_name = nvhi.getProperty('name')
        pos = self.scenePos()
        line = QLineF(pos, nvhi.scenePos())
        line.translate(_RADIUS, _RADIUS)
        if line.length() > (_RADIUS*1.99):
            color = '#5a8bff'
        else:
            color = '#cc0000'
            nvhi_name = nvhi_name + '*'  # mark as invalid
        line.setLength(_RADIUS)
        if neighbor_virtual_helix in wg_dict:
            wedge_item = wg_dict[neighbor_virtual_helix]
        else:
            wedge_item = WedgeGizmo(_RADIUS, WEDGE_RECT, self)
            wg_dict[neighbor_virtual_helix] = wedge_item
        wedge_item.showWedge(line.angle(), color, outline_only=False)
        self._added_wedge_gizmos.add(neighbor_virtual_helix)
コード例 #15
0
ファイル: bar.py プロジェクト: sdouglas/lr-notebook
 def getNeighbors(self):
     items = filter(lambda x: type(x) is VirtualHelixItem, self.collidingItems())
     name = self._virtual_helix.getName()
     pos = self.scenePos()
     print("\n%s (%d, %d)" % (name, pos.x(), pos.y()))
     for nvhi in items:
         npos = nvhi.scenePos()
         line = QLineF(pos, npos)
         print("\t%s (%d, %d) %d" % (nvhi.virtualHelix().getName(), npos.x(), npos.y(), line.length()))
コード例 #16
0
ファイル: E5ArrowItem.py プロジェクト: pycom/EricShort
 def paint(self, painter, option, widget=None):
     """
     Public method to paint the item in local coordinates.
     
     @param painter reference to the painter object (QPainter)
     @param option style options (QStyleOptionGraphicsItem)
     @param widget optional reference to the widget painted on (QWidget)
     """
     if (option.state & QStyle.State_Selected) == \
             QStyle.State(QStyle.State_Selected):
         width = 2
     else:
         width = 1
     
     # draw the line first
     line = QLineF(self._origin, self._end)
     painter.setPen(
         QPen(Qt.black, width, Qt.SolidLine, Qt.FlatCap, Qt.MiterJoin))
     painter.drawLine(line)
     
     # draw the arrow head
     arrowAngle = self._type * ArrowheadAngleFactor
     slope = math.atan2(line.dy(), line.dx())
     
     # Calculate left arrow point
     arrowSlope = slope + arrowAngle
     a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
                  self._end.y() - self._halfLength * math.sin(arrowSlope))
     
     # Calculate right arrow point
     arrowSlope = slope - arrowAngle
     a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope),
                  self._end.y() - self._halfLength * math.sin(arrowSlope))
     
     if self._filled:
         painter.setBrush(Qt.black)
     else:
         painter.setBrush(Qt.white)
     polygon = QPolygonF()
     polygon.append(line.p2())
     polygon.append(a1)
     polygon.append(a2)
     painter.drawPolygon(polygon)
コード例 #17
0
ファイル: explorer_edge.py プロジェクト: c-geek/sakia
    def paint(self, painter, option, widget):
        """
        Customize line adding an arrow head

        :param QPainter painter: Painter instance of the item
        :param option:  Painter option of the item
        :param widget:  Widget instance
        """
        if not self.source or not self.destination:
            return
        line = QLineF(self.source_point, self.destination_point)
        if qFuzzyCompare(line.length(), 0):
            return

        # Draw the line itself
        color = QColor()
        color.setHsv(120 - 60 / self.steps_max * self.steps,
                     180 + 50 / self.steps_max * self.steps,
                     150 + 80 / self.steps_max * self.steps)
        if self.highlighted:
            color.setHsv(0, 0, 0)

        style = self.line_style

        painter.setPen(QPen(color, 1, style, Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(line)
        painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))

        # Draw the arrows
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (2.0 * math.pi) - angle

        #  arrow in the middle of the arc
        hpx = line.p1().x() + (line.dx() / 2.0)
        hpy = line.p1().y() + (line.dy() / 2.0)
        head_point = QPointF(hpx, hpy)

        painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        destination_arrow_p1 = head_point + QPointF(
            math.sin(angle - math.pi / 3) * self.arrow_size,
            math.cos(angle - math.pi / 3) * self.arrow_size)
        destination_arrow_p2 = head_point + QPointF(
            math.sin(angle - math.pi + math.pi / 3) * self.arrow_size,
            math.cos(angle - math.pi + math.pi / 3) * self.arrow_size)

        painter.setBrush(color)
        painter.drawPolygon(QPolygonF([head_point, destination_arrow_p1, destination_arrow_p2]))

        if self.metadata["confirmation_text"]:
            painter.drawText(head_point, self.metadata["confirmation_text"])
コード例 #18
0
ファイル: wot.py プロジェクト: zero-code/sakia
    def paint(self, painter, option, widget):
        """
        Customize line adding an arrow head

        :param QPainter painter: Painter instance of the item
        :param option:  Painter option of the item
        :param widget:  Widget instance
        """
        if not self.source or not self.destination:
            return
        line = QLineF(self.source_point, self.destination_point)
        if qFuzzyCompare(line.length(), 0):
            return

        # Draw the line itself
        color = QColor()
        style = Qt.SolidLine
        if self.status == ARC_STATUS_STRONG:
            color.setNamedColor('blue')
        if self.status == ARC_STATUS_WEAK:
            color.setNamedColor('salmon')
            style = Qt.DashLine

        painter.setPen(QPen(color, 1, style, Qt.RoundCap, Qt.RoundJoin))
        painter.drawLine(line)
        painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))

        # Draw the arrows
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (2.0 * math.pi) - angle

        #  arrow in the middle of the arc
        hpx = line.p1().x() + (line.dx() / 2.0)
        hpy = line.p1().y() + (line.dy() / 2.0)
        head_point = QPointF(hpx, hpy)

        painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        destination_arrow_p1 = head_point + QPointF(
            math.sin(angle - math.pi / 3) * self.arrow_size,
            math.cos(angle - math.pi / 3) * self.arrow_size)
        destination_arrow_p2 = head_point + QPointF(
            math.sin(angle - math.pi + math.pi / 3) * self.arrow_size,
            math.cos(angle - math.pi + math.pi / 3) * self.arrow_size)

        painter.setBrush(color)
        painter.drawPolygon(QPolygonF([head_point, destination_arrow_p1, destination_arrow_p2]))

        if self.metadata["confirmation_text"]:
            painter.drawText(head_point, self.metadata["confirmation_text"])
コード例 #19
0
ファイル: board.py プロジェクト: thesmartwon/OpenChess-Python
    def paint(self, painter, option, widget):
        assert self.fromSquare is not None
        assert self.toSquare is not None
        line = QLineF(self.sourcePoint, self.destPoint)

        assert(line.length() != 0.0)

        # Draw the arrows if there's enough room.
        angle = math.acos(line.dx() / line.length())
        if line.dy() >= 0:
            angle = (math.pi*2.0) - angle

        destArrowP1 = self.destPoint + QPointF(
                math.sin(angle - math.pi / 3) * self.arrowSize,
                math.cos(angle - math.pi / 3) * self.arrowSize
        )
        destArrowP2 = self.destPoint + QPointF(
                math.sin(angle - math.pi + math.pi / 3) * self.arrowSize,
                math.cos(angle - math.pi + math.pi / 3) * self.arrowSize
        )

        painter.setPen(self.pen)
        painter.setBrush(self.brush)
        # arrowhead1 = QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2])
        arrowhead2 = QPolygonF([line.p2(), destArrowP1, destArrowP2])
        painter.drawPolygon(arrowhead2)

        painter.setPen(self.pen)
        painter.drawLine(line)
コード例 #20
0
ファイル: Connectors.py プロジェクト: examon/opengeode
 def angle_arrow(self, path, origin='head'):
     ''' Compute the two points of the arrow head with the right angle '''
     if origin == 'tail':
         path = path.toReversed()
     length = path.length()
     percent = path.percentAtLength(length - 10.0)
     src = path.pointAtPercent(percent)
     #path.moveTo(path.pointAtPercent(1))
     end_point = path.pointAtPercent(1)
     #end_point = path.currentPosition()
     line = QLineF(src, end_point)
     angle = math.acos(line.dx() / (line.length() or 1))
     if line.dy() >= 0:
         angle = math.pi * 2 - angle
     arrow_size = 10.0
     arrow_p1 = end_point + QPointF(
             math.sin(angle - math.pi / 3) * arrow_size,
             math.cos(angle - math.pi / 3) * arrow_size)
     arrow_p2 = end_point + QPointF(
             math.sin(angle - math.pi + math.pi / 3) * arrow_size,
             math.cos(angle - math.pi + math.pi / 3) * arrow_size)
     return (arrow_p1, arrow_p2)
コード例 #21
0
    def paint(self, painter, option, widget=None):
        if self.my_start_item.collidesWithItem(self.my_end_item):
            return

        my_start_item = self.my_start_item
        my_end_item = self.my_end_item
        my_color = self.my_color
        my_pen = self.pen()
        my_pen.setColor(self.my_color)
        arrow_size = 20.0
        painter.setPen(my_pen)
        painter.setBrush(my_color)

        center_line = QLineF(my_start_item.pos(), my_end_item.pos())
        end_polygon = my_end_item.polygon

        p1 = end_polygon.first() + my_end_item.pos()

        intersect_point = QPointF()
        for i in end_polygon:
            p2 = i + my_end_item.pos()
            poly_line = QLineF(p1, p2)
            intersect_type = poly_line.intersect(center_line, intersect_point)
            if intersect_type == QLineF.BoundedIntersection:
                break
            p1 = p2

        self.setLine(QLineF(intersect_point, my_start_item.pos()))
        line = self.line()

        angle = math.acos(line.dx() / line.length())

        if line.dy() >= 0:
            angle = (math.pi * 2) - angle

        arrow_p1 = line.p1() + QPointF(math.sin(angle + math.pi / 3.0) * arrow_size,
                                       math.cos(angle + math.pi / 3) * arrow_size)
        arrow_p2 = line.p1() + QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrow_size,
                                       math.cos(angle + math.pi - math.pi / 3.0) * arrow_size)

        self.arrowHead.clear()
        for point in [line.p1(), arrow_p1, arrow_p2]:
            self.arrowHead.append(point)

        painter.drawLine(line)
        painter.drawPolygon(self.arrowHead)
        if self.isSelected():
            painter.setPen(QPen(my_color, 1, Qt.DashLine))
            my_line = QLineF(line)
            my_line.translate(0, 4.0)
            painter.drawLine(my_line)
            my_line.translate(0, -8.0)
            painter.drawLine(my_line)
コード例 #22
0
ファイル: AssociationItem.py プロジェクト: testmana2/eric
 def __findRectIntersectionPoint(self, item, p1, p2):
     """
     Private method to find the intersetion point of a line with a
     rectangle.
     
     @param item item to check against
     @param p1 first point of the line (QPointF)
     @param p2 second point of the line (QPointF)
     @return the intersection point (QPointF)
     """
     rect = self.__mapRectFromItem(item)
     lines = [
         QLineF(rect.topLeft(), rect.topRight()),
         QLineF(rect.topLeft(), rect.bottomLeft()),
         QLineF(rect.bottomRight(), rect.bottomLeft()),
         QLineF(rect.bottomRight(), rect.topRight()),
     ]
     intersectLine = QLineF(p1, p2)
     intersectPoint = QPointF(0, 0)
     for line in lines:
         if intersectLine.intersect(line, intersectPoint) == QLineF.BoundedIntersection:
             return intersectPoint
     return QPointF(-1.0, -1.0)
コード例 #23
0
ファイル: elasticnodes.py プロジェクト: heylenz/python27
    def calculateForces(self):
        if not self.scene() or self.scene().mouseGrabberItem() is self:
            self.newPos = self.pos()
            return
    
        # Sum up all forces pushing this item away.
        xvel = 0.0
        yvel = 0.0
        for item in self.scene().items():
            if not isinstance(item, Node):
                continue

            line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0))
            dx = line.dx()
            dy = line.dy()
            l = 2.0 * (dx * dx + dy * dy)
            if l > 0:
                xvel += (dx * 150.0) / l
                yvel += (dy * 150.0) / l

        # Now subtract all forces pulling items together.
        weight = (len(self.edgeList) + 1) * 10.0
        for edge in self.edgeList:
            if edge.sourceNode() is self:
                pos = self.mapFromItem(edge.destNode(), 0, 0)
            else:
                pos = self.mapFromItem(edge.sourceNode(), 0, 0)
            xvel += pos.x() / weight
            yvel += pos.y() / weight
    
        if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1:
            xvel = yvel = 0.0

        sceneRect = self.scene().sceneRect()
        self.newPos = self.pos() + QPointF(xvel, yvel)
        self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
        self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
コード例 #24
0
ファイル: uiMethods.py プロジェクト: khaledhosny/trufont
def moveUIPoint(contour, point, delta):
    if point.segmentType is None:
        # point is an offCurve. Get its sibling onCurve and the other
        # offCurve.
        siblings = _getOffCurveSiblingPoints(contour, point)
        # if an onCurve is selected, the offCurve will move along with it
        if not siblings:
            return
        point.move(delta)
        for onCurve, otherPoint in siblings:
            if not onCurve.smooth:
                continue
            # if the onCurve is smooth, we need to either...
            if otherPoint.segmentType is None and not otherPoint.selected:
                # keep the other offCurve inline
                line = QLineF(point.x, point.y, onCurve.x, onCurve.y)
                otherLine = QLineF(
                    onCurve.x, onCurve.y, otherPoint.x, otherPoint.y)
                line.setLength(line.length() + otherLine.length())
                otherPoint.x = line.x2()
                otherPoint.y = line.y2()
            else:
                # keep point in tangency with onCurve -> otherPoint segment,
                # i.e. do an orthogonal projection
                point.x, point.y, _ = bezierMath.lineProjection(
                    onCurve.x, onCurve.y, otherPoint.x, otherPoint.y,
                    point.x, point.y, False)
    else:
        # point is an onCurve. Move its offCurves along with it.
        index = contour.index(point)
        point.move(delta)
        for d in (-1, 1):
            # edge-case: contour open, trailing offCurve and moving first
            # onCurve in contour
            if contour.open and index == 0 and d == -1:
                continue
            pt = contour.getPoint(index + d)
            if pt.segmentType is None:
                # avoid double move for qCurve with single offCurve
                if d > 0:
                    otherPt = contour.getPoint(index + 2 * d)
                    if otherPt.segmentType is not None and \
                            otherPt.segmentType != "move" and otherPt.selected:
                        continue
                pt.move(delta)
                maybeProjectUISmoothPointOffcurve(contour, point)
    contour.dirty = True
コード例 #25
0
ファイル: wot.py プロジェクト: sethkontny/cutecoin
    def adjust(self):
        """
        Draw the arc line
        """
        if not self.source or not self.destination:
            return
        line = QLineF(
            self.mapFromItem(
                self.source,
                self.source.boundingRect().width() - (self.source.boundingRect().width() / 2.0),
                self.source.boundingRect().height() / 2.0
            ),
            self.mapFromItem(
                self.destination,
                self.destination.boundingRect().width() / 2.0,
                self.destination.boundingRect().height() / 2.0
            )
        )
        self.prepareGeometryChange()
        self.source_point = line.p1()
        self.destination_point = line.p2()

        # mouse over on line only
        self.setLine(line)
コード例 #26
0
ファイル: elasticnodes.py プロジェクト: heylenz/python27
    def adjust(self):
        if not self.source or not self.dest:
            return

        line = QLineF(self.mapFromItem(self.source, 0, 0),
                self.mapFromItem(self.dest, 0, 0))
        length = line.length()

        self.prepareGeometryChange()

        if length > 20.0:
            edgeOffset = QPointF((line.dx() * 10) / length,
                    (line.dy() * 10) / length)

            self.sourcePoint = line.p1() + edgeOffset
            self.destPoint = line.p2() - edgeOffset
        else:
            self.sourcePoint = line.p1()
            self.destPoint = line.p1()
コード例 #27
0
ファイル: rulerTool.py プロジェクト: mandel59/trufont
 def mouseMoveEvent(self, event):
     path, text = self._rulerObject
     baseElem = path.elementAt(0)
     canvasPos = event.localPos()
     if event.modifiers() & Qt.ShiftModifier:
         basePos = QPointF(baseElem.x, baseElem.y)
         canvasPos = self.clampToOrigin(canvasPos, basePos)
     canvasPos = self.magnetPos(canvasPos)
     x, y = canvasPos.x(), canvasPos.y()
     path.setElementPositionAt(1, x, baseElem.y)
     path.setElementPositionAt(2, x, y)
     path.setElementPositionAt(3, baseElem.x, baseElem.y)
     line = QLineF(baseElem.x, baseElem.y, x, y)
     l = line.length()
     # angle() doesnt go by trigonometric direction. Weird.
     # TODO: maybe split in positive/negative 180s (ff)
     a = 360 - line.angle()
     line.setP2(QPointF(x, baseElem.y))
     h = line.length()
     line.setP1(QPointF(x, y))
     v = line.length()
     text = "%d\n↔ %d\n↕ %d\nα %dº" % (l, h, v, a)
     self._rulerObject = (path, text)
     self.parent().update()
コード例 #28
0
ファイル: graph.py プロジェクト: zhaoruixbj/blink-qt
    def paintEvent(self, event):
        option = QStyleOption()
        option.initFrom(self)

        contents_rect = self.style().subElementRect(
            QStyle.SE_FrameContents, option, self
        ) or self.contentsRect(
        )  # the SE_FrameContents rect is Null unless the stylesheet defines decorations

        if self.graphStyle == self.BarStyle:
            graph_width = self.__dict__['graph_width'] = int(
                ceil(
                    float(contents_rect.width()) /
                    self.horizontalPixelsPerUnit))
        else:
            graph_width = self.__dict__['graph_width'] = int(
                ceil(
                    float(contents_rect.width() - 1) /
                    self.horizontalPixelsPerUnit) + 1)

        max_value = self.__dict__['max_value'] = max(
            chain([0],
                  *(islice(reversed(graph.data), graph_width)
                    for graph in self.graphs if graph.enabled)))

        if self.graphHeight == self.AutomaticHeight or self.graphHeight < 0:
            graph_height = self.__dict__['graph_height'] = max(
                self.scaler.get_height(max_value), self.minHeight)
        else:
            graph_height = self.__dict__['graph_height'] = max(
                self.graphHeight, self.minHeight)

        if self.graphStyle == self.BarStyle:
            height_scaling = float(contents_rect.height()) / graph_height
        else:
            height_scaling = float(contents_rect.height() -
                                   self.lineThickness) / graph_height

        painter = QStylePainter(self)
        painter.drawPrimitive(QStyle.PE_Widget, option)

        painter.setClipRect(contents_rect)

        painter.save()
        painter.translate(contents_rect.x() + contents_rect.width() - 1,
                          contents_rect.y() + contents_rect.height() - 1)
        painter.scale(-1, -1)

        painter.setRenderHint(QStylePainter.Antialiasing,
                              self.graphStyle != self.BarStyle)

        for graph in (graph for graph in self.graphs
                      if graph.enabled and graph.data):
            if self.boundary is not None and 0 < self.boundary < graph_height:
                boundary_width = min(5.0 / height_scaling, self.boundary - 0,
                                     graph_height - self.boundary)
                pen_color = QLinearGradient(
                    0, (self.boundary - boundary_width) * height_scaling, 0,
                    (self.boundary + boundary_width) * height_scaling)
                pen_color.setColorAt(0, graph.color)
                pen_color.setColorAt(1, graph.over_boundary_color)
                brush_color = QLinearGradient(
                    0, (self.boundary - boundary_width) * height_scaling, 0,
                    (self.boundary + boundary_width) * height_scaling)
                brush_color.setColorAt(
                    0, self.color_with_alpha(graph.color,
                                             self.fillTransparency))
                brush_color.setColorAt(
                    1,
                    self.color_with_alpha(graph.over_boundary_color,
                                          self.fillTransparency))
            else:
                pen_color = graph.color
                brush_color = self.color_with_alpha(graph.color,
                                                    self.fillTransparency)
            dataset = islice(reversed(graph.data), graph_width)
            if self.graphStyle == self.BarStyle:
                lines = [
                    QLineF(x * self.horizontalPixelsPerUnit, 0,
                           x * self.horizontalPixelsPerUnit,
                           y * height_scaling) for x, y in enumerate(dataset)
                ]
                painter.setPen(QPen(pen_color, self.lineThickness))
                painter.drawLines(lines)
            else:
                painter.translate(0, +self.lineThickness / 2 - 1)

                if self.smoothEnvelope and self.smoothFactor > 0:
                    min_value = 0
                    max_value = graph_height * height_scaling
                    cx_offset = self.horizontalPixelsPerUnit / 3.0
                    smoothness = self.smoothFactor

                    last_values = deque(
                        3 * [next(dataset) * height_scaling], maxlen=3
                    )  # last 3 values: 0 last, 1 previous, 2 previous previous

                    envelope = QPainterPath()
                    envelope.moveTo(0, last_values[0])
                    for x, y in enumerate(dataset, 1):
                        x = x * self.horizontalPixelsPerUnit
                        y = y * height_scaling * (
                            1 - smoothness) + last_values[0] * smoothness
                        last_values.appendleft(y)
                        c1x = x - cx_offset * 2
                        c2x = x - cx_offset
                        c1y = limit(
                            (1 + smoothness) * last_values[1] -
                            smoothness * last_values[2], min_value, max_value
                        )  # same gradient as previous previous value to previous value
                        c2y = limit(
                            (1 - smoothness) * last_values[0] +
                            smoothness * last_values[1], min_value, max_value
                        )  # same gradient as previous value to last value
                        envelope.cubicTo(c1x, c1y, c2x, c2y, x, y)
                else:
                    envelope = QPainterPath()
                    envelope.addPolygon(
                        QPolygonF([
                            QPointF(x * self.horizontalPixelsPerUnit,
                                    y * height_scaling)
                            for x, y in enumerate(dataset)
                        ]))

                if self.fillEnvelope or graph.fill_envelope:
                    first_element = envelope.elementAt(0)
                    last_element = envelope.elementAt(envelope.elementCount() -
                                                      1)
                    fill_path = QPainterPath()
                    fill_path.moveTo(last_element.x, last_element.y)
                    fill_path.lineTo(last_element.x + 1, last_element.y)
                    fill_path.lineTo(last_element.x + 1, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, -self.lineThickness)
                    fill_path.lineTo(-self.lineThickness, first_element.y)
                    fill_path.connectPath(envelope)
                    painter.fillPath(fill_path, brush_color)

                painter.strokePath(
                    envelope,
                    QPen(pen_color, self.lineThickness, join=Qt.RoundJoin))

                painter.translate(0, -self.lineThickness / 2 + 1)

        if self.boundary is not None and self.boundaryColor:
            painter.setRenderHint(QStylePainter.Antialiasing, False)
            painter.setPen(QPen(self.boundaryColor, 1.0))
            painter.drawLine(0, self.boundary * height_scaling,
                             contents_rect.width(),
                             self.boundary * height_scaling)

        painter.restore()

        # queue the 'updated' signal to be emitted after returning to the main loop
        QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
コード例 #29
0
 def showAt(self, initialPosition):
     self.start = initialPosition
     self.end = initialPosition
     self.setLine(QLineF(self.start, self.end))
     self.show()
コード例 #30
0
    def resetLine(self):
        self.direction = ""
        if self.fromLocation == None and self.toLocation == None:
            return

        if self.fromLocation == None:
            #self.toLocation.edges[self.boxName]="left"
            x2 = self.toLocation.x() + self.toLocation.rect.x()
            y2 = self.toLocation.y() + self.toLocation.rect.x(
            ) + self.toLocation.rect.height() * 0.3
            x1 = x2 - 30
            y1 = y2
        elif self.toLocation == None:
            #self.fromLocation.edges[self.boxName]="right"
            x1 = self.fromLocation.x() + self.fromLocation.rect.x(
            ) + self.fromLocation.rect.width()
            y1 = self.fromLocation.y() + self.fromLocation.rect.y(
            ) + self.fromLocation.rect.height() * 0.3
            x2 = x1 + 30
            y2 = y1
        else:
            adjustX1 = self.fromLocation.x() + self.fromLocation.rect.x()
            adjustX2 = self.toLocation.x() + self.toLocation.rect.x()
            adjustY1 = self.fromLocation.y() + self.fromLocation.rect.y()
            adjustY2 = self.toLocation.y() + self.toLocation.rect.y()
            if self.fromLocation.boxName == self.toLocation.boxName:
                self.drawLine2Self()
                self.fromLocation.edgeToSelf = self.boxName
                return
            x_diff = self.toLocation.x() - self.fromLocation.x()
            y_diff = self.toLocation.y() - self.fromLocation.y()
            x_diff_standand = (self.fromLocation.rect.width() +
                               self.toLocation.rect.width()) / 2
            y_diff_standand = (self.fromLocation.rect.height() +
                               self.toLocation.rect.height()) / 2
            if ((abs(y_diff) < y_diff_standand)):
                if x_diff > 0:

                    self.direction = "x>"

                    self.fromLocation.edges[self.boxName] = "right"
                    self.toLocation.edges[self.boxName] = "left"
                    x1 = self.fromLocation.rect.width() + adjustX1
                    y1 = self.fromLocation.rect.height() * 0.4 + adjustY1
                    x2 = adjustX2
                    y2 = self.toLocation.rect.height() * 0.4 + adjustY2
                else:
                    self.direction = "x<"
                    self.fromLocation.edges[self.boxName] = "left"
                    self.toLocation.edges[self.boxName] = "right"
                    x1 = adjustX1
                    y1 = self.fromLocation.rect.height() * 0.6 + adjustY1
                    x2 = self.toLocation.rect.width() + adjustX2
                    y2 = self.toLocation.rect.height() * 0.6 + adjustY2
            elif ((abs(x_diff) < x_diff_standand)):
                if (y_diff > 0):
                    self.direction = "y>"

                    self.fromLocation.edges[self.boxName] = "bottom"
                    self.toLocation.edges[self.boxName] = "top"
                    x1 = self.fromLocation.rect.width() * 0.4 + adjustX1
                    y1 = self.fromLocation.rect.height() + adjustY1
                    x2 = self.toLocation.rect.width() * 0.4 + adjustX2
                    y2 = adjustY2
                else:
                    self.direction = "y<"
                    self.fromLocation.edges[self.boxName] = "top"
                    self.toLocation.edges[self.boxName] = "bottom"
                    x1 = self.fromLocation.rect.width() * 0.6 + adjustX1
                    y1 = adjustY1
                    x2 = self.toLocation.rect.width() * 0.6 + adjustX2
                    y2 = self.toLocation.rect.height() + adjustY2
            else:
                if (x_diff > 0) and (y_diff > 0):
                    self.direction = "xy>"
                    self.fromLocation.edges[self.boxName] = "right"
                    self.toLocation.edges[self.boxName] = "top"
                    x1 = self.fromLocation.rect.width() + adjustX1
                    y1 = self.fromLocation.rect.height() * 0.8 + adjustY1
                    x2 = self.toLocation.rect.width() * 0.2 + adjustX2
                    y2 = adjustY2
                elif ((x_diff < 0) and (y_diff < 0)):
                    self.direction = "xy<"
                    self.fromLocation.edges[self.boxName] = "left"
                    self.toLocation.edges[self.boxName] = "bottom"
                    x1 = adjustX1
                    y1 = self.fromLocation.rect.height() * 0.2 + adjustY1
                    x2 = self.toLocation.rect.width() * 0.8 + adjustX2
                    y2 = self.toLocation.rect.height() + adjustY2
                elif (x_diff > 0) and (y_diff < 0):
                    self.direction = "x>y<"
                    self.fromLocation.edges[self.boxName] = "top"
                    self.toLocation.edges[self.boxName] = "left"
                    x1 = self.fromLocation.rect.width() * 0.8 + adjustX1
                    y1 = adjustY1
                    x2 = adjustX2
                    y2 = self.toLocation.rect.height() * 0.8 + adjustY2
                else:
                    self.direction = "x<y>"
                    self.fromLocation.edges[self.boxName] = "bottom"
                    self.toLocation.edges[self.boxName] = "right"
                    x1 = self.fromLocation.rect.width() * 0.2 + adjustX1
                    y1 = adjustY1 + self.fromLocation.rect.height()
                    x2 = adjustX2 + self.toLocation.rect.width()
                    y2 = self.toLocation.rect.height() * 0.2 + adjustY2
        self.direction = self.direction + " fLX:" + str(
            self.fromLocation.x()) + ",fLrx" + str(
                self.fromLocation.rect.x()) + ",fLrw" + str(
                    self.fromLocation.rect.width()) + ",Lx" + str(x1)
        self.source = QPointF(x1, y1)
        self.dest = QPointF(x2, y2)
        self.line = QLineF(self.source, self.dest)
        self.line.setLength(self.line.length() - 5)
コード例 #31
0
def calcArrow(srcdes_list,itemignoreZooming,iconScale):
    ''' if PoolItem then boundingrect should be background rather than graphicsobject '''
    src = srcdes_list[0]
    des = srcdes_list[1]
    endtype = srcdes_list[2]
    order = srcdes_list[3]
    # print("Source => ", src)
    compartment = src.parentItem()
    srcobj = src.gobj
    desobj = des.gobj
    if isinstance(src,PoolItem):
        srcobj = src.bg
    if isinstance(des,PoolItem):
        desobj = des.bg
            
    # if itemignoreZooming:
    #     srcRect = self.recalcSceneBoundingRect(srcobj)
    #     desRect = self.recalcSceneBoundingRect(desobj)
    # else:
    srcRect = compartment.mapFromScene(srcobj.sceneBoundingRect()).boundingRect()
    desRect = compartment.mapFromScene(desobj.sceneBoundingRect()).boundingRect()
    arrow = QPolygonF()
    if srcRect.intersects(desRect):                
        ''' This is created for getting a emptyline reference \
            because 'lineCord' function keeps a reference between qgraphicsline and its src and des
        '''
        arrow.append(QPointF(0,0))
        arrow.append(QPointF(0,0))
        return arrow
    if (order == 0):
        tmpLine = QLineF(srcRect.center().x(),
                                srcRect.center().y(),
                                desRect.center().x(),
                                desRect.center().y())
    elif(order > 0):
        dx = desRect.center().x()- srcRect.center().x()
        dy = desRect.center().y()- srcRect.center().y()
        dx0 = dy
        dy0 = -dx
        tetha1 = (atan2(dy0,dx0))
        a0 = 4 *(cos(tetha1))
        b0 = 4 *(sin(tetha1))
        ''' Higher order ( > 4) connectivity will not be done'''
        if ((order == 3) or (order == 4)):
            a0 = a0*2
            b0 = b0*2
        if(order %2 == 0):
            srcCentera0 = srcRect.center().x()-a0
            srcCenterb0 = srcRect.center().y()-b0
            desCentera0 = desRect.center().x()-a0
            desCenterb0 = desRect.center().y()-b0
        else:
            srcCentera0 = srcRect.center().x()+a0
            srcCenterb0 = srcRect.center().y()+b0
            desCentera0 = desRect.center().x()+a0
            desCenterb0 = desRect.center().y()+b0
        pointa = QPointF(srcCentera0,srcCenterb0)
        pointb = QPointF(desCentera0,desCenterb0)
        tmpLine = QLineF(srcCentera0,srcCenterb0,desCentera0,desCenterb0)

    srcIntersects, lineSrcPoint = calcLineRectIntersection(srcRect, tmpLine)
    destIntersects, lineDestPoint = calcLineRectIntersection(desRect, tmpLine)

    if not srcIntersects:
        print('Source does not intersect line. Arrow points:',lineSrcPoint,src.mobj.name, src.mobj.className)
    if not destIntersects:
        print('Dest does not intersect line. Arrow points:', lineDestPoint,  des.mobj.name, des.mobj.className)

    '''src and des are connected with line co-ordinates
       Arrow head is drawned if the distance between src and des line is >8 just for clean appeareance
    '''
    if (abs(lineSrcPoint.x()-lineDestPoint.x()) > 8 or abs(lineSrcPoint.y()-lineDestPoint.y())>8):
        srcAngle = tmpLine.angle()
        if endtype == 'p' or endtype == 'stp':
            ''' Arrow head for Destination is calculated'''
            arrow.append(lineSrcPoint)
            arrow.append(lineDestPoint)
            degree = -60
            srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineDestPoint,iconScale)
            arrow.append(QPointF(srcXArr1,srcYArr1))
            arrow.append(QPointF(lineDestPoint.x(),lineDestPoint.y()))
                
            degree = -120
            srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineDestPoint,iconScale)
            arrow.append(QPointF(srcXArr2,srcYArr2))                    
            arrow.append(QPointF(lineDestPoint.x(),lineDestPoint.y()))
 
        elif endtype == 'st':
            ''' Arrow head for Source is calculated'''
            arrow.append(lineDestPoint)
            arrow.append(lineSrcPoint)
            degree = 60
            srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineSrcPoint,iconScale)
            arrow.append(QPointF(srcXArr2,srcYArr2))                    
            arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y()))

            degree = 120
            srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineSrcPoint,iconScale)
            arrow.append(QPointF(srcXArr1,srcYArr1))
            arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y()))

        elif endtype == 's' or endtype == 'sts':
            arrow.append(lineDestPoint)
            arrow.append(lineSrcPoint)
            
            degree = 60
            srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineSrcPoint,iconScale)
            arrow.append(QPointF(srcXArr2,srcYArr2))                    
            arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y()))

            degree = 120
            srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineSrcPoint,iconScale)
            arrow.append(QPointF(srcXArr1,srcYArr1))
            arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y()))
        else:
            arrow.append(lineSrcPoint)
            arrow.append(lineDestPoint)
    return arrow
コード例 #32
0
 def paint(self, qp, style_option_view_item, model_index):
     mid = model_index.data()
     if type(mid) is ClassifiedImageBundle:
         qp.save()
         qp.drawImage(style_option_view_item.rect.left() + 4,
                      style_option_view_item.rect.top() + 4,
                      mid.get_thumb())
         qp.setRenderHint(QPainter.Antialiasing)
         qp.setRenderHint(QPainter.HighQualityAntialiasing)
         if mid.has_color():
             qp.setPen(
                 QPen(QBrush(mid.get_color()), 4.0,
                      Qt.DotLine if mid.is_classified() else Qt.SolidLine,
                      Qt.SquareCap, Qt.RoundJoin))
             lines_to_draw = []
             len_of_all_lines = 2 * (mid.get_thumb().height() +
                                     mid.get_thumb().width() + 12)
             line_start_pos = -1 * min(
                 0, mid.animation_progress) * len_of_all_lines
             if mid.animation_progress >= 0:
                 line_end_pos = mid.animation_progress * len_of_all_lines
             else:
                 line_end_pos = 1 * len_of_all_lines
             tx = style_option_view_item.rect.left() + 2
             ty = style_option_view_item.rect.top() + 2
             h = mid.get_thumb().height() + 4
             w = mid.get_thumb().width() + 4
             if line_start_pos <= h and 0 < line_end_pos:
                 lines_to_draw.append(
                     QLineF(tx, ty + line_start_pos, tx,
                            ty + min(h, line_end_pos)))
             if line_start_pos <= h + w and h < line_end_pos:
                 lines_to_draw.append(
                     QLineF(tx + max(line_start_pos, h) - h, ty + h,
                            tx + min(h + w, line_end_pos) - h, ty + h))
             if line_start_pos <= 2 * h + w and h + w < line_end_pos:
                 lines_to_draw.append(
                     QLineF(tx + w,
                            ty + h - (max(line_start_pos - h - w, 0)),
                            tx + w,
                            ty + h - (min(line_end_pos - h - w, h))))
             if line_start_pos <= 2 * h + 2 * w and 2 * h + w < line_end_pos:
                 lines_to_draw.append(
                     QLineF(tx + w - (max(line_start_pos - 2 * h - w, 0)),
                            ty, tx + w - (min(line_end_pos - 2 * h - w, w)),
                            ty))
             qp.drawLines(lines_to_draw)
         if mid.keep or mid.keep is None or mid.get_show_buttons():
             qp.setBrush(QColor(0, 255, 0))
             qp.setPen(
                 QPen(QBrush(QColor(0, 255, 0)), 1.0, Qt.SolidLine,
                      Qt.SquareCap, Qt.RoundJoin))
             qp.drawEllipse(
                 style_option_view_item.rect.left() +
                 mid.get_thumb().width() - 30,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 30, 30, 30)
             qp.setPen(
                 QPen(QBrush(QColor(255, 255, 255)), 6.0, Qt.SolidLine,
                      Qt.SquareCap, Qt.RoundJoin))
             qp.drawLines([
                 QLineF(
                     style_option_view_item.rect.left() +
                     mid.get_thumb().width() - 24,
                     style_option_view_item.rect.top() +
                     mid.get_thumb().height() - 13,
                     style_option_view_item.rect.left() +
                     mid.get_thumb().width() - 19,
                     style_option_view_item.rect.top() +
                     mid.get_thumb().height() - 8),
                 QLineF(
                     style_option_view_item.rect.left() +
                     mid.get_thumb().width() - 19,
                     style_option_view_item.rect.top() +
                     mid.get_thumb().height() - 8,
                     style_option_view_item.rect.left() +
                     mid.get_thumb().width() - 7,
                     style_option_view_item.rect.top() +
                     mid.get_thumb().height() - 20)
             ])
         if (mid.keep is not None
                 and not mid.keep) or mid.get_show_buttons():
             qp.setBrush(QColor(255, 0, 0))
             qp.setPen(
                 QPen(QBrush(QColor(255, 0, 0)), 1.0, Qt.SolidLine,
                      Qt.SquareCap, Qt.RoundJoin))
             qp.drawEllipse(
                 style_option_view_item.rect.left() + 8,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 30, 30, 30)
             qp.setPen(
                 QPen(QBrush(QColor(255, 255, 255)), 6.0, Qt.SolidLine,
                      Qt.SquareCap, Qt.RoundJoin))
             qp.drawLine(
                 style_option_view_item.rect.left() + 16,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 22,
                 style_option_view_item.rect.left() + 30,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 8)
             qp.drawLine(
                 style_option_view_item.rect.left() + 16,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 8,
                 style_option_view_item.rect.left() + 30,
                 style_option_view_item.rect.top() +
                 mid.get_thumb().height() - 22)
         qp.restore()
     else:
         super().paint(qp, style_option_view_item, model_index)
コード例 #33
0
def make_poly(hull):
    polygon = [
        QLineF(hull[i], hull[(i + 1) % len(hull)]) for i in range(len(hull))
    ]
    return polygon
コード例 #34
0
ファイル: knifeTool.py プロジェクト: pathumego/trufont
class KnifeTool(BaseTool):
    name = "Knife"
    iconPath = ":/resources/cutter.svg"

    def __init__(self, parent=None):
        super().__init__(parent)
        self._cachedIntersections = None
        self._knifeLine = None
        self._knifeDots = None

    def _appendIntersection(self, contour, index, pt, dotHalf, dotWidth):
        dotHeight = dotWidth
        x = pt[0] - dotHalf
        y = pt[1] - dotHalf
        self._knifeDots.addEllipse(x, y, dotWidth, dotHeight)
        if (contour, index) in self._cachedIntersections:
            self._cachedIntersections[(contour, index)].append(
                pt[2])
        else:
            self._cachedIntersections[(contour, index)] = [pt[2]]

    # events

    def mousePressEvent(self, event):
        canvasPos = event.localPos()
        self._knifeLine = QLineF(canvasPos, canvasPos)

    def mouseMoveEvent(self, event):
        line = self._knifeLine
        pos = event.localPos()
        widget = self.parent()
        if event.modifiers() & Qt.ShiftModifier:
            pos = self.clampToOrigin(pos, line.p1())
        line.setP2(pos)
        self._cachedIntersections = OrderedDict()
        scale = widget.inverseScale()
        dotWidth = 5 * scale
        dotHalf = dotWidth / 2.0
        self._knifeDots = QPainterPath()
        for contour in self._glyph:
            segments = contour.segments
            for index, seg in enumerate(segments):
                if seg[-1].segmentType == "move":
                    continue
                prev = segments[index - 1][-1]
                if len(seg) == 3:
                    i = bezierMath.curveIntersections(
                        prev, seg[0], seg[1], seg[2],
                        line.x1(), line.y1(), pos.x(), pos.y())
                    for pt in i:
                        self._appendIntersection(
                            contour, index, pt, dotHalf, dotWidth)
                else:
                    pt = bezierMath.lineIntersection(
                        prev.x, prev.y, seg[0].x, seg[0].y,
                        line.x1(), line.y1(), pos.x(), pos.y())
                    if pt is not None:
                        self._appendIntersection(
                            contour, index, pt, dotHalf, dotWidth)
        widget.update()

    def mouseReleaseEvent(self, event):
        self._knifeLine = None
        self._knifeDots = None
        # no-move clicks
        if self._cachedIntersections is None:
            return
        self._glyph.prepareUndo()
        # reverse so as to not invalidate our cached segment indexes
        for loc, ts in reversed(list(self._cachedIntersections.items())):
            contour, index = loc
            prev = 1
            # reverse so as to cut from higher to lower value and compensate
            for t in sorted(ts, reverse=True):
                contour.splitAndInsertPointAtSegmentAndT(index, t / prev)
                prev = t
        self._cachedIntersections = None
        self.parent().update()

    # custom painting

    def paint(self, painter):
        if self._knifeLine is not None and self._knifeLine.length():
            painter.drawLine(self._knifeLine)
            if self._knifeDots is not None:
                painter.drawPath(self._knifeDots)
コード例 #35
0
ファイル: Draw.py プロジェクト: lemauffcam/OpenETran
    def drawObject(self, qp, coord):
        grid = self.paramBox.layout()
        angle = grid.itemAtPosition(2, 1).widget().text()

        realCoord = readObj(self)

        try:
            slope = float(angle)

            if slope > 45:
                slope = 45.0
            elif slope < -45:
                slope = -45.0

        except ValueError:
            slope = 0.0

        tan = math.tan(math.radians(slope))

        # If the object has a height of 0 we don't need to draw it
        if realCoord[1][0] > 0:
            qp.setPen(QPen(Qt.darkGreen, 5, Qt.SolidLine))

            # Left object (starts from left side until the xCoordinate)
            poly = QPolygonF()

            # Bottom left
            point1 = QPointF(
                self.width() - self.drawView.width(),
                self.drawView.height() + self.drawView.width() * tan / 2)
            poly.append(point1)

            # Top left
            point2 = QPointF(self.width() - self.drawView.width(),
                             coord[8][0] + self.drawView.width() * tan / 2)
            poly.append(point2)

            # Top right
            point3 = QPointF(
                coord[7][0], coord[8][0] + tan *
                (self.width() - self.drawView.width() / 2 - coord[7][0]))
            poly.append(point3)

            # Bottom right
            point4 = QPointF(
                coord[7][0],
                self.drawView.height() + tan *
                (self.width() - self.drawView.width() / 2 - coord[7][0]))
            poly.append(point4)

            path = QPainterPath()
            path.addPolygon(poly)

            qp.drawPolygon(poly)
            qp.fillPath(path, QColor(Qt.darkGreen))

            # Adds striking distance to object line
            qp.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine))
            rg = coord[6]
            line = QLineF(point3.x(),
                          point3.y() - rg, point2.x(),
                          point2.y() - rg)

            qp.drawLine(line)

        # If the object has a height of 0 we don't need to draw it
        if realCoord[1][1] > 0:
            qp.setPen(QPen(Qt.darkGreen, 5, Qt.SolidLine))

            # Right object (starts from right side until the xCoordinate)
            poly = QPolygonF()

            # Bottom left
            point1 = QPointF(
                coord[7][1],
                self.drawView.height() + tan *
                (self.width() - self.drawView.width() / 2 - coord[7][1]))
            poly.append(point1)

            # Top left
            point2 = QPointF(
                coord[7][1], coord[8][1] + tan *
                (self.width() - self.drawView.width() / 2 - coord[7][1]))
            poly.append(point2)

            # Top right
            point3 = QPointF(self.width(),
                             coord[8][1] - self.drawView.width() * tan / 2)
            poly.append(point3)

            # Bottom right
            point4 = QPointF(
                self.width(),
                self.drawView.height() - self.drawView.width() * tan / 2)
            poly.append(point4)

            path = QPainterPath()
            path.addPolygon(poly)

            qp.drawPolygon(poly)
            qp.fillPath(path, QColor(Qt.darkGreen))

            # Adds striking distance to object line
            qp.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine))
            rg = coord[6]
            line = QLineF(point3.x(),
                          point3.y() - rg, point2.x(),
                          point2.y() - rg)

            qp.drawLine(line)
コード例 #36
0
 def _appendIntersection(self, pt):
     x, y, _ = pt
     line = QLineF(self._rulerObject[0])
     line.setP2(QPointF(x, y))
     self._rulerPts[line.length()] = (x, y)
コード例 #37
0
    def updateEnd(self, point):
        self.end = point
        self.setLine(QLineF(self.start, self.end))

    # hide() is inherited
コード例 #38
0
def paint_axes(p: QPainter,
               xtick_every=0,
               ytick_every=0,
               xlabels="down",
               ylabels="left",
               opacity=0.5):

    from PyQt5.QtGui import QPen, QColor
    from PyQt5.QtCore import Qt, QLineF

    cur_pen = p.pen()

    color = QColor(Qt.black)
    color.setAlphaF(opacity)
    pen = QPen(color)

    xscale, yscale = scale_of_painter(p)

    xlength = 10000 / xscale
    ylength = 10000 / yscale

    xline_width = 2 / yscale
    yline_width = 2 / xscale

    xtick_length = 10 / yscale
    ytick_length = 10 / xscale

    if not xtick_every:
        xtick_every = 50 / xscale

    if not ytick_every:
        ytick_every = 50 / yscale

    pen.setWidthF(xline_width)
    p.setPen(pen)
    p.drawLine(-xlength / 2, 0, xlength / 2, 0)

    pen.setWidthF(yline_width)
    p.setPen(pen)
    p.drawLine(0, -ylength / 2, 0, ylength / 2)

    p.save()

    for i in range(int(xlength / 2 / xtick_every)):
        p.translate(xtick_every, 0)
        p.drawLine(QLineF(0, -xtick_length / 2, 0, xtick_length / 2))

    p.restore()
    p.save()

    for i in range(int(xlength / 2 / xtick_every)):
        p.translate(-xtick_every, 0)
        p.drawLine(QLineF(0, -xtick_length / 2, 0, xtick_length / 2))

    p.restore()
    p.save()

    pen.setWidthF(xline_width)
    p.setPen(pen)

    for i in range(int(ylength / 2 / ytick_every)):
        p.translate(0, ytick_every)
        p.drawLine(QLineF(-ytick_length / 2, 0, ytick_length / 2, 0))

    p.restore()
    p.save()

    for i in range(int(ylength / 2 / ytick_every)):
        p.translate(0, -ytick_every)
        p.drawLine(QLineF(-ytick_length / 2, 0, ytick_length / 2, 0))

    p.restore()
コード例 #39
0
class ArrowLine(object):
    def __init__(self, x1, y1, x2, y2, fromNode=None, endNode=None):
        self.__source = QPointF(x1, y1)
        self.__dest = QPointF(x2, y2)
        self.__line = QLineF(self.__source, self.__dest)

        self.__arrowLen = 10
        # self.__line.setLength(self.__line.length() - self.__arrowLen)
        self.__penWidth = 2
        self.__pen = QPen()
        self.__brush = QBrush()
        self.__color = QColor(255, 0, 0)
        self.__arrowRatio = 1.0
        self.__isSolid = True
        self.__fromNode = fromNode
        self.__endNode = endNode

    def GetFromNode(self):
        return self.__fromNode

    def GetEndNode(self):
        return self.__endNode

    def SetArrowLen(self, length):
        self.__arrowLen = length

    def GetArrowLen(self):
        return self.__arrowLen

    def SetPenWidth(self, width):
        self.__penWidth = width

    def GetPenWidth(self):
        return self.__penWidth

    def SetArrowSolid(self, flag):
        self.__isSolid = flag

    def IsArrowSolid(self):
        return self.__isSolid

    def SetColor(self, color):
        self.__color = color

    def GetColor(self):
        return self.__color

    def GetLine(self):
        return self.__line

    def Paint(self, QPainter):
        # setPen
        self.__pen.setWidth(self.__penWidth)
        self.__pen.setColor(self.__color)
        QPainter.setPen(self.__pen)

        # setBrush
        if self.__isSolid:
            self.__brush.setColor(self.__color)
            self.__brush.setStyle(Qt.SolidPattern)
            QPainter.setBrush(self.__brush)

        v = self.__line.unitVector()
        v.setLength(self.__arrowLen)
        v.translate(
            QPointF(self.__line.dx() * self.__arrowRatio,
                    self.__line.dy() * self.__arrowRatio))

        # width of arrow
        n = v.normalVector()
        n.setLength(n.length() * 0.5)
        n2 = n.normalVector().normalVector()

        QPainter.drawLine(self.__line)
        QPainter.drawPolygon(v.p2(), n.p2(), n2.p2())
コード例 #40
0
class GraphicEdge(QGraphicsPathItem):

    def __init__(self, edge_wrap, directed, parent=None):
        super().__init__(parent)
        self.edge_wrap = edge_wrap
        self.width = 3.0
        self.pos_src = [0, 0]
        self.pos_dst = [0, 0]
        # 是否有向
        self.directed = directed
        self.flag = 0
        self.capacity = self.edge_wrap.capacity

        self.setAcceptHoverEvents(True)
        # 普通画图时的pen样式
        self._n_pen = QPen(QColor("#000"))
        self._n_pen.setWidthF(self.width)
        # 画图时的pen样式
        self._pen = self._n_pen
        # 悬浮时的pen样式
        self._hover_pen = QPen(Qt.green)
        self._hover_pen.setWidthF(self.width)
        # 拖拽时的样式
        self._pen_dragging = QPen(QColor("#000"))
        self._pen_dragging.setStyle(Qt.DashDotLine)
        self._pen_dragging.setWidthF(self.width)

        self._mark_brush = QBrush()
        self._mark_brush.setColor(Qt.green)
        self._mark_brush.setStyle(Qt.SolidPattern)

        self._normal_brush = QBrush()
        self._normal_brush.setColor(Qt.black)
        self._normal_brush.setStyle(Qt.SolidPattern)

        self.brush = self._normal_brush

        self.setFlag(QGraphicsItem.ItemIsSelectable)
        self.setZValue(-1)

    def set_src(self, x, y):
        self.pos_src = [x, y]

    def set_dst(self, x, y):
        self.pos_dst = [x, y]

    def calc_path(self):
        path = QPainterPath(QPointF(self.pos_src[0], self.pos_src[1]))  # 起点
        path.lineTo(QPointF(self.pos_dst[0], self.pos_dst[1]))  # 终点
        if self.directed:
            # 画箭头
            self.line = QLineF(QPointF(self.pos_src[0], self.pos_src[1]), QPointF(self.pos_dst[0], self.pos_dst[1]))
            if self.flag == 0:
                self.line.setLength(self.line.length() - 20)
            else:
                self.line.setLength(self.line.length() - self.edge_wrap.end_item.r)
            v = self.line.unitVector()
            v.setLength(20)
            v.translate(QPointF(self.line.dx(), self.line.dy()))

            n = v.normalVector()
            n.setLength(n.length() * 0.5)
            n2 = n.normalVector().normalVector()

            p1 = v.p2()
            p2 = n.p2()
            p3 = n2.p2()
            # 方法2
            arrow = QPolygonF([p1, p2, p3, p1])
            path.addPolygon(arrow)
        # path = QPainterPath(QPointF(self.pos_src[0], self.pos_src[1]))
        # path.lineTo(self.pos_dst[0], self.pos_dst[1])
        return path

    def boundingRect(self):
        return self.shape().boundingRect()

    def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent'):
        self.brush = self._mark_brush
        self._pen = self._hover_pen
        self.update()

    def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent'):
        self.brush = self._normal_brush
        self._pen = self._n_pen
        self.update()

    def shape(self):
        # 设置宽度 这里用了100 很大
        qps = QPainterPathStroker()
        qps.setWidth(100)
        return qps.createStroke(self.calc_path())

    def paint(self, painter, graphics_item, widget=None):

        if self.edge_wrap.end_item is None:
            self.ensureVisible()
            self.setPath(self.calc_path())
            path = self.path()

            painter.setPen(self._pen_dragging)
            painter.setBrush(self.brush)
            painter.drawPath(path)
        else:
            # 这画的才是连接后的线
            self.flag = 1
            self.setPath(self.calc_path())  # 设置路径
            path = self.path()
            painter.setPen(self._pen)
            painter.setBrush(self.brush)
            painter.drawPath(path)
            self.flag = 0
            painter.setFont(QFont("Times New Roman", 16))
            painter.setPen(Qt.red)
            x = int((self.pos_src[0] + self.pos_dst[0]) / 2 - 17)
            y = int((self.pos_src[1] + self.pos_dst[1]) / 2 - 7)
            painter.drawText(x, y, "({}) {}".format(self.edge_wrap.id, self.capacity))
コード例 #41
0
    def lineage(self):
        global lineage
        self._zoom
        if lineage:
            lineage = False
            perc = 10
            zoomline = self._photo.pixmap().width()
            if zoomline > 256 and zoomline < 512:
                perc = 2
            elif zoomline > 512 and zoomline < 1024:
                perc = 3
            addedLine = QLineF(240 / 2, 33 / perc, 240 / 2, 223 / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, 33 / perc, 230 / 2, 33 / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, 71 / perc, 230 / 2, 71 / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 - 19) / perc, 235 / 2,
                               (71 - 19) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 19) / perc, 235 / 2,
                               (71 + 19) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38) / perc, 230 / 2,
                               (71 + 38) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38 + 38) / perc, 230 / 2,
                               (71 + 38 + 38) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38 + 19) / perc, 235 / 2,
                               (71 + 38 + 19) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38 + 38 + 38) / perc, 230 / 2,
                               (71 + 38 + 38 + 38) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38 + 38 + 19) / perc, 235 / 2,
                               (71 + 38 + 38 + 19) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, (71 + 38 + 38 + 38 + 19) / perc,
                               230 / 2, (71 + 38 + 38 + 38 + 19) / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))
            addedLine = QLineF(240 / 2, 223 / perc, 230 / 2, 223 / perc)
            self._scene.addLine(addedLine, QColor(0, 0, 0))

            if perc == 2:
                needFont = self._scene.addText("5cm", QtGui.QFont(
                    "Times", 30)).setDefaultTextColor(QColor(255, 255, 255))
            elif perc == 1:
                needFont = self._scene.addText("10cm", QtGui.QFont(
                    "Times", 30)).setDefaultTextColor(QColor(0, 0, 0))
            else:
                needFont = self._scene.addText("20cm", QtGui.QFont(
                    "Times", 30)).setDefaultTextColor(QColor(0, 0, 0))
        else:
            self._scene.clear()
            self._scene = QtWidgets.QGraphicsScene(self)
            self._photo = QtWidgets.QGraphicsPixmapItem()
            self._scene.addItem(self._photo)
            self.setScene(self._scene)
            self.setTransformationAnchor(
                QtWidgets.QGraphicsView.AnchorUnderMouse)
            self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
            self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
            self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
            self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
            self.setFrameShape(QtWidgets.QFrame.NoFrame)
            lineage = True
コード例 #42
0
ファイル: knifeTool.py プロジェクト: yalvex/trufont
class KnifeTool(BaseTool):
    icon = _path
    name = QApplication.translate("KnifeTool", "Knife")
    shortcut = "E"

    def __init__(self, parent=None):
        super().__init__(parent)
        self._cachedIntersections = None
        self._knifeLine = None
        self._knifePts = None

    def _appendIntersection(self, contour, index, pt):
        x, y, t = pt
        self._knifePts.append((x, y))
        if (contour, index) in self._cachedIntersections:
            self._cachedIntersections[(contour, index)].append(t)
        else:
            self._cachedIntersections[(contour, index)] = [t]

    def _findIntersections(self):
        self._cachedIntersections = OrderedDict()
        self._knifePts = []
        line = self._knifeLine
        for contour in self._glyph:
            segments = contour.segments
            for index, seg in enumerate(segments):
                if seg[-1].segmentType == "move":
                    continue
                prev = segments[index - 1][-1]
                if len(seg) == 3:
                    if seg[-1].segmentType == "qcurve":
                        i = bezierMath.qcurveIntersections(
                            line.x1(), line.y1(), line.x2(), line.y2(), prev,
                            *seg)
                    else:
                        i = bezierMath.curveIntersections(
                            line.x1(),
                            line.y1(),
                            line.x2(),
                            line.y2(),
                            prev,
                            seg[0],
                            seg[1],
                            seg[2],
                        )
                    for pt in i:
                        self._appendIntersection(contour, index, pt)
                elif len(seg) == 1:
                    pt = bezierMath.lineIntersection(
                        prev.x,
                        prev.y,
                        seg[0].x,
                        seg[0].y,
                        line.x1(),
                        line.y1(),
                        line.x2(),
                        line.y2(),
                    )
                    if pt is not None:
                        self._appendIntersection(contour, index, pt)

    # events

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            pos = event.localPos()
            self._knifeLine = QLineF(pos, pos)
        else:
            super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            pos = event.localPos()
            if self._knifeLine is None:
                self._knifeLine = QLineF(pos, pos)
                return
            line = self._knifeLine
            if event.modifiers() & Qt.ShiftModifier:
                pos = self.clampToOrigin(pos, line.p1())
            line.setP2(pos)
            self._findIntersections()
            self.parent().update()
        else:
            super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if event.button() != Qt.LeftButton:
            super().mouseReleaseEvent(event)
            return
        if self._knifeLine is not None:
            p1, p2 = self._knifeLine.p1(), self._knifeLine.p2()
        self._knifeLine = None
        self._knifePts = None
        self.parent().update()
        # no-move clicks
        if not self._cachedIntersections:
            return
        self._glyph.beginUndoGroup()
        cutContours = (not event.modifiers() & Qt.AltModifier
                       and len(self._cachedIntersections) > 1)
        if cutContours:
            oldPts = {pt for contour in self._glyph for pt in contour}
            path = self._glyph.getRepresentation("defconQt.QPainterPath")
        # reverse so as to not invalidate our cached segment indexes
        for loc, ts in reversed(list(self._cachedIntersections.items())):
            contour, index = loc
            prev = 1
            # reverse so as to cut from higher to lower value and compensate
            for t in sorted(ts, reverse=True):
                contour.splitAndInsertPointAtSegmentAndT(index, t / prev)
                prev = t
        # TODO: optimize
        if cutContours:
            newPts = {
                pt
                for contour in self._glyph for pt in contour if pt.segmentType
            } - oldPts
            del oldPts

            distances = dict()
            for point in newPts:
                d = bezierMath.distance(p1.x(), p1.y(), point.x, point.y)
                distances[d] = point
            del newPts

            sortedPts = [distances[dist] for dist in sorted(distances.keys())]
            del distances

            # group points by belonging to contour "black area"
            siblings = []
            stack = None
            if not path.contains(p1):
                stack = []
            for pt, nextPt in zip(sortedPts, sortedPts[1:]):
                qPt = QPointF(pt.x, pt.y)
                qHalf = qPt + 0.5 * (QPointF(nextPt.x, nextPt.y) - qPt)
                if path.contains(qHalf):
                    if stack is not None:
                        stack.append(pt)
                else:
                    if stack:
                        stack.append(pt)
                        siblings.extend(stack)
                    stack = []
            if not path.contains(p2):
                if stack:
                    stack.append(nextPt)
                    siblings.extend(stack)
            del stack

            # ok, now i = siblings.index(loc); siblings[i+1-2(i%2)] will yield
            # sibling
            newGlyph = self._glyph.__class__()
            pen = newGlyph.getPointPen()

            def _visitPath(contour, index):
                didJump = False
                pen.beginPath()
                while True:
                    pt = contour.getPoint(index)
                    if pt in visited:
                        pen.endPath()
                        break
                    if pt not in siblings:
                        visited.add(pt)
                    segmentType = pt.segmentType
                    smooth = pt.smooth
                    if didJump or pt in siblings:
                        smooth = False
                        if didJump:
                            segmentType = "line"
                    pen.addPoint((pt.x, pt.y), segmentType, smooth)
                    if pt in siblings and not didJump:
                        i = siblings.index(pt)
                        otherPt = siblings[i + 1 - 2 * (i % 2)]
                        # TODO: optimize-out this lookup
                        for c in self._glyph:
                            try:
                                index = c.index(otherPt)
                            except Exception:
                                pass
                            else:
                                contour = c
                                break
                        didJump = True
                        continue
                    didJump = False
                    index += 1

            visited = set()
            for contour in self._glyph:
                for index, pt in enumerate(contour):
                    if pt in visited or pt in siblings:
                        continue
                    _visitPath(contour, index)
            self._glyph.clearContours()
            pen = self._glyph.getPointPen()
            newGlyph.drawPoints(pen)
        self._glyph.endUndoGroup()
        ##
        self._cachedIntersections = None

    # custom painting

    def paint(self, painter, index):
        widget = self.parent()
        if index != widget.activeIndex():
            return
        line = self._knifeLine
        if line is not None and line.length():
            painter.save()
            pen = painter.pen()
            pen.setWidth(0)
            painter.setPen(pen)
            drawing.drawLine(painter, line.x1(), line.y1(), line.x2(),
                             line.y2())
            if self._knifePts is not None:
                scale = widget.inverseScale()
                dotSize = 5 * scale
                dotHalf = dotSize / 2
                path = QPainterPath()
                for x, y in self._knifePts:
                    x -= dotHalf
                    y -= dotHalf
                    path.addEllipse(x, y, dotSize, dotSize)
                painter.drawPath(path)
            painter.restore()
コード例 #43
0
 def __on_lineEdited(self, line):
     p1, p2 = map(self.item.mapFromScene, (line.p1(), line.p2()))
     self.item.setLine(QLineF(p1, p2))
コード例 #44
0
    def timerEvent(self):
        # Don't move too far away.
        lineToCenter = QLineF(QPointF(0, 0), self.mapFromScene(0, 0))
        if lineToCenter.length() > 150:
            angleToCenter = math.acos(lineToCenter.dx() /
                                      lineToCenter.length())
            if lineToCenter.dy() < 0:
                angleToCenter = Mouse.TwoPi - angleToCenter
            angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) +
                                                 Mouse.Pi / 2)

            if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4:
                # Rotate left.
                self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2]
            elif angleToCenter >= Mouse.Pi and angleToCenter < (
                    Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4):
                # Rotate right.
                self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2]
        elif math.sin(self.angle) < 0:
            self.angle += 0.25
        elif math.sin(self.angle) > 0:
            self.angle -= 0.25

        # Try not to crash with any other mice.
        dangerMice = self.scene().items(
            QPolygonF([
                self.mapToScene(0, 0),
                self.mapToScene(-30, -50),
                self.mapToScene(30, -50)
            ]))

        for item in dangerMice:
            if item is self:
                continue

            lineToMouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0))
            angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length())
            if lineToMouse.dy() < 0:
                angleToMouse = Mouse.TwoPi - angleToMouse
            angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) +
                                                Mouse.Pi / 2)

            if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2:
                # Rotate right.
                self.angle += 0.5
            elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi -
                                                                 Mouse.Pi / 2):
                # Rotate left.
                self.angle -= 0.5

        # Add some random movement.
        if len(dangerMice) > 1 and (qrand() % 10) == 0:
            if qrand() % 1:
                self.angle += (qrand() % 100) / 500.0
            else:
                self.angle -= (qrand() % 100) / 500.0

        self.speed += (-50 + qrand() % 100) / 100.0

        dx = math.sin(self.angle) * 10
        self.mouseEyeDirection = 0.0 if qAbs(dx / 5) < 1 else dx / 5

        self.setRotation(self.rotation() + dx)
        self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
コード例 #45
0
ファイル: knifeTool.py プロジェクト: yalvex/trufont
 def mousePressEvent(self, event):
     if event.button() == Qt.LeftButton:
         pos = event.localPos()
         self._knifeLine = QLineF(pos, pos)
     else:
         super().mousePressEvent(event)
コード例 #46
0
 def short_domain(side, f=0.3):
     r = side.unitVector()
     r = -r.p1() + r.p2()
     p1 = side.p1() + r * (self.a - self.a * f)
     p2 = side.p2()  # - r * self.a * f
     return QLineF(p1, p2)
コード例 #47
0
    def showWedge(self,
                  angle,
                  color,
                  extended=False,
                  rev_gradient=False,
                  outline_only=False):
        """Summary

        Args:
            angle (TYPE): Description
            color (TYPE): Description
            extended (bool, optional): Description
            rev_gradient (bool, optional): Description
            outline_only (bool, optional): Description
        """
        # Hack to keep wedge in front
        # self.setRotation(self.pre_xover_item_group.rotation())

        self._last_params = (angle, color, extended, rev_gradient,
                             outline_only)
        radius = self._radius
        span = self.pre_xover_item_group.partCrossoverSpanAngle() / 2
        radius_adjusted = radius + (_WEDGE_RECT_GAIN / 2)

        tip = QPointF(radius_adjusted, radius_adjusted)
        EXT = 1.35 if extended else 1.0

        # print("wtf", tip, pos)
        base_p2 = QPointF(1, 1)

        line0 = QLineF(tip, QPointF(base_p2))
        line1 = QLineF(tip, QPointF(base_p2))
        line2 = QLineF(tip, QPointF(base_p2))

        quad_scale = 1 + (.22 *
                          (span - 5) / 55)  # lo+(hi-lo)*(val-min)/(max-min)
        line0.setLength(radius_adjusted * EXT *
                        quad_scale)  # for quadTo control point
        line1.setLength(radius_adjusted * EXT)
        line2.setLength(radius_adjusted * EXT)
        line0.setAngle(angle)
        line1.setAngle(angle - span)
        line2.setAngle(angle + span)

        path = QPainterPath()

        if outline_only:
            self.setPen(getPenObj(color, 0.5, alpha=128, capstyle=Qt.RoundCap))
            path.moveTo(line1.p2())
            path.quadTo(line0.p2(), line2.p2())
        else:
            gradient = QRadialGradient(tip, radius_adjusted * EXT)
            color1 = getColorObj(color, alpha=80)
            color2 = getColorObj(color, alpha=0)
            if rev_gradient:
                color1, color2 = color2, color1

            if extended:
                gradient.setColorAt(0, color1)
                gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT),
                                    color1)
                gradient.setColorAt(
                    radius_adjusted / (radius_adjusted * EXT) + 0.01, color2)
                gradient.setColorAt(1, color2)
            else:
                gradient.setColorAt(0, getColorObj(color, alpha=50))
            brush = QBrush(gradient)
            self.setBrush(brush)

            path.moveTo(line1.p1())
            path.lineTo(line1.p2())
            path.quadTo(line0.p2(), line2.p2())
            path.lineTo(line2.p1())

        self.setPath(path)
        self.show()
コード例 #48
0
 def _boundJoystick(self, point):
     limitLine = QLineF(self._center(), point)
     if (limitLine.length() > self.__maxDistance):
         limitLine.setLength(self.__maxDistance)
     return limitLine.p2()
コード例 #49
0
 def long_domain(side, f=0.6):
     r = side.unitVector()
     r = -r.p1() + r.p2()
     p1 = side.p1()
     p2 = side.p2() - r * self.a * 0.4
     return QLineF(p1, p2)
コード例 #50
0
ファイル: _ohlc.py プロジェクト: ajmal017/piker
    def update_from_array(
        self,
        array: np.ndarray,
        just_history=False,
    ) -> None:
        """Update the last datum's bar graphic from input data array.

        This routine should be interface compatible with
        ``pg.PlotCurveItem.setData()``. Normally this method in
        ``pyqtgraph`` seems to update all the data passed to the
        graphics object, and then update/rerender, but here we're
        assuming the prior graphics havent changed (OHLC history rarely
        does) so this "should" be simpler and faster.

        This routine should be made (transitively) as fast as possible.
        """
        # index = self.start_index
        istart, istop = self._xrange

        index = array['index']
        first_index, last_index = index[0], index[-1]

        # length = len(array)
        prepend_length = istart - first_index
        append_length = last_index - istop

        flip_cache = False

        # TODO: allow mapping only a range of lines thus
        # only drawing as many bars as exactly specified.

        if prepend_length:

            # new history was added and we need to render a new path
            new_bars = array[:prepend_length]
            prepend_path = gen_qpath(new_bars, 0, self.w)

            # XXX: SOMETHING IS MAYBE FISHY HERE what with the old_path
            # y value not matching the first value from
            # array[prepend_length + 1] ???

            # update path
            old_path = self.path
            self.path = prepend_path
            self.path.addPath(old_path)

            # trigger redraw despite caching
            self.prepareGeometryChange()

        if append_length:
            # generate new lines objects for updatable "current bar"
            self._last_bar_lines = lines_from_ohlc(array[-1], self.w)

            # generate new graphics to match provided array
            # path appending logic:
            # we need to get the previous "current bar(s)" for the time step
            # and convert it to a sub-path to append to the historical set
            # new_bars = array[istop - 1:istop + append_length - 1]
            new_bars = array[-append_length - 1:-1]
            append_path = gen_qpath(new_bars, 0, self.w)
            self.path.moveTo(float(istop - self.w), float(new_bars[0]['open']))
            self.path.addPath(append_path)

            # trigger redraw despite caching
            self.prepareGeometryChange()
            self.setCacheMode(QtGui.QGraphicsItem.NoCache)
            flip_cache = True

        self._xrange = first_index, last_index

        # last bar update
        i, o, h, l, last, v = array[-1][
            ['index', 'open', 'high', 'low', 'close', 'volume']
        ]
        # assert i == self.start_index - 1
        assert i == last_index
        body, larm, rarm = self._last_bar_lines

        # XXX: is there a faster way to modify this?
        rarm.setLine(rarm.x1(), last, rarm.x2(), last)
        # writer is responsible for changing open on "first" volume of bar
        larm.setLine(larm.x1(), o, larm.x2(), o)

        if l != h:  # noqa
            if body is None:
                body = self._last_bar_lines[0] = QLineF(i, l, i, h)
            else:
                # update body
                body.setLine(i, l, i, h)

            # XXX: pretty sure this is causing an issue where the bar has
            # a large upward move right before the next sample and the body
            # is getting set to None since the next bar is flat but the shm
            # array index update wasn't read by the time this code runs. Iow
            # we're doing this removal of the body for a bar index that is
            # now out of date / from some previous sample. It's weird
            # though because i've seen it do this to bars i - 3 back?

        self.update()

        if flip_cache:
            self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
コード例 #51
0
ファイル: _ohlc.py プロジェクト: pikers/piker
    def update_from_array(
        self,

        # full array input history
        ohlc: np.ndarray,

        # pre-sliced array data that's "in view"
        ohlc_iv: np.ndarray,

        view_range: Optional[tuple[int, int]] = None,
        profiler: Optional[pg.debug.Profiler] = None,

    ) -> None:
        '''
        Update the last datum's bar graphic from input data array.

        This routine should be interface compatible with
        ``pg.PlotCurveItem.setData()``. Normally this method in
        ``pyqtgraph`` seems to update all the data passed to the
        graphics object, and then update/rerender, but here we're
        assuming the prior graphics havent changed (OHLC history rarely
        does) so this "should" be simpler and faster.

        This routine should be made (transitively) as fast as possible.

        '''
        profiler = profiler or pg.debug.Profiler(
            disabled=not pg_profile_enabled(),
            gt=ms_slower_then,
            delayed=True,
        )

        # index = self.start_index
        istart, istop = self._xrange
        ds_istart, ds_istop = self._ds_xrange

        index = ohlc['index']
        first_index, last_index = index[0], index[-1]

        # length = len(ohlc)
        # prepend_length = istart - first_index
        # append_length = last_index - istop

        # ds_prepend_length = ds_istart - first_index
        # ds_append_length = last_index - ds_istop

        flip_cache = False

        x_gt = 16
        if self._ds_line:
            uppx = self._ds_line.x_uppx()
        else:
            uppx = 0

        should_line = self._in_ds
        if (
            self._in_ds
            and uppx < x_gt
        ):
            should_line = False

        elif (
            not self._in_ds
            and uppx >= x_gt
        ):
            should_line = True

        profiler('ds logic complete')

        if should_line:
            # update the line graphic
            # x, y = self._ds_line_xy = ohlc_flatten(ohlc_iv)
            x, y = self._ds_line_xy = ohlc_flatten(ohlc)
            x_iv, y_iv = self._ds_line_xy = ohlc_flatten(ohlc_iv)
            profiler('flattening bars to line')

            # TODO: we should be diffing the amount of new data which
            # needs to be downsampled. Ideally we actually are just
            # doing all the ds-ing in sibling actors so that the data
            # can just be read and rendered to graphics on events of our
            # choice.
            # diff = do_diff(ohlc, new_bit)
            curve = self._ds_line
            curve.update_from_array(
                x=x,
                y=y,
                x_iv=x_iv,
                y_iv=y_iv,
                view_range=None,  # hack
                profiler=profiler,
            )
            profiler('updated ds line')

            if not self._in_ds:
                # hide bars and show line
                self.hide()
                # XXX: is this actually any faster?
                # self._pi.removeItem(self)

                # TODO: a `.ui()` log level?
                log.info(
                    f'downsampling to line graphic {self._name}'
                )

                # self._pi.addItem(curve)
                curve.show()
                curve.update()
                self._in_ds = True

            # stop here since we don't need to update bars path any more
            # as we delegate to the downsample line with updates.
            profiler.finish()
            # print('terminating early')
            return

        else:
            # we should be in bars mode

            if self._in_ds:
                # flip back to bars graphics and hide the downsample line.
                log.info(f'showing bars graphic {self._name}')

                curve = self._ds_line
                curve.hide()
                # self._pi.removeItem(curve)

                # XXX: is this actually any faster?
                # self._pi.addItem(self)
                self.show()
                self._in_ds = False

            # generate in_view path
            self.path = gen_qpath(
                ohlc_iv,
                0,
                self.w,
                # path=self.path,
            )

            # TODO: to make the downsampling faster
            # - allow mapping only a range of lines thus only drawing as
            #   many bars as exactly specified.
            # - move ohlc "flattening" to a shmarr
            # - maybe move all this embedded logic to a higher
            #   level type?

            # if prepend_length:
            #     # new history was added and we need to render a new path
            #     prepend_bars = ohlc[:prepend_length]

            # if ds_prepend_length:
            #     ds_prepend_bars = ohlc[:ds_prepend_length]
            #     pre_x, pre_y = ohlc_flatten(ds_prepend_bars)
            #     fx = np.concatenate((pre_x, fx))
            #     fy = np.concatenate((pre_y, fy))
            #     profiler('ds line prepend diff complete')

            # if append_length:
            #     # generate new graphics to match provided array
            #     # path appending logic:
            #     # we need to get the previous "current bar(s)" for the time step
            #     # and convert it to a sub-path to append to the historical set
            #     # new_bars = ohlc[istop - 1:istop + append_length - 1]
            #     append_bars = ohlc[-append_length - 1:-1]
            #     # print(f'ohlc bars to append size: {append_bars.size}\n')

            # if ds_append_length:
            #     ds_append_bars = ohlc[-ds_append_length - 1:-1]
            #     post_x, post_y = ohlc_flatten(ds_append_bars)
            #     print(
            #         f'ds curve to append sizes: {(post_x.size, post_y.size)}'
            #     )
            #     fx = np.concatenate((fx, post_x))
            #     fy = np.concatenate((fy, post_y))

            #     profiler('ds line append diff complete')

            profiler('array diffs complete')

            # does this work?
            last = ohlc[-1]
            # fy[-1] = last['close']

            # # incremental update and cache line datums
            # self._ds_line_xy = fx, fy

            # maybe downsample to line
            # ds = self.maybe_downsample()
            # if ds:
            #     # if we downsample to a line don't bother with
            #     # any more path generation / updates
            #     self._ds_xrange = first_index, last_index
            #     profiler('downsampled to line')
            #     return

            # print(in_view.size)

            # if self.path:
            #     self.path = path
            #     self.path.reserve(path.capacity())
            #     self.path.swap(path)

            # path updates
            # if prepend_length:
            #     # XXX: SOMETHING IS MAYBE FISHY HERE what with the old_path
            #     # y value not matching the first value from
            #     # ohlc[prepend_length + 1] ???
            #     prepend_path = gen_qpath(prepend_bars, 0, self.w)
            #     old_path = self.path
            #     self.path = prepend_path
            #     self.path.addPath(old_path)
            #     profiler('path PREPEND')

            # if append_length:
            #     append_path = gen_qpath(append_bars, 0, self.w)

            #     self.path.moveTo(
            #         float(istop - self.w),
            #         float(append_bars[0]['open'])
            #     )
            #     self.path.addPath(append_path)

            #     profiler('path APPEND')
            #     fp = self.fast_path
            #     if fp is None:
            #         self.fast_path = append_path

            #     else:
            #         fp.moveTo(
            #             float(istop - self.w), float(new_bars[0]['open'])
            #         )
            #         fp.addPath(append_path)

            #     self.setCacheMode(QtWidgets.QGraphicsItem.NoCache)
            #     flip_cache = True

            self._xrange = first_index, last_index

            # trigger redraw despite caching
            self.prepareGeometryChange()

            # generate new lines objects for updatable "current bar"
            self._last_bar_lines = bar_from_ohlc_row(last, self.w)

            # last bar update
            i, o, h, l, last, v = last[
                ['index', 'open', 'high', 'low', 'close', 'volume']
            ]
            # assert i == self.start_index - 1
            # assert i == last_index
            body, larm, rarm = self._last_bar_lines

            # XXX: is there a faster way to modify this?
            rarm.setLine(rarm.x1(), last, rarm.x2(), last)

            # writer is responsible for changing open on "first" volume of bar
            larm.setLine(larm.x1(), o, larm.x2(), o)

            if l != h:  # noqa

                if body is None:
                    body = self._last_bar_lines[0] = QLineF(i, l, i, h)
                else:
                    # update body
                    body.setLine(i, l, i, h)

                # XXX: pretty sure this is causing an issue where the bar has
                # a large upward move right before the next sample and the body
                # is getting set to None since the next bar is flat but the shm
                # array index update wasn't read by the time this code runs. Iow
                # we're doing this removal of the body for a bar index that is
                # now out of date / from some previous sample. It's weird
                # though because i've seen it do this to bars i - 3 back?

            profiler('last bar set')

            self.update()
            profiler('.update()')

            if flip_cache:
                self.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache)

            profiler.finish()
コード例 #52
0
    def drawRadar(selfself, qp):
        #set frame:
        qp.setBrush(QBrush(QColor(0, 0, 0), Qt.SolidPattern))
        qp.drawRect(20, 10, 700, 700)

        pen_bold = QPen(QColor(102, 204, 255), 0.8, Qt.SolidLine)

        pen = QPen(QColor(102, 204, 255), 0.8, Qt.DashDotLine)

        pen_hide = QPen(QColor(0, 0, 0), 1.5, Qt.SolidLine)

        #add circle:
        qp.setPen(pen)
        qp.drawEllipse(QPointF(370, 360), 347, 347)

        #add scales:
        for i in range(1, 360):
            if i % 30 == 0:
                pass

            else:
                if i % 10 == 0:
                    scaleLine = QLineF()
                    scaleLine.setP1(QPointF(370, 360))
                    scaleLine.setAngle(i)
                    scaleLine.setLength(347)
                    qp.setPen(pen_bold)
                    qp.drawLine(scaleLine)

                    hideLine = QLineF()
                    hideLine.setP1(QPointF(370, 360))
                    hideLine.setAngle(i)
                    hideLine.setLength(337)
                    qp.setPen(pen_hide)
                    qp.drawLine(hideLine)

                else:
                    scaleLine = QLineF()
                    scaleLine.setP1(QPointF(370, 360))
                    scaleLine.setAngle(i)
                    scaleLine.setLength(347)
                    qp.setPen(pen_bold)
                    qp.drawLine(scaleLine)

                    hideLine = QLineF()
                    hideLine.setP1(QPointF(370, 360))
                    hideLine.setAngle(i)
                    hideLine.setLength(342)
                    qp.setPen(pen_hide)
                    qp.drawLine(hideLine)

        #add other circles:
        qp.setPen(pen)
        qp.drawEllipse(QPointF(370, 360), 277, 277)

        qp.setPen(pen)
        qp.drawEllipse(QPointF(370, 360), 207, 207)

        qp.setPen(pen)
        qp.drawEllipse(QPointF(370, 360), 137, 137)

        qp.setPen(pen)
        qp.drawEllipse(QPointF(370, 360), 67, 67)

        #add lines:
        qp.setPen(pen_bold)
        qp.drawLine(20, 360, 720, 360)

        qp.setPen(pen_bold)
        qp.drawLine(370, 10, 370, 710)

        angleLine1 = QLineF()
        angleLine1.setP1(QPointF(370, 360))
        angleLine1.setAngle(30)
        angleLine1.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine1)

        angleLine2 = QLineF()
        angleLine2.setP1(QPointF(370, 360))
        angleLine2.setAngle(60)
        angleLine2.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine2)

        angleLine3 = QLineF()
        angleLine3.setP1(QPointF(370, 360))
        angleLine3.setAngle(120)
        angleLine3.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine3)

        angleLine4 = QLineF()
        angleLine4.setP1(QPointF(370, 360))
        angleLine4.setAngle(150)
        angleLine4.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine4)

        angleLine5 = QLineF()
        angleLine5.setP1(QPointF(370, 360))
        angleLine5.setAngle(210)
        angleLine5.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine5)

        angleLine6 = QLineF()
        angleLine6.setP1(QPointF(370, 360))
        angleLine6.setAngle(240)
        angleLine6.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine6)

        angleLine7 = QLineF()
        angleLine7.setP1(QPointF(370, 360))
        angleLine7.setAngle(300)
        angleLine7.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine7)

        angleLine8 = QLineF()
        angleLine8.setP1(QPointF(370, 360))
        angleLine8.setAngle(330)
        angleLine8.setLength(347)
        qp.setPen(pen)
        qp.drawLine(angleLine8)
コード例 #53
0
 def updatePosition(self):
     line = QLineF(QPointF(*self.end), QPointF(*self.begin))
     self.setLine(line)
     self.shape()
コード例 #54
0
    def drawPath(self, items, useRows):
        """Draws one flight path
		Args
		items -- squares.
		useRows:
			True -- go by rows
			False -- go by cols
		"""
        if useRows:
            way = "row"
            sortFirst = "col"
            oldSide = "left"
            newSide = "right"
            color = QColor(255, 10, 10)
        else:
            way = "col"
            sortFirst = "row"
            oldSide = "top"
            newSide = "bottom"
            color = QColor(10, 255, 10)

        # Pen for main lines
        pen = QPen(color)
        pen.setWidth(2)
        pen.setCosmetic(True)
        # Pen for turning lines
        pen2 = QPen(color)
        pen2.setWidth(2)
        pen2.setStyle(Qt.DashLine)
        pen2.setDashOffset(2)
        pen2.setCosmetic(True)

        # Sort selected items
        items.sort(key=lambda item: item.getRowCol()[sortFirst])
        items.sort(key=lambda item: item.getRowCol()[way])

        def addItem(item):
            self.addItem(item)
            if useRows:
                self.rowLines.append(item)
            else:
                self.colLines.append(item)

        # Draw lines
        newPos = True  # Shows if we're will be at new col/row at next iteration
        prevLine = None  # Previously drawn line
        isLastPointReversed = False  # Shows from which end draw turning line
        for i in range(len(items)):
            item = items[i]
            if newPos:
                side1 = item.getSides()[oldSide]
                newPos = False
            pos = item.getRowCol()[way]
            try:
                nextPos = items[i + 1].getRowCol()[way]
            except:
                nextPos = pos + 1
            if pos != nextPos:
                side2 = item.getSides()[newSide]
                lineF = QLineF(side1, side2)
                line = QGraphicsLineItem(lineF)
                line.setPen(pen)
                addItem(line)
                newPos = True
                if prevLine != None:
                    if isLastPointReversed:
                        start = prevLine.p2()
                        end = side2
                    else:
                        start = prevLine.p1()
                        end = side1
                    newLine = QGraphicsLineItem(QLineF(start, end))
                    newLine.setPen(pen2)
                    addItem(newLine)
                isLastPointReversed = not isLastPointReversed
                prevLine = lineF
コード例 #55
0
ファイル: gridextras.py プロジェクト: cadnano/cadnano2.5
    def showWedge(self, angle, color,
                  extended=False, rev_gradient=False, outline_only=False):
        """Summary

        Args:
            angle (TYPE): Description
            color (TYPE): Description
            extended (bool, optional): Description
            rev_gradient (bool, optional): Description
            outline_only (bool, optional): Description
        """
        # Hack to keep wedge in front
        # self.setRotation(self.pre_xover_item_group.rotation())

        self._last_params = (angle, color, extended, rev_gradient, outline_only)
        radius = self._radius
        span = self.pre_xover_item_group.partCrossoverSpanAngle() / 2
        radius_adjusted = radius + (_WEDGE_RECT_GAIN / 2)

        tip = QPointF(radius_adjusted, radius_adjusted)
        EXT = 1.35 if extended else 1.0

        # print("wtf", tip, pos)
        base_p2 = QPointF(1, 1)

        line0 = QLineF(tip, QPointF(base_p2))
        line1 = QLineF(tip, QPointF(base_p2))
        line2 = QLineF(tip, QPointF(base_p2))

        quad_scale = 1 + (.22*(span - 5) / 55)  # lo+(hi-lo)*(val-min)/(max-min)
        line0.setLength(radius_adjusted * EXT*quad_scale)  # for quadTo control point
        line1.setLength(radius_adjusted * EXT)
        line2.setLength(radius_adjusted * EXT)
        line0.setAngle(angle)
        line1.setAngle(angle - span)
        line2.setAngle(angle + span)

        path = QPainterPath()

        if outline_only:
            self.setPen(getPenObj(color, 0.5, alpha=128, capstyle=Qt.RoundCap))
            path.moveTo(line1.p2())
            path.quadTo(line0.p2(), line2.p2())
        else:
            gradient = QRadialGradient(tip, radius_adjusted * EXT)
            color1 = getColorObj(color, alpha=80)
            color2 = getColorObj(color, alpha=0)
            if rev_gradient:
                color1, color2 = color2, color1

            if extended:
                gradient.setColorAt(0, color1)
                gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT), color1)
                gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT) + 0.01, color2)
                gradient.setColorAt(1, color2)
            else:
                gradient.setColorAt(0, getColorObj(color, alpha=50))
            brush = QBrush(gradient)
            self.setBrush(brush)

            path.moveTo(line1.p1())
            path.lineTo(line1.p2())
            path.quadTo(line0.p2(), line2.p2())
            path.lineTo(line2.p1())

        self.setPath(path)
        self.show()
コード例 #56
0
    def __stepThree(self):
        """Step 3 -- Do basically everything.
		"""

        # Validate data
        def setError(e):
            """Displays string e.
			"""
            self.lblDataError.setText("<html><head/><body><div>" +
                                      self.lang.errData + e +
                                      "</div></body></html>")

        # Try to read data. We need to create fields, because this will be used later in other functions.
        self.xTL = self.__sfloat(self.xTopLeft.text())
        self.xTR = self.__sfloat(self.xTopRight.text())
        self.xBL = self.__sfloat(self.xBottomLeft.text())
        self.xBR = self.__sfloat(self.xBottomRight.text())

        self.yTL = self.__sfloat(self.yTopLeft.text())
        self.yTR = self.__sfloat(self.yTopRight.text())
        self.yBL = self.__sfloat(self.yBottomLeft.text())
        self.yBR = self.__sfloat(self.yBottomRight.text())

        self.xD = self.__sfloat(self.xDelimiter.text())
        self.yD = self.__sfloat(self.yDelimiter.text())

        # Convert delimiters to pixels.
        # Value of another coordinate doesn't matter.
        # If you'll draw a random line and draw crossing lines parallel to one of axes with same distance between these lines by another axis, you'll split your random line into equal pieces.
        # See for yourself:
        # Y
        # ^ ___\_____
        # | ____\____
        # | _____\___
        # |       \
        # |-----------> X
        # You can try it on paper or prove this "theorem" doing some math.
        try:
            self.xDTop = self.width / abs(self.xTL - self.xTR) * self.xD
            self.xDBottom = self.width / abs(self.xBL - self.xBR) * self.xD
            self.yDLeft = self.height / abs(self.yTL - self.yBL) * self.yD
            self.yDRight = self.height / abs(self.yTR - self.yBR) * self.yD
        except ZeroDivisionError:
            setError(self.lang.errCorners)
            return

        # Now do the same stuff, but find how much pixels in one degree.
        # We won't find absolute value for subtraction because axes of image in geographic system may be not codirectional to axes of image in Qt system.
        self.topX = (self.xTR - self.xTL) / self.width
        self.bottomX = (self.xBR - self.xBL) / self.width
        self.leftY = (self.yTL - self.yBL) / self.height
        self.rightY = (self.yTR - self.yBR) / self.height

        # Sides of image in geographic system
        self.top = QLineF(self.xTL, self.yTL, self.xTR, self.yTR)
        self.bottom = QLineF(self.xBL, self.yBL, self.xBR, self.yBR)
        self.left = QLineF(self.xTL, self.yTL, self.xBL, self.yBL)
        self.right = QLineF(self.xTR, self.yTR, self.xBR, self.yBR)

        errors = ""
        if self.xDTop > self.width:
            errors += self.lang.errLongTop + "<br>"
        if self.xDBottom > self.width:
            errors += self.lang.errLongBottom + "<br>"
        if self.yDLeft > self.height:
            errors += self.lang.errLatLeft + "<br>"
        if self.yDRight > self.height:
            errors += self.lang.errLatRight + "<br>"

        if errors != "":
            setError(self.lang.errSides + "<br>" + errors)
            return

        # Check if given coordinates form 8-shaped figure
        if (self.xTL > self.xTR and self.xBL < self.xBR) or (
                self.xTL < self.xTR and self.xBL > self.xBR) or (
                    self.yTL > self.yBL
                    and self.yTR < self.yBR) or (self.yTL < self.yBL
                                                 and self.yTR > self.yTL):
            choice = QMessageBox(QMessageBox.Warning, "AerialWare",
                                 self.lang.warningCoordinates,
                                 QMessageBox.Yes | QMessageBox.No).exec()
            if choice == QMessageBox.No:
                return

        # Draw grid

        # Set points for grid
        # Points will look like:
        # [point, point, ...],
        # [point, point, ...], ...
        pointRows = []
        # Let x1, y1; x2, y2 be vertical line
        # and x3, y3; x4, y4 be horizontal line.
        # Thus, y1 and y2 should be always on top and bottom;
        # x3, x4 -- on left and right
        y1, y2, x3, x4 = 0, self.height, 0, self.width
        # So we have to change:
        #	for vertical line: x1, x2
        #	for horizontal line: y3, y4

        y3 = y4 = 0  # Initial values for horizontal line
        # Move horizontal line
        while y3 <= self.height + self.yDLeft / 2 or y4 <= self.height + self.yDRight / 2:
            x1 = x2 = 0  # Initial values for vertical line
            # Move vertical line
            points = []
            while x1 <= self.width + self.xDTop / 2 or x2 <= self.width + self.xDBottom / 2:
                point = QPointF()
                QLineF.intersect(QLineF(x1, y1, x2, y2),
                                 QLineF(x3, y3, x4, y4), point)
                points.append(point)
                x1 += self.xDTop
                x2 += self.xDBottom
            if points != []:
                pointRows.append(points)
            y3 += self.yDLeft
            y4 += self.yDRight

        # If nothing has been added
        if points == []:
            setError(self.lang.errPoints)
            return

        # Get scene geometry to preserve scene expanding
        rect = self.scene.sceneRect()
        # And add bounds for the grid
        self.bounds = QGraphicsRectItem(rect)
        self.bounds.setFlag(self.bounds.ItemClipsChildrenToShape)
        self.scene.addItem(self.bounds)
        # Create polygons from points
        # We'll recheck previous item
        i = 1  # Rows
        while i < len(pointRows):
            j = 1  # Points
            while j < len(pointRows[i]):
                # Add points in following order: top left, top right, bottom right, bottom left
                points = [
                    pointRows[i - 1][j - 1], pointRows[i - 1][j],
                    pointRows[i][j], pointRows[i][j - 1]
                ]
                # We're assigning self.bounds as parent implicitly, so we shouldn't add polygon to scene by ourselves.
                poly = _QCustomGraphicsPolygonItem(QPolygonF(points),
                                                   self.bounds)
                poly.setRowCol(i - 1, j - 1)
                j += 1
            i += 1
        # Restore scene geometry
        self.scene.setSceneRect(rect)

        self.__turnPage()
        self.btnNext.disconnect()
        self.btnNext.clicked.connect(self.__stepFour)
コード例 #57
0
ファイル: drawing.py プロジェクト: anthrotype/trufont
def _drawGuidelines(painter, glyph, scale, rect, guidelines, drawLines=True,
                    drawText=True, drawSelection=True, color=None):
    if not (drawLines or drawText):
        return
    xMin, yMin, width, height = rect
    xMax = xMin + width
    yMax = yMin + height
    fontSize = painter.font().pointSize()
    for line in guidelines:
        color_ = color
        if color_ is None:
            if line.color:
                color_ = colorToQColor(line.color)
            else:
                color_ = defaultColor("glyphGuideline")
        painter.save()
        painter.setPen(color)
        line1 = None
        if None not in (line.x, line.y):
            if line.angle is not None:
                # make an infinite line that intersects *(line.x, line.y)*
                # 1. make horizontal line from *(line.x, line.y)* of length
                # *diagonal*
                diagonal = math.sqrt(width**2 + height**2)
                line1 = QLineF(line.x, line.y, line.x + diagonal, line.y)
                # 2. set the angle
                # defcon guidelines are clockwise
                line1.setAngle(line.angle)
                # 3. reverse the line and set length to 2 * *diagonal*
                line1.setPoints(line1.p2(), line1.p1())
                line1.setLength(2 * diagonal)
            else:
                line1 = QLineF(xMin, line.y, xMax, line.y)
        textX = 0
        textY = 0
        if drawLines:
            if line1 is not None:
                # line
                drawLine(
                    painter, line1.x1(), line1.y1(), line1.x2(), line1.y2())
                # point
                x, y = line.x, line.y
                smoothWidth = 8 * scale
                smoothHalf = smoothWidth / 2.0
                painter.save()
                pointPath = QPainterPath()
                x -= smoothHalf
                y -= smoothHalf
                pointPath.addEllipse(x, y, smoothWidth, smoothWidth)
                pen = QPen(color_)
                pen.setWidthF(1 * scale)
                painter.setPen(pen)
                if drawSelection and line.selected:
                    painter.fillPath(pointPath, color_)
                painter.drawPath(pointPath)
                painter.restore()
            else:
                if line.y is not None:
                    drawLine(painter, xMin, line.y, xMax, line.y)
                elif line.x is not None:
                    drawLine(painter, line.x, yMin, line.x, yMax)
        if drawText and line.name:
            if line1 is not None:
                textX = line.x
                textY = line.y - 6 * scale
                xAlign = "center"
            else:
                if line.y is not None:
                    textX = glyph.width + 6 * scale
                    textY = line.y - (fontSize / 3.5) * scale
                elif line.x is not None:
                    textX = line.x + 6 * scale
                    textY = 0
                xAlign = "left"
            drawTextAtPoint(
                painter, line.name, textX, textY, scale, xAlign=xAlign)
        painter.restore()
コード例 #58
0
 def updateStart(self, pointVCS):
     ''' !!! start point from FreehandTool is in View CS. '''
     pointViewInt = QPoint(pointVCS.x(), pointVCS.y())
     pointSceneFloat = self.scene().views()[0].mapToScene(pointViewInt)
     self.start = pointSceneFloat
     self.setLine(QLineF(self.start, self.end))
コード例 #59
0
    def setAxisIntersect(self, intersect):
        self._axisIntersect = intersect
        # print "SkeletonsLayer(axis=%d) is updating intersect=%d" % (self._axis, self._axisIntersect)

        nodes, eIntersected, ePlane = self._3d._skeletons.intersect(self._axis, self._axisIntersect)

        # update existing items
        toRemove = []
        for node, item in self._node2view.items():
            if node.pos[self._axis] != self._axisIntersect:
                self._scene.removeItem(item)
                toRemove.append(node)
            elif node.pointF(self._axis) != item.pos():
                item.setPos(self._scene.data2scene.map(node.pointF(self._axis)))
            if node.isSelected() != item.isSelected():
                item.setSelected(node.isSelected())
                assert item.isSelected() == node.isSelected()
            i = 0
            newSize = [0, 0]
            for j in range(3):
                if j == self._axis:
                    continue
                newSize[i] = node.shape[j]
                i += 1
            newRectF = QRectF(0, 0, *newSize)
            newRectF = self._scene.data2scene.mapRect(newRectF)

            item.setRect(
                QRectF(
                    old_div(-newRectF.width(), 2.0),
                    old_div(-newRectF.height(), 2.0),
                    newRectF.width(),
                    newRectF.height(),
                )
            )

        for r in toRemove:
            del self._node2view[r]

        # add new views for nodes
        for n in nodes:
            if n in self._node2view:
                continue

            pos2D = list(n.pos)
            del pos2D[self._axis]

            shape2D = n.shape2D(self._axis)
            itm = QGraphicsSkeletonNode(shape2D, skeletons=self._3d._skeletons, node=n)
            itm.setPos(self._scene.data2scene.map(QPointF(*pos2D)))
            itm.setSelected(n.isSelected())

            self._scene.addItem(itm)
            self._node2view[n] = itm

        for itm in list(self._edge2view.values()):
            self._scene.removeItem(itm)
        self._edge2view = dict()

        for e in ePlane:
            l = QLineF(e[0].pointF(), e[1].pointF())

            c1 = e[0].color()
            c2 = e[1].color()
            assert sys.version_info.major == 2, (
                "Alert! This function has not been "
                "tested under python 3. Please remove this assertion and be wary of any "
                "strnage behavior you encounter"
            )
            mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2)

            line = QGraphicsLineItem(self._scene.data2scene.map(l))
            line.setPen(QPen(mixColor))
            self._scene.addItem(line)
            self._edge2view[e] = line

        for theEdge, e in eIntersected:
            c1 = theEdge[0].color()
            c2 = theEdge[1].color()
            assert sys.version_info.major == 2, (
                "Alert! This function has not been "
                "tested under python 3. Please remove this assertion and be wary of any "
                "strnage behavior you encounter"
            )
            mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2)

            nodeSize = 6
            p = QGraphicsRectItem(old_div(-nodeSize, 2), old_div(-nodeSize, 2), nodeSize, nodeSize)
            pos2D = list(e)
            del pos2D[self._axis]
            p.setPos(self._scene.data2scene.map(QPointF(*pos2D)))
            p.setPen(QPen(mixColor))
            self._scene.addItem(p)
            self._edge2view[e] = p
コード例 #60
0
 def draw_roi(self, roi):
     lines = roi['lines']
     for x1, y1, x2, y2, in lines:
         line = QLineF(x1, y1, x2, y2)
         self.transect_lines.append(line)
         self.addLine(line, self.pen)