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()
def _updateTextAnchors(self): n = len(self._items) items = self._items dist = 15 shape = reduce(QPainterPath.united, [item.path() for item in items]) brect = shape.boundingRect() bradius = max(brect.width() / 2, brect.height() / 2) center = self.boundingRect().center() anchors = _category_anchors(items) self._textanchors = [] for angle, anchor_h, anchor_v in anchors: line = QLineF.fromPolar(bradius, angle) ext = QLineF.fromPolar(dist, angle) line = QLineF(line.p1(), line.p2() + ext.p2()) line = line.translated(center) anchor_pos = line.p2() self._textanchors.append((anchor_pos, anchor_h, anchor_v)) for i in range(n): self._updateTextItemPos(i)
def draw_arrow(self, line, width, color): (x1, y1), (x2, y2) = line # compute points line = QLineF(x1, y1, x2, y2) # If the line is very small, we make our arrowhead smaller arrowsize = min(14, line.length()) lineangle = radians(line.angle()) arrowpt1 = line.p2() + QPointF(sin(lineangle - (pi/3)) * arrowsize, cos(lineangle - (pi/3)) * arrowsize) arrowpt2 = line.p2() + QPointF(sin(lineangle - pi + (pi/3)) * arrowsize, cos(lineangle - pi + (pi/3)) * arrowsize) head = QPolygonF([line.p2(), arrowpt1, arrowpt2]) # We have to draw the actual line a little short for the tip of the arrowhead not to be too wide adjustedLine = QLineF(line) adjustedLine.setLength(line.length() - arrowsize/2) # draw line painter = self.current_painter color = COLORS[color] painter.save() pen = QPen(painter.pen()) pen.setColor(color) pen.setWidthF(width) painter.setPen(pen) painter.drawLine(adjustedLine) # draw arrowhead painter.setPen(Qt.NoPen) brush = painter.brush() brush.setColor(color) brush.setStyle(Qt.SolidPattern) painter.setBrush(brush) painter.drawPolygon(head) painter.restore()
def setLine(self, line): """ Set the arrow base line (a `QLineF` in object coordinates). """ if self.__line != line: self.__line = line # local item coordinate system geom = self.geometry().translated(-self.pos()) if geom.isNull() and not line.isNull(): geom = QRectF(0, 0, 1, 1) arrow_shape = arrow_path_concave(line, self.lineWidth()) arrow_rect = arrow_shape.boundingRect() if not (geom.contains(arrow_rect)): geom = geom.united(arrow_rect) if self.__autoAdjustGeometry: # Shrink the geometry if required. geom = geom.intersected(arrow_rect) # topLeft can move changing the local coordinates. diff = geom.topLeft() line = QLineF(line.p1() - diff, line.p2() - diff) self.__arrowItem.setLine(line) self.__line = line # parent item coordinate system geom.translate(self.pos()) self.setGeometry(geom)
def arrow_path_concave(line, width): """ Return a :class:`QPainterPath` of a pretty looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) start, end = baseline.p1(), baseline.p2() mid = (start + end) / 2.0 normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2() path.moveTo(start) path.lineTo(start + (normal * width / 4.0)) path.quadTo(mid + (normal * width / 4.0), end + (normal * width / 1.5)) path.lineTo(end - (normal * width / 1.5)) path.quadTo(mid - (normal * width / 4.0), start - (normal * width / 4.0)) path.closeSubpath() arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), baseline.p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def paintArc(self, painter, option, widget): assert self.source is self.dest node = self.source def best_angle(): """...is the one furthest away from all other angles""" angles = [ QLineF(node.pos(), other.pos()).angle() for other in chain( (edge.source for edge in node.edges if edge.dest == node and edge.source != node), (edge.dest for edge in node.edges if edge.dest != node and edge.source == node), ) ] angles.sort() if not angles: # If this self-constraint is the only edge return 225 deltas = np.array(angles[1:] + [360 + angles[0]]) - angles return (angles[deltas.argmax()] + deltas.max() / 2) % 360 angle = best_angle() inf = QPointF(-1e20, -1e20) # Doesn't work with real -np.inf! line0 = QLineF(node.pos(), inf) line1 = QLineF(node.pos(), inf) line2 = QLineF(node.pos(), inf) line0.setAngle(angle) line1.setAngle(angle - 13) line2.setAngle(angle + 13) p0 = shape_line_intersection(node.shape(), node.pos(), line0) p1 = shape_line_intersection(node.shape(), node.pos(), line1) p2 = shape_line_intersection(node.shape(), node.pos(), line2) path = QtGui.QPainterPath() path.moveTo(p1) line = QLineF(node.pos(), p0) line.setLength(3 * line.length()) pt = line.p2() path.quadTo(pt, p2) line = QLineF(node.pos(), pt) self.setLine(line) # This invalidates DeviceCoordinateCache painter.drawPath(path) # Draw arrow head line = QLineF(pt, p2) self.arrowHead.clear() for point in self._arrowhead_points(line): self.arrowHead.append(point) painter.setBrush(self.pen().color()) painter.drawPolygon(self.arrowHead) # Update label position self.label.setPos(path.pointAtPercent(0.5)) if 90 < angle < 270: # Right-align the label pos = self.label.pos() x, y = pos.x(), pos.y() self.label.setPos(x - self.label.boundingRect().width(), y) self.squares.placeBelow(self.label)
def paintArc(self, painter, option, widget): assert self.source is self.dest node = self.source def best_angle(): """...is the one furthest away from all other angles""" angles = [ QLineF(node.pos(), other.pos()).angle() for other in chain(( edge.source for edge in node.edges if edge.dest == node and edge.source != node), ( edge.dest for edge in node.edges if edge.dest != node and edge.source == node)) ] angles.sort() if not angles: # If this self-constraint is the only edge return 225 deltas = np.array(angles[1:] + [360 + angles[0]]) - angles return (angles[deltas.argmax()] + deltas.max() / 2) % 360 angle = best_angle() inf = QPointF(-1e20, -1e20) # Doesn't work with real -np.inf! line0 = QLineF(node.pos(), inf) line1 = QLineF(node.pos(), inf) line2 = QLineF(node.pos(), inf) line0.setAngle(angle) line1.setAngle(angle - 13) line2.setAngle(angle + 13) p0 = shape_line_intersection(node.shape(), node.pos(), line0) p1 = shape_line_intersection(node.shape(), node.pos(), line1) p2 = shape_line_intersection(node.shape(), node.pos(), line2) path = QtGui.QPainterPath() path.moveTo(p1) line = QLineF(node.pos(), p0) line.setLength(3 * line.length()) pt = line.p2() path.quadTo(pt, p2) line = QLineF(node.pos(), pt) self.setLine(line) # This invalidates DeviceCoordinateCache painter.drawPath(path) # Draw arrow head line = QLineF(pt, p2) self.arrowHead.clear() for point in self._arrowhead_points(line): self.arrowHead.append(point) painter.setBrush(self.pen().color()) painter.drawPolygon(self.arrowHead) # Update label position self.label.setPos(path.pointAtPercent(.5)) if 90 < angle < 270: # Right-align the label pos = self.label.pos() x, y = pos.x(), pos.y() self.label.setPos(x - self.label.boundingRect().width(), y) self.squares.placeBelow(self.label)
def arrow_path_concave(line, width): """ Return a :class:`QPainterPath` of a pretty looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) start, end = baseline.p1(), baseline.p2() mid = (start + end) / 2.0 normal = QLineF.fromPolar(1.0, baseline.angle() + 90).p2() path.moveTo(start) path.lineTo(start + (normal * width / 4.0)) path.quadTo(mid + (normal * width / 4.0), end + (normal * width / 1.5)) path.lineTo(end - (normal * width / 1.5)) path.quadTo(mid - (normal * width / 4.0), start - (normal * width / 4.0)) path.closeSubpath() arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), baseline.p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2 ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def drawToolButtonMenuIndicator(self, option, painter, widget=None): arrow_rect = self.proxy().subControlRect(QStyle.CC_ToolButton, option, QStyle.SC_ToolButtonMenu, widget) text_color = option.palette.color(QPalette.WindowText if option.state & QStyle.State_AutoRaise else QPalette.ButtonText) button_color = option.palette.color(QPalette.Button) background_color = self.background_color(button_color, 0.5) painter.save() # draw separating vertical line if option.state & (QStyle.State_On|QStyle.State_Sunken): top_offset, bottom_offset = 4, 3 else: top_offset, bottom_offset = 2, 2 if option.direction == Qt.LeftToRight: separator_line = QLineF(arrow_rect.x()-3, arrow_rect.top()+top_offset, arrow_rect.x()-3, arrow_rect.bottom()-bottom_offset) else: separator_line = QLineF(arrow_rect.right()+3, arrow_rect.top()+top_offset, arrow_rect.right()+3, arrow_rect.bottom()-bottom_offset) light_gradient = QLinearGradient(separator_line.p1(), separator_line.p2()) light_gradient.setColorAt(0.0, ColorScheme.shade(self.background_top_color(button_color), ColorScheme.LightShade, 0.0)) light_gradient.setColorAt(1.0, ColorScheme.shade(self.background_bottom_color(button_color), ColorScheme.MidlightShade, 0.5)) separator_color = ColorScheme.shade(self.background_bottom_color(button_color), ColorScheme.MidShade, 0.0) painter.setRenderHint(QPainter.Antialiasing, False) painter.setPen(QPen(light_gradient, 1)) painter.drawLine(separator_line.translated(-1, 0)) painter.drawLine(separator_line.translated(+1, 0)) painter.setPen(QPen(separator_color, 1)) painter.drawLine(separator_line) # draw arrow arrow = QPolygonF([QPointF(-3, -1.5), QPointF(0.5, 2.5), QPointF(4, -1.5)]) if option.direction == Qt.LeftToRight: arrow.translate(-2, 1) else: arrow.translate(+2, 1) pen_thickness = 1.6 painter.setRenderHint(QPainter.Antialiasing, True) painter.translate(arrow_rect.center()) painter.translate(0, +1) painter.setPen(QPen(self.calc_light_color(background_color), pen_thickness, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawPolyline(arrow) painter.translate(0, -1) painter.setPen(QPen(self.deco_color(background_color, text_color), pen_thickness, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawPolyline(arrow) painter.restore()
def draw_arrow(self, line, width, color): (x1, y1), (x2, y2) = line # compute points line = QLineF(x1, y1, x2, y2) # If the line is very small, we make our arrowhead smaller arrowsize = min(14, line.length()) lineangle = radians(line.angle()) arrowpt1 = line.p2() + QPointF( sin(lineangle - (pi / 3)) * arrowsize, cos(lineangle - (pi / 3)) * arrowsize) arrowpt2 = line.p2() + QPointF( sin(lineangle - pi + (pi / 3)) * arrowsize, cos(lineangle - pi + (pi / 3)) * arrowsize) head = QPolygonF([line.p2(), arrowpt1, arrowpt2]) # We have to draw the actual line a little short for the tip of the arrowhead not to be too wide adjustedLine = QLineF(line) adjustedLine.setLength(line.length() - arrowsize / 2) # draw line painter = self.current_painter color = COLORS[color] painter.save() pen = QPen(painter.pen()) pen.setColor(color) pen.setWidthF(width) painter.setPen(pen) painter.drawLine(adjustedLine) # draw arrowhead painter.setPen(Qt.NoPen) brush = painter.brush() brush.setColor(color) brush.setStyle(Qt.SolidPattern) painter.setBrush(brush) painter.drawPolygon(head) painter.restore()
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()
def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) if startPoint.x() > endPoint.x(): dist = (startPoint.x() - endPoint.x()) * 2 tLine = QLineF((dist / 2), 0.0, -(dist / 2), 0.0).translated(QLineF(startPoint, endPoint).pointAt(0.5)) one = tLine.p1() two = tLine.p2() path.cubicTo(one, two, endPoint) self.__path = path return path, QLineF(one, two)
def arrow_path_plain(line, width): """ Return an :class:`QPainterPath` of a plain looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) path.moveTo(baseline.p1()) path.lineTo(baseline.p2()) stroker = QPainterPathStroker() stroker.setWidth(width) path = stroker.createStroke(path) arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2, ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def arrow_path_plain(line, width): """ Return an :class:`QPainterPath` of a plain looking arrow. """ path = QPainterPath() p1, p2 = line.p1(), line.p2() if p1 == p2: return path baseline = QLineF(line) # Require some minimum length. baseline.setLength(max(line.length() - width * 3, width * 3)) path.moveTo(baseline.p1()) path.lineTo(baseline.p2()) stroker = QPainterPathStroker() stroker.setWidth(width) path = stroker.createStroke(path) arrow_head_len = width * 4 arrow_head_angle = 50 line_angle = line.angle() - 180 angle_1 = line_angle - arrow_head_angle / 2.0 angle_2 = line_angle + arrow_head_angle / 2.0 points = [ p2, p2 + QLineF.fromPolar(arrow_head_len, angle_1).p2(), p2 + QLineF.fromPolar(arrow_head_len, angle_2).p2(), p2 ] poly = QPolygonF(points) path_head = QPainterPath() path_head.addPolygon(poly) path = path.united(path_head) return path
def adjustGeometry(self): """ Adjust the widget geometry to exactly fit the arrow inside while preserving the arrow path scene geometry. """ # local system coordinate geom = self.geometry().translated(-self.pos()) line = self.__line arrow_rect = self.__arrowItem.shape().boundingRect() if geom.isNull() and not line.isNull(): geom = QRectF(0, 0, 1, 1) if not (geom.contains(arrow_rect)): geom = geom.united(arrow_rect) geom = geom.intersected(arrow_rect) diff = geom.topLeft() line = QLineF(line.p1() - diff, line.p2() - diff) geom.translate(self.pos()) self.setGeometry(geom) self.setLine(line)
def render(o): path = QPainterPath() # unit_x gives offset and direction of the x base vector. Start and end should be the grid points. # move the endpoints inwards an unnoticable bit, so that the intersection detector # won't trip on the common endpoint. u_x = QLineF(o.unit_x.pointAt(0.0001), o.unit_x.pointAt(0.9999)) path.moveTo(u_x.p1()) if o.is_straight: path.lineTo(u_x.p2()) return path if o.flipped: u_x = QLineF(u_x.p2(), u_x.p1()) u_y = u_x.normalVector() # move y unit to start at (0,0). u_y.translate(-u_y.p1()) scaling = o.length_base / u_x.length() * o.size_correction if o.basewidth * scaling > 0.8: # Plug is too large for the edge length. Make it smaller. scaling = 0.8 / o.basewidth # some magic numbers here... carefully fine-tuned, better leave them as they are. ends_ctldist = 0.4 #base_lcdist = 0.1 * scaling base_ucdist = 0.05 * scaling knob_lcdist = 0.6 * o.knobsize * scaling knob_ucdist = 0.8 * o.knobsize * scaling # set up piece -- here is where the really interesting stuff happens. # We will work from the ends inwards, so that symmetry counterparts are adjacent. # The QLine.pointAt function is used to transform everything into the coordinate # space defined by the us. # -- end points r1y = ends_ctldist * o.basepos * dsin(o.startangle) q6y = ends_ctldist * (1. - o.basepos) * dsin(o.endangle) p1 = u_x.p1() p6 = u_x.p2() r1 = u_x.pointAt( ends_ctldist * o.basepos * dcos(o.startangle)) + u_y.pointAt(r1y) q6 = u_x.pointAt(1. - ends_ctldist * (1. - o.basepos) * dcos(o.endangle)) + u_y.pointAt(q6y) # -- base points p2x = o.basepos - 0.5 * o.basewidth * scaling p5x = o.basepos + 0.5 * o.basewidth * scaling if p2x < 0.1 or p5x > 0.9: # knob to large. center knob on the edge. (o.basewidth * scaling < 0.8 -- see above) p2x = 0.5 - 0.5 * o.basewidth * scaling p5x = 0.5 + 0.5 * o.basewidth * scaling #base_y = r1y > q6y ? r1y : q6y #base_y = 0.5*(r1y + q6y) base_y = -o.baseroundness * ends_ctldist * min(p2x, 1. - p5x) if base_y > 0: base_y = 0 base_lcy = base_y * 2.0 base_y += base_ucdist / 2 base_lcy -= base_ucdist / 2 #base_lcy = r1y #if (q6y < r1y): base_lcy = q6y # at least -base_ucdist from base_y #if (base_lcy > base_y - base_ucdist): base_lcy = base_y-base_ucdist q2 = u_x.pointAt(p2x) + u_y.pointAt(base_lcy) r5 = u_x.pointAt(p5x) + u_y.pointAt(base_lcy) p2 = u_x.pointAt(p2x) + u_y.pointAt(base_y) p5 = u_x.pointAt(p5x) + u_y.pointAt(base_y) r2 = u_x.pointAt(p2x) + u_y.pointAt(base_y + base_ucdist) q5 = u_x.pointAt(p5x) + u_y.pointAt(base_y + base_ucdist) if o._is_plugless: if not o.flipped: path.cubicTo(r1, q2, p2) path.cubicTo(r2, q5, p5) path.cubicTo(r5, q6, p6) else: path.cubicTo(q6, r5, p5) path.cubicTo(q5, r2, p2) path.cubicTo(q2, r1, p1) return path # -- knob points p3x = p2x - o.knobsize * scaling * dsin(o.knobangle - o.knobtilt) p4x = p5x + o.knobsize * scaling * dsin(o.knobangle + o.knobtilt) # for the y coordinate, knobtilt sign was swapped. Knobs look better this way... # like x offset from base points y, but that is 0. p3y = o.knobsize * scaling * dcos(o.knobangle + o.knobtilt) + base_y p4y = o.knobsize * scaling * dcos(o.knobangle - o.knobtilt) + base_y q3 = u_x.pointAt(p3x) + u_y.pointAt(p3y - knob_lcdist) r4 = u_x.pointAt(p4x) + u_y.pointAt(p4y - knob_lcdist) p3 = u_x.pointAt(p3x) + u_y.pointAt(p3y) p4 = u_x.pointAt(p4x) + u_y.pointAt(p4y) r3 = u_x.pointAt(p3x) + u_y.pointAt(p3y + knob_ucdist) q4 = u_x.pointAt(p4x) + u_y.pointAt(p4y + knob_ucdist) # done setting up. construct path. # if flipped, add points in reverse. if not o.flipped: path.cubicTo(r1, q2, p2) path.cubicTo(r2, q3, p3) path.cubicTo(r3, q4, p4) path.cubicTo(r4, q5, p5) path.cubicTo(r5, q6, p6) else: path.cubicTo(q6, r5, p5) path.cubicTo(q5, r4, p4) path.cubicTo(q4, r3, p3) path.cubicTo(q3, r2, p2) path.cubicTo(q2, r1, p1) return path
class ControlPointLine(QGraphicsObject): lineChanged = Signal(QLineF) lineEdited = Signal(QLineF) def __init__(self, parent=None, **kwargs): QGraphicsObject.__init__(self, parent, **kwargs) self.setFlag(QGraphicsItem.ItemHasNoContents) self.setFlag(QGraphicsItem.ItemIsFocusable) self.__line = QLineF() self.__points = \ [ControlPoint(self, ControlPoint.TopLeft), # TopLeft is line start ControlPoint(self, ControlPoint.BottomRight) # line end ] self.__activeControl = None if self.scene(): self.__installFilter() for p in self.__points: p.setFlag(QGraphicsItem.ItemIsFocusable) p.setFocusProxy(self) def setLine(self, line): if not isinstance(line, QLineF): raise TypeError() if line != self.__line: self.__line = line self.__pointsLayout() self.lineChanged.emit(line) def line(self): return self.__line def isControlActive(self): """Return the state of the control. True if the control is active (user is dragging one of the points) False otherwise. """ return self.__activeControl is not None def __installFilter(self): for p in self.__points: p.installSceneEventFilter(self) def itemChange(self, change, value): if change == QGraphicsItem.ItemSceneHasChanged: if self.scene(): self.__installFilter() return QGraphicsObject.itemChange(self, change, value) def sceneEventFilter(self, obj, event): try: obj = toGraphicsObjectIfPossible(obj) if isinstance(obj, ControlPoint): etype = event.type() if etype == QEvent.GraphicsSceneMousePress: self.__setActiveControl(obj) elif etype == QEvent.GraphicsSceneMouseRelease: self.__setActiveControl(None) return QGraphicsObject.sceneEventFilter(self, obj, event) except Exception: log.error("", exc_info=True) def __pointsLayout(self): self.__points[0].setPos(self.__line.p1()) self.__points[1].setPos(self.__line.p2()) def __setActiveControl(self, control): if self.__activeControl != control: if self.__activeControl is not None: self.__activeControl.positionChanged[QPointF].disconnect( self.__activeControlMoved ) self.__activeControl = control if control is not None: control.positionChanged[QPointF].connect( self.__activeControlMoved ) def __activeControlMoved(self, pos): line = QLineF(self.__line) control = self.__activeControl if control.anchor() == ControlPoint.TopLeft: line.setP1(pos) elif control.anchor() == ControlPoint.BottomRight: line.setP2(pos) if self.__line != line: self.blockSignals(True) self.setLine(line) self.blockSignals(False) self.lineEdited.emit(line) def boundingRect(self): return QRectF()
def crop_line(self, line, line_point): global_rect = self.globalBoundingRect() # Go to local coordinate system - ellipse equations assume ellipse is centered on (0,0) local_trans = global_rect.center() local_line = QLineF(line.p1() - local_trans, line.p2() - local_trans) if(local_line.dx() == 0): return line # Solve line equation e_a = ((local_line.p2().y() - local_line.p1().y()) / (local_line.p2().x() - local_line.p1().x())) e_b = local_line.p1().y() - e_a * local_line.p1().x() # ellipse params e_c = global_rect.width()/2 e_d = global_rect.height()/2 # check condition if(e_c * e_d == 0): return line # precalculate things that are used more than once # a^2, b^2 ... ak = math.pow(e_a, 2) bk = math.pow(e_b, 2) ck = math.pow(e_c, 2) dk = math.pow(e_d, 2) # check another condition if((ak * ck + dk) == 0): return line # a^2*c^2, c^2*d^2 akck = ak * ck ckdk = ck * dk # a*b*c^2 abck = e_a*e_b*ck # parts of denomiator and numerator of x denom = (akck + dk) numer = math.sqrt(ck*dk*(akck-bk+dk)) # Decide which points to take xrel = (line.p1().x() > line.p2().x()) yrel = (line.p1().y() > line.p2().y()) if(line_point != 0): xrel = not xrel yrel = not yrel if((xrel and yrel) or (xrel and not yrel)): x1 = (-numer - abck) / denom y1 = (e_b*dk - e_a*math.sqrt(-ckdk*(-akck+bk-dk))) / denom intersectionPoint = QPointF(x1, y1) elif((not xrel and yrel) or (not xrel and not yrel)): x2 = (numer - abck) / denom y2 = -(e_b*dk - e_a*math.sqrt(-ckdk*(-akck+bk-dk))) / denom intersectionPoint = QPointF(x2, y2) # Go back to global coordinate system intersectionPoint = intersectionPoint + local_trans if(line_point == 0): return QLineF(intersectionPoint, line.p2()) else: return QLineF(line.p1(), intersectionPoint) return line
class EEdge(QGraphicsObject): def __init__(self, head, tail, uuid, arrowed=False): QGraphicsObject.__init__(self) self.__arrowed = arrowed if not issubclass(head.__class__, dict) and not isinstance(tail.__class__, dict): raise AttributeError self.setZValue(0.0) self.__kId = uuid self.__head = head self.__tail = tail self.__path = QPainterPath() self.__headPoint = QPointF(0.0, 0.0) self.__tailPoint = QPointF(0.0, 0.0) self.__head[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__tail[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__pen = QPen(QColor(43, 43, 43), 2, Qt.SolidLine) self.update() @property def Id(self): return self.__kId @property def Line(self): return QLineF(self.__headPoint, self.__tailPoint) @property def Head(self): return self.__head @Head.setter def Head(self, newHead): self.__head = newHead @property def Tail(self): return self.__tail @Tail.setter def Tail(self, newTail): self.__tail = newTail def pen(self): return self.__pen def setPen(self, pen): if not isinstance(pen, QPen): raise AttributeError self.__pen = pen def update(self): QGraphicsObject.prepareGeometryChange(self) self.__headPoint = self.mapFromItem(self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributePlug]) self.__tailPoint = self.mapFromItem(self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributePlug]) self.__headOffsetLine = QLineF(self.__headPoint, QPointF(self.__headPoint.x() + 15, self.__headPoint.y())) self.__tailOffsetLine = QLineF(self.__tailPoint, QPointF(self.__tailPoint.x() - 15, self.__tailPoint.y())) line = QLineF(self.__headPoint, self.__tailPoint) self.__line = line def boundingRect(self): extra = (self.pen().width() * 64) / 2 return QRectF(self.__line.p1(), QSizeF(self.__line.p2().x() - self.__line.p1().x(), self.__line.p2().y() - self.__line.p1().y())).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): if self.__arrowed: return QGraphicsObject.shape(self) return QPainterPath(self.__path) def getIntersectPoint(self, polygon, point1, point2): p1 = polygon[0] + point1 intersectPoint = QPointF() for i in polygon: p2 = i + point2 polyLine = QLineF(p1, p2) intersectType = polyLine.intersect(QLineF(point1, point2), intersectPoint) if intersectType == QLineF.BoundedIntersection: break p1 = p2 return intersectPoint def getArrow(self, line): Pi = math.pi TwoPi = 2.0 * Pi arrowSize = 14 if line.length() > 0: angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = TwoPi - angle sourceArrowP1 = line.p1() + QPointF(math.sin(angle + Pi / 3) * arrowSize, math.cos(angle + Pi / 3) * arrowSize) sourceArrowP2 = line.p1() + QPointF(math.sin(angle + Pi - Pi / 3) * arrowSize, math.cos(angle + Pi - Pi / 3) * arrowSize) destinationArrowP1 = line.p2() + QPointF(math.sin(angle - Pi / 3) * arrowSize, math.cos(angle - Pi / 3) * arrowSize) destinationArrowP2 = line.p2() + QPointF(math.sin(angle - Pi + Pi / 3) * arrowSize, math.cos(angle - Pi + Pi / 3) * arrowSize) arrows = [QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]), QPolygonF([line.p2(), destinationArrowP1, destinationArrowP2])] return arrows[0] return QPolygonF() def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) if startPoint.x() > endPoint.x(): dist = (startPoint.x() - endPoint.x()) * 2 tLine = QLineF((dist / 2), 0.0, -(dist / 2), 0.0).translated(QLineF(startPoint, endPoint).pointAt(0.5)) one = tLine.p1() two = tLine.p2() path.cubicTo(one, two, endPoint) self.__path = path return path, QLineF(one, two) def paint(self, painter, option, widget=None): painter.setPen(self.pen()) if not self.__arrowed: headCenter = self.mapFromItem(self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributeParent].boundingRect().center()) tailCenter = self.mapFromItem(self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributeParent].boundingRect().center()) centerPoint = QLineF(headCenter, tailCenter).pointAt(0.5) centerPoint.setX(self.__headOffsetLine.p2().x()) centerPoint.setX(self.__tailOffsetLine.p2().x()) painter.drawPath(self.drawPath(self.__headOffsetLine.p1(), self.__tailOffsetLine.p1())[0]) else: painter.drawLine(self.__line) painter.setPen(Qt.NoPen) painter.setBrush(QColor(43, 43, 43)) headCutPoint = self.getIntersectPoint(self.__head[ENode.kGuiAttributeParent].Polygon, self.__line.p1(), self.__line.p2()) tailCutPoint = self.getIntersectPoint(self.__tail[ENode.kGuiAttributeParent].Polygon, self.__line.p2(), self.__line.p1()) painter.drawPolygon(self.getArrow(QLineF(headCutPoint, tailCutPoint)))
class SliderLine(QGraphicsObject): """A movable slider line.""" valueChanged = Signal(float) linePressed = Signal() lineMoved = Signal() lineReleased = Signal() rangeChanged = Signal(float, float) def __init__(self, parent=None, orientation=Qt.Vertical, value=0.0, length=10.0, **kwargs): self._orientation = orientation self._value = value self._length = length self._min = 0.0 self._max = 1.0 self._line = QLineF() self._pen = QPen() super().__init__(parent, **kwargs) self.setAcceptedMouseButtons(Qt.LeftButton) self.setPen(make_pen(brush=QColor(50, 50, 50), width=1, cosmetic=True)) if self._orientation == Qt.Vertical: self.setCursor(Qt.SizeVerCursor) else: self.setCursor(Qt.SizeHorCursor) def setPen(self, pen): pen = QPen(pen) if self._pen != pen: self.prepareGeometryChange() self._pen = pen self._line = None self.update() def pen(self): return QPen(self._pen) def setValue(self, value): value = min(max(value, self._min), self._max) if self._value != value: self.prepareGeometryChange() self._value = value self._line = None self.valueChanged.emit(value) def value(self): return self._value def setRange(self, minval, maxval): maxval = max(minval, maxval) if minval != self._min or maxval != self._max: self._min = minval self._max = maxval self.rangeChanged.emit(minval, maxval) self.setValue(self._value) def setLength(self, length): if self._length != length: self.prepareGeometryChange() self._length = length self._line = None def length(self): return self._length def setOrientation(self, orientation): if self._orientation != orientation: self.prepareGeometryChange() self._orientation = orientation self._line = None if self._orientation == Qt.Vertical: self.setCursor(Qt.SizeVerCursor) else: self.setCursor(Qt.SizeHorCursor) def mousePressEvent(self, event): event.accept() self.linePressed.emit() def mouseMoveEvent(self, event): pos = event.pos() if self._orientation == Qt.Vertical: self.setValue(pos.y()) else: self.setValue(pos.x()) self.lineMoved.emit() event.accept() def mouseReleaseEvent(self, event): if self._orientation == Qt.Vertical: self.setValue(event.pos().y()) else: self.setValue(event.pos().x()) self.lineReleased.emit() event.accept() def boundingRect(self): if self._line is None: if self._orientation == Qt.Vertical: self._line = QLineF(0, self._value, self._length, self._value) else: self._line = QLineF(self._value, 0, self._value, self._length) r = QRectF(self._line.p1(), self._line.p2()) penw = self.pen().width() return r.adjusted(-penw, -penw, penw, penw) def paint(self, painter, *args): if self._line is None: self.boundingRect() painter.save() painter.setPen(self.pen()) painter.drawLine(self._line) painter.restore()
class EDummy(QGraphicsObject): onEdit = pyqtSignal(QLineF) onPress = pyqtSignal() def __init__(self): QGraphicsObject.__init__(self) self.__uuid = uuid.uuid1() #self.setZValue(-0.5) self.__polygon = EDraw.Circle(7, 12) self.__isSnapMode = False self.__snapPoint = QPointF(0.0, 0.0) self.__gridSize = 10 self.__dummyLine = QLineF() self.__dummyData = None self.__editPointOne = None self.__BBTemp = None self.__angle = 0.0 def isEditMode(self): if self.__editPointOne: return True return False def toggleEditMode(self): if self.__editPointOne is None: self.__editPointOne = self.scenePos() self.__BBTemp = self.scenePos() self.setZValue(1.0) self.update() return self.setZValue(-0.5) self.onEdit.emit(QLineF(self.__editPointOne, self.scenePos())) self.__editPointOne = None self.__BBTemp = None self.update() def setSnapMode(self, snapMode): self.__isSnapMode = snapMode def setGridSize(self, gridSize): self.__gridSize = gridSize def setDummyData(self, dummyData): self.__dummyData = dummyData def getDummyData(self): return self.__dummyData @property def Id(self): return self.__uuid @property def Position(self): if self.__isSnapMode: return self.__snapPoint / self.__gridSize return self.scenePos() / self.__gridSize @property def Angle(self): return self.__angle def boundingRect(self): tempPoint = self.__snapPoint if self.__BBTemp is not None: tempPoint = self.__BBTemp radius = math.sqrt((self.scenePos().x() - tempPoint.x()) ** 2 + (self.scenePos().y() - tempPoint.y()) ** 2) return EDraw.Circle(radius + self.__gridSize / 2, 8).boundingRect().normalized().adjusted(-5, -5, 5, 5) def shape(self): path = QGraphicsItem.shape(self) return path def polygon(self): return self.__polygon def debug(self): return self.__dummyLine.p2() def dummyLine(self, angle=None, length=None): if angle is not None and length is not None: pt1 = QLineF(QPointF(0.0, 0.0), QPointF(0.0, 1.0)) pt1.setAngle(angle) pt1.setLength(length + 16) self.__dummyLine = pt1 return self.__dummyLine = QLineF() def paint(self, painter, option, widget=None): painter.setPen(EDraw.EColor.DefaultEnterHoverPen) lineX = QLineF(QPointF(self.__gridSize, 0.0), QPointF(0.0, 0.0)).translated(-self.scenePos()) lineY = QLineF(QPointF(0.0, -self.__gridSize), QPointF(0.0, 0.0)).translated(-self.scenePos()) painter.drawLines([lineX, lineY]) self.__snapPoint = QPointF(self.__gridSize * round(self.scenePos().x() / self.__gridSize), self.__gridSize * round(self.scenePos().y() / self.__gridSize)) if self.__isSnapMode: painter.drawPolygon(self.__polygon.translated(self.__snapPoint - self.scenePos())) self.__angle = 0.0 if self.__editPointOne is not None: painter.drawPolygon(EDraw.Circle(20, 24).translated(-(self.scenePos()) + self.__BBTemp)) painter.drawLine(QLineF(QPointF(-(self.scenePos()) + self.__BBTemp), QPointF(0.0, 0.0))) dummyLine = QLineF(QPointF(-(self.scenePos()) + self.__BBTemp), QPointF(0.0, 0.0)) painter.drawLine(QLineF(ETransform.rotatePoint(20, dummyLine.angle() + 180), QPointF()).translated(-(self.scenePos()) + self.__BBTemp)) painter.drawLine(QLineF(ETransform.rotatePoint(20, dummyLine.angle() + 360), QPointF()).translated(-(self.scenePos()) + self.__BBTemp)) self.__angle = dummyLine.angle() painter.drawPolygon(self.__polygon) painter.drawLine(self.__dummyLine) #painter.drawRect(self.boundingRect()) def mousePressEvent(self, event): QGraphicsObject.mousePressEvent(self, event) self.onPress.emit()
class EEdge(QGraphicsObject): def __init__(self, head, tail, uuid): QGraphicsObject.__init__(self) if not issubclass(head.__class__, dict) and not isinstance( tail.__class__, dict): raise AttributeError self.setZValue(0.0) self.__kId = uuid self.__head = head self.__tail = tail if head[ENode.kGuiAttributeType].match(EAttribute.kTypeInput): self.__head = tail self.__tail = head self.__head[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__tail[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__headPoint = QPointF(0.0, 0.0) self.__tailPoint = QPointF(0.0, 0.0) self.__pen = QPen(QColor(43, 43, 43), 2, Qt.SolidLine) self.update() @property def Id(self): return self.__kId @property def Head(self): return self.__head @property def Tail(self): return self.__tail def pen(self): return self.__pen def setPen(self, pen): if not isinstance(pen, QPen): raise AttributeError self.__pen = pen def update(self): QGraphicsObject.prepareGeometryChange(self) self.__headPoint = self.mapFromItem( self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributePlug]) self.__tailPoint = self.mapFromItem( self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributePlug]) self.__headOffsetLine = QLineF( self.__headPoint, QPointF(self.__headPoint.x() + 15, self.__headPoint.y())) self.__tailOffsetLine = QLineF( self.__tailPoint, QPointF(self.__tailPoint.x() - 15, self.__tailPoint.y())) line = QLineF(self.__headPoint, self.__tailPoint) self.__line = line def boundingRect(self): extra = (self.pen().width() * 64) / 2 return QRectF( self.__line.p1(), QSizeF(self.__line.p2().x() - self.__line.p1().x(), self.__line.p2().y() - self.__line.p1().y())).normalized().adjusted( -extra, -extra, extra, extra) def shape(self): return QGraphicsObject.shape(self) def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) angle = math.pi / 2 bLine1 = QLineF() bLine1.setP1(startPoint) if startPoint.x() > endPoint.x(): dist = startPoint.x() - endPoint.x() one = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) bLine1.setP1(endPoint) two = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) path.cubicTo(one, two, endPoint) return path, QLineF(one, two) def paint(self, painter, option, widget=None): painter.setPen(self.pen()) headCenter = self.mapFromItem( self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributeParent].boundingRect().center()) tailCenter = self.mapFromItem( self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributeParent].boundingRect().center()) centerPoint = QLineF(headCenter, tailCenter).pointAt(0.5) centerPoint.setX(self.__headOffsetLine.p2().x()) lineFromHead = QLineF(self.__headOffsetLine.p2(), centerPoint) centerPoint.setX(self.__tailOffsetLine.p2().x()) lineFromTail = QLineF(self.__tailOffsetLine.p2(), centerPoint) painter.drawPath( self.drawPath(self.__headOffsetLine.p1(), self.__tailOffsetLine.p1())[0])
class EEdge(QGraphicsObject): def __init__(self, head, tail, uuid): QGraphicsObject.__init__(self) if not issubclass(head.__class__, dict) and not isinstance(tail.__class__, dict): raise AttributeError self.setZValue(0.0) self.__kId = uuid self.__head = head self.__tail = tail if head[ENode.kGuiAttributeType].match(EAttribute.kTypeInput): self.__head = tail self.__tail = head self.__head[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__tail[ENode.kGuiAttributeParent].onMove.connect(self.update) self.__headPoint = QPointF(0.0, 0.0) self.__tailPoint = QPointF(0.0, 0.0) self.__pen = QPen(QColor(43, 43, 43), 2, Qt.SolidLine) self.update() @property def Id(self): return self.__kId @property def Head(self): return self.__head @property def Tail(self): return self.__tail def pen(self): return self.__pen def setPen(self, pen): if not isinstance(pen, QPen): raise AttributeError self.__pen = pen def update(self): QGraphicsObject.prepareGeometryChange(self) self.__headPoint = self.mapFromItem(self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributePlug]) self.__tailPoint = self.mapFromItem(self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributePlug]) self.__headOffsetLine = QLineF(self.__headPoint, QPointF(self.__headPoint.x() + 15, self.__headPoint.y())) self.__tailOffsetLine = QLineF(self.__tailPoint, QPointF(self.__tailPoint.x() - 15, self.__tailPoint.y())) line = QLineF(self.__headPoint, self.__tailPoint) self.__line = line def boundingRect(self): extra = (self.pen().width() * 64) / 2 return QRectF(self.__line.p1(), QSizeF(self.__line.p2().x() - self.__line.p1().x(), self.__line.p2().y() - self.__line.p1().y())).normalized().adjusted(-extra, -extra, extra, extra) def shape(self): return QGraphicsObject.shape(self) def drawPath(self, startPoint, endPoint): path = QPainterPath() one = (QPointF(endPoint.x(), startPoint.y()) + startPoint) / 2 two = (QPointF(startPoint.x(), endPoint.y()) + endPoint) / 2 path.moveTo(startPoint) angle = math.pi / 2 bLine1 = QLineF() bLine1.setP1(startPoint) if startPoint.x() > endPoint.x(): dist = startPoint.x() - endPoint.x() one = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) bLine1.setP1(endPoint) two = (bLine1.p1() + QPointF(math.sin(angle) * dist, math.cos(angle) * dist)) path.cubicTo(one, two, endPoint) return path, QLineF(one, two) def paint(self, painter, option, widget=None): painter.setPen(self.pen()) headCenter = self.mapFromItem(self.__head[ENode.kGuiAttributeParent], self.__head[ENode.kGuiAttributeParent].boundingRect().center()) tailCenter = self.mapFromItem(self.__tail[ENode.kGuiAttributeParent], self.__tail[ENode.kGuiAttributeParent].boundingRect().center()) centerPoint = QLineF(headCenter, tailCenter).pointAt(0.5) centerPoint.setX(self.__headOffsetLine.p2().x()) lineFromHead = QLineF(self.__headOffsetLine.p2(), centerPoint) centerPoint.setX(self.__tailOffsetLine.p2().x()) lineFromTail = QLineF(self.__tailOffsetLine.p2(), centerPoint) painter.drawPath(self.drawPath(self.__headOffsetLine.p1(), self.__tailOffsetLine.p1())[0])
class EDummy(QGraphicsObject): onEditEnd = pyqtSignal(QLineF) onPress = pyqtSignal() def __init__(self): QGraphicsObject.__init__(self) self.__uuid = uuid.uuid1() #self.setZValue(-0.5) self.__polygon = EDraw.Circle(7, 12) self.__isSnapMode = False self.__snapPoint = QPointF(0.0, 0.0) self.__gridSize = 10 self.__dummyLine = QLineF() self.__dummyData = None self.__editPointOne = None self.__BBTemp = None self.__angle = 0.0 def isEditMode(self): if self.__editPointOne: return True return False def toggleEditMode(self): if self.__editPointOne is None: self.__editPointOne = self.scenePos() self.__BBTemp = self.scenePos() self.setZValue(2.0) self.update() return self.setZValue(-0.5) self.onEditEnd.emit(QLineF(self.__editPointOne, self.scenePos())) self.__editPointOne = None self.__BBTemp = None self.update() def setSnapMode(self, snapMode): self.__isSnapMode = snapMode def setGridSize(self, gridSize): self.__gridSize = gridSize def setDummyData(self, dummyData): self.__dummyData = dummyData def getDummyData(self): return self.__dummyData @property def Id(self): return self.__uuid @property def Position(self): if self.__isSnapMode: return self.__snapPoint / self.__gridSize return self.scenePos() / self.__gridSize @property def Angle(self): return self.__angle def boundingRect(self): tempPoint = self.__snapPoint if self.__BBTemp is not None: tempPoint = self.__BBTemp radius = math.sqrt((self.scenePos().x() - tempPoint.x()) ** 2 + (self.scenePos().y() - tempPoint.y()) ** 2) return EDraw.Circle(radius + self.__gridSize / 2, 8).boundingRect().normalized().adjusted(-5, -5, 5, 5) def shape(self): path = QGraphicsItem.shape(self) return path def polygon(self): return self.__polygon def debug(self): return self.__dummyLine.p2() def dummyLine(self, angle=None, length=None): if angle is not None and length is not None: pt1 = QLineF(QPointF(0.0, 0.0), QPointF(0.0, 1.0)) pt1.setAngle(angle) pt1.setLength(length + 16) self.__dummyLine = pt1 return self.__dummyLine = QLineF() def paint(self, painter, option, widget=None): painter.setPen(EDraw.EColor.DefaultEnterHoverPen) lineX = QLineF(QPointF(self.__gridSize, 0.0), QPointF(0.0, 0.0)).translated(-self.scenePos()) lineY = QLineF(QPointF(0.0, -self.__gridSize), QPointF(0.0, 0.0)).translated(-self.scenePos()) painter.drawLines([lineX, lineY]) self.__snapPoint = QPointF(self.__gridSize * round(self.scenePos().x() / self.__gridSize), self.__gridSize * round(self.scenePos().y() / self.__gridSize)) if self.__isSnapMode: painter.drawPolygon(self.__polygon.translated(self.__snapPoint - self.scenePos())) self.__angle = 0.0 if self.__editPointOne is not None: painter.drawPolygon(EDraw.Circle(20, 24).translated(-(self.scenePos()) + self.__BBTemp)) painter.drawLine(QLineF(QPointF(-(self.scenePos()) + self.__BBTemp), QPointF(0.0, 0.0))) dummyLine = QLineF(QPointF(-(self.scenePos()) + self.__BBTemp), QPointF(0.0, 0.0)) painter.drawLine(QLineF(ETransform.rotatePoint(20, dummyLine.angle() + 180), QPointF()).translated(-(self.scenePos()) + self.__BBTemp)) painter.drawLine(QLineF(ETransform.rotatePoint(20, dummyLine.angle() + 360), QPointF()).translated(-(self.scenePos()) + self.__BBTemp)) self.__angle = dummyLine.angle() painter.drawPolygon(self.__polygon) painter.drawLine(self.__dummyLine) #painter.drawRect(self.boundingRect()) def mousePressEvent(self, event): QGraphicsObject.mousePressEvent(self, event) self.onPress.emit()