示例#1
0
 def itemChange(self, change, value):
     # if position of label changes
     if change == QGraphicsItem.ItemPositionChange and self.scene():
         newPos = QPointF(value)  # new position
         newPos += QPointF(self.boundingRect().width() / 2, self.boundingRect().height() / 2)  # pos of center
         points = self.parentItem().points
         firstPoint = points[self.index]
         endPoint = points[self.index + 1]
         if firstPoint.x() == endPoint.x():
             if min(firstPoint.y(), endPoint.y()) > newPos.y():
                 newPos.setY(min(firstPoint.y(), endPoint.y()))
             elif newPos.y() > max(firstPoint.y(), endPoint.y()):
                 newPos.setY(max(firstPoint.y(), endPoint.y()))
         elif firstPoint.y() == endPoint.y():
             if min(firstPoint.x(), endPoint.x()) > newPos.x():
                 newPos.setX(min(firstPoint.x(), endPoint.x()))
             elif newPos.x() > max(firstPoint.x(), endPoint.x()):
                 newPos.setX(max(firstPoint.x(), endPoint.x()))
         newPos -= QPointF(self.boundingRect().width() / 2,
                           self.boundingRect().height() / 2)  # change center pos to top-left
         return newPos
     if change == QGraphicsItem.ItemPositionHasChanged and self.scene():
         self.updateGap()
         self.updateLine()
         return
     return super(LineLabel, self).itemChange(change, value)
 def __init__(self, p1: QPointF, p2: QPointF = None):
     if p2 is not None:
         self.x = p2.x() - p1.x()
         self.y = p2.y() - p1.y()
     else:
         self.x = p1.x()
         self.y = p1.y()
示例#3
0
    def itemChange(self, change, value):
        """ move position of grabber after resize"""
        if change == QGraphicsItem.ItemPositionChange and self.isEnabled():
            p = QPointF(self.pos())
            if self.direction == Qt.Horizontal:
                p.setX(value.x())
                if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2:
                    points = self.parentItem().refLine.points
                    point1 = points[self.parentItem().refIndex]
                    point2 = points[self.parentItem().refIndex + 1]
                    point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1)
                    point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2)
                    if p.x() < min(point1.x(), point2.x()):
                        p.setX(min(point1.x(), point2.x()))
                    elif p.x() > max(point1.x(), point2.x()):
                        p.setX(max(point1.x(), point2.x()))
            elif self.direction == Qt.Vertical:
                p.setY(value.y())
                if self.parentItem().refLine and self.m_index == len(self.parentItem().points) - 2:
                    points = self.parentItem().refLine.points
                    point1 = points[self.parentItem().refIndex]
                    point2 = points[self.parentItem().refIndex + 1]
                    point1 = self.parentItem().mapFromItem(self.parentItem().refLine, point1)
                    point2 = self.parentItem().mapFromItem(self.parentItem().refLine, point2)
                    if p.y() < min(point1.y(), point2.y()):
                        p.setY(min(point1.y(), point2.y()))
                    elif p.y() > max(point1.y(), point2.y()):
                        p.setY(max(point1.y(), point2.y()))

            movement = p - self.pos()
            self.m_annotation_item.movePoints(self.m_index, movement)
            return p
        return super(Grabber, self).itemChange(change, value)
示例#4
0
 def update_path_draw2Pt_bk(self):
     p = QPainterPath()
     p.moveTo(self.pos1)
     if len(self.connPoints) == 0:
         y = self.pos2.y()
         pt =QPointF(self.pos1.x(),y)
     else:
         pt_next = self.connPoints[0]
         dx = np.abs(self.pos1.x()-pt_next.x())
         dy = np.abs(self.pos1.y()-pt_next.y())
         if dx > dy:
             pt = QPointF(self.pos1.x(),pt_next.y())
         else:
             pt = QPointF(pt_next.x(),self.pos1.y())
         if len(self.connPoints)==1:
             pt_1next = self.pos1;
         else:
             pt_1next = self.connPoints[1]
         if pt.x() == pt_next.x() == pt_1next.x() and \
            (pt_next.y() < pt.y() < pt_1next.y() or pt_1next.y() < pt.y() < pt_next.y()):
             self.connPoints.remove(pt_next)
                     
         elif pt.y() == pt_next.y() == pt_1next.y() and \
              (pt_next.x() < pt.x() < pt_1next.x() or pt_1next.x() < pt.x() < pt_next.x()):
             self.connPoints.remove(pt_next)
         
     p.lineTo(pt)
     for el in self.connPoints:
         p.lineTo(el)
     p.lineTo(self.pos2)
     self.setPath(p)
示例#5
0
 def __calculateEndingPoints_topToBottom(self):
     """
     Private method to calculate the ending points of the association item.
     
     The ending points are calculated from the top center of the lower item
     to the bottom center of the upper item.
     """
     if self.itemA is None or self.itemB is None:
         return
     
     self.prepareGeometryChange()
     
     rectA = self.__mapRectFromItem(self.itemA)
     rectB = self.__mapRectFromItem(self.itemB)
     midA = QPointF(rectA.x() + rectA.width() / 2.0,
                    rectA.y() + rectA.height() / 2.0)
     midB = QPointF(rectB.x() + rectB.width() / 2.0,
                    rectB.y() + rectB.height() / 2.0)
     if midA.y() > midB.y():
         startP = QPointF(rectA.x() + rectA.width() / 2.0, rectA.y())
         endP = QPointF(rectB.x() + rectB.width() / 2.0,
                        rectB.y() + rectB.height())
     else:
         startP = QPointF(rectA.x() + rectA.width() / 2.0,
                          rectA.y() + rectA.height())
         endP = QPointF(rectB.x() + rectB.width() / 2.0, rectB.y())
     self.setPoints(startP.x(), startP.y(), endP.x(), endP.y())
示例#6
0
	def get_angle(self,A,B,dI):
		C = [(A.x()+B.x())/2,(A.y()+B.y())/2]
		I = QPointF(C[0]+dI[0],C[1]+dI[1])
		# AI = [I[0]-A.x(),I[1]-A.y()]
		# BI = [I[0]-B.x(),I[1]-B.y()]
		# AB = [B.x()-A.x(),B.y()-A.y()]
		#
		# ##angle(AB = [1,0],AB)
		# if math.sqrt(AB[0]**2+AB[1]**2) != 0:
		# 	alpha = math.acos(AB[0]/math.sqrt(AB[0]**2+AB[1]**2))
		# alpha = int(self.to_deg(angles[0]))
		#
		# ##angle(AC = [1,0],AI)
		# if math.sqrt(AI[0]**2+AI[1]**2) != 0:
		# 	angles[0] = math.acos(AI[0]/math.sqrt(AI[0]**2+AI[1]**2))
		# angles[0] = int(self.to_deg(angles[0]))
		#
		#
		# ##angle(BC,BI)
		# if math.sqrt(BI[0]**2+BI[1]**2) != 0:
		# 	angles[1] = math.acos(BI[0]/math.sqrt(BI[0]**2+BI[1]**2))
		# angles[1] = int(self.to_deg(angles[1]))

		alpha = QLineF(A.x(), A.y(),I.x(), I.y()).angle()
		beta = QLineF(I.x(), I.y(),B.x(), B.y()).angle()
		angles = [-alpha,180-beta]
		return angles
示例#7
0
    def update_path_draw2Pt(self):
        p = QPainterPath()
        p.moveTo(self.pos1)
        for el in self.connPoints:
            p.lineTo(el)
        if len(self.connPoints) == 0:
            y = self.pos1.y()
            pt = QPointF(self.pos2.x(), y)
        else:
            pt_prev = self.connPoints[-1]
            dx = np.abs(self.pos2.x() - pt_prev.x())
            dy = np.abs(self.pos2.y() - pt_prev.y())
            if dx > dy:
                pt = QPointF(self.pos2.x(), pt_prev.y())
            else:
                pt = QPointF(pt_prev.x(), self.pos2.y())
            if len(self.connPoints) == 1:
                pt_2prev = self.pos1
            else:
                pt_2prev = self.connPoints[-2]
            if pt.x() == pt_prev.x() == pt_2prev.x() and \
               (pt_prev.y() < pt.y() < pt_2prev.y() or pt_2prev.y() < pt.y() < pt_prev.y()):
                self.connPoints.remove(pt_prev)

            elif pt.y() == pt_prev.y() == pt_2prev.y() and \
                 (pt_prev.x() < pt.x() < pt_2prev.x() or pt_2prev.x() < pt.x() < pt_prev.x()):
                self.connPoints.remove(pt_prev)

        p.lineTo(pt)
        p.lineTo(self.pos2)
        self.setPath(p)
示例#8
0
 def mousePressEvent(self, event):
     if QPointF.y(event.localPos()) <= QPointF.y(QPointF(
             0.0, 30.0)) and event.button() == Qt.LeftButton:
         self.moving = True
         self.offset = event.pos()
     else:
         self.moving = False
示例#9
0
    def mouseIsOnIO(self, mousePos, click = False):    	
    	#Returns the IO that the mouse is on
        for i in range(0, len(self.ioList)):
            #Adjust if IO is centered on a side
            if self.ioList[i][3] == 'left':
                yTranslation = self.yTranslationLeftIO
            else:
                yTranslation = self.yTranslationRightIO

            #Get point of IO
            IOPoint = QPointF(self.ioList[i][0], self.ioList[i][1] + yTranslation)

            #If mouse is over IO -> return IO
            if mousePos.x() > IOPoint.x() and mousePos.x() < IOPoint.x() + self.ioWidth:
                if mousePos.y() > IOPoint.y() and mousePos.y() < IOPoint.y() + self.ioHeight:
                    # entry point for drawing graphs.......
                    # if click:
                    #     print('mouse on IO: ' + str(i) + ' (' + str(self.ioList[i][3]) + ', ' + str(self.ioList[i][4]) + ')')
                    
                    #Update the hover paramater of the IO
                    self.ioList.insert(i, (self.ioList[i][0], self.ioList[i][1], self.ioList[i][2], self.ioList[i][3], self.ioList[i][4], True, self.ioList[i][6]))
                    del self.ioList[i + 1]

                    self.setFlag(QGraphicsItem.ItemIsSelectable, False)
                    self.setFlag(QGraphicsItem.ItemIsMovable, False)
                    self.hover = False
                    return i
        #If no IO is found under the mouse -> make sure hovering is enabled and return -1
        self.hover = True
        self.setHoveringToFalse()
        return -1
示例#10
0
    def reconfigureRect(self,
                        top_left,
                        bottom_right,
                        padding=80,
                        do_grid=False):
        """Summary

        Args:
            top_left (TYPE): Description
            bottom_right (TYPE): Description

        Returns:
            tuple: tuple of point tuples representing the top_left and
                bottom_right as reconfigured with padding
        """
        rect = self._rect
        ptTL = QPointF(
            *self.padTL(padding, *top_left)) if top_left else rect.topLeft()
        ptBR = QPointF(*self.padBR(
            padding, *bottom_right)) if bottom_right else rect.bottomRight()
        self._rect = new_rect = QRectF(ptTL, ptBR)
        self.setRect(new_rect)
        self.configureOutline(self.outline)
        if do_grid:
            self.griditem.updateGrid()
        return (ptTL.x(), ptTL.y()), (ptBR.x(), ptBR.y())
    def reconfigureRect(self,
                        top_left: Vec2T,
                        bottom_right: Vec2T,
                        padding: int = 80) -> Tuple[Vec2T, Vec2T]:
        """Summary

        Args:
            top_left: top left corner point
            bottom_right: bottom right corner point
            padding: padding of the rectagle in pixels points

        Returns:
            tuple of point tuples representing the ``top_left`` and
                ``bottom_right`` as reconfigured with ``padding``
        """
        rect = self._rect
        ptTL = QPointF(
            *self._padTL(padding, *top_left)) if top_left else rect.topLeft()
        ptBR = QPointF(*self._padBR(
            padding, *bottom_right)) if bottom_right else rect.bottomRight()
        self._rect = new_rect = QRectF(ptTL, ptBR)
        self.setRect(new_rect)
        self._configureOutline(self.outline)
        self.griditem.updateGrid()
        return (ptTL.x(), ptTL.y()), (ptBR.x(), ptBR.y())
示例#12
0
    def save_annotations(self):
        scene: QGraphicsScene = self.viewer.scene()
        self._annot_dao.delete(self.source.id)
        annot_list = []
        for item in scene.items():
            img_bbox: QRectF = self.viewer.pixmap.sceneBoundingRect()
            offset = QPointF(img_bbox.width() / 2, img_bbox.height() / 2)
            if isinstance(item, EditableBox):
                item_box: QRectF = item.sceneBoundingRect()
                x1 = math.floor(item_box.topLeft().x() + offset.x())
                y1 = math.floor(item_box.topRight().y() + offset.y())
                x2 = math.floor(item_box.bottomRight().x() + offset.x())
                y2 = math.floor(item_box.bottomRight().y() + offset.y())
                box = AnnotaVO()
                box.label = item.label.id if item.label else None
                box.entry = self.source.id
                box.kind = "box"
                box.points = ",".join(map(str, [x1, y1, x2, y2]))
                annot_list.append(box)
            elif isinstance(item, EditablePolygon):
                points = [[
                    math.floor(pt.x() + offset.x()),
                    math.floor(pt.y() + offset.y())
                ] for pt in item.points]
                points = np.asarray(points).flatten().tolist()
                poly = AnnotaVO()
                poly.label = item.label.id if item.label else None
                poly.entry = self.source.id
                poly.kind = "polygon"
                poly.points = ",".join(map(str, points))
                annot_list.append(poly)

        self._annot_dao.save(annot_list)
示例#13
0
    def _hitTest(self, rc: QRectF, mousePos: QPointF) -> Hit:
        maxdist = 4
        if not rc.adjusted(-maxdist, -maxdist, maxdist,
                           maxdist).contains(mousePos):
            return Hit.NoHit

        def dist(p1, p2):
            return (p1 - p2).manhattanLength()

        if dist(rc.topLeft(), mousePos) < maxdist:
            return Hit.TopLeft
        elif dist(rc.topRight(), mousePos) < maxdist:
            return Hit.TopRight
        elif dist(rc.bottomRight(), mousePos) < maxdist:
            return Hit.BottomRight
        elif dist(rc.bottomLeft(), mousePos) < maxdist:
            return Hit.BottomLeft
        elif abs(rc.left() - mousePos.x()) < maxdist:
            return Hit.Left
        elif abs(rc.right() - mousePos.x()) < maxdist:
            return Hit.Right
        elif abs(rc.top() - mousePos.y()) < maxdist:
            return Hit.Top
        elif abs(rc.bottom() - mousePos.y()) < maxdist:
            return Hit.Bottom
        elif rc.contains(mousePos):
            return Hit.Center
        else:
            return Hit.NoHit
示例#14
0
    def itemChange(self, change, value):
        # self.logger.debug(change, value)
        # Snap grid excludes alignment

        if change == self.ItemPositionChange:
            if self.parent.parent().snapGrid:
                snapSize = self.parent.parent().snapSize
                self.logger.debug("itemchange")
                self.logger.debug(type(value))
                value = QPointF(value.x() - value.x() % snapSize,
                                value.y() - value.y() % snapSize)
                return value
            else:
                # if self.hasElementsInYBand() and not self.elementInY() and not self.aligned:
                if self.parent.parent().alignMode:
                    if self.hasElementsInYBand():
                        return self.alignBlock(value)
                    else:
                        # self.aligned = False
                        return value

                else:
                    return value
        else:
            return super(BlockItem, self).itemChange(change, value)
示例#15
0
    def __calculateEndingPoints_topToBottom(self):
        """
        Private method to calculate the ending points of the association item.
        
        The ending points are calculated from the top center of the lower item
        to the bottom center of the upper item.
        """
        if self.itemA is None or self.itemB is None:
            return

        self.prepareGeometryChange()

        rectA = self.__mapRectFromItem(self.itemA)
        rectB = self.__mapRectFromItem(self.itemB)
        midA = QPointF(rectA.x() + rectA.width() / 2.0,
                       rectA.y() + rectA.height() / 2.0)
        midB = QPointF(rectB.x() + rectB.width() / 2.0,
                       rectB.y() + rectB.height() / 2.0)
        if midA.y() > midB.y():
            startP = QPointF(rectA.x() + rectA.width() / 2.0, rectA.y())
            endP = QPointF(rectB.x() + rectB.width() / 2.0,
                           rectB.y() + rectB.height())
        else:
            startP = QPointF(rectA.x() + rectA.width() / 2.0,
                             rectA.y() + rectA.height())
            endP = QPointF(rectB.x() + rectB.width() / 2.0, rectB.y())
        self.setPoints(startP.x(), startP.y(), endP.x(), endP.y())
示例#16
0
class RSegment(QObject):
    def __init__(self, x1, y1, x2, y2, color, line_width):
        self._x1 = x1
        self._y1 = y1
        self._x2 = x2
        self._y2 = y2
        self._pos = QPointF(x1, y1)
        super().__init__()
        self.line = QGraphicsLineItem()
        self.line.setLine(x1, y1, x2, y2)
        pen = QPen()
        pen.setWidthF(line_width)
        pen.setColor(color)
        self.line.setPen(pen)

    def x(self):
        return self._pos.x()

    def y(self):
        return self._pos.y()

    @pyqtProperty(QPointF)
    def pos(self):
        return self._pos

    @pos.setter
    def pos(self, value):
        delta_x = value.x() - self._pos.x()
        delta_y = value.y() - self._pos.y()
        self._x1 = self._x1 + delta_x
        self._y1 = self._y1 + delta_y
        self._x2 = self._x2 + delta_x
        self._y2 = self._y2 + delta_y
        self.line.setLine(self._x1, self._y1, self._x2, self._y2)
        self._pos = value
示例#17
0
 def done_work(result):
     result, error = result
     if error:
         raise error
     img_bbox: QRectF = self.viewer.pixmap.sceneBoundingRect()
     offset = QPointF(img_bbox.width() / 2, img_bbox.height() / 2)
     for entry in result:
         try:
             vo: AnnotaVO = entry
             points = map(float, vo.points.split(","))
             points = list(more_itertools.chunked(points, 2))
             if vo.kind == "box":
                 x = points[0][0] - offset.x()
                 y = points[0][1] - offset.y()
                 w = math.fabs(points[0][0] - points[1][0])
                 h = math.fabs(points[0][1] - points[1][1])
                 roi: QRectF = QRectF(x, y, w, h)
                 rect = EditableBox(roi)
                 rect.label = vo.label
                 self.viewer.scene().addItem(rect)
             elif vo.kind == "polygon":
                 polygon = EditablePolygon()
                 polygon.label = vo.label
                 self.viewer.scene().addItem(polygon)
                 for p in points:
                     polygon.addPoint(
                         QPoint(p[0] - offset.x(), p[1] - offset.y()))
         except Exception as ex:
             print(ex)
示例#18
0
 def calcConnector(x1, y1, dir1, rect1, x2, y2, dir2, rect2):
     lines = []
     if dir2 == "down":
         if y1 > y2 and x1 == x2:
             #direct connection
             lines.append(QLineF(QPointF(x1, y1), QPointF(x2, y2)))
         elif y1 > (y2 + 2 * self.grid):
             #z-connection
             return zLine(x1, y1, x2, y2, 'H')
         elif (rect2.topLeft().x() > (rect1.topRight().x() + 2 * grid)
               or rect1.topLeft().x() > (rect2.topRight().x() + 2 * grid)):
             #enough place to draw a line between both rects
             p1 = QPointF(x1, y2 + 2 * grid)
             p2 = QPointF(x2, y2 - 2 * grid)
             lines.append(QLineF(QPointF(x1, y1), p1))
             lines += zLine(p1.x(), p1.y(), p2.x(), p2.y(), 'V')
             lines.append(QLineF(QPointF(x2, y2), p2))
         else:
             #round both
             start = QPointF(x1, y1 - 2 * grid)
             end = QPointF(x2, y2 + 2 * grid)
             line.append(QLineF(start, QPointF(x1, y1)))
             if x1 > x2:
                 length = x1 - rect2.topLeft.x() + 2 * grid
                 lines += uLine(start, end, "right")
             else:
                 length = rect2.topRight.x() - x1 + 2 * grid
                 lines += uLine(start, end, "left")
             line.append(QLineF(end, QPointF(x2, y2)))
示例#19
0
    def intersectionOfSegmentAndCircle(self, center: QtCore.QPointF,
                                       radius: float, p1: QtCore.QPointF,
                                       p2: QtCore.QPointF):
        x0, y0 = center.x(), center.y()
        x1, y1 = p1.x(), p1.y()
        x2, y2 = p2.x(), p2.y()
        r = radius

        intercect1 = ((x0 - x2) * (x1 - x2) + (y0 - y2) * (y1 - y2) -
                      (r**2 * ((x1 - x2)**2 + (y1 - y2)**2) -
                       (-(x2 * y0) - x0 * y1 + x2 * y1 + x1 *
                        (y0 - y2) + x0 * y2)**2)**.5) / ((x1 - x2)**2 +
                                                         (y1 - y2)**2)
        intercect2 = ((x0 - x2) * (x1 - x2) + (y0 - y2) * (y1 - y2) +
                      (r**2 * ((x1 - x2)**2 + (y1 - y2)**2) -
                       (-(x2 * y0) - x0 * y1 + x2 * y1 + x1 *
                        (y0 - y2) + x0 * y2)**2)**.5) / ((x1 - x2)**2 +
                                                         (y1 - y2)**2)

        if isclose(intercect1, 1., abs_tol=1e-5) or isclose(
                intercect1, 0., abs_tol=1e-5):
            intercect = intercect2
        else:
            intercect = intercect1

        # intercect = max([intercect1, intercect2])
        # if abs(intercect) > 1.:
        #     print("Warning!")
        # intercect1 = (p1 + p2) * intercect1
        # intercect2 = (p1 + p2) * intercect2
        intercect = (p1 * intercect + (1. - intercect) * p2)

        return intercect
示例#20
0
 def update_path_draw2OutPort(self):
     p = QPainterPath()
     p.moveTo(self.pos1)
     if len(self.connPoints) == 0:
         pt1 = QPointF((self.pos1.x()+self.pos2.x())/2, self.pos1.y())
         pt2 = QPointF((self.pos1.x()+self.pos2.x())/2, self.pos2.y())
         p.lineTo(pt1)
         p.lineTo(pt2)
     
     else:
         pt=  self.connPoints[0]
         pt1 = QPointF((self.pos1.x()+pt.x())/2, self.pos1.y())
         pt2 = QPointF((self.pos1.x()+pt.x())/2, pt.y())
         p.lineTo(pt1)
         p.lineTo(pt2)
         
         if len(self.connPoints)>=2:
             pt_2next = self.connPoints[1]
             if pt_2next.x() == pt1.x() == pt2.x() or \
                pt_2next.y() == pt1.y() == pt2.y():
                 self.connPoints.remove(pt_2next)
     
         for el in self.connPoints:
             p.lineTo(el)
             
     p.lineTo(self.pos2)
     self.setPath(p)        
示例#21
0
def is_convex(polygon):
    size = len(polygon)
    array_vector = list()
    _sign = 0

    if size < 3:
        return False, _sign

    for i in range(1, size):
        if i < size - 1:
            ab = QPointF(polygon[i].x() - polygon[i - 1].x(),
                         polygon[i].y() - polygon[i - 1].y())
            bc = QPointF(polygon[i + 1].x() - polygon[i].x(),
                         polygon[i + 1].y() - polygon[i].y())
        else:
            ab = QPointF(polygon[i].x() - polygon[i - 1].x(),
                         polygon[i].y() - polygon[i - 1].y())
            bc = QPointF(polygon[1].x() - polygon[0].x(),
                         polygon[1].y() - polygon[0].y())

        array_vector.append(ab.x() * bc.y() - ab.y() * bc.x())

    exist_sign = False
    for i in range(len(array_vector)):
        if array_vector[i] == 0:
            continue

        if exist_sign:
            if sign(array_vector[i]) != _sign:
                return False, _sign
        else:
            _sign = sign(array_vector[i])
            exist_sign = True

    return True, _sign
示例#22
0
文件: main.py 项目: TinyMarcus/CG
def convex_check(figure):
    size = len(figure)
    vector2d = list()
    check_sign = 0
    
    if size < 3:
        return False, check_sign

    for i in range(1, size):
        if i < size - 1:
            ab = QPointF(figure[i].x() - figure[i - 1].x(), figure[i].y() - figure[i - 1].y())
            bc = QPointF(figure[i + 1].x() - figure[i].x(), figure[i + 1].y() - figure[i].y())
        else:
            ab = QPointF(figure[i].x() - figure[i - 1].x(), figure[i].y() - figure[i - 1].y())
            bc = QPointF(figure[1].x() - figure[0].x(), figure[1].y() - figure[0].y())
        
        vector2d.append(ab.x() * bc.y() - ab.y() * bc.x())

    exist_sign = False
    for i in range(len(vector2d)):
        if vector2d[i] == 0:
            continue
        
        if exist_sign:
            if sign(vector2d[i]) != check_sign:
                return False, check_sign
        else:
            check_sign = sign(vector2d[i])
            exist_sign = True

    return True, check_sign
示例#23
0
 def pixmap_hoverMoveEvent_slot(self, evt: QGraphicsSceneHoverEvent, x, y):
     bbox: QRect = self._pixmap.boundingRect()
     offset = QPointF(bbox.width() / 2, bbox.height() / 2)
     self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
     self.vline.setZValue(1)
     self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
     self.hline.setZValue(1)
示例#24
0
 def mousePressEvent(self, event):
     position = QPointF(event.scenePos())
     print("pressed here: " + str(int(position.x() / 70)) + ", " +
           str(int(position.y() / 70)))
     self.boardObject.addBlock(int(position.x() / 70),
                               int(position.y() / 70))
     self.boardObject.getArray()
示例#25
0
 def _determineStartLabelHeight(self, start_point: QtCore.QPointF,
                                down: bool, startAtThis: bool):
     """
     2020.09.28新增。决定开始标签高度。
     如果启用重叠避免,则需要查找近邻计算高度,同时维护数据;
     如果不启用,直接返回配置项。
     """
     if not self.graph.UIConfigData()['avoid_cover']:
         return self.graph.UIConfigData()['start_label_height']
     # 启用重叠避免的情况
     thres = 100  # 左右超过这个范围,就不再搜
     lst = self.labelSpans.setdefault((start_point.y(), down), [])
     a = bisect.bisect_left(lst, (start_point.x() - thres, ))
     b = bisect.bisect_right(lst, (start_point.x() + thres, ))
     w = self.spanItemWidth  # 当前标签宽度
     h0 = self.spanItemWidth
     if startAtThis:
         wl, wr = w / 2, w / 2
     else:
         wl, wr = w, 0
     h = self.graph.UIConfigData()['base_label_height']
     occupied_heights = []
     for i in range(a, b):
         x, hi, wli, wri = lst[i]
         if 0 <= start_point.x() - x < wri + wl or 0 <= x - start_point.x(
         ) < wli + wr:
             # 确定冲突
             occupied_heights.append(hi)
     while h in occupied_heights:
         h += self.graph.UIConfigData()['step_label_height']
     tpl = (start_point.x(), h, wl, wr)
     bisect.insort(lst, tpl)
     self.startLabelInfo = ((start_point.y(), down), tpl)
     return h
示例#26
0
    def getSnappedToSocketPosition(self, scenepos: QPointF) -> ('QDMGraphicsSocket', QPointF):
        """
        Returns grSocket and Scene position to nearest Socket or original position if no nearby Socket found

        :param scenepos: From which point should I snap?
        :type scenepos: ``QPointF``
        :return: grSocket and Scene postion to nearest socket
        """
        scanrect = QRectF(
            scenepos.x() - self.edge_snapping_radius, scenepos.y() - self.edge_snapping_radius,
            self.edge_snapping_radius * 2, self.edge_snapping_radius * 2
        )
        items = self.grScene.items(scanrect)
        items = list(filter(lambda x: isinstance(x, QDMGraphicsSocket), items))

        if len(items) == 0:
            return None, scenepos

        selected_item = items[0]
        if len(items) > 1:
            # calculate the nearest socket
            nearest = 10000000000
            for grsock in items:
                grsock_scenepos = grsock.socket.node.getSocketScenePosition(grsock.socket)
                qpdist = QPointF(*grsock_scenepos) - scenepos
                dist = qpdist.x() * qpdist.x() + qpdist.y() * qpdist.y()
                if dist < nearest:
                    nearest, selected_item = dist, grsock

        selected_item.isHighlighted = True

        calcpos = selected_item.socket.node.getSocketScenePosition(selected_item.socket)

        return selected_item, QPointF(*calcpos)
示例#27
0
    def hoverEnterEvent(self, event):
        """

        """

        self.prepareGeometryChange()
        self._hover = True
        self._pen.setWidth(self.PEN_WIDTH_HOVER)
        self._penMargin = self.PEN_WIDTH_HOVER / 2
        a = QPointF(-self._WIDTH / 2 - randint(0, int(self._HEIGHT / 3)),
                    -self._HEIGHT / 2 - randint(0, int(self._HEIGHT / 3)))
        b = QPointF(self._WIDTH / 2 + randint(0, int(self._HEIGHT / 3)),
                    -self._HEIGHT / 2 - randint(0, int(self._HEIGHT / 3)))
        c = QPointF(self._WIDTH / 2 + randint(0, int(self._HEIGHT / 3)),
                    self._HEIGHT / 2 + randint(0, int(self._HEIGHT / 3)))
        d = QPointF(-self._WIDTH / 2 - randint(0, int(self._HEIGHT / 3)),
                    self._HEIGHT / 2 + randint(0, int(self._HEIGHT / 3)))
        self._boundingRect = QRectF(
            QPointF(
                min(a.x(), d.x()) - self._penMargin,
                min(a.y(), b.y()) - self._penMargin),
            QPointF(
                max(b.x(), c.x()) + self._penMargin,
                max(c.y(), d.y()) + self._penMargin))
        self._shape = QPainterPath()
        self._shape.moveTo(a)
        self._shape.lineTo(b)
        self._shape.lineTo(c)
        self._shape.lineTo(d)
        self._shape.lineTo(a)
        super().hoverEnterEvent(event)
示例#28
0
 def _update_guide_lines(self, x, y):
     bbox: QRect = self._pixmap.boundingRect()
     offset = QPointF(bbox.width() / 2, bbox.height() / 2)
     self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
     self.vline.setZValue(1)
     self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
     self.hline.setZValue(1)
示例#29
0
 def makeGearsTransforms(translate: QPointF, rotate: int):
     arrowTrans = QTransform()
     arrowTrans.translate(translate.x(), translate.y())
     arrowTrans.rotate(rotate)
     numberTrans = QTransform()
     numberTrans.translate(translate.x(), translate.y())
     return arrowTrans, numberTrans
示例#30
0
文件: ray.py 项目: serkov23/tp1
    def recount_second_pt(first_pt: QPointF, second_pt: QPointF) -> QPointF:
        x = second_pt.x() - first_pt.x()
        y = second_pt.y() - first_pt.y()

        phi = math.atan(x / y) + (math.pi if y < 0 else 0)
        r = Ray.INFINITY
        return QPointF(first_pt.x() + r * math.sin(phi),
                       first_pt.y() + r * math.cos(phi))
示例#31
0
文件: HUD.py 项目: wangyeee/MiniGCS
 def rotatePointClockWise(self, p: QPointF, angle):
     '''
     Standard 2x2 rotation matrix, counter-clockwise
       |  cos(phi)   sin(phi) |
       | -sin(phi)   cos(phi) |
     '''
     p.setX(cos(angle) * p.x() + sin(angle)* p.y())
     p.setY((-1.0 * sin(angle) * p.x()) + cos(angle) * p.y())
示例#32
0
 def isClockwise(self, a: QPointF, b: QPointF, c: QPointF):
     val = (b.y() - a.y()) * (c.x() - b.x()) - (c.y() - b.y()) * (b.x() -
                                                                  a.x())
     if (val == 0):
         return 0
     if (val > 0):
         return 1
     return -1
示例#33
0
    def buildEdgeFromGenericEdge(self, item, element):
        """
        Build an edge using the given item type and QDomElement.
        :type item: Item
        :type element: QDomElement
        :rtype: AbstractEdge
        """
        data = element.firstChildElement('data')
        while not data.isNull():

            if data.attribute('key', '') == self.keys['edge_key']:

                points = []
                polyLineEdge = data.firstChildElement('y:PolyLineEdge')
                path = polyLineEdge.firstChildElement('y:Path')
                collection = path.elementsByTagName('y:Point')
                for i in range(0, collection.count()):
                    point = collection.at(i).toElement()
                    pos = QPointF(float(point.attribute('x')), float(point.attribute('y')))
                    pos = QPointF(snapF(pos.x(), DiagramScene.GridSize), snapF(pos.y(), DiagramScene.GridSize))
                    points.append(pos)

                kwargs = {
                    'id': element.attribute('id'),
                    'source': self.scene.node(element.attribute('source')),
                    'target': self.scene.node(element.attribute('target')),
                    'breakpoints': points,
                }

                edge = self.factory.create(item, self.scene, **kwargs)
                # yEd, differently from the node pos whose origin matches the TOP-LEFT corner,
                # consider the center of the shape as original anchor point (0,0). So if the
                # anchor point hs a negative X it's moved a bit on the left with respect to
                # the center of the shape (the same applies for the Y axis)
                sourceP = QPointF(float(path.attribute('sx')), float(path.attribute('sy')))
                sourceP = edge.source.pos() + sourceP
                sourceP = QPointF(snapF(sourceP.x(), DiagramScene.GridSize), snapF(sourceP.y(), DiagramScene.GridSize))

                targetP = QPointF(float(path.attribute('tx')), float(path.attribute('ty')))
                targetP = edge.target.pos() + targetP
                targetP = QPointF(snapF(targetP.x(), DiagramScene.GridSize), snapF(targetP.y(), DiagramScene.GridSize))

                painterPath = edge.source.painterPath()
                if painterPath.contains(edge.source.mapFromScene(sourceP)):
                    edge.source.setAnchor(edge, sourceP)

                painterPath = edge.target.painterPath()
                if painterPath.contains(edge.target.mapFromScene(targetP)):
                    edge.target.setAnchor(edge, targetP)

                edge.source.addEdge(edge)
                edge.target.addEdge(edge)
                return edge

            data = data.nextSiblingElement('data')

        return None
示例#34
0
class PolygonBase(QGraphicsWidget):
    def __init__(self):
        super().__init__()
        self.MAR = 50
        self.points = []
        self.top_left = QPointF(float('Inf'), float('Inf'))
        self.bottom_right = QPointF(-float('Inf'), -float('Inf'))
        self.rect = QRectF()

    def boundingRect(self):
        return self.rect

    def update_bounding_rect(self, pt):
        """插入新顶点时,更新 bounding rect

        Args:
            pt (QPointF): 新插入的顶点
        """
        self.top_left = QPointF(min(self.top_left.x(), pt.x()), min(self.top_left.y(), pt.y()))
        self.bottom_right = QPointF(max(self.bottom_right.x(), pt.x()), max(self.bottom_right.y(), pt.y()))
        self.rect = QRectF(self.top_left, self.bottom_right).adjusted(-self.MAR, -self.MAR, self.MAR, self.MAR)
        self.prepareGeometryChange()

    def move_bounding_rect(self, offset):
        """移动多边形时,更新 bounding rect

        Args:
            offset (QPointF): 平移向量
        """
        self.top_left += offset
        self.bottom_right += offset
        self.rect.adjust(offset.x(), offset.y(), offset.x(), offset.y())
        self.prepareGeometryChange()

    def get_points(self):
        """获取多边形中的顶点列表

        Returns:
            points (list[QPointF]): 顶点列表
        """
        return self.points

    def get_vertices(self):
        """获取多边形中的顶点列表

        Returns:
            vertices (list[list[float]]): 顶点列表
        """
        vertices = [[vertex.x(), vertex.y()] for vertex in self.points]
        return vertices
    def mouseMovedWhileCreatingObject(self, pos, modifiers):
        renderer = self.mapDocument().renderer()
        pixelCoords = renderer.screenToPixelCoords_(pos)
        # Update the size of the new map object
        objectPos = self.mNewMapObjectItem.mapObject().position()
        newSize = QPointF(max(0.0, pixelCoords.x() - objectPos.x()),
                        max(0.0, pixelCoords.y() - objectPos.y()))
        # Holding shift creates circle or square
        if (modifiers & Qt.ShiftModifier):
            m = max(newSize.x(), newSize.y())
            newSize.setX(m)
            newSize.setY(m)

        SnapHelper(renderer, modifiers).snap(newSize)
        self.mNewMapObjectItem.resizeObject(QSizeF(newSize.x(), newSize.y()))
示例#36
0
文件: KEyes.py 项目: pvaret/keyes
  def render(self, widget):

    painter = widget.painter

    if not painter:
      return

    previousRenderHint = painter.renderHints()
    painter.setRenderHints(previousRenderHint | QPainter.Antialiasing)

    painter.setPen(Qt.NoPen)
    painter.setBrush(QColor(253, 242, 245))

    painter.drawEllipse(QRectF(self.pos - self.toPointF(self.size/2), self.size))

    mouseOffset = QPointF(widget.mousePosition) \
                  - self.pos \
                  - QPointF(widget.frameGeometry().topLeft())

    ox, oy = mouseOffset.x(), mouseOffset.y()
    distance = math.sqrt(ox**2 + oy**2)

    if distance > self.eyesight_radius:
      ox *= self.eyesight_radius / distance
      oy *= self.eyesight_radius / distance

    px = self.pos.x() + ox/self.eyesight_radius * (self.size-self.pupil_size).width() / 2
    py = self.pos.y() + oy/self.eyesight_radius * (self.size-self.pupil_size).height() / 2

    pos = QPointF(px, py)

    painter.setBrush(Qt.black)
    painter.drawEllipse(QRectF(pos - self.toPointF(self.pupil_size/2), self.pupil_size))

    painter.setRenderHints(previousRenderHint)
示例#37
0
    def calcRowCol(self, point: QPointF):
        """ Calculate the network row and column that a point is int
            calc the row and column indexes of a point

            The following is the algorithm:
            1.  Find the distance between the point and the left (or top)
            2.  Divide the distance with the width of path to find the relative position
            3.  Multipile this relative position with the number of rows/cols
            4.  Convert the result to int to find the indexes
            5.  If the index is the number of row/col reduce the index
                (This is for the case the the point is on the boundary and in this
                case the relative position is 1 which will cause the indexes to
                be the number of rows/cols - out of the matrix indexes)

            Args:
                point (QPointF) : The point to resolve

            Returns:
                int : The network row that the point is in
                int : The network column that the point is in  

        """
        partialX = (point.x() - self.charPath.boundingRect().left()) / self.charPath.boundingRect().width()
        partialY = (point.y() - self.charPath.boundingRect().top()) / self.charPath.boundingRect().height()
        col_idx = int(partialX * self.netCols)
        row_idx = int(partialY * self.netRows)
        if row_idx == self.netRows:
            row_idx -= 1
        if col_idx == self.netCols:
            col_idx -= 1
        return row_idx, col_idx
示例#38
0
文件: Selection.py 项目: jopohl/urh
    def _get_selected_edge(self, pos: QPointF, transform: QTransform, horizontal_selection: bool):
        x1, x2 = self.x, self.x + self.width
        y1, y2 = self.y, self.y + self.height
        x, y = pos.x(), pos.y()

        spacing = 5
        spacing /= transform.m11() if horizontal_selection else transform.m22()

        if horizontal_selection:
            x1a, x1b = x1 - spacing, x1 + spacing
            y1a, y1b = y1, y2
            x2a, x2b = x2 - spacing, x2 + spacing
            y2a, y2b = y1, y2
        else:
            x1a, x1b, x2a, x2b = x1, x2, x1, x2
            y1a, y1b = min(y1 - spacing, y1 + spacing), max(y1 - spacing, y1 + spacing)
            y2a, y2b = min(y2 - spacing, y2 + spacing), max(y2 - spacing, y2 + spacing)

        if x1a < x < x1b and y1a < y < y1b:
            self.selected_edge = 0
            return 0

        if x2a < x < x2b and y2a < y < y2b:
            self.selected_edge = 1
            return 1

        self.selected_edge = None
        return None
示例#39
0
    def buildNodeFromShapeNode(self, item, element):
        """
        Build a node using the given item type and QDomElement.
        :type item: Item
        :type element: QDomElement
        :rtype: AbstractNode
        """
        data = element.firstChildElement('data')
        while not data.isNull():

            if data.attribute('key', '') == self.keys['node_key']:

                shapeNode = data.firstChildElement('y:ShapeNode')
                geometry = shapeNode.firstChildElement('y:Geometry')

                kwargs = {
                    'id': element.attribute('id'),
                    'height': float(geometry.attribute('height')),
                    'width': float(geometry.attribute('width')),
                }

                node = self.factory.create(item, self.scene, **kwargs)
                # yEd uses the TOP-LEFT corner as (0,0) coordinate => we need to translate our
                # position (0,0), which is instead at the center of the shape, so that the TOP-LEFT
                # corner of the shape in yEd matches the TOP-LEFT corner of the shape in Eddy.
                # Additionally we force-snap the position to the grid so that items say aligned.
                pos = QPointF(float(geometry.attribute('x')), float(geometry.attribute('y')))
                pos = pos + QPointF(node.width() / 2, node.height() / 2)
                pos = QPointF(snapF(pos.x(), DiagramScene.GridSize), snapF(pos.y(), DiagramScene.GridSize))
                node.setPos(pos)
                return node

            data = data.nextSiblingElement('data')

        return None
示例#40
0
    def getLargerEdgePath(self):
        #Used to fill in the small areas on the edge
        #This makes it easier to select the edge
        yTranslation = 2

        #Curve 1
        beginPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() + yTranslation)
        curvePoint1 = QPointF(self.curvePoint1.x()+4, self.curvePoint1.y() + yTranslation)
        curvePoint2 = QPointF(self.curvePoint2.x()+4, self.curvePoint2.y() + yTranslation)
        endPoint = QPointF(self.endPoint.x(), self.endPoint.y() + yTranslation)
        path = QPainterPath(beginPoint)
        point1 = QPointF(curvePoint1.x(), curvePoint1.y())
        point2 = QPointF(curvePoint2.x(), curvePoint2.y())
        path.cubicTo(point1, point2, endPoint)

        #Arrow
        arrowBeginPoint = QPointF(self.endPoint.x(), self.endPoint.y() + 4)
        path.lineTo(arrowBeginPoint)
        if self.endSide == 'right':
            path.lineTo(QPointF(self.endPoint.x() - 10, self.endPoint.y()))
        else:
            path.lineTo(QPointF(self.endPoint.x() + 10, self.endPoint.y()))
        path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 4))
        path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 2))

        #Curve 2 (back)
        endPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() - yTranslation)
        curvePoint2 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() - yTranslation)
        curvePoint1 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() - yTranslation)
        beginPoint = QPointF(self.endPoint.x(), self.endPoint.y() - yTranslation)
        point1 = QPointF(curvePoint1.x(), curvePoint1.y())
        point2 = QPointF(curvePoint2.x(), curvePoint2.y())
        path.cubicTo(point1, point2, endPoint) 

        if self.beginSide == 'right':
            path.lineTo(QPointF(self.beginPoint.x() - 10, self.beginPoint.y() - 2))
            path.lineTo(QPointF(self.beginPoint.x() - 10, self.beginPoint.y() + 2))            
        else:
            path.lineTo(QPointF(self.beginPoint.x() + 10, self.beginPoint.y() - 2))
            path.lineTo(QPointF(self.beginPoint.x() + 10, self.beginPoint.y() + 2))
        path.lineTo(QPointF(self.beginPoint.x(), self.beginPoint.y() + 2))

        return path
示例#41
0
文件: ROI.py 项目: Cyber-Forensic/urh
    def is_in_roi(self, pos: QPointF):
        x1 = self.rect().x()
        x2 = x1 + self.rect().width()
        y1 = self.rect().y()
        y2 = y1 + self.rect().width()

        if x1 < pos.x() < x2 and y1 < pos.y() < y2:
            return True

        return False
示例#42
0
文件: KEyes.py 项目: pvaret/keyes
class Eye:

  pupil_size      = QSizeF(5, 5)
  eyesight_radius = 100.0


  def __init__(self, x, y, w, h):

    ## x, y are the coordinates of the center of the eye.
    ## w, h are the total width and height of the eye.

    self.size = QSizeF(w, h)
    self.pos  = QPointF(x, y)


  def toPointF(self, size):

    return QPointF(size.width(), size.height())


  def render(self, widget):

    painter = widget.painter

    if not painter:
      return

    previousRenderHint = painter.renderHints()
    painter.setRenderHints(previousRenderHint | QPainter.Antialiasing)

    painter.setPen(Qt.NoPen)
    painter.setBrush(QColor(253, 242, 245))

    painter.drawEllipse(QRectF(self.pos - self.toPointF(self.size/2), self.size))

    mouseOffset = QPointF(widget.mousePosition) \
                  - self.pos \
                  - QPointF(widget.frameGeometry().topLeft())

    ox, oy = mouseOffset.x(), mouseOffset.y()
    distance = math.sqrt(ox**2 + oy**2)

    if distance > self.eyesight_radius:
      ox *= self.eyesight_radius / distance
      oy *= self.eyesight_radius / distance

    px = self.pos.x() + ox/self.eyesight_radius * (self.size-self.pupil_size).width() / 2
    py = self.pos.y() + oy/self.eyesight_radius * (self.size-self.pupil_size).height() / 2

    pos = QPointF(px, py)

    painter.setBrush(Qt.black)
    painter.drawEllipse(QRectF(pos - self.toPointF(self.pupil_size/2), self.pupil_size))

    painter.setRenderHints(previousRenderHint)
示例#43
0
def moveUIPoint(contour, point, delta):
    if point.segmentType is None:
        # point is an offCurve. Get its sibling onCurve and the other
        # offCurve.
        onCurve, otherPoint = _getOffCurveSiblingPoints(contour, point)
        # if the onCurve is selected, the offCurve will move along with it
        if onCurve.selected:
            return
        point.move(delta)
        if not onCurve.smooth:
            contour.dirty = True
            return
        # 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,
            # ie. do an orthogonal projection
            line = QLineF(otherPoint.x, otherPoint.y, onCurve.x, onCurve.y)
            n = line.normalVector()
            n.translate(QPointF(point.x, point.y) - n.p1())
            targetPoint = QPointF()
            n.intersect(line, targetPoint)
            # check that targetPoint is beyond its neighbor onCurve
            # we do this by calculating position of the offCurve and second
            # onCurve relative to the first onCurve. If there is no symmetry
            # in at least one of the axis, then we need to clamp
            onCurvePoint = line.p2()
            onDistance = line.p1() - onCurvePoint
            newDistance = targetPoint - onCurvePoint
            if (onDistance.x() >= 0) != (newDistance.x() <= 0) or \
                    (onDistance.y() >= 0) != (newDistance.y() <= 0):
                targetPoint = onCurvePoint
            # ok, now set pos
            point.x, point.y = targetPoint.x(), targetPoint.y()
    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:
                pt.move(delta)
    contour.dirty = True
示例#44
0
    def getEdgePath(self):
        yTranslation = 2

        #Curve 1
        beginPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() + yTranslation)
        curvePoint1 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() + yTranslation)
        curvePoint2 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() + yTranslation)
        endPoint = QPointF(self.endPoint.x(), self.endPoint.y() + yTranslation)
        path = QPainterPath(beginPoint)
        point1 = QPointF(curvePoint1.x(), curvePoint1.y())
        point2 = QPointF(curvePoint2.x(), curvePoint2.y())
        path.cubicTo(point1, point2, endPoint)

        #Arrow
        arrowBeginPoint = QPointF(self.endPoint.x(), self.endPoint.y() + 4)
        path.lineTo(arrowBeginPoint)
        if self.endSide == 'right':
            path.lineTo(QPointF(self.endPoint.x() - 10, self.endPoint.y()))
        else:
            path.lineTo(QPointF(self.endPoint.x() + 10, self.endPoint.y()))
        path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 4))
        path.lineTo(QPointF(self.endPoint.x(), self.endPoint.y() - 2))

        #Curve 2 (back)
        endPoint = QPointF(self.beginPoint.x(), self.beginPoint.y() - yTranslation)
        curvePoint2 = QPointF(self.curvePoint1.x(), self.curvePoint1.y() - yTranslation)
        curvePoint1 = QPointF(self.curvePoint2.x(), self.curvePoint2.y() - yTranslation)
        beginPoint = QPointF(self.endPoint.x(), self.endPoint.y() - yTranslation)
        point1 = QPointF(curvePoint1.x(), curvePoint1.y())
        point2 = QPointF(curvePoint2.x(), curvePoint2.y())
        path.cubicTo(point1, point2, endPoint) 

        if self.beginSide == 'right':
            path.lineTo(QPointF(self.beginPoint.x() - 10, self.beginPoint.y() - 2))
            path.lineTo(QPointF(self.beginPoint.x() - 10, self.beginPoint.y() + 2))            
        else:
            path.lineTo(QPointF(self.beginPoint.x() + 10, self.beginPoint.y() - 2))
            path.lineTo(QPointF(self.beginPoint.x() + 10, self.beginPoint.y() + 2))
        path.lineTo(QPointF(self.beginPoint.x(), self.beginPoint.y() + 2))

        return path
示例#45
0
    def getModelPos(self, pos: QPointF) -> Vec3T:
        """Y-axis is inverted in Qt +y === DOWN

        Args:
            pos: a position in this scene

        Returns:
            position in model coordinates
        """
        sf = self.scale_factor
        x, y = pos.x()/sf, -1.0*pos.y()/sf
        return x, y, 0.
示例#46
0
    def helixIndex(self, point: QPointF) -> Vec2T:
        """Returns the (row, col) of the base which point lies within.

        Returns:
            point (tuple) in virtual_helix_item coordinates

        Args:
            point (TYPE): Description
        """
        x = int(int(point.x()) / _BW)
        y = int(int(point.y()) / _BW)
        return (x, y)
示例#47
0
    def reconfigureRect(self,   top_left: Vec2T,
                                bottom_right: Vec2T,
                                padding: int = 80
                                ) -> Tuple[Vec2T, Vec2T]:
        """Summary

        Args:
            top_left: top left corner point
            bottom_right: bottom right corner point
            padding: padding of the rectagle in pixels points

        Returns:
            tuple of point tuples representing the ``top_left`` and
                ``bottom_right`` as reconfigured with ``padding``
        """
        rect = self._rect
        ptTL = QPointF(*self._padTL(padding, *top_left)) if top_left else rect.topLeft()
        ptBR = QPointF(*self._padBR(padding, *bottom_right)) if bottom_right else rect.bottomRight()
        self._rect = new_rect = QRectF(ptTL, ptBR)
        self.setRect(new_rect)
        self._configureOutline(self.outline)
        self.griditem.updateGrid()
        return (ptTL.x(), ptTL.y()), (ptBR.x(), ptBR.y())
示例#48
0
 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
示例#49
0
    def keyPressed(self, event):
        if (self.mAction != Action.NoAction):
            event.ignore()
            return

        moveBy = QPointF()
        x = event.key()
        if x==Qt.Key_Up:
            moveBy = QPointF(0, -1)
        elif x==Qt.Key_Down:
            moveBy = QPointF(0, 1)
        elif x==Qt.Key_Left:
            moveBy = QPointF(-1, 0)
        elif x==Qt.Key_Right:
            moveBy = QPointF(1, 0)
        else:
            super().keyPressed(event)
            return

        items = self.mapScene().selectedObjectItems()
        modifiers = event.modifiers()
        if (moveBy.isNull() or items.isEmpty() or (modifiers & Qt.ControlModifier)):
            event.ignore()
            return

        moveFast = modifiers & Qt.ShiftModifier
        snapToFineGrid = preferences.Preferences.instance().snapToFineGrid()
        if (moveFast):
            # TODO: This only makes sense for orthogonal maps
            moveBy.setX(moveBy.x() * self.mapDocument().map().tileWidth())
            moveBy.setX(moveBy.y() * self.mapDocument().map().tileHeight())
            if (snapToFineGrid):
                moveBy /= preferences.Preferences.instance().gridFine()

        undoStack = self.mapDocument().undoStack()
        undoStack.beginMacro(self.tr("Move %n Object(s)", "", items.size()))
        i = 0
        for objectItem in items:
            object = objectItem.mapObject()
            oldPos = object.position()
            newPos = oldPos + moveBy
            undoStack.push(MoveMapObject(self.mapDocument(), object, newPos, oldPos))
            i += 1

        undoStack.endMacro()
示例#50
0
    def animate(self):
        self.angle += (math.pi / 30)
        xs = 200 * math.sin(self.angle) - 40 + 25
        ys = 200 * math.cos(self.angle) - 40 + 25
        self.m_lightSource.setPos(xs, ys)

        for item in self.m_items:
            effect = item.graphicsEffect()

            delta = QPointF(item.x() - xs, item.y() - ys)
            effect.setOffset(QPointF(delta.toPoint() / 30))

            dd = math.hypot(delta.x(), delta.y())
            color = effect.color()
            color.setAlphaF(max(0.4, min(1 - dd / 200.0, 0.7)))
            effect.setColor(color)

        self.m_scene.update()
示例#51
0
    def zoom(self, step, anchor="center"):
        """
        Zooms the view by *step* increments (with a scale factor of
        1.2^*step*), anchored to *anchor*:

        - QPoint_: center on that point
        - "cursor": center on the mouse cursor position
        - "center": center on the viewport
        - None: don’t anchor, i.e. stick to the viewport’s top-left.

        # TODO: improve docs from QGraphicsView descriptions.

        The default is "center".

        .. _QPoint: http://doc.qt.io/qt-5/qpoint.html
        """
        oldScale = self._scale
        newScale = self._scale * pow(1.2, step)
        scrollArea = self._scrollArea
        if newScale < 1e-2 or newScale > 1e3:
            return
        if scrollArea is not None:
            # compute new scrollbar position
            # http://stackoverflow.com/a/32269574/2037879
            hSB = scrollArea.horizontalScrollBar()
            vSB = scrollArea.verticalScrollBar()
            viewport = scrollArea.viewport()
            if isinstance(anchor, QPoint):
                pos = anchor
            elif anchor == "cursor":
                pos = self.mapFromGlobal(QCursor.pos())
            elif anchor == "center":
                pos = self.mapFromParent(
                    QPoint(viewport.width() / 2, viewport.height() / 2))
            else:
                raise ValueError("invalid anchor value: {}".format(anchor))
            scrollBarPos = QPointF(hSB.value(), vSB.value())
            deltaToPos = pos / oldScale
            delta = deltaToPos * (newScale - oldScale)
        self.setScale(newScale)
        self.update()
        if scrollArea is not None:
            hSB.setValue(scrollBarPos.x() + delta.x())
            vSB.setValue(scrollBarPos.y() + delta.y())
示例#52
0
 def wheelEvent(self, event):
     if event.modifiers() & Qt.ControlModifier:
         factor = pow(1.2, event.angleDelta().y() / 120.0)
         pos = event.pos()
         # compute new scrollbar position
         # http://stackoverflow.com/a/32269574/2037879
         oldScale = self._scale
         newScale = self._scale * factor
         hSB = self._scrollArea.horizontalScrollBar()
         vSB = self._scrollArea.verticalScrollBar()
         scrollBarPos = QPointF(hSB.value(), vSB.value())
         deltaToPos = (self.mapToParent(pos) - self.pos()) / oldScale
         delta = deltaToPos * (newScale - oldScale)
         # TODO: maybe put out a func that does multiply by default
         self.setScale(newScale)
         # TODO: maybe merge this in setScale
         self.adjustSize()
         self.update()
         hSB.setValue(scrollBarPos.x() + delta.x())
         vSB.setValue(scrollBarPos.y() + delta.y())
         event.accept()
     else:
         super().wheelEvent(event)
示例#53
0
    def offsetObjects(self, offset, bounds, wrapX, wrapY):
        for object in self.mObjects:
            objectCenter = object.bounds().center()
            if (not bounds.contains(objectCenter)):
                continue
            newCenter = QPointF(objectCenter + offset)
            if (wrapX and bounds.width() > 0):
                nx = math.fmod(newCenter.x() - bounds.left(), bounds.width())
                if nx < 0:
                    x = bounds.width() + nx
                else:
                    x = nx
                newCenter.setX(bounds.left() + x)

            if (wrapY and bounds.height() > 0):
                ny = math.fmod(newCenter.y() - bounds.top(), bounds.height())
                if ny < 0:
                    x = bounds.height() + ny
                else:
                    x = ny
                newCenter.setY(bounds.top() + x)

            object.setPosition(object.position() + (newCenter - objectCenter))
示例#54
0
    def baseAtPoint(self, pos: QPointF) -> Tuple[StrandSetT, int]:
        """Returns the (Strandset, index) under the location x, y or None.

        It shouldn't be possible to click outside a pathhelix and still call
        this function. However, this sometimes happens if you click exactly
        on the top or bottom edge, resulting in a negative y value.

        Args:
            pos: Description
        """
        x, y = pos.x(), pos.y()
        part = self._model_part
        id_num = self._id_num
        base_idx = int(floor(x / _BASE_WIDTH))
        min_base, max_base = 0, part.maxBaseIdx(id_num)
        if base_idx < min_base or base_idx >= max_base:
            base_idx = util.clamp(base_idx, min_base, max_base)
        if y < 0:
            y = 0  # HACK: zero out y due to erroneous click
        strand_type = floor(y * 1. / _BASE_WIDTH)   # 0 for fwd, 1 for rev
        strand_type = int(util.clamp(strand_type, 0, 1))
        strand_set = part.getStrandSets(id_num)[strand_type]
        return (strand_set, base_idx)
示例#55
0
文件: ROI.py 项目: Cyber-Forensic/urh
    def get_selected_edge(self, pos: QPointF, width_view: float):
        """
        Bestimmt auf welcher Ecke der ROI der Mauszeiger gerade ist.
        0 = links, 1 = rechts

        :param pos: In die Szene gemappte Position des Mauszeigers
        """
        x1 = self.rect().x()
        x2 = x1 + self.rect().width()
        y1 = self.rect().y()
        y2 = y1 + self.rect().height()
        x = pos.x()
        y = pos.y()

        if x1 - 0.025 * width_view < x < x1 + 0.025 * width_view and y1 < y < y2:
            self.selected_edge = 0
            return 0

        if x2 - 0.025 * width_view < x < x2 + 0.025 * width_view and y1 < y < y2:
            self.selected_edge = 1
            return 1

        self.selected_edge = None
        return None
示例#56
0
 def paintEvent(self, evt):
     """
     Protected method handling a paint event.
     
     @param evt reference to the paint event (QPaintEvent)
     """
     painter = QPainter(self)
     
     if self.__image is not None and not self.__image.isNull():
         x = (self.width() - self.__image.width()) // 2 - 1
         y = (self.height() - self.__image.height()) // 2 - 1
         painter.drawImage(x, y, self.__image)
     
     if self.__menu is not None:
         triagPath = QPainterPath()
         startPos = QPointF(self.width() - 5, self.height() - 3)
         triagPath.moveTo(startPos)
         triagPath.lineTo(startPos.x() + 4, startPos.y())
         triagPath.lineTo(startPos.x() + 2, startPos.y() + 2)
         triagPath.closeSubpath()
         painter.setPen(Qt.black)
         painter.setBrush(Qt.black)
         painter.setRenderHint(QPainter.Antialiasing, False)
         painter.drawPath(triagPath)
示例#57
0
class MapObject(Object):
    ##
    # Enumerates the different object shapes. Rectangle is the default shape.
    # When a polygon is set, the shape determines whether it should be
    # interpreted as a filled polygon or a line.
    ##
    Rectangle, Polygon, Polyline, Ellipse = range(4)

    def __init__(self, *args):
        super().__init__(Object.MapObjectType)

        self.mPolygon = QPolygonF()
        self.mName = QString()
        self.mPos = QPointF()
        self.mCell = Cell()
        self.mType = QString()
        self.mId = 0
        self.mShape = MapObject.Rectangle
        self.mObjectGroup = None
        self.mRotation = 0.0
        self.mVisible = True

        l = len(args)
        if l==0:
            self.mSize = QSizeF(0, 0)
        elif l==4:
            name, _type, pos, size = args

            self.mName = name
            self.mType = _type
            self.mPos = pos
            self.mSize = QSizeF(size)

    ##
    # Returns the id of this object. Each object gets an id assigned that is
    # unique for the map the object is on.
    ##
    def id(self):
        return self.mId

    ##
    # Sets the id of this object.
    ##
    def setId(self, id):
        self.mId = id

    ##
    # Returns the name of this object. The name is usually just used for
    # identification of the object in the editor.
    ##
    def name(self):
        return self.mName

    ##
    # Sets the name of this object.
    ##
    def setName(self, name):
        self.mName = name

    ##
    # Returns the type of this object. The type usually says something about
    # how the object is meant to be interpreted by the engine.
    ##
    def type(self):
        return self.mType

    ##
    # Sets the type of this object.
    ##
    def setType(self, type):
        self.mType = type

    ##
    # Returns the position of this object.
    ##
    def position(self):
        return QPointF(self.mPos)

    ##
    # Sets the position of this object.
    ##
    def setPosition(self, pos):
        self.mPos = pos

    ##
    # Returns the x position of this object.
    ##
    def x(self):
        return self.mPos.x()

    ##
    # Sets the x position of this object.
    ##
    def setX(self, x):
        self.mPos.setX(x)

    ##
    # Returns the y position of this object.
    ##
    def y(self):
        return self.mPos.y()

    ##
    # Sets the x position of this object.
    ##
    def setY(self, y):
        self.mPos.setY(y)

    ##
    # Returns the size of this object.
    ##
    def size(self):
        return self.mSize

    ##
    # Sets the size of this object.
    ##
    def setSize(self, *args):
        l = len(args)
        if l==1:
            size = args[0]
            self.mSize = QSizeF(size)
        elif l==2:
            width, height = args
            self.setSize(QSizeF(width, height))

    ##
    # Returns the width of this object.
    ##
    def width(self):
        return self.mSize.width()

    ##
    # Sets the width of this object.
    ##
    def setWidth(self, width):
        self.mSize.setWidth(width)

    ##
    # Returns the height of this object.
    ##
    def height(self):
        return self.mSize.height()

    ##
    # Sets the height of this object.
    ##
    def setHeight(self, height):
        self.mSize.setHeight(height)

    ##
    # Sets the polygon associated with this object. The polygon is only used
    # when the object shape is set to either Polygon or Polyline.
    #
    # \sa setShape()
    ##
    def setPolygon(self, polygon):
        self.mPolygon = polygon

    ##
    # Returns the polygon associated with this object. Returns an empty
    # polygon when no polygon is associated with this object.
    ##
    def polygon(self):
        return QPolygonF(self.mPolygon)

    ##
    # Sets the shape of the object.
    ##
    def setShape(self, shape):
        self.mShape = shape

    ##
    # Returns the shape of the object.
    ##
    def shape(self):
        return self.mShape

    ##
    # Shortcut to getting a QRectF from position() and size().
    ##
    def bounds(self):
        return QRectF(self.mPos, self.mSize)

    ##
    # Shortcut to getting a QRectF from position() and size() that uses cell tile if present.
    ##
    def boundsUseTile(self):
        if (self.mCell.isEmpty()):
            # No tile so just use regular bounds
            return self.bounds()

        # Using the tile for determing boundary
        # Note the position given is the bottom-left corner so correct for that
        return QRectF(QPointF(self.mPos.x(),
                              self.mPos.y() - self.mCell.tile.height()),
                      self.mCell.tile.size())

    ##
    # Sets the tile that is associated with this object. The object will
    # display as the tile image.
    #
    # \warning The object shape is ignored for tile objects!
    ##
    def setCell(self, cell):
        self.mCell = cell

    ##
    # Returns the tile associated with this object.
    ##
    def cell(self):
        return self.mCell

    ##
    # Returns the object group this object belongs to.
    ##
    def objectGroup(self):
        return self.mObjectGroup

    ##
    # Sets the object group this object belongs to. Should only be called
    # from the ObjectGroup class.
    ##
    def setObjectGroup(self, objectGroup):
        self.mObjectGroup = objectGroup

    ##
    # Returns the rotation of the object in degrees.
    ##
    def rotation(self):
        return self.mRotation

    ##
    # Sets the rotation of the object in degrees.
    ##
    def setRotation(self, rotation):
        self.mRotation = rotation

    ##
    # This is somewhat of a workaround for dealing with the ways different objects
    # align.
    #
    # Traditional rectangle objects have top-left alignment.
    # Tile objects have bottom-left alignment on orthogonal maps, but
    # bottom-center alignment on isometric maps.
    #
    # Eventually, the object alignment should probably be configurable. For
    # backwards compatibility, it will need to be configurable on a per-object
    # level.
    ##
    def alignment(self):
        if (self.mCell.isEmpty()):
            return Alignment.TopLeft
        elif (self.mObjectGroup):
            map = self.mObjectGroup.map()
            if map:
                if (map.orientation() == Map.Orientation.Isometric):
                    return Alignment.Bottom

        return Alignment.BottomLeft

    def isVisible(self):
        return self.mVisible
    
    def setVisible(self, visible):
        self.mVisible = visible

    ##
    # Flip this object in the given \a direction. This doesn't change the size
    # of the object.
    ##
    def flip(self, direction):
        if (not self.mCell.isEmpty()):
            if (direction == FlipDirection.FlipHorizontally):
                self.mCell.flippedHorizontally = not self.mCell.flippedHorizontally
            elif (direction == FlipDirection.FlipVertically):
                self.mCell.flippedVertically = not self.mCell.flippedVertically

        if (not self.mPolygon.isEmpty()):
            center2 = self.mPolygon.boundingRect().center() * 2
            if (direction == FlipDirection.FlipHorizontally):
                for i in range(self.mPolygon.size()):
                    # oh, QPointF mPolygon returned is a copy of internal object
                    self.mPolygon[i] = QPointF(center2.x() - self.mPolygon[i].x(), self.mPolygon[i].y())
            elif (direction == FlipDirection.FlipVertically):
                for i in range(self.mPolygon.size()):
                    self.mPolygon[i] = QPointF(self.mPolygon[i].x(), center2.y() - self.mPolygon[i].y())

    ##
    # Returns a duplicate of this object. The caller is responsible for the
    # ownership of this newly created object.
    ##
    def clone(self):
        o = MapObject(self.mName, self.mType, self.mPos, self.mSize)
        o.setProperties(self.properties())
        o.setPolygon(self.mPolygon)
        o.setShape(self.mShape)
        o.setCell(self.mCell)
        o.setRotation(self.mRotation)
        return o
示例#58
0
class TeleopWidget(QWidget):

    stopSIG=pyqtSignal()

    def __init__(self,winParent):
        super(TeleopWidget, self).__init__()
        self.winParent=winParent
        self.line = QPointF(0, 0);
        self.qimage=QtGui.QImage()
        self.qimage.load(':images/ball.png')
        self.stopSIG.connect(self.stop)
        self.initUI()

    def initUI(self):
        layout=QGridLayout()
        self.setLayout(layout)
        self.setAutoFillBackground(True)
        p = self.palette()
        p.setColor(self.backgroundRole(), Qt.black)
        self.setPalette(p)
        self.resize(300,300)
        self.setMinimumSize(300,300)

    def stop(self):
        self.line = QPointF(0, 0);
        self.repaint();

    def mouseMoveEvent(self,e):
        if e.buttons() == Qt.LeftButton:
            x = e.x()-self.width()/2
            y = e.y()-self.height()/2
            self.line = QPointF(x, y)
            self.repaint()


    def returnToOrigin(self):
        x = 0
        y = 0
        self.line = QPointF(x, y)
        self.repaint()

    def paintEvent(self, e):
        _width = self.width()
        _height = self.height()


        width = 2

        painter=QtGui.QPainter(self)

        pen = QtGui.QPen(Qt.blue, width)
        painter.setPen(pen)

        #Centro del widget
        painter.translate(QPoint(_width/2, _height/2))

        #eje
        painter.drawLine(QPointF(-_width, 0),
                QPointF( _width, 0))

        painter.drawLine(QPointF(0, -_height),
                QPointF(0, _height))

        #con el raton
        pen = QtGui.QPen(Qt.red, width)
        painter.setPen(pen)

        #Comprobamos que el raton este dentro de los limites
        if abs(self.line.x()*2) >= self.size().width():
            if self.line.x()>=0:
                self.line.setX(self.size().width()/2)
            elif self.line.x()<0:
                self.line.setX((-self.size().width()/2)+1)

        if abs(self.line.y()*2) >= self.size().height():
            if self.line.y()>=0:
                self.line.setY(self.size().height()/2)
            elif self.line.y()<0:
                self.line.setY((-self.size().height()/2)+1)

        painter.drawLine(QPointF(self.line.x(), -_height),
                QPointF(self.line.x(), _height))

        painter.drawLine(QPointF(-_width, self.line.y()),
                QPointF( _width, self.line.y()))

        #print "x: %f y: %f" % (self.line.x(), self.line.y())

        v_normalized = (1.0/(self.size().height()/2)) * self.line.y()
        v_normalized = float("{0:.2f}".format(v_normalized))
        w_normalized = (1.0/(self.size().width()/2)) * self.line.x()
        w_normalized = float("{0:.2f}".format(w_normalized))

        #print "v: %f w: %f" % (v_normalized,w_normalized)
        self.winParent.setXYValues(w_normalized,v_normalized)
        painter.drawImage(self.line.x()-self.qimage.width()/2, self.line.y()-self.qimage.height()/2, self.qimage);
示例#59
0
class BrushingModel(QObject):
    brushSizeChanged = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged = pyqtSignal(int)

    minBrushSize = 1
    maxBrushSize = 61
    defaultBrushSize = 3
    defaultDrawnNumber = 1
    defaultColor = Qt.white
    erasingColor = Qt.black
    erasingNumber = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb = QRect()  # bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        # an empty scene, where we add all drawn line segments
        # a QGraphicsLineItem, and which we can use to then
        # render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not (self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b - 1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b + 1)

    def setBrushColor(self, color):
        self.drawColor = QColor(color)
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        """

        pos -- QPointF-like
        """
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved  # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert self.pos == pos
            self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001))  # move a little

        # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage.
        # We seem to get better results if we do the following:
        # 1) Slightly offset the source window because apparently there is a small shift in the data
        # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x)
        # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image,
        #     applying some threshold to determine if the final pixel is on or off.

        tempi = QImage(
            QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied
        )  # TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        # Offset the source window.  At first I thought the right offset was 0.5, because
        #  that would seem to make sure points are rounded to pixel CENTERS, but
        #  experimentation indicates that 0.25 is slightly better for some reason...
        source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height()))
        target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height()))
        self.scene.render(painter, target=target_rect, source=source_rect)
        painter.end()

        # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing
        ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int)
        ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr //= 4 * 4

        downsample_threshold = (7.0 / 16) * 255
        labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0))
        labels = labels.swapaxes(0, 1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0:
            labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        # data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x, y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        # update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1))
        # grow bounding box
        self.bb.setLeft(min(self.bb.left(), max(0, x - self.brushSize // 2 - 1)))
        self.bb.setRight(max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1)))
        self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1)))
        self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1)))

        # update/move position
        self.pos = pos
示例#60
0
    def interactiveResize(self, mousePos):
        """
        Handle the interactive resize of the shape.
        :type mousePos: QPointF
        """
        scene = self.scene()
        snap = scene.mainwindow.snapToGrid
        size = scene.GridSize
        offset = self.handleSize + self.handleMove
        moved = self.label.moved

        R = QRectF(self.boundingRect())
        D = QPointF(0, 0)

        minBoundW = self.minwidth + offset * 2
        minBoundH = self.minheight + offset * 2

        self.prepareGeometryChange()

        if self.mousePressHandle == self.handleTL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setLeft(R.left())
            self.background.setTop(R.top())
            self.selection.setLeft(R.left())
            self.selection.setTop(R.top())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTM:

            fromY = self.mousePressBound.top()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, -offset, snap)
            D.setY(toY - fromY)
            R.setTop(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setTop(R.top())
            self.selection.setTop(R.top())
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleTR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.top()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, -offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setTop(toY)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() - minBoundH + R.height())
                R.setTop(R.top() - minBoundH + R.height())

            self.background.setRight(R.right())
            self.background.setTop(R.top())
            self.selection.setRight(R.right())
            self.selection.setTop(R.top())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setTop(R.top() + offset)

        elif self.mousePressHandle == self.handleML:

            fromX = self.mousePressBound.left()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, -offset, snap)
            D.setX(toX - fromX)
            R.setLeft(toX)

             ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())

            self.background.setLeft(R.left())
            self.selection.setLeft(R.left())
            self.polygon.setLeft(R.left() + offset)

        elif self.mousePressHandle == self.handleMR:

            fromX = self.mousePressBound.right()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toX = snapF(toX, size, +offset, snap)
            D.setX(toX - fromX)
            R.setRight(toX)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())

            self.background.setRight(R.right())
            self.selection.setRight(R.right())
            self.polygon.setRight(R.right() - offset)

        elif self.mousePressHandle == self.handleBL:

            fromX = self.mousePressBound.left()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, -offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setLeft(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() - minBoundW + R.width())
                R.setLeft(R.left() - minBoundW + R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setLeft(R.left())
            self.background.setBottom(R.bottom())
            self.selection.setLeft(R.left())
            self.selection.setBottom(R.bottom())
            self.polygon.setLeft(R.left() + offset)
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBM:

            fromY = self.mousePressBound.bottom()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toY = snapF(toY, size, +offset, snap)
            D.setY(toY - fromY)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setBottom(R.bottom())
            self.selection.setBottom(R.bottom())
            self.polygon.setBottom(R.bottom() - offset)

        elif self.mousePressHandle == self.handleBR:

            fromX = self.mousePressBound.right()
            fromY = self.mousePressBound.bottom()
            toX = fromX + mousePos.x() - self.mousePressPos.x()
            toY = fromY + mousePos.y() - self.mousePressPos.y()
            toX = snapF(toX, size, +offset, snap)
            toY = snapF(toY, size, +offset, snap)
            D.setX(toX - fromX)
            D.setY(toY - fromY)
            R.setRight(toX)
            R.setBottom(toY)

            ## CLAMP SIZE
            if R.width() < minBoundW:
                D.setX(D.x() + minBoundW - R.width())
                R.setRight(R.right() + minBoundW - R.width())
            if R.height() < minBoundH:
                D.setY(D.y() + minBoundH - R.height())
                R.setBottom(R.bottom() + minBoundH - R.height())

            self.background.setRight(R.right())
            self.background.setBottom(R.bottom())
            self.selection.setRight(R.right())
            self.selection.setBottom(R.bottom())
            self.polygon.setRight(R.right() - offset)
            self.polygon.setBottom(R.bottom() - offset)

        self.updateHandles()
        self.updateTextPos(moved=moved)
        self.updateAnchors(self.mousePressData, D)