def InitWindow(self): self.button1 = QPushButton("Rotate - ", self) self.button1.setGeometry(200,420,100,50) self.button1.clicked.connect(self.rotateMinus) self.button2 = QPushButton("Rotate +", self) self.button2.setGeometry(400,420,100,50) self.button2.clicked.connect(self.rotatePlus) scene = QGraphicsScene(self) redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10,10,200,200, blackPen, redBrush) rect = scene.addRect(-100,-100,200,200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) # set it to movable rect.setFlag(QGraphicsItem.ItemIsMovable) self.view = QGraphicsView(scene, self) self.view.setGeometry(0,0,680,400) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.setWindowIcon(QtGui.QIcon('./icon/icon.png')) self.show()
def InitWindow(self): self.button1 = QPushButton("Rotate - ", self) self.button1.setGeometry(200, 420, 100, 50) self.button1.clicked.connect(self.rotateminus) self.button2 = QPushButton("Rotate +", self) self.button2.setGeometry(320, 420, 100, 50) self.button2.clicked.connect(self.rotateplus) scene = QGraphicsScene() #the scene redbrush = QBrush(Qt.red) bluebrush = QBrush(Qt.blue) blackpen = QPen(Qt.black) blackpen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackpen, redbrush) rect = scene.addRect(-100, -100, 200, 200, blackpen, bluebrush) line = scene.addLine(-100, -100, 200, 200, blackpen) ellipse.setFlag(QGraphicsItem.ItemIsMovable) rect.setFlag(QGraphicsItem.ItemIsMovable) line.setFlag(QGraphicsItem.ItemIsMovable) self.view = QGraphicsView(scene, self) self.view.setGeometry(0, 0, 680, 400) self.setWindowIcon(QtGui.QIcon("mongol.jpg")) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.show()
class View(QGraphicsView): def __init__(self): super().__init__() self.setGeometry(300, 300, 300, 300) self.setRenderHint(QPainter.Antialiasing) self.init() def init(self): self.scene = QGraphicsScene() r1 = self.scene.addRect(150, 40, 100, 100) r1.setBrush(QColor(250, 50, 0)) r1.setPen(QColor(250, 50, 0)) el = self.scene.addEllipse(40, 70, 80, 80) el.setBrush(QColor(0, 50, 250)) el.setPen(QColor(0, 50, 250)) r2 = self.scene.addRect(60, 180, 150, 70) r2.setBrush(QColor(0, 250, 50)) r2.setPen(QColor(0, 250, 50)) self.setScene(self.scene)
class GameWindow(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) self.sx = Settings.width self.sy = Settings.height self.lines = [] #self.draw_grid() #self.set_opacity(0.3) self.scene = QGraphicsScene(0, 0, Settings.width, Settings.height) self.setScene(self.scene) self.x = 0 self.y = 0 self.w = 5 self.h = 5 pen = QPen(QColor('dodgerblue')) #pen = QPen(QColor(Qt.green)) brush = QBrush(pen.color()) #brush = QBrush(pen.color().darker(150)) # As opposed to using QPen and QBrush, this colors the periphery only #dot = scene.addEllipse(self.x, self.y, self.w, self.h, QColor('dodgerblue')) self.dot = self.scene.addEllipse(self.x, self.y, self.w, self.h, pen, brush) self.dot.setFlag(QGraphicsItem.ItemIsMovable) def draw_grid(self): width = Settings.NUM_BLOCKS_X * Settings.BLOCK_WIDTH height = Settings.NUM_BLOCKS_Y * Settings.BLOCK_HEIGHT #self.setSceneRect(0,0,width,height) #self.setItemIndexMethod(QTwidgets.QgraphicsScene.NoIndex) pen = QPen(QColor(0, 0, 0), 1, Qt.SolidLine) for x in range(-320, Settings.NUM_BLOCKS_X + 1): xc = x * Settings.BLOCK_WIDTH self.lines.append( self.scene.addLine(xc, 0 - height / 2, xc, height, pen)) for y in range(-240, Settings.NUM_BLOCKS_Y + 1): yc = y * Settings.BLOCK_HEIGHT self.lines.append( self.scene.addLine(0 - width / 2, yc, width, yc, pen)) def set_visible(self, visible=True): for line in self.lines: line.setVisible(visible) def delete_grid(self): for line in self.lines: self.removeItem(line) del self.lines[:] def set_opacity(self, opacity): for line in self.lines: line.setOpacity(opacity)
def ItemsInit(self, scene: QGraphicsScene): ic = len(self.Inputs()) oc = len(self.Outputs()) m = max(ic, oc) * 10 self.windowRect.setHeight(m * 2 + 20) ins = self.Inputs() ino = 20 + m - ic * 10 ouo = 20 + m - oc * 10 pix = scene.addPixmap(self.icon) pix.setPos( (self.windowRect.width() - self.icon.width()) * 0.5, 20 + (self.windowRect.height() - 20 - self.icon.height()) * 0.5) pix.setParentItem(self.item) for i in range(0, ic): ti = scene.addText(ins[i]) ti.setPos(0, i * 20 + ino) ti.setParentItem(self.item) ie = scene.addEllipse( QRectF(QPointF(-5, i * 20 + 5 + ino), QSizeF(10, 10))) ie.setParentItem(self.item) ie.setFlag(QGraphicsItem.ItemNegativeZStacksBehindParent) ie.setZValue(-1) ins = self.Outputs() for i in range(0, oc): ti = scene.addText(ins[i]) ti.setPos( QPointF(self.windowRect.width() - ti.boundingRect().width(), i * 20 + ouo)) ti.setParentItem(self.item) ie = scene.addEllipse( QRectF(QPointF(self.windowRect.width() - 5, i * 20 + 5 + ouo), QSizeF(10, 10))) ie.setParentItem(self.item) ie.setFlag(QGraphicsItem.ItemNegativeZStacksBehindParent) ie.setZValue(-1) self.inputs = [] for i in range(0, ic): self.inputs.append(NodeConnector())
class PointerApp: def __init__(self, point_color, point_size): self.app = QApplication(sys.argv) self.window = QWidget() self.window.setWindowTitle('PyQt5 Pointer App') self.window.setGeometry(100, 100, point_size + 2, point_size + 2) self.window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.window.setAttribute(Qt.WA_TranslucentBackground, True) self.scene = QGraphicsScene() self.scene.setBackgroundBrush(QBrush(QColor(0, 0, 0, 0))) self.scene.update() self.scene.addEllipse(0, 0, point_size, point_size, brush=QBrush(QColor(*point_color))) self.view = QGraphicsView(self.scene, parent=self.window) self.view.setStyleSheet("background-color:transparent;") self.view.show() self.timer = QTimer(self.app) self.timer.timeout.connect(self.updateFunc) signal.signal(signal.SIGINT, self.sigint_handler) def sigint_handler(*args): QApplication.quit() def spin(self): print("Hit ctrl+c in the terminal to stop the pointer app.") self.window.show() self.timer.start(50) return self.app.exec_() def updateFunc(self): data = display.Display().screen().root.query_pointer()._data self.window.move(data["root_x"] + 5, data["root_y"] + 5)
def initUi(self): layout = QGridLayout() graphics_view = QGraphicsView() layout.addWidget(graphics_view) width = graphics_view.frameGeometry().width() height = graphics_view.frameGeometry().height() scene = QGraphicsScene() scene.setSceneRect(0.0, 0.0, float(width), float(height)) scene.addRect(100, 100, 150, 150) pen = QPen(Qt.SolidLine) pen.setColor(Qt.red) brush = QBrush(Qt.Dense3Pattern) brush.setColor(Qt.darkGreen) scene.addEllipse(300, 300, 100, 100, pen, brush) graphics_view.setScene(scene) self.setLayout(layout)
def init(self): scene = QGraphicsScene() redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, redBrush) rectange = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) #使图像可移动 rectange.setFlag(QGraphicsItem.ItemIsMovable) self.graphicsView.setScene(scene) self.graphicsView.scale(1.2, -1.2)
class Window(QMainWindow): def __init__(self): super().__init__() self.title = "PyQt5 QGraphicView" self.top = 200 self.left = 500 self.width = 600 self.height = 500 self.InitWindow() def InitWindow(self): self.setWindowIcon(QtGui.QIcon("icon.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.createGraphicView() self.show() def createGraphicView(self): self.scene = QGraphicsScene() self.greenBrush = QBrush(Qt.green) self.grayBrush = QBrush(Qt.gray) self.pen = QPen(Qt.red) graphicView = QGraphicsView(self.scene, self) graphicView.setGeometry(0, 0, 600, 500) self.shapes() def shapes(self): ellipse = self.scene.addEllipse(20, 20, 200, 200, self.pen, self.greenBrush) rect = self.scene.addRect(-100, -100, 200, 200, self.pen, self.grayBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) rect.setFlag(QGraphicsItem.ItemIsMovable) ellipse.setFlag(QGraphicsItem.ItemIsSelectable)
def InitWindow(self): scene = QGraphicsScene(self) redBrush = QBrush(Qt.red) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) blackPen.setWidth(7) ellipse = scene.addEllipse(10, 10, 200, 200, blackPen, redBrush) rect = scene.addRect(-100, -100, 200, 200, blackPen, blueBrush) ellipse.setFlag(QGraphicsItem.ItemIsMovable) # set it to movable rect.setFlag(QGraphicsItem.ItemIsMovable) view = QGraphicsView(scene, self) view.setGeometry(0, 0, 680, 500) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) self.setWindowIcon(QtGui.QIcon('./icon/icon.png')) self.show()
class MyView(QGraphicsView): def __init__(self): super().__init__() self.initView() self.initScene() self.checkCollisions() def initView(self): self.setWindowTitle("Collision detection") self.setRenderHint(QPainter.Antialiasing) self.setGeometry(300, 300, 300, 250) def initScene(self): self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, 300, 250) self.item = Item() self.scene.addEllipse(160, 60, 40, 40) self.scene.addEllipse(80, 80, 80, 80) self.scene.addEllipse(190, 120, 60, 60) self.scene.addEllipse(150, 165, 50, 50) self.scene.addItem(self.item) self.setScene(self.scene) def checkCollisions(self): items = self.scene.items() brush = QBrush(Qt.SolidPattern) brush.setStyle(Qt.HorPattern) for i in range(len(items)): item = items[i] if self.scene.collidingItems(item): item.setBrush(brush)
def __init__(self, parent=None): super().__init__(parent) self.sx = 635 self.sy = 475 scene = QGraphicsScene(0, 0, self.sx, self.sy) self.setScene(scene) self.x = 0 self.y = 0 self.w = 30 self.h = 30 pen = QPen(QColor('dodgerblue')) #pen = QPen(QColor(Qt.green)) brush = QBrush(pen.color()) #brush = QBrush(pen.color().darker(150)) # As opposed to using QPen and QBrush, this colors the periphery only #dot = scene.addEllipse(self.x, self.y, self.w, self.h, QColor('dodgerblue')) self.dot = scene.addEllipse(self.x, self.y, self.w, self.h, pen, brush) self.dot.setFlag(QGraphicsItem.ItemIsMovable)
def mostrar(self, raiz): scene = QGraphicsScene() elipse = scene.addEllipse(0, 0, 100, 50) elipse.setBrush(QColor(245, 235, 255)) text = scene.addText(raiz.getRaiz()) text1 = scene.addText("RAIZ") self.raiz = Nodo(elipse, [text, text1]) self.conteo = np.zeros(self.controlador.getNAtributos() + 1) self.conteo[0] = 2 if (raiz.getHijos()): self.recurrir(raiz.getHijos(), 0, scene, self.raiz) self.redim(self.raiz, 0, scene) self.unir(self.raiz, scene) self.ui.viewer.setScene(scene) self.ui.viewer.show() self.ui.viewer.verticalScrollBar().setValue(self.ui.viewer.verticalScrollBar().minimum()) self.ui.viewer.horizontalScrollBar().setValue(int(self.ui.viewer.horizontalScrollBar().maximum() / 2))
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14/15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width()*0.95 height = self.contentsRect().height()*0.95 return min(width, height*self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth()*(1/self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2*self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5*baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [leftOffset+(self.borderRatio+x)*baseWidth for x in range(self.board.size)] partionHeight = [topOffset+(self.borderRatio+x)*baseHeight for x in range(self.board.size)] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size-1][n] yBot += self.baseWidth*0.4/self.baseRectRatio xBot -= self.baseWidth*0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth*1.2 yLeft -= self.baseWidth*0.3/self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth*0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x-rad, y-rad, rad*2.0, rad*2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale*self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class panel(QGraphicsView): def __init__(self): super(panel, self).__init__() self.arbolito = None #arbol de entornos self.y = 50 #posicion en y inicial self.escena = QGraphicsScene() #escena de dibujo self.setScene( self.escena) #asignamos la escena al QGraphicsView de la clase # ------------------------------------------------------------------------------------------------- # metodo que verifica cuando se hace click en la escena # ------------------------------------------------------------------------------------------------- def mousePressEvent(self, event): print("clicked") x = event.pos().x() y = event.pos().y() print(x, y) pt = self.mapToScene( event.pos() ) #se escala la posicion de click del QGraphicsView a la escena (QGraphicsScene) root = self.arbolito.get_root() #raiz del arbol if (root != None): rect = QRect( int(pt.x()), int(pt.y()), root.tam, root.tam) # se crea un rectangulo para la colision con el nodo self.__colision(root, rect) # ------------------------------------------------------------------------------------------------- # metodo que verifica si el evento del click se realizo sobre algun nodo # ------------------------------------------------------------------------------------------------- def __colision(self, nodo, rect): #si el nodo entrante fue el clickeado if nodo.rect.intersects(rect): #se muestra un mensaje #con la informacion del nodo-> nombre del procedimiento o funcion msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("Nombre Ambiente: " + str(nodo.info)) msg.exec_() return True else: #si no se mira si se hizo el click en alguno de los hijos for i in nodo.childrens: self.__colision(i, rect) # ------------------------------------------------------------------------------------------------- # metodo que limpia la escena y llama al metodo de pintado del arbol # ------------------------------------------------------------------------------------------------- def dibujar(self): #self.arbolito.get_root().print_tree() self.escena.clear() self.pintar() # ------------------------------------------------------------------------------------------------- # metodo publico que llama el pintado del arbol y sus lineas desde la razi # ------------------------------------------------------------------------------------------------- def pintar(self): root = self.arbolito.get_root() self.y = 50 self.__pintar_arbol(root, 10, self.y) self.__lineas(root) # ------------------------------------------------------------------------------------------------- # metodo que pinta todos los nodos del arbol # ------------------------------------------------------------------------------------------------- def __pintar_arbol(self, nodo, x, y): pen = QPen(Qt.black) #lapiz de nodo normal pen2 = QPen(Qt.green) #lapiz de nodo actual nodo.x = x #se asigna posicion x al nodo nodo.y = self.y #se asigna posicion y al nodo nodo.rect = QRect( nodo.x, nodo.y, nodo.tam, nodo.tam ) # se crea un rectangulo para el nodo,para los eventos click #print("Pos x : ",nodo.x,"Pos y : ",nodo.y," Dato :",nodo.data," Info : ",nodo.info) xp = nodo.tam / 2 #self.escena.addRect(nodo.rect,pen) if nodo.activo: self.escena.addEllipse(nodo.x, nodo.y, nodo.tam, nodo.tam, pen2) else: self.escena.addEllipse(nodo.x, nodo.y, nodo.tam, nodo.tam, pen) #texto del nodo text = self.escena.addText(str(nodo.data)) text.setPos(QPointF(nodo.x + 2, nodo.y - 3)) x += 50 ##pintar los hijos for i in nodo.childrens: self.y += 40 self.__pintar_arbol(i, x, self.y) # ------------------------------------------------------------------------------------------------- # metodo que pinta las lineas de relacion en el arbol # ------------------------------------------------------------------------------------------------- def __lineas(self, nodo): pen = QPen(Qt.black) xp = nodo.tam / 2 for i in nodo.childrens: xl1_a = nodo.x + nodo.tam + 5 yl1_a = nodo.y + nodo.tam - 5 ylb = i.y + xp self.escena.addLine(nodo.x + nodo.tam, yl1_a, xl1_a, yl1_a) self.escena.addLine(xl1_a, yl1_a, xl1_a, ylb, pen) self.escena.addLine(xl1_a, ylb, i.x, ylb, pen) self.__lineas(i)
class MapPainter(object): def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit): super().__init__() self.view = view self.displayCities = displayCities self.displayConnections = displayConnections self.displayBestUnit = displayBestUnit self.problemMap = None self.bestUnit = None self.scene = QGraphicsScene(parent) self.resizeScene() self.view.setScene(self.scene) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def resizeScene(self): height = self.view.size().height() width = self.view.size().width() self.scene.setSceneRect(0.0, 0.0, width, height) def setProblemMap(self, problemMap): self.problemMap = problemMap def setBestUnit(self, unit): self.bestUnit = unit def setDisplayCities(self, enabled=False): self.displayCities = bool(enabled) def setDisplayConnections(self, enabled=False): self.displayConnections = bool(enabled) def setDisplayBestUnit(self, enabled=False): self.displayBestUnit = bool(enabled) def repaint(self): if self.problemMap is None: return self.scene.clear() self.resizeScene() height = self.scene.height() width = self.scene.width() if self.displayCities: cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern) cityPen = QPen(cityBrush, 5.0) for city in self.problemMap.cities: x = width * city.positionX y = height * city.positionY self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush) if self.displayConnections: connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern) connectionPen = QPen(connectionBrush, 1.0) for city in self.problemMap.cities: for neighbour in city.connections: x = width * city.positionX y = height * city.positionY x2 = width * self.problemMap.cities[neighbour].positionX y2 = height * self.problemMap.cities[neighbour].positionY self.scene.addLine(x, y, x2, y2, connectionPen) if self.displayBestUnit and self.bestUnit is not None: bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern) bestUnitPen = QPen(bestUnitBrush, 2.0) for i in range(-1, len(self.bestUnit.path) - 1): currCity = self.problemMap.cities[self.bestUnit.path[i]] nextCity = self.problemMap.cities[self.bestUnit.path[i + 1]] x = width * currCity.positionX y = height * currCity.positionY x2 = width * nextCity.positionX y2 = height * nextCity.positionY self.scene.addLine(x, y, x2, y2, bestUnitPen) self.view.fitInView(self.scene.sceneRect())
class SunMoonWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setupGraphicsScene() self.configuration = tombo.configfile.ConfigFile('sunmoon.conf') self.getConfiguration() self.minimum_interval = self.miscellaneous['minimum_interval'] self.setLocation() self.timer = QTimer() self.setupMethods() self.setCurrentDate() self.setConfigurationText() self.displayedDate = QDateTime(self.ui.deDate.date()) self.show() def setLocation(self): self.location = Location((self.astral['name'], self.astral['region'], float(self.astral['latitude']), float(self.astral['longitude']), self.astral['timezone'], self.astral['elevation'])) def getConfiguration(self): self.astral = self.configuration.getItems('ASTRAL') self.miscellaneous = self.configuration.getItems('MISCELLANEOUS') def setConfigurationText(self): config_label_text_color = "#" + self.miscellaneous['config_text_color'] self.ui.leLatitude.setText(self.astral['latitude']) self.ui.lblLatitude.setText("<font color='" + config_label_text_color + "'>" + self.astral['latitude'] + "</font>") self.ui.leLongitude.setText(self.astral['longitude']) self.ui.lblLongitude.setText("<font color='" + config_label_text_color + "'>" + self.astral['longitude'] + "</font>") self.ui.leElevation.setText(self.astral['elevation']) self.ui.lblElevation.setText("<font color='" + config_label_text_color + "'>" + self.astral['elevation'] + "</font>") self.ui.leLocation.setText(self.astral['name']) self.ui.lblLocation.setText("<font color='" + config_label_text_color + "'>" + self.astral['name'] + "</font>") self.ui.leCountry.setText(self.astral['region']) self.ui.lblRegion.setText("<font color='" + config_label_text_color + "'>" + self.astral['region'] + "</font>") self.ui.leTimeZone.setText(self.astral['timezone']) self.ui.lblTimeZone.setText("<font color='" + config_label_text_color + "'>" + self.astral['timezone'] + "</font>") self.ui.leMinimumInterval.setText(self.miscellaneous['minimum_interval']) self.ui.leTextColor.setText(self.miscellaneous['config_text_color']) def setCurrentDate(self): self.ui.deDate.setDate(QDate.currentDate()) self.displayedDate = QDateTime(self.ui.deDate.date()) def setupGraphicsScene(self): self.scene = QGraphicsScene() self.scene.setBackgroundBrush(Qt.black) self.scene.setSceneRect(0, 0, 209, 169) self.ui.gvMoon.setScene(self.scene) self.brushWhite = QBrush(QColor(Qt.white)) self.brushBlack = QBrush(QColor(Qt.black)) self.pen = QPen(Qt.NoPen) self.ellipseWhite = self.scene.addEllipse(50, 30, 100, 100, self.pen, self.brushWhite) self.ellipseBlack = self.scene.addEllipse(50, 30, 100, 100, self.pen, self.brushBlack) def setupMethods(self): self.ui.deDate.dateChanged.connect(self.setTimes) self.ui.pbStart.clicked.connect(lambda: self.autoStartStop("start")) self.ui.pbStop.clicked.connect(lambda: self.autoStartStop("stop")) self.ui.pbSave.clicked.connect(lambda: self.configActions("save")) self.ui.pbDiscard.clicked.connect(lambda: self.configActions("discard")) self.ui.pbClear.clicked.connect(lambda: self.configActions("clear")) self.timer.timeout.connect(self.advanceDate) self.ui.pbSetCurrentDate.clicked.connect(self.setCurrentDate) #---------------------------------------------------------------------- def configActions(self, action): """Some pushbutton actions route here.""" #print(action) if action == 'clear': self.clearConfigFields() elif action == 'discard': self.clearConfigFields() self.setConfigurationText() elif action == 'save': self.saveConfiguration() #---------------------------------------------------------------------- def saveConfiguration(self): """Save info from config fields.""" self.configuration.setValue('MISCELLANEOUS', 'minimum_interval', self.ui.leMinimumInterval.text()) self.configuration.setValue('MISCELLANEOUS', 'config_text_color', self.ui.leTextColor.text()) self.configuration.setValue('ASTRAL', 'latitude', self.ui.leLatitude.text()) self.configuration.setValue('ASTRAL', 'longitude', self.ui.leLongitude.text()) self.configuration.setValue('ASTRAL', 'elevation', self.ui.leElevation.text()) self.configuration.setValue('ASTRAL', 'timezone', self.ui.leTimeZone.text()) self.configuration.setValue('ASTRAL', 'name', self.ui.leLocation.text()) self.configuration.setValue('ASTRAL', 'region', self.ui.leCountry.text()) self.getConfiguration() self.setConfigurationText() #---------------------------------------------------------------------- def clearConfigFields(self): """Clear text from all config tab fields.""" self.ui.leLatitude.setText('') self.ui.leLongitude.setText('') self.ui.leElevation.setText('') self.ui.leLocation.setText('') self.ui.leCountry.setText('') self.ui.leTimeZone.setText('') self.ui.leMinimumInterval.setText('') self.ui.leTextColor.setText('') #---------------------------------------------------------------------- def discardConfigFields(self): """Clear all config fields and repopulate with original text.""" self.clearConfigFields() self.setConfigurationText() def autoStartStop(self, action): if action == 'start': if self.ui.sbInterval.value() == 0: self.timer.setInterval(int(self.miscellaneous['minimum_interval'])) else: self.timer.setInterval(self.ui.sbInterval.value() * 1000) self.timer.start() elif action == 'stop': self.timer.stop() def advanceDate(self): self.displayedDate = self.displayedDate.addDays(1) self.ui.deDate.setDate(self.displayedDate.date()) def setTimes(self): date_displayed = self.ui.deDate.date().toPyDate() astral_info = self.location.sun(date_displayed) self.ui.leSunrise.setText(astral_info['sunrise'].strftime('%I:%M %p')) self.ui.leSunset.setText(astral_info['sunset'].strftime('%I:%M %p')) self.ui.leDaylight.setText(self.calcDaylight(astral_info['sunset'] - astral_info['sunrise'])) self.ui.leMoonPhase.setText('Day ' + str(self.location.moon_phase(date_displayed, type(float)))) self.setMoonPhase(self.location.moon_phase(date_displayed, type(float))) #print(self.location.moon_phase(date=None, rtype=type(float))) def calcDaylight(self, timedelta): return '{} hours, {} minutes'.format(timedelta.seconds // 3600, (timedelta.seconds // 60) % 60) def setMoonPhase(self, moon_phase): #print(moon_phase) increment = 100 / 14 self.scene.removeItem(self.ellipseBlack) if moon_phase < 15: self.ellipseBlack = self.scene.addEllipse((moon_phase * -increment) + 50, 30, 100, 100, self.pen, self.brushBlack) else: self.ellipseBlack = self.scene.addEllipse(((moon_phase - 28) * -increment) + 50, 30, 100, 100, self.pen, self.brushBlack)
class Battlefield(QGraphicsView): """The graphical battlefield.""" click = pyqtSignal(int) start = pyqtSignal() stop = pyqtSignal() def __init__(self, path: str): super().__init__() self.load_from_file(path) self.possible_colors = {"health": 0, "strength": 1, "braveness": 2} self.unit_size = 10 self.scene = QGraphicsScene() self.grid_size = 50 self.colormap = 0 self.background = QPixmap("gui/fond.png") self.zoom_level = 1 self.selected_unit = 0 self.edit = False self.simu = False self.wait = False self.mousePressEvent = self.on_mousePressEvent self.mouseMoveEvent = self.on_mouseMoveEvent self.mouseReleaseEvent = self.on_mouseReleaseEvent self.setGeometry(300, 300, self.grid_size * 10, self.grid_size * 10) self.setScene(self.scene) self.show() self.draw() def get_specs_tables(self): SPECS = [[[], []], [[], []], [[], []]] for i in range(self.size): speci = [[0, 0], [0, 0], [0, 0], [0, 0]] for unit in self.simulation.units(i): speci[0][unit.side] += 1 speci[1][unit.side] += unit.health speci[2][unit.side] += unit.strength speci[3][unit.side] += unit.braveness for j in range(3): for k in range(2): SPECS[j][k].append(speci[j + 1][k] / speci[0][k]) return SPECS def load_from_file(self, path: str): self.simulation = read_battle(path) self._state = 0 self._size = self.simulation.size def update(self, state_step: int): """Update the graphics and the grid between two steps.""" step_validity = 0 <= self._state + state_step < self.simulation.size if step_validity: self._state += state_step self.draw() return step_validity def go_to_state(self, state): """Move animation to given state.""" if 0 <= state < self.simulation.size: self._state = int(state) self.draw() def zoom(self, precision: float): """Zoom in on the picture.""" self.zoom_level *= precision self.resetCachedContent() self.draw() def get_unit(self, index: int): """Access specific unit.""" return self.simulation.units(self._state)[index] @property def size(self): """Get the size of the simulation.""" return self._size @property def state(self): """Get the current state.""" return self._state def change_colormap(self, color: str): """Change the colormap.""" if color in self.possible_colors: self.colormap = self.possible_colors[color] self.draw() def unit_position(self, unit): """Get screen position of unit.""" return (unit.coords + 10) * self.unit_size * self.zoom_level def on_mousePressEvent(self, event): pos = self.mapToScene(event.pos()) click = np.array((pos.x(), pos.y())) for i, unit in enumerate(self.simulation.units(self.state)): unit_pos = self.unit_position(unit) if np.all(unit_pos <= click) and np.all( click <= unit_pos + self.unit_size): self.click.emit(i) self.selected_unit = i self.draw() break else: # no unit found under pointer pos = event.pos() self.centerOn(pos.x(), pos.y()) def on_mouseMoveEvent(self, event): if self.edit: self.draw() pos = self.mapToScene(event.pos()) self.scene.addRect(pos.x(), pos.y(), self.unit_size, self.unit_size, QPen(), QBrush(QColor(0, 255, 0, 125))) QTest.qWait(10) def on_mouseReleaseEvent(self, event): if self.edit: pos = self.mapToScene(event.pos()) new_x = (pos.x() / (self.zoom_level * self.unit_size)) - 10 new_y = (pos.y() / (self.zoom_level * self.unit_size)) - 10 self.simulation.units( self.state)[self.selected_unit].coords = np.array( [new_x, new_y]) self.draw() if self.simu: self.instant_export() def change_mod(self): self.edit = not (self.edit) def change_simu(self): self.simu = not (self.simu) def gen_color(self, index, unit): """Generate a colormap for unit.""" def specs(unit): if not unit.is_centurion: return [unit.health, unit.strength, unit.braveness] return [0, 0, 0] max_val = max( [specs(unit)[index] for unit in self.simulation.units(0)]) shade = 150 * (specs(unit)[index] / max_val) + 105 color = [0, 0, 0] color[2 * unit.side] = shade return QColor(*color) def draw_unit(self, unit, pen, brush): position = self.unit_position(unit) if unit.reach >= 5: self.scene.addEllipse(*position, *[self.unit_size] * 2, pen, brush) else: self.scene.addRect(*position, *[self.unit_size] * 2, pen, brush) def draw_image(self, image): def shape(dim): return int(dim * (1 + self.zoom_level)) self.scene.addPixmap( image.scaled(*map(shape, (image.width(), image.height())))) def draw(self): """Draw the units and background.""" self.scene.clear() self.draw_image(self.background) # shuffle so that we also see blue units state = self.simulation.units(self.state) for unit in state: if not unit.is_dead: if not unit.is_centurion: color = self.gen_color(self.colormap, unit) else: if unit.side == 0: color = QColor(255, 0, 0) else: color = QColor(0, 0, 255) self.draw_unit(unit, QPen(), QBrush(color)) self.draw_unit(state[self.selected_unit], QPen(), QBrush(QColor(0, 255, 0))) def export(self, name): """To export the current state""" if not (self.wait): self.wait = True self.scene.addRect( -10, -10, int(self.background.width() * (1 + self.zoom_level)), int(self.background.height() * (1 + self.zoom_level)), QPen(), QBrush(QColor(255, 255, 255))) loading = QLabel() gif_load = QMovie("gui/loading.gif") loading.setMovie(gif_load) gif_load.start() self.scene.addWidget(loading) QTest.qWait(200) make_battle(self.simulation.state(self.state), name) QTest.qWait(200) self.draw() self.wait = False def instant_export(self): if not (self.wait): self.export("data/new.txt") self.load_from_file("data/new.txt")
class IdpRecording(QWidget): def __init__(self): super().__init__() # -------------------- First class -------------------- self.main_page = QHBoxLayout(self) self.setLayout(self.main_page) # -------------------- Second class -------------------- # 1. input block (vertical) # 2. instruction block (horizontal) self.input_block = init_container(parent=self.main_page, vertical=True, style=None) self.instruction_block = init_container(parent=self.main_page, vertical=False, style="background-color: white;", size=config.instruction_block_size) # -------------------- third class -------------------- # 1. Input block # 1-1. Interval last # 1-2. Repeats # 1-3. Classes # 1-4. Subject name # 1-5. Training data directory # 1-6. Buttons + help self.interval_last_block, self.interval_slider_view = init_slider_bar_box(self.input_block, label=config.operation_interval_label, max_value=config.recording_interval) self.repeats_block, self.repeat_slider_view = init_slider_bar_box(self.input_block, label=config.operation_repeats_label, max_value=config.repeat_times) self.classes_block, self.classes_textbox = init_inputBox(self.input_block, label=config.operation_classes_label, label_bold=False, default_input=config.indexPen_classes_default) self.subject_name_block, self.subject_names_textbox = init_inputBox(self.input_block, label=config.operation_subject_name_label, label_bold=False, default_input= config.indexPen_subjectName_default) self.training_dir_block, self.training_dir_textbox = init_inputBox(self.input_block, label=config.trainingDataPath_label, label_bold=False, default_input= config.indexPen_trainingDataDir_default) # -------------------- fourth class -------------------- # 1-6. Buttons + help (horizontally distributed) # 1-6-1. Buttons # 1-6-2. Help (message box) self.buttons_block = init_container(self.input_block, vertical=False) self.help_block = init_container(self.input_block) # -------------------- fifth class -------------------- # 1-6-1. Buttons # 1-6-1-1. Interrupt # 1-6-1-2. Start/end test # 1-6-1-3. Start Recording self.interrupt_btn = init_button(parent=self.buttons_block, label=config.interrupt_btn_label, function=self.interrupt_btn_action) self.test_btn = init_button(parent=self.buttons_block, label=config.test_btn_start_label, function=self.test_btn_action) self.recording_btn = init_button(parent=self.buttons_block, label=config.record_btn_start_label, function=self.recording_btn_action) self.help_btn = init_button(parent=self.buttons_block, label=config.help_btn_label, function=help_btn_action) # -------------------- third class -------------------- # 1. Instruction block (horizontal) # 1-1. circles block (vertical) # 1-2. text block (vertical) self.counter_block = init_container(parent=self.instruction_block, vertical=True, size=config.counter_block_size) self.ist_text_block = init_container(parent=self.instruction_block, vertical=True, size=config.ist_text_block_size) # -------------------- fourth class -------------------- # 1-1. circles block (vertical) # 1-1-1. circles_view # 1-1-1-1. circles_scene # 1-1-1-1. 4 circles drawn to the scene self.metronome_scene = QGraphicsScene() self.metronome_view = QGraphicsView(self.metronome_scene) # positions of the four circles # stored for redraw self.x1, self.x2, self.x3, self.x4, self.y1, self.y2, self.y3, self.y4, self.circle_scene_width, \ self.circle_scene_height = self.setup_canvas() # show the circles self.paint(first_circle_colored=False) # -------------------- fourth class -------------------- # 1-2. text block (vertical) # ------- preparation ------- # 1-1-1. "You will be writing: " # char_set ::= A sequence of text the user will write # "Press Enter To Continue" # # ------- forecast ------ # 1-1-1. Label1: Forecast # # ------- record ------ # 1-1-1. Label1: "Write" # character to write # "...next" + next character to write # will be initialized when the user presses enter/return after preparation self.countdown_block, self.countdown_label = None, None # will be initialized when the forecast animation is over self.lb_char_to_write, self.lb_char_next = None, None self.show() # ============================= others ========================== # get input values self.interval = self.interval_slider_view.slider.value() self.repeat_times = self.repeat_slider_view.slider.value() # stored in a list self.classes = self.get_classes() self.subject_name = self.get_subject_name() self.training_dir = self.get_training_data_dir() self.char_set = generate_char_set(self.classes, self.repeat_times) # ======================= indicators, counters ========================== self.state = ['idle'] # see the docstring of self.update_state for details # tracking if the user pressed the return key to start recording self.is_dir_valid = False self.cur_countdown, self.tempo_counter = 0, 0 self.reset_instruction() # =========================== timers ============================= self.timer = QtCore.QTimer() self.timer.setTimerType(QtCore.Qt.PreciseTimer) self.timer.setInterval(self.interval * 1000) self.timer.timeout.connect(self.ticks) self.timer.start() # self.count = 0 # self.start_time = time.time() def update_state(self, action): """ update the current state based on action The working states, as oppose to 'idle' include that of 'pending', 'testing', 'countingDown', 'writing' @param action: str: issued with the following functions with the corresponding value: * self.keyPressEvent(): 'enter_pressed' * self.countdown_tick(): 'countdown_over' * self.test_btn_action(): 'start_test' * self.update_state: 'countdown_over' @@for restarting writing when in test mode @note: you will see that there's a slight pause at the start of writing and the instruction says writing '...', this is an expected behavior as we are not updating the states in a clock, but rather posting to the state changes in function class. It's not a bug, it's a feature! """ if action == 'test_pressed': if 'idle' in self.state: # start the test mode self.idle_to_pending() self.state = ['testing', 'pending'] else: # back to idle self.update_state('interrupt') # this is equivalent to issuing an interrupt action # break pending state and start count down elif action == 'enter_pressed': if 'pending' in self.state: self.state.remove('pending') self.state.append('countingDown') self.pending_to_countdown() elif action == 'countdown_over': if 'countingDown' in self.state: # countingDown may not be in the states if looping in test mode self.state.remove('countingDown') self.state.append('writing') self.countdown_to_writing() elif action == 'writing_over': self.state.remove('writing') if 'testing' in self.state: # restart writing if in test mode self.update_state('countdown_over') elif '': pass # TODO implement writing over when in recording mode else: raise Exception('Unknown State change') elif action == 'interrupt': self.working_to_idle() # working includes that self.state = ['idle'] else: raise Exception('Unknown State change') self.resolve_state() def resolve_state(self): if 'testing' in self.state: self.test_btn.setText(config.test_btn_end_label) self.recording_btn.setDisabled(True) else: self.test_btn.setText(config.test_btn_start_label) self.recording_btn.setDisabled(False) def idle_to_pending(self): self.get_experiment_config() self.char_set = generate_char_set(self.classes, self.repeat_times) init_preparation_block(parent=self.ist_text_block, text=self.char_set) def working_to_idle(self): self.reset_instruction() def pending_to_countdown(self): # clear the preparation text block self.reset_instruction() # create the forecast block self.countdown_block, self.countdown_label = init_countdown_block(self.ist_text_block, label=" ", font=36, bold=True) def countdown_to_writing(self): clear_layout(self.ist_text_block) self.reset_instruction() self.lb_char_to_write, self.lb_char_next = init_instruction_text_block(self.ist_text_block) def keyPressEvent(self, key_event): print(key_event) if is_enter_key_event(key_event): self.update_state('enter_pressed') @pg.QtCore.pyqtSlot() def ticks(self): """ check the current state ticks every 'refresh' milliseconds """ # duration = time.time() - self.start_time # self.count += 1 if 'pending' in self.state: pass elif 'countingDown' in self.state: self.countdown_tick() elif 'writing' in self.state: self.metronome_tick() pass @pg.QtCore.pyqtSlot() def countdown_tick(self): # after the text block shows all countdown texts, stop updating, do nothing and return if self.cur_countdown == len(config.countdown_animation_text): self.cur_countdown += 1 return # wait for a given interval and start the input timer elif self.cur_countdown > len(config.countdown_animation_text): # end of counting down self.update_state('countdown_over') else: self.countdown_label.setText(config.countdown_animation_text[self.cur_countdown]) self.cur_countdown += 1 def metronome_tick(self): # tempo: dah, dih, dih,dih self.repaint(circle=self.tempo_counter % 4 + 1) if not self.tempo_counter % 4: dah() char_count = int(self.tempo_counter / 4) if char_count < len(self.char_set): # draw a new one cur_char = self.char_set[char_count] next_char = 'no Next' if (char_count + 1) == len(self.char_set) else self.char_set[char_count + 1] self.lb_char_to_write.setText(cur_char) self.lb_char_next.setText(config.instruction_next_text + next_char) # finish a recording loop else: self.update_state('writing_over') # must return here to avoid further incrementing the tempo counter, it is reset within update_state() return else: dih() self.tempo_counter += 1 def setup_canvas(self): self.counter_block.addWidget(self.metronome_view) self.metronome_view.resize(config.unit_size, config.WINDOW_HEIGHT / 3) position = self.metronome_view.pos() self.metronome_scene.setSceneRect(position.x(), position.y(), self.metronome_view.width(), self.metronome_view.height()) # size of the scene width = self.metronome_scene.width() height = self.metronome_scene.height() # positions of circles x1, y1 = position.x() + width / 3, position.y() x2, y2 = position.x() + width / 3, position.y() + 3 * (height / 10) x3, y3 = position.x() + width / 3, position.y() + 6 * (height / 10) x4, y4 = position.x() + width / 3, position.y() + 9 * (height / 10) return x1, x2, x3, x4, y1, y2, y3, y4, width, height def repaint(self, circle=1): x = self.x1 y = self.y1 if circle == 1: # remove all current circles for item in self.metronome_scene.items(): self.metronome_scene.removeItem(item) # paint them light gray self.paint() else: if circle == 2: x = self.x2 y = self.y2 elif circle == 3: x = self.x3 y = self.y3 elif circle == 4: x = self.x4 y = self.y4 # locate the circle circle = self.metronome_scene.itemAt(x, y, QTransform()) # remove the original circle if circle: self.metronome_scene.removeItem(circle) # repaint a blue one pen = QPen(Qt.black, 5, Qt.SolidLine) brush = QBrush(Qt.blue, Qt.SolidPattern) self.metronome_scene.addEllipse(x, y, self.circle_scene_width / 3, self.circle_scene_width / 3, pen, brush) def paint(self, first_circle_colored=False): pen = QPen(Qt.black, 5, Qt.SolidLine) brush = QBrush(Qt.lightGray, Qt.SolidPattern) self.metronome_scene.addEllipse(self.x2, self.y2, self.circle_scene_width / 3, self.circle_scene_width / 3, pen, brush) self.metronome_scene.addEllipse(self.x3, self.y3, self.circle_scene_width / 3, self.circle_scene_width / 3, pen, brush) self.metronome_scene.addEllipse(self.x4, self.y4, self.circle_scene_width / 3, self.circle_scene_width / 3, pen, brush) if first_circle_colored: brush = QBrush(Qt.blue, Qt.SolidPattern) self.metronome_scene.addEllipse(self.x1, self.y1, self.circle_scene_width / 3, self.circle_scene_width / 3, pen, brush) def get_experiment_config(self): self.interval = self.interval_slider_view.slider.value() self.repeat_times = self.repeat_slider_view.slider.value() self.classes = self.get_classes() self.subject_name = self.get_subject_name() self.training_dir = self.get_training_data_dir() def get_training_data_dir(self): _user_input = self.training_dir_textbox.text() if not _user_input: _user_input = config.indexPen_trainingDataDir_default return _user_input def get_subject_name(self): _user_input = self.subject_names_textbox.text() if not _user_input: _user_input = config.indexPen_subjectName_default return _user_input def get_classes(self): _user_input = self.classes_textbox.text() if not _user_input: _user_input = config.indexPen_classes_default # change to a list classes = _user_input.split(" ") return classes def interrupt_btn_action(self): self.update_state('interrupt') def test_btn_action(self): self.update_state('test_pressed') def recording_btn_action(self): # TODO implement this action pass # if self.is_recording: # self.reset() # # # if not recording yet # elif not self.is_recording: # # self.get_experiment_config() # # try starting recording # # check the data path first # self.is_dir_valid = self.check_dir_valid() # # if self.is_dir_valid: # # if valid data path, show preparation page # # start recording # self.is_recording = True # self.prepare() # self.recording_btn.setText(config.record_btn_end_label) # self.countdown_timer.start() # # msg = QMessageBox() # msg.setIcon(QMessageBox.Information) # msg.setText("Recording") # msg.exec() def check_dir_valid(self): print(self.training_dir) if os.path.exists(self.training_dir): return True else: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(config.datapath_invalid_message) msg.exec() return False def reset_instruction(self): clear_layout(self.ist_text_block) for item in self.metronome_scene.items(): self.metronome_scene.removeItem(item) self.paint() self.lb_char_next, self.lb_char_to_write = None, None self.cur_countdown, self.tempo_counter = 0, 0
def paint(self, scene: QtWidgets.QGraphicsScene): scene.addEllipse(self.x(), self.y(), 1, 1, self.color, self.color)
class MainFunction(QMainWindow, QObject): def __init__(self): QMainWindow.__init__(self) # define values file upload. value.set_value() self.measureData = [] self.tempMessage = [] self.xlist, self.ylist, self.rlist, self.xclist, self.yclist, self.laserlist = [], [], [], [], [], [] self.tempData = [self.measureData, self.xlist, self.ylist, self.rlist, self.xclist, self.yclist, self.laserlist] self.resultData = data_set.MeasureData(None) # start ui drawing. self.ui = Ui_MainWindow() self.ui.setupUi(self) # set window view size maximum. self.showMaximized() self.message_list = [self.ui.msg_1, self.ui.msg_2, self.ui.msg_3, self.ui.msg_4, self.ui.msg_5] # laser connect state ui values list. self.uiList = [self.ui.img_Rsock, self.ui.img_Lsock, self.ui.img_Bsock] self.uiBList = [self.ui.img_B1, self.ui.img_B2, self.ui.laser_state_B] # laser state ui values list. self.uiLaserList = [self.ui.img_R1, self.ui.img_R2, self.ui.img_R3, self.ui.img_R4, self.ui.img_L1, self.ui.img_L2, self.ui.img_L3, self.ui.img_L4] self.layerlist = [self.ui.layer_R1, self.ui.layer_R2, self.ui.layer_R3, self.ui.layer_R4, self.ui.layer_L1, self.ui.layer_L2, self.ui.layer_L3, self.ui.layer_L4] # set range. self.gScene = QGraphicsScene(0, 0, value.get_frame()/4, value.get_frame()/4, self.ui.graphicsView) self.ui.graphicsView.setScene(self.gScene) # socket connection start self.th = Socket(self, self.uiList) self.th.start() self.dialog = Connection(self.th) self.calculation = Calculation() # setting window set. Setting.setting = Setting(self.th, self.uiBList) Setting.setting.ui = Ui_SettingWindow() Setting.setting.ui.setupUi(Setting.setting) Setting.setting.btnList = [Setting.setting.ui.btn_laser, Setting.setting.ui.btn_chuck_default, Setting.setting.ui.btn_frame_set, Setting.setting.ui.btn_coor_set, Setting.setting.ui.btn_chuck_set, Setting.setting.ui.btn_laser_set] Setting.setting.ui.setting_info.setText('척 기본값 : %s\n프레임 길이 : %d\n좌표계 보정값 : %s\n척 보정값 : %s\n레이저 사이 간격 : %s' % (value.get_chuck(), value.get_frame(), value.get_coor(), value.get_chuck_scale(), value.get_laser())) # drawing basic view --------------------------------------------------------------------------- # ------------------------------------------------------------------------------------------------- # pen, brush setting inside_color = QBrush(Qt.white) pen = QPen(Qt.red) pen.setWidth(4) # make 8 laser lines self.laser = [] line = self.calculation.get_laser_location() for i in range(len(line)): line[i] = line[i] * 0.25 self.laser.append(QGraphicsLineItem(0, (self.gScene.height() / 2-line[i]), self.gScene.width(), (self.gScene.height() / 2-line[i]))) self.laser[i].setPen(pen) self.gScene.addItem(self.laser[i]) # make circle pen.setColor(Qt.blue) self.circle = self.gScene.addEllipse(self.gScene.width() / 2 - 50, self.gScene.height() / 2 - 50, 100, 100, pen, inside_color) self.circle_pot = self.gScene.addEllipse(self.gScene.width() / 2 - 2.25, self.gScene.height() / 2 - 2.25, 5, 5, pen, Qt.blue) # make chuck pot pen.setColor(Qt.red) self.chuck_pot = self.gScene.addEllipse(self.gScene.width() / 2 - 2.25, self.gScene.height() / 2 - 2.25, 5, 5, pen, Qt.red) # make x, y lines self.x_line = QGraphicsLineItem(0, self.gScene.height() / 2, self.gScene.width(), self.gScene.height() / 2) self.gScene.addItem(self.x_line) self.y_line = QGraphicsLineItem(self.gScene.width() / 2, 0, self.gScene.width() / 2, self.gScene.height()) self.gScene.addItem(self.y_line) def slot_menu(self): Setting.setting.show() def slot_exit(self): self.close() def closeEvent(self, event): result = QMessageBox.question(self, 'exit message', '종료하시겠습니까?', QMessageBox.Yes|QMessageBox.No) event.ignore() if result == QMessageBox.Yes: self.th.closet_socket() event.accept() @staticmethod def math_code_distinction(number): if number == 0: return '0' elif number > 0: return '+' else: return '-' def message_setting(self, message): # reset message list : new first old next. for i in range(len(self.message_list)-1, 0, -1): self.message_list[i].setText(self.message_list[i-1].text()) self.message_list[0].setText(message) def double_arr(self, i, fot_int): temp_result = [] for j in range(fot_int): temp = [] for k in range(len(self.tempData[i])): temp.append(self.tempData[i][k][j]) temp.sort() half = int(len(temp) / 2) temp_result.append(temp[half + 1]) return temp_result[:] # 알고리즘 후 max choice. def slot_ok(self): self.chuck_define = Setting.setting.get_chuck() if len(self.chuck_define) != 2: # if system don't have chuck information, you can't start measure program. QMessageBox.question(self, 'Alert Box', '척 기본값을 먼저 셋팅해 주세요.', QMessageBox.Yes) else: # [ change ] image -> text. self.slot_ok_time = time.time() for_int = 0 del self.measureData[:] del self.tempMessage[:] for i in range(len(self.tempData)): del self.tempData[i][:] object_name = self.sender().objectName() if object_name == 'btn_one': for_int = 1 elif object_name == 'btn_all_ten': for_int = 10 else: for_int = 5 circle_scale = value.get_coor() chuck_scale = value.get_chuck_scale() self.resultData = data_set.MeasureData(None) for i in range(for_int): self.measureData.append(self.th.message('$MEASURE\0')) if self.measureData[i] == 'error': while True: self.measureData[i] = self.th.message('$MEASURE\0') if self.measureData[i] != 'error': break for i in range(for_int): laser_length = self.measureData[i] if len(laser_length) == 10: pipe = self.calculation.func_calculation(laser_length) # Scale pipeY, pipeZ, chuck_x, chuck_y. pipeY = pipe[0] - circle_scale[0] pipeZ = pipe[1] - circle_scale[1] chuck_x = (laser_length[-2] - self.chuck_define[0]) - chuck_scale[0] chuck_y = (laser_length[-1] - self.chuck_define[1]) - chuck_scale[1] #chuck_y = (self.chuck_define[1] - laser_length[-1]) - chuck_scale[1] self.tempData[1].append(pipeY) self.tempData[2].append(pipeZ) self.tempData[3].append(pipe[2]) self.tempData[4].append(chuck_x) self.tempData[5].append(chuck_y) self.tempData[6].append(pipe[3]) self.tempMessage.append('\t파이프 좌표 y, z (%d, %d) / 파이프 지름 : %d \n\t척 y, z (%d, %d)\n\t%02d:%02d:%02d' % (-pipeY, pipeZ, pipe[2] * 2, -chuck_x, chuck_y, time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec)) else: self.tempData[1].append('error') self.tempData[2].append('error') self.tempData[3].append(0) self.tempData[4].append('error') self.tempData[5].append('error') self.tempData[6].append([0, 0, 0, 0, 0, 0]) self.tempMessage.append('\t측정이 잘못되었습니다. 측정을 다시 시도해주세요.\n\t%02d:%02d:%02d' %(time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec)) result = [] half = int(for_int/2) for i in range(len(self.tempData)): if object_name == 'btn_one': if self.tempData[i][0] == 'error': self.resultData.errorFlag = True break else: result.append(self.tempData[i][0]) else: if i == 0: result.append(self.double_arr(i, 10)) elif i != len(self.tempData)-1: self.tempData[i].sort() if self.tempData[i][half+1] == 'error': self.resultData.errorFlag = True break else: result.append(self.tempData[i][half]) else: result.append(self.double_arr(i, 6)) if not self.resultData.errorFlag: self.resultData.setting(result) if len(self.measureData) > 0: message = self.resultData.message+'\n\t%02d:%02d:%02d' %(time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec) self.message_setting(message) self.ui.msg_0.setText(('{0}회 측정 최종 값\n'.format(for_int))+message) self.draw() else: self.ui.msg_0.setText('\t측정이 잘못되었습니다. 다시 측정해주세요.\n\t%02d:%02d:%02d' %(time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec)) self.message_setting('\t측정이 잘못되었습니다. 다시 측정해주세요.\n\t%02d:%02d:%02d' %(time.localtime().tm_hour, time.localtime().tm_min, time.localtime().tm_sec)) self.ui.img_LR.setPixmap(QPixmap('Dusan-4/uiFile/non-arrow.png')) self.ui.img_UD.setPixmap(QPixmap('Dusan-4/uiFile/non-arrow.png')) self.ui.information_LR.setText('ㅡ') self.ui.information_UD.setText('ㅡ') def draw(self): if self.resultData is not None: laserLength = self.resultData.laserData pipe_y, pipe_z, pipe_r, chuckY, chuckZ, laser_state, message = self.resultData.getting() print '\n\ndef draw(self) in ---------------------------------------------------------------------------------------' print '\tdraw :: laserLength > %s' % laserLength print '\tdraw :: pipe_y > {0} >> {1}'.format(pipe_y, round(pipe_y)) pipe_y = int(round(pipe_y)) print '\tdraw :: pipe_z > {0} >> {1}'.format(pipe_z, round(pipe_z)) pipe_z = int(round(pipe_z)) print '\tdraw :: pipe_r > ', pipe_r print '\tdraw :: chuckY > {0} >> {1}'.format(chuckY, int(chuckY)) chuckY = int(chuckY) print '\tdraw :: chuckZ > {0} >> {1}'.format(chuckZ, int(chuckZ)) chuckZ = int(chuckZ) print '\tdraw :: laserState > ', laser_state print '\tdraw :: message > ', message print '----------------------------------------------------------------------------------------------------------------\n' # Show lasers measuring data. for i in range(len(laserLength) - 2): self.layerlist[i].display(int(laserLength[i])) # 이후에 대한 내용은 마지막 값에 대한 결과만 표시할 것. if laser_state[-2] == 1: self.ui.img_B1.setPixmap(QPixmap('Dusan-4/uiFile/red-check.png')) else: self.ui.img_B1.setPixmap(QPixmap('Dusan-4/uiFile/uncheck.png')) if laser_state[-1] == 1: self.ui.img_B2.setPixmap(QPixmap('Dusan-4/uiFile/red-check.png')) else: self.ui.img_B2.setPixmap(QPixmap('Dusan-4/uiFile/uncheck.png')) if laser_state[-1] == 1 and laser_state[-2] == 1: self.ui.laser_state_B.setText('후면 레이저의 측정이 완료되었습니다.') else: self.ui.laser_state_B.setText('후면 레이저의 측정을 실패하였습니다.') count = 0 for i in range(len(laser_state)-2): if laser_state[i] == 1: count += 1 self.uiLaserList[i].setPixmap(QPixmap('Dusan-4/uiFile/red-check.png')) self.uiLaserList[i+4].setPixmap(QPixmap('Dusan-4/uiFile/red-check.png')) else: self.uiLaserList[i].setPixmap(QPixmap('Dusan-4/uiFile/uncheck.png')) self.uiLaserList[i+4].setPixmap(QPixmap('Dusan-4/uiFile/uncheck.png')) if count == (len(laser_state)-2): self.ui.laser_state_RL.setText('정확도가 가장 높은 상태입니다.') elif count == 2: self.ui.laser_state_RL.setText('정확도가 가장 낮은 상태입니다.') elif count < 2: self.ui.laser_state_RL.setText('측정을 위해서\n최소 4개의 데이터가 필요합니다.\n재측정 해주세요.') else: if laser_state[0] == 0: self.ui.laser_state_RL.setText('파이프 위치를 조금 위로 조정해주시면\n정확도가 올라갑니다.') elif laser_state[3] == 0: self.ui.laser_state_RL.setText('파이프 위치를 조금 아래로 조정해주시면\n정확도가 올라갑니다.') # 원을 좌표계에 그리기 시작함. self.circle.setRect(self.gScene.width() / 2 - pipe_r, self.gScene.height() / 2 - pipe_r, pipe_r * 2, pipe_r * 2) self.circle.setPos(pipe_y, -pipe_z) self.circle_pot.setPos(pipe_y, -pipe_z) # 척을 좌표계에 그리기 시작함. self.chuck_pot.setPos(chuckY, -chuckZ) # 사용자에게 움직임을 알려줄 UI tip 생성. print(' 좌표 측정 테스트-----------------------------------------------------------------------------------------------') print('\n\tMinus calculation :: %d, %d' % (abs(pipe_y - chuckY), abs(pipe_z - chuckZ))) print('\t차장님 calculation :: %d, %d' % (abs(pipe_y + chuckY), abs(pipe_z - chuckZ))) if self.math_code_distinction(pipe_y) == self.math_code_distinction(chuckY): a = pipe_y - chuckY else: a = pipe_y + chuckY if self.math_code_distinction(pipe_z) == self.math_code_distinction(chuckZ): b = pipe_z - chuckZ else: b = pipe_z + chuckZ print('\tSecond calculation :: {0}, {1}'.format(a, b)) if pipe_y == chuckY: self.ui.information_LR.setText('파이프와 척의 좌우가 일치합니다.') self.ui.img_LR.setPixmap(QPixmap('Dusan-4/uiFile/arrow.png')) elif pipe_y > chuckY: self.ui.information_LR.setText('척을 y- 방향으로 %dmm 이동하세요.' % abs(pipe_y - chuckY)) self.ui.img_LR.setPixmap(QPixmap('Dusan-4/uiFile/left-arrow.png')) else: self.ui.information_LR.setText('척을 y+ 방향으로 %dmm 이동하세요.' % abs(pipe_y - chuckY)) self.ui.img_LR.setPixmap(QPixmap('Dusan-4/uiFile/right-arrow.png')) if pipe_z == chuckZ: self.ui.information_UD.setText('파이프와 척의 상하가 일치합니다.') self.ui.img_UD.setPixmap(QPixmap('Dusan-4/uiFile/arrow.png')) elif pipe_z > chuckZ: self.ui.information_UD.setText('척을 Up 방향으로 %dmm 이동하세요.' % abs(pipe_z - chuckZ)) self.ui.img_UD.setPixmap(QPixmap('Dusan-4/uiFile/up-arrow.png')) else: self.ui.information_UD.setText('척을 Down 방향으로 %dmm 이동하세요.' % abs(pipe_z - chuckZ)) self.ui.img_UD.setPixmap(QPixmap('Dusan-4/uiFile/down-arrow.png')) print '----------------------------------------------------------- end main program : %s' %(self.slot_ok_time - time.time())
class Ui_MainWindow(object): def setupUi(self, MainWindow): self.newDetectionAvailable = False MainWindow.setObjectName("MainWindow") MainWindow.resize(820, 620) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.dropdown_menu = QComboBox(self.centralwidget) font = QtGui.QFont() font.setPointSize(20) self.dropdown_menu.setFont(font) self.dropdown_menu.setGeometry(QtCore.QRect(540, 540, 240, 50)) self.robot_index = 0 for name_ip in NAME_IP_LIST: text = name_ip[0] + ': ' + name_ip[1] self.dropdown_menu.addItem(text) self.ip_addr = NAME_IP_LIST[0][1] self.server_running = True self.server_thread = threading.Thread(target=self.server) self.server_thread.start() font = QtGui.QFont() font.setPointSize(20) self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(10, 10, 800, 431)) self.graphicsView.setObjectName("graphicsView") self.StandardButton = QtWidgets.QPushButton(self.centralwidget) self.StandardButton.setGeometry(QtCore.QRect(60, 470, 170, 60)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.StandardButton.sizePolicy().hasHeightForWidth()) self.StandardButton.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setPointSize(20) self.StandardButton.setFont(font) self.StandardButton.setObjectName("StandardButton") self.AdvancedButton = QtWidgets.QPushButton(self.centralwidget) self.AdvancedButton.setGeometry(QtCore.QRect(570, 470, 170, 60)) font = QtGui.QFont() font.setPointSize(20) self.AdvancedButton.setFont(font) self.AdvancedButton.setObjectName("AdvancedButton") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.LCD = QLCDNumber(self.centralwidget) self.LCD.setGeometry(QtCore.QRect(350, 480, 100, 40)) self.LCD.display(0) self.LCD.setStyleSheet( 'QLCDNumber {background-color: green; color: red;}') self.clockLCD = QLCDNumber(self.centralwidget) self.clockLCD.setGeometry(QtCore.QRect(350, 540, 100, 40)) self.clockLCD.display('3:00') self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) greenBrush = QBrush(Qt.green) #2 single healthy yellowBrush = QBrush(Qt.yellow) #1 single stressed whiteBrush = QBrush(Qt.white) #0 empty blueBrush = QBrush(Qt.blue) #3 double pinkBrush = QBrush(Qt.magenta) #4 tiller self.blackPen = QPen(Qt.black) self.BrushList = [ whiteBrush, yellowBrush, greenBrush, blueBrush, pinkBrush, QBrush(Qt.black) ] self.colorNames = [ 'Empty', 'Stressed', 'Healthy', 'Double', 'Tiller', 'Detection' ] self.level = 0 #standard self.newDetectionAvailable = False self.detectedFieldConfig = 5 * np.ones((4, 16), dtype=np.int8) self.fieldConfig = self.randFieldConfig() self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.AdvancedButton.clicked.connect(self.AdvBtnClickedSlot) self.StandardButton.clicked.connect(self.StdBtnClickedSlot) self.StdBtnClickedSlot() self.drawPlants() self.drawing_timer = QTimer() self.drawing_timer.setInterval(50) self.drawing_timer.timeout.connect(self.updateDetectionResult) self.drawing_timer.start() self.clock_seconds = 0 self.timestamp = '0:00' self.clock_timer = QTimer() self.clock_timer.setInterval(1000) self.clock_timer.timeout.connect(self.updateClock) self.clock_timer.start() self.time_is_up = False app.aboutToQuit.connect(self.closeEvent) def updateClock(self): if self.clock_seconds >= 300: if self.clock_seconds % 2 == 0: self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') else: self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: white; color: red;}') self.clockLCD.display('5:00') self.time_is_up = True else: self.timestamp = str(self.clock_seconds // 60) + ':' sec = self.clock_seconds % 60 self.timestamp += '0' + str(sec) if sec < 10 else str(sec) self.clockLCD.display(self.timestamp) self.clock_seconds += 1 def updateDetectionResult(self): if self.newDetectionAvailable: self.drawPlants() self.newDetectionAvailable = False def closeEvent(self): self.server_running = False self.server_thread.join() def server(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', PORT)) while self.server_running: try: s.settimeout(1) s.listen(1) c, addr = s.accept() if addr[0] != self.ip_addr: c.close() continue with c: while self.server_running: try: c.settimeout(5) msg = c.recv(1024) if len(msg) != 64: c.close() print('invalid msg') break if not self.time_is_up: text = msg.decode('utf-8') self.detectedFieldConfig = np.reshape( np.array(list(text), dtype=np.int8), (4, 16)) upper_limit = 3 if self.level == 0 else 5 self.detectedFieldConfig[ (self.detectedFieldConfig < 0) | (self.detectedFieldConfig >= upper_limit)] = 5 self.newDetectionAvailable = True #f = open("log.txt", "a") #f.write(self.ip_addr+','+self.timestamp+','+msg) #f.close() except socket.timeout: print('client stopped sending updates') c.close() break except socket.error as exc: print(exc) c.close() break except socket.timeout: pass s.close() def drawPlants(self): size = 20 hor_space = 40 ver_space = 100 self.scene.clear() for y in range(4): for x in range(16): plant_type = self.fieldConfig.item((y, x)) r = QtCore.QRectF(QtCore.QPointF(x * hor_space, y * ver_space), QtCore.QSizeF(size, size)) self.scene.addRect(r, self.blackPen, self.BrushList[plant_type]) detected_plant_type = self.detectedFieldConfig.item((y, x)) self.scene.addEllipse(x * hor_space, y * ver_space + 30, size, size, self.blackPen, self.BrushList[detected_plant_type]) # separation line self.scene.addLine( QtCore.QLineF(16.4 * hor_space, 0, 16.4 * hor_space, 350)) # draw a legend for i in range(3 if self.level == 0 else 5): r = QtCore.QRectF( QtCore.QPointF(17 * hor_space, i * ver_space / 2), QtCore.QSizeF(size, size)) self.scene.addRect(r, self.blackPen, self.BrushList[i]) t = self.scene.addText(self.colorNames[i], QFont("Helvetica")) t.setPos(18 * hor_space, i * ver_space / 2) i = 3 if self.level == 0 else 5 self.scene.addEllipse(17 * hor_space, i * ver_space / 2, size, size, self.blackPen, self.BrushList[5]) t = self.scene.addText(self.colorNames[5], QFont("Helvetica")) t.setPos(18 * hor_space, i * ver_space / 2) #calculate the score true_count_per_row = np.count_nonzero( np.logical_and(self.fieldConfig > 0, self.fieldConfig < 5), axis=1) + np.count_nonzero(self.fieldConfig == 3, axis=1) robot_count_per_row = np.count_nonzero( np.logical_and(self.detectedFieldConfig > 0, self.detectedFieldConfig < 5), axis=1) + np.count_nonzero(self.detectedFieldConfig == 3, axis=1) # plant density score error_per_row = np.abs(true_count_per_row - robot_count_per_row) density_score = np.zeros(4, dtype=np.int32) density_score[error_per_row == 0] = 5 density_score[error_per_row == 1] = 3 density_score[error_per_row == 2] = 1 correct_detections = self.fieldConfig[np.equal( self.fieldConfig, self.detectedFieldConfig)] points_for_empty_or_stress = 3 if self.level == 0 else 2 detection_score = points_for_empty_or_stress * len( correct_detections[(correct_detections == 0) | (correct_detections == 1)]) if self.level == 1: detection_score += 4 * len( correct_detections[(correct_detections == 3) | (correct_detections == 4)]) print(detection_score, density_score.sum()) score = detection_score + density_score.sum() self.LCD.display(score) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle( _translate("MainWindow", "2020 ASABE Robotics Competition")) self.StandardButton.setText(_translate("MainWindow", "Standard")) self.AdvancedButton.setText(_translate("MainWindow", "Advanced")) def initialize(self): self.fieldConfig = self.randFieldConfig() self.drawPlants() self.server_running = False self.server_thread.join() self.ip_addr = NAME_IP_LIST[self.dropdown_menu.currentIndex()][1] self.server_thread = threading.Thread(target=self.server) self.server_running = True self.server_thread.start() self.time_is_up = False self.clock_seconds = 0 self.clockLCD.setStyleSheet( 'QLCDNumber {background-color: yellow; color: red;}') def StdBtnClickedSlot(self): self.StandardButton.setStyleSheet("background-color: red") self.AdvancedButton.setStyleSheet("background-color: gray") self.level = 0 self.initialize() def AdvBtnClickedSlot(self): self.AdvancedButton.setStyleSheet("background-color: red") self.StandardButton.setStyleSheet("background-color: gray") self.level = 1 self.initialize() def randFieldConfig(self): #reset robot detection result self.detectedFieldConfig = 5 * np.ones((4, 16), dtype=np.int8) # standard # 0: empty, 12 # 1: single stressed, 8 # 2: single healthy, 44 # advanced # 0: empty, 12 # 1: single stressed, 8 # 2: single healthuy, 36 # 3: double, 4 # 4: tiller, 4 num_single_healthy_plants_per_row = 11 if self.level == 0 else 9 single_healthy_block = 2 * np.ones( (4, num_single_healthy_plants_per_row), dtype=np.int8) num_abnormal_spots = 20 if self.level == 0 else 28 abnormal_spots_array = np.zeros((1, num_abnormal_spots), dtype=np.int8) abnormal_spots_array[0, 12:20] = 1 if self.level == 1: abnormal_spots_array[0, 20:24] = 3 abnormal_spots_array[0, 24:28] = 4 shuffle_by_row = np.vectorize(np.random.permutation, signature='(n)->(n)') abnormal_spots_array = shuffle_by_row(abnormal_spots_array) abnormal_block = np.reshape(abnormal_spots_array, (4, -1)) fieldConfig = np.concatenate((single_healthy_block, abnormal_block), axis=1) fieldConfig = shuffle_by_row(fieldConfig) return fieldConfig
class MyApp(QMainWindow): def __init__(self): super(MyApp, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) #BUTTONS self.ui.addBtn.clicked.connect(self.addButton) self.ui.deleteBtn.clicked.connect(self.deleteButton) self.ui.calcBtn.clicked.connect(self.calc) #TABLE self.table = self.ui.table #DRAWING AREA self.drArea = self.ui.drawArea self.drArea.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.drArea.setSceneRect(0, 0, self.drArea.viewport().width(), self.drArea.viewport().height()) self.scene = QGraphicsScene() self.drArea.setScene(self.scene) def addButton(self): self.table.insertRow(self.ui.table.rowCount()) def deleteButton(self): if self.table.rowCount() > 3: self.table.removeRow(self.table.rowCount() - 1) def calc(self): data = self.getDataFromTable() if data is None: return spline = getSplineBezier(data) self.scene.clear() self.drawLines(spline) self.drawDots(data) def drawLines(self, data): for i in range(len(data) - 1): self.scene.addLine(QtCore.QLineF(data[i][0], data[i][1],\ data[i + 1][0], data[i + 1][1])) def drawDots(self, data): for i in range(len(data)): self.scene.addEllipse( QtCore.QRectF(data[i][0] - 5, data[i][1] - 5, 10, 10)) def getDataFromTable(self): for i in range(self.table.rowCount()): if self.table.item(i, 0) is None or self.table.item(i, 1) is None: return if self.table.item(i, 0).text() is "" or self.table.item( i, 1).text() is "": return data = [] for i in range(self.table.rowCount()): x = float(self.table.item(i, 0).text()) y = float(self.table.item(i, 1).text()) data.append([x, y]) return data
class Paint(QGraphicsView): def __init__(self): QGraphicsView.__init__(self) self.setSceneRect(QRectF(self.viewport().rect())) self.scene = QGraphicsScene() self.paint = False self.put_clusters = False self.isdelete = False self.coords_points = [] self.coords_clusters = [] self.clusters = [] self.points = [] def tools(self, e): x = e.x() y = e.y() if self.paint: brush = QBrush(Qt.SolidPattern) if self.put_clusters: pen = QPen(Qt.blue) self.coords_clusters.append([x, y]) self.clusters.append(self.scene.addEllipse(x, y, 15, 15, pen, brush)) self.scene.addItem(self.clusters[-1]) self.setScene(self.scene) else: pen = QPen(Qt.black) self.coords_points.append([x, y]) self.points.append(self.scene.addEllipse(x, y, 8, 8, pen, brush)) self.scene.addItem(self.points[-1]) self.setScene(self.scene) if self.isdelete: _ = [self.scene.removeItem(item) for item in self.items()] self.isdelete = False def mousePressEvent(self, event): e = QPointF(self.mapToScene(event.pos())) self.tools(e) def redraw_points(self, coords_poins): colors = {0: Qt.black, 1: Qt.green, 2: Qt.cyan, 3: Qt.yellow, 4: Qt.gray, 5: Qt.magenta, 6: Qt.red, 7:Qt.darkYellow} set = [] for i in [list(product([i], set)) for i, set in coords_poins.items()]: set.extend(i) _ = [self.scene.removeItem(item) for item in self.points] self.points.clear() self.scene.clearFocus() brush = QBrush(Qt.SolidPattern) pen = QPen() for point in set: pen.setColor(colors[point[0] % 8]) self.points.append(self.scene.addRect(point[1][0], point[1][1], 10, 10, pen, brush)) self.scene.addItem(self.points[-1])
class MorphingApp(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MorphingApp, self).__init__(parent) self.setupUi(self) self.btnBlend.setEnabled(False) self.chkTriangles.setEnabled(False) self.sliderAlpha.setEnabled(False) self.startSetImg = QGraphicsScene() self.endSetImg = QGraphicsScene() self.Morpher = QGraphicsScene() self.initialPoints = False self.addPoints = False self.comfirm = False # QGraphicsScene() # self.leftImg = #self.rightImg = self.state = "first_state" self.gfxLeft.setScene(self.startSetImg) self.gfxRight.setScene(self.endSetImg) self.gfxBlendImg.setScene(self.Morpher) self.btnStartImg.clicked.connect(self.loadLeftImage) self.btnEndImg.clicked.connect(self.loadRightImage) self.sliderAlpha.valueChanged.connect(self.setAlpha) self.chkTriangles.stateChanged.connect(self.triangulation) self.btnBlend.clicked.connect(self.getImageAtAlpha) self.gfxLeft.mousePressEvent = self.setLeftPoints self.gfxRight.mousePressEvent = self.setRightPoints self.centralwidget.mousePressEvent = self.secondWaySave self.keyPressEvent = self.BackSpace #self.retriangulation() def loadLeftImage(self): """ *** DO NOT MODIFY THIS METHOD! *** Obtain a file name from a file dialog, and pass it on to the loading method. This is to facilitate automated testing. Invoke this method when clicking on the 'load' button. You must modify the method below. """ self.filePath, _ = QFileDialog.getOpenFileName( self, caption='Open JPG file ...', filter="Image (*.jpg *.png)") if not self.filePath: return self.startImage = imageio.imread(self.filePath) self.startSetImg.clear() self.startSetImg.addPixmap(QPixmap(self.filePath)) self.gfxLeft.fitInView(self.startSetImg.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio) self.LeftimgPoints = self.filePath + '.txt' try: fh = open(self.LeftimgPoints, 'r') redPen = QPen(QtCore.Qt.red) redBrush = QBrush(QtCore.Qt.red) self.leftPoints = np.loadtxt(self.LeftimgPoints) self.initialPoints = True for x, y in self.leftPoints: self.startSetImg.addEllipse(x, y, 20, 20, redPen, redBrush) except FileNotFoundError: open(self.LeftimgPoints, 'w').close() self.initialPoints = False self.addPoints = False def loadRightImage(self): """ *** DO NOT MODIFY THIS METHOD! *** Obtain a file name from a file dialog, and pass it on to the loading method. This is to facilitate automated testing. Invoke this method when clicking on the 'load' button. You must modify the method below. """ self.filePath1, _ = QFileDialog.getOpenFileName( self, caption='Open JPG file ...', filter="Image (*.jpg *.png)") if not self.filePath1: return self.endImage = imageio.imread(self.filePath1) self.endSetImg.clear() self.endSetImg.addPixmap(QPixmap(self.filePath1)) self.gfxRight.fitInView(self.endSetImg.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio) self.btnBlend.setEnabled(True) self.chkTriangles.setEnabled(True) self.sliderAlpha.setEnabled(True) self.txtAlpha.setEnabled(True) #load point correspondence self.RightimgPoints = self.filePath1 + '.txt' try: fh = open(self.RightimgPoints, 'r') self.rightPoints = np.loadtxt(self.RightimgPoints) redPen = QPen(QtCore.Qt.red) print(self.rightPoints) redBrush = QBrush(QtCore.Qt.red) self.initialPoints = True for x, y in self.rightPoints: self.endSetImg.addEllipse(x, y, 20, 20, redPen, redBrush) except FileNotFoundError: open(self.RightimgPoints, 'w').close() self.initialPoints = False self.addPoints = False def setAlpha(self): self.txtAlpha.setText(str(self.sliderAlpha.value() / 20.0)) def retriangulation(self): if self.state == "right_set": if self.chkTriangles.isChecked(): self.chkTriangles.setChecked(False) self.chkTriangles.setChecked(True) def triangulation(self): if self.chkTriangles.isChecked() == True: self.tri1 = [] self.tri2 = [] self.leftSimplices = Delaunay(self.leftPoints).simplices if self.initialPoints == True and self.addPoints == True: Pen = QPen(QtCore.Qt.cyan) print(1) elif self.addPoints == True: Pen = QPen(QtCore.Qt.blue) print(2) else: Pen = QPen(QtCore.Qt.red) for triangle in self.leftSimplices.tolist(): #TriLeft = self.leftPoints[triangle] #TriRight = self.rightPoints[triangle] #leftTriangles.append(Tri) # print(self.leftPoints[triangle]) #print(self.leftPoints[triangle[0]]) pointA = QtCore.QPointF(self.leftPoints[triangle[0]][0], self.leftPoints[triangle[0]][1]) PointB = QtCore.QPointF(self.leftPoints[triangle[1]][0], self.leftPoints[triangle[1]][1]) PointC = QtCore.QPointF(self.leftPoints[triangle[2]][0], self.leftPoints[triangle[2]][1]) self.drawTriangle = QtGui.QPolygonF([pointA, PointB, PointC]) self.tri1Item = QGraphicsPolygonItem(self.drawTriangle) self.tri1Item.setPen(Pen) self.startSetImg.addItem(self.tri1Item) self.tri1.append(self.tri1Item) pointAA = QtCore.QPointF(self.rightPoints[triangle[0]][0], self.rightPoints[triangle[0]][1]) PointBB = QtCore.QPointF(self.rightPoints[triangle[1]][0], self.rightPoints[triangle[1]][1]) PointCC = QtCore.QPointF(self.rightPoints[triangle[2]][0], self.rightPoints[triangle[2]][1]) self.drawTriangle1 = QtGui.QPolygonF( [pointAA, PointBB, PointCC]) self.tri2Item = QGraphicsPolygonItem(self.drawTriangle1) self.tri2Item.setPen(Pen) self.endSetImg.addItem(self.tri2Item) self.tri2.append(self.tri2Item) else: #print("111111111") for item1 in self.tri1: self.startSetImg.removeItem(item1) for item2 in self.tri2: self.endSetImg.removeItem(item2) def getImageAtAlpha(self): triangleTuple = loadTriangles(self.filePath + '.txt', self.filePath1 + '.txt') #img = Morpher(leftImage, triangleTuple[0], rightImage, triangleTuple[1]).getImageAtAlpha() alpha = self.sliderAlpha.value() img = Morpher(self.startImage, triangleTuple[0], self.endImage, triangleTuple[1]).getImageAtAlpha(alpha / 20.0) imgQt = QImage(ImageQt.ImageQt(Image.fromarray(img))) result = QPixmap.fromImage(imgQt) self.Morpher.addPixmap(result) self.gfxBlendImg.fitInView(self.Morpher.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio) def secondWaySave(self, e): if self.state == "right_set": self.comfirmPoints() self.state = "first_state" def setLeftPoints(self, e): if self.state == "first_state": ## if it contains points already self.leftPoint = self.gfxLeft.mapToScene(e.pos()) greenPen = QPen(QtCore.Qt.green) greenBrush = QBrush(QtCore.Qt.green) self.leftPointItem = QGraphicsEllipseItem(self.leftPoint.x(), self.leftPoint.y(), 20, 20) self.leftPointItem.setPen(greenPen) self.leftPointItem.setBrush(greenBrush) self.startSetImg.addItem(self.leftPointItem) self.state = "left_set" elif self.state == "right_set": self.comfirmPoints() ## if it contains points already self.leftPoint = self.gfxLeft.mapToScene(e.pos()) greenPen = QPen(QtCore.Qt.green) greenBrush = QBrush(QtCore.Qt.green) self.leftPointItem = QGraphicsEllipseItem(self.leftPoint.x(), self.leftPoint.y(), 20, 20) self.leftPointItem.setPen(greenPen) self.leftPointItem.setBrush(greenBrush) self.startSetImg.addItem(self.leftPointItem) self.state = "left_set" def setRightPoints(self, e): if self.state == "left_set": ## if it contains points already self.rightPoint = self.gfxRight.mapToScene(e.pos()) greenPen = QPen(QtCore.Qt.green) greenBrush = QBrush(QtCore.Qt.green) self.rightPointItem = QGraphicsEllipseItem(self.rightPoint.x(), self.rightPoint.y(), 20, 20) self.rightPointItem.setPen(greenPen) self.rightPointItem.setBrush(greenBrush) self.endSetImg.addItem(self.rightPointItem) self.state = "right_set" def comfirmPoints(self): #print(123) self.addPoints = True self.comfirm = True bluePen = QPen(QtCore.Qt.blue) blueBrush = QBrush(QtCore.Qt.blue) self.startSetImg.removeItem(self.leftPointItem) self.endSetImg.removeItem(self.rightPointItem) self.leftPointItem.setPen(bluePen) self.leftPointItem.setBrush(blueBrush) self.rightPointItem.setPen(bluePen) self.rightPointItem.setBrush(blueBrush) self.endSetImg.addItem(self.rightPointItem) self.startSetImg.addItem(self.leftPointItem) if os.stat(self.LeftimgPoints).st_size == 0 and os.stat( self.RightimgPoints).st_size == 0: self.leftPoints = np.array( [[self.leftPoint.x(), self.leftPoint.y()]]) self.rightPoints = np.array( [[self.rightPoint.x(), self.rightPoint.y()]]) else: self.leftPoints = np.vstack( (self.leftPoints, [self.leftPoint.x(), self.leftPoint.y()])) #self.leftPoints.append([self.leftPoint.x(), self.leftPoint.y()]) #self.rightPoints.append([self.rightPoint.x(), self.rightPoint.y()]) self.rightPoints = np.vstack( (self.rightPoints, [self.rightPoint.x(), self.rightPoint.y()])) self.retriangulation() with open(self.filePath + '.txt', "w") as fin: for point in self.leftPoints.tolist(): fin.write( str((round(point[0], 1))) + ' ' + str((round(point[1], 1))) + '\n') with open(self.filePath1 + '.txt', "w") as fin1: for point in self.rightPoints.tolist(): fin1.write( str((round(point[0], 1))) + ' ' + str((round(point[1], 1))) + '\n') def BackSpace(self, e): key = e.key() if key == QtCore.Qt.Key_Backspace: if self.state == "left_set": self.startSetImg.removeItem(self.leftPointItem) self.state = "first_state" elif self.state == "right_set": self.endSetImg.removeItem(self.rightPointItem) self.state = "left_set"
class Dashboard(QGraphicsView): # Parameters WINDOW_WIDTH = 800 WINDOW_HEIGHT = 480 INACTIVE_COLOR = QColor('#252525') OK_COLOR = Qt.green WARNING_COLOR = Qt.yellow DANGEROUS_COLOR = Qt.red TACHOMETER_GEARS_ARROW_COLOR = Qt.white TACHOMETER_GEARS_NUMBER_COLOR = Qt.black GEAR_NUMBER_COLOR = Qt.white TACHOMETER_SCALING = 100 ACCELEROMETER_MIN_ANGEL = 10 ACCELEROMETER_MAX_ANGEL = 350 # Constructor def __init__(self, initMode: DriveMode) -> None: # Init values self.mode = initMode self.tachometerEngineRpm = 0 # 0 - 9000 self.tachometerEngineLevel = DashboardLevel.inactive self.tachometerGearboxRpm = 0 # 0 - 9000 self.tachometerGearboxLevel = DashboardLevel.inactive self.tachometerGear1Rpm = 0 # 0 - 9000 self.tachometerGear2Rpm = 0 # 0 - 9000 self.tachometerGear3Rpm = 0 # 0 - 9000 self.tachometerGear4Rpm = 0 # 0 - 9000 self.tachometerGear5Rpm = 0 # 0 - 9000 self.accelerometerAngel = 0 # -180 - +180 self.accelerometerValue = 0.0 # 0.0 - 1.0 self.accelerometerLevel = DashboardLevel.inactive self.steeringWheelEncoderAngel = 0 # -7 - +7 self.steeringWheelEncoderLevel = DashboardLevel.inactive self.turnLeftIndicatorLevel = DashboardLevel.inactive self.turnRightIndicatorLevel = DashboardLevel.inactive self.oilWarningIndicatorLevel = DashboardLevel.inactive self.watterWarningIndicatorLevel = DashboardLevel.inactive self.gearNumberValue = 0 # 0 - 5 self.speedometerValue = 0 # 0 - 999 self.speedometerLevel = DashboardLevel.inactive self.stopwatchMills = 0 # 0 - 99 self.stopwatchSeconds = 0 # 0 - 59 self.stopwatchMinutes = 0 # 0 - 59 self.stopwatchHours = 0 # 0 - 9 self.stopwatchLevel = DashboardLevel.inactive self.oilManometerValue = 0.0 # 0.0 - 9.99 self.oilManometerLevel = DashboardLevel.inactive self.oilThermometerValue = 0 # 0 - 999 self.oilThermometerLevel = DashboardLevel.inactive self.watterThermometerValue = 0 # 0 - 999 self.watterThermometerLevel = DashboardLevel.inactive self.odometerValue = 0 # 0 - 9999 self.odometerLevel = DashboardLevel.inactive # Init UI super(Dashboard, self).__init__() viewport = QOpenGLWidget() viewportFormat = QSurfaceFormat() viewportFormat.setSwapInterval(0) # disable VSync viewportFormat.setSamples(2**8) viewportFormat.setDefaultFormat(viewportFormat) viewport.setFormat(viewportFormat) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setGeometry(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setStyleSheet("border: 0px") self.setWindowTitle("Dashboard") self.setWindowFlags(Qt.FramelessWindowHint) self.scene = QGraphicsScene(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setScene(self.scene) self.setViewport(viewport) self.setInteractive(False) self.levelPens = { DashboardLevel.inactive: QPen(self.INACTIVE_COLOR, 1, Qt.SolidLine), DashboardLevel.ok: QPen(self.OK_COLOR, 1, Qt.SolidLine), DashboardLevel.warning: QPen(self.WARNING_COLOR, 1, Qt.SolidLine), DashboardLevel.dangerous: QPen(self.DANGEROUS_COLOR, 1, Qt.SolidLine) } self.levelBrushes = { DashboardLevel.inactive: QBrush(self.INACTIVE_COLOR, Qt.SolidPattern), DashboardLevel.ok: QBrush(self.OK_COLOR, Qt.SolidPattern), DashboardLevel.warning: QBrush(self.WARNING_COLOR, Qt.SolidPattern), DashboardLevel.dangerous: QBrush(self.DANGEROUS_COLOR, Qt.SolidPattern) } # Helpers dirPath = os.path.dirname(os.path.abspath(__file__)) inactivePen = self.levelPens[DashboardLevel.inactive] inactiveBrush = self.levelBrushes[DashboardLevel.inactive] def buildPolygonItem(origin: QPointF, polygon: List[QPointF]): return self.scene.addPolygon( QPolygonF([ QPointF(p.x() + origin.x(), p.y() + origin.y()) for p in polygon ]), inactivePen, inactiveBrush) def makeNumberItems(origin: QPointF, polygon: Dict[str, List[QPointF]]): return {k: buildPolygonItem(origin, p) for k, p in polygon.items()} # Add background self.backgroundPixmaps = { DriveMode.race: QPixmap(os.path.join(dirPath, "background_race.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT), DriveMode.street: QPixmap(os.path.join(dirPath, "background_street.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT) } logging.debug( f"[Dashboard.__init__] Loaded: backgroundPixmaps = {self.backgroundPixmaps}, initMode = {initMode}" ) self.backgroundItem = QGraphicsPixmapItem() self.backgroundItem.setZValue(-1) self.scene.addItem(self.backgroundItem) # Add tachometer graphics self.tachometerEngineItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_ENGINE.items()} self.tachometerGearboxItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_GEARBOX.items()} self.tachometerGearsPens = { "A": QPen(self.TACHOMETER_GEARS_ARROW_COLOR, 1, Qt.SolidLine), "N": QPen(self.TACHOMETER_GEARS_NUMBER_COLOR, 1, Qt.SolidLine) } self.tachometerGearsBrushes = { "A": QBrush(self.TACHOMETER_GEARS_ARROW_COLOR, Qt.SolidPattern), "N": QBrush(self.TACHOMETER_GEARS_NUMBER_COLOR, Qt.SolidPattern) } def makeGearsTransforms(translate: QPointF, rotate: int): arrowTrans = QTransform() arrowTrans.translate(translate.x(), translate.y()) arrowTrans.rotate(rotate) numberTrans = QTransform() numberTrans.translate(translate.x(), translate.y()) return arrowTrans, numberTrans self.tachometerGearsTransforms = \ {k: makeGearsTransforms(p[0], p[1]) for k, p in PolygonsMapping.TACHOMETER_GEARS["T"].items()} def tachometerGearsItem(gearNumber: int): (arrowTrans, numberTrans) = self.tachometerGearsTransforms[0] arrowItem = self.scene.addPolygon( PolygonsMapping.TACHOMETER_GEARS["A"], inactivePen, inactiveBrush) arrowItem.setTransform(arrowTrans) numberItem = buildPolygonItem( PolygonsMapping.TACHOMETER_GEARS["N"]["O"], PolygonsMapping.TACHOMETER_GEARS["N"]["P"][gearNumber]) numberItem.setTransform(numberTrans) return arrowItem, numberItem self.tachometerGearsItems = { 1: tachometerGearsItem(1), 2: tachometerGearsItem(2), 3: tachometerGearsItem(3), 4: tachometerGearsItem(4), 5: tachometerGearsItem(5) } # Add accelerometer graphics def makeEllipse(points: Tuple[QPointF, QPointF]): return self.scene.addEllipse(points[0].x(), points[0].y(), points[1].x() - points[0].x(), points[1].y() - points[0].y(), inactivePen, inactiveBrush) self.accelerometerCenterItem = makeEllipse( PolygonsMapping.ACCELEROMETER["C"]) self.accelerometerSectorItem = makeEllipse( PolygonsMapping.ACCELEROMETER["S"]) self.accelerometerSectorItem.setStartAngle( int((270 - (self.ACCELEROMETER_MIN_ANGEL / 2))) * 16) self.accelerometerSectorItem.setSpanAngle( self.ACCELEROMETER_MIN_ANGEL * 16) # Add steering wheel encoder graphics self.steeringWheelEncoderItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.STEERING_WHEEL_ENCODER.items()} # Add turn indicator graphics def makeTurnIndicatorItem(initCoordinates: Dict[str, Any]): return buildPolygonItem(initCoordinates["C"], initCoordinates["P"]) self.turnIndicatorLeftItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["L"]) self.turnIndicatorRightItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["R"]) # Add warning indicators graphics def makeWarningIndicatorItems(initCoordinates: Dict[str, Any]): return [ buildPolygonItem(initCoordinates["C"], p) for p in initCoordinates["P"] ] self.oilWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["OIL"]) self.watterWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["WATTER"]) # Add gear number graphics self.gearNumberPen = QPen(self.GEAR_NUMBER_COLOR, 1, Qt.SolidLine) self.gearNumberBrush = QBrush(self.GEAR_NUMBER_COLOR, Qt.SolidPattern) self.gearNumberItems = makeNumberItems( PolygonsMapping.GEAR_NUMBER["C"], PolygonsMapping.GEAR_NUMBER["P"]) # Add speedometer graphics self.speedometer001Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[1], PolygonsMapping.SPEED_NUMBERS) self.speedometer010Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[10], PolygonsMapping.SPEED_NUMBERS) self.speedometer100Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[100], PolygonsMapping.SPEED_NUMBERS) # Add stopwatch graphics self.stopwatchMS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchMS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["S01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["S10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM01Items = makeNumberItems( PolygonsMapping.STOPWATCH["M01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM10Items = makeNumberItems( PolygonsMapping.STOPWATCH["M10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchH01Items = makeNumberItems( PolygonsMapping.STOPWATCH["H01"], PolygonsMapping.STANDARD_NUMBERS) # Add oil manometer graphics self.oilManometer0d01Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.01], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer0d10Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.1], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer1d00Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[1], PolygonsMapping.STANDARD_NUMBERS) # Add oil thermometer graphics self.oilThermometer001Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer010Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer100Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add watter thermometer graphics self.watterThermometer001Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer010Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer100Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add odometer graphics self.watterOdometer0001Items = makeNumberItems( PolygonsMapping.ODOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0010Items = makeNumberItems( PolygonsMapping.ODOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0100Items = makeNumberItems( PolygonsMapping.ODOMETER[100], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer1000Items = makeNumberItems( PolygonsMapping.ODOMETER[1000], PolygonsMapping.STANDARD_NUMBERS) # Initial rendering self.renderBackground() self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) self.renderAccelerometer() self.renderSteeringWheelEncoder() self.renderTurnLeftIndicator() self.renderTurnRightIndicator() self.renderOilWarningIndicator() self.renderWatterWarningIndicator() self.renderGearNumber() self.renderSpeedometer() self.renderStopwatch() self.renderOilManometer() self.renderOilThermometer() self.renderWatterThermometer() self.renderOdometer() # Helpers def renderNumberHelper(self, number: int, items: Dict[str, QStandardItem], level: DashboardLevel) -> None: def setLevel(p: QStandardItem, l: DashboardLevel): p.setPen(self.levelPens[l]) p.setBrush(self.levelBrushes[l]) if level != DashboardLevel.inactive: for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][0]: setLevel(items[s], level) for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][1]: setLevel(items[s], DashboardLevel.inactive) else: for _, p in items.items(): setLevel(p, DashboardLevel.inactive) def renderTripleNumberHelper(self, value: int, items001: Dict[str, QStandardItem], items010: Dict[str, QStandardItem], items100: Dict[str, QStandardItem], level: DashboardLevel) -> None: v001 = value % 10 v010 = (value % 100) // 10 v100 = value // 100 self.renderNumberHelper(v001, items001, level) self.renderNumberHelper( v010, items010, level if v010 > 0 or v100 > 0 else DashboardLevel.inactive) self.renderNumberHelper(v100, items100, level if v100 > 0 else DashboardLevel.inactive) # Rendering def renderBackground(self) -> None: logging.debug(f"[Dashboard.renderBackground] For mode = {self.mode}") # Render background pixmap self.backgroundItem.setPixmap(self.backgroundPixmaps[self.mode]) # Re-render all indicators self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) self.renderTachometerGear(1, self.tachometerGear1Rpm) self.renderTachometerGear(2, self.tachometerGear2Rpm) self.renderTachometerGear(3, self.tachometerGear3Rpm) self.renderTachometerGear(4, self.tachometerGear4Rpm) self.renderTachometerGear(5, self.tachometerGear5Rpm) self.renderAccelerometer() self.renderSteeringWheelEncoder() self.renderTurnLeftIndicator() self.renderTurnRightIndicator() self.renderOilWarningIndicator() self.renderWatterWarningIndicator() self.renderGearNumber() self.renderSpeedometer() self.renderStopwatch() self.renderOilManometer() self.renderOilThermometer() self.renderWatterThermometer() self.renderOdometer() def renderTachometerScale(self, items: Dict[int, QStandardItem], rpm: int, level: DashboardLevel) -> None: segment = round(rpm / self.TACHOMETER_SCALING) for k, p in items.items(): if k <= segment: p.setPen(self.levelPens[level]) p.setBrush(self.levelBrushes[level]) else: p.setPen(self.levelPens[DashboardLevel.inactive]) p.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderTachometerGear(self, gearNumber: int, rpm: int) -> None: (arrowItem, numberItem) = self.tachometerGearsItems[gearNumber] segment = ((rpm if rpm <= 8600 else 8600) // 200) * 2 (arrowTrans, numberTrans) = self.tachometerGearsTransforms[segment] arrowItem.setTransform(arrowTrans) arrowItem.setPen(self.tachometerGearsPens["A"]) arrowItem.setBrush(self.tachometerGearsBrushes["A"]) numberItem.setTransform(numberTrans) numberItem.setPen(self.tachometerGearsPens["N"]) numberItem.setBrush(self.tachometerGearsBrushes["N"]) def renderAccelerometer(self) -> None: newPen = self.levelPens[self.accelerometerLevel] newBrush = self.levelBrushes[self.accelerometerLevel] self.accelerometerCenterItem.setPen(newPen) self.accelerometerCenterItem.setBrush(newBrush) self.accelerometerSectorItem.setPen(newPen) self.accelerometerSectorItem.setBrush(newBrush) span = ((self.ACCELEROMETER_MAX_ANGEL - self.ACCELEROMETER_MIN_ANGEL) * self.accelerometerValue)\ + self.ACCELEROMETER_MIN_ANGEL startAngel = self.accelerometerAngel - (span / 2) correctedAngel = ((startAngel - 90) if startAngel >= 90 else (270 + startAngel)) self.accelerometerSectorItem.setStartAngle(int(correctedAngel) * 16) self.accelerometerSectorItem.setSpanAngle(int(span) * 16) def renderSteeringWheelEncoder(self) -> None: angel = self.steeringWheelEncoderAngel for k, p in self.steeringWheelEncoderItems.items(): if (angel == 0 and k == 0) or (abs(k) <= abs(angel) and k != 0 and (k * angel) > 0): p.setPen(self.levelPens[self.steeringWheelEncoderLevel]) p.setBrush(self.levelBrushes[self.steeringWheelEncoderLevel]) else: p.setPen(self.levelPens[DashboardLevel.inactive]) p.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderTurnLeftIndicator(self) -> None: self.turnIndicatorLeftItem.setPen( self.levelPens[self.turnLeftIndicatorLevel]) self.turnIndicatorLeftItem.setBrush( self.levelBrushes[self.turnLeftIndicatorLevel]) def renderTurnRightIndicator(self) -> None: self.turnIndicatorRightItem.setPen( self.levelPens[self.turnRightIndicatorLevel]) self.turnIndicatorRightItem.setBrush( self.levelBrushes[self.turnRightIndicatorLevel]) def renderOilWarningIndicator(self) -> None: for p in self.oilWarningIndicatorItems: p.setPen(self.levelPens[self.oilWarningIndicatorLevel]) p.setBrush(self.levelBrushes[self.oilWarningIndicatorLevel]) def renderWatterWarningIndicator(self) -> None: for p in self.watterWarningIndicatorItems: p.setPen(self.levelPens[self.watterWarningIndicatorLevel]) p.setBrush(self.levelBrushes[self.watterWarningIndicatorLevel]) def renderGearNumber(self) -> None: for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][0]: segment = self.gearNumberItems[s] segment.setPen(self.gearNumberPen) segment.setBrush(self.gearNumberBrush) for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][1]: segment = self.gearNumberItems[s] segment.setPen(self.levelPens[DashboardLevel.inactive]) segment.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderSpeedometer(self) -> None: self.renderTripleNumberHelper(self.speedometerValue, self.speedometer001Items, self.speedometer010Items, self.speedometer100Items, self.speedometerLevel) def renderStopwatch(self) -> None: self.renderNumberHelper(self.stopwatchMills % 10, self.stopwatchMS01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMills // 10, self.stopwatchMS10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchSeconds % 10, self.stopwatchS01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchSeconds // 10, self.stopwatchS10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMinutes % 10, self.stopwatchM01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMinutes // 10, self.stopwatchM10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchHours, self.stopwatchH01Items, self.stopwatchLevel) def renderOilManometer(self) -> None: intValue = int(self.oilManometerValue * 100) self.renderNumberHelper(intValue % 10, self.oilManometer0d01Items, self.oilManometerLevel) self.renderNumberHelper((intValue % 100) // 10, self.oilManometer0d10Items, self.oilManometerLevel) self.renderNumberHelper(intValue // 100, self.oilManometer1d00Items, self.oilManometerLevel) def renderOilThermometer(self) -> None: self.renderTripleNumberHelper(self.oilThermometerValue, self.oilThermometer001Items, self.oilThermometer010Items, self.oilThermometer100Items, self.oilThermometerLevel) def renderWatterThermometer(self) -> None: self.renderTripleNumberHelper(self.watterThermometerValue, self.watterThermometer001Items, self.watterThermometer010Items, self.watterThermometer100Items, self.watterThermometerLevel) def renderOdometer(self) -> None: v0001 = (self.odometerValue % 10) v0010 = (self.odometerValue % 100) // 10 v0100 = (self.odometerValue % 1000) // 100 v1000 = self.odometerValue // 1000 def level(isActive: bool): return self.odometerLevel if isActive > 0 else DashboardLevel.inactive self.renderNumberHelper(v0001, self.watterOdometer0001Items, self.odometerLevel) self.renderNumberHelper(v0010, self.watterOdometer0010Items, level(v0010 > 0 or v0100 > 0 or v1000 > 0)) self.renderNumberHelper(v0100, self.watterOdometer0100Items, level(v0100 > 0 or v1000 > 0)) self.renderNumberHelper(v1000, self.watterOdometer1000Items, level(v1000 > 0)) # Methods @pyqtSlot(DriveMode) def inMode(self, mode: DriveMode) -> None: logging.debug(f"[Dashboard.inMode] New mode = {mode}") # Store new state self.mode = mode # Redraw UI self.renderBackground() @pyqtSlot(int, DashboardLevel) def inTachometerEngine(self, rpm: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inTachometerEngine] New rpm = {rpm}, level = {level}") # Store new state self.tachometerEngineRpm = 0 if rpm < 0 else ( 9000 if rpm > 9000 else rpm) self.tachometerEngineLevel = level # Redraw UI self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) @pyqtSlot(int, DashboardLevel) def inTachometerGearbox(self, rpm: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inTachometerGearbox] New rpm = {rpm}, level = {level}" ) # Store new state self.tachometerGearboxRpm = 0 if rpm < 0 else ( 9000 if rpm > 9000 else rpm) self.tachometerGearboxLevel = level # Redraw UI self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) @pyqtSlot(int, int, int, int, int) def inTachometerGears(self, rpm1: int, rpm2: int, rpm3: int, rpm4: int, rpm5: int) -> None: logging.debug( f"[Dashboard.inTachometerGears] New rpm1 = {rpm1}, rpm2 = {rpm2}, rpm3 = {rpm3}, " f"rpm4 = {rpm4}, rpm5 = {rpm5}") # Store new state self.tachometerGear1Rpm = 0 if rpm1 < 0 else ( 9000 if rpm1 > 9000 else rpm1) self.tachometerGear2Rpm = 0 if rpm2 < 0 else ( 9000 if rpm2 > 9000 else rpm2) self.tachometerGear3Rpm = 0 if rpm3 < 0 else ( 9000 if rpm3 > 9000 else rpm3) self.tachometerGear4Rpm = 0 if rpm4 < 0 else ( 9000 if rpm4 > 9000 else rpm4) self.tachometerGear5Rpm = 0 if rpm5 < 0 else ( 9000 if rpm5 > 9000 else rpm5) # Redraw UI self.renderTachometerGear(1, self.tachometerGear1Rpm) self.renderTachometerGear(2, self.tachometerGear2Rpm) self.renderTachometerGear(3, self.tachometerGear3Rpm) self.renderTachometerGear(4, self.tachometerGear4Rpm) self.renderTachometerGear(5, self.tachometerGear5Rpm) @pyqtSlot(int, float, DashboardLevel) def inAccelerometer(self, angel: int, value: float, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inAccelerometer] New angel = {angel}, value = {value}, level = {level}" ) # Store new state self.accelerometerAngel = -180 if angel < -180 else ( 180 if angel > 180 else angel) self.accelerometerValue = 0.0 if value < 0.0 else ( 1.0 if value > 1.0 else value) self.accelerometerLevel = level # Redraw UI self.renderAccelerometer() @pyqtSlot(int, DashboardLevel) def inSteeringWheelEncoder(self, angel: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inSteeringWheelEncoder] New angel = {angel}, level = {level}" ) # Store new state self.steeringWheelEncoderAngel = -7 if angel < -7 else ( 7 if angel > 7 else angel) self.steeringWheelEncoderLevel = level # Redraw UI self.renderSteeringWheelEncoder() @pyqtSlot(DashboardLevel) def inTurnLeftIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inTurnLeftIndicator] New level = {level}") # Store new state self.turnLeftIndicatorLevel = level # Redraw UI self.renderTurnLeftIndicator() @pyqtSlot(DashboardLevel) def inTurnRightIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inTurnRightIndicator] New level = {level}") # Store new state self.turnRightIndicatorLevel = level # Redraw UI self.renderTurnRightIndicator() @pyqtSlot(int) def inGearNumber(self, value: int) -> None: logging.debug(f"[Dashboard.inGearNumber] New value = {value}") # Store new state self.gearNumberValue = 0 if value < 0 else (5 if value > 5 else value) # Redraw UI self.renderGearNumber() @pyqtSlot(DashboardLevel) def inOilWarningIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inOilWarningIndicator] New level = {level}") # Store new state self.oilWarningIndicatorLevel = level # Redraw UI self.renderOilWarningIndicator() @pyqtSlot(DashboardLevel) def inWatterWarningIndicator(self, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inWatterWarningIndicator] New level = {level}") # Store new state self.watterWarningIndicatorLevel = level # Redraw UI self.renderWatterWarningIndicator() @pyqtSlot(int, DashboardLevel) def inSpeedometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inSpeedometer] New value = {value}, level = {level}") # Store new state self.speedometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.speedometerLevel = level # Redraw UI self.renderSpeedometer() @pyqtSlot(int, int, int, int, DashboardLevel) def inStopwatch(self, mills: int, seconds: int, minutes: int, hours: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inStopwatch] New mills = {mills}, seconds = {seconds}, minutes = {minutes}, " f"hours = {hours}, level = {level}") # Store new state self.stopwatchMills = 0 if mills < 0 else (99 if mills > 99 else mills) self.stopwatchSeconds = 0 if seconds < 0 else ( 59 if seconds > 59 else seconds) self.stopwatchMinutes = 0 if minutes < 0 else ( 59 if minutes > 59 else minutes) self.stopwatchHours = 0 if hours < 0 else (9 if hours > 9 else hours) self.stopwatchLevel = level # Redraw UI self.renderStopwatch() @pyqtSlot(float, DashboardLevel) def inOilManometer(self, value: float, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOilManometer] New value = {value}, level = {level}") # Store new state self.oilManometerValue = 0.0 if value < 0.0 else ( 9.99 if value > 9.99 else value) self.oilManometerLevel = level # Redraw UI self.renderOilManometer() @pyqtSlot(int, DashboardLevel) def inOilThermometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOilThermometer] New value = {value}, level = {level}" ) # Store new state self.oilThermometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.oilThermometerLevel = level # Redraw UI self.renderOilThermometer() @pyqtSlot(int, DashboardLevel) def inWatterThermometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inWatterThermometer] New value = {value}, level = {level}" ) # Store new state self.watterThermometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.watterThermometerLevel = level # Redraw UI self.renderWatterThermometer() @pyqtSlot(int, DashboardLevel) def inOdometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOdometer] New value = {value}, level = {level}") # Store new state self.odometerValue = 0 if value < 0 else ( 9999 if value > 9999 else value) self.odometerLevel = level # Redraw UI self.renderOdometer()
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14 / 15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width() * 0.95 height = self.contentsRect().height() * 0.95 return min(width, height * self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth() * (1 / self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2 * self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5 * baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [ leftOffset + (self.borderRatio + x) * baseWidth for x in range(self.board.size) ] partionHeight = [ topOffset + (self.borderRatio + x) * baseHeight for x in range(self.board.size) ] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size - 1][n] yBot += self.baseWidth * 0.4 / self.baseRectRatio xBot -= self.baseWidth * 0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth * 1.2 yLeft -= self.baseWidth * 0.3 / self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth * 0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x - rad, y - rad, rad * 2.0, rad * 2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale * self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class Paint(QGraphicsView): #clase para crear el plano donde podremos dibujar def __init__(self): QGraphicsView.__init__(self) r = QRectF(self.viewport().rect() ) #área de la ventana en la que se podrá dibujar self.setSceneRect(r) self.scene = QGraphicsScene( ) #escena que debemos añadir al plano de dibujo self.isParticles = False #para dibujar partículas self.penColors = [ Qt.red, QColor.fromRgb(255, 105, 180), Qt.blue, Qt.green ] #lista de colores para el pen (el de rgb es rosa, por si hace falta) self.globalList = [ ] #lista para llevar ordenados los ids de curvas y partículas que se van dibujando en las imgs (para el UNDO) self.N = 10 #número de puntos a partir del cual lo dibujado se corresponde a una curva y no a una partícula self.setScene(self.scene) #para incluir la escena en el plano self.previousPoint = None #para quitar la separación entre puntos cuando se dibuja muy rápido def initIMG(self, filename, scale): self.scene.clear() #con clear() se queda el plano en blanco self.colorN = 0 #comenzamos pintando curvas en rojo self.imgCurves = dict( ) #diccionario para guardar cada curva de la imagen como clave, y como valores su lista de puntos self.imgParticles = dict( ) #diccionario para guardar cada partícula de la imagen como clave, y como valores su lista de puntos self.curveCounter = 1 #contador para indicar la curva self.particleCounter = 1 # contador de partículas self.pointList = [] #lista de puntos para las curvas de la imagen self.particleList = [] #lista de partículas utilsPac.cropImageBorders( filename) #recortar los bordes negros de la imagen img = QImage(filename) #convertir la imagen a QImage imgS = img.scaled(img.width() * scale, img.height() * scale) #ajustar la img a la pantalla self.pixMap = QPixmap().fromImage(imgS) #convertir la imagen a QPixmap scenePix = self.scene.addPixmap( self.pixMap) # añadimos la imagen (escalada) a la escena scenePix.setPos( -350, -70 ) #esto es para que la imagen este en la esquina superior izquierda def draw(self, e, thickness, width=1): #función para pintar con el raton self.pen = QPen( self.penColors[self.colorN] ) #creamos un pen y le asociamos un color de la lista de colores self.pen.setWidth(width) #grosor de la línea brush = QBrush( Qt.SolidPattern) #para que lo que se dibuje no tenga transparencia # incluir el pen a la escena: el pen dibuja círculos (ellipse con altura=thickness y anchura=thickness), el brush los rellena self.scene.addItem( self.scene.addEllipse(e.x(), e.y(), thickness, thickness, self.pen, brush)) self.scene.update() #para actualizar los puntos dibujados con el ratón def mousePressEvent(self, event): #cuando se pulsa el ratón e = QPointF(self.mapToScene( event.pos())) #crear un punto en la posición marcada por el ratón self.previousPoint = ( e.x(), e.y() ) #lo guardamos para poder comprobar su distancia con el siguiente punto self.colorN = 0 #cuando empezamos a dibujar, siempre pintamos en rojo self.pointList.append( (e.x(), e.y())) # añadir el punto a la lista de puntos para las curvas self.draw( e, 1 ) #dibujar el punto de la curva/partícula con una thickness = 1 (grosor del lápiz) def mouseMoveEvent(self, event): #cuando se mueve el ratón mientras está pulsado e = QPointF(self.mapToScene( event.pos())) #crear un punto en la posición marcada por el ratón self.completeWithLine( self.previousPoint, (e.x(), e.y()) ) #completar los puntos con una línea recta si están muy separados self.previousPoint = ( e.x(), e.y() ) #guardamos el punto para poder calcular la distancia con el siguiente self.colorN = 0 #seguimos pintando en rojo self.pointList.append( (e.x(), e.y())) # añadir el punto a la lista de puntos para las curvas self.draw( e, 1 ) #dibujar el punto de la curva/partícula con una thickness = 1 (grosor del lápiz) def mouseReleaseEvent(self, event, scale=None): #cuando se suelta el ratón if len( self.pointList ) > self.N: #si el numero de puntos del trazo es mayor que N (N determina si es curva o partícula)... self.isParticles = False #el trazo dibujado es una curva if not scale == None: #aplicar escala self.pointList = [(x * scale, y * scale) for (x, y) in self.pointList] # terminar la curva con una línea recta start = self.pointList[ 0] #el comienzo de dicha línea sera el primer punto dibujado end = self.pointList[ len(self.pointList) - 1] #el final de dicha línea sera el último punto dibujado self.completeWithLine(start, end) #dibujamos la línea curveN = "curve" + str( self.curveCounter ) #esto será la clave del diccionario (curve1, curve2...) self.curveCounter += 1 #aumentamos el contador de curva # diccionario para asociar una lista de puntos a cada una de las curvas de la imagen self.imgCurves.update({curveN: self.pointList}) #añadir el id de la curva a la lista global self.globalList.append(curveN) # una vez guardados los puntos de una curva, reiniciamos la lista de puntos para poder pintar una nueva curva self.pointList = [] else: self.isParticles = True #el trazo dibujado es una partícula particle = self.pointList.pop( ) #si se han dibujado varios puntos, nos quedamos con el último de ellos p = particle if not scale == None: # aplicar escala p[0] = p[0] * scale p[1] = p[1] * scale particleN = "particle" + str( self.particleCounter ) #clave del diccionario (particle1, particle2...) self.particleCounter += 1 #aumentamos el contador de partículas # diccionario para asociar una lista de puntos a cada una de las partículas de la imagen self.imgParticles.update({particleN: particle}) # añadir el id de la partícula a la lista global self.globalList.append(particleN) # una vez guardados los puntos de una partícula, reiniciamos la lista de puntos para poder pintar nuevas partículas self.pointList = [] self.colorN = 2 #las partículas las pintamos en azul e = QPointF(p[0], p[1]) #creamos un punto en la posición marcada #le restamos 3 píxeles para que el punto se dibuje centrado, justo donde se ha marcado con el ratón e.setX(e.x() - 3) e.setY(e.y() - 3) self.draw( e, 8, 2 ) #pintamos la partícula, con un grosor de lápiz=8, y un radio de brush=2 (para que se vea bien hermosote) def completeWithLine( self, start, end): #función para completar el trazo con líneas rectas startPoint = QPointF( start[0], start[1] ) #creamos un punto con las coordernadas del punto de inicio endPoint = QPointF( end[0], end[1]) #creamos un punto con las coordernadas del punto de fin self.line = QGraphicsLineItem(QLineF( startPoint, endPoint)) #dibujamos una línea con esos ptos # para que la línea se vea bien, la pintamos un poco más gordita self.pen.setWidth(2) self.line.setPen(self.pen) self.scene.addItem(self.line) #añadimos la línea a la escena def loadCurves( self, inputName, scale=None): #función para cargar las curvas de la img actual self.colorN = 0 #las curvas de la img actual van en rojo if os.path.isfile( inputName ): #si hay algún json con curvas de otra sesión anterior... with open( inputName, 'r' ) as f: #lo leemos y escribimos su contenido en el diccionario de curvas de la img s = f.read() self.imgCurves = json.loads(s) if not len(self.imgCurves ) == 0: #si hay alguna curva en el diccionario... self.drawPastCurves( self.imgCurves, 1, scale ) #la dibujamos en la img, con un grosor de lápiz=1 (más finita para que no moleste) else: print("there are no curves for this image") else: print("there's no json file for this image") def loadParticles( self, inputName, scale=None): #función para cargar las partículas de la img actual self.colorN = 2 #las partículas de la img actual van en azul if os.path.isfile( inputName ): #si hay algún json con partículas de otra sesión anterior... with open( inputName, 'r' ) as f: #lo leemos y escribimos su contenido en el diccionario de partículas de la img s = f.read() self.imgParticles = json.loads(s) if not len( self.imgParticles ) == 0: #si hay alguna partícula en el diccionario... self.drawPastParticles( self.imgParticles, 8, scale ) #la dibujamos en la img, con un grosor de lápiz=8 (para que se vean bien) else: print("there are no particles for this image") else: print("there's no json file for this image") def drawPastCurves(self, dic, thickness, scale): #función para pintar las curvas del json for curve, points in dic.items(): #recorremos el diccionario de curvas self.curveCounter += 1 #aumentamos el contador de curva para que las claves del diccionario sigan un orden lógico if not scale == None: # aplicar escala points = [(x / scale, y / scale) for (x, y) in points] for i in range( len(points) - 1 ): #recorremos la lista de puntos pertenecientes a una curva e = QPointF( points[i][0], points[i] [1]) # crear un punto en la posición marcada por el json self.draw(e, thickness) #dibujarlo con el grosor especificado # volver a dibujar los puntos de la curva, sin separaciones entre ellos (para la función completeWithLine) distance = numpy.sqrt(((points[i][0] - points[i + 1][0])**2) + ((points[i][1] - points[i + 1][1])**2)) if distance > 2: #si la distancia euclídea entre ptos consecutivos es muy grande, debemos rellenar el espacio con una línea recta self.completeWithLine(points[i], points[i + 1]) # terminar con una línea recta si se deja de dibujar y la curva no estaba completa start = points[0] end = points[len(points) - 1] self.completeWithLine(start, end) def drawPastParticles(self, dic, thickness, scale): #función para pintar las partículas del json for keyN, particle in dic.items( ): #recorremos el diccionario de partículas self.particleCounter += 1 #aumentamos el contador de partícula para que las claves del diccionario sigan un orden lógico if not scale == None: particle[0] = particle[0] / scale particle[1] = particle[1] / scale e = QPointF( particle[0], particle[1]) #creamos el punto en la posición de la partícula self.draw(e, thickness, 2) #la dibujamos gordita def showPrevCurves( self, currentImg, prevImg): #función para mostrar curvas de la imagen anterior if os.path.isfile(prevImg): #si hay img anterior... with open( prevImg, 'r' ) as f: #leemos su json de curvas y guardamos los ptos en un diccionario s = f.read() dic = json.loads(s) if not len(dic) == 0: #si hay alguna curva... mask = self.generateMask( prevImg, dic) #generamos la máscara de la img y sus curvas img = cv2.imread(currentImg) #leemos la img actual # escalamos esta img con el tamaño de la máscara de la img antetior para que casen bien small = cv2.resize(img, (mask.shape[1], mask.shape[0])) small[ mask == 0] //= 2 #mostramos la img actual oscurecida en los ptos de la máscara que estén a 0 (negro) # volvemos a hacer resize (primero con la Y y luego la X) para mostrar la img en la ventana: img = cv2.resize(small, (img.shape[1], img.shape[0])) head, sep, tail = currentImg.rpartition( "/") #para meterlo en la carpeta data currentImgData = head + "/data/" + tail cv2.imwrite( currentImgData + '_masked.png', img) #guardamos la mascara en un png para comprobar return currentImgData + '_masked.png' #la devolvemos else: #si no hay curvas img = cv2.imread(currentImg) #leemos la img actual img //= 2 #oscurecemos toda la img, puesto que no hay ninguna curva en la img anterior (su máscara sería todo 0's) head, sep, tail = currentImg.rpartition( "/") # para meterlo en la carpeta data currentImgData = head + "/data/" + tail cv2.imwrite( currentImgData + '_masked.png', img) #guardamos la máscara en un png para comprobar return currentImgData + '_masked.png' #la devolvemos else: return currentImg def showPrevParticles( self, inputName, scale=None ): #función para mostrar partículas de la imagen anterior self.colorN = 3 #las pintamos en verde if os.path.isfile( inputName ): #si existe un fichero de partículas de la img anterior, lo leemos y cargamos los ptos en el diccionario with open(inputName, 'r') as f: s = f.read() dic = json.loads(s) if not len( dic ) == 0: #si no está vacío, dibujamos los puntos gorditos self.drawPastParticles(dic, 8, scale) else: print("there are no particles for this image") else: print("there's no json file for this image") def generateMask( self, outputName, dic ): #generar la máscara de una img: 0 negro (fuera de la curva), 255 blanco (area dentro de la curva) if 'particles' not in outputName: #si es curva.. finalMaskCurves = numpy.zeros( (self.pixMap.height(), self.pixMap.width() )) #creamos un array de 0's (toda la máscara negra al ppio) for keyN, points in dic.items(): #recorremos las curvas #para cada curva, generamos su máscara correspondiente mask = utilsPac.getMask( dic[keyN], (self.pixMap.height(), self.pixMap.width() )) #obtenemos la máscara (esta función es la más pesada) finalMaskCurves[ mask] = 255 #los puntos dentro de la curva seran blancos (255) cv2.imwrite(outputName + '_maskCurves.png', finalMaskCurves) return finalMaskCurves else: #si es partícula... finalMaskParticles = numpy.zeros( (self.pixMap.height(), self.pixMap.width() )) #creamos un array de 0's (toda la máscara negra al ppio) for keyN, points in dic.items(): #recorremos las partículas px = int( points[0] ) + 350 #coordenada x de la partícula (hay que sumarle la posición absoluta que le aplicamos a la img al ppio) py = int(points[1]) + 70 #coordenada y #primero la y y luego la x: 'x' son las columnas e 'y' las filas de la matriz de la imagen finalMaskParticles[ py, px] = 255 #ponemos a blanco las posiciones de la máscara en las que hay partícula #cv2.imwrite(outputName + '_maskParticles.png', self.finalMaskParticles) return finalMaskParticles
class MapPainter(object): def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit): super().__init__() self.view = view self.displayCities = displayCities self.displayConnections = displayConnections self.displayBestUnit = displayBestUnit self.problemMap = None self.bestUnit = None self.scene = QGraphicsScene(parent) self.resizeScene() self.view.setScene(self.scene) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def resizeScene(self): height = self.view.size().height() width = self.view.size().width() self.scene.setSceneRect(0.0, 0.0, width, height) def setProblemMap(self, problemMap): self.problemMap = problemMap def setBestUnit(self, unit): self.bestUnit = unit def setDisplayCities(self, enabled = False): self.displayCities = bool(enabled) def setDisplayConnections(self, enabled = False): self.displayConnections = bool(enabled) def setDisplayBestUnit(self, enabled = False): self.displayBestUnit = bool(enabled) def repaint(self): if self.problemMap is None: return self.scene.clear() self.resizeScene() height = self.scene.height() width = self.scene.width() if self.displayCities: cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern) cityPen = QPen(cityBrush, 5.0) for city in self.problemMap.cities: x = width * city.positionX y = height * city.positionY self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush) if self.displayConnections: connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern) connectionPen = QPen(connectionBrush, 1.0) for city in self.problemMap.cities: for neighbour in city.connections: x = width * city.positionX y = height * city.positionY x2 = width * self.problemMap.cities[neighbour].positionX y2 = height * self.problemMap.cities[neighbour].positionY self.scene.addLine(x, y, x2, y2, connectionPen) if self.displayBestUnit and self.bestUnit is not None: bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern) bestUnitPen = QPen(bestUnitBrush, 2.0) for i in range(-1, len(self.bestUnit.path)-1): currCity = self.problemMap.cities[self.bestUnit.path[i]] nextCity = self.problemMap.cities[self.bestUnit.path[i+1]] x = width * currCity.positionX y = height * currCity.positionY x2 = width * nextCity.positionX y2 = height * nextCity.positionY self.scene.addLine(x, y, x2, y2, bestUnitPen) self.view.fitInView(self.scene.sceneRect())
class frameArbol(QGraphicsView): def __init__(self): super(frameArbol, self).__init__() # Inicializar el arbol de entornos self.arbolEntornos = None # Definir la ubicacion inicial en el cuadro de dibujo self.y = 50 # Definir el cuadro de dibujo haciendo uso de librerias externas self.panelDibujo = QGraphicsScene() # Asignar el panelDibujo como escena principal del frame del arbol self.setScene(self.panelDibujo) # Indicar en que momento se debe repintar el canvas principal def drawA(self): self.panelDibujo.clear() self.graficar() # Proceso para graficar el arbol, incluyendo sus ambientes(nodos) y sus aristas def graficar(self): raiz = self.arbolEntornos.getRaiz() self.y = 50 self.graficarArbol(raiz, 10, self.y) self.graficarAristas(raiz) # Sobrescribir el metodo mousePressEvent de la libreria QGraphicsView def mousePressEvent(self, event: eventoRaton) -> None: # Capturar las coordenadas sobre las que se realizo el evento coordenadaX = event.pos().x() coordenadaY = event.pos().y() # Ubicar el evento en la escena definida ubicacion = self.mapToScene(event.pos()) # Obtener la reiz del arbol raiz = self.arbolEntornos.getRaiz() if (raiz != None): # Se crea para poder operar el ambiente, tener acceso a el ambienteN = QRect(int(ubicacion.x()), int(ubicacion.y()), raiz.dimension, raiz.dimension) self.verificarNodo(raiz, ambienteN) # Verificar relacion panel-ambiente def verificarNodo(self, ambienteActual, ambienteBuscar): # Verificar si el ambienteActual buscado es el ambienteActual con el evento mouse if ambienteActual.dibujarN.intersects(ambienteBuscar): # Informacion del ambienteBuscar (ambienteActual)zz mensaje = QMessageBox() mensaje.setIcon(QMessageBox.Information) mensaje.setText("Ambiente: " + str(ambienteActual.contenido)) mensaje.exec_() return True else: # Realizar la busqueda en todos los ambientes (nodos) restantes for i in ambienteActual.hijos: self.verificarNodo(i, ambienteBuscar) # Graficar el arbol generado def graficarArbol(self, ambiente, posX, posY): # Crear los esquemas ara utilizar la libreria nodo1 = QPen(Qt.black) nodo2 = QPen(Qt.green) # Asignar coordenada X y Y al nuevo ambiente ambiente.x = posX ambiente.y = self.y # Crear un modelo de ambiente (nodo) ambiente.dibujarN = QRect(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension) # Definir si el ambiente esta activo para marcarlo con color diferente a los demas if ambiente.nActivo: self.panelDibujo.addEllipse(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension, nodo2) else: self.panelDibujo.addEllipse(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension, nodo1) # Informacion que tendra el ambiente cadena = QGraphicsTextItem() cadena.setPlainText(str(ambiente.nombre)) cadena.setPos(QPointF(ambiente.x + 2, ambiente.y - 3)) posX += 50 # Graficar los hijos del ambiente actual for i in ambiente.hijos: self.y += 40 self.graficarArbol(i, posX, self.y) # Graficar las aristas del arbol def graficarAristas(self, ambiente): linea1 = QPen(Qt.black) puntoIni = ambiente.dimension / 2 for i in ambiente.hijos: posXInicial = ambiente.x + ambiente.dimension + 5 posYInicial = ambiente.y + ambiente.dimension - 5 posYFinal = i.y + puntoIni self.panelDibujo.addLine(ambiente.x + ambiente.dimension, posYInicial, posXInicial, posYInicial) self.panelDibujo.addLine(posXInicial, posYInicial, posXInicial, posYFinal, linea1) self.panelDibujo.addLine(posXInicial, posYFinal, i.x, posYFinal, linea1) self.graficarAristas(i)
class MyWin(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.ui = my.Ui_MainWindow() self.ui.setupUi(self) #self.ui.MainWindow.setFixedWidth(self.ui.geometry.width) self.setWindowIcon(QIcon('./pict/icone.png')) self.setWindowFlags(Qt.Window | Qt.MSWindowsFixedSizeDialogHint) self.ui.graph.setDisabled(True) self.ui.pushButton.clicked.connect(self.createP) self.ui.pushButton_2.clicked.connect(self.createI) self.ui.pushButtonDel.clicked.connect(self.delP) self.ui.pushButtonDel_2.clicked.connect(self.delI) self.ui.pushButton_9.clicked.connect(self.angle) self.ui.pushButton_10.clicked.connect(self.lenght) self.scene = QGraphicsScene() self.ui.graph.setScene(self.scene) self.scene.setSceneRect(0, 0, self.ui.graph.width(), self.ui.graph.height()) self.ui.graph.installEventFilter(self) self.grid(13) self.PointFlag = 0 self.points = list() self.lines = list() self.InteFlag = 0 self.delIflag = 0 self.delPflag = 0 self.Linepenpen = QPen(QColor('#000000'), 2) self.pointpen = QPen(QColor('#ff0000'), 2) self.Linepenpen.style = "DashLine" self.Linepenpen.cap = "RoundCap" def angle(self): self.createmodal('Угол') def lenght(self): self.createmodal('Длина') def createmodal(self, t): modalWindow = QWidget(window, Qt.Window) modalWindow.setWindowTitle(t) modalWindow.resize(250, 40) modalWindow.setWindowModality(Qt.WindowModal) modalWindow.setAttribute(Qt.WA_DeleteOnClose, True) modalWindow.move(window.geometry().center() - modalWindow.rect().center() - QPoint(4, 30)) modLab = QLabel(t) modBut = QPushButton('Применить') lineEdit = QLineEdit() hBox = QHBoxLayout() hBox.addWidget(modLab) hBox.addWidget(lineEdit) hBox.addWidget(modBut) modalWindow.setLayout(hBox) modBut.clicked.connect(modalWindow.close) modalWindow.show() def eventFilter(self, source, event): if (event.type() == QEvent.MouseButtonPress and source is self.ui.graph): if self.PointFlag == 1: pos = event.pos() print('add point: (%d, %d)' % (pos.x(), pos.y())) self.points.append(Point(pos.x(), pos.y())) self.PointFlag = 0 self.painter() if self.delPflag == 1: pos = event.pos() poi = self.getpoint(event.pos()) if poi != None: allline = list() for line in self.lines: if line.P1 == poi or line.P2 == poi: allline.append(line) for line in allline: self.lines.remove(line) self.points.remove(poi) self.delPflag = 0 self.painter() if self.delIflag == 1: pos = event.pos() lin = self.getline(event.pos()) if lin != None: self.lines.remove(lin) self.delIflag = 0 self.painter() if self.InteFlag > 0: if self.InteFlag == 2: lin = Line() if self.getpoint(event.pos()) != None: lin.setP1(self.getpoint(event.pos())) self.lines.append(lin) else: self.InteFlag += 1 else: if self.getpoint(event.pos()) != None: self.lines[-1].setP2(self.getpoint(event.pos())) print('add line()', self.lines[-1].x1(), self.lines[-1].y1(), self.lines[-1].x2(), self.lines[-1].y2()) self.painter() else: self.InteFlag += 1 self.InteFlag -= 1 return QWidget.eventFilter(self, source, event) def painter(self): self.scene.clear() self.grid(13) for point in self.points: self.scene.addEllipse(point.X - 2.5, point.Y - 2.5, 5, 5, self.pointpen) for line in self.lines: self.scene.addLine(line.x1(), line.y1(), line.x2(), line.y2(), self.Linepenpen) self.scene.update() def getpoint(self, a): x = a.x() y = a.y() tolerance = 10 for point in self.points: if abs(point.getX() - x) < tolerance and abs(point.getY() - y) < tolerance: return point return None def getline(self, a): x = a.x() y = a.y() tolerance = 5 for line in self.lines: t = abs(y - (line.y1() + ((line.y2() - line.y1()) * (x - line.x1()) / (line.x2() - line.x1())))) print(t) if t < tolerance: return line return None def grid(self, dxy): pen = QPen() pen.setColor(QColor('#C0C0C0')) for i in range(0, int(self.ui.graph.height() / dxy) + 1): self.scene.addLine(0, dxy * i, self.ui.graph.width(), dxy * i, pen) for i in range(0, int(self.ui.graph.width() / dxy) + 1): self.scene.addLine(dxy * i, 0, dxy * i, self.ui.graph.height(), pen) def delP(self): self.delPflag = 1 self.delIflag = 0 self.PointFlag = 0 self.InteFlag = 0 def delI(self): self.delIflag = 1 self.delPflag = 0 self.PointFlag = 0 self.InteFlag = 0 def createP(self): self.PointFlag = 1 self.delPflag = 0 self.delIflag = 0 self.InteFlag = 0 def createI(self): self.InteFlag = 2 self.delPflag = 0 self.delIflag = 0 self.PointFlag = 0
class Screenshot(QGraphicsView): """ Main Class """ screen_shot_grabed = pyqtSignal(QImage) widget_closed = pyqtSignal() def __init__(self, flags=constant.DEFAULT, parent=None): """ flags: binary flags. see the flags in the constant.py """ super().__init__(parent) # Init self.penColorNow = QColor(PENCOLOR) self.penSizeNow = PENSIZE self.fontNow = QFont('Sans') self.clipboard = QApplication.clipboard() self.drawListResult = [ ] # draw list that sure to be drew, [action, coord] self.drawListProcess = None # the process to the result self.selectedArea = QRect( ) # a QRect instance which stands for the selected area self.selectedAreaRaw = QRect() self.mousePosition = MousePosition.OUTSIDE_AREA # mouse position self.screenPixel = None self.textRect = None self.mousePressed = False self.action = ACTION_SELECT self.mousePoint = self.cursor().pos() self.startX, self.startY = 0, 0 # the point where you start self.endX, self.endY = 0, 0 # the point where you end self.pointPath = QPainterPath( ) # the point mouse passes, used by draw free line self.itemsToRemove = [ ] # the items that should not draw on screenshot picture self.textPosition = None # result self.target_img = None # Init window self.getscreenshot() self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.setMouseTracking(True) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setContentsMargins(0, 0, 0, 0) self.setStyleSheet("QGraphicsView { border-style: none; }") self.tooBar = MyToolBar(flags, self) self.tooBar.trigger.connect(self.changeAction) self.penSetBar = None if flags & constant.RECT or flags & constant.ELLIPSE or flags & constant.LINE or flags & constant.FREEPEN \ or flags & constant.ARROW or flags & constant.TEXT: self.penSetBar = PenSetWidget(self) self.penSetBar.penSizeTrigger.connect(self.changePenSize) self.penSetBar.penColorTrigger.connect(self.changePenColor) self.penSetBar.fontChangeTrigger.connect(self.changeFont) self.textInput = TextInput(self) self.textInput.inputChanged.connect(self.textChange) self.textInput.cancelPressed.connect(self.cancelInput) self.textInput.okPressed.connect(self.okInput) self.graphicsScene = QGraphicsScene(0, 0, self.screenPixel.width(), self.screenPixel.height()) self.show() self.setScene(self.graphicsScene) self.windowHandle().setScreen(QGuiApplication.screenAt(QCursor.pos())) self.scale = self.get_scale() # self.setFixedSize(self.screenPixel.width(), self.screenPixel.height()) self.setGeometry(QGuiApplication.screenAt(QCursor.pos()).geometry()) self.showFullScreen() self.redraw() QShortcut(QKeySequence('ctrl+s'), self).activated.connect(self.saveScreenshot) QShortcut(QKeySequence('esc'), self).activated.connect(self.close) @staticmethod def take_screenshot(flags): loop = QEventLoop() screen_shot = Screenshot(flags) screen_shot.show() screen_shot.widget_closed.connect(loop.quit) loop.exec() img = screen_shot.target_img return img def getscreenshot(self): screen = QGuiApplication.screenAt(QCursor.pos()) self.screenPixel = screen.grabWindow(0) def mousePressEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if event.button() != Qt.LeftButton: return if self.action is None: self.action = ACTION_SELECT self.startX, self.startY = event.x(), event.y() if self.action == ACTION_SELECT: if self.mousePosition == MousePosition.OUTSIDE_AREA: self.mousePressed = True self.selectedArea = QRect() self.selectedArea.setTopLeft(QPoint(event.x(), event.y())) self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() elif self.mousePosition == MousePosition.INSIDE_AREA: self.mousePressed = True else: pass elif self.action == ACTION_MOVE_SELECTED: if self.mousePosition == MousePosition.OUTSIDE_AREA: self.action = ACTION_SELECT self.selectedArea = QRect() self.selectedArea.setTopLeft(QPoint(event.x(), event.y())) self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() self.mousePressed = True elif self.action in DRAW_ACTION: self.mousePressed = True if self.action == ACTION_FREEPEN: self.pointPath = QPainterPath() self.pointPath.moveTo(QPoint(event.x(), event.y())) elif self.action == ACTION_TEXT: if self.textPosition is None: self.textPosition = QPoint(event.x(), event.y()) self.textRect = None self.redraw() def mouseMoveEvent(self, event: QMouseEvent): """ :type event: QMouseEvent :param event: :return: """ self.mousePoint = QPoint(event.globalPos().x(), event.globalPos().y()) if self.action is None: self.action = ACTION_SELECT if not self.mousePressed: point = QPoint(event.x(), event.y()) self.detectMousePosition(point) self.setCursorStyle() self.redraw() else: self.endX, self.endY = event.x(), event.y() # if self.mousePosition != OUTSIDE_AREA: # self.action = ACTION_MOVE_SELECTED if self.action == ACTION_SELECT: self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selectedArea = QRect(self.selectedAreaRaw) if self.mousePosition == MousePosition.INSIDE_AREA: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y() - self.startY + self.selectedArea.top() if 0 <= moveToX <= self.screenPixel.width( ) - 1 - self.selectedArea.width(): self.selectedArea.moveLeft(moveToX) if 0 <= moveToY <= self.screenPixel.height( ) - 1 - self.selectedArea.height(): self.selectedArea.moveTop(moveToY) self.selectedArea = self.selectedArea.normalized() self.selectedAreaRaw = QRect(self.selectedArea) self.startX, self.startY = event.x(), event.y() self.redraw() elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE: moveToX = event.x() - self.startX + self.selectedArea.left( ) if moveToX <= self.selectedArea.right(): self.selectedArea.setLeft(moveToX) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE: moveToX = event.x( ) - self.startX + self.selectedArea.right() self.selectedArea.setRight(moveToX) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_UP_SIDE: moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTop(moveToY) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE: moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottom(moveToY) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTopLeft(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER: moveToX = event.x( ) - self.startX + self.selectedArea.right() moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottomRight(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER: moveToX = event.x( ) - self.startX + self.selectedArea.right() moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTopRight(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottomLeft(QPoint(moveToX, moveToY)) self.redraw() else: pass elif self.action == ACTION_RECT: self.drawRect(self.startX, self.startY, event.x(), event.y(), False) self.redraw() pass elif self.action == ACTION_ELLIPSE: self.drawEllipse(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_ARROW: self.drawArrow(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_LINE: self.drawLine(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_FREEPEN: y1, y2 = event.x(), event.y() rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() self.pointPath.lineTo(y1, y2) self.drawFreeLine(self.pointPath, False) self.redraw() def mouseReleaseEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if event.button() != Qt.LeftButton: return if self.mousePressed: self.mousePressed = False self.endX, self.endY = event.x(), event.y() if self.action == ACTION_SELECT: self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.selectedAreaRaw = QRect(self.selectedArea) self.action = ACTION_MOVE_SELECTED self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selectedAreaRaw = QRect(self.selectedArea) self.redraw() # self.action = None elif self.action == ACTION_RECT: self.drawRect(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_ELLIPSE: self.drawEllipse(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_ARROW: self.drawArrow(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_LINE: self.drawLine(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_FREEPEN: self.drawFreeLine(self.pointPath, True) self.redraw() def detectMousePosition(self, point): """ :type point: QPoint :param point: the mouse position you want to check :return: """ if self.selectedArea == QRect(): self.mousePosition = MousePosition.OUTSIDE_AREA return if self.selectedArea.left() - ERRORRANGE <= point.x( ) <= self.selectedArea.left() and (self.selectedArea.top() - ERRORRANGE <= point.y() <= self.selectedArea.top()): self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER elif self.selectedArea.right() <= point.x() <= self.selectedArea.right( ) + ERRORRANGE and (self.selectedArea.top() - ERRORRANGE <= point.y() <= self.selectedArea.top()): self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER elif self.selectedArea.left() - ERRORRANGE <= point.x( ) <= self.selectedArea.left() and ( self.selectedArea.bottom() <= point.y() <= self.selectedArea.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER elif self.selectedArea.right() <= point.x() <= self.selectedArea.right( ) + ERRORRANGE and (self.selectedArea.bottom() <= point.y() <= self.selectedArea.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER elif -ERRORRANGE <= point.x() - self.selectedArea.left() <= 0 and ( self.selectedArea.topLeft().y() < point.y() < self.selectedArea.bottomLeft().y()): self.mousePosition = MousePosition.ON_THE_LEFT_SIDE elif 0 <= point.x() - self.selectedArea.right() <= ERRORRANGE and ( self.selectedArea.topRight().y() < point.y() < self.selectedArea.bottomRight().y()): self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE elif -ERRORRANGE <= point.y() - self.selectedArea.top() <= 0 and ( self.selectedArea.topLeft().x() < point.x() < self.selectedArea.topRight().x()): self.mousePosition = MousePosition.ON_THE_UP_SIDE elif 0 <= point.y() - self.selectedArea.bottom() <= ERRORRANGE and ( self.selectedArea.bottomLeft().x() < point.x() < self.selectedArea.bottomRight().x()): self.mousePosition = MousePosition.ON_THE_DOWN_SIDE elif not self.selectedArea.contains(point): self.mousePosition = MousePosition.OUTSIDE_AREA else: self.mousePosition = MousePosition.INSIDE_AREA def setCursorStyle(self): if self.action in DRAW_ACTION: self.setCursor(Qt.CrossCursor) return if self.mousePosition == MousePosition.ON_THE_LEFT_SIDE or \ self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE: self.setCursor(Qt.SizeHorCursor) elif self.mousePosition == MousePosition.ON_THE_UP_SIDE or \ self.mousePosition == MousePosition.ON_THE_DOWN_SIDE: self.setCursor(Qt.SizeVerCursor) elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER or \ self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER: self.setCursor(Qt.SizeFDiagCursor) elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER or \ self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER: self.setCursor(Qt.SizeBDiagCursor) elif self.mousePosition == MousePosition.OUTSIDE_AREA: self.setCursor(Qt.ArrowCursor) elif self.mousePosition == MousePosition.INSIDE_AREA: self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.ArrowCursor) pass def drawMagnifier(self): # First, calculate the magnifier position due to the mouse position watchAreaWidth = 16 watchAreaHeight = 16 watchAreaPixmap = QPixmap() cursor_pos = self.mousePoint watchArea = QRect( QPoint(cursor_pos.x() - watchAreaWidth / 2, cursor_pos.y() - watchAreaHeight / 2), QPoint(cursor_pos.x() + watchAreaWidth / 2, cursor_pos.y() + watchAreaHeight / 2)) if watchArea.left() < 0: watchArea.moveLeft(0) watchArea.moveRight(watchAreaWidth) if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width( ): watchArea.moveRight(self.screenPixel.width() - 1) watchArea.moveLeft(watchArea.right() - watchAreaWidth) if self.mousePoint.y() - watchAreaHeight / 2 < 0: watchArea.moveTop(0) watchArea.moveBottom(watchAreaHeight) if self.mousePoint.y( ) + watchAreaHeight / 2 >= self.screenPixel.height(): watchArea.moveBottom(self.screenPixel.height() - 1) watchArea.moveTop(watchArea.bottom() - watchAreaHeight) # tricks to solve the hidpi impact on QCursor.pos() watchArea.setTopLeft( QPoint(watchArea.topLeft().x() * self.scale, watchArea.topLeft().y() * self.scale)) watchArea.setBottomRight( QPoint(watchArea.bottomRight().x() * self.scale, watchArea.bottomRight().y() * self.scale)) watchAreaPixmap = self.screenPixel.copy(watchArea) # second, calculate the magnifier area magnifierAreaWidth = watchAreaWidth * 10 magnifierAreaHeight = watchAreaHeight * 10 fontAreaHeight = 40 cursorSize = 24 magnifierArea = QRectF( QPoint(QCursor.pos().x() + cursorSize, QCursor.pos().y() + cursorSize), QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth, QCursor.pos().y() + cursorSize + magnifierAreaHeight)) if magnifierArea.right() >= self.screenPixel.width(): magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth - cursorSize / 2) if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height( ): magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight - cursorSize / 2 - fontAreaHeight) # third, draw the watch area to magnifier area watchAreaScaled = watchAreaPixmap.scaled( QSize(magnifierAreaWidth * self.scale, magnifierAreaHeight * self.scale)) magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled) magnifierPixmap.setOffset(magnifierArea.topLeft()) # then draw lines and text self.graphicsScene.addRect(QRectF(magnifierArea), QPen(QColor(255, 255, 255), 2)) self.graphicsScene.addLine( QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()), QPointF(magnifierArea.center().x(), magnifierArea.bottom())), QPen(QColor(0, 255, 255), 2)) self.graphicsScene.addLine( QLineF(QPointF(magnifierArea.left(), magnifierArea.center().y()), QPointF(magnifierArea.right(), magnifierArea.center().y())), QPen(QColor(0, 255, 255), 2)) # get the rgb of mouse point pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint)) # draw information self.graphicsScene.addRect( QRectF( magnifierArea.bottomLeft(), magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)), Qt.black, QBrush(Qt.black)) rgbInfo = self.graphicsScene.addSimpleText( ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(), pointRgb.blue())) rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5)) rgbInfo.setPen(QPen(QColor(255, 255, 255), 2)) rect = self.selectedArea.normalized() sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format( rect.width() * self.scale, rect.height() * self.scale)) sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) + QPoint(0, fontAreaHeight / 2)) sizeInfo.setPen(QPen(QColor(255, 255, 255), 2)) def get_scale(self): return self.devicePixelRatio() def saveScreenshot(self, clipboard=False, fileName='screenshot.png', picType='png'): fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1) selected = QRect(self.selectedArea) if selected.left() < 0: selected.setLeft(0) if selected.right() >= self.width(): selected.setRight(self.width() - 1) if selected.top() < 0: selected.setTop(0) if selected.bottom() >= self.height(): selected.setBottom(self.height() - 1) source = (fullWindow & selected) source.setTopLeft( QPoint(source.topLeft().x() * self.scale, source.topLeft().y() * self.scale)) source.setBottomRight( QPoint(source.bottomRight().x() * self.scale, source.bottomRight().y() * self.scale)) image = self.screenPixel.copy(source) image.setDevicePixelRatio(1) if clipboard: QGuiApplication.clipboard().setImage(QImage(image), QClipboard.Clipboard) else: image.save(fileName, picType, 10) self.target_img = image self.screen_shot_grabed.emit(QImage(image)) def redraw(self): self.graphicsScene.clear() # draw screenshot self.graphicsScene.addPixmap(self.screenPixel) # prepare for drawing selected area rect = QRectF(self.selectedArea) rect = rect.normalized() topLeftPoint = rect.topLeft() topRightPoint = rect.topRight() bottomLeftPoint = rect.bottomLeft() bottomRightPoint = rect.bottomRight() topMiddlePoint = (topLeftPoint + topRightPoint) / 2 leftMiddlePoint = (topLeftPoint + bottomLeftPoint) / 2 bottomMiddlePoint = (bottomLeftPoint + bottomRightPoint) / 2 rightMiddlePoint = (topRightPoint + bottomRightPoint) / 2 # draw the picture mask mask = QColor(0, 0, 0, 155) if self.selectedArea == QRect(): self.graphicsScene.addRect(0, 0, self.screenPixel.width(), self.screenPixel.height(), QPen(Qt.NoPen), mask) else: self.graphicsScene.addRect(0, 0, self.screenPixel.width(), topRightPoint.y(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect(0, topLeftPoint.y(), topLeftPoint.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect( topRightPoint.x(), topRightPoint.y(), self.screenPixel.width() - topRightPoint.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect( 0, bottomLeftPoint.y(), self.screenPixel.width(), self.screenPixel.height() - bottomLeftPoint.y(), QPen(Qt.NoPen), mask) # draw the toolBar if self.action != ACTION_SELECT: spacing = 5 # show the toolbar first, then move it to the correct position # because the width of it may be wrong if this is the first time it shows self.tooBar.show() dest = QPointF(rect.bottomRight() - QPointF(self.tooBar.width(), 0) - QPointF(spacing, -spacing)) if dest.x() < spacing: dest.setX(spacing) pen_set_bar_height = self.penSetBar.height( ) if self.penSetBar is not None else 0 if dest.y() + self.tooBar.height( ) + pen_set_bar_height >= self.height(): if rect.top() - self.tooBar.height( ) - pen_set_bar_height < spacing: dest.setY(rect.top() + spacing) else: dest.setY(rect.top() - self.tooBar.height() - pen_set_bar_height - spacing) self.tooBar.move(dest.toPoint()) if self.penSetBar is not None: self.penSetBar.show() self.penSetBar.move(dest.toPoint() + QPoint(0, self.tooBar.height() + spacing)) if self.action == ACTION_TEXT: self.penSetBar.showFontWidget() else: self.penSetBar.showPenWidget() else: self.tooBar.hide() if self.penSetBar is not None: self.penSetBar.hide() # draw the list for step in self.drawListResult: self.drawOneStep(step) if self.drawListProcess is not None: self.drawOneStep(self.drawListProcess) if self.action != ACTION_TEXT: self.drawListProcess = None if self.selectedArea != QRect(): self.itemsToRemove = [] # draw the selected rectangle pen = QPen(QColor(0, 255, 255), 2) self.itemsToRemove.append(self.graphicsScene.addRect(rect, pen)) # draw the drag point radius = QPoint(3, 3) brush = QBrush(QColor(0, 255, 255)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topLeftPoint - radius, topLeftPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topMiddlePoint - radius, topMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topRightPoint - radius, topRightPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(leftMiddlePoint - radius, leftMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(rightMiddlePoint - radius, rightMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomLeftPoint - radius, bottomLeftPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomMiddlePoint - radius, bottomMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomRightPoint - radius, bottomRightPoint + radius), pen, brush)) # draw the textedit if self.textPosition is not None: textSpacing = 50 position = QPoint() if self.textPosition.x() + self.textInput.width( ) >= self.screenPixel.width(): position.setX(self.textPosition.x() - self.textInput.width()) else: position.setX(self.textPosition.x()) if self.textRect is not None: if self.textPosition.y() + self.textInput.height( ) + self.textRect.height() >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height() - self.textRect.height()) else: position.setY(self.textPosition.y() + self.textRect.height()) else: if self.textPosition.y() + self.textInput.height( ) >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height()) else: position.setY(self.textPosition.y()) self.textInput.move(position) self.textInput.show() # self.textInput.getFocus() # draw the magnifier if self.action == ACTION_SELECT: self.drawMagnifier() if self.mousePressed: self.drawSizeInfo() if self.action == ACTION_MOVE_SELECTED: self.drawSizeInfo() # deal with every step in drawList def drawOneStep(self, step): """ :type step: tuple """ if step[0] == ACTION_RECT: self.graphicsScene.addRect( QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_ELLIPSE: self.graphicsScene.addEllipse( QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_ARROW: arrow = QPolygonF() linex = float(step[1] - step[3]) liney = float(step[2] - step[4]) line = sqrt(pow(linex, 2) + pow(liney, 2)) # in case to divided by 0 if line == 0: return sinAngel = liney / line cosAngel = linex / line # sideLength is the length of bottom side of the body of an arrow # arrowSize is the size of the head of an arrow, left and right # sides' size is arrowSize, and the bottom side's size is arrowSize / 2 sideLength = step[5].width() arrowSize = 8 bottomSize = arrowSize / 2 tmpPoint = QPointF(step[3] + arrowSize * sideLength * cosAngel, step[4] + arrowSize * sideLength * sinAngel) point1 = QPointF(step[1] + sideLength * sinAngel, step[2] - sideLength * cosAngel) point2 = QPointF(step[1] - sideLength * sinAngel, step[2] + sideLength * cosAngel) point3 = QPointF(tmpPoint.x() - sideLength * sinAngel, tmpPoint.y() + sideLength * cosAngel) point4 = QPointF(tmpPoint.x() - bottomSize * sideLength * sinAngel, tmpPoint.y() + bottomSize * sideLength * cosAngel) point5 = QPointF(step[3], step[4]) point6 = QPointF(tmpPoint.x() + bottomSize * sideLength * sinAngel, tmpPoint.y() - bottomSize * sideLength * cosAngel) point7 = QPointF(tmpPoint.x() + sideLength * sinAngel, tmpPoint.y() - sideLength * cosAngel) arrow.append(point1) arrow.append(point2) arrow.append(point3) arrow.append(point4) arrow.append(point5) arrow.append(point6) arrow.append(point7) arrow.append(point1) self.graphicsScene.addPolygon(arrow, step[5], step[6]) elif step[0] == ACTION_LINE: self.graphicsScene.addLine( QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_FREEPEN: self.graphicsScene.addPath(step[1], step[2]) elif step[0] == ACTION_TEXT: textAdd = self.graphicsScene.addSimpleText(step[1], step[2]) textAdd.setPos(step[3]) textAdd.setBrush(QBrush(step[4])) self.textRect = textAdd.boundingRect() # draw the size information on the top left corner def drawSizeInfo(self): sizeInfoAreaWidth = 200 sizeInfoAreaHeight = 30 spacing = 5 rect = self.selectedArea.normalized() sizeInfoArea = QRect(rect.left(), rect.top() - spacing - sizeInfoAreaHeight, sizeInfoAreaWidth, sizeInfoAreaHeight) if sizeInfoArea.top() < 0: sizeInfoArea.moveTopLeft(rect.topLeft() + QPoint(spacing, spacing)) if sizeInfoArea.right() >= self.screenPixel.width(): sizeInfoArea.moveTopLeft(rect.topLeft() - QPoint(spacing, spacing) - QPoint(sizeInfoAreaWidth, 0)) if sizeInfoArea.left() < spacing: sizeInfoArea.moveLeft(spacing) if sizeInfoArea.top() < spacing: sizeInfoArea.moveTop(spacing) self.itemsToRemove.append( self.graphicsScene.addRect(QRectF(sizeInfoArea), Qt.white, QBrush(Qt.black))) sizeInfo = self.graphicsScene.addSimpleText(' {0} x {1}'.format( rect.width() * self.scale, rect.height() * self.scale)) sizeInfo.setPos(sizeInfoArea.topLeft() + QPoint(0, 2)) sizeInfo.setPen(QPen(QColor(255, 255, 255), 2)) self.itemsToRemove.append(sizeInfo) def drawRect(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized() resultRect = rect & tmpRect tmp = [ ACTION_RECT, resultRect.topLeft().x(), resultRect.topLeft().y(), resultRect.bottomRight().x(), resultRect.bottomRight().y(), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawEllipse(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized() resultRect = rect & tmpRect tmp = [ ACTION_ELLIPSE, resultRect.topLeft().x(), resultRect.topLeft().y(), resultRect.bottomRight().x(), resultRect.bottomRight().y(), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawArrow(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() tmp = [ ACTION_ARROW, x1, x2, y1, y2, QPen(QColor(self.penColorNow), int(self.penSizeNow)), QBrush(QColor(self.penColorNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawLine(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() tmp = [ ACTION_LINE, x1, x2, y1, y2, QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawFreeLine(self, pointPath, result): tmp = [ ACTION_FREEPEN, QPainterPath(pointPath), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def textChange(self): if self.textPosition is None: return self.text = self.textInput.getText() self.drawListProcess = [ ACTION_TEXT, str(self.text), QFont(self.fontNow), QPoint(self.textPosition), QColor(self.penColorNow) ] self.redraw() def undoOperation(self): if len(self.drawListResult) == 0: self.action = ACTION_SELECT self.selectedArea = QRect() self.selectedAreaRaw = QRect() self.tooBar.hide() if self.penSetBar is not None: self.penSetBar.hide() else: self.drawListResult.pop() self.redraw() def saveOperation(self): filename = QFileDialog.getSaveFileName(self, 'Save file', './screenshot.png', '*.png;;*.jpg') if len(filename[0]) == 0: return else: self.saveScreenshot(False, filename[0], filename[1][2:]) self.close() def close(self): self.widget_closed.emit() super().close() self.tooBar.close() if self.penSetBar is not None: self.penSetBar.close() def saveToClipboard(self): QApplication.clipboard().setText('Test in save function') self.saveScreenshot(True) self.close() # slots def changeAction(self, nextAction): QApplication.clipboard().setText('Test in changeAction function') if nextAction == ACTION_UNDO: self.undoOperation() elif nextAction == ACTION_SAVE: self.saveOperation() elif nextAction == ACTION_CANCEL: self.close() elif nextAction == ACTION_SURE: self.saveToClipboard() else: self.action = nextAction self.setFocus() def changePenSize(self, nextPenSize): self.penSizeNow = nextPenSize def changePenColor(self, nextPenColor): self.penColorNow = nextPenColor def cancelInput(self): self.drawListProcess = None self.textPosition = None self.textRect = None self.textInput.hide() self.textInput.clearText() self.redraw() def okInput(self): self.text = self.textInput.getText() self.drawListResult.append([ ACTION_TEXT, str(self.text), QFont(self.fontNow), QPoint(self.textPosition), QColor(self.penColorNow) ]) self.textPosition = None self.textRect = None self.textInput.hide() self.textInput.clearText() self.redraw() def changeFont(self, font): self.fontNow = font
class InitialPoseDialog(QDialog, Ui_PoseDialog): data_manager = None image = None y_line = 0 y_top_line = 0 y_lower_line = 0 landmark_size = 2 lines = None middle_idx = 0 pose_model = None def __init__(self, data_manager): super(InitialPoseDialog, self).__init__() self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) assert isinstance(data_manager, DataManager) self.data_manager = data_manager self.pose_model = InitialPoseModel(data_manager) self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.image = Filter.crop_image(self.data_manager.radiographs[0].image) self.findButton.clicked.connect(self.find_jaw_divider) self.openButton.clicked.connect(self._open_radiograph) self._redraw() def find_jaw_divider(self): self.y_top_line, self.y_lower_line = self.pose_model._find_jaw_separation_line(self.pose_model._crop_image_sides(self.image)) upper_jaw_image = self.pose_model.crop_upper_jaw(self.image, self.y_top_line) lower_jaw_image = self.pose_model.crop_lower_jaw(self.image, self.y_lower_line) # Filter the image upper_jaw_image = Filter.process_image(upper_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) lower_jaw_image = Filter.process_image(lower_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) upper_jaw_image = self.pose_model._convert_to_binary_image(upper_jaw_image) lower_jaw_image = self.pose_model._convert_to_binary_image(lower_jaw_image) upper_lines = self.pose_model._find_hough_lines(upper_jaw_image, threshold=15) lower_lines = self.pose_model._find_hough_lines(lower_jaw_image, threshold=15) # Filter out lines upper_lines = self.pose_model._filter_lines(upper_lines, upper_jaw_image.shape, line_offset=6, max_line_gap=90) lower_lines = self.pose_model._filter_lines(lower_lines, lower_jaw_image.shape, line_offset=2, max_line_gap=60) self.image = lower_jaw_image self.lines = lower_lines self._redraw() def _open_radiograph(self): file_dialog = QFileDialog(self) file_dialog.setDirectory("./data/Radiographs") file_dialog.setFileMode(QFileDialog.ExistingFile) file_dialog.setNameFilter("Radiograph (*.tif)") if file_dialog.exec_() and len(file_dialog.selectedFiles()) == 1: radiograph = Radiograph() radiograph.path_to_img = file_dialog.selectedFiles()[0] #self.image = radiograph.image #crop_translation = -Filter.get_cropping_region(radiograph.image).left_top self.image = Filter.crop_image(radiograph.image) self.lines = None self._redraw() def _redraw(self, normalize=False): self.scene.clear() img = self.image.copy() if normalize: img = (img / img.max()) * 255 # Draw image qimg = toQImage(img.astype(np.uint8)) self.scene.addPixmap(QPixmap.fromImage(qimg)) # Add jaws divider self.scene.addLine(QLineF(0, self.y_line, self.image.shape[1], self.y_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_top_line, self.image.shape[1], self.y_top_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_lower_line, self.image.shape[1], self.y_lower_line), pen=QPen(QColor.fromRgb(255, 0, 0))) # Add image center self.scene.addEllipse(self.image.shape[0]/2 - self.landmark_size, self.image.shape[1]/2 - self.landmark_size, self.landmark_size * 2, self.landmark_size * 2, pen=QPen(QColor.fromRgb(255, 0, 0)), brush=QBrush(QColor.fromRgb(255, 0, 0))) # Draw Hough lines if self.lines is not None: #for x1,y1,x2,y2 in self.lines[0]: for i, line_param in enumerate(self.lines): rho,theta = line_param a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 200*(-b)) y1 = int(y0 + 200*(a)) x2 = int(x0 - 200*(-b)) y2 = int(y0 - 200*(a)) self.scene.addLine(QLineF(x1, y1, x2, y2), pen=QPen(QColor.fromRgb(0, 255, 0)))