def findNearestPoint(self, part_item, target_scenepos): """ Args: part_item (TYPE): Description target_scenepos (TYPE): Description """ li = self._line_item pos = li.mapFromScene(target_scenepos) line = li.line() mouse_point_vec = QLineF(self._CENTER_OF_HELIX, pos) # Check if the click happened on the origin VH if mouse_point_vec.length() < self._RADIUS: # return part_item.mapFromScene(target_scenepos) return None angle_min = 9999 direction_min = None for vector in self.vectors: angle_new = mouse_point_vec.angleTo(vector) if angle_new < angle_min: direction_min = vector angle_min = angle_new if direction_min is not None: li.setLine(direction_min) return part_item.mapFromItem(li, direction_min.p2()) else: print("default point") line.setP2(pos) li.setLine(line) return part_item.mapFromItem(li, pos)
def move(self, item, dest, moveSpeed): walkLine = QLineF(item.getGuidedPos(), dest) if moveSpeed >= 0 and walkLine.length() > moveSpeed: # The item is too far away from it's destination point so we move # it towards it instead. dx = walkLine.dx() dy = walkLine.dy() if abs(dx) > abs(dy): # Walk along x-axis. if dx != 0: d = moveSpeed * dy / abs(dx) if dx > 0: s = moveSpeed else: s = -moveSpeed dest.setX(item.getGuidedPos().x() + s) dest.setY(item.getGuidedPos().y() + d) else: # Walk along y-axis. if dy != 0: d = moveSpeed * dx / abs(dy) if dy > 0: s = moveSpeed else: s = -moveSpeed dest.setX(item.getGuidedPos().x() + d) dest.setY(item.getGuidedPos().y() + s) item.setGuidedPos(dest)
def setActive5p(self, is_active, neighbor_item=None): """Summary Args: is_active (TYPE): Description neighbor_item (None, optional): Description """ phos = self.phos_item bond = self.bond_3p if bond is None: return if not self.is_active5p and is_active: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX + 10) self.is_active5p = True if neighbor_item is not None: n_scene_pos = neighbor_item.scenePos() p2 = self.mapFromScene(n_scene_pos) bline = bond.line() test = QLineF(bline.p1(), p2) # angle = test.angleTo(bline) + self.theta0 if self.is_fwd else -bline.angleTo(test) + self.theta0 angle = -bline.angleTo(test) + self.theta0 if self.is_fwd else test.angleTo(bline) + self.theta0 else: p2 = self._active_p2_3p angle = -90 if self.is_fwd else 90 self.animate(phos, 'rotation', 300, self.theta0, angle) self.animate(bond, 'bondp2', 300, self._default_p2_3p, p2) elif self.is_active5p: self.pre_xover_item_group.virtual_helix_item.setZValue(styles.ZGRIDHELIX) self.is_active5p = False self.animate(phos, 'rotation', 300, phos.rotation(), self.theta0) self.animate(bond, 'bondp2', 300, bond.line().p2(), self._default_p2_3p)
def image(cls, **kwargs): """ Returns an image suitable for the palette. :rtype: QPixmap """ # INITIALIZATION pixmap = QPixmap(kwargs['w'], kwargs['h']) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) # INIT THE LINE p1 = QPointF(((kwargs['w'] - 54) / 2), kwargs['h'] / 2) p2 = QPointF(((kwargs['w'] - 54) / 2) + 54 - 2, kwargs['h'] / 2) line = QLineF(p1, p2) # CLACULATE HEAD COORDS angle = line.angle() p1 = QPointF(line.p2().x() + 2, line.p2().y()) p2 = p1 - QPointF(sin(angle + M_PI / 3.0) * 8, cos(angle + M_PI / 3.0) * 8) p3 = p1 - QPointF(sin(angle + M_PI - M_PI / 3.0) * 8, cos(angle + M_PI - M_PI / 3.0) * 8) # INITIALIZE HEAD head = QPolygonF([p1, p2, p3]) # DRAW EDGE LINE painter.setRenderHint(QPainter.Antialiasing) painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) # DRAW EDGE HEAD painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.setBrush(QColor(0, 0, 0)) painter.drawPolygon(head) return pixmap
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 image(cls, **kwargs): """ Returns an image suitable for the palette. :rtype: QPixmap """ # INITIALIZATION pixmap = QPixmap(kwargs['w'], kwargs['h']) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) # INITIALIZE EDGE LINE pp1 = QPointF(((kwargs['w'] - 52) / 2), kwargs['h'] / 2) pp2 = QPointF(((kwargs['w'] - 52) / 2) + 52 - 2, kwargs['h'] / 2) line = QLineF(pp1, pp2) # CALCULATE HEAD COORDINATES angle = radians(line.angle()) p1 = QPointF(line.p2().x() + 2, line.p2().y()) p2 = p1 - QPointF(sin(angle + M_PI / 3.0) * 8, cos(angle + M_PI / 3.0) * 8) p3 = p1 - QPointF(sin(angle + M_PI - M_PI / 3.0) * 8, cos(angle + M_PI - M_PI / 3.0) * 8) # INITIALIZE EDGE HEAD head = QPolygonF([p1, p2, p3]) # DRAW THE POLYGON painter.setRenderHint(QPainter.Antialiasing) painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) # DRAW HEAD painter.setPen(QPen(QColor(0, 0, 0), 1.1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.setBrush(QColor(0, 0, 0)) painter.drawPolygon(head) # DRAW THE TEXT ON TOP OF THE EDGE space = 2 if Platform.identify() is Platform.Darwin else 0 painter.setFont(Font('Arial', 9, Font.Light)) painter.drawText(pp1.x() + space, (kwargs['h'] / 2) - 4, 'instanceOf') return pixmap
def __init__(self, line_or_point, follows=None): super(GuideLine, self).__init__(follows) if isinstance(line_or_point, QLineF): self.line = line_or_point elif follows is not None: self.line = QLineF(self.prevGuide.endPos(), line_or_point) else: self.line = QLineF(QPointF(0, 0), line_or_point)
def timerEvent(self): # Don't move too far away. lineToCenter = QLineF(QPointF(0, 0), self.mapFromScene(0, 0)) if lineToCenter.length() > 150: angleToCenter = math.acos(lineToCenter.dx() / lineToCenter.length()) if lineToCenter.dy() < 0: angleToCenter = Mouse.TwoPi - angleToCenter; angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) + Mouse.Pi / 2) if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4: # Rotate left. self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2] elif angleToCenter >= Mouse.Pi and angleToCenter < (Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4): # Rotate right. self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2] elif math.sin(self.angle) < 0: self.angle += 0.25 elif math.sin(self.angle) > 0: self.angle -= 0.25 # Try not to crash with any other mice. dangerMice = self.scene().items(QPolygonF([self.mapToScene(0, 0), self.mapToScene(-30, -50), self.mapToScene(30, -50)])) for item in dangerMice: if item is self: continue lineToMouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0)) angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length()) if lineToMouse.dy() < 0: angleToMouse = Mouse.TwoPi - angleToMouse angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) + Mouse.Pi / 2) if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2: # Rotate right. self.angle += 0.5 elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi - Mouse.Pi / 2): # Rotate left. self.angle -= 0.5 # Add some random movement. if len(dangerMice) > 1 and (qrand() % 10) == 0: if qrand() % 1: self.angle += (qrand() % 100) / 500.0 else: self.angle -= (qrand() % 100) / 500.0 self.speed += (-50 + qrand() % 100) / 100.0 dx = math.sin(self.angle) * 10 self.mouseEyeDirection = 0.0 if qAbs(dx / 5) < 1 else dx / 5 self.setRotation(self.rotation() + dx) self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
class GuideLine(Guide): def __init__(self, line_or_point, follows=None): super(GuideLine, self).__init__(follows) if isinstance(line_or_point, QLineF): self.line = line_or_point elif follows is not None: self.line = QLineF(self.prevGuide.endPos(), line_or_point) else: self.line = QLineF(QPointF(0, 0), line_or_point) def length(self): return self.line.length() def startPos(self): return QPointF(self.line.p1().x() * self.scaleX, self.line.p1().y() * self.scaleY) def endPos(self): return QPointF(self.line.p2().x() * self.scaleX, self.line.p2().y() * self.scaleY) def guide(self, item, moveSpeed): frame = item.guideFrame - self.startLength endX = (self.line.p1().x() + (frame * self.line.dx() / self.length())) * self.scaleX endY = (self.line.p1().y() + (frame * self.line.dy() / self.length())) * self.scaleY pos = QPointF(endX, endY) self.move(item, pos, moveSpeed)
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
def intersection(self, line): """ Returns the intersection of the shape with the given line (in scene coordinates). :type line: QLineF :rtype: QPointF """ intersection = QPointF() path = self.painterPath() polygon = self.mapToScene(path.toFillPolygon(self.transform())) for i in range(0, polygon.size() - 1): polyline = QLineF(polygon[i], polygon[i + 1]) if polyline.intersect(line, intersection) == QLineF.BoundedIntersection: return intersection return None
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 paint(self, painter, option, widget): if not self.source or not self.dest: return # Draw the line itself. line = QLineF(self.sourcePoint, self.destPoint) if line.length() == 0.0: return painter.setPen(QPen(Qt.black, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) # Draw the arrows if there's enough room. angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = Edge.TwoPi - angle sourceArrowP1 = self.sourcePoint + QPointF(math.sin(angle + Edge.Pi / 3) * self.arrowSize, math.cos(angle + Edge.Pi / 3) * self.arrowSize) sourceArrowP2 = self.sourcePoint + QPointF(math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize, math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize); destArrowP1 = self.destPoint + QPointF(math.sin(angle - Edge.Pi / 3) * self.arrowSize, math.cos(angle - Edge.Pi / 3) * self.arrowSize) destArrowP2 = self.destPoint + QPointF(math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize, math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize) painter.setBrush(Qt.black) painter.drawPolygon(QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2])) painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2]))
def setWedgeGizmo(self, neighbor_virtual_helix: int, neighbor_virtual_helix_item: GridVirtualHelixItemT): """Adds a WedgeGizmo to oriented toward the specified neighbor vhi. Called by NucleicAcidPartItem _refreshVirtualHelixItemGizmos, in between with beginAddWedgeGizmos and endAddWedgeGizmos. Args: neighbor_virtual_helix: the id_num of neighboring virtual helix neighbor_virtual_helix_item: the neighboring virtual helix item """ wg_dict = self.wedge_gizmos nvhi = neighbor_virtual_helix_item nvhi_name = nvhi.getProperty('name') pos = self.scenePos() line = QLineF(pos, nvhi.scenePos()) line.translate(_RADIUS, _RADIUS) if line.length() > (_RADIUS*1.99): color = '#5a8bff' else: color = '#cc0000' nvhi_name = nvhi_name + '*' # mark as invalid line.setLength(_RADIUS) if neighbor_virtual_helix in wg_dict: wedge_item = wg_dict[neighbor_virtual_helix] else: wedge_item = WedgeGizmo(_RADIUS, WEDGE_RECT, self) wg_dict[neighbor_virtual_helix] = wedge_item wedge_item.showWedge(line.angle(), color, outline_only=False) self._added_wedge_gizmos.add(neighbor_virtual_helix)
def getNeighbors(self): items = filter(lambda x: type(x) is VirtualHelixItem, self.collidingItems()) name = self._virtual_helix.getName() pos = self.scenePos() print("\n%s (%d, %d)" % (name, pos.x(), pos.y())) for nvhi in items: npos = nvhi.scenePos() line = QLineF(pos, npos) print("\t%s (%d, %d) %d" % (nvhi.virtualHelix().getName(), npos.x(), npos.y(), line.length()))
def paint(self, painter, option, widget=None): """ Public method to paint the item in local coordinates. @param painter reference to the painter object (QPainter) @param option style options (QStyleOptionGraphicsItem) @param widget optional reference to the widget painted on (QWidget) """ if (option.state & QStyle.State_Selected) == \ QStyle.State(QStyle.State_Selected): width = 2 else: width = 1 # draw the line first line = QLineF(self._origin, self._end) painter.setPen( QPen(Qt.black, width, Qt.SolidLine, Qt.FlatCap, Qt.MiterJoin)) painter.drawLine(line) # draw the arrow head arrowAngle = self._type * ArrowheadAngleFactor slope = math.atan2(line.dy(), line.dx()) # Calculate left arrow point arrowSlope = slope + arrowAngle a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), self._end.y() - self._halfLength * math.sin(arrowSlope)) # Calculate right arrow point arrowSlope = slope - arrowAngle a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), self._end.y() - self._halfLength * math.sin(arrowSlope)) if self._filled: painter.setBrush(Qt.black) else: painter.setBrush(Qt.white) polygon = QPolygonF() polygon.append(line.p2()) polygon.append(a1) polygon.append(a2) painter.drawPolygon(polygon)
def paint(self, painter, option, widget): """ Customize line adding an arrow head :param QPainter painter: Painter instance of the item :param option: Painter option of the item :param widget: Widget instance """ if not self.source or not self.destination: return line = QLineF(self.source_point, self.destination_point) if qFuzzyCompare(line.length(), 0): return # Draw the line itself color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 150 + 80 / self.steps_max * self.steps) if self.highlighted: color.setHsv(0, 0, 0) style = self.line_style painter.setPen(QPen(color, 1, style, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) # Draw the arrows angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (2.0 * math.pi) - angle # arrow in the middle of the arc hpx = line.p1().x() + (line.dx() / 2.0) hpy = line.p1().y() + (line.dy() / 2.0) head_point = QPointF(hpx, hpy) painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) destination_arrow_p1 = head_point + QPointF( math.sin(angle - math.pi / 3) * self.arrow_size, math.cos(angle - math.pi / 3) * self.arrow_size) destination_arrow_p2 = head_point + QPointF( math.sin(angle - math.pi + math.pi / 3) * self.arrow_size, math.cos(angle - math.pi + math.pi / 3) * self.arrow_size) painter.setBrush(color) painter.drawPolygon(QPolygonF([head_point, destination_arrow_p1, destination_arrow_p2])) if self.metadata["confirmation_text"]: painter.drawText(head_point, self.metadata["confirmation_text"])
def paint(self, painter, option, widget): """ Customize line adding an arrow head :param QPainter painter: Painter instance of the item :param option: Painter option of the item :param widget: Widget instance """ if not self.source or not self.destination: return line = QLineF(self.source_point, self.destination_point) if qFuzzyCompare(line.length(), 0): return # Draw the line itself color = QColor() style = Qt.SolidLine if self.status == ARC_STATUS_STRONG: color.setNamedColor('blue') if self.status == ARC_STATUS_WEAK: color.setNamedColor('salmon') style = Qt.DashLine painter.setPen(QPen(color, 1, style, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) # Draw the arrows angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (2.0 * math.pi) - angle # arrow in the middle of the arc hpx = line.p1().x() + (line.dx() / 2.0) hpy = line.p1().y() + (line.dy() / 2.0) head_point = QPointF(hpx, hpy) painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) destination_arrow_p1 = head_point + QPointF( math.sin(angle - math.pi / 3) * self.arrow_size, math.cos(angle - math.pi / 3) * self.arrow_size) destination_arrow_p2 = head_point + QPointF( math.sin(angle - math.pi + math.pi / 3) * self.arrow_size, math.cos(angle - math.pi + math.pi / 3) * self.arrow_size) painter.setBrush(color) painter.drawPolygon(QPolygonF([head_point, destination_arrow_p1, destination_arrow_p2])) if self.metadata["confirmation_text"]: painter.drawText(head_point, self.metadata["confirmation_text"])
def paint(self, painter, option, widget): assert self.fromSquare is not None assert self.toSquare is not None line = QLineF(self.sourcePoint, self.destPoint) assert(line.length() != 0.0) # Draw the arrows if there's enough room. angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi*2.0) - angle destArrowP1 = self.destPoint + QPointF( math.sin(angle - math.pi / 3) * self.arrowSize, math.cos(angle - math.pi / 3) * self.arrowSize ) destArrowP2 = self.destPoint + QPointF( math.sin(angle - math.pi + math.pi / 3) * self.arrowSize, math.cos(angle - math.pi + math.pi / 3) * self.arrowSize ) painter.setPen(self.pen) painter.setBrush(self.brush) # arrowhead1 = QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]) arrowhead2 = QPolygonF([line.p2(), destArrowP1, destArrowP2]) painter.drawPolygon(arrowhead2) painter.setPen(self.pen) painter.drawLine(line)
def angle_arrow(self, path, origin='head'): ''' Compute the two points of the arrow head with the right angle ''' if origin == 'tail': path = path.toReversed() length = path.length() percent = path.percentAtLength(length - 10.0) src = path.pointAtPercent(percent) #path.moveTo(path.pointAtPercent(1)) end_point = path.pointAtPercent(1) #end_point = path.currentPosition() line = QLineF(src, end_point) angle = math.acos(line.dx() / (line.length() or 1)) if line.dy() >= 0: angle = math.pi * 2 - angle arrow_size = 10.0 arrow_p1 = end_point + QPointF( math.sin(angle - math.pi / 3) * arrow_size, math.cos(angle - math.pi / 3) * arrow_size) arrow_p2 = end_point + QPointF( math.sin(angle - math.pi + math.pi / 3) * arrow_size, math.cos(angle - math.pi + math.pi / 3) * arrow_size) return (arrow_p1, arrow_p2)
def paint(self, painter, option, widget=None): if self.my_start_item.collidesWithItem(self.my_end_item): return my_start_item = self.my_start_item my_end_item = self.my_end_item my_color = self.my_color my_pen = self.pen() my_pen.setColor(self.my_color) arrow_size = 20.0 painter.setPen(my_pen) painter.setBrush(my_color) center_line = QLineF(my_start_item.pos(), my_end_item.pos()) end_polygon = my_end_item.polygon p1 = end_polygon.first() + my_end_item.pos() intersect_point = QPointF() for i in end_polygon: p2 = i + my_end_item.pos() poly_line = QLineF(p1, p2) intersect_type = poly_line.intersect(center_line, intersect_point) if intersect_type == QLineF.BoundedIntersection: break p1 = p2 self.setLine(QLineF(intersect_point, my_start_item.pos())) line = self.line() angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2) - angle arrow_p1 = line.p1() + QPointF(math.sin(angle + math.pi / 3.0) * arrow_size, math.cos(angle + math.pi / 3) * arrow_size) arrow_p2 = line.p1() + QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrow_size, math.cos(angle + math.pi - math.pi / 3.0) * arrow_size) self.arrowHead.clear() for point in [line.p1(), arrow_p1, arrow_p2]: self.arrowHead.append(point) painter.drawLine(line) painter.drawPolygon(self.arrowHead) if self.isSelected(): painter.setPen(QPen(my_color, 1, Qt.DashLine)) my_line = QLineF(line) my_line.translate(0, 4.0) painter.drawLine(my_line) my_line.translate(0, -8.0) painter.drawLine(my_line)
def __findRectIntersectionPoint(self, item, p1, p2): """ Private method to find the intersetion point of a line with a rectangle. @param item item to check against @param p1 first point of the line (QPointF) @param p2 second point of the line (QPointF) @return the intersection point (QPointF) """ rect = self.__mapRectFromItem(item) lines = [ QLineF(rect.topLeft(), rect.topRight()), QLineF(rect.topLeft(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.bottomLeft()), QLineF(rect.bottomRight(), rect.topRight()), ] intersectLine = QLineF(p1, p2) intersectPoint = QPointF(0, 0) for line in lines: if intersectLine.intersect(line, intersectPoint) == QLineF.BoundedIntersection: return intersectPoint return QPointF(-1.0, -1.0)
def calculateForces(self): if not self.scene() or self.scene().mouseGrabberItem() is self: self.newPos = self.pos() return # Sum up all forces pushing this item away. xvel = 0.0 yvel = 0.0 for item in self.scene().items(): if not isinstance(item, Node): continue line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0)) dx = line.dx() dy = line.dy() l = 2.0 * (dx * dx + dy * dy) if l > 0: xvel += (dx * 150.0) / l yvel += (dy * 150.0) / l # Now subtract all forces pulling items together. weight = (len(self.edgeList) + 1) * 10.0 for edge in self.edgeList: if edge.sourceNode() is self: pos = self.mapFromItem(edge.destNode(), 0, 0) else: pos = self.mapFromItem(edge.sourceNode(), 0, 0) xvel += pos.x() / weight yvel += pos.y() / weight if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1: xvel = yvel = 0.0 sceneRect = self.scene().sceneRect() self.newPos = self.pos() + QPointF(xvel, yvel) self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)) self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
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 adjust(self): """ Draw the arc line """ if not self.source or not self.destination: return line = QLineF( self.mapFromItem( self.source, self.source.boundingRect().width() - (self.source.boundingRect().width() / 2.0), self.source.boundingRect().height() / 2.0 ), self.mapFromItem( self.destination, self.destination.boundingRect().width() / 2.0, self.destination.boundingRect().height() / 2.0 ) ) self.prepareGeometryChange() self.source_point = line.p1() self.destination_point = line.p2() # mouse over on line only self.setLine(line)
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 mouseMoveEvent(self, event): path, text = self._rulerObject baseElem = path.elementAt(0) canvasPos = event.localPos() if event.modifiers() & Qt.ShiftModifier: basePos = QPointF(baseElem.x, baseElem.y) canvasPos = self.clampToOrigin(canvasPos, basePos) canvasPos = self.magnetPos(canvasPos) x, y = canvasPos.x(), canvasPos.y() path.setElementPositionAt(1, x, baseElem.y) path.setElementPositionAt(2, x, y) path.setElementPositionAt(3, baseElem.x, baseElem.y) line = QLineF(baseElem.x, baseElem.y, x, y) l = line.length() # angle() doesnt go by trigonometric direction. Weird. # TODO: maybe split in positive/negative 180s (ff) a = 360 - line.angle() line.setP2(QPointF(x, baseElem.y)) h = line.length() line.setP1(QPointF(x, y)) v = line.length() text = "%d\n↔ %d\n↕ %d\nα %dº" % (l, h, v, a) self._rulerObject = (path, text) self.parent().update()
def paintEvent(self, event): option = QStyleOption() option.initFrom(self) contents_rect = self.style().subElementRect( QStyle.SE_FrameContents, option, self ) or self.contentsRect( ) # the SE_FrameContents rect is Null unless the stylesheet defines decorations if self.graphStyle == self.BarStyle: graph_width = self.__dict__['graph_width'] = int( ceil( float(contents_rect.width()) / self.horizontalPixelsPerUnit)) else: graph_width = self.__dict__['graph_width'] = int( ceil( float(contents_rect.width() - 1) / self.horizontalPixelsPerUnit) + 1) max_value = self.__dict__['max_value'] = max( chain([0], *(islice(reversed(graph.data), graph_width) for graph in self.graphs if graph.enabled))) if self.graphHeight == self.AutomaticHeight or self.graphHeight < 0: graph_height = self.__dict__['graph_height'] = max( self.scaler.get_height(max_value), self.minHeight) else: graph_height = self.__dict__['graph_height'] = max( self.graphHeight, self.minHeight) if self.graphStyle == self.BarStyle: height_scaling = float(contents_rect.height()) / graph_height else: height_scaling = float(contents_rect.height() - self.lineThickness) / graph_height painter = QStylePainter(self) painter.drawPrimitive(QStyle.PE_Widget, option) painter.setClipRect(contents_rect) painter.save() painter.translate(contents_rect.x() + contents_rect.width() - 1, contents_rect.y() + contents_rect.height() - 1) painter.scale(-1, -1) painter.setRenderHint(QStylePainter.Antialiasing, self.graphStyle != self.BarStyle) for graph in (graph for graph in self.graphs if graph.enabled and graph.data): if self.boundary is not None and 0 < self.boundary < graph_height: boundary_width = min(5.0 / height_scaling, self.boundary - 0, graph_height - self.boundary) pen_color = QLinearGradient( 0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling) pen_color.setColorAt(0, graph.color) pen_color.setColorAt(1, graph.over_boundary_color) brush_color = QLinearGradient( 0, (self.boundary - boundary_width) * height_scaling, 0, (self.boundary + boundary_width) * height_scaling) brush_color.setColorAt( 0, self.color_with_alpha(graph.color, self.fillTransparency)) brush_color.setColorAt( 1, self.color_with_alpha(graph.over_boundary_color, self.fillTransparency)) else: pen_color = graph.color brush_color = self.color_with_alpha(graph.color, self.fillTransparency) dataset = islice(reversed(graph.data), graph_width) if self.graphStyle == self.BarStyle: lines = [ QLineF(x * self.horizontalPixelsPerUnit, 0, x * self.horizontalPixelsPerUnit, y * height_scaling) for x, y in enumerate(dataset) ] painter.setPen(QPen(pen_color, self.lineThickness)) painter.drawLines(lines) else: painter.translate(0, +self.lineThickness / 2 - 1) if self.smoothEnvelope and self.smoothFactor > 0: min_value = 0 max_value = graph_height * height_scaling cx_offset = self.horizontalPixelsPerUnit / 3.0 smoothness = self.smoothFactor last_values = deque( 3 * [next(dataset) * height_scaling], maxlen=3 ) # last 3 values: 0 last, 1 previous, 2 previous previous envelope = QPainterPath() envelope.moveTo(0, last_values[0]) for x, y in enumerate(dataset, 1): x = x * self.horizontalPixelsPerUnit y = y * height_scaling * ( 1 - smoothness) + last_values[0] * smoothness last_values.appendleft(y) c1x = x - cx_offset * 2 c2x = x - cx_offset c1y = limit( (1 + smoothness) * last_values[1] - smoothness * last_values[2], min_value, max_value ) # same gradient as previous previous value to previous value c2y = limit( (1 - smoothness) * last_values[0] + smoothness * last_values[1], min_value, max_value ) # same gradient as previous value to last value envelope.cubicTo(c1x, c1y, c2x, c2y, x, y) else: envelope = QPainterPath() envelope.addPolygon( QPolygonF([ QPointF(x * self.horizontalPixelsPerUnit, y * height_scaling) for x, y in enumerate(dataset) ])) if self.fillEnvelope or graph.fill_envelope: first_element = envelope.elementAt(0) last_element = envelope.elementAt(envelope.elementCount() - 1) fill_path = QPainterPath() fill_path.moveTo(last_element.x, last_element.y) fill_path.lineTo(last_element.x + 1, last_element.y) fill_path.lineTo(last_element.x + 1, -self.lineThickness) fill_path.lineTo(-self.lineThickness, -self.lineThickness) fill_path.lineTo(-self.lineThickness, first_element.y) fill_path.connectPath(envelope) painter.fillPath(fill_path, brush_color) painter.strokePath( envelope, QPen(pen_color, self.lineThickness, join=Qt.RoundJoin)) painter.translate(0, -self.lineThickness / 2 + 1) if self.boundary is not None and self.boundaryColor: painter.setRenderHint(QStylePainter.Antialiasing, False) painter.setPen(QPen(self.boundaryColor, 1.0)) painter.drawLine(0, self.boundary * height_scaling, contents_rect.width(), self.boundary * height_scaling) painter.restore() # queue the 'updated' signal to be emitted after returning to the main loop QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
def showAt(self, initialPosition): self.start = initialPosition self.end = initialPosition self.setLine(QLineF(self.start, self.end)) self.show()
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)
def calcArrow(srcdes_list,itemignoreZooming,iconScale): ''' if PoolItem then boundingrect should be background rather than graphicsobject ''' src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] order = srcdes_list[3] # print("Source => ", src) compartment = src.parentItem() srcobj = src.gobj desobj = des.gobj if isinstance(src,PoolItem): srcobj = src.bg if isinstance(des,PoolItem): desobj = des.bg # if itemignoreZooming: # srcRect = self.recalcSceneBoundingRect(srcobj) # desRect = self.recalcSceneBoundingRect(desobj) # else: srcRect = compartment.mapFromScene(srcobj.sceneBoundingRect()).boundingRect() desRect = compartment.mapFromScene(desobj.sceneBoundingRect()).boundingRect() arrow = QPolygonF() if srcRect.intersects(desRect): ''' This is created for getting a emptyline reference \ because 'lineCord' function keeps a reference between qgraphicsline and its src and des ''' arrow.append(QPointF(0,0)) arrow.append(QPointF(0,0)) return arrow if (order == 0): tmpLine = QLineF(srcRect.center().x(), srcRect.center().y(), desRect.center().x(), desRect.center().y()) elif(order > 0): dx = desRect.center().x()- srcRect.center().x() dy = desRect.center().y()- srcRect.center().y() dx0 = dy dy0 = -dx tetha1 = (atan2(dy0,dx0)) a0 = 4 *(cos(tetha1)) b0 = 4 *(sin(tetha1)) ''' Higher order ( > 4) connectivity will not be done''' if ((order == 3) or (order == 4)): a0 = a0*2 b0 = b0*2 if(order %2 == 0): srcCentera0 = srcRect.center().x()-a0 srcCenterb0 = srcRect.center().y()-b0 desCentera0 = desRect.center().x()-a0 desCenterb0 = desRect.center().y()-b0 else: srcCentera0 = srcRect.center().x()+a0 srcCenterb0 = srcRect.center().y()+b0 desCentera0 = desRect.center().x()+a0 desCenterb0 = desRect.center().y()+b0 pointa = QPointF(srcCentera0,srcCenterb0) pointb = QPointF(desCentera0,desCenterb0) tmpLine = QLineF(srcCentera0,srcCenterb0,desCentera0,desCenterb0) srcIntersects, lineSrcPoint = calcLineRectIntersection(srcRect, tmpLine) destIntersects, lineDestPoint = calcLineRectIntersection(desRect, tmpLine) if not srcIntersects: print('Source does not intersect line. Arrow points:',lineSrcPoint,src.mobj.name, src.mobj.className) if not destIntersects: print('Dest does not intersect line. Arrow points:', lineDestPoint, des.mobj.name, des.mobj.className) '''src and des are connected with line co-ordinates Arrow head is drawned if the distance between src and des line is >8 just for clean appeareance ''' if (abs(lineSrcPoint.x()-lineDestPoint.x()) > 8 or abs(lineSrcPoint.y()-lineDestPoint.y())>8): srcAngle = tmpLine.angle() if endtype == 'p' or endtype == 'stp': ''' Arrow head for Destination is calculated''' arrow.append(lineSrcPoint) arrow.append(lineDestPoint) degree = -60 srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineDestPoint,iconScale) arrow.append(QPointF(srcXArr1,srcYArr1)) arrow.append(QPointF(lineDestPoint.x(),lineDestPoint.y())) degree = -120 srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineDestPoint,iconScale) arrow.append(QPointF(srcXArr2,srcYArr2)) arrow.append(QPointF(lineDestPoint.x(),lineDestPoint.y())) elif endtype == 'st': ''' Arrow head for Source is calculated''' arrow.append(lineDestPoint) arrow.append(lineSrcPoint) degree = 60 srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineSrcPoint,iconScale) arrow.append(QPointF(srcXArr2,srcYArr2)) arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y())) degree = 120 srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineSrcPoint,iconScale) arrow.append(QPointF(srcXArr1,srcYArr1)) arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y())) elif endtype == 's' or endtype == 'sts': arrow.append(lineDestPoint) arrow.append(lineSrcPoint) degree = 60 srcXArr2,srcYArr2 = arrowHead(srcAngle,degree,lineSrcPoint,iconScale) arrow.append(QPointF(srcXArr2,srcYArr2)) arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y())) degree = 120 srcXArr1,srcYArr1= arrowHead(srcAngle,degree,lineSrcPoint,iconScale) arrow.append(QPointF(srcXArr1,srcYArr1)) arrow.append(QPointF(lineSrcPoint.x(),lineSrcPoint.y())) else: arrow.append(lineSrcPoint) arrow.append(lineDestPoint) return arrow
def paint(self, qp, style_option_view_item, model_index): mid = model_index.data() if type(mid) is ClassifiedImageBundle: qp.save() qp.drawImage(style_option_view_item.rect.left() + 4, style_option_view_item.rect.top() + 4, mid.get_thumb()) qp.setRenderHint(QPainter.Antialiasing) qp.setRenderHint(QPainter.HighQualityAntialiasing) if mid.has_color(): qp.setPen( QPen(QBrush(mid.get_color()), 4.0, Qt.DotLine if mid.is_classified() else Qt.SolidLine, Qt.SquareCap, Qt.RoundJoin)) lines_to_draw = [] len_of_all_lines = 2 * (mid.get_thumb().height() + mid.get_thumb().width() + 12) line_start_pos = -1 * min( 0, mid.animation_progress) * len_of_all_lines if mid.animation_progress >= 0: line_end_pos = mid.animation_progress * len_of_all_lines else: line_end_pos = 1 * len_of_all_lines tx = style_option_view_item.rect.left() + 2 ty = style_option_view_item.rect.top() + 2 h = mid.get_thumb().height() + 4 w = mid.get_thumb().width() + 4 if line_start_pos <= h and 0 < line_end_pos: lines_to_draw.append( QLineF(tx, ty + line_start_pos, tx, ty + min(h, line_end_pos))) if line_start_pos <= h + w and h < line_end_pos: lines_to_draw.append( QLineF(tx + max(line_start_pos, h) - h, ty + h, tx + min(h + w, line_end_pos) - h, ty + h)) if line_start_pos <= 2 * h + w and h + w < line_end_pos: lines_to_draw.append( QLineF(tx + w, ty + h - (max(line_start_pos - h - w, 0)), tx + w, ty + h - (min(line_end_pos - h - w, h)))) if line_start_pos <= 2 * h + 2 * w and 2 * h + w < line_end_pos: lines_to_draw.append( QLineF(tx + w - (max(line_start_pos - 2 * h - w, 0)), ty, tx + w - (min(line_end_pos - 2 * h - w, w)), ty)) qp.drawLines(lines_to_draw) if mid.keep or mid.keep is None or mid.get_show_buttons(): qp.setBrush(QColor(0, 255, 0)) qp.setPen( QPen(QBrush(QColor(0, 255, 0)), 1.0, Qt.SolidLine, Qt.SquareCap, Qt.RoundJoin)) qp.drawEllipse( style_option_view_item.rect.left() + mid.get_thumb().width() - 30, style_option_view_item.rect.top() + mid.get_thumb().height() - 30, 30, 30) qp.setPen( QPen(QBrush(QColor(255, 255, 255)), 6.0, Qt.SolidLine, Qt.SquareCap, Qt.RoundJoin)) qp.drawLines([ QLineF( style_option_view_item.rect.left() + mid.get_thumb().width() - 24, style_option_view_item.rect.top() + mid.get_thumb().height() - 13, style_option_view_item.rect.left() + mid.get_thumb().width() - 19, style_option_view_item.rect.top() + mid.get_thumb().height() - 8), QLineF( style_option_view_item.rect.left() + mid.get_thumb().width() - 19, style_option_view_item.rect.top() + mid.get_thumb().height() - 8, style_option_view_item.rect.left() + mid.get_thumb().width() - 7, style_option_view_item.rect.top() + mid.get_thumb().height() - 20) ]) if (mid.keep is not None and not mid.keep) or mid.get_show_buttons(): qp.setBrush(QColor(255, 0, 0)) qp.setPen( QPen(QBrush(QColor(255, 0, 0)), 1.0, Qt.SolidLine, Qt.SquareCap, Qt.RoundJoin)) qp.drawEllipse( style_option_view_item.rect.left() + 8, style_option_view_item.rect.top() + mid.get_thumb().height() - 30, 30, 30) qp.setPen( QPen(QBrush(QColor(255, 255, 255)), 6.0, Qt.SolidLine, Qt.SquareCap, Qt.RoundJoin)) qp.drawLine( style_option_view_item.rect.left() + 16, style_option_view_item.rect.top() + mid.get_thumb().height() - 22, style_option_view_item.rect.left() + 30, style_option_view_item.rect.top() + mid.get_thumb().height() - 8) qp.drawLine( style_option_view_item.rect.left() + 16, style_option_view_item.rect.top() + mid.get_thumb().height() - 8, style_option_view_item.rect.left() + 30, style_option_view_item.rect.top() + mid.get_thumb().height() - 22) qp.restore() else: super().paint(qp, style_option_view_item, model_index)
def make_poly(hull): polygon = [ QLineF(hull[i], hull[(i + 1) % len(hull)]) for i in range(len(hull)) ] return polygon
class KnifeTool(BaseTool): name = "Knife" iconPath = ":/resources/cutter.svg" def __init__(self, parent=None): super().__init__(parent) self._cachedIntersections = None self._knifeLine = None self._knifeDots = None def _appendIntersection(self, contour, index, pt, dotHalf, dotWidth): dotHeight = dotWidth x = pt[0] - dotHalf y = pt[1] - dotHalf self._knifeDots.addEllipse(x, y, dotWidth, dotHeight) if (contour, index) in self._cachedIntersections: self._cachedIntersections[(contour, index)].append( pt[2]) else: self._cachedIntersections[(contour, index)] = [pt[2]] # events def mousePressEvent(self, event): canvasPos = event.localPos() self._knifeLine = QLineF(canvasPos, canvasPos) def mouseMoveEvent(self, event): line = self._knifeLine pos = event.localPos() widget = self.parent() if event.modifiers() & Qt.ShiftModifier: pos = self.clampToOrigin(pos, line.p1()) line.setP2(pos) self._cachedIntersections = OrderedDict() scale = widget.inverseScale() dotWidth = 5 * scale dotHalf = dotWidth / 2.0 self._knifeDots = QPainterPath() for contour in self._glyph: segments = contour.segments for index, seg in enumerate(segments): if seg[-1].segmentType == "move": continue prev = segments[index - 1][-1] if len(seg) == 3: i = bezierMath.curveIntersections( prev, seg[0], seg[1], seg[2], line.x1(), line.y1(), pos.x(), pos.y()) for pt in i: self._appendIntersection( contour, index, pt, dotHalf, dotWidth) else: pt = bezierMath.lineIntersection( prev.x, prev.y, seg[0].x, seg[0].y, line.x1(), line.y1(), pos.x(), pos.y()) if pt is not None: self._appendIntersection( contour, index, pt, dotHalf, dotWidth) widget.update() def mouseReleaseEvent(self, event): self._knifeLine = None self._knifeDots = None # no-move clicks if self._cachedIntersections is None: return self._glyph.prepareUndo() # reverse so as to not invalidate our cached segment indexes for loc, ts in reversed(list(self._cachedIntersections.items())): contour, index = loc prev = 1 # reverse so as to cut from higher to lower value and compensate for t in sorted(ts, reverse=True): contour.splitAndInsertPointAtSegmentAndT(index, t / prev) prev = t self._cachedIntersections = None self.parent().update() # custom painting def paint(self, painter): if self._knifeLine is not None and self._knifeLine.length(): painter.drawLine(self._knifeLine) if self._knifeDots is not None: painter.drawPath(self._knifeDots)
def drawObject(self, qp, coord): grid = self.paramBox.layout() angle = grid.itemAtPosition(2, 1).widget().text() realCoord = readObj(self) try: slope = float(angle) if slope > 45: slope = 45.0 elif slope < -45: slope = -45.0 except ValueError: slope = 0.0 tan = math.tan(math.radians(slope)) # If the object has a height of 0 we don't need to draw it if realCoord[1][0] > 0: qp.setPen(QPen(Qt.darkGreen, 5, Qt.SolidLine)) # Left object (starts from left side until the xCoordinate) poly = QPolygonF() # Bottom left point1 = QPointF( self.width() - self.drawView.width(), self.drawView.height() + self.drawView.width() * tan / 2) poly.append(point1) # Top left point2 = QPointF(self.width() - self.drawView.width(), coord[8][0] + self.drawView.width() * tan / 2) poly.append(point2) # Top right point3 = QPointF( coord[7][0], coord[8][0] + tan * (self.width() - self.drawView.width() / 2 - coord[7][0])) poly.append(point3) # Bottom right point4 = QPointF( coord[7][0], self.drawView.height() + tan * (self.width() - self.drawView.width() / 2 - coord[7][0])) poly.append(point4) path = QPainterPath() path.addPolygon(poly) qp.drawPolygon(poly) qp.fillPath(path, QColor(Qt.darkGreen)) # Adds striking distance to object line qp.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine)) rg = coord[6] line = QLineF(point3.x(), point3.y() - rg, point2.x(), point2.y() - rg) qp.drawLine(line) # If the object has a height of 0 we don't need to draw it if realCoord[1][1] > 0: qp.setPen(QPen(Qt.darkGreen, 5, Qt.SolidLine)) # Right object (starts from right side until the xCoordinate) poly = QPolygonF() # Bottom left point1 = QPointF( coord[7][1], self.drawView.height() + tan * (self.width() - self.drawView.width() / 2 - coord[7][1])) poly.append(point1) # Top left point2 = QPointF( coord[7][1], coord[8][1] + tan * (self.width() - self.drawView.width() / 2 - coord[7][1])) poly.append(point2) # Top right point3 = QPointF(self.width(), coord[8][1] - self.drawView.width() * tan / 2) poly.append(point3) # Bottom right point4 = QPointF( self.width(), self.drawView.height() - self.drawView.width() * tan / 2) poly.append(point4) path = QPainterPath() path.addPolygon(poly) qp.drawPolygon(poly) qp.fillPath(path, QColor(Qt.darkGreen)) # Adds striking distance to object line qp.setPen(QPen(Qt.darkGreen, 2, Qt.SolidLine)) rg = coord[6] line = QLineF(point3.x(), point3.y() - rg, point2.x(), point2.y() - rg) qp.drawLine(line)
def _appendIntersection(self, pt): x, y, _ = pt line = QLineF(self._rulerObject[0]) line.setP2(QPointF(x, y)) self._rulerPts[line.length()] = (x, y)
def updateEnd(self, point): self.end = point self.setLine(QLineF(self.start, self.end)) # hide() is inherited
def paint_axes(p: QPainter, xtick_every=0, ytick_every=0, xlabels="down", ylabels="left", opacity=0.5): from PyQt5.QtGui import QPen, QColor from PyQt5.QtCore import Qt, QLineF cur_pen = p.pen() color = QColor(Qt.black) color.setAlphaF(opacity) pen = QPen(color) xscale, yscale = scale_of_painter(p) xlength = 10000 / xscale ylength = 10000 / yscale xline_width = 2 / yscale yline_width = 2 / xscale xtick_length = 10 / yscale ytick_length = 10 / xscale if not xtick_every: xtick_every = 50 / xscale if not ytick_every: ytick_every = 50 / yscale pen.setWidthF(xline_width) p.setPen(pen) p.drawLine(-xlength / 2, 0, xlength / 2, 0) pen.setWidthF(yline_width) p.setPen(pen) p.drawLine(0, -ylength / 2, 0, ylength / 2) p.save() for i in range(int(xlength / 2 / xtick_every)): p.translate(xtick_every, 0) p.drawLine(QLineF(0, -xtick_length / 2, 0, xtick_length / 2)) p.restore() p.save() for i in range(int(xlength / 2 / xtick_every)): p.translate(-xtick_every, 0) p.drawLine(QLineF(0, -xtick_length / 2, 0, xtick_length / 2)) p.restore() p.save() pen.setWidthF(xline_width) p.setPen(pen) for i in range(int(ylength / 2 / ytick_every)): p.translate(0, ytick_every) p.drawLine(QLineF(-ytick_length / 2, 0, ytick_length / 2, 0)) p.restore() p.save() for i in range(int(ylength / 2 / ytick_every)): p.translate(0, -ytick_every) p.drawLine(QLineF(-ytick_length / 2, 0, ytick_length / 2, 0)) p.restore()
class ArrowLine(object): def __init__(self, x1, y1, x2, y2, fromNode=None, endNode=None): self.__source = QPointF(x1, y1) self.__dest = QPointF(x2, y2) self.__line = QLineF(self.__source, self.__dest) self.__arrowLen = 10 # self.__line.setLength(self.__line.length() - self.__arrowLen) self.__penWidth = 2 self.__pen = QPen() self.__brush = QBrush() self.__color = QColor(255, 0, 0) self.__arrowRatio = 1.0 self.__isSolid = True self.__fromNode = fromNode self.__endNode = endNode def GetFromNode(self): return self.__fromNode def GetEndNode(self): return self.__endNode def SetArrowLen(self, length): self.__arrowLen = length def GetArrowLen(self): return self.__arrowLen def SetPenWidth(self, width): self.__penWidth = width def GetPenWidth(self): return self.__penWidth def SetArrowSolid(self, flag): self.__isSolid = flag def IsArrowSolid(self): return self.__isSolid def SetColor(self, color): self.__color = color def GetColor(self): return self.__color def GetLine(self): return self.__line def Paint(self, QPainter): # setPen self.__pen.setWidth(self.__penWidth) self.__pen.setColor(self.__color) QPainter.setPen(self.__pen) # setBrush if self.__isSolid: self.__brush.setColor(self.__color) self.__brush.setStyle(Qt.SolidPattern) QPainter.setBrush(self.__brush) v = self.__line.unitVector() v.setLength(self.__arrowLen) v.translate( QPointF(self.__line.dx() * self.__arrowRatio, self.__line.dy() * self.__arrowRatio)) # width of arrow n = v.normalVector() n.setLength(n.length() * 0.5) n2 = n.normalVector().normalVector() QPainter.drawLine(self.__line) QPainter.drawPolygon(v.p2(), n.p2(), n2.p2())
class GraphicEdge(QGraphicsPathItem): def __init__(self, edge_wrap, directed, parent=None): super().__init__(parent) self.edge_wrap = edge_wrap self.width = 3.0 self.pos_src = [0, 0] self.pos_dst = [0, 0] # 是否有向 self.directed = directed self.flag = 0 self.capacity = self.edge_wrap.capacity self.setAcceptHoverEvents(True) # 普通画图时的pen样式 self._n_pen = QPen(QColor("#000")) self._n_pen.setWidthF(self.width) # 画图时的pen样式 self._pen = self._n_pen # 悬浮时的pen样式 self._hover_pen = QPen(Qt.green) self._hover_pen.setWidthF(self.width) # 拖拽时的样式 self._pen_dragging = QPen(QColor("#000")) self._pen_dragging.setStyle(Qt.DashDotLine) self._pen_dragging.setWidthF(self.width) self._mark_brush = QBrush() self._mark_brush.setColor(Qt.green) self._mark_brush.setStyle(Qt.SolidPattern) self._normal_brush = QBrush() self._normal_brush.setColor(Qt.black) self._normal_brush.setStyle(Qt.SolidPattern) self.brush = self._normal_brush self.setFlag(QGraphicsItem.ItemIsSelectable) self.setZValue(-1) def set_src(self, x, y): self.pos_src = [x, y] def set_dst(self, x, y): self.pos_dst = [x, y] def calc_path(self): path = QPainterPath(QPointF(self.pos_src[0], self.pos_src[1])) # 起点 path.lineTo(QPointF(self.pos_dst[0], self.pos_dst[1])) # 终点 if self.directed: # 画箭头 self.line = QLineF(QPointF(self.pos_src[0], self.pos_src[1]), QPointF(self.pos_dst[0], self.pos_dst[1])) if self.flag == 0: self.line.setLength(self.line.length() - 20) else: self.line.setLength(self.line.length() - self.edge_wrap.end_item.r) v = self.line.unitVector() v.setLength(20) v.translate(QPointF(self.line.dx(), self.line.dy())) n = v.normalVector() n.setLength(n.length() * 0.5) n2 = n.normalVector().normalVector() p1 = v.p2() p2 = n.p2() p3 = n2.p2() # 方法2 arrow = QPolygonF([p1, p2, p3, p1]) path.addPolygon(arrow) # path = QPainterPath(QPointF(self.pos_src[0], self.pos_src[1])) # path.lineTo(self.pos_dst[0], self.pos_dst[1]) return path def boundingRect(self): return self.shape().boundingRect() def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent'): self.brush = self._mark_brush self._pen = self._hover_pen self.update() def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent'): self.brush = self._normal_brush self._pen = self._n_pen self.update() def shape(self): # 设置宽度 这里用了100 很大 qps = QPainterPathStroker() qps.setWidth(100) return qps.createStroke(self.calc_path()) def paint(self, painter, graphics_item, widget=None): if self.edge_wrap.end_item is None: self.ensureVisible() self.setPath(self.calc_path()) path = self.path() painter.setPen(self._pen_dragging) painter.setBrush(self.brush) painter.drawPath(path) else: # 这画的才是连接后的线 self.flag = 1 self.setPath(self.calc_path()) # 设置路径 path = self.path() painter.setPen(self._pen) painter.setBrush(self.brush) painter.drawPath(path) self.flag = 0 painter.setFont(QFont("Times New Roman", 16)) painter.setPen(Qt.red) x = int((self.pos_src[0] + self.pos_dst[0]) / 2 - 17) y = int((self.pos_src[1] + self.pos_dst[1]) / 2 - 7) painter.drawText(x, y, "({}) {}".format(self.edge_wrap.id, self.capacity))
def lineage(self): global lineage self._zoom if lineage: lineage = False perc = 10 zoomline = self._photo.pixmap().width() if zoomline > 256 and zoomline < 512: perc = 2 elif zoomline > 512 and zoomline < 1024: perc = 3 addedLine = QLineF(240 / 2, 33 / perc, 240 / 2, 223 / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, 33 / perc, 230 / 2, 33 / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, 71 / perc, 230 / 2, 71 / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 - 19) / perc, 235 / 2, (71 - 19) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 19) / perc, 235 / 2, (71 + 19) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38) / perc, 230 / 2, (71 + 38) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38 + 38) / perc, 230 / 2, (71 + 38 + 38) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38 + 19) / perc, 235 / 2, (71 + 38 + 19) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38 + 38 + 38) / perc, 230 / 2, (71 + 38 + 38 + 38) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38 + 38 + 19) / perc, 235 / 2, (71 + 38 + 38 + 19) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, (71 + 38 + 38 + 38 + 19) / perc, 230 / 2, (71 + 38 + 38 + 38 + 19) / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) addedLine = QLineF(240 / 2, 223 / perc, 230 / 2, 223 / perc) self._scene.addLine(addedLine, QColor(0, 0, 0)) if perc == 2: needFont = self._scene.addText("5cm", QtGui.QFont( "Times", 30)).setDefaultTextColor(QColor(255, 255, 255)) elif perc == 1: needFont = self._scene.addText("10cm", QtGui.QFont( "Times", 30)).setDefaultTextColor(QColor(0, 0, 0)) else: needFont = self._scene.addText("20cm", QtGui.QFont( "Times", 30)).setDefaultTextColor(QColor(0, 0, 0)) else: self._scene.clear() self._scene = QtWidgets.QGraphicsScene(self) self._photo = QtWidgets.QGraphicsPixmapItem() self._scene.addItem(self._photo) self.setScene(self._scene) self.setTransformationAnchor( QtWidgets.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30))) self.setFrameShape(QtWidgets.QFrame.NoFrame) lineage = True
class KnifeTool(BaseTool): icon = _path name = QApplication.translate("KnifeTool", "Knife") shortcut = "E" def __init__(self, parent=None): super().__init__(parent) self._cachedIntersections = None self._knifeLine = None self._knifePts = None def _appendIntersection(self, contour, index, pt): x, y, t = pt self._knifePts.append((x, y)) if (contour, index) in self._cachedIntersections: self._cachedIntersections[(contour, index)].append(t) else: self._cachedIntersections[(contour, index)] = [t] def _findIntersections(self): self._cachedIntersections = OrderedDict() self._knifePts = [] line = self._knifeLine for contour in self._glyph: segments = contour.segments for index, seg in enumerate(segments): if seg[-1].segmentType == "move": continue prev = segments[index - 1][-1] if len(seg) == 3: if seg[-1].segmentType == "qcurve": i = bezierMath.qcurveIntersections( line.x1(), line.y1(), line.x2(), line.y2(), prev, *seg) else: i = bezierMath.curveIntersections( line.x1(), line.y1(), line.x2(), line.y2(), prev, seg[0], seg[1], seg[2], ) for pt in i: self._appendIntersection(contour, index, pt) elif len(seg) == 1: pt = bezierMath.lineIntersection( prev.x, prev.y, seg[0].x, seg[0].y, line.x1(), line.y1(), line.x2(), line.y2(), ) if pt is not None: self._appendIntersection(contour, index, pt) # events def mousePressEvent(self, event): if event.button() == Qt.LeftButton: pos = event.localPos() self._knifeLine = QLineF(pos, pos) else: super().mousePressEvent(event) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: pos = event.localPos() if self._knifeLine is None: self._knifeLine = QLineF(pos, pos) return line = self._knifeLine if event.modifiers() & Qt.ShiftModifier: pos = self.clampToOrigin(pos, line.p1()) line.setP2(pos) self._findIntersections() self.parent().update() else: super().mouseMoveEvent(event) def mouseReleaseEvent(self, event): if event.button() != Qt.LeftButton: super().mouseReleaseEvent(event) return if self._knifeLine is not None: p1, p2 = self._knifeLine.p1(), self._knifeLine.p2() self._knifeLine = None self._knifePts = None self.parent().update() # no-move clicks if not self._cachedIntersections: return self._glyph.beginUndoGroup() cutContours = (not event.modifiers() & Qt.AltModifier and len(self._cachedIntersections) > 1) if cutContours: oldPts = {pt for contour in self._glyph for pt in contour} path = self._glyph.getRepresentation("defconQt.QPainterPath") # reverse so as to not invalidate our cached segment indexes for loc, ts in reversed(list(self._cachedIntersections.items())): contour, index = loc prev = 1 # reverse so as to cut from higher to lower value and compensate for t in sorted(ts, reverse=True): contour.splitAndInsertPointAtSegmentAndT(index, t / prev) prev = t # TODO: optimize if cutContours: newPts = { pt for contour in self._glyph for pt in contour if pt.segmentType } - oldPts del oldPts distances = dict() for point in newPts: d = bezierMath.distance(p1.x(), p1.y(), point.x, point.y) distances[d] = point del newPts sortedPts = [distances[dist] for dist in sorted(distances.keys())] del distances # group points by belonging to contour "black area" siblings = [] stack = None if not path.contains(p1): stack = [] for pt, nextPt in zip(sortedPts, sortedPts[1:]): qPt = QPointF(pt.x, pt.y) qHalf = qPt + 0.5 * (QPointF(nextPt.x, nextPt.y) - qPt) if path.contains(qHalf): if stack is not None: stack.append(pt) else: if stack: stack.append(pt) siblings.extend(stack) stack = [] if not path.contains(p2): if stack: stack.append(nextPt) siblings.extend(stack) del stack # ok, now i = siblings.index(loc); siblings[i+1-2(i%2)] will yield # sibling newGlyph = self._glyph.__class__() pen = newGlyph.getPointPen() def _visitPath(contour, index): didJump = False pen.beginPath() while True: pt = contour.getPoint(index) if pt in visited: pen.endPath() break if pt not in siblings: visited.add(pt) segmentType = pt.segmentType smooth = pt.smooth if didJump or pt in siblings: smooth = False if didJump: segmentType = "line" pen.addPoint((pt.x, pt.y), segmentType, smooth) if pt in siblings and not didJump: i = siblings.index(pt) otherPt = siblings[i + 1 - 2 * (i % 2)] # TODO: optimize-out this lookup for c in self._glyph: try: index = c.index(otherPt) except Exception: pass else: contour = c break didJump = True continue didJump = False index += 1 visited = set() for contour in self._glyph: for index, pt in enumerate(contour): if pt in visited or pt in siblings: continue _visitPath(contour, index) self._glyph.clearContours() pen = self._glyph.getPointPen() newGlyph.drawPoints(pen) self._glyph.endUndoGroup() ## self._cachedIntersections = None # custom painting def paint(self, painter, index): widget = self.parent() if index != widget.activeIndex(): return line = self._knifeLine if line is not None and line.length(): painter.save() pen = painter.pen() pen.setWidth(0) painter.setPen(pen) drawing.drawLine(painter, line.x1(), line.y1(), line.x2(), line.y2()) if self._knifePts is not None: scale = widget.inverseScale() dotSize = 5 * scale dotHalf = dotSize / 2 path = QPainterPath() for x, y in self._knifePts: x -= dotHalf y -= dotHalf path.addEllipse(x, y, dotSize, dotSize) painter.drawPath(path) painter.restore()
def __on_lineEdited(self, line): p1, p2 = map(self.item.mapFromScene, (line.p1(), line.p2())) self.item.setLine(QLineF(p1, p2))
def timerEvent(self): # Don't move too far away. lineToCenter = QLineF(QPointF(0, 0), self.mapFromScene(0, 0)) if lineToCenter.length() > 150: angleToCenter = math.acos(lineToCenter.dx() / lineToCenter.length()) if lineToCenter.dy() < 0: angleToCenter = Mouse.TwoPi - angleToCenter angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) + Mouse.Pi / 2) if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4: # Rotate left. self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2] elif angleToCenter >= Mouse.Pi and angleToCenter < ( Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4): # Rotate right. self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2] elif math.sin(self.angle) < 0: self.angle += 0.25 elif math.sin(self.angle) > 0: self.angle -= 0.25 # Try not to crash with any other mice. dangerMice = self.scene().items( QPolygonF([ self.mapToScene(0, 0), self.mapToScene(-30, -50), self.mapToScene(30, -50) ])) for item in dangerMice: if item is self: continue lineToMouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0)) angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length()) if lineToMouse.dy() < 0: angleToMouse = Mouse.TwoPi - angleToMouse angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) + Mouse.Pi / 2) if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2: # Rotate right. self.angle += 0.5 elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi - Mouse.Pi / 2): # Rotate left. self.angle -= 0.5 # Add some random movement. if len(dangerMice) > 1 and (qrand() % 10) == 0: if qrand() % 1: self.angle += (qrand() % 100) / 500.0 else: self.angle -= (qrand() % 100) / 500.0 self.speed += (-50 + qrand() % 100) / 100.0 dx = math.sin(self.angle) * 10 self.mouseEyeDirection = 0.0 if qAbs(dx / 5) < 1 else dx / 5 self.setRotation(self.rotation() + dx) self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: pos = event.localPos() self._knifeLine = QLineF(pos, pos) else: super().mousePressEvent(event)
def short_domain(side, f=0.3): r = side.unitVector() r = -r.p1() + r.p2() p1 = side.p1() + r * (self.a - self.a * f) p2 = side.p2() # - r * self.a * f return QLineF(p1, p2)
def showWedge(self, angle, color, extended=False, rev_gradient=False, outline_only=False): """Summary Args: angle (TYPE): Description color (TYPE): Description extended (bool, optional): Description rev_gradient (bool, optional): Description outline_only (bool, optional): Description """ # Hack to keep wedge in front # self.setRotation(self.pre_xover_item_group.rotation()) self._last_params = (angle, color, extended, rev_gradient, outline_only) radius = self._radius span = self.pre_xover_item_group.partCrossoverSpanAngle() / 2 radius_adjusted = radius + (_WEDGE_RECT_GAIN / 2) tip = QPointF(radius_adjusted, radius_adjusted) EXT = 1.35 if extended else 1.0 # print("wtf", tip, pos) base_p2 = QPointF(1, 1) line0 = QLineF(tip, QPointF(base_p2)) line1 = QLineF(tip, QPointF(base_p2)) line2 = QLineF(tip, QPointF(base_p2)) quad_scale = 1 + (.22 * (span - 5) / 55) # lo+(hi-lo)*(val-min)/(max-min) line0.setLength(radius_adjusted * EXT * quad_scale) # for quadTo control point line1.setLength(radius_adjusted * EXT) line2.setLength(radius_adjusted * EXT) line0.setAngle(angle) line1.setAngle(angle - span) line2.setAngle(angle + span) path = QPainterPath() if outline_only: self.setPen(getPenObj(color, 0.5, alpha=128, capstyle=Qt.RoundCap)) path.moveTo(line1.p2()) path.quadTo(line0.p2(), line2.p2()) else: gradient = QRadialGradient(tip, radius_adjusted * EXT) color1 = getColorObj(color, alpha=80) color2 = getColorObj(color, alpha=0) if rev_gradient: color1, color2 = color2, color1 if extended: gradient.setColorAt(0, color1) gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT), color1) gradient.setColorAt( radius_adjusted / (radius_adjusted * EXT) + 0.01, color2) gradient.setColorAt(1, color2) else: gradient.setColorAt(0, getColorObj(color, alpha=50)) brush = QBrush(gradient) self.setBrush(brush) path.moveTo(line1.p1()) path.lineTo(line1.p2()) path.quadTo(line0.p2(), line2.p2()) path.lineTo(line2.p1()) self.setPath(path) self.show()
def _boundJoystick(self, point): limitLine = QLineF(self._center(), point) if (limitLine.length() > self.__maxDistance): limitLine.setLength(self.__maxDistance) return limitLine.p2()
def long_domain(side, f=0.6): r = side.unitVector() r = -r.p1() + r.p2() p1 = side.p1() p2 = side.p2() - r * self.a * 0.4 return QLineF(p1, p2)
def update_from_array( self, array: np.ndarray, just_history=False, ) -> None: """Update the last datum's bar graphic from input data array. This routine should be interface compatible with ``pg.PlotCurveItem.setData()``. Normally this method in ``pyqtgraph`` seems to update all the data passed to the graphics object, and then update/rerender, but here we're assuming the prior graphics havent changed (OHLC history rarely does) so this "should" be simpler and faster. This routine should be made (transitively) as fast as possible. """ # index = self.start_index istart, istop = self._xrange index = array['index'] first_index, last_index = index[0], index[-1] # length = len(array) prepend_length = istart - first_index append_length = last_index - istop flip_cache = False # TODO: allow mapping only a range of lines thus # only drawing as many bars as exactly specified. if prepend_length: # new history was added and we need to render a new path new_bars = array[:prepend_length] prepend_path = gen_qpath(new_bars, 0, self.w) # XXX: SOMETHING IS MAYBE FISHY HERE what with the old_path # y value not matching the first value from # array[prepend_length + 1] ??? # update path old_path = self.path self.path = prepend_path self.path.addPath(old_path) # trigger redraw despite caching self.prepareGeometryChange() if append_length: # generate new lines objects for updatable "current bar" self._last_bar_lines = lines_from_ohlc(array[-1], self.w) # generate new graphics to match provided array # path appending logic: # we need to get the previous "current bar(s)" for the time step # and convert it to a sub-path to append to the historical set # new_bars = array[istop - 1:istop + append_length - 1] new_bars = array[-append_length - 1:-1] append_path = gen_qpath(new_bars, 0, self.w) self.path.moveTo(float(istop - self.w), float(new_bars[0]['open'])) self.path.addPath(append_path) # trigger redraw despite caching self.prepareGeometryChange() self.setCacheMode(QtGui.QGraphicsItem.NoCache) flip_cache = True self._xrange = first_index, last_index # last bar update i, o, h, l, last, v = array[-1][ ['index', 'open', 'high', 'low', 'close', 'volume'] ] # assert i == self.start_index - 1 assert i == last_index body, larm, rarm = self._last_bar_lines # XXX: is there a faster way to modify this? rarm.setLine(rarm.x1(), last, rarm.x2(), last) # writer is responsible for changing open on "first" volume of bar larm.setLine(larm.x1(), o, larm.x2(), o) if l != h: # noqa if body is None: body = self._last_bar_lines[0] = QLineF(i, l, i, h) else: # update body body.setLine(i, l, i, h) # XXX: pretty sure this is causing an issue where the bar has # a large upward move right before the next sample and the body # is getting set to None since the next bar is flat but the shm # array index update wasn't read by the time this code runs. Iow # we're doing this removal of the body for a bar index that is # now out of date / from some previous sample. It's weird # though because i've seen it do this to bars i - 3 back? self.update() if flip_cache: self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache)
def update_from_array( self, # full array input history ohlc: np.ndarray, # pre-sliced array data that's "in view" ohlc_iv: np.ndarray, view_range: Optional[tuple[int, int]] = None, profiler: Optional[pg.debug.Profiler] = None, ) -> None: ''' Update the last datum's bar graphic from input data array. This routine should be interface compatible with ``pg.PlotCurveItem.setData()``. Normally this method in ``pyqtgraph`` seems to update all the data passed to the graphics object, and then update/rerender, but here we're assuming the prior graphics havent changed (OHLC history rarely does) so this "should" be simpler and faster. This routine should be made (transitively) as fast as possible. ''' profiler = profiler or pg.debug.Profiler( disabled=not pg_profile_enabled(), gt=ms_slower_then, delayed=True, ) # index = self.start_index istart, istop = self._xrange ds_istart, ds_istop = self._ds_xrange index = ohlc['index'] first_index, last_index = index[0], index[-1] # length = len(ohlc) # prepend_length = istart - first_index # append_length = last_index - istop # ds_prepend_length = ds_istart - first_index # ds_append_length = last_index - ds_istop flip_cache = False x_gt = 16 if self._ds_line: uppx = self._ds_line.x_uppx() else: uppx = 0 should_line = self._in_ds if ( self._in_ds and uppx < x_gt ): should_line = False elif ( not self._in_ds and uppx >= x_gt ): should_line = True profiler('ds logic complete') if should_line: # update the line graphic # x, y = self._ds_line_xy = ohlc_flatten(ohlc_iv) x, y = self._ds_line_xy = ohlc_flatten(ohlc) x_iv, y_iv = self._ds_line_xy = ohlc_flatten(ohlc_iv) profiler('flattening bars to line') # TODO: we should be diffing the amount of new data which # needs to be downsampled. Ideally we actually are just # doing all the ds-ing in sibling actors so that the data # can just be read and rendered to graphics on events of our # choice. # diff = do_diff(ohlc, new_bit) curve = self._ds_line curve.update_from_array( x=x, y=y, x_iv=x_iv, y_iv=y_iv, view_range=None, # hack profiler=profiler, ) profiler('updated ds line') if not self._in_ds: # hide bars and show line self.hide() # XXX: is this actually any faster? # self._pi.removeItem(self) # TODO: a `.ui()` log level? log.info( f'downsampling to line graphic {self._name}' ) # self._pi.addItem(curve) curve.show() curve.update() self._in_ds = True # stop here since we don't need to update bars path any more # as we delegate to the downsample line with updates. profiler.finish() # print('terminating early') return else: # we should be in bars mode if self._in_ds: # flip back to bars graphics and hide the downsample line. log.info(f'showing bars graphic {self._name}') curve = self._ds_line curve.hide() # self._pi.removeItem(curve) # XXX: is this actually any faster? # self._pi.addItem(self) self.show() self._in_ds = False # generate in_view path self.path = gen_qpath( ohlc_iv, 0, self.w, # path=self.path, ) # TODO: to make the downsampling faster # - allow mapping only a range of lines thus only drawing as # many bars as exactly specified. # - move ohlc "flattening" to a shmarr # - maybe move all this embedded logic to a higher # level type? # if prepend_length: # # new history was added and we need to render a new path # prepend_bars = ohlc[:prepend_length] # if ds_prepend_length: # ds_prepend_bars = ohlc[:ds_prepend_length] # pre_x, pre_y = ohlc_flatten(ds_prepend_bars) # fx = np.concatenate((pre_x, fx)) # fy = np.concatenate((pre_y, fy)) # profiler('ds line prepend diff complete') # if append_length: # # generate new graphics to match provided array # # path appending logic: # # we need to get the previous "current bar(s)" for the time step # # and convert it to a sub-path to append to the historical set # # new_bars = ohlc[istop - 1:istop + append_length - 1] # append_bars = ohlc[-append_length - 1:-1] # # print(f'ohlc bars to append size: {append_bars.size}\n') # if ds_append_length: # ds_append_bars = ohlc[-ds_append_length - 1:-1] # post_x, post_y = ohlc_flatten(ds_append_bars) # print( # f'ds curve to append sizes: {(post_x.size, post_y.size)}' # ) # fx = np.concatenate((fx, post_x)) # fy = np.concatenate((fy, post_y)) # profiler('ds line append diff complete') profiler('array diffs complete') # does this work? last = ohlc[-1] # fy[-1] = last['close'] # # incremental update and cache line datums # self._ds_line_xy = fx, fy # maybe downsample to line # ds = self.maybe_downsample() # if ds: # # if we downsample to a line don't bother with # # any more path generation / updates # self._ds_xrange = first_index, last_index # profiler('downsampled to line') # return # print(in_view.size) # if self.path: # self.path = path # self.path.reserve(path.capacity()) # self.path.swap(path) # path updates # if prepend_length: # # XXX: SOMETHING IS MAYBE FISHY HERE what with the old_path # # y value not matching the first value from # # ohlc[prepend_length + 1] ??? # prepend_path = gen_qpath(prepend_bars, 0, self.w) # old_path = self.path # self.path = prepend_path # self.path.addPath(old_path) # profiler('path PREPEND') # if append_length: # append_path = gen_qpath(append_bars, 0, self.w) # self.path.moveTo( # float(istop - self.w), # float(append_bars[0]['open']) # ) # self.path.addPath(append_path) # profiler('path APPEND') # fp = self.fast_path # if fp is None: # self.fast_path = append_path # else: # fp.moveTo( # float(istop - self.w), float(new_bars[0]['open']) # ) # fp.addPath(append_path) # self.setCacheMode(QtWidgets.QGraphicsItem.NoCache) # flip_cache = True self._xrange = first_index, last_index # trigger redraw despite caching self.prepareGeometryChange() # generate new lines objects for updatable "current bar" self._last_bar_lines = bar_from_ohlc_row(last, self.w) # last bar update i, o, h, l, last, v = last[ ['index', 'open', 'high', 'low', 'close', 'volume'] ] # assert i == self.start_index - 1 # assert i == last_index body, larm, rarm = self._last_bar_lines # XXX: is there a faster way to modify this? rarm.setLine(rarm.x1(), last, rarm.x2(), last) # writer is responsible for changing open on "first" volume of bar larm.setLine(larm.x1(), o, larm.x2(), o) if l != h: # noqa if body is None: body = self._last_bar_lines[0] = QLineF(i, l, i, h) else: # update body body.setLine(i, l, i, h) # XXX: pretty sure this is causing an issue where the bar has # a large upward move right before the next sample and the body # is getting set to None since the next bar is flat but the shm # array index update wasn't read by the time this code runs. Iow # we're doing this removal of the body for a bar index that is # now out of date / from some previous sample. It's weird # though because i've seen it do this to bars i - 3 back? profiler('last bar set') self.update() profiler('.update()') if flip_cache: self.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache) profiler.finish()
def drawRadar(selfself, qp): #set frame: qp.setBrush(QBrush(QColor(0, 0, 0), Qt.SolidPattern)) qp.drawRect(20, 10, 700, 700) pen_bold = QPen(QColor(102, 204, 255), 0.8, Qt.SolidLine) pen = QPen(QColor(102, 204, 255), 0.8, Qt.DashDotLine) pen_hide = QPen(QColor(0, 0, 0), 1.5, Qt.SolidLine) #add circle: qp.setPen(pen) qp.drawEllipse(QPointF(370, 360), 347, 347) #add scales: for i in range(1, 360): if i % 30 == 0: pass else: if i % 10 == 0: scaleLine = QLineF() scaleLine.setP1(QPointF(370, 360)) scaleLine.setAngle(i) scaleLine.setLength(347) qp.setPen(pen_bold) qp.drawLine(scaleLine) hideLine = QLineF() hideLine.setP1(QPointF(370, 360)) hideLine.setAngle(i) hideLine.setLength(337) qp.setPen(pen_hide) qp.drawLine(hideLine) else: scaleLine = QLineF() scaleLine.setP1(QPointF(370, 360)) scaleLine.setAngle(i) scaleLine.setLength(347) qp.setPen(pen_bold) qp.drawLine(scaleLine) hideLine = QLineF() hideLine.setP1(QPointF(370, 360)) hideLine.setAngle(i) hideLine.setLength(342) qp.setPen(pen_hide) qp.drawLine(hideLine) #add other circles: qp.setPen(pen) qp.drawEllipse(QPointF(370, 360), 277, 277) qp.setPen(pen) qp.drawEllipse(QPointF(370, 360), 207, 207) qp.setPen(pen) qp.drawEllipse(QPointF(370, 360), 137, 137) qp.setPen(pen) qp.drawEllipse(QPointF(370, 360), 67, 67) #add lines: qp.setPen(pen_bold) qp.drawLine(20, 360, 720, 360) qp.setPen(pen_bold) qp.drawLine(370, 10, 370, 710) angleLine1 = QLineF() angleLine1.setP1(QPointF(370, 360)) angleLine1.setAngle(30) angleLine1.setLength(347) qp.setPen(pen) qp.drawLine(angleLine1) angleLine2 = QLineF() angleLine2.setP1(QPointF(370, 360)) angleLine2.setAngle(60) angleLine2.setLength(347) qp.setPen(pen) qp.drawLine(angleLine2) angleLine3 = QLineF() angleLine3.setP1(QPointF(370, 360)) angleLine3.setAngle(120) angleLine3.setLength(347) qp.setPen(pen) qp.drawLine(angleLine3) angleLine4 = QLineF() angleLine4.setP1(QPointF(370, 360)) angleLine4.setAngle(150) angleLine4.setLength(347) qp.setPen(pen) qp.drawLine(angleLine4) angleLine5 = QLineF() angleLine5.setP1(QPointF(370, 360)) angleLine5.setAngle(210) angleLine5.setLength(347) qp.setPen(pen) qp.drawLine(angleLine5) angleLine6 = QLineF() angleLine6.setP1(QPointF(370, 360)) angleLine6.setAngle(240) angleLine6.setLength(347) qp.setPen(pen) qp.drawLine(angleLine6) angleLine7 = QLineF() angleLine7.setP1(QPointF(370, 360)) angleLine7.setAngle(300) angleLine7.setLength(347) qp.setPen(pen) qp.drawLine(angleLine7) angleLine8 = QLineF() angleLine8.setP1(QPointF(370, 360)) angleLine8.setAngle(330) angleLine8.setLength(347) qp.setPen(pen) qp.drawLine(angleLine8)
def updatePosition(self): line = QLineF(QPointF(*self.end), QPointF(*self.begin)) self.setLine(line) self.shape()
def drawPath(self, items, useRows): """Draws one flight path Args items -- squares. useRows: True -- go by rows False -- go by cols """ if useRows: way = "row" sortFirst = "col" oldSide = "left" newSide = "right" color = QColor(255, 10, 10) else: way = "col" sortFirst = "row" oldSide = "top" newSide = "bottom" color = QColor(10, 255, 10) # Pen for main lines pen = QPen(color) pen.setWidth(2) pen.setCosmetic(True) # Pen for turning lines pen2 = QPen(color) pen2.setWidth(2) pen2.setStyle(Qt.DashLine) pen2.setDashOffset(2) pen2.setCosmetic(True) # Sort selected items items.sort(key=lambda item: item.getRowCol()[sortFirst]) items.sort(key=lambda item: item.getRowCol()[way]) def addItem(item): self.addItem(item) if useRows: self.rowLines.append(item) else: self.colLines.append(item) # Draw lines newPos = True # Shows if we're will be at new col/row at next iteration prevLine = None # Previously drawn line isLastPointReversed = False # Shows from which end draw turning line for i in range(len(items)): item = items[i] if newPos: side1 = item.getSides()[oldSide] newPos = False pos = item.getRowCol()[way] try: nextPos = items[i + 1].getRowCol()[way] except: nextPos = pos + 1 if pos != nextPos: side2 = item.getSides()[newSide] lineF = QLineF(side1, side2) line = QGraphicsLineItem(lineF) line.setPen(pen) addItem(line) newPos = True if prevLine != None: if isLastPointReversed: start = prevLine.p2() end = side2 else: start = prevLine.p1() end = side1 newLine = QGraphicsLineItem(QLineF(start, end)) newLine.setPen(pen2) addItem(newLine) isLastPointReversed = not isLastPointReversed prevLine = lineF
def showWedge(self, angle, color, extended=False, rev_gradient=False, outline_only=False): """Summary Args: angle (TYPE): Description color (TYPE): Description extended (bool, optional): Description rev_gradient (bool, optional): Description outline_only (bool, optional): Description """ # Hack to keep wedge in front # self.setRotation(self.pre_xover_item_group.rotation()) self._last_params = (angle, color, extended, rev_gradient, outline_only) radius = self._radius span = self.pre_xover_item_group.partCrossoverSpanAngle() / 2 radius_adjusted = radius + (_WEDGE_RECT_GAIN / 2) tip = QPointF(radius_adjusted, radius_adjusted) EXT = 1.35 if extended else 1.0 # print("wtf", tip, pos) base_p2 = QPointF(1, 1) line0 = QLineF(tip, QPointF(base_p2)) line1 = QLineF(tip, QPointF(base_p2)) line2 = QLineF(tip, QPointF(base_p2)) quad_scale = 1 + (.22*(span - 5) / 55) # lo+(hi-lo)*(val-min)/(max-min) line0.setLength(radius_adjusted * EXT*quad_scale) # for quadTo control point line1.setLength(radius_adjusted * EXT) line2.setLength(radius_adjusted * EXT) line0.setAngle(angle) line1.setAngle(angle - span) line2.setAngle(angle + span) path = QPainterPath() if outline_only: self.setPen(getPenObj(color, 0.5, alpha=128, capstyle=Qt.RoundCap)) path.moveTo(line1.p2()) path.quadTo(line0.p2(), line2.p2()) else: gradient = QRadialGradient(tip, radius_adjusted * EXT) color1 = getColorObj(color, alpha=80) color2 = getColorObj(color, alpha=0) if rev_gradient: color1, color2 = color2, color1 if extended: gradient.setColorAt(0, color1) gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT), color1) gradient.setColorAt(radius_adjusted / (radius_adjusted * EXT) + 0.01, color2) gradient.setColorAt(1, color2) else: gradient.setColorAt(0, getColorObj(color, alpha=50)) brush = QBrush(gradient) self.setBrush(brush) path.moveTo(line1.p1()) path.lineTo(line1.p2()) path.quadTo(line0.p2(), line2.p2()) path.lineTo(line2.p1()) self.setPath(path) self.show()
def __stepThree(self): """Step 3 -- Do basically everything. """ # Validate data def setError(e): """Displays string e. """ self.lblDataError.setText("<html><head/><body><div>" + self.lang.errData + e + "</div></body></html>") # Try to read data. We need to create fields, because this will be used later in other functions. self.xTL = self.__sfloat(self.xTopLeft.text()) self.xTR = self.__sfloat(self.xTopRight.text()) self.xBL = self.__sfloat(self.xBottomLeft.text()) self.xBR = self.__sfloat(self.xBottomRight.text()) self.yTL = self.__sfloat(self.yTopLeft.text()) self.yTR = self.__sfloat(self.yTopRight.text()) self.yBL = self.__sfloat(self.yBottomLeft.text()) self.yBR = self.__sfloat(self.yBottomRight.text()) self.xD = self.__sfloat(self.xDelimiter.text()) self.yD = self.__sfloat(self.yDelimiter.text()) # Convert delimiters to pixels. # Value of another coordinate doesn't matter. # If you'll draw a random line and draw crossing lines parallel to one of axes with same distance between these lines by another axis, you'll split your random line into equal pieces. # See for yourself: # Y # ^ ___\_____ # | ____\____ # | _____\___ # | \ # |-----------> X # You can try it on paper or prove this "theorem" doing some math. try: self.xDTop = self.width / abs(self.xTL - self.xTR) * self.xD self.xDBottom = self.width / abs(self.xBL - self.xBR) * self.xD self.yDLeft = self.height / abs(self.yTL - self.yBL) * self.yD self.yDRight = self.height / abs(self.yTR - self.yBR) * self.yD except ZeroDivisionError: setError(self.lang.errCorners) return # Now do the same stuff, but find how much pixels in one degree. # We won't find absolute value for subtraction because axes of image in geographic system may be not codirectional to axes of image in Qt system. self.topX = (self.xTR - self.xTL) / self.width self.bottomX = (self.xBR - self.xBL) / self.width self.leftY = (self.yTL - self.yBL) / self.height self.rightY = (self.yTR - self.yBR) / self.height # Sides of image in geographic system self.top = QLineF(self.xTL, self.yTL, self.xTR, self.yTR) self.bottom = QLineF(self.xBL, self.yBL, self.xBR, self.yBR) self.left = QLineF(self.xTL, self.yTL, self.xBL, self.yBL) self.right = QLineF(self.xTR, self.yTR, self.xBR, self.yBR) errors = "" if self.xDTop > self.width: errors += self.lang.errLongTop + "<br>" if self.xDBottom > self.width: errors += self.lang.errLongBottom + "<br>" if self.yDLeft > self.height: errors += self.lang.errLatLeft + "<br>" if self.yDRight > self.height: errors += self.lang.errLatRight + "<br>" if errors != "": setError(self.lang.errSides + "<br>" + errors) return # Check if given coordinates form 8-shaped figure if (self.xTL > self.xTR and self.xBL < self.xBR) or ( self.xTL < self.xTR and self.xBL > self.xBR) or ( self.yTL > self.yBL and self.yTR < self.yBR) or (self.yTL < self.yBL and self.yTR > self.yTL): choice = QMessageBox(QMessageBox.Warning, "AerialWare", self.lang.warningCoordinates, QMessageBox.Yes | QMessageBox.No).exec() if choice == QMessageBox.No: return # Draw grid # Set points for grid # Points will look like: # [point, point, ...], # [point, point, ...], ... pointRows = [] # Let x1, y1; x2, y2 be vertical line # and x3, y3; x4, y4 be horizontal line. # Thus, y1 and y2 should be always on top and bottom; # x3, x4 -- on left and right y1, y2, x3, x4 = 0, self.height, 0, self.width # So we have to change: # for vertical line: x1, x2 # for horizontal line: y3, y4 y3 = y4 = 0 # Initial values for horizontal line # Move horizontal line while y3 <= self.height + self.yDLeft / 2 or y4 <= self.height + self.yDRight / 2: x1 = x2 = 0 # Initial values for vertical line # Move vertical line points = [] while x1 <= self.width + self.xDTop / 2 or x2 <= self.width + self.xDBottom / 2: point = QPointF() QLineF.intersect(QLineF(x1, y1, x2, y2), QLineF(x3, y3, x4, y4), point) points.append(point) x1 += self.xDTop x2 += self.xDBottom if points != []: pointRows.append(points) y3 += self.yDLeft y4 += self.yDRight # If nothing has been added if points == []: setError(self.lang.errPoints) return # Get scene geometry to preserve scene expanding rect = self.scene.sceneRect() # And add bounds for the grid self.bounds = QGraphicsRectItem(rect) self.bounds.setFlag(self.bounds.ItemClipsChildrenToShape) self.scene.addItem(self.bounds) # Create polygons from points # We'll recheck previous item i = 1 # Rows while i < len(pointRows): j = 1 # Points while j < len(pointRows[i]): # Add points in following order: top left, top right, bottom right, bottom left points = [ pointRows[i - 1][j - 1], pointRows[i - 1][j], pointRows[i][j], pointRows[i][j - 1] ] # We're assigning self.bounds as parent implicitly, so we shouldn't add polygon to scene by ourselves. poly = _QCustomGraphicsPolygonItem(QPolygonF(points), self.bounds) poly.setRowCol(i - 1, j - 1) j += 1 i += 1 # Restore scene geometry self.scene.setSceneRect(rect) self.__turnPage() self.btnNext.disconnect() self.btnNext.clicked.connect(self.__stepFour)
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()
def updateStart(self, pointVCS): ''' !!! start point from FreehandTool is in View CS. ''' pointViewInt = QPoint(pointVCS.x(), pointVCS.y()) pointSceneFloat = self.scene().views()[0].mapToScene(pointViewInt) self.start = pointSceneFloat self.setLine(QLineF(self.start, self.end))
def setAxisIntersect(self, intersect): self._axisIntersect = intersect # print "SkeletonsLayer(axis=%d) is updating intersect=%d" % (self._axis, self._axisIntersect) nodes, eIntersected, ePlane = self._3d._skeletons.intersect(self._axis, self._axisIntersect) # update existing items toRemove = [] for node, item in self._node2view.items(): if node.pos[self._axis] != self._axisIntersect: self._scene.removeItem(item) toRemove.append(node) elif node.pointF(self._axis) != item.pos(): item.setPos(self._scene.data2scene.map(node.pointF(self._axis))) if node.isSelected() != item.isSelected(): item.setSelected(node.isSelected()) assert item.isSelected() == node.isSelected() i = 0 newSize = [0, 0] for j in range(3): if j == self._axis: continue newSize[i] = node.shape[j] i += 1 newRectF = QRectF(0, 0, *newSize) newRectF = self._scene.data2scene.mapRect(newRectF) item.setRect( QRectF( old_div(-newRectF.width(), 2.0), old_div(-newRectF.height(), 2.0), newRectF.width(), newRectF.height(), ) ) for r in toRemove: del self._node2view[r] # add new views for nodes for n in nodes: if n in self._node2view: continue pos2D = list(n.pos) del pos2D[self._axis] shape2D = n.shape2D(self._axis) itm = QGraphicsSkeletonNode(shape2D, skeletons=self._3d._skeletons, node=n) itm.setPos(self._scene.data2scene.map(QPointF(*pos2D))) itm.setSelected(n.isSelected()) self._scene.addItem(itm) self._node2view[n] = itm for itm in list(self._edge2view.values()): self._scene.removeItem(itm) self._edge2view = dict() for e in ePlane: l = QLineF(e[0].pointF(), e[1].pointF()) c1 = e[0].color() c2 = e[1].color() assert sys.version_info.major == 2, ( "Alert! This function has not been " "tested under python 3. Please remove this assertion and be wary of any " "strnage behavior you encounter" ) mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2) line = QGraphicsLineItem(self._scene.data2scene.map(l)) line.setPen(QPen(mixColor)) self._scene.addItem(line) self._edge2view[e] = line for theEdge, e in eIntersected: c1 = theEdge[0].color() c2 = theEdge[1].color() assert sys.version_info.major == 2, ( "Alert! This function has not been " "tested under python 3. Please remove this assertion and be wary of any " "strnage behavior you encounter" ) mixColor = QColor((c1.red() + c2.red()) // 2, (c1.green() + c2.green()) // 2, (c1.blue() + c2.blue()) // 2) nodeSize = 6 p = QGraphicsRectItem(old_div(-nodeSize, 2), old_div(-nodeSize, 2), nodeSize, nodeSize) pos2D = list(e) del pos2D[self._axis] p.setPos(self._scene.data2scene.map(QPointF(*pos2D))) p.setPen(QPen(mixColor)) self._scene.addItem(p) self._edge2view[e] = p
def draw_roi(self, roi): lines = roi['lines'] for x1, y1, x2, y2, in lines: line = QLineF(x1, y1, x2, y2) self.transect_lines.append(line) self.addLine(line, self.pen)