def drawLink(self, name: str, points: Tuple[int]): """Draw linkage function. The link color will be the default color. """ color = colorQt('Blue') pen = QPen(color) pen.setWidth(self.linkWidth) self.painter.setPen(pen) brush = QColor(226, 219, 190) brush.setAlphaF(0.70) self.painter.setBrush(brush) qpoints = tuple( QPointF(self.Point[i][0] * self.zoom, self.Point[i][1] * -self.zoom) for i in points if self.Point[i] and not isnan(self.Point[i][0])) if len(qpoints) == len(points): self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if self.showPointMark and name != 'ground' and qpoints: pen.setColor(Qt.darkGray) self.painter.setPen(pen) self.painter.setFont(QFont('Arial', self.fontSize)) text = "[{}]".format(name) cenX = sum(self.Point[i][0] for i in points if self.Point[i]) cenY = sum(self.Point[i][1] for i in points if self.Point[i]) cenX *= self.zoom / len(points) cenY *= -self.zoom / len(points) self.painter.drawText(QPointF(cenX, cenY), text)
def addChart(self, title, data, fftchose): axisX = QValueAxis() axisY = QValueAxis() chart = DataChart(title, axisX, axisY) chart.setTheme(QChart.ChartThemeBlueNcs) ffttmp = [] for col in data: line = QSplineSeries() line.setName(col[0]) for row, value in enumerate(col[1:]): if fftchose: ffttmp.append(value) else: line.append(QPointF(self.sampletime * row, value)) if fftchose: sp = np.fft.fft(ffttmp) Ayf = np.abs(sp) freq = np.fft.fftfreq(len(ffttmp), d=self.sampletime) for i in range(len(Ayf) - 1): line.append(QPointF(freq[i], Ayf[i])) chart.addSeries(line) line.attachAxis(axisX) line.attachAxis(axisY) self.view = QView() self.view.combinedata(data) self.view.addQchart(chart) self.tabWidget.addTab(self.view, title) self.tabcount.append([title, self.view])
def __drawSlvsRanges(self): """Draw solving range.""" pen = QPen() self.painter.setFont(QFont("Arial", self.fontSize + 5)) pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(colorNum(i + 1)) range_color.setAlpha(30) self.painter.setBrush(range_color) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) cx = rect.x() * self.zoom cy = rect.y() * -self.zoom if rect.width(): self.painter.drawRect( QRectF(cx, cy, rect.width() * self.zoom, rect.height() * self.zoom)) else: self.painter.drawEllipse(QPointF(cx, cy), 3, 3) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) self.painter.drawText(QPointF(cx + 6, cy - 6), tag) self.painter.setBrush(Qt.NoBrush)
def __draw_point(self, i: int, vpoint: VPoint): """Draw a point.""" if vpoint.type in {VJoint.P, VJoint.RP}: pen = QPen(QColor(*vpoint.color)) pen.setWidth(2) # Draw slot point and pin point. for j, (cx, cy) in enumerate(vpoint.c): if not vpoint.links: grounded = False else: grounded = vpoint.links[j] == 'ground' # Slot point. if j == 0 or vpoint.type == VJoint.P: pen.setColor(Qt.black if self.monochrome else QColor( *vpoint.color)) self.painter.setPen(pen) cp = QPointF(cx, -cy) * self.zoom jr = self.joint_size * (2 if j == 0 else 1) rp = QPointF(jr, -jr) self.painter.drawRect(QRectF(cp + rp, cp - rp)) if self.show_point_mark: pen.setColor(Qt.darkGray) self.painter.setPen(pen) text = f"[Point{i}]" if self.show_dimension: text += f":({cx:.02f}, {cy:.02f})" self.painter.drawText(cp + rp, text) else: self.draw_point(i, cx, cy, grounded, vpoint.color) # Slider line pen.setColor(QColor(*vpoint.color).darker()) self.painter.setPen(pen) qline_m = QLineF( QPointF(vpoint.c[1][0], -vpoint.c[1][1]) * self.zoom, QPointF(vpoint.c[0][0], -vpoint.c[0][1]) * self.zoom) nv = qline_m.normalVector() nv.setLength(self.joint_size) nv.setPoints(nv.p2(), nv.p1()) qline_1 = nv.normalVector() qline_1.setLength(qline_m.length()) self.painter.drawLine(qline_1) nv.setLength(nv.length() * 2) nv.setPoints(nv.p2(), nv.p1()) qline_2 = nv.normalVector() qline_2.setLength(qline_m.length()) qline_2.setAngle(qline_2.angle() + 180) self.painter.drawLine(qline_2) else: self.draw_point(i, vpoint.cx, vpoint.cy, vpoint.grounded(), vpoint.color) # For selects function. if self.select_mode == SelectMode.Joint and (i in self.selections): pen = QPen(QColor(161, 16, 239)) pen.setWidth(3) self.painter.setPen(pen) self.painter.drawRect(vpoint.cx * self.zoom - 12, vpoint.cy * -self.zoom - 12, 24, 24)
def __draw_link(self, name: str, points: List[int]): """Draw link function. The link color will be the default color. """ color = color_qt('Blue') pen = QPen(color) pen.setWidth(self.link_width) self.painter.setPen(pen) brush = QColor(226, 219, 190) brush.setAlphaF(0.70) self.painter.setBrush(brush) qpoints = tuple( QPointF(self.pos[i][0], -self.pos[i][1]) * self.zoom for i in points if self.pos[i] and (not isnan(self.pos[i][0])) ) if len(qpoints) == len(points): self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if self.show_point_mark and (name != 'ground') and qpoints: pen.setColor(Qt.darkGray) self.painter.setPen(pen) self.painter.setFont(QFont('Arial', self.font_size)) text = f"[{name}]" cen_x = sum(self.pos[i][0] for i in points if self.pos[i]) cen_y = sum(self.pos[i][1] for i in points if self.pos[i]) self.painter.drawText(QPointF(cen_x, -cen_y) * self.zoom / len(points), text)
def __drawPoint(self, i: int, vpoint: VPoint): """Draw a point.""" if vpoint.type == 1 or vpoint.type == 2: #Draw slider silder_points = vpoint.c for j, (cx, cy) in enumerate(silder_points): if vpoint.type == 1: if j == 0: self._BaseCanvas__drawPoint( i, cx, cy, vpoint.links[j] == 'ground', vpoint.color) else: pen = QPen(vpoint.color) pen.setWidth(2) self.painter.setPen(pen) r = 5 self.painter.drawRect( QRectF( QPointF(cx * self.zoom + r, cy * -self.zoom + r), QPointF(cx * self.zoom - r, cy * -self.zoom - r))) elif vpoint.type == 2: if j == 0: self._BaseCanvas__drawPoint( i, cx, cy, vpoint.links[j] == 'ground', vpoint.color) else: #Turn off point mark. showPointMark = self.showPointMark self.showPointMark = False self._BaseCanvas__drawPoint( i, cx, cy, vpoint.links[j] == 'ground', vpoint.color) self.showPointMark = showPointMark pen = QPen(vpoint.color.darker()) pen.setWidth(2) self.painter.setPen(pen) x_all = tuple(cx for cx, cy in silder_points) if x_all: p_left = silder_points[x_all.index(min(x_all))] p_right = silder_points[x_all.index(max(x_all))] if p_left == p_right: y_all = tuple(cy for cx, cy in silder_points) p_left = silder_points[y_all.index(min(y_all))] p_right = silder_points[y_all.index(max(y_all))] self.painter.drawLine( QPointF(p_left[0] * self.zoom, p_left[1] * -self.zoom), QPointF(p_right[0] * self.zoom, p_right[1] * -self.zoom)) else: self._BaseCanvas__drawPoint(i, vpoint.cx, vpoint.cy, vpoint.grounded(), vpoint.color) #For selects function. if i in self.pointsSelection: pen = QPen(QColor(161, 16, 239)) pen.setWidth(3) self.painter.setPen(pen) self.painter.drawRect(vpoint.cx * self.zoom - 12, vpoint.cy * -self.zoom - 12, 24, 24)
def graph(G: Graph, width: int, engine: [str, Dict[int, Tuple[float, float]]], node_mode: bool = False, except_node: int = None) -> QIcon: """Draw a linkage graph.""" try: pos = engine_picker(G, engine, node_mode) except EngineError as e: raise e width_ = -inf for x, y in pos.values(): if abs(x) > width_: width_ = x if abs(y) > width_: width_ = y width_ *= 2 * 1.2 image = QImage(QSize(width_, width_), QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) painter = QPainter(image) painter.translate(image.width() / 2, image.height() / 2) pen = QPen() r = width_ / 50 pen.setWidth(r) painter.setPen(pen) if node_mode: for l1, l2 in G.edges: painter.drawLine(QPointF(pos[l1][0], -pos[l1][1]), QPointF(pos[l2][0], -pos[l2][1])) else: painter.setBrush(QBrush(QColor(226, 219, 190, 150))) for link in G.nodes: if link == except_node: continue #Distance sorted function from canvas painter.drawPolygon(*convex_hull([(pos[n][0], -pos[n][1]) for n, edge in edges_view(G) if link in edge])) for k, (x, y) in pos.items(): if node_mode: color = colorNum(len(list(G.neighbors(k))) - 1) else: if except_node in tuple(G.edges)[k]: color = colorQt('Green') else: color = colorQt('Blue') pen.setColor(color) painter.setPen(pen) painter.setBrush(QBrush(color)) painter.drawEllipse(QPointF(x, -y), r, r) painter.end() icon = QIcon(QPixmap.fromImage(image).scaledToWidth(width)) return icon
def drawArrow(self, x1: float, y1: float, x2: float, y2: float): """Front point -> Back point""" a = atan2(y2 - y1, x2 - x1) x1 = (x1 + x2) / 2 - 7.5*cos(a) y1 = (y1 + y2) / 2 - 7.5*sin(a) self.painter.drawLine( QPointF(x1, y1), QPointF(x1 + 15*cos(a + radians(20)), y1 + 15*sin(a + radians(20))) ) self.painter.drawLine( QPointF(x1, y1), QPointF(x1 + 15*cos(a - radians(20)), y1 + 15*sin(a - radians(20))) )
def paintEvent(self, event): """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ self.painter = QPainter() self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) self.painter.translate(self.ox, self.oy) #Draw origin lines. pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) x_l = -self.ox x_r = self.width()-self.ox self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0)) y_t = self.height()-self.oy y_b = -self.oy self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t)) #Draw tick. Indexing = lambda v: int(v/self.zoom - (v/self.zoom)%5) for x in range(Indexing(x_l), Indexing(x_r)+1, 5): self.painter.drawLine( QPointF(x*self.zoom, 0), QPointF(x*self.zoom, -10 if x%10==0 else -5) ) for y in range(Indexing(y_b), Indexing(y_t)+1, 5): self.painter.drawLine( QPointF(0, y*self.zoom), QPointF(10 if y%10==0 else 5, y*self.zoom) ) """Please to call the "end" method when ending paint event.
def drawLimit(self, sq_w: int): """Center square.""" limit = sq_w / 2 * self.zoom self.painter.drawLine(QPointF(-limit, limit), QPointF(limit, limit)) self.painter.drawLine(QPointF(-limit, limit), QPointF(-limit, -limit)) self.painter.drawLine(QPointF(-limit, -limit), QPointF(limit, -limit)) self.painter.drawLine(QPointF(limit, -limit), QPointF(limit, limit))
def __init__(self, parent: QWidget): """Set the parameters for drawing.""" super(BaseCanvas, self).__init__(parent) self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.setFocusPolicy(Qt.StrongFocus) self.painter = QPainter() # Origin coordinate. self.ox = self.width() / 2 self.oy = self.height() / 2 # Canvas zoom rate. self.rate = 2. self.zoom = 2. * self.rate # Joint size. self.joint_size = 3 # Canvas line width. self.link_width = 3 self.path_width = 3 # Font size. self.font_size = 15 # Show point mark or dimension. self.show_point_mark = True self.show_dimension = True # Path track. self.Path = _Path() # Path solving. self.target_path = {} self.show_target_path = False # Background self.background = QImage() self.background_opacity = 1. self.background_scale = 1 self.background_offset = QPointF(0, 0)
def on_save_atlas_clicked(self): """Save function as same as type synthesis widget.""" count = self.collection_list.count() if not count: return lateral, ok = QInputDialog.getInt(self, "Atlas", "The number of lateral:", 5, 1, 10) if not ok: return fileName = self.outputTo("Atlas image", Qt_images) if not fileName: return icon_size = self.collection_list.iconSize() width = icon_size.width() image_main = QImage( QSize(lateral * width if count > lateral else count * width, ((count // lateral) + bool(count % lateral)) * width), self.collection_list.item(0).icon().pixmap( icon_size).toImage().format()) image_main.fill(QColor(Qt.white).rgb()) painter = QPainter(image_main) for row in range(count): image = self.collection_list.item(row).icon().pixmap( icon_size).toImage() painter.drawImage( QPointF(row % lateral * width, row // lateral * width), image) painter.end() pixmap = QPixmap() pixmap.convertFromImage(image_main) pixmap.save(fileName, format=QFileInfo(fileName).suffix()) self.saveReplyBox("Atlas", fileName)
def convex_hull(points: List[_Coord], *, as_qpoint: bool = False) -> Union[List[_Coord], List[QPointF]]: """Returns points on convex hull in counterclockwise order according to Graham's scan algorithm. """ def cmp(a: float, b: float) -> int: return (a > b) - (a < b) def turn(p: _Coord, q: _Coord, r: _Coord) -> int: px, py = p qx, qy = q rx, ry = r return cmp((qx - px) * (ry - py) - (rx - px) * (qy - py), 0) def keep_left(hull: List[_Coord], r: _Coord) -> List[_Coord]: while len(hull) > 1 and turn(hull[-2], hull[-1], r) != 1: hull.pop() if not hull or hull[-1] != r: hull.append(r) return hull points.sort() lower = reduce(keep_left, points, []) upper = reduce(keep_left, reversed(points), []) lower.extend(upper[i] for i in range(1, len(upper) - 1)) result = [] for x, y in lower: if as_qpoint: result.append(QPointF(x, y)) else: result.append((x, y)) return result
def draw_curve(self, path: Sequence[_Coord]): """Draw path as curve.""" if len(set(path)) <= 2: return painter_path = QPainterPath() error = False for i, (x, y) in enumerate(path): if isnan(x): error = True self.painter.drawPath(painter_path) painter_path = QPainterPath() else: x *= self.zoom y *= -self.zoom if i == 0: painter_path.moveTo(x, y) self.painter.drawEllipse(QPointF(x, y), self.joint_size, self.joint_size) continue if error: painter_path.moveTo(x, y) error = False else: painter_path.lineTo(x, y) self.painter.drawPath(painter_path)
def __save_atlas(self): """Save function as same as type synthesis widget.""" count = self.collection_list.count() if not count: return lateral, ok = QInputDialog.getInt(self, "Atlas", "The number of lateral:", 5, 1) if not ok: return file_name = self.output_to("Atlas image", qt_image_format) if not file_name: return icon_size = self.collection_list.iconSize() width = icon_size.width() image_main = QImage( QSize(lateral * width if count > lateral else count * width, ((count // lateral) + bool(count % lateral)) * width), self.collection_list.item(0).icon().pixmap( icon_size).toImage().format()) image_main.fill(Qt.transparent) painter = QPainter(image_main) for row in range(count): image = self.collection_list.item(row).icon().pixmap( icon_size).toImage() painter.drawImage( QPointF(row % lateral * width, row // lateral * width), image) painter.end() pixmap = QPixmap() pixmap.convertFromImage(image_main) pixmap.save(file_name) self.save_reply_box("Atlas", file_name)
def drawSolution(self, func: str, args: Tuple[str], target: str): """Draw the solution triangle.""" params = [args[0], args[-1]] params.append(target) if func == 'PLLP': color = QColor(121, 171, 252) else: color = QColor(249, 84, 216) color.setAlpha(255) pen = QPen() pen.setColor(color) pen.setWidth(self.r) self.painter.setPen(pen) for n in (0, 1): x, y = self.pos[int(params[-1].replace('P', ''))] x2, y2 = self.pos[int(params[n].replace('P', ''))] self.drawArrow( x*self.zoom, y*-self.zoom, x2*self.zoom, y2*-self.zoom ) color.setAlpha(30) self.painter.setBrush(QBrush(color)) qpoints = [] for name in params: x, y = self.pos[int(name.replace('P', ''))] qpoints.append(QPointF(x*self.zoom, y*-self.zoom)) self.painter.drawPolygon(*qpoints)
def convex_hull(points: Sequence[Tuple[float, float]]): """Returns points on convex hull in CCW order according to Graham's scan algorithm. """ def cmp(a: float, b: float) -> int: return (a > b) - (a < b) def turn(p: Tuple[float, float], q: Tuple[float, float], r: Tuple[float, float]): return cmp( (q[0] - p[0]) * (r[1] - p[1]) - (r[0] - p[0]) * (q[1] - p[1]), 0) def keep_left(hull: Sequence[Tuple[float, float]], r: Tuple[float, float]): while (len(hull) > 1) and (turn(hull[-2], hull[-1], r) != 1): hull.pop() if not len(hull) or hull[-1] != r: hull.append(r) return hull points = sorted(points) l = reduce(keep_left, points, []) u = reduce(keep_left, reversed(points), []) return [ QPointF(x, y) for x, y in (l.extend(u[i] for i in range(1, len(u) - 1)) or l) ]
def Topologic_result_context_menu(self, point): """Context menu for the type synthesis results.""" index = self.Topologic_result.currentIndex().row() self.add_collection.setEnabled(index>-1) self.copy_edges.setEnabled(index>-1) self.copy_image.setEnabled(index>-1) action = self.popMenu_topo.exec_(self.Topologic_result.mapToGlobal(point)) if not action: return clipboard = QApplication.clipboard() if action==self.add_collection: self.addCollection(self.answer[index].edges) elif action==self.copy_edges: clipboard.setText(str(self.answer[index].edges)) elif action==self.copy_image: #Turn the transparent background to white. image1 = self.atlas_image() image2 = QImage(image1.size(), image1.format()) image2.fill(QColor(Qt.white).rgb()) painter = QPainter(image2) painter.drawImage(QPointF(0, 0), image1) painter.end() pixmap = QPixmap() pixmap.convertFromImage(image2) clipboard.setPixmap(pixmap)
def convex_hull( points: List[Tuple[float, float]], *, as_qpoint: bool = False ) -> Union[List[Tuple[float, float]], List[QPointF]]: """Returns points on convex hull in counterclockwise order according to Graham's scan algorithm. """ coordinate: type = Tuple[float, float] def cmp(a: float, b: float) -> int: return (a > b) - (a < b) def turn(p: coordinate, q: coordinate, r: coordinate) -> int: return cmp((q[0] - p[0])*(r[1] - p[1]) - (r[0] - p[0])*(q[1] - p[1]), 0) def keep_left(hull: List[coordinate], r: coordinate) -> List[coordinate]: while (len(hull) > 1) and (turn(hull[-2], hull[-1], r) != 1): hull.pop() if not len(hull) or hull[-1] != r: hull.append(r) return hull points.sort() lower = reduce(keep_left, points, []) upper = reduce(keep_left, reversed(points), []) lower.extend(upper[i] for i in range(1, len(upper) - 1)) result = [] for x, y in lower: if as_qpoint: result.append(QPointF(x, y)) else: result.append((x, y)) return result
def __drawLink(self, vlink: VLink): """Draw a link.""" points = [] for i in vlink.points: vpoint = self.Points[i] if vpoint.type == 1 or vpoint.type == 2: coordinate = vpoint.c[0 if (vlink.name == vpoint.links[0]) else 1] x = coordinate[0] * self.zoom y = coordinate[1] * -self.zoom else: x = vpoint.cx * self.zoom y = vpoint.cy * -self.zoom points.append((x, y)) pen = QPen(vlink.color) pen.setWidth(self.linkWidth) self.painter.setPen(pen) brush = QColor(226, 219, 190) brush.setAlphaF(self.transparency) self.painter.setBrush(brush) #Rearrange: Put the nearest point to the next position. qpoints = convex_hull(points) if qpoints: self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if ((not self.showPointMark) or (vlink.name == 'ground') or (not qpoints)): return pen.setColor(Qt.darkGray) self.painter.setPen(pen) cenX = sum(p[0] for p in points) / len(points) cenY = sum(p[1] for p in points) / len(points) self.painter.drawText(QPointF(cenX, cenY), '[{}]'.format(vlink.name))
def solutionPolygon( self, func: str, args: Sequence[str], target: str, pos: Union[Tuple[VPoint, ...], Dict[int, Tuple[float, float]]] ) -> Tuple[List[QPointF], QColor]: """Get solution polygon.""" if func == 'PLLP': color = QColor(121, 171, 252) params = [args[0], args[-1]] elif func == 'PLAP': color = QColor(249, 84, 216) params = [args[0]] else: if func == 'PLPP': color = QColor(94, 255, 185) else: # PXY color = QColor(249, 175, 27) params = [args[0]] params.append(target) tmp_list = [] for name in params: try: index = int(name.replace('P', '')) except ValueError: continue else: x, y = pos[index] tmp_list.append(QPointF(x, -y) * self.zoom) return tmp_list, color
def paintEvent(self, event): """Drawing functions.""" width = self.width() height = self.height() if ((self.width_old is not None) and ((self.width_old != width) or (self.height_old != height))): self.ox += (width - self.width_old) / 2 self.oy += (height - self.height_old) / 2 super(DynamicCanvas, self).paintEvent(event) self.painter.setFont(QFont('Arial', self.fontSize)) if self.freemove != FreeMode.NoFreeMove: #Draw a colored frame for free move mode. pen = QPen() if self.freemove == FreeMode.Translate: pen.setColor(QColor(161, 105, 229)) elif self.freemove == FreeMode.Rotate: pen.setColor(QColor(219, 162, 6)) elif self.freemove == FreeMode.Reflect: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.__drawFrame() #Draw links except ground. for vlink in self.Links[1:]: self.__drawLink(vlink) #Draw path. if self.Path.show != -2: self.__drawPath() #Draw solving path. if self.showTargetPath: self.__drawSlvsRanges() self._BaseCanvas__drawTargetPath() #Draw points. for i, vpoint in enumerate(self.Points): self.__drawPoint(i, vpoint) #Rectangular selection if self.Selector.RectangularSelection: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect( QRectF(QPointF(self.Selector.x, self.Selector.y), QPointF(self.Selector.sx, self.Selector.sy))) self.painter.end() #Record the widget size. self.width_old = width self.height_old = height
def updateRanges(self, ranges: Dict[str, Tuple[float, float, float]]): """Update the ranges of dimensional synthesis.""" self.ranges.clear() self.ranges.update({tag: QRectF( QPointF(values[0] - values[2]/2, values[1] + values[2]/2), QSizeF(values[2], values[2]) ) for tag, values in ranges.items()}) self.update()
def drawDot(self, path: Sequence[Tuple[float, float]]): """Draw path as dots.""" if len(set(path)) <= 2: return for x, y in path: if isnan(x): continue self.painter.drawPoint(QPointF(x, -y) * self.zoom)
def __draw_frame(self): """Draw a external frame.""" pos_x = self.width() - self.ox pos_y = -self.oy neg_x = -self.ox neg_y = self.height() - self.oy self.painter.drawLine(QPointF(neg_x, pos_y), QPointF(pos_x, pos_y)) self.painter.drawLine(QPointF(neg_x, neg_y), QPointF(pos_x, neg_y)) self.painter.drawLine(QPointF(neg_x, pos_y), QPointF(neg_x, neg_y)) self.painter.drawLine(QPointF(pos_x, pos_y), QPointF(pos_x, neg_y))
def __draw_arrow( self, x1: float, y1: float, x2: float, y2: float, *, zoom: bool = False, text: str = '' ): """Front point -> Back point""" if zoom: x1 *= self.zoom y1 *= self.zoom x2 *= self.zoom y2 *= self.zoom a = atan2(y2 - y1, x2 - x1) x1 = (x1 + x2) / 2 - 7.5 * cos(a) y1 = (y1 + y2) / 2 - 7.5 * sin(a) first_point = QPointF(x1, y1) self.painter.drawLine(first_point, QPointF( x1 + 15 * cos(a + radians(20)), y1 + 15 * sin(a + radians(20)) )) self.painter.drawLine(first_point, QPointF( x1 + 15 * cos(a - radians(20)), y1 + 15 * sin(a - radians(20)) )) if not text: return # Font font = self.painter.font() font_copy = QFont(font) font.setBold(True) font.setPointSize(font.pointSize() + 8) self.painter.setFont(font) # Color pen = self.painter.pen() color = pen.color() pen.setColor(color.darker()) self.painter.setPen(pen) self.painter.drawText(first_point, text) pen.setColor(color) self.painter.setPen(pen) self.painter.setFont(font_copy)
def paintEvent(self, event): """Drawing functions.""" width = self.width() height = self.height() if self.width_old != width or self.height_old != height: self.ox += (width - self.width_old) / 2 self.oy += (height - self.height_old) / 2 super(DynamicCanvas, self).paintEvent(event) self.painter.setFont(QFont('Arial', self.fontSize)) if self.freemove: #Draw a colored frame for free move mode. pen = QPen() if self.freemove == 1: pen.setColor(QColor(161, 105, 229)) elif self.freemove == 2: pen.setColor(QColor(219, 162, 6)) elif self.freemove == 3: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.drawFrame() if self.Selector.RectangularSelection: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect( QRectF(QPointF(self.Selector.x, self.Selector.y), QPointF(self.Selector.sx, self.Selector.sy))) #Draw links. for vlink in self.Link[1:]: self.drawLink(vlink) #Draw path. if self.Path.show > -2: self.drawPath() #Draw solving path. if self.showTargetPath: self.drawSlvsRanges() self.drawTargetPath() #Draw points. for i, vpoint in enumerate(self.Point): self.drawPoint(i, vpoint) self.painter.end() self.width_old = width self.height_old = height
def drawCurve(self, path): pointPath = QPainterPath() for i, (x, y) in enumerate(path): if isnan(x): continue else: if i==0: pointPath.moveTo(x*self.zoom, y*-self.zoom) else: pointPath.lineTo(QPointF(x*self.zoom, y*-self.zoom)) self.painter.drawPath(pointPath)
def paintEvent(self, event): """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) # Translation self.painter.translate(self.ox, self.oy) # Background if not self.background.isNull(): rect = self.background.rect() self.painter.setOpacity(self.background_opacity) img_origin: QPointF = self.background_offset * self.zoom self.painter.drawImage( QRectF(img_origin, QSizeF( rect.width() * self.background_scale * self.zoom, rect.height() * self.background_scale * self.zoom )), self.background, QRectF(rect) ) self.painter.setOpacity(1) # Show frame. pen = QPen(Qt.blue) pen.setWidth(1) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.font_size)) # Draw origin lines. pen.setColor(Qt.gray) self.painter.setPen(pen) x_l = -self.ox x_r = self.width() - self.ox self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0)) y_t = self.height() - self.oy y_b = -self.oy self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t)) def indexing(v): """Draw tick.""" return int(v / self.zoom - v / self.zoom % 5) for x in range(indexing(x_l), indexing(x_r) + 1, 5): self.painter.drawLine( QPointF(x, 0) * self.zoom, QPointF(x * self.zoom, -10 if x % 10 == 0 else -5) ) for y in range(indexing(y_b), indexing(y_t) + 1, 5): self.painter.drawLine( QPointF(0, y) * self.zoom, QPointF(10 if y % 10 == 0 else 5, y * self.zoom) )
def setZoom(self, zoom: int): """Update zoom factor.""" zoom_old = self.zoom self.zoom = zoom / 100 * self.rate dz = zoom_old - self.zoom if self.zoomby == 0: pos = self.mapFromGlobal(QCursor.pos()) else: pos = QPointF(self.width() / 2, self.height() / 2) self.ox += (pos.x() - self.ox) / self.zoom * dz self.oy += (pos.y() - self.oy) / self.zoom * dz self.update()