"""Várias instâncias, uma pilha de matrizes só. Aula 04 — Instanciamento e Transformações Geométricas 2D. Exemplo em Python com PySide6 e PyOpenGL (pipeline fixed-function). Execute com: python pilha_instancias2d.py ``_desenhar_estrela`` desenha SEMPRE em torno da própria origem — ela não recebe posição, ângulo nem escala. Cada uma das sete instâncias em INSTANCIAS é desenhada dentro de um glPushMatrix()/glPopMatrix(), com glTranslatef/glRotatef/glScalef entre os dois: é a matriz corrente, não a função de desenho, que decide onde, com que ângulo e em que tamanho cada cópia aparece. Experimente comentar a linha "glPopMatrix()" do laço principal e rodar de novo: as transformações passam a se acumular de uma instância para a próxima, cada vez mais deslocadas — o vazamento que a pilha existe para evitar. Desfaça o comentário antes de seguir para a atividade. Tecla: Esc fecha """ from __future__ import annotations import math import sys from PySide6.QtCore import Qt from PySide6.QtGui import QSurfaceFormat from PySide6.QtWidgets import QApplication from PySide6.QtOpenGLWidgets import QOpenGLWidget from OpenGL.GL import * from OpenGL.GLU import gluOrtho2D MUNDO = 14.0 RAIO_EXTERNO = 1.0 RAIO_INTERNO = 0.4 # (cx, cy, ângulo em graus, escala, cor) — uma linha por instância. Nenhuma # outra informação sobre a estrela fica aqui: a forma em si vem sempre de # _desenhar_estrela. INSTANCIAS = [ (-9.0, 2.0, 0.0, 1.0, (0.93, 0.20, 0.31)), (-6.0, 5.0, 25.0, 0.7, (0.99, 0.69, 0.19)), (-2.0, 6.0, 50.0, 1.3, (0.00, 0.65, 0.32)), (2.0, 6.0, 80.0, 0.9, (0.00, 0.51, 0.78)), (6.0, 5.0, 110.0, 1.1, (0.55, 0.35, 0.85)), (9.0, 2.0, 140.0, 0.6, (0.93, 0.20, 0.31)), (0.0, -3.0, 200.0, 1.6, (0.99, 0.69, 0.19)), ] class PilhaInstancias2D(QOpenGLWidget): """Uma função de desenho, sete instâncias, uma pilha de matrizes.""" def initializeGL(self) -> None: glClearColor(0.10, 0.11, 0.13, 1.0) def resizeGL(self, w: int, h: int) -> None: w, h = max(1, w), max(1, h) glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() if w <= h: gluOrtho2D(-MUNDO, MUNDO, -MUNDO * h / w, MUNDO * h / w) else: gluOrtho2D(-MUNDO * w / h, MUNDO * w / h, -MUNDO, MUNDO) glMatrixMode(GL_MODELVIEW) glLoadIdentity() @staticmethod def _desenhar_estrela(cor) -> None: """Uma estrela de cinco pontas, sempre centrada na própria origem.""" glColor3f(*cor) glBegin(GL_LINE_LOOP) for k in range(10): raio = RAIO_EXTERNO if k % 2 == 0 else RAIO_INTERNO ang = math.pi / 2 + k * math.pi / 5 glVertex2f(raio * math.cos(ang), raio * math.sin(ang)) glEnd() def paintGL(self) -> None: glClear(GL_COLOR_BUFFER_BIT) glLineWidth(2.0) for cx, cy, angulo, escala, cor in INSTANCIAS: glPushMatrix() glTranslatef(cx, cy, 0.0) glRotatef(angulo, 0.0, 0.0, 1.0) glScalef(escala, escala, 1.0) self._desenhar_estrela(cor) glPopMatrix() def keyPressEvent(self, event) -> None: if event.key() == Qt.Key.Key_Escape: self.close() def main() -> int: fmt = QSurfaceFormat() fmt.setVersion(2, 1) fmt.setProfile(QSurfaceFormat.OpenGLContextProfile.NoProfile) fmt.setDepthBufferSize(0) QSurfaceFormat.setDefaultFormat(fmt) app = QApplication(sys.argv) janela = PilhaInstancias2D() janela.setWindowTitle("Pilha de matrizes — sete instâncias") janela.resize(800, 560) janela.show() return app.exec() if __name__ == "__main__": raise SystemExit(main())