| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 | import numpy as npfrom PyQt5.QtCore import Qtfrom PyQt5.QtGui import QImage, QPixmap, QPainter, QColor, QPolygonfrom PyQt5.QtCore import QPoint, QSize, QRectfrom PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QTextEditfrom PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QFrameclass Window(QMainWindow):    """    Simple application window to render the environment into    """    def __init__(self):        super().__init__()        self.setWindowTitle('MiniGrid Gym Environment')        # Image label to display the rendering        self.imgLabel = QLabel()        self.imgLabel.setFrameStyle(QFrame.Panel | QFrame.Sunken)        # Text box for the mission        self.missionBox = QTextEdit()        self.missionBox.setReadOnly(True)        self.missionBox.setMinimumSize(400, 100)        # Center the image        hbox = QHBoxLayout()        hbox.addStretch(1)        hbox.addWidget(self.imgLabel)        hbox.addStretch(1)        # Arrange widgets vertically        vbox = QVBoxLayout()        vbox.addLayout(hbox)        vbox.addWidget(self.missionBox)        # Create a main widget for the window        mainWidget = QWidget(self)        self.setCentralWidget(mainWidget)        mainWidget.setLayout(vbox)        # Show the application window        self.show()        self.setFocus()        self.closed = False        # Callback for keyboard events        self.keyDownCb = None    def closeEvent(self, event):        self.closed = True    def setPixmap(self, pixmap):        self.imgLabel.setPixmap(pixmap)    def setText(self, text):        self.missionBox.setPlainText(text)    def setKeyDownCb(self, callback):        self.keyDownCb = callback    def keyPressEvent(self, e):        if self.keyDownCb == None:            return        keyName = None        if e.key() == Qt.Key_Left:            keyName = 'LEFT'        elif e.key() == Qt.Key_Right:            keyName = 'RIGHT'        elif e.key() == Qt.Key_Up:            keyName = 'UP'        elif e.key() == Qt.Key_Down:            keyName = 'DOWN'        elif e.key() == Qt.Key_Space:            keyName = 'SPACE'        elif e.key() == Qt.Key_Return:            keyName = 'RETURN'        elif e.key() == Qt.Key_Alt:            keyName = 'ALT'        elif e.key() == Qt.Key_Control:            keyName = 'CTRL'        elif e.key() == Qt.Key_PageUp:            keyName = 'PAGE_UP'        elif e.key() == Qt.Key_PageDown:            keyName = 'PAGE_DOWN'        elif e.key() == Qt.Key_Backspace:            keyName = 'BACKSPACE'        elif e.key() == Qt.Key_Escape:            keyName = 'ESCAPE'        if keyName == None:            return        self.keyDownCb(keyName)class Renderer:    def __init__(self, width, height, ownWindow=False):        self.width = width        self.height = height        self.img = QImage(width, height, QImage.Format_RGB888)        self.painter = QPainter()        self.window = None        if ownWindow:            self.app = QApplication([])            self.window = Window()    def close(self):        """        Deallocate resources used        """        pass    def beginFrame(self):        self.painter.begin(self.img)        self.painter.setRenderHint(QPainter.Antialiasing, False)        # Clear the background        self.painter.setBrush(QColor(0, 0, 0))        self.painter.drawRect(0, 0, self.width - 1, self.height - 1)    def endFrame(self):        self.painter.end()        if self.window:            if self.window.closed:                self.window = None            else:                self.window.setPixmap(self.getPixmap())                self.app.processEvents()    def getPixmap(self):        return QPixmap.fromImage(self.img)    def getArray(self):        """        Get a numpy array of RGB pixel values.        The array will have shape (height, width, 3)        """        numBytes = self.width * self.height * 3        buf = self.img.bits().asstring(numBytes)        output = np.frombuffer(buf, dtype='uint8')        output = output.reshape((self.height, self.width, 3))        return output    def push(self):        self.painter.save()    def pop(self):        self.painter.restore()    def rotate(self, degrees):        self.painter.rotate(degrees)    def translate(self, x, y):        self.painter.translate(x, y)    def scale(self, x, y):        self.painter.scale(x, y)    def setLineColor(self, r, g, b, a=255):        self.painter.setPen(QColor(r, g, b, a))    def setColor(self, r, g, b, a=255):        self.painter.setBrush(QColor(r, g, b, a))    def setLineWidth(self, width):        pen = self.painter.pen()        pen.setWidthF(width)        self.painter.setPen(pen)    def drawLine(self, x0, y0, x1, y1):        self.painter.drawLine(x0, y0, x1, y1)    def drawCircle(self, x, y, r):        center = QPoint(x, y)        self.painter.drawEllipse(center, r, r)    def drawPolygon(self, points):        """Takes a list of points (tuples) as input"""        points = map(lambda p: QPoint(p[0], p[1]), points)        self.painter.drawPolygon(QPolygon(points))    def drawPolyline(self, points):        """Takes a list of points (tuples) as input"""        points = map(lambda p: QPoint(p[0], p[1]), points)        self.painter.drawPolyline(QPolygon(points))    def fillRect(self, x, y, width, height, r, g, b, a=255):        self.painter.fillRect(QRect(x, y, width, height), QColor(r, g, b, a))
 |