[Python] With QPainter, I created a path, duplicated it and connected their corresponding...

Discussão em 'Python' iniciado por Stack, Fevereiro 13, 2025.

  1. Stack

    Stack Membro Participativo

    So I'm trying to create a fake 3D / isometric extrusion effect by creating a QPainterPath, duplicating and offsetting it, converting both to polygons, extracting their points and finally connecting these points with straight lines. This is the result: [​IMG]

    I can't figure out a way to fill the inner lines with color, any help?

    Here's the full code to run the app from the .gif posted above:

    from PyQt6.QtGui import QPainter, QPainterPath, QFont, QPen, QBrush, QColor
    from PyQt6.QtCore import QPointF, Qt
    from PyQt6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout
    import sys
    import math

    class TextPathPoints(QWidget):
    def __init__(self):
    super().__init__()

    self.resize(800, 300)

    # Create a QPainterPath with text
    self.font = QFont("Super Dessert", 120) # Use a valid font
    self.path = QPainterPath()
    self.path.addText(100, 200, self.font, "HELLO!")

    # Control variables for extrusion
    self.extrusion_length = 25 # Length of extrusion
    self.extrusion_angle = 45 # Angle in degrees (measured counterclockwise from the positive x-axis)

    layout = QVBoxLayout()

    # Create slider for extrusion length (range 0-100, step 1)
    self.length_slider = QSlider()
    self.length_slider.setRange(0, 100)
    self.length_slider.setValue(self.extrusion_length)
    self.length_slider.setTickInterval(1)
    self.length_slider.valueChanged.connect(self.update_extrusion_length)
    layout.addWidget(self.length_slider)

    # Create slider for extrusion angle (range 0-360, step 1)
    self.angle_slider = QSlider()
    self.angle_slider.setRange(0, 360)
    self.angle_slider.setValue(self.extrusion_angle)
    self.angle_slider.setTickInterval(1)
    self.angle_slider.valueChanged.connect(self.update_extrusion_angle)
    layout.addWidget(self.angle_slider)

    self.setLayout(layout)

    def update_extrusion_length(self, value):
    self.extrusion_length = value
    self.update() # Trigger repaint to update the path

    def update_extrusion_angle(self, value):
    self.extrusion_angle = value
    self.update() # Trigger repaint to update the path

    def paintEvent(self, event):
    painter = QPainter(self)
    painter.setRenderHint(QPainter.RenderHint.Antialiasing)

    painter.setRenderHint(QPainter.RenderHint.Antialiasing)

    # Convert angle to radians
    angle_rad = math.radians(self.extrusion_angle)

    # Calculate x and y offsets based on extrusion length and angle
    self.offset_x = self.extrusion_length * math.cos(angle_rad)
    self.offset_y = self.extrusion_length * math.sin(angle_rad)

    # Duplicate the path
    self.duplicated_path = QPainterPath(self.path) # Duplicate the original path
    self.duplicated_path.translate(self.offset_x, self.offset_y) # Offset using calculated values

    # Convert paths to polygons
    original_polygon = self.path.toFillPolygon()
    duplicated_polygon = self.duplicated_path.toFillPolygon()

    # Extract points from polygons
    self.original_points = [(p.x(), p.y()) for p in original_polygon]
    self.duplicated_points = [(p.x(), p.y()) for p in duplicated_polygon]

    # Set brush for filling the path
    brush = QBrush(QColor("#ebd086")) # Front and back fill
    painter.setBrush(brush)

    # Fill the original path
    painter.fillPath(self.path, brush)

    # Set pen for drawing lines between points
    pen = QPen()
    pen.setColor(QColor("black")) # Color of the lines
    pen.setWidthF(1.4)
    painter.setPen(pen)
    pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)
    pen.setCapStyle(Qt.PenCapStyle.RoundCap)

    # Draw duplicated path
    painter.drawPath(self.duplicated_path)

    # Connect corresponding points between the original and duplicated paths
    num_points = min(len(self.original_points), len(self.duplicated_points))
    for i in range(num_points):
    original_x, original_y = self.original_points
    duplicated_x, duplicated_y = self.duplicated_points
    painter.drawLine(QPointF(original_x, original_y), QPointF(duplicated_x, duplicated_y))

    # Draw the original path
    painter.drawPath(self.path)


    app = QApplication(sys.argv)
    window = TextPathPoints()
    window.show()
    sys.exit(app.exec())

    Continue reading...

Compartilhe esta Página