def __draw_link(self, name: str, points: Sequence[int]) -> None: """Draw link function. The link color will be the default color. """ pen = QPen(Qt.black if self.monochrome else color_qt('blue')) pen.setWidth(self.link_width) self.painter.setPen(pen) brush = color_qt('dark-gray') if self.monochrome else LINK_COLOR 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 != VLink.FRAME and qpoints: pen.setColor(Qt.darkGray) self.painter.setPen(pen) self.painter.setFont(QFont('Arial', self.font_size)) 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), f"[{name}]" )
def __draw_path(self) -> None: """Draw paths. Recording first.""" paths = self.path_record or self.path.path or self.path_preview if len(self.vpoints) != len(paths): return pen = QPen() fmt_paths: List[Tuple[int, _Path]] = list(enumerate(paths)) if paths is self.path_preview: fmt_paths.extend(self.slider_path_preview.items()) for i, path in fmt_paths: if self.path.show != i and self.path.show != -1: continue if self.monochrome: color = color_qt('gray') elif self.vpoints[i].color is None: color = color_qt('green') else: color = QColor(*self.vpoints[i].color) pen.setColor(color) pen.setWidth(self.path_width) self.painter.setPen(pen) if self.path.curve: self.draw_curve(path) else: self.draw_dot(path)
def __draw_path(self) -> None: """Draw paths. Recording first.""" paths: _Paths = self.path_record or self.path.path or self.path_preview if len(self.vpoints) != len(paths): return pen = QPen() fmt_paths = [(i, p) for i, p in enumerate(paths)] if paths is self.path_preview: fmt_paths.extend(self.slider_path_preview.items()) elif paths is self.path_record: fmt_paths.extend(self.slider_record.items()) else: # User paths fmt_paths.extend(self.path.slider_path.items()) for i, path in fmt_paths: if self.path.show != i and self.path.show != -1: continue vpoint = self.vpoints[i] if self.monochrome: color = color_qt('gray') else: color = color_qt(vpoint.color) pen.setColor(color) pen.setWidth(self.path_width) self.painter.setPen(pen) if self.path.curve: self.draw_curve(path) else: self.draw_dot(path)
def paintEvent(self, event: QPaintEvent) -> None: """Drawing function.""" super(_DynamicCanvas, self).paintEvent(event) pen = QPen() pen.setWidth(self.link_width) brush = color_qt('dark-gray') if self.monochrome else LINK_COLOR self.painter.setBrush(brush) for vlink in self.vlinks: if vlink.name == VLink.FRAME or not vlink.points: continue points = [] for i in vlink.points: vpoint = self.vpoints[i] if (vpoint.type == VJoint.R or not vpoint.is_slot_link(vlink.name)): x, y = self.path.path[i][self.ind] else: x, y = self.path.slider_path[i][self.ind] points.append((x * self.zoom, y * -self.zoom)) qpoints = convex_hull(points, as_qpoint=True) pen.setColor( Qt.black if self.monochrome else color_qt(vlink.color)) self.painter.setPen(pen) self.painter.drawPolygon(*qpoints) self.painter.setBrush(Qt.NoBrush) pen.setWidth(self.path_width) for paths, vel, acc in [ (enumerate(self.path.path), self.vel, self.acc), (self.path.slider_path.items(), self.vel_slider, self.acc_slider), ]: for i, path in paths: vpoint = self.vpoints[i] if self.monochrome: color = color_qt('gray') else: color = color_qt(vpoint.color) pen.setColor(color) self.painter.setPen(pen) self.draw_curve(path) x, y = path[self.ind] zoom = 1. for vec, color in [(vel[i], Qt.blue), (acc[i], Qt.red)]: if self.ind >= len(vec): break vx, vy = vec[self.ind] if isnan(vx) or isnan(vy): break zoom /= self.factor r = hypot(vx, vy) * zoom if isclose(r, 0): break th = atan2(vy, vx) pen.setColor(color) self.painter.setPen(pen) self.draw_arrow(x, y, x + r * cos(th), y + r * sin(th)) self.draw_point(i, x, y, vpoint.grounded(), vpoint.color) self.painter.end()
def __draw_paths(self) -> None: """Draw paths.""" pen = QPen() pen.setWidth(self.path_width) for i, path in enumerate(self.path.path): if self.monochrome: pen.setColor(color_qt('gray')) elif self.vpoints[i].color is None: pen.setColor(color_qt('green')) else: pen.setColor(QColor(*self.vpoints[i].color)) self.painter.setPen(pen) self.draw_curve(path)
def __draw_path(self) -> None: """Draw a path. A simple function than main canvas. """ pen = QPen() for i, path in enumerate(self.path.path): color = color_qt('Green') if f"P{i}" in self.target_path: color = color_qt('Dark-Orange') pen.setColor(color) pen.setWidth(self.path_width) self.painter.setPen(pen) self.draw_curve(path)
def __draw_link(self, vlink: VLink) -> None: """Draw a link.""" if vlink.name == VLink.FRAME or not vlink.points: return pen = QPen() # Rearrange: Put the nearest point to the next position. qpoints = convex_hull( [(c.x * self.zoom, c.y * -self.zoom) for c in vlink.points_pos(self.vpoints)], 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 color_qt(vlink.color)) self.painter.setPen(pen) self.painter.drawPolygon(*qpoints) if not self.show_point_mark: return pen.setColor(Qt.darkGray) self.painter.setPen(pen) p_count = len(qpoints) cen_x = sum(p.x() for p in qpoints) / p_count cen_y = sum(p.y() for p in qpoints) / p_count self.painter.drawText( QRectF(cen_x - 50, cen_y - 50, 100, 100), Qt.AlignCenter, f'[{vlink.name}]' )
def __draw_link(self, vlink: VLink) -> None: """Draw a link.""" if vlink.name == VLink.FRAME 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 = color_qt('dark-gray') if self.monochrome else LINK_COLOR 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 __set_rgb(self) -> None: """Add a custom color from current color.""" color = QColorDialog.getColor( color_qt(self.color_box.currentText()), self ) if color.isValid(): add_custom_color(self.color_box, color)
def __draw_path(self) -> None: """Draw a path. A simple function than main canvas. """ pen = QPen() pen.setWidth(self.path_width) for i, path in enumerate(self.path.path): if self.no_mechanism and i not in self.target_path: continue if i in self.target_path: if self.monochrome: color = color_qt('black') else: color = color_qt('dark-orange') else: if self.monochrome: color = color_qt('gray') else: color = color_qt('green') pen.setColor(color) self.painter.setPen(pen) self.draw_curve(path)
def paintEvent(self, event: QPaintEvent) -> None: """Drawing functions.""" width = self.width() height = self.height() if self.width_old is None: self.width_old = width if self.height_old is None: self.height_old = 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 # 'self' is the instance of 'DynamicCanvas'. BaseCanvas.paintEvent(self, event) # Draw links except ground brush = color_qt('dark-gray') if self.monochrome else LINK_COLOR brush.setAlphaF(self.transparency) self.painter.setBrush(brush) for vlink in self.vlinks[1:]: self.__draw_link(vlink) self.painter.setBrush(Qt.NoBrush) # Draw path if self.path.show != -2: self.__draw_path() # Draw solving path if self.show_target_path: self.painter.setFont(QFont("Arial", self.font_size + 5)) self.draw_ranges() self.draw_target_path() self.painter.setFont(QFont("Arial", self.font_size)) # Draw points for i, vpoint in enumerate(self.vpoints): self.__draw_point(i, vpoint) # Draw solutions if self.select_mode == SelectMode.SOLUTION: for i, expr in enumerate(self.exprs): func = expr[0] params = expr[1:-1] target = expr[-1] self.draw_solution(func, params, target, self.vpoints) if i in self.selections: pos, _ = self.solution_polygon(func, params, target, self.vpoints) pen = QPen() pen.setWidth(self.link_width + 3) pen.setColor(QColor(161, 16, 239)) self.painter.setPen(pen) self.painter.drawPolygon(QPolygonF([QPointF(x, y) for x, y in pos])) # Draw a colored frame for free move mode if self.free_move != FreeMode.NO_FREE_MOVE: pen = QPen() if self.free_move == FreeMode.TRANSLATE: pen.setColor(QColor(161, 16, 229)) elif self.free_move == FreeMode.ROTATE: pen.setColor(QColor(219, 162, 6)) elif self.free_move == FreeMode.REFLECT: pen.setColor(QColor(79, 249, 193)) pen.setWidth(8) self.painter.setPen(pen) self.__draw_frame() # Rectangular selection if self.selector.picking: pen = QPen(Qt.gray) pen.setWidth(1) self.painter.setPen(pen) self.painter.drawRect(self.selector.to_rect(self.zoom)) # Show FPS self.fps_updated.emit() self.painter.end() # Record the widget size self.width_old = width self.height_old = height
def __draw_point(self, i: int, vpoint: VPoint) -> None: """Draw a point.""" connected = len(vpoint.links) - 1 if vpoint.type in {VJoint.P, VJoint.RP}: pen = QPen(color_qt(vpoint.color)) pen.setWidth(2) # Draw slot point and pin point for j, (cx, cy) in enumerate(vpoint.c): # Slot point if j == 0 or vpoint.type == VJoint.P: if self.monochrome: color = Qt.black else: color = color_qt(vpoint.color) pen.setColor(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: grounded = (len(vpoint.c) == len(vpoint.links) and vpoint.links[j] == VLink.FRAME) self.draw_point(i, cx, cy, grounded, vpoint.color, connected) # Slider line pen.setColor(color_qt(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, connected) # 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 )