def calculateForces(self): if not self.scene() or self.scene().mouseGrabberItem() is self: self.newPos = self.pos() return # Sum up all forces pushing this item away. xvel = 0.0 yvel = 0.0 for item in self.scene().items(): if not isinstance(item, Node): continue line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0)) dx = line.dx() dy = line.dy() l = 2.0 * (dx * dx + dy * dy) if l > 0: xvel += (dx * 150.0) / l yvel += (dy * 150.0) / l # Now subtract all forces pulling items together. #weight = (len(self.edgeList) + 1) * 100.0 for edge in self.edgeList: if edge.sourceNode() is self: pos = self.mapFromItem(edge.destNode(), 0, 0) else: weight = edge.weight * 6 pos = self.mapFromItem(edge.sourceNode(), 0, 0) xvel += pos.x() / weight yvel += pos.y() / weight if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1: xvel = yvel = 0.0 sceneRect = self.scene().sceneRect() self.newPos = self.pos() + QPointF(xvel, yvel) self.newPos.setX( min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)) self.newPos.setY( min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
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 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
def paint(self, painter, option, widget): if not self.source or not self.dest: return # Draw the line itself. line = QLineF(self.sourcePoint, self.destPoint) if line.length() == 0.0: return palette = QPalette() self.setZValue(self.state) if self.state == 3: pen = QPen(Qt.red, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) if self.state == 2: pen = QPen(Qt.red, 2, Qt.DashLine, Qt.RoundCap, Qt.RoundJoin) elif self.state == 1: pen = QPen(palette.color(QPalette.Disabled, QPalette.WindowText), 0, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) elif self.state == 0: pen = QPen() pen.setBrush(QBrush(Qt.NoBrush)) painter.setPen(pen) painter.drawLine(line) angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = Edge.TwoPi - angle # draw arrowheads if self.state == 2 or self.state == 3: # Draw the arrows if there's enough room. sourceArrowP1 = self.sourcePoint + QPointF( math.sin(angle + Edge.Pi / 3) * self.arrowSize, math.cos(angle + Edge.Pi / 3) * self.arrowSize) sourceArrowP2 = self.sourcePoint + QPointF( math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize, math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize) destArrowP1 = self.destPoint + QPointF( math.sin(angle - Edge.Pi / 3) * self.arrowSize, math.cos(angle - Edge.Pi / 3) * self.arrowSize) destArrowP2 = self.destPoint + QPointF( math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize, math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize) painter.setPen( QPen(Qt.red, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.setBrush(QBrush(Qt.red, Qt.SolidPattern)) painter.drawPolygon( QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2])) #painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2])) if self.state > 0 and self.source > self.dest: point = QPointF((self.sourcePoint.x() + self.destPoint.x()) / 2, (self.sourcePoint.y() + self.destPoint.y()) / 2) point = QPointF(point.x() + math.sin(angle) * 16, point.y() + math.cos(angle) * 16) painter.drawText(point, self.text)