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 __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_link(self, vlink: VLink): """Draw a link.""" if vlink.name == 'ground' or (not vlink.points): return points = self.__points_pos(vlink) pen = QPen() # Rearrange: Put the nearest point to the next position. qpoints = convex_hull(points, as_qpoint=True) if (self.select_mode == SelectMode.Link and self.vlinks.index(vlink) in self.selections): pen.setWidth(self.link_width + 6) pen.setColor(Qt.black if self.monochrome else QColor(161, 16, 239)) self.painter.setPen(pen) self.painter.drawPolygon(*qpoints) pen.setWidth(self.link_width) pen.setColor(Qt.black if self.monochrome else QColor(*vlink.color)) self.painter.setPen(pen) brush = QColor(Qt.darkGray) if self.monochrome else QColor( 226, 219, 190) brush.setAlphaF(self.transparency) self.painter.setBrush(brush) self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) if not self.show_point_mark: return pen.setColor(Qt.darkGray) self.painter.setPen(pen) p_count = len(points) cen_x = sum(p[0] for p in points) / p_count cen_y = sum(p[1] for p in points) / p_count self.painter.drawText(QRectF(cen_x - 50, cen_y - 50, 100, 100), Qt.AlignCenter, f'[{vlink.name}]')
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 __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 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 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 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 __init__(self, mechanism: Dict[str, Any], path: Sequence[Sequence[Tuple[float, float]]], vpoints: List[VPoint], vlinks: List[VLink], parent: QWidget): """Input link and path data.""" super(_DynamicCanvas, self).__init__(parent) self.mechanism = mechanism self.path.path = path self.vpoints = vpoints self.vlinks = vlinks ranges: Dict[int, Tuple[float, float, float]] = self.mechanism['Placement'] self.ranges.update({ f"P{i}": QRectF(QPointF(values[0] - values[2], values[1] + values[2]), QSizeF(values[2] * 2, values[2] * 2)) for i, values in ranges.items() }) same: Dict[int, int] = self.mechanism['same'] target_path: Dict[int, List[Tuple[float, float]]] = self.mechanism['Target'] for i, path in target_path.items(): for j in range(i): if j in same: i -= 1 self.target_path[f"P{i}"] = path self.__index = 0 self.__interval = 1 self.__path_count = max(len(path) for path in self.path.path) - 1 self.pos: List[Tuple[float, float]] = [] # Error self.error = False self.__no_error = 0 # Timer start. self.__timer = QTimer() self.__timer.timeout.connect(self.__change_index) self.__timer.start(18)
def draw_slvs_ranges(self): """Draw solving range.""" pen = QPen() pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(color_num(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(QPointF(cx, cy), QSizeF(rect.width(), 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, cy) + QPointF(6, -6), tag) self.painter.setBrush(Qt.NoBrush)
def to_rect(self, zoom: float) -> QRectF: """Return limit as QRectF type.""" return QRectF(QPointF(self.x * zoom, -self.y * zoom), QPointF(self.sx * zoom, -self.sy * zoom))