def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget=None): if not self.source or not self.dest: return line = QLineF(self.source_point, self.dest_point) if line.length() == 0.0: return color = self.get_color() width = SupremeSettings()['edge_width'] if option.state & QStyle.State_Sunken: color, width = Qt.red, 2 painter.setPen(QPen(Qt.black, 2, Qt.DashLine)) painter.drawPolygon(self.getSelectionPolygon()) elif option.state & QStyle.State_MouseOver: color, width = Qt.blue, 2 painter.setPen( QPen(color, width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line) angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = math.pi * 2 - angle if self.arrow_size > 0: dest_arrow_p1 = self.dest_point + QPointF( math.sin(angle - math.pi / 3) * self.arrow_size, math.cos(angle - math.pi / 3) * self.arrow_size) dest_arrow_p2 = self.dest_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([line.p2(), dest_arrow_p1, dest_arrow_p2])) self.draw_animated_objects()
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 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 paint(self, painter, option, widget): color = Qt.red if self.isSelected() else Qt.black painter.setPen(QPen(color, 2, Qt.SolidLine)) path = QPainterPath(self.startPoint) # start path # iterating over all points of line for i in range(len(self.points) - 1): x1, y1 = self.points[i].x(), self.points[i].y() x2, y2 = self.points[i + 1].x(), self.points[i + 1].y() for point in sorted(self.commonPathsCenters, key=lambda x: x.x() + x.y(), reverse=x2 < x1 or y2 < y1): x, y = point.x(), point.y() if x == x1 == x2: # vertical if min(y1, y2) + 8 <= y < max(y1, y2) - 8: if y2 > y1: path.lineTo(point - QPointF(0, 8)) path.arcTo(QRectF(x - 8, y - 8, 16, 16), 90, -180) path.moveTo(point + QPointF(0, 8)) else: path.lineTo(point + QPointF(0, 8)) path.arcTo(QRectF(x - 8, y - 8, 16, 16), -90, 180) path.moveTo(point - QPointF(0, 8)) elif y == y1 == y2: # horizontal if min(x1, x2) + 8 <= x < max(x1, x2) - 8: if x2 > x1: path.lineTo(point - QPointF(8, 0)) path.arcTo(QRectF(x - 8, y - 8, 16, 16), 180, 180) path.moveTo(point + QPointF(8, 0)) else: path.lineTo(point + QPointF(8, 0)) path.arcTo(QRectF(x - 8, y - 8, 16, 16), 0, -180) path.lineTo(point - QPointF(8, 0)) path.lineTo(self.points[i + 1]) # draw arrow in last segment if i == len(self.points) - 2: arrow_size = 20.0 line = QLineF(self.points[i], self.points[i + 1]) if line.length() < 20: continue angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = (math.pi * 2) - angle arrow_p1 = line.p2() - QPointF(math.sin(angle + math.pi / 2.5) * arrow_size, math.cos(angle + math.pi / 2.5) * arrow_size) arrow_p2 = line.p2() - QPointF(math.sin(angle + math.pi - math.pi / 2.5) * arrow_size, math.cos(angle + math.pi - math.pi / 2.5) * arrow_size) arrowHead = QPolygonF() arrowHead.append(line.p2()) arrowHead.append(arrow_p1) arrowHead.append(arrow_p2) painter.save() painter.setBrush(Qt.black) painter.drawPolygon(arrowHead) painter.restore() painter.drawPath(path) # draw final path
def gen_endpoints(origin_sides: dict, destination_sides: dict) -> QLineF: """ This method finds the shortest path between two rectangles. Parameters ---------- origin_sides : dict The dictionary {side_label: side_size} of the starting rect. destination_sides : dict The dictionary {side_label: side_size} of the ending rect. Returns ---------- QLineF The shortest line. """ # Init the line with the maximum possible value shortest_line = QLineF(-sys.maxsize / 2, -sys.maxsize / 2, sys.maxsize / 2, sys.maxsize / 2) for o_side, origin_side in origin_sides.items(): o_mid_x, o_mid_y = u.get_midpoint(o_side, origin_side) for d_side, destination_side in destination_sides.items(): d_mid_x, d_mid_y = u.get_midpoint(d_side, destination_side) # Update line line = QLineF(o_mid_x, o_mid_y, d_mid_x, d_mid_y) if line.length() < shortest_line.length(): shortest_line = line return shortest_line
def area(self) -> float: d1 = QLineF(self.points[0], self.points[2]) d2 = QLineF(self.points[1], self.points[3]) angle = d1.angleTo(d2) angle = math.radians(angle) d1 = d1.length() d2 = d2.length() return abs(d1 * d2 * math.sin(angle))
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 paint(self, painter, index): widget = self.parent() if index != widget.activeIndex(): return scale = widget.inverseScale() # metrics if self._rulerObject is not None: line, a = self._rulerObject origin = line.p1() cursor = line.p2() size = 8 * scale halfSize = 4 * scale color = QColor(255, 85, 127, 170) # line painter.save() painter.setPen(color) drawing.drawLine(painter, origin.x(), origin.y(), cursor.x(), cursor.y(), scale) # ellipses ellipses = [ (origin.x(), origin.y()), (cursor.x(), cursor.y()), ] path = QPainterPath() path.setFillRule(Qt.WindingFill) for x, y in itertools.chain(self._rulerPts.values(), ellipses): x -= halfSize y -= halfSize path.addEllipse(x, y, size, size) painter.fillPath(path, color) painter.restore() # text line = QLineF(line) xAlign = yAlign = "center" ellipses.pop(0) rp = self._rulerPts # XXX: sort shouldn't be performed in paintEvent for pt in itertools.chain((rp[k] for k in sorted(rp)), ellipses): p = QPointF(*pt) line.setP2(p) if line.length(): d = str(round(line.length(), 1)) pos = (line.p1() + line.p2()) / 2 drawing.drawTextAtPoint(painter, d, pos.x(), pos.y(), scale, xAlign, yAlign) line.setP1(p) xAlign, yAlign = "left", "top" dx = cursor.x() - origin.x() px = size if dx < 0: xAlign = "right" px = -px drawing.drawTextAtPoint(painter, a, cursor.x() + px, cursor.y() + size, scale, xAlign, yAlign)
def moveUIPoint(contour, point, delta): if point.segmentType is None: # point is an offCurve. Get its sibling onCurve and the other # offCurve. onCurve, otherPoint = _getOffCurveSiblingPoints(contour, point) # if the onCurve is selected, the offCurve will move along with it if onCurve.selected: return point.move(delta) if not onCurve.smooth: contour.dirty = True return # if the onCurve is smooth, we need to either... if otherPoint.segmentType is None and not otherPoint.selected: # keep the other offCurve inline line = QLineF(point.x, point.y, onCurve.x, onCurve.y) otherLine = QLineF( onCurve.x, onCurve.y, otherPoint.x, otherPoint.y) line.setLength(line.length() + otherLine.length()) otherPoint.x = line.x2() otherPoint.y = line.y2() else: # keep point in tangency with onCurve -> otherPoint segment, # ie. do an orthogonal projection line = QLineF(otherPoint.x, otherPoint.y, onCurve.x, onCurve.y) n = line.normalVector() n.translate(QPointF(point.x, point.y) - n.p1()) targetPoint = QPointF() n.intersect(line, targetPoint) # check that targetPoint is beyond its neighbor onCurve # we do this by calculating position of the offCurve and second # onCurve relative to the first onCurve. If there is no symmetry # in at least one of the axis, then we need to clamp onCurvePoint = line.p2() onDistance = line.p1() - onCurvePoint newDistance = targetPoint - onCurvePoint if (onDistance.x() >= 0) != (newDistance.x() <= 0) or \ (onDistance.y() >= 0) != (newDistance.y() <= 0): targetPoint = onCurvePoint # ok, now set pos point.x, point.y = targetPoint.x(), targetPoint.y() else: # point is an onCurve. Move its offCurves along with it. index = contour.index(point) point.move(delta) for d in (-1, 1): # edge-case: contour open, trailing offCurve and moving first # onCurve in contour if contour.open and index == 0 and d == -1: continue pt = contour.getPoint(index + d) if pt.segmentType is None: pt.move(delta) contour.dirty = True
def moveUIPoint(contour, point, delta): if point.segmentType is None: # point is an offCurve. Get its sibling onCurve and the other # offCurve. onCurve, otherPoint = _getOffCurveSiblingPoints(contour, point) # if the onCurve is selected, the offCurve will move along with it if onCurve.selected: return point.move(delta) if not onCurve.smooth: contour.dirty = True return # if the onCurve is smooth, we need to either... if otherPoint.segmentType is None and not otherPoint.selected: # keep the other offCurve inline line = QLineF(point.x, point.y, onCurve.x, onCurve.y) otherLine = QLineF(onCurve.x, onCurve.y, otherPoint.x, otherPoint.y) line.setLength(line.length() + otherLine.length()) otherPoint.x = line.x2() otherPoint.y = line.y2() else: # keep point in tangency with onCurve -> otherPoint segment, # ie. do an orthogonal projection line = QLineF(otherPoint.x, otherPoint.y, onCurve.x, onCurve.y) n = line.normalVector() n.translate(QPointF(point.x, point.y) - n.p1()) targetPoint = QPointF() n.intersect(line, targetPoint) # check that targetPoint is beyond its neighbor onCurve # we do this by calculating position of the offCurve and second # onCurve relative to the first onCurve. If there is no symmetry # in at least one of the axis, then we need to clamp onCurvePoint = line.p2() onDistance = line.p1() - onCurvePoint newDistance = targetPoint - onCurvePoint if (onDistance.x() >= 0) != (newDistance.x() <= 0) or \ (onDistance.y() >= 0) != (newDistance.y() <= 0): targetPoint = onCurvePoint # ok, now set pos point.x, point.y = targetPoint.x(), targetPoint.y() else: # point is an onCurve. Move its offCurves along with it. index = contour.index(point) point.move(delta) for d in (-1, 1): # edge-case: contour open, trailing offCurve and moving first # onCurve in contour if contour.open and index == 0 and d == -1: continue pt = contour.getPoint(index + d) if pt.segmentType is None: pt.move(delta) contour.dirty = True
def 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 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): """ 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): """ 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]))
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 setWedgeGizmo(self, neighbor_virtual_helix: int, neighbor_virtual_helix_item: SliceVirtualHelixItemT): """Adds a :class:`WedgeGizmo` to oriented toward the specified neighbor vhi. Called by :meth:`SliceNucleicAcidPartItem._refreshVirtualHelixItemGizmos`, before :meth:`setWedgeGizmo` and :meth:`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 pos = self.scenePos() line = QLineF(pos, nvhi.scenePos()) line.translate(_RADIUS, _RADIUS) if line.length() > (_RADIUS * 1.99): color = '#5a8bff' else: color = '#cc0000' 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 adjust(self): if not self.source or not self.dest: return line = QLineF( self.mapFromItem(self.source, self.source.getDrawSize() * -0.5, self.source.getDrawSize() * -0.5), self.mapFromItem(self.dest, self.dest.getDrawSize() * -0.5, self.dest.getDrawSize() * -0.5)) length = line.length() self.prepareGeometryChange() if length > self.source.getDrawSize(): edgeOffset = QPointF( (line.dx() * self.source.getDrawSize() / 2) / length, (line.dy() * self.source.getDrawSize() / 2) / length) self.sourcePoint = line.p1() + edgeOffset self.destPoint = line.p2() - edgeOffset else: self.sourcePoint = line.p1() self.destPoint = line.p1()
def setWedgeGizmo(self, neighbor_virtual_helix, neighbor_virtual_helix_item): """Adds a WedgeGizmo to oriented toward the specified neighbor vhi. Called by NucleicAcidPartItem _refreshVirtualHelixItemGizmos, in between with beginAddWedgeGizmos and endAddWedgeGizmos. Args: neighbor_virtual_helix (int): the id_num of neighboring virtual helix neighbor_virtual_helix_item (cadnano.views.sliceview.virtualhelixitem.VirtualHelixItem): the neighboring virtual helix item """ wg_dict = self.wedge_gizmos nvhi = neighbor_virtual_helix_item pos = self.scenePos() line = QLineF(pos, nvhi.scenePos()) line.translate(_RADIUS, _RADIUS) if line.length() > (_RADIUS * 1.99): color = '#5a8bff' else: color = '#cc0000' 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 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)
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 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 joystick_direction(self): if not self.grab_center: return 0 norm_vector = QLineF(self._center(), self.moving_offset) current_distance = norm_vector.length() angle = norm_vector.angle() distance = min(current_distance / self.__max_distance, 1.0) if current_distance > 30: if 22.5 <= angle < 67.5: self.calc_pwm(1, 1) return (Direction.RightUp, distance) elif 67.5 <= angle < 112.5: self.calc_pwm(0, 1) return (Direction.Up, distance) elif 112.5 <= angle < 157.5: self.calc_pwm(-1, 1) return (Direction.LeftUp, distance) elif 157.5 <= angle < 202.5: self.calc_pwm(-1, 0) return (Direction.Left, distance) elif 202.5 <= angle < 247.5: self.calc_pwm(-1, -1) return (Direction.LeftDown, distance) elif 247.5 <= angle < 292.5: self.calc_pwm(0, -1) return (Direction.Down, distance) elif 292.5 <= angle < 337.5: self.calc_pwm(1, -1) return (Direction.RightDown, distance) else: self.calc_pwm(1, 0) return (Direction.Right, distance) else: return (Direction.Neutral, 0)
def paint(self, painter, option, widget): if self._source is None or self._dest is None: return # Get level of detail lod = option.levelOfDetailFromTransform(painter.worldTransform()) if lod < 0.1: return scene = self.scene() if scene is None: return line = QLineF(self.source_point, self.dest_point) if self._source != self._dest and qFuzzyCompare(line.length(), 0.): return # If selected, change color to red if option.state & QStyle.State_Selected: pen = scene.networkStyle().edgePen(selected=True) pen.setWidthF(self.pen().widthF()) painter.setPen(pen) else: painter.setPen(self.pen()) painter.drawPath(self.path())
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 ulti(self): scene_items = self.scene().items() for i in scene_items: if (isinstance(i, Minion) or isinstance(i, BigMinion)) and i.team != self.team: this_line = QLineF(self.pos(), i.pos()) if this_line.length() <= 150: this_line.setLength(150) i.setPos(i.x() + this_line.dx(), i.y() + this_line.dy()) elif (i.__class__.__name__ == 'Tower' or i.__class__.__name__ == 'Nexus' or i.__class__.__name__ == 'Inhibitor') and i.team != self.team: this_line = QLineF(self.pos(), i.pos()) if this_line.length() <= 150: i.decrease_health(100) self.ulti_available = False self.ulti_cooldown_timer.start(self.cooldown)
def should_be_moving(self): ln = QLineF(self.pos(), self.destination) CLOSE_DIST = 30 if ln.length() > CLOSE_DIST: return True else: return False
def distance_to(self, item): distance = QLineF(QPointF(self.pos().x() + 25, self.pos().y() + 25), item.pos()) line = QGraphicsLineItem(distance) line.setPen(QPen(Qt.red)) # self.scene().addItem(line) return distance.length()
def scaleLineFinishedHandler(mode, line: QLineF): global finished if (finished): return if not mode == 'scaleLine': return # show dialog for input the length of line # lineLength, ok = QInputDialog.getDouble(self, 'Input the length of line', 'Length of line(mm)') lineLength, ok = QInputDialog.getDouble( self, 'Input the length of line', 'Length of line(mm)') if not ok: return if not (lineLength and line.length()): QMessageBox.warning('Length of line must be positive number.') return self.realScale = lineLength / line.length() finished = True print('Real Scale: %s' % self.realScale)
def joystickDirection(self): if not self.grabCenter: return 0 normVector = QLineF(self._center(), self.movingOffset) currentDistance = normVector.length() angle = int(normVector.angle()) distance = int(currentDistance / self.__maxDistance * 0) setPID(angle, distance) return (Direction.Right, distance)
def updatePosition(self, force=False): #if self.toNode() is None and self.fromNode() is None: #if not force: #self.updateArrowHead() #self.updateTextPosition() #return if self.dest() and self.source(): self._updatingPos = True #self.saveTextPosition() self.prepareGeometryChange() if len(self._points) == 2: a = self.source().closestBoundaryPosToItem(self.dest()) b = self.dest().closestBoundaryPosToItem(self.source()) a = self.mapFromItem(self.source(), a) b = self.mapFromItem(self.dest(), b) else: a = self.source().closestBoundaryPosToItem(self._points[1]) b = self.dest().closestBoundaryPosToItem(self._points[-2]) a = self.mapFromItem(self.source(), a) b = self.mapFromItem(self.dest(), b) line = QLineF(a, b) length = line.length() # BUGFIX if abs(length) == 0: line = QLineF(a, QPointF(a.x() + 1, a.y())) length = 1 dx = line.dx() dx /= length if dx > 1: dx = 1 elif dx < -1: dx = -1 angle = acos(dx) size = self.arrowHeadSize() head = self._arrowHead if line.dy() >= 0: angle = pi * 2 - angle p2 = line.p2() u = p2 + QPointF( sin(angle + pi + pi / 3) * size, cos(angle + pi + pi / 3) * size) v = p2 + QPointF( sin(angle - pi / 3) * size, cos(angle - pi / 3) * size) if self.dest() != self.toPoint(): self.toPoint().setPos(line.p2()) if self.source() != self.fromPoint(): self.fromPoint().setPos(line.p1()) self.updateArrowHead() #self.updateTextPosition() self._updatingPos = False else: self.updateArrowHead() self.updateTextPosition()
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() self.sourcePoint = line.p1() self.destPoint = line.p2()
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() min_len = self._source.radius() + self._dest.radius( ) + self._source.pen().widthF() + self._dest.pen().widthF() if length > min_len: offset = QPointF( (line.dx() * (self._source.radius() + self._source.pen().widthF() + 1)) / length, (line.dy() * (self._source.radius() + self._source.pen().widthF() + 1)) / length) self.source_point = line.p1() + offset offset = QPointF( (line.dx() * (self._dest.radius() + self._dest.pen().widthF() + 1)) / length, (line.dy() * (self._dest.radius() + self._dest.pen().widthF() + 1)) / length) self.dest_point = line.p2() - offset else: self.source_point = self.dest_point = line.p1() path = QPainterPath() if self.sourceNode() == self.destNode(): # Draw self-loops self.__is_self_loop = True radius = self._source.radius() path.moveTo( self.source_point.x() - radius - 2 * self._source.pen().widthF(), self.source_point.y()) path.cubicTo( QPointF(self.source_point.x() - 4 * radius, self.source_point.y()), QPointF(self.source_point.x(), self.source_point.y() - 4 * radius), QPointF( self.dest_point.x(), self.dest_point.y() - radius - 2 * self._source.pen().widthF())) else: self.__is_self_loop = False path.moveTo(self.source_point) path.lineTo(self.dest_point) self.setPath(path)
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 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) conditionPoint = self.sourcePoint + QPointF( math.sin(angle + Edge.Pi / 3) * self.arrowSize * 2, math.cos(angle + Edge.Pi / 3) * self.arrowSize * 2) textToPrint = self.condition for path in self.source.edges(): if path.destNode( ).name == self.dest.name and path.condition != self.condition: textToPrint += ", %c" % (path.condition) if path.condition > self.condition: return painter.setBrush(Qt.black) painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2])) painter.drawText(conditionPoint, textToPrint)
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.green, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(line)
def move_forward(self): distance_line = QLineF(self.pos(), self.currentDestination) if (distance_line.length() < 5): self.point_index += 1 if (self.point_index >= len(self.directionPoints)): return self.currentDestination = self.directionPoints[self.point_index] self.rotateToPoint(self.currentDestination) theta = self.rotation() dy = Alien.STEP_SIZE * np.sin(np.radians(theta)) dx = Alien.STEP_SIZE * np.cos(np.radians(theta)) self.setPos(self.x() + dx, self.y() + dy)
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 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 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)
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 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()))