def addEdge(self, startPt, endPt, label, edgeColor, labelColor=None, xoffset=0.0): if not labelColor: labelColor = edgeColor assert isinstance(startPt, QPointF) assert isinstance(endPt, QPointF) assert isinstance(label, str) # if color in self.edgeList: # self.lineList[color].extend( line_list ) # else: # self.lineList[color] = line_list # print(self.edgeList) edge = QLineF(startPt, endPt) if edgeColor in self.edgeList.keys(): self.edgeList[edgeColor].append(edge) else: self.edgeList[edgeColor] = [edge] # self.update() midp = QPointF((edge.x1() * 0.2 + edge.x2() * 0.8), (edge.y1() * 0.2 + edge.y2() * 0.8)) self.addLabel(midp, label, labelColor, xoffset=xoffset)
def get_midpoint(label: str, side: QLineF) -> (QPointF, QPointF): """ Procedure to compute the midpoint of a rectangle side. Parameters ---------- label : str The side label ("top", "right", "bottom", "left") side : QLineF The line representing the side. Returns ---------- tuple The two coordinates of the mid-point. """ mid_x = (side.x1() + side.x2()) / 2 mid_y = (side.y1() + side.y2()) / 2 # Add a margin depending on the side if label == "top": mid_y += 4 elif label == "right": mid_x -= 4 elif label == "bottom": mid_y -= 4 elif label == "left": mid_x += 4 return mid_x, mid_y
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
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
def rotateUIPointAroundRefLine(x1, y1, x2, y2, pt): """ Given three points p1, p2, pt this rotates pt around p2 such that p1,p2 and p1,pt are collinear. """ line = QLineF(pt.x, pt.y, x2, y2) p2p_l = line.length() line.setP1(QPointF(x1, y1)) p1p2_l = line.length() if not p1p2_l: return line.setLength(p1p2_l + p2p_l) pt.x = line.x2() pt.y = line.y2()
def draw_axis( painter: QtGui.QPainter, axis: QtCore.QLineF, pen: QtGui.QPen, dash_pen: QtGui.QPen ) -> None: """ Рисует координатную ось """ painter.setPen(pen) painter.drawLine( int(axis.x1()), int(axis.y1()), int(axis.x2()), int(axis.y2()) )
def moveUIPoint(contour, point, delta): if point.segmentType is None: # point is an offCurve. Get its sibling onCurve and the other # offCurve. siblings = _getOffCurveSiblingPoints(contour, point) # if an onCurve is selected, the offCurve will move along with it if not siblings: return point.move(delta) for onCurve, otherPoint in siblings: if not onCurve.smooth: continue # if the onCurve is smooth, we need to either... if otherPoint.segmentType is None and not otherPoint.selected: # keep the other offCurve inline line = QLineF(point.x, point.y, onCurve.x, onCurve.y) otherLine = QLineF( onCurve.x, onCurve.y, otherPoint.x, otherPoint.y) line.setLength(line.length() + otherLine.length()) otherPoint.x = line.x2() otherPoint.y = line.y2() else: # keep point in tangency with onCurve -> otherPoint segment, # i.e. do an orthogonal projection point.x, point.y, _ = bezierMath.lineProjection( onCurve.x, onCurve.y, otherPoint.x, otherPoint.y, point.x, point.y, False) else: # point is an onCurve. Move its offCurves along with it. index = contour.index(point) point.move(delta) for d in (-1, 1): # edge-case: contour open, trailing offCurve and moving first # onCurve in contour if contour.open and index == 0 and d == -1: continue pt = contour.getPoint(index + d) if pt.segmentType is None: # avoid double move for qCurve with single offCurve if d > 0: otherPt = contour.getPoint(index + 2 * d) if otherPt.segmentType is not None and \ otherPt.segmentType != "move" and otherPt.selected: continue pt.move(delta) maybeProjectUISmoothPointOffcurve(contour, point) contour.dirty = True
def _drawGuidelines(painter, glyph, scale, rect, guidelines, drawLines=True, drawText=True, drawSelection=True, color=None): if not (drawLines or drawText): return xMin, yMin, width, height = rect xMax = xMin + width yMax = yMin + height for line in guidelines: color_ = color if color_ is None: if line.color: color_ = colorToQColor(line.color) else: color_ = defaultColor("glyphGuideline") painter.save() painter.setPen(color) line1 = None if None not in (line.x, line.y): if line.angle is not None: # make an infinite line that intersects *(line.x, line.y)* # 1. make horizontal line from *(line.x, line.y)* of length # *diagonal* diagonal = math.sqrt(width**2 + height**2) line1 = QLineF(line.x, line.y, line.x + diagonal, line.y) # 2. set the angle # defcon guidelines are clockwise line1.setAngle(line.angle) # 3. reverse the line and set length to 2 * *diagonal* line1.setPoints(line1.p2(), line1.p1()) line1.setLength(2 * diagonal) else: line1 = QLineF(xMin, line.y, xMax, line.y) textX = 0 textY = 0 if drawLines: if line1 is not None: # line drawLine(painter, line1.x1(), line1.y1(), line1.x2(), line1.y2()) # point x, y = line.x, line.y smoothWidth = 8 * scale smoothHalf = smoothWidth / 2.0 painter.save() pointPath = QPainterPath() x -= smoothHalf y -= smoothHalf pointPath.addEllipse(x, y, smoothWidth, smoothWidth) pen = QPen(color_) pen.setWidthF(1 * scale) painter.setPen(pen) if drawSelection and line.selected: painter.fillPath(pointPath, color_) painter.drawPath(pointPath) painter.restore() else: if line.y is not None: drawLine(painter, xMin, line.y, xMax, line.y) elif line.x is not None: drawLine(painter, line.x, yMin, line.x, yMax) if drawText and line.name: if line1 is not None: textX = line.x textY = line.y - 6 * scale xAlign = "center" else: if line.y is not None: fontSize = painter.font().pointSize() textX = glyph.width + 6 * scale textY = line.y - (fontSize / 3.5) * scale elif line.x is not None: textX = line.x + 6 * scale textY = 0 xAlign = "left" drawTextAtPoint(painter, line.name, textX, textY, scale, xAlign=xAlign) painter.restore()
def _drawGuidelines(painter, glyph, scale, rect, guidelines, drawLines=True, drawText=True, drawSelection=True, color=None): if not (drawLines or drawText): return xMin, yMin, width, height = rect xMax = xMin + width yMax = yMin + height fontSize = painter.font().pointSize() for line in guidelines: color_ = color if color_ is None: if line.color: color_ = colorToQColor(line.color) else: color_ = defaultColor("glyphGuideline") painter.save() painter.setPen(color) line1 = None if None not in (line.x, line.y): if line.angle is not None: # make an infinite line that intersects *(line.x, line.y)* # 1. make horizontal line from *(line.x, line.y)* of length # *diagonal* diagonal = math.sqrt(width**2 + height**2) line1 = QLineF(line.x, line.y, line.x + diagonal, line.y) # 2. set the angle # defcon guidelines are clockwise line1.setAngle(line.angle) # 3. reverse the line and set length to 2 * *diagonal* line1.setPoints(line1.p2(), line1.p1()) line1.setLength(2 * diagonal) else: line1 = QLineF(xMin, line.y, xMax, line.y) textX = 0 textY = 0 if drawLines: if line1 is not None: # line drawLine( painter, line1.x1(), line1.y1(), line1.x2(), line1.y2()) # point x, y = line.x, line.y smoothWidth = 8 * scale smoothHalf = smoothWidth / 2.0 painter.save() pointPath = QPainterPath() x -= smoothHalf y -= smoothHalf pointPath.addEllipse(x, y, smoothWidth, smoothWidth) pen = QPen(color_) pen.setWidthF(1 * scale) painter.setPen(pen) if drawSelection and line.selected: painter.fillPath(pointPath, color_) painter.drawPath(pointPath) painter.restore() else: if line.y is not None: drawLine(painter, xMin, line.y, xMax, line.y) elif line.x is not None: drawLine(painter, line.x, yMin, line.x, yMax) if drawText and line.name: if line1 is not None: textX = line.x textY = line.y - 6 * scale xAlign = "center" else: if line.y is not None: textX = glyph.width + 6 * scale textY = line.y - (fontSize / 3.5) * scale elif line.x is not None: textX = line.x + 6 * scale textY = 0 xAlign = "left" drawTextAtPoint( painter, line.name, textX, textY, scale, xAlign=xAlign) painter.restore()
class EdgeItem(QGraphicsLineItem): def __init__(self, boxName, fromLocation, toLocation, guard, reset, scene, parentForm, style=Qt.SolidLine, rect=None, matrix=QTransform()): super(EdgeItem, self).__init__() self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable) self.style = style self.boxName = boxName self.guard = guard self.reset = reset self._fromLocation = None self._toLocation = None if fromLocation == None: x1 = 10 y1 = 10 else: x1 = fromLocation.rect.right() y1 = fromLocation.rect.top() + fromLocation.rect.height() * 0.3 if toLocation == None: x2 = 100 y2 = 100 else: x2 = toLocation.rect.left() y2 = toLocation.rect.top() + fromLocation.rect.height() * 0.3 self.parentForm = parentForm self.source = QPointF(x1, y1) self.dest = QPointF(x2, y2) self.fromLocation = fromLocation self.toLocation = toLocation self.direction = "a" self.myColor = Qt.black self.setPen( QPen(self.myColor, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 5) self.resetLine() self.scene = scene scene.clearSelection() scene.addItem(self) self.setSelected(True) self.setFocus() global Dirty Dirty = True def drawLine2Self(self): haveEdges = [ strDirection for strDirection in self.fromLocation.edges.values() ] self.arcx1 = self.fromLocation.x() + self.fromLocation.rect.x( ) - 40 #-30 self.arcy1 = self.fromLocation.y() + self.fromLocation.rect.y( ) # -50#+self.fromLocation.rect.height*0.3 self.minAngle = 90 x1 = self.arcx1 + 33 y1 = self.arcy1 + 80 x2 = self.arcx1 + 40 y2 = self.arcy1 + 80 self.arcTextx = self.arcx1 self.arcTexty = self.arcy1 + 40 self.spanAngle = 180 if "top" not in haveEdges and self.fromLocation.isNameAbove == False: self.arcx1 = self.fromLocation.x() + self.fromLocation.rect.x( ) + 10 self.arcy1 = self.fromLocation.y() + self.fromLocation.rect.y( ) - 40 x1 = self.arcx1 + 80 y1 = self.arcy1 + 40 - 7 x2 = self.arcx1 + 80 y2 = self.arcy1 + 40 self.minAngle = 0 self.arcTextx = self.arcx1 + 40 self.arcTexty = self.arcy1 elif "left" not in haveEdges: self.arcx1 = self.fromLocation.x() + self.fromLocation.rect.x( ) - 40 #-30 self.arcy1 = self.fromLocation.y() + self.fromLocation.rect.y( ) + 10 # -50#+self.fromLocation.rect.height*0.3 self.minAngle = 90 x1 = self.arcx1 + 33 y1 = self.arcy1 + 80 x2 = self.arcx1 + 40 y2 = self.arcy1 + 80 self.arcTextx = self.arcx1 self.arcTexty = self.arcy1 + 40 elif "bottom" not in haveEdges and self.fromLocation.isNameAbove: self.arcx1 = self.fromLocation.x() + self.fromLocation.rect.x( ) + 10 self.arcy1 = self.fromLocation.y() + self.fromLocation.rect.y( ) + self.fromLocation.rect.height() - 40 self.minAngle = 180 x1 = self.arcx1 + 80 y1 = self.arcy1 + 7 + 40 x2 = self.arcx1 + 80 y2 = self.arcy1 + 40 self.arcTextx = self.arcx1 + 40 self.arcTexty = self.arcy1 + 80 elif "right" not in haveEdges: self.arcx1 = self.fromLocation.x() + self.fromLocation.rect.x( ) + self.fromLocation.rect.width() - 40 #-30 self.arcy1 = self.fromLocation.y() + self.fromLocation.rect.y( ) + 10 # -50#+self.fromLocation.rect.height*0.3 self.minAngle = 270 x1 = self.arcx1 + 7 + 25 + adjustX1 y1 = self.arcy1 + 80 x2 = self.arcx1 + 25 + adjustX1 y2 = self.arcy1 + 80 self.arcTextx = self.arcx1 + 80 self.arcTexty = self.arcy1 + 40 self.source = QPointF(x1, y1) self.dest = QPointF(x2, y2) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 5) #if 'time' not in listOfStrings : # print("Yes, 'time' NOT found in List : " , listOfStrings) def getQPixmap4Guard(self): guardFig = Figure(figsize=(5, 0.4)) canvas = FigureCanvas(guardFig) strData = self.guard try: guardFig.text(0.1, 0.3, strData, family="Consolas", fontsize=10) except: pass canvas.draw() size = canvas.size() width, height = size.width(), size.height() im = QImage(canvas.buffer_rgba(), width, height, QImage.Format_ARGB32) return QPixmap(im) def getQPixmap4Reset(self): guardFig = Figure(figsize=(5, 0.4)) canvas = FigureCanvas(guardFig) strData = self.reset try: guardFig.text(0.1, 0.3, strData, family="Consolas", fontsize=10) except: pass canvas.draw() size = canvas.size() width, height = size.width(), size.height() im = QImage(canvas.buffer_rgba(), width, height, QImage.Format_ARGB32) return QPixmap(im) def resetLine(self): self.direction = "" if self.fromLocation == None and self.toLocation == None: return if self.fromLocation == None: #self.toLocation.edges[self.boxName]="left" x2 = self.toLocation.x() + self.toLocation.rect.x() y2 = self.toLocation.y() + self.toLocation.rect.x( ) + self.toLocation.rect.height() * 0.3 x1 = x2 - 30 y1 = y2 elif self.toLocation == None: #self.fromLocation.edges[self.boxName]="right" x1 = self.fromLocation.x() + self.fromLocation.rect.x( ) + self.fromLocation.rect.width() y1 = self.fromLocation.y() + self.fromLocation.rect.y( ) + self.fromLocation.rect.height() * 0.3 x2 = x1 + 30 y2 = y1 else: adjustX1 = self.fromLocation.x() + self.fromLocation.rect.x() adjustX2 = self.toLocation.x() + self.toLocation.rect.x() adjustY1 = self.fromLocation.y() + self.fromLocation.rect.y() adjustY2 = self.toLocation.y() + self.toLocation.rect.y() if self.fromLocation.boxName == self.toLocation.boxName: self.drawLine2Self() self.fromLocation.edgeToSelf = self.boxName return x_diff = self.toLocation.x() - self.fromLocation.x() y_diff = self.toLocation.y() - self.fromLocation.y() x_diff_standand = (self.fromLocation.rect.width() + self.toLocation.rect.width()) / 2 y_diff_standand = (self.fromLocation.rect.height() + self.toLocation.rect.height()) / 2 if ((abs(y_diff) < y_diff_standand)): if x_diff > 0: self.direction = "x>" self.fromLocation.edges[self.boxName] = "right" self.toLocation.edges[self.boxName] = "left" x1 = self.fromLocation.rect.width() + adjustX1 y1 = self.fromLocation.rect.height() * 0.4 + adjustY1 x2 = adjustX2 y2 = self.toLocation.rect.height() * 0.4 + adjustY2 else: self.direction = "x<" self.fromLocation.edges[self.boxName] = "left" self.toLocation.edges[self.boxName] = "right" x1 = adjustX1 y1 = self.fromLocation.rect.height() * 0.6 + adjustY1 x2 = self.toLocation.rect.width() + adjustX2 y2 = self.toLocation.rect.height() * 0.6 + adjustY2 elif ((abs(x_diff) < x_diff_standand)): if (y_diff > 0): self.direction = "y>" self.fromLocation.edges[self.boxName] = "bottom" self.toLocation.edges[self.boxName] = "top" x1 = self.fromLocation.rect.width() * 0.4 + adjustX1 y1 = self.fromLocation.rect.height() + adjustY1 x2 = self.toLocation.rect.width() * 0.4 + adjustX2 y2 = adjustY2 else: self.direction = "y<" self.fromLocation.edges[self.boxName] = "top" self.toLocation.edges[self.boxName] = "bottom" x1 = self.fromLocation.rect.width() * 0.6 + adjustX1 y1 = adjustY1 x2 = self.toLocation.rect.width() * 0.6 + adjustX2 y2 = self.toLocation.rect.height() + adjustY2 else: if (x_diff > 0) and (y_diff > 0): self.direction = "xy>" self.fromLocation.edges[self.boxName] = "right" self.toLocation.edges[self.boxName] = "top" x1 = self.fromLocation.rect.width() + adjustX1 y1 = self.fromLocation.rect.height() * 0.8 + adjustY1 x2 = self.toLocation.rect.width() * 0.2 + adjustX2 y2 = adjustY2 elif ((x_diff < 0) and (y_diff < 0)): self.direction = "xy<" self.fromLocation.edges[self.boxName] = "left" self.toLocation.edges[self.boxName] = "bottom" x1 = adjustX1 y1 = self.fromLocation.rect.height() * 0.2 + adjustY1 x2 = self.toLocation.rect.width() * 0.8 + adjustX2 y2 = self.toLocation.rect.height() + adjustY2 elif (x_diff > 0) and (y_diff < 0): self.direction = "x>y<" self.fromLocation.edges[self.boxName] = "top" self.toLocation.edges[self.boxName] = "left" x1 = self.fromLocation.rect.width() * 0.8 + adjustX1 y1 = adjustY1 x2 = adjustX2 y2 = self.toLocation.rect.height() * 0.8 + adjustY2 else: self.direction = "x<y>" self.fromLocation.edges[self.boxName] = "bottom" self.toLocation.edges[self.boxName] = "right" x1 = self.fromLocation.rect.width() * 0.2 + adjustX1 y1 = adjustY1 + self.fromLocation.rect.height() x2 = adjustX2 + self.toLocation.rect.width() y2 = self.toLocation.rect.height() * 0.2 + adjustY2 self.direction = self.direction + " fLX:" + str( self.fromLocation.x()) + ",fLrx" + str( self.fromLocation.rect.x()) + ",fLrw" + str( self.fromLocation.rect.width()) + ",Lx" + str(x1) self.source = QPointF(x1, y1) self.dest = QPointF(x2, y2) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 5) @property def boxName(self): return self._boxName @boxName.setter def boxName(self, value): if not isinstance(value, str): raise ValueError('EdgeName must be an string!') self._boxName = value @property def guard(self): return self._guard @guard.setter def guard(self, value): if not isinstance(value, str): raise ValueError('EdgeName must be an string!') self._guard = value @property def reset(self): return self._reset @reset.setter def reset(self, value): if not isinstance(value, str): raise ValueError('EdgeName must be an string!') self._reset = value def toSaveJson(self): data = { "type": "Edge", "boxName": self.boxName, "strFromLocation": self.fromLocation.boxName, "strToLocation": self.toLocation.boxName, "guard": self.guard, "reset": self.reset, "style": self.style, "rotation": self.rotation() } return data @property def fromLocation(self): return self._fromLocation @fromLocation.setter def fromLocation(self, value): if value != None: if not isinstance(value, LocationItem): raise ValueError('LocationName must be a LocationItem!') self._fromLocation = value self.resetLine() @property def toLocation(self): return self._toLocation @toLocation.setter def toLocation(self, value): if value != None: if not isinstance(value, LocationItem): raise ValueError('LocationName must be a LocationItem!') self._toLocation = value self.resetLine() def parentWidget(self): return self.scene.views()[0] def itemChange(self, change, variant): if change != QGraphicsItem.ItemSelectedChange: global Dirty Dirty = True return QGraphicsLineItem.itemChange(self, change, variant) def mouseDoubleClickEvent(self, event): dialog = edgeItemDlg(self, self.parentWidget(), self.parentWidget(), self.scene, self.parentForm) dialog.exec_() def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None): # setPen pen = QPen() pen.setWidth(1) pen.setJoinStyle(Qt.MiterJoin) #让箭头变尖 QPainter.setPen(pen) # draw line QPainter.drawLine(self.line) ptextx = (self.line.x1() + self.line.x2()) / 2 ptexty = (self.line.y1() + self.line.y2()) / 2 ptexty -= 5 ptextx -= len(self.boxName) * 3 #QPainter.drawText(QPointF(ptextx, ptexty+20), self.direction) # setBrush brush = QBrush() brush.setColor(Qt.black) brush.setStyle(Qt.SolidPattern) QPainter.setBrush(brush) v = self.line.unitVector() v.setLength(5) v.translate(QPointF(self.line.dx(), self.line.dy())) n = v.normalVector() n.setLength(n.length() * 0.5) n2 = n.normalVector().normalVector() p1 = v.p2() p2 = n.p2() p3 = n2.p2() # 方法1 QPainter.drawLine(self.line) QPainter.drawPolygon(p1, p2, p3) if self.fromLocation is not None and self.toLocation is not None: if self.fromLocation.boxName == self.toLocation.boxName: QPainter.drawArc(self.arcx1, self.arcy1, 80, 80, self.minAngle * 16, self.spanAngle * 16) ptextx = self.arcTextx ptexty = self.arcTexty #QPainter.drawArc(self.arcx1, self.arcy1+100, 50, 50, 270*16, 89*16) #QPainter.drawArc(self.arcx1, self.arcy1+200, 50, 50, 0*16, 89*16) #QPainter.drawArc(self.arcx1, self.arcy1+300, 50, 50, 270*16, 180*16) #QPainter.drawArc(self.arcx1, self.arcy1+400, 50, 50, 270*16, 270*16) #QPainter.drawArc(self.arcx1, self.arcy1+500, 50, 50, 180*16, 89*16) QPainter.drawText(QPointF(ptextx, ptexty), self.boxName) #QPainter.drawRect(self.arcx1, self.arcy1, 50, 50) self.scene.update()
class LineItem(QGraphicsLineItem): def __init__(self, boxName, fromBox, toBox, position, scene, parentForm, style=Qt.SolidLine, rect=None, matrix=QTransform()): super(LineItem, self).__init__() self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsFocusable) self.style = style self.boxName = boxName self._fromBox = None self._toBox = None if fromBox == None: x1 = 10 y1 = 10 else: x1 = fromBox.boundingRect().right() y1 = fromBox.boundingRect().top( ) + fromBox.boundingRect().height() * 0.3 if toBox == None: x2 = 100 y2 = 100 else: x2 = toBox.boundingRect().left() y2 = toBox.boundingRect().top( ) + fromBox.boundingRect().height() * 0.3 self.parentForm = parentForm self.source = QPointF(x1, y1) self.dest = QPointF(x2, y2) self.fromBox = fromBox self.toBox = toBox self.direction = "a" self.myColor = Qt.black self.setPen( QPen(self.myColor, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 5) self.resetLine() self.scene = scene scene.clearSelection() scene.addItem(self) self.setSelected(True) self.setFocus() global Dirty Dirty = True def resetLine(self): if self.fromBox == None and self.toBox == None: return if self.fromBox == None: x2 = self.toBox.x() y2 = self.toBox.y() + self.toBox.boundingRect().height() * 0.3 x1 = x2 - 30 y1 = y2 elif self.toBox == None: x1 = self.fromBox.x() + self.fromBox.boundingRect().width() y1 = self.fromBox.y() + self.fromBox.boundingRect().height() * 0.3 x2 = x1 + 30 y2 = y1 else: x_diff = self.toBox.x() - self.fromBox.x() y_diff = self.toBox.y() - self.fromBox.y() x_diff_standand = (self.fromBox.boundingRect().width() + self.toBox.boundingRect().width()) / 2 y_diff_standand = (self.fromBox.boundingRect().height() + self.toBox.boundingRect().height()) / 2 if ((abs(y_diff) < y_diff_standand)): if x_diff > 0: self.direction = "x>" x1 = self.fromBox.x() + self.fromBox.boundingRect().width() y1 = self.fromBox.y( ) + self.fromBox.boundingRect().height() * 0.3 x2 = self.toBox.x() y2 = self.toBox.y( ) + self.toBox.boundingRect().height() * 0.3 else: self.direction = "x<" x1 = self.fromBox.x() y1 = self.fromBox.y( ) + self.fromBox.boundingRect().height() * 0.67 x2 = self.toBox.x() + self.toBox.boundingRect().width() y2 = self.toBox.y( ) + self.toBox.boundingRect().height() * 0.67 elif ((abs(x_diff) < x_diff_standand)): if (y_diff > 0): self.direction = "y>" x1 = self.fromBox.x( ) + self.fromBox.boundingRect().width() * 0.3 y1 = self.fromBox.y() + self.fromBox.boundingRect().height( ) x2 = self.toBox.x( ) + self.toBox.boundingRect().width() * 0.3 y2 = self.toBox.y() else: self.direction = "y<" x1 = self.fromBox.x( ) + self.fromBox.boundingRect().width() * 0.67 y1 = self.fromBox.y() x2 = self.toBox.x( ) + self.toBox.boundingRect().width() * 0.67 y2 = self.toBox.y() + self.toBox.boundingRect().height() else: if (x_diff > 0) and (y_diff > 0): self.direction = "xy>" x1 = self.fromBox.x() + self.fromBox.boundingRect().width() y1 = self.fromBox.y( ) + self.fromBox.boundingRect().height() * 0.87 x2 = self.toBox.x( ) + self.toBox.boundingRect().width() * 0.13 y2 = self.toBox.y() elif ((x_diff < 0) and (y_diff < 0)): self.direction = "xy<" x1 = self.fromBox.x() y1 = self.fromBox.y( ) + self.fromBox.boundingRect().height() * 0.13 x2 = self.toBox.x( ) + self.toBox.boundingRect().width() * 0.87 y2 = self.toBox.y() + self.toBox.boundingRect().height() elif (x_diff > 0) and (y_diff < 0): self.direction = "x>y<" x1 = self.fromBox.x( ) + self.fromBox.boundingRect().width() * 0.87 y1 = self.fromBox.y() x2 = self.toBox.x() y2 = self.toBox.y( ) + self.toBox.boundingRect().height() * 0.87 else: self.direction = "x<y>" x1 = self.fromBox.x( ) + self.fromBox.boundingRect().width() * 0.13 y1 = self.fromBox.y() + self.fromBox.boundingRect().height( ) x2 = self.toBox.x() + self.toBox.boundingRect().width() y2 = self.toBox.y( ) + self.toBox.boundingRect().height() * 0.13 self.source = QPointF(x1, y1) self.dest = QPointF(x2, y2) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 5) @property def boxName(self): return self._boxName @boxName.setter def boxName(self, value): if not isinstance(value, str): raise ValueError('boxName must be an string!') self._boxName = value def toSaveJson(self): data = { "type": "Line", "boxName": self.boxName, "strFromBox": self.fromBox.boxName, "strToBox": self.toBox.boxName, "style": self.style, "rotation": self.rotation() } return data @property def fromBox(self): return self._fromBox @fromBox.setter def fromBox(self, value): if value != None: if not isinstance(value, QGraphicsTextItem): raise ValueError('boxName must be an string!') self._fromBox = value self.resetLine() @property def toBox(self): return self._toBox @toBox.setter def toBox(self, value): if value != None: if not isinstance(value, QGraphicsTextItem): raise ValueError('boxName must be an string!') self._toBox = value self.resetLine() def parentWidget(self): return self.scene().views()[0] def itemChange(self, change, variant): if change != QGraphicsItem.ItemSelectedChange: global Dirty Dirty = True return QGraphicsLineItem.itemChange(self, change, variant) def mouseDoubleClickEvent(self, event): dialog = LineItemDlg(self, self.parentWidget(), self.parentWidget(), self.scene, self.parentForm) dialog.exec_() def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None): # setPen pen = QPen() pen.setWidth(1) pen.setJoinStyle(Qt.MiterJoin) #让箭头变尖 QPainter.setPen(pen) # draw line QPainter.drawLine(self.line) ptextx = (self.line.x1() + self.line.x2()) / 2 ptexty = (self.line.y1() + self.line.y2()) / 2 ptexty -= 5 ptextx -= len(self.boxName) * 3 QPainter.drawText(QPointF(ptextx, ptexty), self.boxName) #Painter.drawText(QPointF(ptextx, ptexty+20), self.direction) # setBrush brush = QBrush() brush.setColor(Qt.black) brush.setStyle(Qt.SolidPattern) QPainter.setBrush(brush) v = self.line.unitVector() v.setLength(5) v.translate(QPointF(self.line.dx(), self.line.dy())) n = v.normalVector() n.setLength(n.length() * 0.5) n2 = n.normalVector().normalVector() p1 = v.p2() p2 = n.p2() p3 = n2.p2() # 方法1 QPainter.drawLine(self.line) QPainter.drawPolygon(p1, p2, p3) QPainter.drawArc(10, 10, 50, 50, 0, 180 * 16) v = self.line.unitVector() v.setLength(5) v.translate(QPointF(10, 60)) n = v.normalVector() n.setLength(n.length() * 0.5) n2 = n.normalVector().normalVector() p1 = v.p2() p2 = n.p2() p3 = n2.p2() # 方法1 #QPainter.drawLine(self.line) QPainter.drawPolygon(p1, p2, p3) self.scene.update()
def line_q_to_s(line: QLineF): return Line(Point(line.x1(), line.y1()), Point(line.x2(), line.y2()))
def draw_axis(painter: QtGui.QPainter, axis: QtCore.QLineF, pen, dash_pen) -> None: painter.setPen(pen) painter.drawLine(0, 0, int(axis.x1()), int(axis.y1())) painter.setPen(dash_pen) painter.drawLine(0, 0, int(axis.x2()), int(axis.y2()))