class Winform(QWidget): def __init__(self,parent=None): super(Winform,self).__init__(parent) self.setWindowTitle("双缓冲绘图例子") self.pix = QPixmap() self.lastPoint = QPoint() self.endPoint = QPoint() # 辅助画布 self.tempPix = QPixmap() # 标志是否正在绘图 self.isDrawing = False self.initUi() def initUi(self): #窗口大小设置为600*500 self.resize(600, 500); # 画布大小为400*400,背景为白色 self.pix = QPixmap(400, 400); self.pix.fill(Qt.white); def paintEvent(self,event): painter = QPainter(self) x = self.lastPoint.x() y = self.lastPoint.y() w = self.endPoint.x() - x h = self.endPoint.y() - y # 如果正在绘图,就在辅助画布上绘制 if self.isDrawing : # 将以前pix中的内容复制到tempPix中,保证以前的内容不消失 self.tempPix = self.pix pp = QPainter( self.tempPix) pp.drawRect(x,y,w,h) painter.drawPixmap(0, 0, self.tempPix) else : pp = QPainter(self.pix ) pp.drawRect(x, y, w, h) painter.drawPixmap(0, 0, self.pix) def mousePressEvent(self, event) : # 鼠标左键按下 if event.button() == Qt.LeftButton : self.lastPoint = event.pos() self.endPoint = self.lastPoint self.isDrawing = True def mouseReleaseEvent( self, event): # 鼠标左键释放 if event.button() == Qt.LeftButton : self.endPoint = event.pos() #进行重新绘制 self.update() self.isDrawing = False
class Bullet: """Bullet contains: 1 StartPosition 2 EndPosition 3 Color 4 Text( A String) 5 Duration It uses the "window" to draw it selft """ #这个叫做 类的属性 Count=0# 通过类名Bullet.bullet访问,就是一个静态变量 Height=GLOBAL.BULLETFONTSIZE+6 #一个Bullet占用的像素高度 def __init__(self, Text, Color,Duration): Bullet.Count+=1 #这个里面self给定的内容则只属于当前对象 self.Text=Text self.Color=Color self.Duration=Duration*1000 #单位是毫秒,输入的是秒 self.IsExpired=False """this method must be called when this bullet is ready to shoot at the first time """ def prepare(self): self.elapsedTimer=QElapsedTimer() self.elapsedTimer.start() #start time self.StartPosition=QPoint(GLOBAL.WINDOWWIDTH+random.randrange(200,500,20),\ (Bullet.Height+(Bullet.Count%(GLOBAL.WINDOWHEIGHT//Bullet.Height))*Bullet.Height)) self.EndPosition=QPoint(-2000 ,self.StartPosition.y()) """Draw this bullet at position x,y ,use painter Returns True indicates this bullet is out of screen """ def draw(self,painter): ratio=self.elapsedTimer.elapsed()/self.Duration if(ratio>0.9): self.IsExpired=True # pos=ratio*self.EndPosition+(1-ratio)*self.StartPosition pos=QPoint(ratio*self.EndPosition.x()+(1-ratio)*self.StartPosition.x(),self.StartPosition.y()) #这里需要插入绘制字体阴影的代码 # # font.setFixedPitch(True) # painter.setFont(font) painter.save() painter.drawText(pos+QPoint(2,2),self.Text) painter.setPen(QPen(self.Color)) painter.drawText(pos,self.Text) painter.restore() # def __del__(self): # Count-=1 # print ("刚刚自动Delete了一个bullet\n")
def draw_item(self, face, painter): is_draw = True if self.is_clipping: is_draw = self.sphere.is_face_visible(face) if is_draw: polygon = QPolygon() for index, point_index in enumerate(face): p1_x = int(self.sphere.geom.points[face[index-1]][0]) p1_y = int(self.sphere.geom.points[face[index-1]][1]) p1_z = int(self.sphere.geom.points[face[index-1]][2]) p2_x = int(self.sphere.geom.points[point_index][0]) p2_y = int(self.sphere.geom.points[point_index][1]) p2_z = int(self.sphere.geom.points[point_index][2]) if self.sphere.projection_name == "front": # Фронтальная проекция (вид спереди) -> z = 0 real_p1 = QPoint(p1_x, p1_y) real_p2 = QPoint(p2_x, p2_y) elif self.sphere.projection_name == "horizontal": # Горизонтальная проекция (вид сверху) -> y = 0 real_p1 = QPoint(p1_x, p1_z) real_p2 = QPoint(p2_x, p2_z) elif self.sphere.projection_name == "profile": # Профильная проекция (вид сбоку) -> x = 0 real_p1 = QPoint(p1_y, p1_z) real_p2 = QPoint(p2_y, p2_z) else: real_p1 = QPoint(p1_x, p1_y) real_p2 = QPoint(p2_x, p2_y) # Точки для проволочного рисования real_p1.setX(self.width()/2 + real_p1.x()) real_p1.setY(self.height()/2 - real_p1.y()) real_p2.setX(self.width()/2 + real_p2.x()) real_p2.setY(self.height()/2 - real_p2.y()) # Полигоны для рисования с цветом polygon.append(real_p1) polygon.append(real_p2) if not self.is_light: painter.drawLine(real_p1, real_p2) if self.is_light: painter.setBrush(self.sphere.get_face_light(face, self.faces_color)) painter.drawPolygon(polygon)
class CanvasView(QtCanvasView): itemClickedSignal = pyqtSignal(QtCanvasItem) itemMovedSignal = pyqtSignal(QtCanvasItem) def __init__(self, arg1=None, arg2=None): if type(arg1)==QtCanvas: super(CanvasView, self).__init__(arg1, arg2) else: super(CanvasView, self).__init__(arg1) self.moving = QtCanvasItem(None) self.moving_start = QPoint() def contentsMousePressEvent(self, event): self.handleMouseClickEvent(event) def contentsMouseDoubleClickEvent(self, event): self.handleMouseClickEvent(event) def handleMouseClickEvent(self, event): p = self.inverseWorldMatrix().map(event.pos()) l = self.canvas().collisions(p) self.moving = QtCanvasItem(None) if (not l.isEmpty()): self.moving = l.first() self.moving_start = p self.itemClickedSignal.emit(self.moving) def contentsMouseMoveEvent(self, event): if (self.moving): p = self.inverseWorldMatrix().map(event.pos()) self.moving.moveBy(p.x() - self.moving_start.x(), p.y() - self.moving_start.y()) self.moving_start = p self.canvas().update() self.itemMovedSignal.emit(self.moving)
def click(): window_name = get_window_name() query_value = get_query_value() automation_type = get_query_automation_type() widget = find_widget(window_name, query_value, automation_type) if widget is None: return {} if isinstance(widget, QWidget): clicker.click_on(widget) return get_widget_json(widget) if isinstance(widget, QQuickItem): pointf = widget.mapToScene(QPointF(0.0, 0.0)) x = pointf.x() y = pointf.y() x += qml_method_or_default(widget, "width", 0.0) / 2.0 y += qml_method_or_default(widget, "height", 0.0) / 2.0 window_name = get_window_name() root_widget = get_root_widget(window_name) point = QPoint(x,y) quick_widget = root_widget.childAt(point.x(), point.y()) clicker.click_on(quick_widget, point) return get_widget_json(widget) return {}
def snapToGrid(self, position): #Return position of closest grid point gridSizeX = 40 gridSizeY = 20 curPos = QPoint(position.x(), position.y()) gridPos = QPoint(round(curPos.x() / gridSizeX) * gridSizeX, round(curPos.y() / gridSizeY) * gridSizeY) return gridPos
class Winform(QWidget): def __init__(self,parent=None): super(Winform,self).__init__(parent) self.setWindowTitle("绘制矩形图形例子") self.pix = QPixmap() self.lastPoint = QPoint() self.endPoint = QPoint() self.initUi() def initUi(self): #窗口大小设置为600*500 self.resize(600, 500) # 画布大小为400*400,背景为白色 self.pix = QPixmap(400, 400) self.pix.fill(Qt.white) def paintEvent(self,event): painter = QPainter(self) x = self.lastPoint.x() y = self.lastPoint.y() w = self.endPoint.x() - x h = self.endPoint.y() - y pp = QPainter(self.pix) pp.drawRect(x, y, w, h) painter.drawPixmap(0, 0, self.pix) def mousePressEvent(self, event) : # 鼠标左键按下 if event.button() == Qt.LeftButton : self.lastPoint = event.pos() self.endPoint = self.lastPoint def mouseMoveEvent(self, event): # 鼠标左键按下的同时移动鼠标 if event.buttons() and Qt.LeftButton : self.endPoint = event.pos() #进行重新绘制 self.update() def mouseReleaseEvent( self, event): # 鼠标左键释放 if event.button() == Qt.LeftButton : self.endPoint = event.pos() #进行重新绘制 self.update()
def get_linear_gradient(self): fontHeight = self.fontMetrics().height() startPoint = QPoint(self.rect().x(), self.rect().y() + 0.5 * (self.rect().height() - fontHeight)) endPoint = QPoint(startPoint.x(), startPoint.y() + fontHeight) linear = QLinearGradient(startPoint, endPoint) colorCounts = len(self.colors) for i in range(colorCounts): linear.setColorAt(0.2 + i / colorCounts, self.colors[i]) return linear
def kineticMove(self, oldx, oldy, newx, newy ): """Start a kinetic move from (oldx, oldy) to (newx, newy)""" if newx == oldx and newy == oldy: return speed = QPoint(0,0) # solve speed*(speed+1)/2 = delta to ensure 1+2+3+...+speed is as close as possible under delta.. speed.setX((sqrt(1+8*abs(newx-oldx))-1)/2) speed.setY((sqrt(1+8*abs(newy-oldy))-1)/2) # compute the amount of displacement still needed because we're dealing with integer values. diff = QPoint(0,0) diff.setX((speed.x() * (speed.x() + 1) // 2) - abs(newx - oldx)) diff.setY((speed.y() * (speed.y() + 1) // 2) - abs(newy - oldy)) # Since this function is called for exact moves (not free scrolling) # limit the kinetic time to 2 seconds, which means 100 ticks, 5050 pixels. if speed.y() > 100: speed.setY(100) diff.setY(-abs(newy-oldy) + 5050) # Although it is less likely to go beyond that limit for horizontal scrolling, # do it for x as well. if speed.x() > 100: speed.setX(100) diff.setX(-abs(newx-oldx) + 5050) # move left or right, up or down if newx > oldx : speed.setX(-speed.x()) diff.setX(-diff.x()) if newy > oldy : speed.setY(-speed.y()) diff.setY(-diff.y()) # move immediately by the step that cannot be handled by kinetic scrolling. # By construction that step is smaller that the initial speed value. self.fastScrollBy(diff) self.kineticStart(speed)
def wave(self): # print(points[0][0] ,'<', points[1][0], 'and', points[0][1], '>', points[1][1]) t = self.machine.getTransition(self.t_active) init = QPoint(t.getOrig()[0], t.getOrig()[1]) end = QPoint(t.getDest()[0], t.getDest()[1]) angle = t.getAngle() print('processing transition', t.id, t.orig, t.dest) while t.isActive(): self.pts = [[init.x(), init.y()], [end.x(), end.y()]] if self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle)
def wave(self): t = self.machine.getActiveTransition() if t != None: init = QPoint(t.getOrig()[0], t.getOrig()[1]) end = QPoint(t.getDest()[0], t.getDest()[1]) angle = t.getAngle() #print('processing transition', t.id, t.orig, t.dest) while t.isActive(): #for i in range(3): #for testing self.pts = [[init.x(), init.y()], [end.x(), end.y()]] if self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle)
def setOffset(self, offset): # Clamp the offset within the offset bounds newOffset = QPoint(min(self.mOffsetBounds.right(), max(self.mOffsetBounds.left(), offset.x())), min(self.mOffsetBounds.bottom(), max(self.mOffsetBounds.top(), offset.y()))) if (self.mOffset != newOffset): xChanged = self.mOffset.x() != newOffset.x() yChanged = self.mOffset.y() != newOffset.y() self.mOffset = newOffset if (xChanged): self.offsetXChanged.emit(self.mOffset.x()) if (yChanged): self.offsetYChanged.emit(self.mOffset.y()) self.offsetChanged.emit(self.mOffset) self.update()
def enemyClick(self, enemy): # Opens an info screen on the enemy if self.parent.gameover == False and enemy.isDead == False: if self.parent.isTowerSelected == False: # self.statusBarMessage("Enemy clicked") self.enemyPopUp = QFrame() self.enemyPopUp.setGeometry(500, 500, 100, 100) grid = QGridLayout() self.enemyPopUp.setLayout(grid) enemyStats = QLabel("Enemy Stats") name = QLabel("Name: " + str(enemy.name)) speed = QLabel("Speed: " + str(enemy.speed)) health = QLabel("Health: {:.0f}".format(enemy.health)) pixmap = QLabel() pixmap.setPixmap(enemy.picture) vbox = QVBoxLayout() vbox.addWidget(enemyStats) vbox.addWidget(name) vbox.addWidget(speed) vbox.addWidget(health) grid.addLayout(vbox, 0, 0) vbox2 = QVBoxLayout() vbox2.addWidget(pixmap) vbox2.addStretch() doneButton = QPushButton("Done") vbox2.addWidget(doneButton) grid.addLayout(vbox2, 0, 1) location = QPoint(QCursor.pos()) self.enemyPopUp.move(location.x() - 100, location.y()) self.enemyPopUp.show() doneButton.clicked.connect(self.enemyPopUp.hide) elif self.parent.gameover == True: self.statusBarMessage("The game has ended. Stop doing stuff.")
def download(self): grab = None for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(self._tilesRect.topLeft() + QPoint(x, y)) if tp not in self._tilePixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % (self.zoom, grab.x(), grab.y()) self._url = QUrl(path) request = QNetworkRequest() request.setUrl(self._url) request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') request.setAttribute(QNetworkRequest.User, grab) self._manager.get(request)
def fillRegion(layer, fillOrigin): # Create that region that will hold the fill fillRegion = QRegion() # Silently quit if parameters are unsatisfactory if (not layer.contains(fillOrigin)): return fillRegion # Cache cell that we will match other cells against matchCell = layer.cellAt(fillOrigin) # Grab map dimensions for later use. layerWidth = layer.width() layerHeight = layer.height() layerSize = layerWidth * layerHeight # Create a queue to hold cells that need filling fillPositions = QList() fillPositions.append(fillOrigin) # Create an array that will store which cells have been processed # This is faster than checking if a given cell is in the region/list processedCellsVec = QVector() for i in range(layerSize): processedCellsVec.append(0xff) processedCells = processedCellsVec # Loop through queued positions and fill them, while at the same time # checking adjacent positions to see if they should be added while (not fillPositions.empty()): currentPoint = fillPositions.takeFirst() startOfLine = currentPoint.y() * layerWidth # Seek as far left as we can left = currentPoint.x() while (left > 0 and layer.cellAt(left - 1, currentPoint.y()) == matchCell): left -= 1 # Seek as far right as we can right = currentPoint.x() while (right + 1 < layerWidth and layer.cellAt(right + 1, currentPoint.y()) == matchCell): right += 1 # Add cells between left and right to the region fillRegion += QRegion(left, currentPoint.y(), right - left + 1, 1) # Add cell strip to processed cells for i in range(startOfLine + left, right + startOfLine, 1): processedCells[i] = 1 # These variables cache whether the last cell was added to the queue # or not as an optimization, since adjacent cells on the x axis # do not need to be added to the queue. lastAboveCell = False lastBelowCell = False # Loop between left and right and check if cells above or # below need to be added to the queue for x in range(left, right+1): fillPoint = QPoint(x, currentPoint.y()) # Check cell above if (fillPoint.y() > 0): aboveCell = QPoint(fillPoint.x(), fillPoint.y() - 1) if (not processedCells[aboveCell.y() * layerWidth + aboveCell.x()] and layer.cellAt(aboveCell) == matchCell): # Do not add the above cell to the queue if its # x-adjacent cell was added. if (not lastAboveCell): fillPositions.append(aboveCell) lastAboveCell = True else: lastAboveCell = False processedCells[aboveCell.y() * layerWidth + aboveCell.x()] = 1 # Check cell below if (fillPoint.y() + 1 < layerHeight): belowCell = QPoint(fillPoint.x(), fillPoint.y() + 1) if (not processedCells[belowCell.y() * layerWidth + belowCell.x()] and layer.cellAt(belowCell) == matchCell): # Do not add the below cell to the queue if its # x-adjacent cell was added. if (not lastBelowCell): fillPositions.append(belowCell) lastBelowCell = True else: lastBelowCell = False processedCells[belowCell.y() * layerWidth + belowCell.x()] = 1 return fillRegion
def get_real_coordinate(self, pos: QtCore.QPoint): return round((pos.x() - self.img_bounds[0]) * self.ratio[0]), round( (pos.y() - self.img_bounds[1]) * self.ratio[1])
class TimeAxis(QWidget): STEP_LIST = [ 10000, 5000, 2500, 2000, 1000, 500, 250, 200, 100, 50, 25, 20, 10, 5, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01 ] DEFAULT_MARGIN_PIXEL = 0 MAIN_SCALE_MIN_PIXEL = 50 def __init__(self): super(TimeAxis, self).__init__() self.__width = 0 self.__height = 0 self.__axis_width = 0 self.__axis_length = 0 self.__axis_area = QRect(0, 0, 0, 0) self.__paint_area = QRect(0, 0, 0, 0) self.__axis_mid = 0 self.__axis_left = 0 self.__axis_right = 0 self.__axis_space_w = 30 self.__axis_align_offset = 0.3 self.__thread_width = 0 self.__thread_left_area = QRect(0, 0, 0, 0) self.__thread_right_area = QRect(0, 0, 0, 0) self.__offset = 0.0 self.__scroll = 0.0 self.__scale_per_page = 10 self.__pixel_per_scale = 0 self.__paint_since_scale = 0 self.__paint_until_scale = 0 self.__paint_start_scale = 0 self.__paint_start_offset = 0 self.__l_pressing = False self.__l_down_point = None # Real time tips self.__tip_font = QFont() self.__tip_font.setFamily("微软雅黑") self.__tip_font.setPointSize(8) self.__enable_real_time_tips = True self.__mouse_on_index = HistoricalRecord() self.__mouse_on_scale_value = 0.0 self.__mouse_on_coordinate = QPoint(0, 0) self.__era = '' self.__layout = LAYOUT_HORIZON self.__step_selection = 0 self.__main_step = 0 self.__sub_step = 0 self.setMinimumWidth(400) self.setMinimumHeight(500) self.set_time_range(0, 2000) self.setMouseTracking(True) self.__history_core = None self.__history_editor = None self.__history_threads = [] self.__left_history_threads = [] self.__right_history_threads = [] # ----------------------------------------------------- Method ----------------------------------------------------- def set_era(self, era: str): self.__era = era def set_offset(self, offset: float): if 0.0 <= offset <= 1.0: self.__axis_align_offset = offset self.repaint() def set_horizon(self): self.__layout = LAYOUT_HORIZON self.repaint() def set_vertical(self): self.__layout = LAYOUT_VERTICAL self.repaint() def set_time_range(self, since: float, until: float): self.auto_scale(min(since, until), max(since, until)) self.repaint() def set_history_core(self, history: History): self.__history_core = history def get_history_threads(self, align: int = ALIGN_RIGHT) -> list: return self.__left_history_threads if align == ALIGN_LEFT else self.__right_history_threads def add_history_thread(self, thread, align: int = ALIGN_RIGHT): if thread not in self.__history_threads: if align == ALIGN_LEFT: self.__left_history_threads.append(thread) else: self.__right_history_threads.append(thread) self.__history_threads.append(thread) self.repaint() def remove_history_threads(self, thread): if thread in self.__history_threads: self.__history_threads.remove(thread) if thread in self.__left_history_threads: self.__left_history_threads.remove(thread) if thread in self.__right_history_threads: self.__right_history_threads.remove(thread) self.repaint() def remove_all_history_threads(self): self.__history_threads.clear() self.__left_history_threads.clear() self.__right_history_threads.clear() self.repaint() def enable_real_time_tips(self, enable: bool): self.__enable_real_time_tips = enable # --------------------------------------------------- UI Action ---------------------------------------------------- def mousePressEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.__l_pressing = True self.__l_down_point = event.pos() def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: self.__l_pressing = False self.__scroll += self.__offset self.__offset = 0 self.repaint() def mouseDoubleClickEvent(self, event): now_pos = event.pos() index = self.index_from_point(now_pos) if index is not None: self.popup_editor_for_index(index) def mouseMoveEvent(self, event): now_pos = event.pos() if self.__l_pressing and self.__l_down_point is not None: if self.__layout == LAYOUT_HORIZON: self.__offset = self.__l_down_point.x() - now_pos.x() else: self.__offset = self.__l_down_point.y() - now_pos.y() self.repaint() else: self.on_pos_updated(now_pos) def wheelEvent(self, event): angle = event.angleDelta() / 8 angle_x = angle.x() angle_y = angle.y() modifiers = QApplication.keyboardModifiers() if modifiers == QtCore.Qt.ControlModifier: # Get the value before step update current_pos = event.pos() current_pos_offset = self.calc_point_to_paint_start_offset( current_pos) current_pos_scale_value = self.pixel_offset_to_scale_value( current_pos_offset) self.select_step_scale(self.__step_selection + (1 if angle_y > 0 else -1)) # Make the value under mouse keep the same place on the screen total_pixel_offset = self.__pixel_per_scale * current_pos_scale_value / self.__main_step total_pixel_offset -= current_pos_offset self.__scroll = total_pixel_offset - self.__offset else: self.__scroll += (1 if angle_y < 0 else -1) * self.__pixel_per_scale / 4 self.repaint() # ----------------------------------------------------- Action ----------------------------------------------------- def popup_editor_for_index(self, index: HistoricalRecord): if index is None: print('None index.') return # if index.get_focus_label() == 'index': # source = index.source() # if source is None or source == '': # print('Source is empty.') # return # loader = HistoricalRecordLoader() # if not loader.from_source(source): # print('Load source error : ' + source) # return # records = loader.get_loaded_records() # self.update_records(records) # else: # # It's a full record # records = [index] self.__history_editor = HistoryEditorDialog(editor_agent=self) self.__history_editor.get_history_editor().edit_source( index.source(), index.uuid()) self.__history_editor.show_browser(False) self.__history_editor.exec() # ----------------------------------------------------- Paint ------------------------------------------------------ def paintEvent(self, event): qp = QPainter() qp.begin(self) self.update_paint_area() self.update_pixel_per_scale() self.calc_paint_parameters() self.calc_paint_layout() self.paint_background(qp) if self.__layout == LAYOUT_HORIZON: self.paint_horizon(qp) else: self.paint_vertical(qp) self.paint_threads(qp) self.paint_real_time_tips(qp) qp.end() def paint_background(self, qp: QPainter): qp.setBrush(AXIS_BACKGROUND_COLORS[2]) qp.drawRect(0, 0, self.__width, self.__height) def paint_horizon(self, qp: QPainter): pass def paint_vertical(self, qp: QPainter): qp.drawLine(self.__axis_mid, 0, self.__axis_mid, self.__height) main_scale_start = int(self.__axis_mid - 15) main_scale_end = int(self.__axis_mid + 15) sub_scale_start = int(self.__axis_mid - 5) sub_scale_end = int(self.__axis_mid + 5) for i in range(0, 12): y_main = int( self.__pixel_per_scale * i) - self.__paint_start_offset + TimeAxis.DEFAULT_MARGIN_PIXEL time_main = (self.__paint_start_scale + i) * self.__main_step qp.drawLine(main_scale_start, y_main, main_scale_end, y_main) qp.drawText(main_scale_end - 100, y_main, str(time_main)) for j in range(0, 10): y_sub = int(y_main + self.__pixel_per_scale * j / 10) qp.drawLine(sub_scale_start, y_sub, sub_scale_end, y_sub) def paint_threads(self, qp: QPainter): for thread in self.__history_threads: thread.repaint(qp) def paint_real_time_tips(self, qp: QPainter): if not self.__enable_real_time_tips or self.__l_pressing: return qp.drawLine(0, self.__mouse_on_coordinate.y(), self.__width, self.__mouse_on_coordinate.y()) qp.drawLine(self.__mouse_on_coordinate.x(), 0, self.__mouse_on_coordinate.x(), self.__height) tip_text = self.format_real_time_tip() fm = QFontMetrics(self.__tip_font) text_width = fm.width(tip_text) text_height = fm.height() tip_area = QRect(self.__mouse_on_coordinate, QSize(text_width, text_height)) tip_area.setTop(tip_area.top() - fm.height()) tip_area.setBottom(tip_area.bottom() - fm.height()) if tip_area.right() > self.__axis_width: tip_area.setLeft(tip_area.left() - text_width) tip_area.setRight(tip_area.right() - text_width) qp.setFont(self.__tip_font) qp.setBrush(QColor(36, 169, 225)) qp.drawRect(tip_area) qp.drawText(tip_area, Qt.AlignLeft, tip_text) # -------------------------------------------------- Calculation --------------------------------------------------- def index_from_point(self, point: QPoint) -> HistoricalRecord: for thread in self.__history_threads: index = thread.index_from_point(point) if index is not None: return index return None def calc_point_to_paint_start_offset(self, point): if self.__layout == LAYOUT_HORIZON: return point.x() - TimeAxis.DEFAULT_MARGIN_PIXEL else: return point.y() - TimeAxis.DEFAULT_MARGIN_PIXEL def update_paint_area(self): wnd_size = self.size() self.__width = wnd_size.width() self.__height = wnd_size.height() self.__paint_area.setRect(0, 0, self.__width, self.__width) self.__axis_width = self.__height if self.__layout == LAYOUT_HORIZON else self.__width self.__axis_length = self.__width if self.__layout == LAYOUT_HORIZON else self.__height self.__axis_length -= self.DEFAULT_MARGIN_PIXEL * 2 def update_pixel_per_scale(self): self.__pixel_per_scale = self.__axis_length / self.__scale_per_page self.__pixel_per_scale = max(self.__pixel_per_scale, TimeAxis.MAIN_SCALE_MIN_PIXEL) def calc_paint_parameters(self): total_pixel_offset = self.__scroll + self.__offset self.__paint_since_scale = float( total_pixel_offset) / self.__pixel_per_scale self.__paint_until_scale = self.__paint_since_scale + self.__axis_length / self.__pixel_per_scale self.__paint_start_scale = math.floor(self.__paint_since_scale) self.__paint_start_offset = total_pixel_offset - self.__paint_start_scale * self.__pixel_per_scale for thread in self.__history_threads: thread.on_paint_scale_range_updated( self.__paint_since_scale * self.__main_step, self.__paint_until_scale * self.__main_step) def calc_paint_layout(self): era_text_width = 80 self.__axis_mid = int(self.__axis_width * self.__axis_align_offset) self.__axis_left = int(self.__axis_mid - self.__axis_space_w / 2 - 10) - era_text_width self.__axis_right = int(self.__axis_mid + self.__axis_space_w / 2 + 10) left_thread_count = len(self.__left_history_threads) right_thread_count = len(self.__right_history_threads) left_thread_width = self.__axis_left / left_thread_count if left_thread_count > 0 else 0 right_thread_width = (self.__axis_width - self.__axis_right) / right_thread_count \ if right_thread_count > 0 else 0 # Vertical -> Horizon : Left rotate for i in range(0, left_thread_count): thread = self.__left_history_threads[i] if self.__layout == LAYOUT_HORIZON: # TODO: Can we just rotate the QPaint axis? pass else: top = TimeAxis.DEFAULT_MARGIN_PIXEL bottom = self.__axis_length - TimeAxis.DEFAULT_MARGIN_PIXEL left = i * left_thread_width area = QRect(QPoint(left, top), QPoint(left + left_thread_width, bottom)) thread.on_paint_canvas_size_update(area) for i in range(0, right_thread_count): thread = self.__right_history_threads[i] if self.__layout == LAYOUT_HORIZON: # TODO: Can we just rotate the QPaint axis? pass else: top = TimeAxis.DEFAULT_MARGIN_PIXEL bottom = self.__axis_length - TimeAxis.DEFAULT_MARGIN_PIXEL left = self.__axis_right + i * right_thread_width area = QRect(QPoint(left, top), QPoint(left + right_thread_width, bottom)) thread.on_paint_canvas_size_update(area) # ----------------------------------------------------- Scale ------------------------------------------------------ def pixel_offset_to_scale_value(self, display_pixel_offset: int) -> float: delta_pixel_offset = display_pixel_offset + self.__paint_start_offset - self.DEFAULT_MARGIN_PIXEL delta_scale_offset = delta_pixel_offset / self.__pixel_per_scale return (self.__paint_start_scale + delta_scale_offset) * self.__main_step def auto_scale(self, since: float, until: float): since_rough = lower_rough(since) until_rough = upper_rough(until) delta = until_rough - since_rough delta_rough = upper_rough(delta) step_rough = delta_rough / 10 step_index = 1 while step_index < len(TimeAxis.STEP_LIST): if TimeAxis.STEP_LIST[step_index] < step_rough: break step_index += 1 self.select_step_scale(step_index - 1) self.update_pixel_per_scale() self.__scroll = since_rough * self.__pixel_per_scale def select_step_scale(self, step_index: int): self.__step_selection = step_index self.__step_selection = max(self.__step_selection, 0) self.__step_selection = min(self.__step_selection, len(TimeAxis.STEP_LIST) - 1) self.__main_step = TimeAxis.STEP_LIST[self.__step_selection] self.__sub_step = self.__main_step / 10 # abs_num = abs(num) # if abs_num >= 100: # index_10 = math.log(abs_num, 10) # round_index_10 = math.floor(index_10) # scale = math.pow(10, round_index_10) # delta = scale / 10 # elif 10 < abs_num < 100: # delta = 10 # elif 1 < abs_num <= 10: # delta = 1 # else: # if sign > 0: # delta = 1 # else: # delta = 0 # return sign * delta * ratio # ------------------------------------------ Art ------------------------------------------ def format_real_time_tip(self) -> str: tip_text = '(' + HistoryTime.standard_time_to_str( self.__mouse_on_scale_value) + ')' if self.__mouse_on_index is not None: since = self.__mouse_on_index.since() until = self.__mouse_on_index.until() abstract_tags = self.__mouse_on_index.get_tags('abstract') abstract = abstract_tags[0] if len(abstract_tags) > 0 else '' abstract = abstract.strip() if len(abstract) > 0: tip_text += ' | ' tip_text += abstract if since == until: tip_text += ' : [' + HistoryTime.standard_time_to_str( since) + ']' else: tip_text += '(' + str(math.floor(self.__mouse_on_scale_value - since + 1)) + \ '/' + str(math.floor(until - since)) + ') : [' tip_text += HistoryTime.standard_time_to_str(since) + \ ' - ' + HistoryTime.standard_time_to_str(until) + ']' return tip_text # ------------------------------------- Real Time Tips ------------------------------------ def on_pos_updated(self, pos: QPoint): if not self.__enable_real_time_tips: return if self.__mouse_on_coordinate != pos: self.__mouse_on_coordinate = pos self.__mouse_on_scale_value = self.pixel_offset_to_scale_value( pos.y()) self.__mouse_on_index = self.index_from_point(pos) self.repaint() # ------------------------------- HistoryRecordEditor.Agent ------------------------------- def on_apply(self): if self.__history_editor is None: print('Unexpected Error: History editor is None.') return records = self.__history_editor.get_history_editor().get_records() if records is None or len(records) == 0: return indexer = HistoricalRecordIndexer() indexer.index_records(records) indexes = indexer.get_indexes() # TODO: Maybe we should named it as update_*() self.__history_core.update_records(records) self.__history_core.update_indexes(indexes) self.__history_editor.on_apply() self.__history_editor.close() self.repaint() def on_cancel(self): if self.__history_editor is not None: self.__history_editor.close() else: print('Unexpected Error: History editor is None.')
class MandelbrotWidget(QWidget): def __init__(self, parent=None): super(MandelbrotWidget, self).__init__(parent) self.thread = RenderThread() self.pixmap = QPixmap() self.pixmapOffset = QPoint() self.lastDragPos = QPoint() self.centerX = DefaultCenterX self.centerY = DefaultCenterY self.pixmapScale = DefaultScale self.curScale = DefaultScale self.thread.renderedImage.connect(self.updatePixmap) self.setWindowTitle("Mandelbrot") self.setCursor(Qt.CrossCursor) self.resize(550, 400) def paintEvent(self, event): painter = QPainter(self) painter.fillRect(self.rect(), Qt.black) if self.pixmap.isNull(): painter.setPen(Qt.white) painter.drawText(self.rect(), Qt.AlignCenter, "Rendering initial image, please wait...") return if self.curScale == self.pixmapScale: painter.drawPixmap(self.pixmapOffset, self.pixmap) else: scaleFactor = self.pixmapScale / self.curScale newWidth = int(self.pixmap.width() * scaleFactor) newHeight = int(self.pixmap.height() * scaleFactor) newX = self.pixmapOffset.x() + (self.pixmap.width() - newWidth) / 2 newY = self.pixmapOffset.y() + (self.pixmap.height() - newHeight) / 2 painter.save() painter.translate(newX, newY) painter.scale(scaleFactor, scaleFactor) exposed, _ = painter.matrix().inverted() exposed = exposed.mapRect(self.rect()).adjusted(-1, -1, 1, 1) painter.drawPixmap(exposed, self.pixmap, exposed) painter.restore() text = "Use mouse wheel or the '+' and '-' keys to zoom. Press and " \ "hold left mouse button to scroll." metrics = painter.fontMetrics() textWidth = metrics.width(text) painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 127)) painter.drawRect((self.width() - textWidth) / 2 - 5, 0, textWidth + 10, metrics.lineSpacing() + 5) painter.setPen(Qt.white) painter.drawText((self.width() - textWidth) / 2, metrics.leading() + metrics.ascent(), text) def resizeEvent(self, event): self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom(ZoomInFactor) elif event.key() == Qt.Key_Minus: self.zoom(ZoomOutFactor) elif event.key() == Qt.Key_Left: self.scroll(-ScrollStep, 0) elif event.key() == Qt.Key_Right: self.scroll(+ScrollStep, 0) elif event.key() == Qt.Key_Down: self.scroll(0, -ScrollStep) elif event.key() == Qt.Key_Up: self.scroll(0, +ScrollStep) else: super(MandelbrotWidget, self).keyPressEvent(event) def wheelEvent(self, event): numDegrees = event.angleDelta().y() / 8 numSteps = numDegrees / 15.0 self.zoom(pow(ZoomInFactor, numSteps)) def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.lastDragPos = QPoint(event.pos()) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint(event.pos()) self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint() deltaX = (self.width() - self.pixmap.width()) / 2 - self.pixmapOffset.x() deltaY = (self.height() - self.pixmap.height()) / 2 - self.pixmapOffset.y() self.scroll(deltaX, deltaY) def updatePixmap(self, image, scaleFactor): if not self.lastDragPos.isNull(): return self.pixmap = QPixmap.fromImage(image) self.pixmapOffset = QPoint() self.lastDragPosition = QPoint() self.pixmapScale = scaleFactor self.update() def zoom(self, zoomFactor): self.curScale *= zoomFactor self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def scroll(self, deltaX, deltaY): self.centerX += deltaX * self.curScale self.centerY += deltaY * self.curScale self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size())
class TileSelectionTool(AbstractTileTool): def __init__(self, parent = None): super().__init__(self.tr("Rectangular Select"), QIcon(":images/22x22/stock-tool-rect-select.png"), QKeySequence(self.tr("R")), parent) self.mSelectionMode = SelectionMode.Replace self.mSelecting = False self.setTilePositionMethod(TilePositionMethod.BetweenTiles) self.mSelectionStart = QPoint() def tr(self, sourceText, disambiguation = '', n = -1): return QCoreApplication.translate('TileSelectionTool', sourceText, disambiguation, n) def mousePressed(self, event): button = event.button() modifiers = event.modifiers() if (button == Qt.LeftButton): if (modifiers == Qt.ControlModifier): self.mSelectionMode = SelectionMode.Subtract elif (modifiers == Qt.ShiftModifier): self.mSelectionMode = SelectionMode.Add elif (modifiers == (Qt.ControlModifier | Qt.ShiftModifier)): self.mSelectionMode = SelectionMode.Intersect else: self.mSelectionMode = SelectionMode.Replace self.mSelecting = True self.mSelectionStart = self.tilePosition() self.brushItem().setTileRegion(QRegion()) def mouseReleased(self, event): if (event.button() == Qt.LeftButton): self.mSelecting = False document = self.mapDocument() selection = document.selectedArea() area = self.selectedArea() x = self.mSelectionMode if x==SelectionMode.Replace: selection = area elif x==SelectionMode.Add: selection += area elif x==SelectionMode.Subtract: selection = selection.xored(QRegion(area)) elif x==SelectionMode.Intersect: selection &= area if (selection != document.selectedArea()): cmd = ChangeSelectedArea(document, selection) document.undoStack().push(cmd) self.brushItem().setTileRegion(QRegion()) self.updateStatusInfo() def languageChanged(self): self.setName(self.tr("Rectangular Select")) self.setShortcut(QKeySequence(self.tr("R"))) def tilePositionChanged(self, tilePos): if (self.mSelecting): self.brushItem().setTileRegion(self.selectedArea()) def updateStatusInfo(self): if (not self.isBrushVisible() or not self.mSelecting): super().updateStatusInfo() return pos = self.tilePosition() area = self.selectedArea() self.setStatusInfo(self.tr("%d, %d - Rectangle: (%d x %d)"%((pos.x()), pos.y(), area.width(), area.height()))) def selectedArea(self): tilePos = self.tilePosition() pos = QPoint(min(tilePos.x(), self.mSelectionStart.x()), min(tilePos.y(), self.mSelectionStart.y())) size = QSize(abs(tilePos.x() - self.mSelectionStart.x()), abs(tilePos.y() - self.mSelectionStart.y())) return QRect(pos, size)
class HelloGLWidget(QOpenGLWidget): """HelloGLWidget(QOpenGLWidget) Provides a custom widget to display an OpenGL-rendered Qt logo. Various properties and slots are defined so that the user can rotate the logo, and signals are defined to enable other components to react to changes to its orientation. """ # We define three signals that are used to indicate changes to the # rotation of the logo. xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) def __init__(self, parent=None): super(HelloGLWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.lastPos = QPoint() self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) self.setWindowTitle("Hello GL") # The rotation of the logo about the x-axis can be controlled using the # xRotation property, defined using the following getter and setter # methods. def getXRotation(self): return self.xRot # The setXRotation() setter method is also a slot. @pyqtSlot(int) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() xRotation = pyqtProperty(int, getXRotation, setXRotation) # The rotation of the logo about the y-axis can be controlled using the # yRotation property, defined using the following getter and setter # methods. def getYRotation(self): return self.yRot # The setYRotation() setter method is also a slot. @pyqtSlot(int) def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() yRotation = pyqtProperty(int, getYRotation, setYRotation) # The rotation of the logo about the z-axis can be controlled using the # zRotation property, defined using the following getter and setter # methods. def getZRotation(self): return self.zRot # The setZRotation() setter method is also a slot. @pyqtSlot(int) def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() zRotation = pyqtProperty(int, getZRotation, setZRotation) def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(200, 200) def initializeGL(self): self.gl = self.context().versionFunctions() self.gl.initializeOpenGLFunctions() self.setClearColor(self.trolltechPurple.darker()) self.object = self.makeObject() self.gl.glShadeModel(self.gl.GL_SMOOTH) self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glEnable(self.gl.GL_CULL_FACE) def paintGL(self): self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.gl.glLoadIdentity() self.gl.glTranslated(0.0, 0.0, -10.0) self.gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) self.gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) self.gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) self.gl.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) self.gl.glViewport((width - side) / 2, (height - side) / 2, side, side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() self.gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = QPoint(event.pos()) def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = QPoint(event.pos()) def makeObject(self): genList = self.gl.glGenLists(1) self.gl.glNewList(genList, self.gl.GL_COMPILE) self.gl.glBegin(self.gl.GL_QUADS) x1 = +0.06 y1 = -0.14 x2 = +0.14 y2 = -0.06 x3 = +0.08 y3 = +0.00 x4 = +0.30 y4 = +0.22 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) self.quad(x3, y3, x4, y4, y4, x4, y3, x3) self.extrude(x1, y1, x2, y2) self.extrude(x2, y2, y2, x2) self.extrude(y2, x2, y1, x1) self.extrude(y1, x1, x1, y1) self.extrude(x3, y3, x4, y4) self.extrude(x4, y4, y4, x4) self.extrude(y4, x4, y3, x3) Pi = 3.14159265358979323846 NumSectors = 200 for i in range(NumSectors): angle1 = (i * 2 * Pi) / NumSectors x5 = 0.30 * math.sin(angle1) y5 = 0.30 * math.cos(angle1) x6 = 0.20 * math.sin(angle1) y6 = 0.20 * math.cos(angle1) angle2 = ((i + 1) * 2 * Pi) / NumSectors x7 = 0.20 * math.sin(angle2) y7 = 0.20 * math.cos(angle2) x8 = 0.30 * math.sin(angle2) y8 = 0.30 * math.cos(angle2) self.quad(x5, y5, x6, y6, x7, y7, x8, y8) self.extrude(x6, y6, x7, y7) self.extrude(x8, y8, x5, y5) self.gl.glEnd() self.gl.glEndList() return genList def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): self.setColor(self.trolltechGreen) self.gl.glVertex3d(x1, y1, -0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x3, y3, -0.05) self.gl.glVertex3d(x4, y4, -0.05) self.gl.glVertex3d(x4, y4, +0.05) self.gl.glVertex3d(x3, y3, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x1, y1, +0.05) def extrude(self, x1, y1, x2, y2): self.setColor(self.trolltechGreen.darker(250 + int(100 * x1))) self.gl.glVertex3d(x1, y1, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x1, y1, -0.05) def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def setClearColor(self, c): self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
class GLWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) zoomChanged = pyqtSignal(int) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.model = None self.xRot = 1700 self.yRot = 2850 self.zRot = 0 self.viewX = 0 self.viewY = 0 self.lastPos = QPoint() self.r_back = self.g_back = self.b_back = 0 self.plotdata = [] self.plotlen = 16000 # Where we are centering. self.xcenter = 0.0 self.ycenter = 0.0 self.zcenter = 0.0 # Where the eye is self.distance = 10.0 # Field of view in y direction self.fovy = 30.0 # Position of clipping planes. self.near = 0.1 self.far = 1000.0 # View settings self.perspective = 0 self.lat = 0 self.minlat = -90 self.maxlat = 90 # does not show HUD by default self.hud = Hud() # self.hud.show("stuff") # add a 100ms timer to poll linuxcnc stats self.timer = QTimer() self.timer.timeout.connect(self.update) self.timer.start(100) def getOpenglInfo(self): info = """ Vendor: {0} Renderer: {1} OpenGL Version: {2} Shader Version: {3} """.format( GL.glGetString(GL.GL_VENDOR), GL.glGetString(GL.GL_RENDERER), GL.glGetString(GL.GL_VERSION), GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION) ) return info def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(400, 400) def winfo_width(self): return self.geometry().width() def winfo_height(self): return self.geometry().height() def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def setZoom(self, depth): self.distance = depth self.update() def zoomin(self): self.distance = self.distance / 1.1 if self.distance < self.near: self.distance = self.near self.update() def zoomout(self): self.distance = self.distance * 1.1 if self.distance > self.far: self.distance = self.far self.update() def set_latitudelimits(self, minlat, maxlat): """Set the new "latitude" limits for rotations.""" if maxlat > 180: return if minlat < -180: return if maxlat <= minlat: return self.maxlat = maxlat self.minlat = minlat def initializeGL(self): # basic_lighting GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, (1, -1, .5, 0)) GL.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, (.2, .2, .2, 0)) GL.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, (.6, .6, .4, 0)) GL.glLightfv(GL.GL_LIGHT0 + 1, GL.GL_POSITION, (-1, -1, .5, 0)) GL.glLightfv(GL.GL_LIGHT0 + 1, GL.GL_AMBIENT, (.0, .0, .0, 0)) GL.glLightfv(GL.GL_LIGHT0 + 1, GL.GL_DIFFUSE, (.0, .0, .4, 0)) GL.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, (1, 1, 1, 0)) GL.glDisable(GL.GL_CULL_FACE) GL.glEnable(GL.GL_LIGHTING) GL.glEnable(GL.GL_LIGHT0) GL.glEnable(GL.GL_LIGHT0 + 1) GL.glDepthFunc(GL.GL_LESS) GL.glEnable(GL.GL_DEPTH_TEST) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() def paintGL(self): GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glLoadIdentity() GL.glTranslated(0.0, 0.0, -10.0) GL.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) GL.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) GL.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) # draw Objects GL.glPushMatrix() # Protect our matrix # set view size w = self.winfo_width() h = self.winfo_height() GL.glViewport(0, 0, w, h) # Clear the background and depth buffer. GL.glClearColor(self.r_back, self.g_back, self.b_back, 0.) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GLU.gluPerspective(self.fovy, float(w) / float(h), self.near, self.far) if 1: # Now translate the scene origin away from the world origin GL.glMatrixMode(GL.GL_MODELVIEW) mat = GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX) GL.glLoadIdentity() GL.glTranslatef(-(self.xcenter + self.viewX), -(self.ycenter + self.viewY), -(self.zcenter + self.distance)) GL.glMultMatrixd(mat) else: GLU.gluLookAt(self.xcenter, self.ycenter, self.zcenter + self.distance, self.xcenter, self.ycenter, self.zcenter, 0., 1., 0.) GL.glMatrixMode(GL.GL_MODELVIEW) # Call objects redraw method. self.drawObjects() GL.glFlush() # Tidy up GL.glPopMatrix() # Restore the matrix def drawObjects(self, *args): if self.winfo_width() == 1: return if self.model is None: return self.model.traverse() # current coords: world # the matrices tool2view, work2view, and world2view # transform from tool/work/world coords to viewport coords # if we want to draw in tool coords, we need to do # "tool -> view -> world" (since the current frame is world) # and if we want to draw in work coords, we need # "work -> view -> world". For both, we need to invert # the world2view matrix to do the second step view2world = invert(self.world2view.t) # likewise, for backplot, we want to transform the tooltip # position from tool coords (where it is [0,0,0]) to work # coords, so we need tool -> view -> work # so lets also invert the work2view matrix view2work = invert(self.work2view.t) # since backplot lines only need vertices, not orientation, # and the tooltip is at the origin, getting the tool coords # is easy tx, ty, tz = self.tool2view.t[3][:3] # now we have to transform them to the work frame wx = tx * view2work[0][0] + ty * view2work[1][0] + tz * view2work[2][0] + view2work[3][0] wy = tx * view2work[0][1] + ty * view2work[1][1] + tz * view2work[2][1] + view2work[3][1] wz = tx * view2work[0][2] + ty * view2work[1][2] + tz * view2work[2][2] + view2work[3][2] # wx, wy, wz are the values to use for backplot # so we save them in a buffer if len(self.plotdata) == self.plotlen: del self.plotdata[:self.plotlen // 10] point = [wx, wy, wz] if not self.plotdata or point != self.plotdata[-1]: self.plotdata.append(point) # now lets draw something in the tool coordinate system # GL.glPushMatrix() # matrixes take effect in reverse order, so the next # two lines do "tool -> view -> world" # GL.glMultMatrixd(view2world) # GL.glMultMatrixd(self.tool2view.t) # do drawing here # cylinder normally goes to +Z, we want it down # GL.glTranslatef(0,0,-60) # GLU.gluCylinder(self.q1, 20, 20, 60, 32, 16) # back to world coords # GL.glPopMatrix() # we can also draw in the work coord system GL.glPushMatrix() # "work -> view -> world" GL.glMultMatrixd(view2world) GL.glMultMatrixd(self.work2view.t) # now we can draw in work coords, and whatever we draw # will move with the work, (if the work is attached to # a table or indexer or something that moves with # respect to the world # just a test object, sitting on the table # GLU.gluCylinder(self.q2, 40, 20, 60, 32, 16) # draw head up display if (hasattr(self.hud, "draw")): self.hud.draw() # draw backplot GL.glDisable(GL.GL_LIGHTING) GL.glLineWidth(2) GL.glColor3f(1.0, 0.5, 0.5) GL.glBegin(GL.GL_LINE_STRIP) for p in self.plotdata: GL.glVertex3f(*p) GL.glEnd() GL.glEnable(GL.GL_LIGHTING) GL.glColor3f(1, 1, 1) GL.glLineWidth(1) GL.glDisable(GL.GL_BLEND) GL.glDepthFunc(GL.GL_LESS) # back to world again GL.glPopMatrix() def plotclear(self): del self.plotdata[:self.plotlen] def resizeGL(self, width, height): side = min(width, height) if side < 0: return GL.glViewport((width - side) // 2, (height - side) // 2, side, side) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) GL.glMatrixMode(GL.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot - 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) else: # basic panning if dx > 0: self.viewX -=2 elif dx < 0: self.viewX +=2 if dy > 0: self.viewY +=2 elif dy < 0: self.viewY -=2 self.lastPos = event.pos() def mouseDoubleClickEvent(self, event): if event.button() & Qt.RightButton: self.plotclear() def wheelEvent(self, event): # Use the mouse wheel to zoom in/out a = event.angleDelta().y() / 200 if a < 0: self.zoomout() else: self.zoomin() event.accept() def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle
class GLWidget(QGLWidget): def __init__(self, parent=None): super(GLWidget, self).__init__(QGLFormat(QGL.SampleBuffers), parent) midnight = QTime(0, 0, 0) random.seed(midnight.secsTo(QTime.currentTime())) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.image = QImage() self.bubbles = [] self.lastPos = QPoint() self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) self.animationTimer = QTimer() self.animationTimer.setSingleShot(False) self.animationTimer.timeout.connect(self.animate) self.animationTimer.start(25) self.setAutoFillBackground(False) self.setMinimumSize(200, 200) self.setWindowTitle("Overpainting a Scene") def __del__(self): self.makeCurrent() glDeleteLists(self.object, 1) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle def initializeGL(self): self.object = self.makeObject() def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() def paintEvent(self, event): self.makeCurrent() glMatrixMode(GL_MODELVIEW) glPushMatrix() self.qglClearColor(self.trolltechPurple.darker()) glShadeModel(GL_SMOOTH) glEnable(GL_DEPTH_TEST) #glEnable(GL_CULL_FACE) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_MULTISAMPLE) lightPosition = (0.5, 5.0, 7.0, 1.0) glLightfv(GL_LIGHT0, GL_POSITION, lightPosition) self.setupViewport(self.width(), self.height()) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslated(0.0, 0.0, -10.0) glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) glCallList(self.object) glMatrixMode(GL_MODELVIEW) glPopMatrix() painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) for bubble in self.bubbles: if bubble.rect().intersects(QRectF(event.rect())): bubble.drawBubble(painter) self.drawInstructions(painter) painter.end() def resizeGL(self, width, height): self.setupViewport(width, height) def showEvent(self, event): self.createBubbles(20 - len(self.bubbles)) def sizeHint(self): return QSize(400, 400) def makeObject(self): list = glGenLists(1) glNewList(list, GL_COMPILE) glEnable(GL_NORMALIZE) glBegin(GL_QUADS) logoDiffuseColor = (self.trolltechGreen.red() / 255.0, self.trolltechGreen.green() / 255.0, self.trolltechGreen.blue() / 255.0, 1.0) glMaterialfv(GL_FRONT, GL_DIFFUSE, logoDiffuseColor) x1 = +0.06 y1 = -0.14 x2 = +0.14 y2 = -0.06 x3 = +0.08 y3 = +0.00 x4 = +0.30 y4 = +0.22 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) self.quad(x3, y3, x4, y4, y4, x4, y3, x3) self.extrude(x1, y1, x2, y2) self.extrude(x2, y2, y2, x2) self.extrude(y2, x2, y1, x1) self.extrude(y1, x1, x1, y1) self.extrude(x3, y3, x4, y4) self.extrude(x4, y4, y4, x4) self.extrude(y4, x4, y3, x3) NumSectors = 200 for i in range(NumSectors): angle1 = (i * 2 * math.pi) / NumSectors x5 = 0.30 * math.sin(angle1) y5 = 0.30 * math.cos(angle1) x6 = 0.20 * math.sin(angle1) y6 = 0.20 * math.cos(angle1) angle2 = ((i + 1) * 2 * math.pi) / NumSectors x7 = 0.20 * math.sin(angle2) y7 = 0.20 * math.cos(angle2) x8 = 0.30 * math.sin(angle2) y8 = 0.30 * math.cos(angle2) self.quad(x5, y5, x6, y6, x7, y7, x8, y8) self.extrude(x6, y6, x7, y7) self.extrude(x8, y8, x5, y5) glEnd() glEndList() return list def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): glNormal3d(0.0, 0.0, -1.0) glVertex3d(x1, y1, -0.05) glVertex3d(x2, y2, -0.05) glVertex3d(x3, y3, -0.05) glVertex3d(x4, y4, -0.05) glNormal3d(0.0, 0.0, 1.0) glVertex3d(x4, y4, +0.05) glVertex3d(x3, y3, +0.05) glVertex3d(x2, y2, +0.05) glVertex3d(x1, y1, +0.05) def extrude(self, x1, y1, x2, y2): self.qglColor(self.trolltechGreen.darker(250 + int(100 * x1))) glNormal3d((x1 + x2) / 2.0, (y1 + y2) / 2.0, 0.0) glVertex3d(x1, y1, +0.05) glVertex3d(x2, y2, +0.05) glVertex3d(x2, y2, -0.05) glVertex3d(x1, y1, -0.05) def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def createBubbles(self, number): for i in range(number): position = QPointF(self.width() * (0.1 + 0.8 * random.random()), self.height() * (0.1 + 0.8 * random.random())) radius = min(self.width(), self.height()) * (0.0125 + 0.0875 * random.random()) velocity = QPointF( self.width() * 0.0125 * (-0.5 + random.random()), self.height() * 0.0125 * (-0.5 + random.random())) self.bubbles.append(Bubble(position, radius, velocity)) def animate(self): for bubble in self.bubbles: bubble.move(self.rect()) self.update() def setupViewport(self, width, height): side = min(width, height) glViewport((width - side) // 2, (height - side) // 2, side, side) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) glMatrixMode(GL_MODELVIEW) def drawInstructions(self, painter): text = "Click and drag with the left mouse button to rotate the Qt " \ "logo." metrics = QFontMetrics(self.font()) border = max(4, metrics.leading()) rect = metrics.boundingRect(0, 0, self.width() - 2 * border, int(self.height() * 0.125), Qt.AlignCenter | Qt.TextWordWrap, text) painter.setRenderHint(QPainter.TextAntialiasing) painter.fillRect(QRect(0, 0, self.width(), rect.height() + 2 * border), QColor(0, 0, 0, 127)) painter.setPen(Qt.white) painter.fillRect(QRect(0, 0, self.width(), rect.height() + 2 * border), QColor(0, 0, 0, 127)) painter.drawText( (self.width() - rect.width()) / 2, border, rect.width(), rect.height(), Qt.AlignCenter | Qt.TextWordWrap, text)
class PyQtOpenGL(QOpenGLWidget): # rotation signals mouse movement x_rotation_changed = pyqtSignal(int) y_rotation_changed = pyqtSignal(int) z_rotation_changed = pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) self.paint_0 = True self.paint_1 = True self.paint_2 = True self.resize_lines = True # set orthographic matrix multiplier to large/small self.resize_lines = False self.paint_rotation = True self.paint_rotation = False self.x_rotation = 0 # rotation variables self.y_rotation = 0 self.z_rotation = 0 self.last_pos = QPoint() def normalize_angle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle # slots for xyz-rotation def set_x_rotation(self, angle): angle = self.normalize_angle(angle) if angle != self.x_rotation: self.x_rotation = angle self.x_rotation_changed.emit(angle) self.update() def set_y_rotation(self, angle): angle = self.normalize_angle(angle) if angle != self.y_rotation: self.y_rotation = angle self.y_rotation_changed.emit(angle) self.update() def set_z_rotation(self, angle): angle = self.normalize_angle(angle) if angle != self.z_rotation: self.z_rotation = angle self.z_rotation_changed.emit(angle) self.update() def initializeGL(self): # reimplemented glClearColor(0.0, 0.0, 1.0, 0.0) # blue glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glShadeModel(GL_SMOOTH) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) lightPosition = [0, 0, 10, 1.0] glLightfv(GL_LIGHT0, GL_POSITION, lightPosition) def paintGL(self): # reimplemented glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslatef(0.0, 0.0, -10.0) glRotatef(self.x_rotation / 16.0, 1.0, 0.0, 0.0) glRotatef(self.y_rotation / 16.0, 0.0, 1.0, 0.0) glRotatef(self.z_rotation / 16.0, 0.0, 0.0, 1.0) self.draw() def draw(self): if self.paint_rotation: glColor3f(1.0, 0.0, 0.0) glBegin(GL_QUADS) # bottom of pyramid glNormal3f(0, 0, -1) glVertex3f(-1 ,-1, 0) glVertex3f(-1 ,1, 0) glVertex3f(1, 1, 0) glVertex3f(1, -1, 0) glEnd() glColor3f(0.0, 0.0, 0.0) glBegin(GL_TRIANGLES) # four sides of pyramid glNormal3f(0, -1, 0.707) glVertex3f(-1, -1, 0) glVertex3f(1, -1, 0) glVertex3f(0, 0, 1.2) glEnd() glBegin(GL_TRIANGLES) glNormal3f(1,0, 0.707) glVertex3f(1,-1,0) glVertex3f(1,1,0) glVertex3f(0,0,1.2) glEnd() glBegin(GL_TRIANGLES) glNormal3f(0,1,0.707) glVertex3f(1,1,0) glVertex3f(-1,1,0) glVertex3f(0,0,1.2) glEnd() glBegin(GL_TRIANGLES) glNormal3f(-1,0,0.707) glVertex3f(-1,1,0) glVertex3f(-1,-1,0) glVertex3f(0,0,1.2) glEnd() # square and lines if self.paint_0: glColor3f(1.0, 0.0, 0.0) # functions expects 3 f(loats); RGB: red glRectf(-5, -5, 5, 5) # draw a filled rectangle with above color, position(x,y) pairs from center of window if self.paint_1: glColor3f(0.0, 1.0, 0.0) # set color to RGB: green x=10 y=10 self.draw_loop(x, y) if self.paint_2: glColor3f(0.0, 0.0, 0.0) # set color to RGB: black x=5 y=5 self.draw_loop(x, y) def resizeGL(self, width, height): # reimplemented side = min(width, height) if side < 0: return glViewport((width - side) // 2, (height - side) // 2, side, side) glMatrixMode(GL_PROJECTION) glLoadIdentity() if self.resize_lines: glOrtho(-50, 50, -50, 50, -50.0, 50.0) # for square and lines; combined with pyramid else: glOrtho(-2, +2, -2, +2, 1.0, 15.0) # original pyramid setting glMatrixMode(GL_MODELVIEW) def draw_loop(self, x, y, incr=10): for _ in range(5): self.draw_square_lines(x, y) x += incr y += incr def draw_square_lines(self, x=10, y=10, z=0): glBegin(GL_LINES) # begin to draw a line glVertex3f(x, y, z) # start line relative to center of window glVertex3f(x, -y, z) # draw first line glVertex3f(x, -y, z) glVertex3f(-x, -y, z) glVertex3f(-x, -y, z) glVertex3f(-x, y, z) glVertex3f(-x, y, z) glVertex3f(x, y, z) glEnd() def mousePressEvent(self, event): # reimplemented self.last_pos = event.pos() def mouseMoveEvent(self, event): # reimplemented move_x = event.x() - self.last_pos.x() move_y = event.y() - self.last_pos.y() if event.buttons() & Qt.LeftButton: # left mouse button self.set_x_rotation(self.x_rotation + 8 * move_y) self.set_y_rotation(self.y_rotation + 8 * move_x) elif event.buttons() & Qt.RightButton: # right mouse button self.set_x_rotation(self.x_rotation + 8 * move_y) self.set_z_rotation(self.z_rotation + 8 * move_x) # spin pyramid around itself self.last_pos = event.pos()
class GLWidget(QOpenGLWidget): clicked = pyqtSignal() PROGRAM_VERTEX_ATTRIBUTE, PROGRAM_TEXCOORD_ATTRIBUTE = range(2) vsrc = """ attribute highp vec4 vertex; attribute mediump vec4 texCoord; varying mediump vec4 texc; uniform mediump mat4 matrix; void main(void) { gl_Position = matrix * vertex; texc = texCoord; } """ fsrc = """ uniform sampler2D texture; varying mediump vec4 texc; void main(void) { gl_FragColor = texture2D(texture, texc.st); } """ coords = (((+1, -1, -1), (-1, -1, -1), (-1, +1, -1), (+1, +1, -1)), ((+1, +1, -1), (-1, +1, -1), (-1, +1, +1), (+1, +1, +1)), ((+1, -1, +1), (+1, -1, -1), (+1, +1, -1), (+1, +1, +1)), ((-1, -1, -1), (-1, -1, +1), (-1, +1, +1), (-1, +1, -1)), ((+1, -1, +1), (-1, -1, +1), (-1, -1, -1), (+1, -1, -1)), ((-1, -1, +1), (+1, -1, +1), (+1, +1, +1), (-1, +1, +1))) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.clearColor = QColor(Qt.black) self.xRot = 0 self.yRot = 0 self.zRot = 0 self.program = None self.lastPos = QPoint() def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(200, 200) def rotateBy(self, xAngle, yAngle, zAngle): self.xRot += xAngle self.yRot += yAngle self.zRot += zAngle self.update() def setClearColor(self, color): self.clearColor = color self.update() def initializeGL(self): self.gl = self.context().versionFunctions() self.gl.initializeOpenGLFunctions() self.makeObject() self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glEnable(self.gl.GL_CULL_FACE) vshader = QOpenGLShader(QOpenGLShader.Vertex, self) vshader.compileSourceCode(self.vsrc) fshader = QOpenGLShader(QOpenGLShader.Fragment, self) fshader.compileSourceCode(self.fsrc) self.program = QOpenGLShaderProgram() self.program.addShader(vshader) self.program.addShader(fshader) self.program.bindAttributeLocation('vertex', self.PROGRAM_VERTEX_ATTRIBUTE) self.program.bindAttributeLocation('texCoord', self.PROGRAM_TEXCOORD_ATTRIBUTE) self.program.link() self.program.bind() self.program.setUniformValue('texture', 0) self.program.enableAttributeArray(self.PROGRAM_VERTEX_ATTRIBUTE) self.program.enableAttributeArray(self.PROGRAM_TEXCOORD_ATTRIBUTE) self.program.setAttributeArray(self.PROGRAM_VERTEX_ATTRIBUTE, self.vertices) self.program.setAttributeArray(self.PROGRAM_TEXCOORD_ATTRIBUTE, self.texCoords) def paintGL(self): self.gl.glClearColor(self.clearColor.redF(), self.clearColor.greenF(), self.clearColor.blueF(), self.clearColor.alphaF()) self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) m = QMatrix4x4() m.ortho(-0.5, 0.5, 0.5, -0.5, 4.0, 15.0) m.translate(0.0, 0.0, -10.0) m.rotate(self.xRot / 16.0, 1.0, 0.0, 0.0) m.rotate(self.yRot / 16.0, 0.0, 1.0, 0.0) m.rotate(self.zRot / 16.0, 0.0, 0.0, 1.0) self.program.setUniformValue('matrix', m) for i, texture in enumerate(self.textures): texture.bind() self.gl.glDrawArrays(self.gl.GL_TRIANGLE_FAN, i * 4, 4) def resizeGL(self, width, height): side = min(width, height) self.gl.glViewport((width - side) // 2, (height - side) // 2, side, side) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.rotateBy(8 * dy, 8 * dx, 0) elif event.buttons() & Qt.RightButton: self.rotateBy(8 * dy, 0, 8 * dx) self.lastPos = event.pos() def mouseReleaseEvent(self, event): self.clicked.emit() def makeObject(self): self.textures = [] self.texCoords = [] self.vertices = [] root = QFileInfo(__file__).absolutePath() for i in range(6): self.textures.append( QOpenGLTexture( QImage(root + ('/textures/metal%d.png' % (i + 1))).mirrored())) for j in range(4): self.texCoords.append(((j == 0 or j == 3), (j == 0 or j == 1))) x, y, z = self.coords[i][j] self.vertices.append((0.2 * x, 0.2 * y, 0.2 * z))
class GLWidget(QtWidgets.QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) orthoChanged = pyqtSignal(float) def __init__(self, parent): # super(GLWidget, self).__init__(parent) self.objects = { 'box': self.makeBox, 'sphere': self.makeSphere, 'pyramid': self.makePyramid, 'thor': self.makeThor, 'cylinder': self.makeCylinder } self.csg_objects = { 'a_or_b': self.makeAorB, 'a_and_b': self.makeAandB, # 'a_not_b': self.makeAnotB, # 'b_not_a': self.makeBnotA } QtWidgets.QOpenGLWidget.__init__(self, parent) # Positioning self.xRot = 0 self.yRot = 0 self.zRot = 0 self.orthoSize = 1 self.invertedWheel = False self.mouseWheelSensitivity = 5 self.rotationSensitivity = 5 self.GLlighting = False self.lastPos = QPoint() self.object = None def setGLlighting(self, value: bool) -> None: self.GLlighting = value self.update() def setMouseWheelInvertion(self, value: bool) -> None: self.invertedWheel = value def setMouseWheelSensitivity(self, value: int) -> None: self.mouseWheelSensitivity = value def setRotationSensitivity(self, value: int) -> None: self.rotationSensitivity = value def getObjectsNames(self): return self.objects.keys() def setObject(self, objectName, **kwargs): if objectName == 'sphere': r = kwargs['r'] step = kwargs['step'] self.object = self.objects[objectName](r, step) elif objectName == 'thor': ir = kwargs['ir'] step = kwargs['step'] self.object = self.objects[objectName](ir, step) elif objectName == 'cylinder': r = kwargs['r'] h = kwargs['h'] step = kwargs['step'] self.object = self.objects[objectName](r, h, step) elif objectName == 'csg': operation = kwargs['operation'] self.object = self.csg_objects[operation](self.makeBox(), self.makeCylinder( 1, 0.5, 100)) else: self.object = self.objects[objectName]() self.update() def makeAorB(self, objA, objB): drawAorBList = glGenLists(1) glNewList(drawAorBList, GL_COMPILE) glCallList(objA) glCallList(objB) glEndList() return drawAorBList def makeAandB(self, objA, objB): drawAandBList = glGenLists(1) glNewList(drawAandBList, GL_COMPILE) glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) glCullFace(GL_BACK) glCallList(objA) glDepthMask(GL_FALSE) glEnable(GL_STENCIL_TEST) glStencilOp(GL_KEEP, GL_KEEP, GL_INCR) glStencilFunc(GL_ALWAYS, 0, 0) glCallList(objB) glStencilOp(GL_KEEP, GL_KEEP, GL_DECR) glCullFace(GL_FRONT) glCallList(objB) glDepthMask(GL_TRUE) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) glStencilFunc(GL_NOTEQUAL, 0, 1) glDisable(GL_DEPTH_TEST) glCullFace(GL_BACK) glCallList(objA) glDisable(GL_STENCIL_TEST) glEndList() return drawAandBList def makeBox(self): drawBoxList = glGenLists(1) glNewList(drawBoxList, GL_COMPILE) # Front glBegin(GL_POLYGON) glNormal(0, 0, -1) glVertex3f(-0.5, -0.5, -0.5) glVertex3f(-0.5, 0.5, -0.5) glVertex3f(0.5, 0.5, -0.5) glVertex3f(0.5, -0.5, -0.5) glEnd() # Back glBegin(GL_POLYGON) glColor3f(1.0, 1.0, 1.0) glNormal(0, 0, 1) glVertex3f(0.5, -0.5, 0.5) glVertex3f(0.5, 0.5, 0.5) glVertex3f(-0.5, 0.5, 0.5) glVertex3f(-0.5, -0.5, 0.5) glEnd() # # Right glBegin(GL_POLYGON) glColor3f(1.0, 0.0, 1.0) glNormal(1, 0, 0) glVertex3f(0.5, -0.5, -0.5) glVertex3f(0.5, 0.5, -0.5) glVertex3f(0.5, 0.5, 0.5) glVertex3f(0.5, -0.5, 0.5) glEnd() # # Left glBegin(GL_POLYGON) glColor3f(0.0, 1.0, 0.0) glNormal(-1, 0, 0) glVertex3f(-0.5, -0.5, 0.5) glVertex3f(-0.5, 0.5, 0.5) glVertex3f(-0.5, 0.5, -0.5) glVertex3f(-0.5, -0.5, -0.5) glEnd() # # Top glBegin(GL_POLYGON) glColor3f(0.0, 0.0, 1.0) glNormal(0, 1, 0) glVertex3f(0.5, 0.5, 0.5) glVertex3f(0.5, 0.5, -0.5) glVertex3f(-0.5, 0.5, -0.5) glVertex3f(-0.5, 0.5, 0.5) glEnd() # # Bottom glBegin(GL_POLYGON) glNormal(0, -1, 0) glColor3f(1.0, 0.0, 0.0) glVertex3f(0.5, -0.5, -0.5) glVertex3f(0.5, -0.5, 0.5) glVertex3f(-0.5, -0.5, 0.5) glVertex3f(-0.5, -0.5, -0.5) glEnd() glEndList() return drawBoxList def makeSphere(self, r, step): drawSphereList = glGenLists(1) glNewList(drawSphereList, GL_COMPILE) for i in range(step + 1): lat0 = math.pi * (-0.5 + i - 1 / step) z0 = math.sin(lat0) zr0 = math.cos(lat0) lat1 = math.pi * (-0.5 + i / step) z1 = math.sin(lat1) zr1 = math.cos(lat1) glBegin(GL_QUAD_STRIP) for j in range(step + 1): lng = 2 * math.pi * (j - 1) / step x = math.cos(lng) y = math.sin(lng) glNormal3f(x * zr0, y * zr0, z0) glColor3f(i % 2, 1, 0) glVertex3f(r * x * zr0, r * y * zr0, r * z0) glNormal3f(x * zr1, y * zr1, z1) glColor3f(1, j % 2, 0) glVertex3f(r * x * zr1, r * y * zr1, r * z1) glEnd() glEndList() return drawSphereList def makeThor(self, internal_radius, step): drawThorList = glGenLists(1) glNewList(drawThorList, GL_COMPILE) for i in range(step + 1): glBegin(GL_QUAD_STRIP) for j in range(step + 1): k = 1 while k >= 0: s = (i + k) % step + 0.5 t = j % step radius = 1 - internal_radius x = (1 + radius * math.cos(s * 2 * math.pi / step) ) * math.sin(t * 2 * math.pi / step) y = (1 + radius * math.cos(s * 2 * math.pi / step) ) * math.cos(t * 2 * math.pi / step) z = radius * math.sin(s * 2 * math.pi / step) glNormal(x, y, z) glVertex3f(x, y, z) k -= 1 glEnd() glEndList() return drawThorList def makePyramid(self): drawPyramidList = glGenLists(1) glNewList(drawPyramidList, GL_COMPILE) # Face 1 glBegin(GL_POLYGON) glColor3f(1.0, 0.0, 1.0) glNormal(0, 0.5, 0.5) glVertex3f(0.5, 0.5, 0) glVertex3f(-0.5, 0.5, 0) glVertex3f(0, 0, 0.5) glEnd() # # Face 2 glBegin(GL_POLYGON) glColor3f(1.0, 1.0, 1.0) glNormal(-0.5, 0, 0.5) glVertex3f(-0.5, 0.5, 0) glVertex3f(-0.5, -0.5, 0) glVertex3f(0, 0, 0.5) glEnd() # # Face 3 glBegin(GL_POLYGON) glColor3f(0.0, 0.0, 1.0) glNormal(0, -0.5, 0.5) glVertex3f(-0.5, -0.5, 0) glVertex3f(0.5, -0.5, 0) glVertex3f(0, 0, 0.5) glEnd() # # Face 4 glBegin(GL_POLYGON) glColor3f(0.0, 0.5, 1.0) glNormal(0.5, 0, 0.5) glVertex3f(0.5, -0.5, 0) glVertex3f(0.5, 0.5, 0) glVertex3f(0, 0, 0.5) glEnd() # # Bottom glBegin(GL_POLYGON) glColor3f(1.0, 0.0, 0.0) glNormal(0, 0, -1) glVertex3f(-0.5, -0.5, 0.0) glVertex3f(0.5, -0.5, 0.0) glVertex3f(0.5, 0.5, 0.0) glVertex3f(-0.5, 0.5, 0.0) glEnd() glEndList() return drawPyramidList def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) if self.GLlighting: glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_COLOR_MATERIAL) glShadeModel(GL_SMOOTH) #TODO ShadeModel checkbox glMaterialfv(GL_FRONT, GL_SPECULAR, 1, 1, 1, 1) glMaterialfv(GL_FRONT, GL_SHININESS, 50) glLightfv(GL_LIGHT0, GL_POSITION, 0.5, -1, -0.2, 0) else: glDisable(GL_LIGHTING) glDisable(GL_LIGHT0) glDisable(GL_COLOR_MATERIAL) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.orthoSize, +self.orthoSize, +self.orthoSize, -self.orthoSize, 2.0, 15.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() # glOrtho(-self.orthoSize, +self.orthoSize, +self.orthoSize, -self.orthoSize, 2.0, 15.0) # glTranslatef(-2.5, 0.5, -6.0) glTranslated(0.0, 0.0, -10.0) glColor3f(1.0, 1.5, 0.0) glRotated(self.xRot / self.rotationSensitivity, 1.0, 0.0, 0.0) glRotated(self.yRot / self.rotationSensitivity, 0.0, 1.0, 0.0) glRotated(self.zRot / self.rotationSensitivity, 0.0, 0.0, 1.0) glCallList(self.object) # glFlush() def makeCylinder(self, radius: float, height: float, step: int): step = 1 / step drawCylinderList = glGenLists(1) glNewList(drawCylinderList, GL_COMPILE) # Draw the tube glColor3f(1.0, 1.0, 1.0) glBegin(GL_QUAD_STRIP) angle = 0 while angle < 2 * math.pi: x = radius * math.cos(angle) y = radius * math.sin(angle) glNormal3f(x, y, height // 2) glVertex3f(x, y, height // 2) glNormal3f(x, y, -height // 2) glVertex3f(x, y, -height // 2) angle += step glVertex3f(radius, 0, height // 2) glVertex3f(radius, 0, -height // 2) glEnd() # Draw the circles glColor3f(1, 0.5, 0.5) glBegin(GL_POLYGON) angle = 0 while angle < 2 * math.pi: x = radius * math.cos(angle) y = radius * math.sin(angle) glNormal3f(x, y, height // 2) glVertex3f(x, y, height // 2) angle += step glVertex3f(radius, 0, height // 2) glEnd() glBegin(GL_POLYGON) angle = 0 while angle < 2 * math.pi: x = radius * math.cos(angle) y = radius * math.sin(angle) glNormal3f(x, y, -height // 2) glVertex3f(x, y, -height // 2) angle += step glVertex3f(radius, 0, -height // 2) glEnd() glEndList() return drawCylinderList def resetPosition(self) -> None: self.xRot = 0 self.yRot = 0 self.zRot = 0 self.orthoSize = 1 self.update() def resizeGL(self, width, height): glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.orthoSize, +self.orthoSize, +self.orthoSize, -self.orthoSize, 2.0, 15.0) glMatrixMode(GL_MODELVIEW) def initializeGL(self): self.setObject('cylinder', r=0.5, h=1, step=100) # self.object = self.objects['box']() glEnable(GL_DEPTH_TEST) glViewport(0, 0, self.width(), self.height()) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(45.0, self.width() / self.height(), 0.1, 100.0) def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + dy) self.setYRotation(self.yRot + dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + dy) self.setZRotation(self.zRot + dx) def mousePressEvent(self, event): self.lastPos = event.pos() def wheelEvent(self, event): delta = event.angleDelta().y() / (120 * self.mouseWheelSensitivity) delta = -delta if self.invertedWheel else delta print(f'Wheel: {delta}') self.setOrtho(self.orthoSize + delta) def setOrtho(self, value): value = self.normalizeOrtho(value) if value != self.orthoSize: self.orthoSize = value # self.orthoChanged.emit(value) self.update() print(value) def normalizeOrtho(self, value): if value < 0.05: return 0.05 if value > 2: return 2 return value def print_angles(self): print(f'X: {self.xRot}\t' f'Y: {self.yRot}\t' f'Z: {self.zRot}\t') def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() self.print_angles() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() self.print_angles() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() self.print_angles() def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle
class MandelbrotWidget(QWidget): def __init__(self, parent=None): super(MandelbrotWidget, self).__init__(parent) self.thread = RenderThread() self.pixmap = QPixmap() self.pixmapOffset = QPoint() self.lastDragPos = QPoint() self.centerX = DefaultCenterX self.centerY = DefaultCenterY self.pixmapScale = DefaultScale self.curScale = DefaultScale self.thread.renderedImage.connect(self.updatePixmap) self.setWindowTitle("Mandelbrot") self.setCursor(Qt.CrossCursor) self.resize(550, 400) def paintEvent(self, event): painter = QPainter(self) painter.fillRect(self.rect(), Qt.black) if self.pixmap.isNull(): painter.setPen(Qt.white) painter.drawText( self.rect(), Qt.AlignCenter, "Rendering initial image, please wait..." ) return if self.curScale == self.pixmapScale: painter.drawPixmap(self.pixmapOffset, self.pixmap) else: scaleFactor = self.pixmapScale / self.curScale newWidth = int(self.pixmap.width() * scaleFactor) newHeight = int(self.pixmap.height() * scaleFactor) newX = self.pixmapOffset.x() + (self.pixmap.width() - newWidth) / 2 newY = self.pixmapOffset.y() + (self.pixmap.height() - newHeight) / 2 painter.save() painter.translate(newX, newY) painter.scale(scaleFactor, scaleFactor) exposed, _ = painter.matrix().inverted() exposed = exposed.mapRect(self.rect()).adjusted(-1, -1, 1, 1) painter.drawPixmap(exposed, self.pixmap, exposed) painter.restore() text = ( "Use mouse wheel or the '+' and '-' keys to zoom. Press and " "hold left mouse button to scroll." ) metrics = painter.fontMetrics() textWidth = metrics.width(text) painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 127)) painter.drawRect( (self.width() - textWidth) / 2 - 5, 0, textWidth + 10, metrics.lineSpacing() + 5, ) painter.setPen(Qt.white) painter.drawText( (self.width() - textWidth) / 2, metrics.leading() + metrics.ascent(), text ) def resizeEvent(self, event): self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom(ZoomInFactor) elif event.key() == Qt.Key_Minus: self.zoom(ZoomOutFactor) elif event.key() == Qt.Key_Left: self.scroll(-ScrollStep, 0) elif event.key() == Qt.Key_Right: self.scroll(+ScrollStep, 0) elif event.key() == Qt.Key_Down: self.scroll(0, -ScrollStep) elif event.key() == Qt.Key_Up: self.scroll(0, +ScrollStep) else: super(MandelbrotWidget, self).keyPressEvent(event) def wheelEvent(self, event): numDegrees = event.angleDelta().y() / 8 numSteps = numDegrees / 15.0 self.zoom(pow(ZoomInFactor, numSteps)) def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: self.lastDragPos = QPoint(event.pos()) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint(event.pos()) self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.pixmapOffset += event.pos() - self.lastDragPos self.lastDragPos = QPoint() deltaX = (self.width() - self.pixmap.width()) / 2 - self.pixmapOffset.x() deltaY = (self.height() - self.pixmap.height()) / 2 - self.pixmapOffset.y() self.scroll(deltaX, deltaY) def updatePixmap(self, image, scaleFactor): if not self.lastDragPos.isNull(): return self.pixmap = QPixmap.fromImage(image) self.pixmapOffset = QPoint() self.lastDragPosition = QPoint() self.pixmapScale = scaleFactor self.update() def zoom(self, zoomFactor): self.curScale *= zoomFactor self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size()) def scroll(self, deltaX, deltaY): self.centerX += deltaX * self.curScale self.centerY += deltaY * self.curScale self.update() self.thread.render(self.centerX, self.centerY, self.curScale, self.size())
def is_pos_in_separea(self, pos: QPoint): if self.scene_type == 0: return False padding = constants.SEPARATION_PADDING * self.view_rect().height() return self.y_sep - padding <= pos.y() <= self.y_sep + padding
class CorvusGL3DWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) def __init__(self, parent=None): super(CorvusGL3DWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.points = [] self.lastPos = QPoint() self.black = QColor.fromRgb(0.0,0.0,0.0) def minimumSizeHint(self): width = 50 height = 50 return QSize(width, height) def sizeHint(self): width = 500 height = 500 return QSize(width, height) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def initializeGL(self): self.setClearColor(self.black.darker()) self.object = self.makeObject() gl.glShadeModel(gl.GL_FLAT) gl.glEnable(gl.GL_DEPTH_TEST) gl.glEnable(gl.GL_CULL_FACE) def updateObject(self): self.setClearColor(self.black.darker()) self.object = self.makeObject() self.repaint() def paintGL(self): gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gl.glLoadIdentity() gl.glTranslated(0.0, 0.0, -10.0) gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) gl.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) if side < 0: return gl.glViewport((width - side) // 2, (height - side) // 2, side, side) gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() gl.glOrtho(-1.0, +1.0, +1.0, -1.0, 4.0, 15.0) gl.glMatrixMode(gl.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * -dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * -dy) self.setZRotation(self.zRot + 8 * -dx) self.lastPos = event.pos() def makeObject(self): genList = gl.glGenLists(1) gl.glNewList(genList, gl.GL_COMPILE) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glEnable(gl.GL_BLEND ) gl.glBegin(gl.GL_POINTS) red = 147.5 / 255.0 green = 167.1 / 255.0 blue = 186.2 / 255.0 for p in self.points: x = p[0] y = p[1] z = p[2] alpha = pow((1.0 - (sqrt(pow(x,2) + pow(y,2) + pow(z,2)) / sqrt(3.0))), 4) self.setColor(red, green, blue, alpha) gl.glVertex3d(x,y,z) gl.glEnd() gl.glEndList() return genList def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def setClearColor(self, c): gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, red, green, blue, alpha): gl.glColor4f(red, green, blue, alpha)
def float_horizon(scene_width, scene_hight, x_min, x_max, x_step, z_min, z_max, z_step, tx, ty, tz, func, image): # инициализация массивов горизонтов top = {x: 0 for x in range(1, int(scene_width) + 1)} bottom = {x: scene_hight for x in range(1, int(scene_width) + 1)} z = z_max # duyet theo chiều từ gần ra xa while z >= z_min: #print("z = ", z) # mặt phẳng toạ độ Z x = x_min y = func(x, z) # phép quay theo X, Y, Z x, y, z_buf = tranform(x, y, z, tx, ty, tz) # Обрабатываем левое ребро(смотрим предыдущее с текущим) #если точка является первой точкой на первой кривой if fabs(z - z_max) < eps: P = QPoint(x, y) else: top, bottom = add_line(P.x(), P.y(), x, y, top, bottom, image) P = QPoint(x, y) # điểm bắt đầu trong mặt phẳng z = const x = x_min while x <= x_max: #print("\t x = ", x) # xác định điểm tiếp theo y = func(x, z) x_curr, y_curr, z_curr = tranform(x, y, z, tx, ty, tz) p_curr = QPoint(x_curr, y_curr) isVis_curr = isVisable(p_curr, top, bottom) if fabs(x - x_min) > eps: isVis_curr = isVisable(p_curr, top, bottom) if (isVis_curr * isVis_prev == 0 and isVis_curr + isVis_prev): if (isVis_curr + isVis_prev == 1): try: if (p_prev.x() == p_curr.x()): I = QPoint(p_prev.x(), min(p_curr.y(), p_prev.y())) top[I.x()] = I.y() print("check", p_prev, p_curr, I, top[I.x()], isVis_curr, isVis_prev) else: I = intersection(p_prev, p_curr, top[p_prev.x()], top[p_curr.x()]) except: print("err") else: if (p_prev.x() == p_curr.x()): I = QPoint(p_prev.x(), max(p_curr.y(), p_prev.y())) bottom[I.x()] = I.y() else: y1 = bottom[p_prev.x()] y2 = bottom[p_curr.x()] I = intersection(p_prev, p_curr, y1, y2) if (isVis_curr == 0): top, bottom = add_line(p_prev.x(), p_prev.y(), I.x(), I.y(), top, bottom, image) if (p_prev.x() == p_curr.x()): print('----', top[p_prev.x()], bottom[p_prev.x()]) else: top, bottom = add_line(I.x(), I.y(), p_curr.x(), p_curr.y(), top, bottom, image) elif isVis_curr * isVis_prev != 0: top, bottom = add_line(p_prev.x(), p_prev.y(), p_curr.x(), p_curr.y(), top, bottom, image) p_prev = p_curr isVis_prev = isVis_curr + 0 x += x_step # Обрабатываем правое ребро(смотрим текущее со следующим) if fabs(z - z_max) < eps: Q = p_curr else: top, bottom = add_line(Q.x(), Q.y(), p_curr.x(), p_curr.y(), top, bottom, image) Q = p_curr z -= z_step return image
def mouseMoveEvent(self, event): """if old_pos exists moves the frame""" if (self.old_pos): delta = QPoint(event.globalPos() - self.old_pos) self.move(self.x() + delta.x(), self.y() + delta.y()) self.old_pos = event.globalPos()
class Overlay(QWidget): def __init__(self, parent, binpath): super().__init__(parent) sizePolicy = QSizePolicy() sizePolicy.setHorizontalPolicy(QSizePolicy.Maximum) sizePolicy.setVerticalPolicy(QSizePolicy.Maximum) #self.setSizePolicy(sizePolicy) self.setMouseTracking(True) self.on_selection = False self.selected = False self.c = Communicate() self.start_position = QPoint(0,0) self.last_position = QPoint(0,0) image = ( b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00" b"\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00" b"\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00" b"\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00" b"\x00\x00\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00" b"\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") im = QImage(image, 8,8, QImage.Format_RGB16) im = im.scaled(64,64) self.crop = QPixmap() self.crop.convertFromImage(im) def insideSelection(self, point): width = self.last_position.x() - self.start_position.x() height = self.last_position.y() - self.start_position.y() return ( point.x() > self.start_position.x() and point.x() < self.start_position.x() + width and point.y() > self.start_position.y() and point.y() < self.start_position.y() + height ) def mouseMoveEvent(self, event): if self.on_selection: self.last_position = event.pos() self.update() def mousePressEvent(self, QMouseEvent): if not self.insideSelection(QMouseEvent.pos()): self.on_selection = True self.selected = True self.start_position = QMouseEvent.pos() self.last_position = QMouseEvent.pos() self.update() def mouseDoubleClickEvent(self, QMouseEvent): if self.insideSelection(QMouseEvent.pos()): width = self.last_position.x() - self.start_position.x() height = self.last_position.y() - self.start_position.y() self.c.cropImage.emit(self.start_position.x(), self.start_position.y(), width,height) def mouseReleaseEvent(self, QMouseEvent): self.on_selection = False self.update() def enterEvent(self, event): return super().enterEvent(event) def leaveEvent(self, event): return super().enterEvent(event) def paintEvent(self, e): qp = QPainter() qp.begin(self) #self.drawWidget(qp) if self.selected: qp.setCompositionMode(QPainter.CompositionMode_HardLight) qp.setBrush(QColor(0, 0, 0, 128)) qp.drawRect(0,0, self.width(), self.height()) qp.setCompositionMode(QPainter.CompositionMode_Overlay) qp.setBrush(QColor(255, 255, 255, 255)) width = self.last_position.x() - self.start_position.x() height = self.last_position.y()-self.start_position.y() qp.drawRect(self.start_position.x(), self.start_position.y(), width, height) qp.setCompositionMode(QPainter.CompositionMode_SourceOver) image_w = min([abs(width), abs(height), self.crop.width()]) #self.crop.width() image_h = image_w #self.crop.height() qp.drawPixmap(self.start_position.x() + width/2 - image_w/2, self.start_position.y() + height/2 - image_h/2, image_w, image_h, self.crop) qp.end()
def mouseMoveEvent(self, event): delta = QPoint (event.globalPos() - self.oldPos) self.move(self.x() + delta.x(), self.y() + delta.y()) self.oldPos = event.globalPos()
class RenderArea(QWidget): Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse, Arc, Chord, \ Pie, Path, Text, Pixmap = range(13) def __init__(self, machine, parent=None): super(RenderArea, self).__init__(parent) self.pen = QPen() self.brush = QBrush() self.antialiased = True self.setBackgroundRole(QPalette.Base) self.setAutoFillBackground(True) self.machine = machine self.dist_radius = min(self.width() / 4, self.height() / 4) * 1.5 self.dist_center = QPoint(self.width() / 2.0, self.height() / 2.0) self.n_states = len(self.machine.getStates()) self.state_radius = self.funcc(self.dist_radius, self.n_states) self.active = -1 self.t_active = -1 self.pts = [] #Brushes linearGradient = QLinearGradient(-self.state_radius, -self.state_radius, self.state_radius, self.state_radius) linearGradient.setColorAt(0.0, Qt.darkGreen) linearGradient.setColorAt(0.7, Qt.green) linearGradient.setColorAt(0.3, Qt.green) linearGradient.setColorAt(1.0, Qt.white) self.greenGradientBrush = QBrush(linearGradient) linearGradient = QLinearGradient(-self.state_radius, -self.state_radius, self.state_radius, self.state_radius) linearGradient.setColorAt(0.0, Qt.darkGray) linearGradient.setColorAt(0.7, Qt.lightGray) linearGradient.setColorAt(0.3, Qt.gray) linearGradient.setColorAt(1.0, Qt.white) self.grayGradientBrush = QBrush(linearGradient) self.setBrush(self.grayGradientBrush) #end brushes def funcc(self, r, n): return int((r*0.05) / (n*0.04)) def minimumSizeHint(self): return QSize(100, 100) def sizeHint(self): return QSize(400, 200) def setPen(self, pen): self.pen = pen self.update() def setBrush(self, brush): self.brush = brush self.update() def resizeEvent(self, event): self.dist_center = QPoint(self.width() / 2.0, self.height() / 2.0) self.dist_radius = min(self.width() / 4, self.height() / 4) * 1.5 self.state_radius = self.funcc(self.dist_radius, self.n_states) self.update() def poly(self, pts): return QPolygonF(map(lambda p: QPointF(*p), pts)) def wave(self): t = self.machine.getActiveTransition() if t != None: init = QPoint(t.getOrig()[0], t.getOrig()[1]) end = QPoint(t.getDest()[0], t.getDest()[1]) angle = t.getAngle() #print('processing transition', t.id, t.orig, t.dest) while t.isActive(): #for i in range(3): #for testing self.pts = [[init.x(), init.y()], [end.x(), end.y()]] if self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] <= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] >= self.pts[1][1]: self.sumPoint(angle) elif self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: while self.pts[0][0] >= self.pts[1][0] and self.pts[0][1] <= self.pts[1][1]: self.sumPoint(angle) def sumPoint(self, angle): self.pts[0][0] += (self.state_radius * math.cos(angle) * 0.1) self.pts[0][1] -= (self.state_radius * math.sin(angle) * 0.1) self.update() QApplication.processEvents() time.sleep(0.025) def paintEvent(self, event): painter = QPainter(self) painter.setPen(self.pen) painter.setBrush(self.brush) if self.antialiased: painter.setRenderHint(QPainter.Antialiasing) angle_step = 360 / self.n_states painter.save() #Save_1. Save the state of the system (push matrix) painter.translate(self.dist_center.x(), self.dist_center.y()) # go to the center of the render area painter.rotate(-180) #to start painting from the left side of the circle (clockwise) #center of the circumference where through we are going to paint our states x = self.dist_radius * math.cos(0) y = self.dist_radius * math.sin(0) for h in range(self.n_states): rot = angle_step * h # each state is equidistant from the others. We paint them in circles painter.save() #Save_2 painter.rotate(rot) #now our system is pointing to the next state to be drawn painter.translate(x,y) #now our origin is in the center of the next state to be drawn #if the state is active, fill it green if self.machine.getState(h).isActive(): painter.setBrush(self.greenGradientBrush) painter.drawEllipse(QPoint(0,0), self.state_radius, self.state_radius) #draw the new state #global position of transformed coordinates (before any transformation, origin at top-left corner) gx = painter.worldTransform().map(QPoint(0,0)).x() gy = painter.worldTransform().map(QPoint(0,0)).y() self.machine.getState(h).setPos(gx, gy) #store the center of the state without any transformation applied # text transformation. Our origin is still in the center of the current state painter.save() #Save_3 painter.rotate(180) #making the text go vertical painter.rotate(-rot) #undoing the rotation made for painting the state. No the text is horizontal font = painter.font(); font.setPixelSize(self.state_radius*.4); painter.setFont(font); rect = QRect(-self.state_radius, -self.state_radius, self.state_radius*2, self.state_radius*2) painter.drawText(rect, Qt.AlignCenter, self.machine.getState(h).getName()); painter.restore() #Restore_3 #end text transformation painter.restore() #Restore_2 painter.restore() #Restore_1. Restore the state of the system (pop matrix) #drawing transitions. Line between states painter.save() # Save_4 pptv = QTransform() #Define a new transformation. Needed to rotate the system along other axis than Z pptv.translate(0, self.height()) #We are now at the bottom-left corner of the screen pptv.rotate(-180, Qt.XAxis) #Rotate along the X-axis so now we are in a typical cartesian system. painter.setTransform(pptv) #Apply the transformation states = self.machine.getStates() for state in states: transitions = state.getTransitions() for transition in transitions: #get the center of the origin and destination states in our current system state orig = QPoint(state.getPos()[0], state.getPos()[1]) end = QPoint(self.machine.getState(transition.getStateEnd()).getPos()[0], self.machine.getState(transition.getStateEnd()).getPos()[1]) # get those coordinates without transformation orig2 = QPoint(painter.worldTransform().map(orig)) end2 = QPoint(painter.worldTransform().map(end)) #get the angle between states centers and the horizon angle = math.atan2(end2.y() - orig2.y(), end2.x() - orig2.x()) #get the coordinates of the starting point of the transition (it starts in the bound of the state, not in the center) newX = self.state_radius * math.cos(angle) + orig2.x() newY = self.state_radius * math.sin(angle) + orig2.y() #now the transition starts at the border, not in the center orig2.setX(newX) orig2.setY(newY) #same for the destination state angle2 = math.atan2(orig2.y() - end2.y(), orig2.x() - end2.x()) newX2 = self.state_radius * math.cos(angle2) + end2.x() newY2 = self.state_radius * math.sin(angle2) + end2.y() end2.setX(newX2) end2.setY(newY2) #draw the line between the origin and destination states painter.drawLine(orig2, end2) #get the start and the end of the transition untransformed init = QPoint(painter.worldTransform().map(orig2)) end = QPoint(painter.worldTransform().map(end2)) #store that info transition.setOrig(init.x(), init.y()) transition.setDest(end.x(), end.y()) transition.setAngle(angle) painter.restore() #Restore_4 #Appliying style to the transitions painter.setPen(QPen(QColor(Qt.gray), 3)) for state in self.machine.getStates(): for transition in state.getTransitions(): #get the start and end coordinates of the transition i = QPoint(transition.getOrig()[0], transition.getOrig()[1]) o = QPoint(transition.getDest()[0], transition.getDest()[1]) painter.drawPolyline(i, o) #Drawing the arrow at the end of the transition painter.save() #Save_5 painter.setPen(QPen(QColor(Qt.gray), 2)) painter.translate(transition.getDest()[0],transition.getDest()[1]) #Go to the end of the transition painter.rotate(90 - transition.getAngle()*180/math.pi) #Rotate to point in the direction of the transition #coordinates of the arrow (triangle) a = QPoint(0,0) b = QPoint(-5,10) c = QPoint(5,10) #coordinates of the arrow untransformed a1 = painter.worldTransform().map(a) b1 = painter.worldTransform().map(b) c1 = painter.worldTransform().map(c) #Drawin the actual arrow pointer = QPolygon([a,b,c]) painter.drawPolygon(pointer) painter.restore() #Restore_5 #For the animation of the transition painter.save() #Save_6 if transition.isActive(): #if the current transition is the active one the wave function will be running, so it's updating the canvas painter.setPen(QPen(QColor(Qt.green), 3)) painter.drawPolyline(i,o) painter.setPen(QPen(QColor(Qt.gray), 3)) painter.drawPolyline(self.poly(self.pts)) #Draw the arrow in the active state (red arrow) painter.setBrush(QBrush(QColor(255, 0, 0))) painter.setPen(QPen(QColor(Qt.red), 2)) pointer = QPolygon([a1,b1,c1]) painter.drawPolygon(pointer) #Ball that follows the line animation for x, y in self.pts: painter.drawEllipse(QRectF(self.pts[0][0] - 4, self.pts[0][1] - 4, 8, 8)) painter.restore() #Restore_6 #Painting the text of the transition painter.save() #Save_7 pptv = QTransform() painter.setPen(QPen(QColor(Qt.black), 3)) #get the middle point of the transition middleX = (transition.getOrig()[0] + transition.getDest()[0]) /2 middleY = (transition.getOrig()[1] + transition.getDest()[1]) /2 pptv.translate(middleX, middleY) #translate to that point painter.setTransform(pptv) #apply the transformation font = painter.font(); font.setPixelSize(self.state_radius*.2); painter.setFont(font); rect = QRect(-self.state_radius, -self.state_radius, self.state_radius*2, self.state_radius*2) name = str(transition.getId())+ '. ' + transition.getName() painter.drawText(rect, Qt.AlignCenter, name) painter.restore() #Restore_7 #paint the actual canvas painter.setPen(self.palette().dark().color()) painter.setBrush(Qt.NoBrush) painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1)) def start(self,n): '''print('active', n) self.active = n%3 self.deactivateAll() self.machine.setStateActive(self.active, True) #time.sleep(5) self.t_active = n%3 self.wave() for i in range(self.n_states): print('active', i) self.active = i self.deactivateAll() self.machine.setStateActive(self.active, True) self.update() QApplication.processEvents() time.sleep(2) self.t_active = i self.deactivateAll() self.machine.setTransitionActive (self.t_active, True) for i in self.machine.getTransitions(): print (i.isActive()) self.update() QApplication.processEvents() self.wave()''' def stop(self): self.machine.deactivateAll()
class GLWidget(QOpenGLWidget): def __init__(self, systemModel, parent=None): super(GLWidget, self).__init__(parent) self.setFixedSize(systemModel.view_width, systemModel.view_height) self.systemModel = systemModel self.min_method = None self.min_options = None self.errval0 = None self.errval1 = None self.errval = None self.iter_count = 0 self.image = None self.image_file = None self._show_target_image = True self.full_image = None self.image_bg_threshold = None self.latest_rendered_image = None self.im_def_scale = systemModel.view_width / systemModel.cam.width self.im_scale = self.im_def_scale self.im_xoff = 0 self.im_yoff = 0 self.im_width = systemModel.cam.width self.im_height = systemModel.cam.height self.debug_c = 0 self.gl = None self._paint_entered = False self._render = True self._algo_render = False self._center_model = False self._discretize_tol = False self.latest_discretization_err_q = False self.add_image_noise = True self._noise_image = os.path.join(SCRIPT_DIR, '../data/noise-fg.png') self._width = None self._height = None self._side = None self._gl_image = None self._object = None self._lastPos = QPoint() self._imgColor = QColor.fromRgbF(1, 1, 1, 0.4) self._fgColor = QColor.fromRgbF(0.6, 0.6, 0.6, 1) self._bgColor = QColor.fromRgbF(0, 0, 0, 1) #self._bgColor = QColor.fromCmykF(0.0, 0.0, 0.0, 1.0) self._frustum_near = 0.1 self._frustum_far = self.systemModel.max_distance self._expire = 0 def minimumSizeHint(self): return self.sizeHint() def maximumSizeHint(self): return self.sizeHint() def sizeHint(self): return QSize(self.systemModel.view_width, self.systemModel.view_height) def initializeGL(self): f = QSurfaceFormat() #f.setVersion(2, 2) f.setDepthBufferSize(32) p = QOpenGLVersionProfile(f) self.gl = self.context().versionFunctions(p) self.gl.initializeOpenGLFunctions() self.setClearColor(self._bgColor) self.loadObject() if not BATCH_MODE: self.loadTargetImageMeta( self.systemModel.asteroid.sample_image_meta_file) self.gl.glEnable(self.gl.GL_CULL_FACE) # for transparent asteroid image on top of model self.gl.glBlendFunc(self.gl.GL_SRC_ALPHA, self.gl.GL_ONE_MINUS_SRC_ALPHA) if self._render: self._rendOpts() else: self._projOpts() if not BATCH_MODE: self.loadTargetImage(self.systemModel.asteroid.sample_image_file) # if not USE_IMG_LABEL_FOR_SC_POS: # CentroidAlgo.update_sc_pos(self.systemModel, self.full_image) def _projOpts(self): # reset from potentially set rendering options self.gl.glDisable(self.gl.GL_LIGHTING) self.gl.glDisable(self.gl.GL_DEPTH_TEST) self.gl.glShadeModel(self.gl.GL_FLAT) def _rendOpts(self): # rendering options self.gl.glEnable(self.gl.GL_LIGHTING) self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glShadeModel(self.gl.GL_SMOOTH) # TODO: try with flat self.gl.glEnable(self.gl.GL_LIGHT0) def resizeGL(self, width, height): rel_scale = self.im_scale / self.im_def_scale self.im_def_scale = min(width / self.systemModel.cam.width, height / self.systemModel.cam.height) self.im_scale = self.im_def_scale * rel_scale self._width = width self._height = height self._side = min(width, height) self.updateFrustum() def updateFrustum(self): # calculate frustum based on fov, aspect & near # NOTE: with wide angle camera, would need to take into account # im_xoff, im_yoff, im_width and im_height x_fov = self.systemModel.cam.x_fov * self.im_def_scale / self.im_scale y_fov = self.systemModel.cam.y_fov * self.im_def_scale / self.im_scale # calculate frustum based on fov, aspect & near right = self._frustum_near * math.tan(math.radians(x_fov / 2)) top = self._frustum_near * math.tan(math.radians(y_fov / 2)) self._frustum = { 'left': -right, 'right': right, 'bottom': -top, 'top': top, } if self._width is not None: self.gl.glViewport((self._width - self._side) // 2, (self._height - self._side) // 2, self._side, self._side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() self.gl.glFrustum(self._frustum['left'], self._frustum['right'], self._frustum['bottom'], self._frustum['top'], self._frustum_near, self._frustum_far) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) def renderParams(self): m = self.systemModel # NOTE: with wide angle camera, would need to take into account # im_xoff, im_yoff, im_width and im_height xc_off = (self.im_xoff + self.im_width / 2 - m.cam.width / 2) xc_angle = xc_off / m.cam.width * math.radians(m.cam.x_fov) yc_off = (self.im_yoff + self.im_height / 2 - m.cam.height / 2) yc_angle = yc_off / m.cam.height * math.radians(m.cam.y_fov) # first rotate around x-axis, then y-axis, # note that diff angle in image y direction corresponds to rotation # around x-axis and vise versa q_crop = (np.quaternion(math.cos(-yc_angle / 2), math.sin( -yc_angle / 2), 0, 0) * np.quaternion(math.cos(-xc_angle / 2), 0, math.sin(-xc_angle / 2), 0)) x = m.x_off.value y = m.y_off.value z = m.z_off.value # rotate offsets using q_crop x, y, z = tools.q_times_v(q_crop.conj(), np.array([x, y, z])) # maybe put object in center of view if self._center_model: x, y = 0, 0 # get object rotation and turn it a bit based on cropping effect q, err_q = m.gl_sc_asteroid_rel_q(self._discretize_tol) if self._discretize_tol: self.latest_discretization_err_q = err_q qfin = (q * q_crop.conj()) rv = tools.q_to_angleaxis(qfin) # light direction light, _ = m.gl_light_rel_dir(err_q) res = (light, (x, y, z), (math.degrees(rv[0]), ) + tuple(rv[1:])) return res def paintGL(self): if self._algo_render: self.gl.glDisable(self.gl.GL_BLEND) else: self.gl.glEnable(self.gl.GL_BLEND) self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) light, transl, rot = self.renderParams() self.gl.glLoadIdentity() # sunlight config if self._render or self._algo_render: self.gl.glLightfv(self.gl.GL_LIGHT0, self.gl.GL_POSITION, tuple(-light) + (0, )) self.gl.glLightfv(self.gl.GL_LIGHT0, self.gl.GL_SPOT_DIRECTION, tuple(light)) self.gl.glLightfv(self.gl.GL_LIGHT0, self.gl.GL_DIFFUSE, (.4, .4, .4, 1)) self.gl.glLightfv(self.gl.GL_LIGHT0, self.gl.GL_AMBIENT, (0, 0, 0, 1)) self.gl.glLightModelfv(self.gl.GL_LIGHT_MODEL_AMBIENT, (0, 0, 0, 1)) self.gl.glTranslated(*transl) self.gl.glRotated(*rot) if self._object is not None: self.gl.glCallList(self._object) if not self._algo_render and self._gl_image is not None: self.gl.glLoadIdentity() self.setColor(self._imgColor) # self.gl.glRasterPos3f(self._frustum['left'], # self._frustum['bottom'], -self._frustum_near) self.gl.glWindowPos2f(0, 0) self.gl.glDrawPixels(self._image_w, self._image_h, self.gl.GL_RGBA, self.gl.GL_UNSIGNED_BYTE, self._gl_image) # dont need? commented out glFinish as it takes around 4s to run # after win10 "creators update" #self.gl.glFinish() def saveView(self, grayscale=True, depth=False): self.makeCurrent() # for some reason following gives 24 and not 32 bits # f = self.format() # print('dbs: %s'%f.depthBufferSize()) pixels = glReadPixels( 0, 0, self.systemModel.view_width, self.systemModel.view_height, self.gl.GL_DEPTH_COMPONENT if depth else self.gl.GL_LUMINANCE if grayscale else self.gl.GL_RGBA, self.gl.GL_FLOAT if depth else self.gl.GL_UNSIGNED_BYTE) data = np.frombuffer(pixels, dtype=('float32' if depth else 'uint8')) if depth: near = self._frustum_near far = self._frustum_far a = -(far - near) / (2.0 * far * near) b = (far + near) / (2.0 * far * near) data = np.divide(1.0, (2.0 * a) * data - (a - b)) # 1/((2*X-1)*a+b) data = np.flipud( data.reshape( [self.systemModel.view_height, self.systemModel.view_width] + ([] if depth or grayscale else [4]))) # print('data: %s'%(data,)) # cv2.imshow('target_image', data) # cv2.waitKey() return data def saveViewOld(self): fbo = self.grabFramebuffer() # calls paintGL buffer = QBuffer() buffer.open(QIODevice.ReadWrite) fbo.save(buffer, "PNG", quality=100) # TODO: find a more efficient way than # bytes => buffer => PNG => nparray => cvimage # - maybe here's some ideas: # https://vec.io/posts/faster-alternatives-to-glreadpixels\ # -and-glteximage2d-in-opengl-es imdata = np.frombuffer(buffer.data(), dtype='int8') view = cv2.imdecode(imdata, cv2.IMREAD_GRAYSCALE) return view def saveViewTest(self): if False: # this takes around double the time than current way fbo = self.grabFramebuffer() arr = fbo.constBits().asarray(512 * 512 * 4) view = [0] * 256 for i in range(1, 512 * 512 * 4, 4): view[arr[i]] += 1 elif False: # glReadPixels doesnt exist arr = self.gl.glReadPixels(0, 0, 512, 512, self.gl.GL_RGB, self.gl.GL_UNSIGNED_BYTE) view = [0] * 256 for i in range(1, 512 * 512 * 3, 3): view[arr[i]] += 1 return view def saveViewToFile(self, imgfile): cv2.imwrite(imgfile, self.render(center=False)) def render(self, center=True, depth=False, discretize_tol=False): if not self._render: self._rendOpts() self._algo_render = True self._discretize_tol = discretize_tol tmp = self._center_model self._center_model = center fbo = self.grabFramebuffer() # calls paintGL self.latest_rendered_image = rr = self.saveView(depth=False) if depth: dr = self.saveView(depth=True) self._center_model = tmp self._discretize_tol = False self._algo_render = False if not self._render: self._projOpts() return (rr, dr) if depth else rr def mousePressEvent(self, event): self._lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self._lastPos.x() dy = event.y() - self._lastPos.y() if event.buttons() & (Qt.LeftButton | Qt.RightButton): self.systemModel.x_rot.value = \ (self.systemModel.x_rot.value + dy/2 + 90) % 180 - 90 param = 'y_rot' if event.buttons() & Qt.LeftButton else 'z_rot' getattr(self.systemModel, param).value = \ (getattr(self.systemModel, param).value + dx/2) % 360 self.update() self._lastPos = event.pos() def setImageZoomAndResolution(self, im_xoff=0, im_yoff=0, im_width=None, im_height=None, im_scale=1): self.im_xoff = im_xoff self.im_yoff = im_yoff self.im_width = im_width or self.systemModel.cam.width self.im_height = im_height or self.systemModel.cam.height self.im_scale = im_scale self.image = ImageProc.crop_and_zoom_image(self.full_image, self.im_xoff, self.im_yoff, self.im_width, self.im_height, self.im_scale) self._image_h = self.image.shape[0] self._image_w = self.image.shape[1] if self._show_target_image: # form _gl_image that is used for rendering # black => 0 alpha, non-black => white => .5 alpha im = self.image.copy() alpha = np.zeros(im.shape, im.dtype) #im[im > 0] = 255 alpha[im > 0] = 128 self._gl_image = np.flipud(cv2.merge( (im, im, im, alpha))).tobytes() self.updateFrustum() # WORK-AROUND: for some reason wont use new frustum if window not resized s = self.parent().size() self.parent().resize(s.width() + 1, s.height()) self.parent().resize(s.width(), s.height()) self.update() QCoreApplication.processEvents() def loadTargetImage(self, src, remove_bg=True): tmp = cv2.imread(src, cv2.IMREAD_GRAYSCALE) if tmp is None: raise Exception('Cant load image from file %s' % (src, )) cam = self.systemModel.cam if tmp.shape != (cam.height, cam.width): # visit fails to generate 1024 high images tmp = cv2.resize(tmp, None, fx=cam.width / tmp.shape[1], fy=cam.height / tmp.shape[0], interpolation=cv2.INTER_CUBIC) if BATCH_MODE and self.add_image_noise and self._noise_image: tmp = ImageProc.add_noise_to_image(tmp, self._noise_image) self.image_file = src if remove_bg: self.full_image, h, th = ImageProc.process_target_image(tmp) self.image_bg_threshold = th self.parent().centroid.bg_threshold = th else: self.full_image = tmp self.image_bg_threshold = None self.parent().centroid.bg_threshold = None self.setImageZoomAndResolution(im_scale=self.im_def_scale) def loadTargetImageMeta(self, src): if True: # FIX: currently doesnt correspond with what is shown lblloader.load_image_meta(src, self.systemModel) else: self.systemModel.ast_x_rot.value = -83.88 self.systemModel.ast_y_rot.value = 74.38 self.systemModel.ast_z_rot.value = -77.98 self.systemModel.time.range = (1437391848.27 * 0.99, 1437391848.27 * 1.01) self.systemModel.time.value = 1437391848.27 self.systemModel.x_off.value = -0.42 self.systemModel.x_rot.value = -49.39 self.systemModel.y_off.value = 2.47 self.systemModel.y_rot.value = 123.26 self.systemModel.z_off.value = -158.39 self.systemModel.z_rot.value = -96.62 self.update() def loadObject(self, noisy_model=None): genList = self.gl.glGenLists(1) self.gl.glNewList(genList, self.gl.GL_COMPILE) self.gl.glBegin(self.gl.GL_TRIANGLES) # GL_POLYGON? self.setColor(self._fgColor) #self.gl.glEnable(self.gl.GL_COLOR_MATERIAL); #self.gl.glMaterialfv(self.gl.GL_FRONT, self.gl.GL_SPECULAR, (0,0,0,1)); #self.gl.glMaterialfv(self.gl.GL_FRONT, self.gl.GL_SHININESS, (0,)); if self.systemModel.asteroid.real_shape_model is None: rsm = self.systemModel.asteroid.real_shape_model = objloader.ShapeModel( fname=self.systemModel.asteroid.target_model_file) else: rsm = self.systemModel.asteroid.real_shape_model if noisy_model is not None: sm = noisy_model # elif self._add_shape_model_noise and not BATCH_MODE: #sup = objloader.ShapeModel(fname=SHAPE_MODEL_NOISE_SUPPORT) #sm, noise, L = tools.apply_noise(rsm, support=np.array(sup.vertices)) # sm, noise, L = tools.apply_noise(rsm) else: sm = rsm for triangle, norm, tx in sm.faces: self.triangle(sm.vertices[triangle[0]], sm.vertices[triangle[1]], sm.vertices[triangle[2]], sm.normals[norm]) self.gl.glEnd() self.gl.glEndList() if DEBUG: # assume all 32bit (4B) variables, no reuse of vertices # => triangle count x (3 vertices + 1 normal) x 3d vectors x bytes per variable mem_needed = len(sm.faces) * 4 * 3 * 4 print('3D model mem use: %.0fx %.0fB => %.1fMB' % (len(sm.faces), 4 * 3 * 4, mem_needed / 1024 / 1024)) self._object = genList def triangle(self, x1, x2, x3, n): self.gl.glNormal3f(*n) self.gl.glVertex3f(*x1) self.gl.glVertex3f(*x2) self.gl.glVertex3f(*x3) def setClearColor(self, c): self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
def drawGrid(self, painter, exposed, gridColor): rect = exposed.toAlignedRect() if (rect.isNull()): return p = RenderParams(self.map()) # Determine the tile and pixel coordinates to start at startTile = self.screenToTileCoords_(rect.topLeft()).toPoint() startPos = self.tileToScreenCoords_(startTile).toPoint() ## Determine in which half of the tile the top-left corner of the area we # need to draw is. If we're in the upper half, we need to start one row # up due to those tiles being visible as well. How we go up one row # depends on whether we're in the left or right half of the tile. ## inUpperHalf = rect.y() - startPos.y() < p.sideOffsetY inLeftHalf = rect.x() - startPos.x() < p.sideOffsetX if (inUpperHalf): startTile.setY(startTile.y() - 1) if (inLeftHalf): startTile.setX(startTile.x() - 1) startTile.setX(max(0, startTile.x())) startTile.setY(max(0, startTile.y())) startPos = self.tileToScreenCoords_(startTile).toPoint() oct = [ QPoint(0, p.tileHeight - p.sideOffsetY), QPoint(0, p.sideOffsetY), QPoint(p.sideOffsetX, 0), QPoint(p.tileWidth - p.sideOffsetX, 0), QPoint(p.tileWidth, p.sideOffsetY), QPoint(p.tileWidth, p.tileHeight - p.sideOffsetY), QPoint(p.tileWidth - p.sideOffsetX, p.tileHeight), QPoint(p.sideOffsetX, p.tileHeight) ] lines = QVector() #lines.reserve(8) gridColor.setAlpha(128) gridPen = QPen(gridColor) gridPen.setCosmetic(True) _x = QVector() _x.append(2) _x.append(2) gridPen.setDashPattern(_x) painter.setPen(gridPen) if (p.staggerX): # Odd row shifting is applied in the rendering loop, so un-apply it here if (p.doStaggerX(startTile.x())): startPos.setY(startPos.y() - p.rowHeight) while (startPos.x() <= rect.right() and startTile.x() < self.map().width()): rowTile = QPoint(startTile) rowPos = QPoint(startPos) if (p.doStaggerX(startTile.x())): rowPos.setY(rowPos.y() + p.rowHeight) while (rowPos.y() <= rect.bottom() and rowTile.y() < self.map().height()): lines.append(QLineF(rowPos + oct[1], rowPos + oct[2])) lines.append(QLineF(rowPos + oct[2], rowPos + oct[3])) lines.append(QLineF(rowPos + oct[3], rowPos + oct[4])) isStaggered = p.doStaggerX(startTile.x()) lastRow = rowTile.y() == self.map().height() - 1 lastColumn = rowTile.x() == self.map().width() - 1 bottomLeft = rowTile.x() == 0 or (lastRow and isStaggered) bottomRight = lastColumn or (lastRow and isStaggered) if (bottomRight): lines.append(QLineF(rowPos + oct[5], rowPos + oct[6])) if (lastRow): lines.append(QLineF(rowPos + oct[6], rowPos + oct[7])) if (bottomLeft): lines.append(QLineF(rowPos + oct[7], rowPos + oct[0])) painter.drawLines(lines) lines.resize(0) rowPos.setY(rowPos.y() + p.tileHeight + p.sideLengthY) rowTile.setY(rowTile.y() + 1) startPos.setX(startPos.x() + p.columnWidth) startTile.setX(startTile.x() + 1) else: # Odd row shifting is applied in the rendering loop, so un-apply it here if (p.doStaggerY(startTile.y())): startPos.setX(startPos.x() - p.columnWidth) while (startPos.y() <= rect.bottom() and startTile.y() < self.map().height()): rowTile = QPoint(startTile) rowPos = QPoint(startPos) if (p.doStaggerY(startTile.y())): rowPos.setX(rowPos.x() + p.columnWidth) while (rowPos.x() <= rect.right() and rowTile.x() < self.map().width()): lines.append(QLineF(rowPos + oct[0], rowPos + oct[1])) lines.append(QLineF(rowPos + oct[1], rowPos + oct[2])) lines.append(QLineF(rowPos + oct[3], rowPos + oct[4])) isStaggered = p.doStaggerY(startTile.y()) lastRow = rowTile.y() == self.map().height() - 1 lastColumn = rowTile.x() == self.map().width() - 1 bottomLeft = lastRow or (rowTile.x() == 0 and not isStaggered) bottomRight = lastRow or (lastColumn and isStaggered) if (lastColumn): lines.append(QLineF(rowPos + oct[4], rowPos + oct[5])) if (bottomRight): lines.append(QLineF(rowPos + oct[5], rowPos + oct[6])) if (bottomLeft): lines.append(QLineF(rowPos + oct[7], rowPos + oct[0])) painter.drawLines(lines) lines.resize(0) rowPos.setX(rowPos.x() + p.tileWidth + p.sideLengthX) rowTile.setX(rowTile.x() + 1) startPos.setY(startPos.y() + p.rowHeight) startTile.setY(startTile.y() + 1)
class PersonalInformationManager(QObject): """ Class implementing the personal information manager used to complete form fields. """ FullName = 0 LastName = 1 FirstName = 2 Email = 3 Mobile = 4 Phone = 5 Address = 6 City = 7 Zip = 8 State = 9 Country = 10 HomePage = 11 Special1 = 12 Special2 = 13 Special3 = 14 Special4 = 15 Max = 16 Invalid = 256 def __init__(self, parent=None): """ Constructor @param parent reference to the parent object (QObject) """ super(PersonalInformationManager, self).__init__(parent) self.__loaded = False self.__allInfo = {} self.__infoMatches = {} self.__translations = {} self.__view = None self.__clickedPos = QPoint() def __loadSettings(self): """ Private method to load the settings. """ self.__allInfo[self.FullName] = Preferences.getWebBrowser( "PimFullName") self.__allInfo[self.LastName] = Preferences.getWebBrowser( "PimLastName") self.__allInfo[self.FirstName] = Preferences.getWebBrowser( "PimFirstName") self.__allInfo[self.Email] = Preferences.getWebBrowser("PimEmail") self.__allInfo[self.Mobile] = Preferences.getWebBrowser("PimMobile") self.__allInfo[self.Phone] = Preferences.getWebBrowser("PimPhone") self.__allInfo[self.Address] = Preferences.getWebBrowser("PimAddress") self.__allInfo[self.City] = Preferences.getWebBrowser("PimCity") self.__allInfo[self.Zip] = Preferences.getWebBrowser("PimZip") self.__allInfo[self.State] = Preferences.getWebBrowser("PimState") self.__allInfo[self.Country] = Preferences.getWebBrowser("PimCountry") self.__allInfo[self.HomePage] = Preferences.getWebBrowser( "PimHomePage") self.__allInfo[self.Special1] = Preferences.getWebBrowser( "PimSpecial1") self.__allInfo[self.Special2] = Preferences.getWebBrowser( "PimSpecial2") self.__allInfo[self.Special3] = Preferences.getWebBrowser( "PimSpecial3") self.__allInfo[self.Special4] = Preferences.getWebBrowser( "PimSpecial4") self.__translations[self.FullName] = self.tr("Full Name") self.__translations[self.LastName] = self.tr("Last Name") self.__translations[self.FirstName] = self.tr("First Name") self.__translations[self.Email] = self.tr("E-mail") self.__translations[self.Mobile] = self.tr("Mobile") self.__translations[self.Phone] = self.tr("Phone") self.__translations[self.Address] = self.tr("Address") self.__translations[self.City] = self.tr("City") self.__translations[self.Zip] = self.tr("ZIP Code") self.__translations[self.State] = self.tr("State/Region") self.__translations[self.Country] = self.tr("Country") self.__translations[self.HomePage] = self.tr("Home Page") self.__translations[self.Special1] = self.tr("Custom 1") self.__translations[self.Special2] = self.tr("Custom 2") self.__translations[self.Special3] = self.tr("Custom 3") self.__translations[self.Special4] = self.tr("Custom 4") self.__infoMatches[self.FullName] = ["fullname", "realname"] self.__infoMatches[self.LastName] = ["lastname", "surname"] self.__infoMatches[self.FirstName] = ["firstname", "name"] self.__infoMatches[self.Email] = ["email", "e-mail", "mail"] self.__infoMatches[self.Mobile] = ["mobile", "mobilephone"] self.__infoMatches[self.Phone] = ["phone", "telephone"] self.__infoMatches[self.Address] = ["address"] self.__infoMatches[self.City] = ["city"] self.__infoMatches[self.Zip] = ["zip"] self.__infoMatches[self.State] = ["state", "region"] self.__infoMatches[self.Country] = ["country"] self.__infoMatches[self.HomePage] = ["homepage", "www"] self.__loaded = True def showConfigurationDialog(self): """ Public method to show the configuration dialog. """ from .PersonalDataDialog import PersonalDataDialog dlg = PersonalDataDialog() if dlg.exec_() == QDialog.Accepted: dlg.storeData() self.__loadSettings() def createSubMenu(self, menu, view, hitTestResult): """ Public method to create the personal information sub-menu. @param menu reference to the main menu (QMenu) @param view reference to the view (HelpBrowser) @param hitTestResult reference to the hit test result (WebHitTestResult) """ self.__view = view self.__clickedPos = hitTestResult.pos() if not hitTestResult.isContentEditable(): return if not self.__loaded: self.__loadSettings() submenu = QMenu(self.tr("Insert Personal Information"), menu) submenu.setIcon(UI.PixmapCache.getIcon("pim.png")) for key, info in sorted(self.__allInfo.items()): if info: act = submenu.addAction(self.__translations[key]) act.setData(info) act.triggered.connect(lambda: self.__insertData(act)) submenu.addSeparator() submenu.addAction(self.tr("Edit Personal Information"), self.showConfigurationDialog) menu.addMenu(submenu) menu.addSeparator() def __insertData(self, act): """ Private slot to insert the selected personal information. @param act reference to the action that triggered @type QAction """ if self.__view is None or self.__clickedPos.isNull(): return info = act.data() info = info.replace('"', '\\"') source = """ var e = document.elementFromPoint({0}, {1}); if (e) {{ var v = e.value.substring(0, e.selectionStart); v += "{2}" + e.value.substring(e.selectionEnd); e.value = v; }}""".format(self.__clickedPos.x(), self.__clickedPos.y(), info) self.__view.page().runJavaScript(source, WebBrowserPage.SafeJsWorld) def viewKeyPressEvent(self, view, evt): """ Protected method to handle key press events we are interested in. @param view reference to the view (HelpBrowser) @param evt reference to the key event (QKeyEvent) @return flag indicating handling of the event (boolean) """ if view is None: return False isEnter = evt.key() in [Qt.Key_Return, Qt.Key_Enter] isControlModifier = evt.modifiers() & Qt.ControlModifier if not isEnter or not isControlModifier: return False if not self.__loaded: self.__loadSettings() source = """ var inputs = document.getElementsByTagName('input'); var table = {0}; for (var i = 0; i < inputs.length; ++i) {{ var input = inputs[i]; if (input.type != 'text' || input.name == '') continue; for (var key in table) {{ if (!table.hasOwnProperty(key)) continue; if (key == input.name || input.name.indexOf(key) != -1) {{ input.value = table[key]; break; }} }} }}""".format(self.__matchingJsTable()) view.page().runJavaScript(source, WebBrowserPage.SafeJsWorld) return True def connectPage(self, page): """ Public method to allow the personal information manager to connect to the page. @param page reference to the web page @type WebBrowserPage """ page.loadFinished.connect(lambda ok: self.__pageLoadFinished(ok, page)) def __pageLoadFinished(self, ok, page): """ Private slot to handle the completion of a page load. @param ok flag indicating a successful load @type bool @param page reference to the web page object @type WebBrowserPage """ if page is None or not ok: return if not self.__loaded: self.__loadSettings() source = """ var inputs = document.getElementsByTagName('input'); var table = {0}; for (var i = 0; i < inputs.length; ++i) {{ var input = inputs[i]; if (input.type != 'text' || input.name == '') continue; for (var key in table) {{ if (!table.hasOwnProperty(key) || table[key] == '') continue; if (key == input.name || input.name.indexOf(key) != -1) {{ input.style['-webkit-appearance'] = 'none'; input.style['-webkit-box-shadow'] = 'inset 0 0 2px 1px #000EEE'; break; }} }} }}""".format(self.__matchingJsTable()) page.runJavaScript(source, WebBrowserPage.SafeJsWorld) def __matchingJsTable(self): """ Private method to create the common part of the JavaScript sources. @return JavaScript source @rtype str """ values = [] for key, names in self.__infoMatches.items(): for name in names: value = self.__allInfo[key].replace('"', '\\"') values.append('"{0}":"{1}"'.format(name, value)) return "{{ {0} }}".format(",".join(values))
class ImageWithMouseControl(QWidget): def __init__(self, parent=None): super().__init__(parent) self.left_click = False self.parent = parent self.img = QPixmap(img_url) self.scaled_img = self.img.scaled(self.size()) self.point = QPoint(0, 0) def paintEvent(self, e): ''' 绘图 :param e: :return: ''' painter = QPainter() painter.begin(self) self.draw_img(painter) painter.end() def draw_img(self, painter): painter.drawPixmap(self.point, self.scaled_img) def mouseMoveEvent(self, e): # 重写移动事件 if self.left_click: self._endPos = e.pos() - self._startPos self.point = self.point + self._endPos self._startPos = e.pos() self.repaint() def mousePressEvent(self, e): if e.button() == Qt.LeftButton: self.left_click = True self._startPos = e.pos() else: print('an xia qu') def mouseReleaseEvent(self, e): print(e.button()) global count_num if e.button() == Qt.LeftButton: self.left_click = False elif e.button() == Qt.RightButton: # 右键标记 print('song kai ') self.mark_node(e.x(), e.y()) self.img = QPixmap('D:/23.jpg') self.scaled_img = self.img.scaled(img_hight * rate, img_width * rate) self.repaint() count_num = count_num + 1 def get_pre_img(self): self.img = QPixmap('D:/23.jpg') self.scaled_img = self.img.scaled(img_hight * rate, img_width * rate) self.repaint() def revoke_node(self): global node_list, count_num if len(node_list) != 0: node_list.pop() image_mark.Image_mark.mark_function(node_list, img_url, sizz) self.img = QPixmap('D:/23.jpg') self.scaled_img = self.img.scaled(img_hight * rate, img_width * rate) self.repaint() count_num = count_num - 1 def wheelEvent(self, e): global rate if e.angleDelta().y() > 0: # 放大图片 rate = rate + 0.05 self.scaled_img = self.img.scaled(img_hight * rate, img_width * rate) new_w = e.x() - (self.scaled_img.width() * (e.x() - self.point.x())) / ( self.scaled_img.width() / 0.99) new_h = e.y() - (self.scaled_img.height() * (e.y() - self.point.y())) / ( self.scaled_img.height() / 0.99) self.point = QPoint(new_w, new_h) self.repaint() elif e.angleDelta().y() < 0: # 缩小图片 rate = rate - 0.05 self.scaled_img = self.img.scaled(img_hight * rate, img_width * rate) new_w = e.x() - (self.scaled_img.width() * (e.x() - self.point.x())) / ( self.scaled_img.width() * 0.99) new_h = e.y() - (self.scaled_img.height() * (e.y() - self.point.y())) / ( self.scaled_img.height() * 0.99) self.point = QPoint(new_w, new_h) self.repaint() def resizeEvent(self, e): if self.parent is not None: self.scaled_img = self.img.scaled(self.size()) self.point = QPoint(0, 0) self.update() def mark_node(self, x, y): # 标点 global node_list tx = (x - self.point.x()) / (rate * k) ty = (y - self.point.y()) / (rate * k) # print(tx,ty) node_list.append((tx, ty)) # try: image_mark.Image_mark.mark_function(node_list, img_url, sizz) # 文件写入
def update_seed(self, seed: QPoint): self.seed_point = seed self.seed_x.setText(str(seed.x())) self.seed_y.setText(str(seed.y()))
class GLWidget(CanvasBase): CAM_LEFT_X = -0.5 CAM_RIGHT_X = 0.5 CAM_BOTTOM_Y = 0.5 CAM_TOP_Y = -0.5 CAM_NEAR_Z = -14.0 CAM_FAR_Z = 14.0 COLOR_BACKGROUND = QColor.fromHsl(160, 0, 255, 255) COLOR_NORMAL = QColor.fromCmykF(1.0, 0.5, 0.0, 0.0, 1.0) COLOR_SELECT = QColor.fromCmykF(0.0, 1.0, 0.9, 0.0, 1.0) COLOR_NORMAL_DISABLED = QColor.fromCmykF(1.0, 0.5, 0.0, 0.0, 0.25) COLOR_SELECT_DISABLED = QColor.fromCmykF(0.0, 1.0, 0.9, 0.0, 0.25) COLOR_ENTRY_ARROW = QColor.fromRgbF(0.0, 0.0, 1.0, 1.0) COLOR_EXIT_ARROW = QColor.fromRgbF(0.0, 1.0, 0.0, 1.0) COLOR_ROUTE = QColor.fromRgbF(0.5, 0.0, 0.0, 1.0) COLOR_STMOVE = QColor.fromRgbF(0.5, 0.0, 0.25, 1.0) COLOR_BREAK = QColor.fromRgbF(1.0, 0.0, 1.0, 0.7) COLOR_LEFT = QColor.fromHsl(134, 240, 130, 255) COLOR_RIGHT = QColor.fromHsl(186, 240, 130, 255) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.shapes = Shapes([]) self.orientation = 0 self.wpZero = 0 self.routearrows = [] self.expprv = None self.isPanning = False self.isRotating = False self.isMultiSelect = False self._lastPos = QPoint() self.posX = 0.0 self.posY = 0.0 self.posZ = 0.0 self.rotX = 0.0 self.rotY = 0.0 self.rotZ = 0.0 self.scale = 1.0 self.scaleCorr = 1.0 self.showPathDirections = False self.showDisabledPaths = False self.topLeft = Point() self.bottomRight = Point() self.tol = 0 def tr(self, string_to_translate): """ Translate a string using the QCoreApplication translation framework @param string_to_translate: a unicode string @return: the translated unicode string if it was possible to translate """ return text_type(QCoreApplication.translate('GLWidget', string_to_translate)) def resetAll(self): # the wpzero is currently generated "last" if self.wpZero > 0: GL.glDeleteLists(self.orientation + 1, self.wpZero - self.orientation) self.shapes = Shapes([]) self.wpZero = 0 self.delete_opt_paths() self.posX = 0.0 self.posY = 0.0 self.posZ = 0.0 self.rotX = 0.0 self.rotY = 0.0 self.rotZ = 0.0 self.scale = 1.0 self.topLeft = Point() self.bottomRight = Point() self.update() def delete_opt_paths(self): if len(self.routearrows) > 0: GL.glDeleteLists(self.routearrows[0][2], len(self.routearrows)) self.routearrows = [] def addexproutest(self): self.expprv = Point3D(g.config.vars.Plane_Coordinates['axis1_start_end'], g.config.vars.Plane_Coordinates['axis2_start_end'], 0) def addexproute(self, exp_order, layer_nr): """ This function initialises the Arrows of the export route order and its numbers. """ for shape_nr in range(len(exp_order)): shape = self.shapes[exp_order[shape_nr]] st = self.expprv en, self.expprv = shape.get_start_end_points_physical() en = en.to3D(shape.axis3_start_mill_depth) self.expprv = self.expprv.to3D(shape.axis3_mill_depth) self.routearrows.append([st, en, 0]) # TODO self.routetext.append(RouteText(text=("%s,%s" % (layer_nr, shape_nr+1)), startp=en)) def addexprouteen(self): st = self.expprv en = Point3D(g.config.vars.Plane_Coordinates['axis1_start_end'], g.config.vars.Plane_Coordinates['axis2_start_end'], 0) self.routearrows.append([st, en, 0]) for route in self.routearrows: route[2] = self.makeRouteArrowHead(route[0], route[1]) def contextMenuEvent(self, event): if not self.isRotating: clicked, offset, _ = self.getClickedDetails(event) MyDropDownMenu(self, event.globalPos(), clicked, offset) def setXRotation(self, angle): self.rotX = self.normalizeAngle(angle) def setYRotation(self, angle): self.rotY = self.normalizeAngle(angle) def setZRotation(self, angle): self.rotZ = self.normalizeAngle(angle) def normalizeAngle(self, angle): return (angle - 180) % -360 + 180 def mousePressEvent(self, event): if self.isPanning or self.isRotating: self.setCursor(Qt.ClosedHandCursor) elif event.button() == Qt.LeftButton: clicked, offset, tol = self.getClickedDetails(event) xyForZ = {} for shape in self.shapes: hit = False z = shape.axis3_start_mill_depth if z not in xyForZ: xyForZ[z] = self.determineSelectedPosition(clicked, z, offset) hit |= shape.isHit(xyForZ[z], tol) if not hit: z = shape.axis3_mill_depth if z not in xyForZ: xyForZ[z] = self.determineSelectedPosition(clicked, z, offset) hit |= shape.isHit(xyForZ[z], tol) if self.isMultiSelect and shape.selected: hit = not hit if hit != shape.selected: g.window.TreeHandler.updateShapeSelection(shape, hit) shape.selected = hit self.update() self._lastPos = event.pos() def getClickedDetails(self, event): min_side = min(self.frameSize().width(), self.frameSize().height()) clicked = Point((event.pos().x() - self.frameSize().width() / 2), (event.pos().y() - self.frameSize().height() / 2)) / min_side / self.scale offset = Point3D(-self.posX, -self.posY, -self.posZ) / self.scale tol = 4 * self.scaleCorr / min_side / self.scale return clicked, offset, tol def determineSelectedPosition(self, clicked, forZ, offset): angleX = -radians(self.rotX) angleY = -radians(self.rotY) zv = forZ - offset.z clickedZ = ((zv + clicked.x * sin(angleY)) / cos(angleY) - clicked.y * sin(angleX)) / cos(angleX) sx, sy, sz = self.deRotate(clicked.x, clicked.y, clickedZ) return Point(sx + offset.x, - sy - offset.y) #, sz + offset.z def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton or event.button() == Qt.RightButton: if self.isPanning: self.setCursor(Qt.OpenHandCursor) elif self.isRotating: self.setCursor(Qt.PointingHandCursor) def mouseMoveEvent(self, event): dx = event.pos().x() - self._lastPos.x() dy = event.pos().y() - self._lastPos.y() if self.isRotating: if event.buttons() == Qt.LeftButton: self.setXRotation(self.rotX - dy / 2) self.setYRotation(self.rotY + dx / 2) elif event.buttons() == Qt.RightButton: self.setXRotation(self.rotX - dy / 2) self.setZRotation(self.rotZ + dx / 2) elif self.isPanning: if event.buttons() == Qt.LeftButton: min_side = min(self.frameSize().width(), self.frameSize().height()) dx, dy, dz = self.deRotate(dx, dy, 0) self.posX += dx / min_side self.posY += dy / min_side self.posZ += dz / min_side self._lastPos = event.pos() self.update() def wheelEvent(self, event): min_side = min(self.frameSize().width(), self.frameSize().height()) x = (event.pos().x() - self.frameSize().width() / 2) / min_side y = (event.pos().y() - self.frameSize().height() / 2) / min_side s = 1.001 ** event.angleDelta().y() x, y, z = self.deRotate(x, y, 0) self.posX = (self.posX - x) * s + x self.posY = (self.posY - y) * s + y self.posZ = (self.posZ - z) * s + z self.scale *= s self.update() def rotate(self, x, y, z): angleZ = radians(self.rotZ) x, y, z = x*cos(angleZ) - y*sin(angleZ), x*sin(angleZ) + y*cos(angleZ), z angleY = radians(self.rotY) x, y, z = x*cos(angleY) + z*sin(angleY), y, -x*sin(angleY) + z*cos(angleY) angleX = radians(self.rotX) return x, y*cos(angleX) - z*sin(angleX), y*sin(angleX) + z*cos(angleX) def deRotate(self, x, y, z): angleX = -radians(self.rotX) x, y, z = x, y*cos(angleX) - z*sin(angleX), y*sin(angleX) + z*cos(angleX) angleY = -radians(self.rotY) x, y, z = x*cos(angleY) + z*sin(angleY), y, -x*sin(angleY) + z*cos(angleY) angleZ = -radians(self.rotZ) return x*cos(angleZ) - y*sin(angleZ), x*sin(angleZ) + y*cos(angleZ), z def getRotationVectors(self, orgRefVector, toRefVector): """ Generate a rotation matrix such that toRefVector = matrix * orgRefVector @param orgRefVector: A 3D unit vector @param toRefVector: A 3D unit vector @return: 3 vectors such that matrix = [vx; vy; vz] """ # based on: # http://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d if orgRefVector == toRefVector: return Point3D(1, 0, 0), Point3D(0, 1, 0), Point3D(0, 0, 1) v = orgRefVector.cross_product(toRefVector) mn = (1 - orgRefVector * toRefVector) / v.length_squared() vx = Point3D(1, -v.z, v.y) + mn * Point3D(-v.y**2 - v.z**2, v.x * v.y, v.x * v.z) vy = Point3D(v.z, 1, -v.x) + mn * Point3D(v.x * v.y, -v.x**2 - v.z**2, v.y * v.z) vz = Point3D(-v.y, v.x, 1) + mn * Point3D(v.x * v.z, v.y * v.z, -v.x**2 - v.y**2) return vx, vy, vz def initializeGL(self): logger.debug(self.tr("Using OpenGL version: %s") % GL.glGetString(GL.GL_VERSION).decode("utf-8")) self.setClearColor(GLWidget.COLOR_BACKGROUND) GL.glEnable(GL.GL_MULTISAMPLE) GL.glEnable(GL.GL_POLYGON_SMOOTH) GL.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST) # GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE) GL.glShadeModel(GL.GL_SMOOTH) GL.glEnable(GL.GL_DEPTH_TEST) GL.glEnable(GL.GL_CULL_FACE) # GL.glEnable(GL.GL_LIGHTING) # GL.glEnable(GL.GL_LIGHT0) GL.glEnable(GL.GL_BLEND) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) # GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, (0.5, 5.0, 7.0, 1.0)) # GL.glEnable(GL.GL_NORMALIZE) self.drawOrientationArrows() def paintGL(self): # The last transformation you specify takes place first. GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glLoadIdentity() GL.glRotatef(self.rotX, 1.0, 0.0, 0.0) GL.glRotatef(self.rotY, 0.0, 1.0, 0.0) GL.glRotatef(self.rotZ, 0.0, 0.0, 1.0) GL.glTranslatef(self.posX, self.posY, self.posZ) GL.glScalef(self.scale, self.scale, self.scale) for shape in self.shapes.selected_iter(): if not shape.disabled: self.setColor(GLWidget.COLOR_STMOVE) GL.glCallList(shape.drawStMove) self.setColor(GLWidget.COLOR_SELECT) GL.glCallList(shape.drawObject) elif self.showDisabledPaths: self.setColor(GLWidget.COLOR_SELECT_DISABLED) GL.glCallList(shape.drawObject) for shape in self.shapes.not_selected_iter(): if not shape.disabled: if shape.parentLayer.isBreakLayer(): self.setColor(GLWidget.COLOR_BREAK) elif shape.cut_cor == 41: self.setColor(GLWidget.COLOR_LEFT) elif shape.cut_cor == 42: self.setColor(GLWidget.COLOR_RIGHT) else: self.setColor(GLWidget.COLOR_NORMAL) GL.glCallList(shape.drawObject) if self.showPathDirections: self.setColor(GLWidget.COLOR_STMOVE) GL.glCallList(shape.drawStMove) elif self.showDisabledPaths: self.setColor(GLWidget.COLOR_NORMAL_DISABLED) GL.glCallList(shape.drawObject) # optimization route arrows self.setColor(GLWidget.COLOR_ROUTE) GL.glBegin(GL.GL_LINES) for route in self.routearrows: start = route[0] end = route[1] GL.glVertex3f(start.x, -start.y, start.z) GL.glVertex3f(end.x, -end.y, end.z) GL.glEnd() GL.glScalef(self.scaleCorr / self.scale, self.scaleCorr / self.scale, self.scaleCorr / self.scale) scaleArrow = self.scale / self.scaleCorr for route in self.routearrows: end = scaleArrow * route[1] GL.glTranslatef(end.x, -end.y, end.z) GL.glCallList(route[2]) GL.glTranslatef(-end.x, end.y, -end.z) # direction arrows for shape in self.shapes: if shape.selected and (not shape.disabled or self.showDisabledPaths) or\ self.showPathDirections and not shape.disabled: start, end = shape.get_start_end_points_physical() start = scaleArrow * start.to3D(shape.axis3_start_mill_depth) end = scaleArrow * end.to3D(shape.axis3_mill_depth) GL.glTranslatef(start.x, -start.y, start.z) GL.glCallList(shape.drawArrowsDirection[0]) GL.glTranslatef(-start.x, start.y, -start.z) GL.glTranslatef(end.x, -end.y, end.z) GL.glCallList(shape.drawArrowsDirection[1]) GL.glTranslatef(-end.x, end.y, -end.z) if self.wpZero > 0: GL.glCallList(self.wpZero) GL.glTranslatef(-self.posX / self.scaleCorr, -self.posY / self.scaleCorr, -self.posZ / self.scaleCorr) GL.glCallList(self.orientation) def resizeGL(self, width, height): GL.glViewport(0, 0, width, height) side = min(width, height) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() if width >= height: scale_x = width / height GL.glOrtho(GLWidget.CAM_LEFT_X * scale_x, GLWidget.CAM_RIGHT_X * scale_x, GLWidget.CAM_BOTTOM_Y, GLWidget.CAM_TOP_Y, GLWidget.CAM_NEAR_Z, GLWidget.CAM_FAR_Z) else: scale_y = height / width GL.glOrtho(GLWidget.CAM_LEFT_X, GLWidget.CAM_RIGHT_X, GLWidget.CAM_BOTTOM_Y * scale_y, GLWidget.CAM_TOP_Y * scale_y, GLWidget.CAM_NEAR_Z, GLWidget.CAM_FAR_Z) self.scaleCorr = 400 / side GL.glMatrixMode(GL.GL_MODELVIEW) def setClearColor(self, c): GL.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.setColorRGBA(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColorRGBA(self, r, g, b, a): # GL.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, (r, g, b, a)) GL.glColor4f(r, g, b, a) def plotAll(self, shapes): for shape in shapes: self.paint_shape(shape) self.shapes.append(shape) self.drawWpZero() def repaint_shape(self, shape): GL.glDeleteLists(shape.drawObject, 4) self.paint_shape(shape) def paint_shape(self, shape): shape.drawObject = self.makeShape(shape) # 1 object shape.stmove = StMove(shape) shape.drawStMove = self.makeStMove(shape.stmove) # 1 object shape.drawArrowsDirection = self.makeDirArrows(shape) # 2 objects def makeShape(self, shape): genList = GL.glGenLists(1) GL.glNewList(genList, GL.GL_COMPILE) GL.glBegin(GL.GL_LINES) shape.make_path(self.drawHorLine, self.drawVerLine) GL.glEnd() GL.glEndList() self.topLeft.detTopLeft(shape.topLeft) self.bottomRight.detBottomRight(shape.bottomRight) return genList def makeStMove(self, stmove): genList = GL.glGenLists(1) GL.glNewList(genList, GL.GL_COMPILE) GL.glBegin(GL.GL_LINES) stmove.make_path(self.drawHorLine, self.drawVerLine) GL.glEnd() GL.glEndList() return genList def drawHorLine(self, caller, Ps, Pe): GL.glVertex3f(Ps.x, -Ps.y, caller.axis3_start_mill_depth) GL.glVertex3f(Pe.x, -Pe.y, caller.axis3_start_mill_depth) GL.glVertex3f(Ps.x, -Ps.y, caller.axis3_mill_depth) GL.glVertex3f(Pe.x, -Pe.y, caller.axis3_mill_depth) def drawVerLine(self, caller, Ps): GL.glVertex3f(Ps.x, -Ps.y, caller.axis3_start_mill_depth) GL.glVertex3f(Ps.x, -Ps.y, caller.axis3_mill_depth) def drawOrientationArrows(self): rCone = 0.01 rCylinder = 0.004 zTop = 0.05 zMiddle = 0.02 zBottom = -0.03 segments = 20 arrow = GL.glGenLists(1) GL.glNewList(arrow, GL.GL_COMPILE) self.drawCone(Point(), rCone, zTop, zMiddle, segments) self.drawSolidCircle(Point(), rCone, zMiddle, segments) self.drawCylinder(Point(), rCylinder, zMiddle, zBottom, segments) self.drawSolidCircle(Point(), rCylinder, zBottom, segments) GL.glEndList() self.orientation = GL.glGenLists(1) GL.glNewList(self.orientation, GL.GL_COMPILE) self.setColorRGBA(0.0, 0.0, 1.0, 0.5) GL.glCallList(arrow) GL.glRotatef(90, 0, 1, 0) self.setColorRGBA(1.0, 0.0, 0.0, 0.5) GL.glCallList(arrow) GL.glRotatef(90, 1, 0, 0) self.setColorRGBA(0.0, 1.0, 0.0, 0.5) GL.glCallList(arrow) GL.glEndList() def drawWpZero(self): r = 0.02 segments = 20 # must be a multiple of 4 self.wpZero = GL.glGenLists(1) GL.glNewList(self.wpZero, GL.GL_COMPILE) self.setColorRGBA(0.2, 0.2, 0.2, 0.7) self.drawSphere(r, segments, segments // 4, segments, segments // 4) GL.glBegin(GL.GL_TRIANGLE_FAN) GL.glVertex3f(0, 0, 0) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(0, -1, 0) GL.glVertex3f(xy2.x, 0, xy2.y) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(-1, 0, 0) GL.glVertex3f(0, -xy2.y, -xy2.x) for i in range(segments // 4 + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r) # GL.glNormal3f(0, 0, 1) GL.glVertex3f(-xy2.y, xy2.x, 0) GL.glEnd() self.setColorRGBA(0.6, 0.6, 0.6, 0.5) self.drawSphere(r * 1.25, segments, segments, segments, segments) GL.glEndList() def drawSphere(self, r, lats, mlats, longs, mlongs): lats //= 2 # based on http://www.cburch.com/cs/490/sched/feb8/index.html for i in range(mlats): lat0 = pi * (-0.5 + i / lats) z0 = r * sin(lat0) zr0 = r * cos(lat0) lat1 = pi * (-0.5 + (i + 1) / lats) z1 = r * sin(lat1) zr1 = r * cos(lat1) GL.glBegin(GL.GL_QUAD_STRIP) for j in range(mlongs + 1): lng = 2 * pi * j / longs x = cos(lng) y = sin(lng) GL.glNormal3f(x * zr0, y * zr0, z0) GL.glVertex3f(x * zr0, y * zr0, z0) GL.glNormal3f(x * zr1, y * zr1, z1) GL.glVertex3f(x * zr1, y * zr1, z1) GL.glEnd() def drawSolidCircle(self, origin, r, z, segments): GL.glBegin(GL.GL_TRIANGLE_FAN) # GL.glNormal3f(0, 0, -1) GL.glVertex3f(origin.x, -origin.y, z) for i in range(segments + 1): ang = -i * 2 * pi / segments xy2 = origin.get_arc_point(ang, r) GL.glVertex3f(xy2.x, -xy2.y, z) GL.glEnd() def drawCone(self, origin, r, zTop, zBottom, segments): GL.glBegin(GL.GL_TRIANGLE_FAN) GL.glVertex3f(origin.x, -origin.y, zTop) for i in range(segments + 1): ang = i * 2 * pi / segments xy2 = origin.get_arc_point(ang, r) # GL.glNormal3f(xy2.x, -xy2.y, zBottom) GL.glVertex3f(xy2.x, -xy2.y, zBottom) GL.glEnd() def drawCylinder(self, origin, r, zTop, zBottom, segments): GL.glBegin(GL.GL_QUAD_STRIP) for i in range(segments + 1): ang = i * 2 * pi / segments xy = origin.get_arc_point(ang, r) # GL.glNormal3f(xy.x, -xy.y, 0) GL.glVertex3f(xy.x, -xy.y, zTop) GL.glVertex3f(xy.x, -xy.y, zBottom) GL.glEnd() def makeDirArrows(self, shape): (start, start_dir), (end, end_dir) = shape.get_start_end_points_physical(None, False) startArrow = GL.glGenLists(1) GL.glNewList(startArrow, GL.GL_COMPILE) self.setColor(GLWidget.COLOR_ENTRY_ARROW) self.drawDirArrow(Point3D(), start_dir.to3D(), True) GL.glEndList() endArrow = GL.glGenLists(1) GL.glNewList(endArrow, GL.GL_COMPILE) self.setColor(GLWidget.COLOR_EXIT_ARROW) self.drawDirArrow(Point3D(), end_dir.to3D(), False) GL.glEndList() return startArrow, endArrow def drawDirArrow(self, origin, direction, startError): offset = 0.0 if startError else 0.05 zMiddle = -0.02 + offset zBottom = -0.05 + offset rx, ry, rz = self.getRotationVectors(Point3D(0, 0, 1), direction) self.drawArrowHead(origin, rx, ry, rz, offset) GL.glBegin(GL.GL_LINES) zeroMiddle = Point3D(0, 0, zMiddle) GL.glVertex3f(zeroMiddle * rx + origin.x, -zeroMiddle * ry - origin.y, zeroMiddle * rz + origin.z) zeroBottom = Point3D(0, 0, zBottom) GL.glVertex3f(zeroBottom * rx + origin.x, -zeroBottom * ry - origin.y, zeroBottom * rz + origin.z) GL.glEnd() def makeRouteArrowHead(self, start, end): if end == start: direction = Point3D(0, 0, 1) else: direction = (end - start).unit_vector() rx, ry, rz = self.getRotationVectors(Point3D(0, 0, 1), direction) head = GL.glGenLists(1) GL.glNewList(head, GL.GL_COMPILE) self.drawArrowHead(Point3D(), rx, ry, rz, 0) GL.glEndList() return head def drawArrowHead(self, origin, rx, ry, rz, offset): r = 0.01 segments = 10 zTop = 0 + offset zBottom = -0.02 + offset GL.glBegin(GL.GL_TRIANGLE_FAN) zeroTop = Point3D(0, 0, zTop) GL.glVertex3f(zeroTop * rx + origin.x, -zeroTop * ry - origin.y, zeroTop * rz + origin.z) for i in range(segments + 1): ang = i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r).to3D(zBottom) GL.glVertex3f(xy2 * rx + origin.x, -xy2 * ry - origin.y, xy2 * rz + origin.z) GL.glEnd() GL.glBegin(GL.GL_TRIANGLE_FAN) zeroBottom = Point3D(0, 0, zBottom) GL.glVertex3f(zeroBottom * rx + origin.x, -zeroBottom * ry - origin.y, zeroBottom * rz + origin.z) for i in range(segments + 1): ang = -i * 2 * pi / segments xy2 = Point().get_arc_point(ang, r).to3D(zBottom) GL.glVertex3f(xy2 * rx + origin.x, -xy2 * ry - origin.y, xy2 * rz + origin.z) GL.glEnd() def setShowPathDirections(self, flag): self.showPathDirections = flag def setShowDisabledPaths(self, flag=True): self.showDisabledPaths = flag def autoscale(self): # TODO currently only works correctly when object is not rotated if self.frameSize().width() >= self.frameSize().height(): aspect_scale_x = self.frameSize().width() / self.frameSize().height() aspect_scale_y = 1 else: aspect_scale_x = 1 aspect_scale_y = self.frameSize().height() / self.frameSize().width() scaleX = (GLWidget.CAM_RIGHT_X - GLWidget.CAM_LEFT_X) * aspect_scale_x / (self.bottomRight.x - self.topLeft.x) scaleY = (GLWidget.CAM_BOTTOM_Y - GLWidget.CAM_TOP_Y) * aspect_scale_y / (self.topLeft.y - self.bottomRight.y) self.scale = min(scaleX, scaleY) * 0.95 self.posX = ((GLWidget.CAM_LEFT_X + GLWidget.CAM_RIGHT_X) * 0.95 * aspect_scale_x - (self.topLeft.x + self.bottomRight.x) * self.scale) / 2 self.posY = -((GLWidget.CAM_TOP_Y + GLWidget.CAM_BOTTOM_Y) * 0.95 * aspect_scale_y - (self.topLeft.y + self.bottomRight.y) * self.scale) / 2 self.posZ = 0 self.update() def topView(self): self.rotX = 0 self.rotY = 0 self.rotZ = 0 self.update() def isometricView(self): self.rotX = -22 self.rotY = -22 self.rotZ = 0 self.update()
def setCursorShape(self, e_pos: QPoint): diff = 3 # Left - Bottom if (((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)) or # Left # Right-Bottom ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)) or # Right # Left-Top ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)) or # Left # Right-Top (e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right # Left - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZEBL self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # Right - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZEBR self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Left - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZETL self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Right - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZETR self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # check cursor horizontal position elif ((e_pos.x() < self.x() + diff) or # Left (e_pos.x() > self.x() + self.width() - diff)): # Right if e_pos.x() < self.x() + diff: # Left self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZEL else: # Right self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZER # check cursor vertical position elif ((e_pos.y() > self.y() + self.height() - diff) or # Bottom (e_pos.y() < self.y() + diff)): # Top if e_pos.y() < self.y() + diff: # Top self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZET else: # Bottom self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZEB else: self.setCursor(QCursor(QtCore.Qt. ArrowCursor)) self.mode = Mode.MOVE
class SlippyMap(QObject): updated = pyqtSignal(QRect) def __init__(self, parent=None): super(SlippyMap, self).__init__(parent) self._offset = QPoint() self._tilesRect = QRect() self._tilePixmaps = {} # Point(x, y) to QPixmap mapping self._manager = QNetworkAccessManager() self._url = QUrl() # public vars self.width = 400 self.height = 300 self.zoom = 15 self.latitude = 59.9138204 self.longitude = 10.7387413 self._emptyTile = QPixmap(TDIM, TDIM) self._emptyTile.fill(Qt.lightGray) cache = QNetworkDiskCache() cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self._manager.setCache(cache) self._manager.finished.connect(self.handleNetworkData) def invalidate(self): if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = int(self.width / 2 - (tx - math.floor(tx)) * TDIM) yp = int(self.height / 2 - (ty - math.floor(ty)) * TDIM) # first tile vertical and horizontal xa = (xp + TDIM - 1) / TDIM ya = (yp + TDIM - 1) / TDIM xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self._offset = QPoint(xp - xa * TDIM, yp - ya * TDIM) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / TDIM ye = int(ty) + (self.height - yp - 1) / TDIM # build a rect self._tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self._url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, p, rect): for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(x + self._tilesRect.left(), y + self._tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): p.drawPixmap(box, self._tilePixmaps.get(tp, self._emptyTile)) def pan(self, delta): dx = QPointF(delta) / float(TDIM) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() # slots def handleNetworkData(self, reply): img = QImage() tp = Point(reply.request().attribute(QNetworkRequest.User)) url = reply.url() if not reply.error(): if img.load(reply, None): self._tilePixmaps[tp] = QPixmap.fromImage(img) reply.deleteLater() self.updated.emit(self.tileRect(tp)) # purge unused tiles bound = self._tilesRect.adjusted(-2, -2, 2, 2) for tp in list(self._tilePixmaps.keys()): if not bound.contains(tp): del self._tilePixmaps[tp] self.download() def download(self): grab = None for x in range(self._tilesRect.width()): for y in range(self._tilesRect.height()): tp = Point(self._tilesRect.topLeft() + QPoint(x, y)) if tp not in self._tilePixmaps: grab = QPoint(tp) break if grab is None: self._url = QUrl() return path = 'http://tile.openstreetmap.org/%d/%d/%d.png' % (self.zoom, grab.x(), grab.y()) self._url = QUrl(path) request = QNetworkRequest() request.setUrl(self._url) request.setRawHeader(b'User-Agent', b'Nokia (PyQt) Graphics Dojo 1.0') request.setAttribute(QNetworkRequest.User, grab) self._manager.get(request) def tileRect(self, tp): t = tp - self._tilesRect.topLeft() x = t.x() * TDIM + self._offset.x() y = t.y() * TDIM + self._offset.y() return QRect(x, y, TDIM, TDIM)
class TContainer(QWidget): """ allow to move and resize by user""" menu = None mode = Mode.NONE position = None inFocus = pyqtSignal(bool) outFocus = pyqtSignal(bool) newGeometry = pyqtSignal(QRect) def __init__(self, parent, p, cWidget): super().__init__(parent=parent) self.menu = QMenu(parent=self, title='menu') self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) self.setVisible(True) self.setAutoFillBackground(False) self.setMouseTracking(True) self.setFocusPolicy(QtCore.Qt.ClickFocus) self.setFocus() self.move(p) self.vLayout = QVBoxLayout(self) self.setChildWidget(cWidget) self.m_infocus = True self.m_showMenu = False self.m_isEditing = True self.installEventFilter(parent) def setChildWidget(self, cWidget): if cWidget: self.childWidget = cWidget self.childWidget.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents, True) self.childWidget.setParent(self) self.childWidget.releaseMouse() self.vLayout.addWidget(cWidget) self.vLayout.setContentsMargins(0,0,0,0) def popupShow(self, pt: QPoint): if self.menu.isEmpty: return global_ = self.mapToGlobal(pt) self.m_showMenu = True self.menu.exec(global_) self.m_showMenu = False def focusInEvent(self, a0: QtGui.QFocusEvent): self.m_infocus = True p = self.parentWidget() p.installEventFilter(self) p.repaint() self.inFocus.emit(True) def focusOutEvent(self, a0: QtGui.QFocusEvent): if not self.m_isEditing: return if self.m_showMenu: return self.mode = Mode.NONE self.outFocus.emit(False) self.m_infocus = False def paintEvent(self, e: QtGui.QPaintEvent): painter = QtGui.QPainter(self) color = (r, g, b, a) = (255, 0, 0, 16) painter.fillRect(e.rect(), QColor(r, g, b, a)) if self.m_infocus: rect = e.rect() rect.adjust(0,0,-1,-1) painter.setPen(QColor(r, g, b)) painter.drawRect(rect) def mousePressEvent(self, e: QtGui.QMouseEvent): self.position = QPoint(e.globalX() - self.geometry().x(), e.globalY() - self.geometry().y()) if not self.m_isEditing: return if not self.m_infocus: return if not e.buttons() and QtCore.Qt.LeftButton: self.setCursorShape(e.pos()) return if e.button() == QtCore.Qt.RightButton: self.popupShow(e.pos()) e.accept() def keyPressEvent(self, e: QtGui.QKeyEvent): if not self.m_isEditing: return if e.key() == QtCore.Qt.Key_Delete: self.deleteLater() # Moving container with arrows if QApplication.keyboardModifiers() == QtCore.Qt.ControlModifier: newPos = QPoint(self.x(), self.y()) if e.key() == QtCore.Qt.Key_Up: newPos.setY(newPos.y() - 1) if e.key() == QtCore.Qt.Key_Down: newPos.setY(newPos.y() + 1) if e.key() == QtCore.Qt.Key_Left: newPos.setX(newPos.x() - 1) if e.key() == QtCore.Qt.Key_Right: newPos.setX(newPos.x() + 1) self.move(newPos) if QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier: if e.key() == QtCore.Qt.Key_Up: self.resize(self.width(), self.height() - 1) if e.key() == QtCore.Qt.Key_Down: self.resize(self.width(), self.height() + 1) if e.key() == QtCore.Qt.Key_Left: self.resize(self.width() - 1, self.height()) if e.key() == QtCore.Qt.Key_Right: self.resize(self.width() + 1, self.height()) self.newGeometry.emit(self.geometry()) def setCursorShape(self, e_pos: QPoint): diff = 3 # Left - Bottom if (((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)) or # Left # Right-Bottom ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)) or # Right # Left-Top ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)) or # Left # Right-Top (e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right # Left - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZEBL self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # Right - Bottom if ((e_pos.y() > self.y() + self.height() - diff) and # Bottom (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZEBR self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Left - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() < self.x() + diff)): # Left self.mode = Mode.RESIZETL self.setCursor(QCursor(QtCore.Qt.SizeFDiagCursor)) # Right - Top if ((e_pos.y() < self.y() + diff) and # Top (e_pos.x() > self.x() + self.width() - diff)): # Right self.mode = Mode.RESIZETR self.setCursor(QCursor(QtCore.Qt.SizeBDiagCursor)) # check cursor horizontal position elif ((e_pos.x() < self.x() + diff) or # Left (e_pos.x() > self.x() + self.width() - diff)): # Right if e_pos.x() < self.x() + diff: # Left self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZEL else: # Right self.setCursor(QCursor(QtCore.Qt.SizeHorCursor)) self.mode = Mode.RESIZER # check cursor vertical position elif ((e_pos.y() > self.y() + self.height() - diff) or # Bottom (e_pos.y() < self.y() + diff)): # Top if e_pos.y() < self.y() + diff: # Top self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZET else: # Bottom self.setCursor(QCursor(QtCore.Qt.SizeVerCursor)) self.mode = Mode.RESIZEB else: self.setCursor(QCursor(QtCore.Qt. ArrowCursor)) self.mode = Mode.MOVE def mouseReleaseEvent(self, e: QtGui.QMouseEvent): QWidget.mouseReleaseEvent(self, e) def mouseMoveEvent(self, e: QtGui.QMouseEvent): QWidget.mouseMoveEvent(self, e) if not self.m_isEditing: return if not self.m_infocus: return if not e.buttons() and QtCore.Qt.LeftButton: p = QPoint(e.x() + self.geometry().x(), e.y() + self.geometry().y()) self.setCursorShape(p) return if (self.mode == Mode.MOVE or self.mode == Mode.NONE) and e.buttons() and QtCore.Qt.LeftButton: toMove = e.globalPos() - self.position if toMove.x() < 0:return if toMove.y() < 0:return if toMove.x() > self.parentWidget().width() - self.width(): return self.move(toMove) self.newGeometry.emit(self.geometry()) self.parentWidget().repaint() return if (self.mode != Mode.MOVE) and e.buttons() and QtCore.Qt.LeftButton: if self.mode == Mode.RESIZETL: # Left - Top newwidth = e.globalX() - self.position.x() - self.geometry().x() newheight = e.globalY() - self.position.y() - self.geometry().y() toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, self.geometry().height() - newheight) self.move(toMove.x(), toMove.y()) elif self.mode == Mode.RESIZETR: # Right - Top newheight = e.globalY() - self.position.y() - self.geometry().y() toMove = e.globalPos() - self.position self.resize(e.x(), self.geometry().height() - newheight) self.move(self.x(), toMove.y()) elif self.mode== Mode.RESIZEBL: # Left - Bottom newwidth = e.globalX() - self.position.x() - self.geometry().x() toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, e.y()) self.move(toMove.x(), self.y()) elif self.mode == Mode.RESIZEB: # Bottom self.resize(self.width(), e.y()) elif self.mode == Mode.RESIZEL: # Left newwidth = e.globalX() - self.position.x() - self.geometry().x() toMove = e.globalPos() - self.position self.resize(self.geometry().width() - newwidth, self.height()) self.move(toMove.x(), self.y()) elif self.mode == Mode.RESIZET:# Top newheight = e.globalY() - self.position.y() - self.geometry().y() toMove = e.globalPos() - self.position self.resize(self.width(), self.geometry().height() - newheight) self.move(self.x(), toMove.y()) elif self.mode == Mode.RESIZER: # Right self.resize(e.x(), self.height()) elif self.mode == Mode.RESIZEBR:# Right - Bottom self.resize(e.x(), e.y()) self.parentWidget().repaint() self.newGeometry.emit(self.geometry())
def createCurveIcons(self): pix = QPixmap(self.m_iconSize) painter = QPainter() gradient = QLinearGradient(0, 0, 0, self.m_iconSize.height()) gradient.setColorAt(0.0, QColor(240, 240, 240)) gradient.setColorAt(1.0, QColor(224, 224, 224)) brush = QBrush(gradient) # The original C++ code uses undocumented calls to get the names of the # different curve types. We do the Python equivalant (but without # cheating). curve_types = [(n, c) for n, c in QEasingCurve.__dict__.items() if isinstance(c, QEasingCurve.Type) and c != QEasingCurve.Custom] curve_types.sort(key=lambda ct: ct[1]) painter.begin(pix) for curve_name, curve_type in curve_types: painter.fillRect(QRect(QPoint(0, 0), self.m_iconSize), brush) curve = QEasingCurve(curve_type) if curve_type == QEasingCurve.BezierSpline: curve.addCubicBezierSegment(QPointF(0.4, 0.1), QPointF(0.6, 0.9), QPointF(1.0, 1.0)) elif curve_type == QEasingCurve.TCBSpline: curve.addTCBSegment(QPointF(0.0, 0.0), 0, 0, 0) curve.addTCBSegment(QPointF(0.3, 0.4), 0.2, 1, -0.2) curve.addTCBSegment(QPointF(0.7, 0.6), -0.2, 1, 0.2) curve.addTCBSegment(QPointF(1.0, 1.0), 0, 0, 0) painter.setPen(QColor(0, 0, 255, 64)) xAxis = self.m_iconSize.height() / 1.5 yAxis = self.m_iconSize.width() / 3.0 painter.drawLine(0, xAxis, self.m_iconSize.width(), xAxis) painter.drawLine(yAxis, 0, yAxis, self.m_iconSize.height()) curveScale = self.m_iconSize.height() / 2.0; painter.setPen(Qt.NoPen) # Start point. painter.setBrush(Qt.red) start = QPoint(yAxis, xAxis - curveScale * curve.valueForProgress(0)) painter.drawRect(start.x() - 1, start.y() - 1, 3, 3) # End point. painter.setBrush(Qt.blue) end = QPoint(yAxis + curveScale, xAxis - curveScale * curve.valueForProgress(1)) painter.drawRect(end.x() - 1, end.y() - 1, 3, 3) curvePath = QPainterPath() curvePath.moveTo(QPointF(start)) t = 0.0 while t <= 1.0: to = QPointF(yAxis + curveScale * t, xAxis - curveScale * curve.valueForProgress(t)) curvePath.lineTo(to) t += 1.0 / curveScale painter.setRenderHint(QPainter.Antialiasing, True) painter.strokePath(curvePath, QColor(32, 32, 32)) painter.setRenderHint(QPainter.Antialiasing, False) item = QListWidgetItem() item.setIcon(QIcon(pix)) item.setText(curve_name) self.m_ui.easingCurvePicker.addItem(item) painter.end()
class adamGLWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) xTransChanged = pyqtSignal(int) yTransChanged = pyqtSignal(int) zTransChanged = pyqtSignal(int) def __init__(self, parent=None): super(adamGLWidget, self).__init__(parent) self.xRot = 0 self.yRot = 0 self.zRot = 0 self.z_trans = 300 self.x_trans = 0 self.y_trans = 0 self.z_near = 1.0 self.z_far = 5000. self.cPart = 0 self.g_ambientLight = (0.35, 0.35, 0.35, 1.0) self.g_diffuseLight = (0.75, 0.75, 0.75, 0.7) self.g_specular = (1.0, 1.0, 1.0, 1.0) self.lastPos = QPoint() self.render_lock = QMutex() # def load_adam(self, pkl_path): self.adamWrapper = ADAM( pkl_path= '/home/xiul/workspace/PanopticDome/models/adamModel_lbs_200.pkl') adamdpPath = '/media/posefs3b/Users/xiu/PanopticDome/models/adam_to_uvi.pkl' with open(adamdpPath) as fio: adamdpPkl = pickle.load(fio) dp_colors_adam = np.array(adamdpPkl['adam_to_uvi']) dp_colors_adam = dp_colors_adam[:, [1, 0, 2]] self.part_index = dp_colors_adam[:, 2].astype(np.int) self.dp_colors = dp_colors_adam self.dp_colors[:, 2] = self.dp_colors[:, 2] / 255.0 self.dp_colors[:, :] = self.dp_colors[:, ::-1] self.dp_colors_shuffle = self.dp_colors.copy() np.random.shuffle(self.dp_colors_shuffle) self.dp_colors_shuffle[:, 0] = self.dp_colors_shuffle[:, 0] / 24 * 200 #self.dp_colors[:,0:2] = 0.5 self.f = self.adamWrapper.f vshape = self.adamWrapper.size[0] vbyf_vid = self.f.flatten('F') vbyf_fid = np.arange(self.f.shape[0]) vbyf_fid = np.concatenate((vbyf_fid, vbyf_fid, vbyf_fid)) vbyf_val = np.ones(len(vbyf_vid)) self.vbyf = scipy.sparse.coo_matrix( (vbyf_val, (vbyf_vid, vbyf_fid)), shape=(vshape, self.f.shape[0])).tocsr() pose = np.zeros(186) trans = np.zeros(3) betas = np.zeros(30) exps = np.zeros(200) self.adamJoints = None self.adamParam = { "pose": pose, "trans": trans, "betas": betas, "faces": exps } self.instanceAdam() def getOpenglInfo(self): info = """ Vendor: {} Renderer: {} OpenGL Version: {} Shader Version: {} """.format(glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION)) return info def vertices_normals(self, f, v): fNormal_u = v[f[:, 1], :] - v[f[:, 0], :] fNormal_v = v[f[:, 2], :] - v[f[:, 0], :] fNormal = np.cross(fNormal_u, fNormal_v) fNormal = sklearn.preprocessing.normalize(fNormal) vNormal = self.vbyf.dot(fNormal) vNormal = sklearn.preprocessing.normalize(vNormal) return vNormal def instanceAdam(self): self.render_lock.lock() adamParam = self.adamParam adamParam['faces'] = numpy.random.random_sample((200, )) / 80 trans = adamParam['trans'][np.newaxis, :] betas = adamParam['betas'][np.newaxis, :] poses = adamParam['pose'][np.newaxis, :] exps = adamParam['faces'][np.newaxis, :] v, j = self.adamWrapper(betas, poses, exps, get_skin=True) v += np.expand_dims(trans, axis=1) #j += np.expand_dims(trans, axis=1) j += trans self.adamJoints = j[0, :, :] import copy c = copy.deepcopy(self.dp_colors_shuffle) if self.cPart > 0: cHi = self.part_index != self.cPart c[cHi, :] = [0.5, 0.5, 0.5] c_data = c.flatten() v = np.reshape(v, (-1, 3)) vn = self.vertices_normals(f=self.f, v=v) v_data = v.flatten() vn_data = vn.flatten() glBindBuffer(GL_ARRAY_BUFFER, self.vn_buffer) glBufferData(GL_ARRAY_BUFFER, len(vn_data) * sizeof(ctypes.c_float), (ctypes.c_float * len(vn_data))(*vn_data), GL_STATIC_DRAW) glBindBuffer(GL_ARRAY_BUFFER, self.vts_buffer) glBufferData(GL_ARRAY_BUFFER, len(v_data) * sizeof(ctypes.c_float), (ctypes.c_float * len(v_data))(*v_data), GL_STATIC_DRAW) glBindBuffer(GL_ARRAY_BUFFER, self.color_buffer) glBufferData(GL_ARRAY_BUFFER, len(c_data) * sizeof(ctypes.c_float), (ctypes.c_float * len(c_data))(*c_data), GL_STATIC_DRAW) self.render_lock.unlock() def renderAdam(self): self.render_lock.lock() smpl_color = [125 / 255.0, 125 / 255.0, 125 / 255.0] glPushMatrix() glShadeModel(GL_SMOOTH) #glEnable(GL_LIGHTING) glColor4f(smpl_color[0], smpl_color[1], smpl_color[2], 0.3) ambientFskeleton = 0.1 diffuseFskeleton = 0.9 specularFskeleton = 0.1 smpl_shiness = 120.0 smpl_ambient = [ ambientFskeleton * smpl_color[0], ambientFskeleton * smpl_color[1], ambientFskeleton * smpl_color[2], 1.0 ] smpl_diffuse = [ diffuseFskeleton * smpl_color[0], diffuseFskeleton * smpl_color[1], diffuseFskeleton * smpl_color[2], 1.0 ] smpl_spectular = [ specularFskeleton * smpl_color[0], specularFskeleton * smpl_color[1], specularFskeleton * smpl_color[2], 1.0 ] glMaterialfv(GL_FRONT, GL_AMBIENT, smpl_ambient) glMaterialfv(GL_FRONT, GL_DIFFUSE, smpl_diffuse) glMaterialfv(GL_FRONT, GL_SPECULAR, smpl_spectular) glMaterialf(GL_FRONT, GL_SHININESS, smpl_shiness) glLineWidth(.5) if not self.cPart == 1: glEnableVertexAttribArray(2) glBindBuffer(GL_ARRAY_BUFFER, self.vn_buffer) glVertexAttribPointer( 2, # attribute 3, # size GL_FLOAT, # type GL_TRUE, # normalized? 0, #/ stride None # array buffer offset ) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, self.vts_buffer) glVertexAttribPointer( 0, # attribute 3, # size GL_FLOAT, # type GL_FALSE, # normalized? 0, #/ stride None # array buffer offset ) glEnableVertexAttribArray(3) glBindBuffer(GL_ARRAY_BUFFER, self.color_buffer) glVertexAttribPointer( 3, # attribute 3, # size GL_FLOAT, # type GL_FALSE, # normalized? 0, #/ stride None # array buffer offset ) glPolygonMode(GL_FRONT, GL_FILL) glPolygonMode(GL_BACK, GL_FILL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.inds_buffer) glDrawElements(GL_TRIANGLES, self.f.shape[0] * 3, GL_UNSIGNED_INT, None) glPolygonMode(GL_FRONT, GL_FILL) glPolygonMode(GL_BACK, GL_FILL) else: np.savetxt('Adam.txt', self.adamJoints) glPopMatrix() #render Joints for cid, pid in enumerate(self.adamWrapper.parents): if pid >= 0: # glColor4f(1.0,0.0,0.0,1.0) # glBegin(GL_LINES) # glVertex3f(self.adamJoints[cid,0],self.adamJoints[cid,1],self.adamJoints[cid,2]) # glVertex3f(self.adamJoints[pid,0],self.adamJoints[pid,1],self.adamJoints[pid,2]) # glEnd() glLineWidth(1) glColor4f(1.0, 0.0, 0.0, 1.0) glBegin(GL_LINES) #self.easyCylinder(self.adamJoints[cid],self.adamJoints[pid],15,[1.0,0.0,1.0,1]) glVertex3f(self.adamJoints[cid, 0], self.adamJoints[cid, 1], self.adamJoints[cid, 2]) glVertex3f(self.adamJoints[pid, 0], self.adamJoints[pid, 1], self.adamJoints[pid, 2]) glEnd() glPointSize(5) glBegin(GL_POINTS) glColor4f(0.1, 0.0, 1.0, 1.0) glVertex3f(self.adamJoints[cid, 0], self.adamJoints[cid, 1], self.adamJoints[cid, 2]) glEnd() self.render_lock.unlock() def setColorPart(self, partid): self.cPart = partid self.instanceAdam() self.update() def setAdamPoseParam(self, adamPose): self.adamParam['pose'] = adamPose self.instanceAdam() self.update() def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def setXTrans(self, trans): if trans != self.x_trans: self.x_trans = trans self.xTransChanged.emit(trans) self.update() def setYTrans(self, trans): if trans != self.y_trans: self.y_trans = trans self.yTransChanged.emit(trans) self.update() def setZTrans(self, trans): if trans != self.z_trans: self.z_trans = trans self.zTransChanged.emit(trans) self.update() def initializeGL(self): print(self.getOpenglInfo()) self.vts_buffer = glGenBuffers(1) self.vn_buffer = glGenBuffers(1) self.inds_buffer = glGenBuffers(1) self.color_buffer = glGenBuffers(1) self.load_adam( '/home/xiul/workspace/PanopticDome/models/adamModel_lbs_200.pkl') f_data = self.f.flatten() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.inds_buffer) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ctypes.c_uint) * len(f_data), (ctypes.c_uint * len(f_data))(*f_data), GL_STATIC_DRAW) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) glClearColor(1.0, 1.0, 1.0, 1.0) # Enable depth testing #glShadeModel(GL_SMOOTH) glShadeModel(GL_FLAT) glProvokingVertex(GL_FIRST_VERTEX_CONVENTION) glLightfv(GL_LIGHT0, GL_AMBIENT, self.g_ambientLight) glLightfv(GL_LIGHT0, GL_DIFFUSE, self.g_diffuseLight) glLightfv(GL_LIGHT0, GL_SPECULAR, self.g_specular) glLightfv(GL_LIGHT0, GL_POSITION, [-1, -1, 0]) # glEnable(GL_LIGHTING) glDisable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_DEPTH_TEST) glEnable(GL_COLOR_MATERIAL) glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) #gen buffer def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() gluLookAt(0, 0, 0, 0, 0, 1, 0, -1, 0) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(65, float(self.width()) / float(self.height()), self.z_near, self.z_far) glMatrixMode(GL_MODELVIEW) self.setView() #self.renderFloor() self.renderAdam() def resizeGL(self, width, height): glViewport(0, 0, width, height) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 2 * dy) self.setYRotation(self.yRot + 2 * dx) # elif event.buttons() & Qt.RightButton: # self.setXTrans(self.x_trans+8*dx) # self.setYTrans(self.y_trans+8*dy) self.lastPos = event.pos() def wheelEvent(self, event): dz = event.angleDelta().y() / 8 self.setZTrans(self.z_trans + dz) def normalizeAngle(self, angle): while angle < 0: angle += 360 while angle > 360: angle -= 360 return angle def setClearColor(self, c): glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def renderFloor(self): gridNum = 10 width = 50 g_floorCenter = np.array([0, 0, 0]) g_floorAxis1 = np.array([1, 0, 0]) g_floorAxis2 = np.array([0, 0, 1]) origin = g_floorCenter - g_floorAxis1 * \ (width*gridNum/2) - g_floorAxis2*(width*gridNum/2) axis1 = g_floorAxis1 * width axis2 = g_floorAxis2 * width for y in range(gridNum + 1): for x in range(gridNum + 1): if (x + y) % 2 == 0: glColor(1.0, 1.0, 1.0, 1.0) # white else: glColor(0.7, 0.7, 0.7, 1) # grey p1 = origin + axis1 * x + axis2 * y p2 = p1 + axis1 p3 = p1 + axis2 p4 = p1 + axis1 + axis2 glBegin(GL_QUADS) glVertex3f(p1[0], p1[1], p1[2]) glVertex3f(p2[0], p2[1], p2[2]) glVertex3f(p4[0], p4[1], p4[2]) glVertex3f(p3[0], p3[1], p3[2]) glEnd() def setView(self): glTranslatef(0, 0, self.z_trans) glRotatef(self.xRot, 1.0, 0.0, 0.0) glRotatef(self.yRot, 0.0, 1.0, 0.0) glRotatef(self.zRot, 0.0, 0.0, 1.0) glTranslatef(self.x_trans, 0.0, 0.0) glTranslatef(0.0, self.y_trans, 0.0)
def move(self, pos): # make new pos to center pos = QPoint(pos.x() - self.width() * 0.5, pos.y() - self.height() * 0.5) # make this always on top self.raise_() QWidget.move(self, pos)
class GLWidget(QGLWidget): def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.lastPos = QPoint() # 设置QT图形颜色,静态函数fromRgb(), fromHsv(),fromCmyk()可以通过指定特定值返回需要的颜色 # CYMK:青色Cyan、洋红色Magenta、黄色Yellow,黑色Black self.trolltechGreen = QColor.fromCmykF(0.50, 0.50, 0.1, 0.0) # 设置界面背景色 self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.39, 0.0) def minimumSizeHint(self): # QSize 类代表一个矩形区域的大小,实现在 QtCore 共享库中。它可以认为是由一个整型的宽度和整型的高度组合 return QSize(50, 50) def sizeHint(self): return QSize(400, 400) def normalizeAngle(self, angle): print('angle=', angle) if angle < 0: angle += 360 * 16 elif angle > 360 * 16: angle -= 360 * 16 else: pass return angle def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.update() # 也可以是self.updateGL() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.update() # 也可以是self.updateGL() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.update() # 也可以是self.updateGL() # mousePressEvent鼠标键按下时调用 def mousePressEvent(self, event): # pos() - 返回相对于控件空间的QPoint对象; self.lastPos = event.localPos() print('lastPos1.x = ', self.lastPos.x()) print('lastPos1.y = ', self.lastPos.y()) def mouseMoveEvent(self, event): # x() - 返回当前控件上鼠标的x坐标 dx = +event.x() - self.lastPos.x() print('event.x=', event.x()) dy = -event.y() + self.lastPos.y() print('event.y=', event.y()) print('lastPos.x2 = ', self.lastPos.x()) print('lastPos.y2 = ', self.lastPos.y()) if event.buttons() == Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() == Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() def initializeGL(self): self.qglClearColor(self.trolltechPurple.darker()) self.object = self.makeObject() GL.glShadeModel(GL.GL_FLAT) GL.glEnable(GL.GL_DEPTH_TEST) GL.glEnable(GL.GL_CULL_FACE) def paintGL(self): ''' clear buffers to preset values,用预制的值来清空缓冲区 参数: GL_COLOR_BUFFER_BIT,颜色缓冲 GL_DEPTH_BUFFER_BIT,深度缓冲 GL_STENCIL_BUFFER_BIT,模板缓冲 ''' GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) GL.glLoadIdentity() GL.glTranslated(0.0, 0.0, -6.0) # GL.glRotated函数功能:以点(0,0,0)到点(x,y,z)为轴,旋转angle角度; GL.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) GL.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) GL.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) GL.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) if side < 0: return ''' Viewport(GLint x,GLint y,GLsizei width,GLsizei height) x,y 以像素为单位,指定了视口的左下角位置 width,height 表示这个视口矩形的宽度和高度,根据窗口的实时变化重绘窗口。 # //为向下取整 ''' GL.glViewport(0, 0, side, side) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() # 正交投影glOrtho(left, right, bottom, top, near, far) # 透视投影glFrustum(left, right, bottom, top, near, far) # glFrustum()中near和far表示离视点的远近,它们总为正值(near/far 必须>0) GL.glFrustum(-0.5, +0.5, +0.5, -0.5, 5.0, 8.0) GL.glMatrixMode(GL.GL_MODELVIEW) def makeObject(self): # glGenLists()会生成一组连续的空的显示列表,参数range为空列表数量 genList = GL.glGenLists(1) GL.glNewList(genList, GL.GL_COMPILE) GL.glBegin(GL.GL_TRIANGLE_STRIP) r_sec = 0.02 R_ring = 0.3 NumRing = 120 NumSec = 20 delta_AR = 2 * math.pi / NumRing delta_AS = 2 * math.pi / NumSec AngleRing = 0 for i in range(NumRing): AngleRing = AngleRing + delta_AR AngleSec = 0 for j in range(NumSec + 1): x_p1 = (R_ring + r_sec * math.cos(AngleSec)) * math.cos(AngleRing) y_p1 = (R_ring + r_sec * math.cos(AngleSec)) * math.sin(AngleRing) z_p1 = r_sec * math.sin(AngleSec) x_p2 = (R_ring + r_sec * math.cos(AngleSec)) * math.cos(AngleRing + delta_AR) y_p2 = (R_ring + r_sec * math.cos(AngleSec)) * math.sin(AngleRing + delta_AR) z_p2 = r_sec * math.sin(AngleSec) GL.glColor3f(i / (NumRing), 0.5, 0.5) GL.glVertex3d(x_p1, y_p1, z_p1) GL.glVertex3d(x_p2, y_p2, z_p2) AngleSec = AngleSec + delta_AS trans_x = (R_ring - r_sec) * 2 rotate_X = 15 * math.pi / 180 GL.glEnd() GL.glEndList() return genList
class ScribbleArea(QWidget): def __init__(self, width, height, scaling_factor, foreground_color, background_color, enable_grid, grid_color, parent): super().__init__(parent) self.parent = parent self.scribbling = 0 self.width = width self.height = height self.scaling_factor = scaling_factor self.pen_width = 1 self.foreground_color = foreground_color self.background_color = background_color self.grid_enabled = enable_grid if grid_color is not None: self.grid_color = grid_color else: self.grid_color = self.palette().color(QPalette.Window) self.image = QImage(QSize(width, height), QImage.Format_RGB32) self.setFixedSize(width*self.scaling_factor, height*self.scaling_factor) self.last_point = QPoint() self.clear_image() def set_foreground_color(self, color): self.foreground_color = color def array_draw(self, r, g, b, scale=1): for i in range(len(r)): self.image.setPixel(QPoint(i%self.width, i//self.width), (r[i]*scale << 16) | (g[i]*scale << 8) | b[i]*scale) self.update() def fill_image(self, color): self.image.fill(color) self.update() def clear_image(self): self.image.fill(self.background_color) self.update() def mousePressEvent(self, event): self.parent.scribbling_started.emit() if event.button() == Qt.LeftButton: self.last_point = event.pos() self.scribbling = 1 elif event.button() == Qt.RightButton: self.last_point = event.pos() self.scribbling = 2 def mouseMoveEvent(self, event): if (event.buttons() & Qt.LeftButton) and self.scribbling == 1: self.draw_line_to(event.pos()) elif (event.buttons() & Qt.RightButton) and self.scribbling == 2: self.draw_line_to(event.pos()) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.scribbling == 1: self.draw_line_to(event.pos()) self.scribbling = 0 elif event.button() == Qt.RightButton and self.scribbling == 2: self.draw_line_to(event.pos()) self.scribbling = 0 def paintEvent(self, event): painter = QPainter(self) painter.drawImage(QRect(0, 0, super().width(), super().height()), self.image) if self.grid_enabled: painter.setPen(QPen(self.grid_color)) for x in range(1, self.width): painter.drawLine(x * self.scaling_factor, 0, x * self.scaling_factor, super().height()) for y in range(1, self.height): painter.drawLine(0, y * self.scaling_factor, super().width(), y * self.scaling_factor) self.parent.paint_overlay(event, painter) def draw_line_to(self, end_point): painter = QPainter(self.image) painter.setPen(QPen(self.foreground_color if self.scribbling == 1 else self.background_color, self.pen_width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(QPoint(self.last_point.x()//self.scaling_factor, self.last_point.y()//self.scaling_factor), QPoint(end_point.x()//self.scaling_factor, end_point.y()//self.scaling_factor)) self.update() self.last_point = QPoint(end_point)
class GLWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.lastPos = QPoint() self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(400, 400) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def initializeGL(self): self.gl = self.context().versionFunctions() self.gl.initializeOpenGLFunctions() self.setClearColor(self.trolltechPurple.darker()) self.object = self.makeObject() self.gl.glShadeModel(self.gl.GL_FLAT) self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glEnable(self.gl.GL_CULL_FACE) def paintGL(self): self.gl.glClear( self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.gl.glLoadIdentity() self.gl.glTranslated(0.0, 0.0, -10.0) self.gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) self.gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) self.gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) self.gl.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) if side < 0: return self.gl.glViewport((width - side) // 2, (height - side) // 2, side, side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() self.gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() def makeObject(self): genList = self.gl.glGenLists(1) self.gl.glNewList(genList, self.gl.GL_COMPILE) self.gl.glBegin(self.gl.GL_QUADS) x1 = +0.06 y1 = -0.14 x2 = +0.14 y2 = -0.06 x3 = +0.08 y3 = +0.00 x4 = +0.30 y4 = +0.22 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) self.quad(x3, y3, x4, y4, y4, x4, y3, x3) self.extrude(x1, y1, x2, y2) self.extrude(x2, y2, y2, x2) self.extrude(y2, x2, y1, x1) self.extrude(y1, x1, x1, y1) self.extrude(x3, y3, x4, y4) self.extrude(x4, y4, y4, x4) self.extrude(y4, x4, y3, x3) NumSectors = 200 for i in range(NumSectors): angle1 = (i * 2 * math.pi) / NumSectors x5 = 0.30 * math.sin(angle1) y5 = 0.30 * math.cos(angle1) x6 = 0.20 * math.sin(angle1) y6 = 0.20 * math.cos(angle1) angle2 = ((i + 1) * 2 * math.pi) / NumSectors x7 = 0.20 * math.sin(angle2) y7 = 0.20 * math.cos(angle2) x8 = 0.30 * math.sin(angle2) y8 = 0.30 * math.cos(angle2) self.quad(x5, y5, x6, y6, x7, y7, x8, y8) self.extrude(x6, y6, x7, y7) self.extrude(x8, y8, x5, y5) self.gl.glEnd() self.gl.glEndList() return genList def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): self.setColor(self.trolltechGreen) self.gl.glVertex3d(x1, y1, -0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x3, y3, -0.05) self.gl.glVertex3d(x4, y4, -0.05) self.gl.glVertex3d(x4, y4, +0.05) self.gl.glVertex3d(x3, y3, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x1, y1, +0.05) def extrude(self, x1, y1, x2, y2): self.setColor(self.trolltechGreen.darker(250 + int(100 * x1))) self.gl.glVertex3d(x1, y1, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x1, y1, -0.05) def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def setClearColor(self, c): self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
class Settings(object): l = logging.getLogger('Settings') def __init__(self, fileName = 'notepad.ini'): self.fileName = fileName self.notepads = [] self.mainWindowSize = QSize(1200, 700) self.mainWindowPos = QPoint(240, 200) self.browserPath = [] def load(self): self.l.debug('Loading local settings ...') config = configparser.ConfigParser() config.read(self.fileName) # load dropbox configuration self.dropboxToken = '' if config.has_section('dropbox'): self.dropboxToken = config['dropbox'].get('dropboxToken') # load browser state if config.has_section('browser'): browserSettings = config['browser'] path = browserSettings.get('path') self.browserPath = ast.literal_eval(path) # load main window position and size if config.has_section('mainWindow'): windowSettings = config['mainWindow'] # read position pos = windowSettings.get('pos', '{},{}'.format(self.mainWindowPos.x(), self.mainWindowPos.y())).split(',') self.mainWindowPos = QPoint(int(pos[0]), int(pos[1])) # read size size = windowSettings.get('size', '{},{}'.format(self.mainWindowSize.width(), self.mainWindowSize.height())).split(',') self.mainWindowSize = QSize(int(size[0]), int(size[1])) # load notepads self.notepads = [] for s in config.sections(): if s.startswith('notepad_'): npDef = None npType = config.get(s, 'type') if npType == 'local': npDef = {'name' : config.get(s, 'name'), 'type' : npType, 'path' : config.get(s, 'path') } elif npType == 'dropbox': npDef = {'name' : config.get(s, 'name'), 'type' : npType } if npDef is not None: self.notepads.append(npDef) def dump(self, channel): self.l.debug('Saving local settings ...') config = configparser.ConfigParser() config.add_section('dropbox') config.set('dropbox', 'dropboxToken', self.dropboxToken) config.add_section('browser') config.set('browser', 'path', str(self.browserPath)) config.add_section('mainWindow') config.set('mainWindow', 'pos', '{},{}'.format(self.mainWindowPos.x(), self.mainWindowPos.y())) config.set('mainWindow', 'size', '{},{}'.format(self.mainWindowSize.width(), self.mainWindowSize.height())) idx = 0 for s in self.notepads: sectName = "notepad_{}".format(idx) idx += 1 config.add_section(sectName) config.set(sectName, 'name', s['name']) config.set(sectName, 'type', s['type']) if s['type'] == 'local': config.set(sectName, 'path', s['path']) config.write(channel) def save(self): with open(self.fileName, 'w') as configfile: self.dump(configfile) def getNotepads(self): return self.notepads def addNotepad(self, npDef): self.notepads.append(npDef) def setMainWindowPos(self, pos): self.mainWindowPos = pos def setBrowserPath(self, path): self.browserPath = path def setMainWindowSize(self, size): self.mainWindowSize = size def getMainWindowPos(self): return self.mainWindowPos def getMainWindowSize(self): return self.mainWindowSize def getBrowserPath(self): return self.browserPath def getDropboxToken(self): return self.dropboxToken def setDropboxToken(self, token): self.dropboxToken = token
class GLWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.lastPos = QPoint() self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(400, 400) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def initializeGL(self): self.gl = self.context().versionFunctions() self.gl.initializeOpenGLFunctions() self.setClearColor(self.trolltechPurple.darker()) self.object = self.makeObject() self.gl.glShadeModel(self.gl.GL_FLAT) self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glEnable(self.gl.GL_CULL_FACE) def paintGL(self): self.gl.glClear(self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.gl.glLoadIdentity() self.gl.glTranslated(0.0, 0.0, -10.0) self.gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) self.gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) self.gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) self.gl.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) if side < 0: return self.gl.glViewport((width - side) // 2, (height - side) // 2, side, side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() self.gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() def makeObject(self): genList = self.gl.glGenLists(1) self.gl.glNewList(genList, self.gl.GL_COMPILE) self.gl.glBegin(self.gl.GL_QUADS) x1 = +0.06 y1 = -0.14 x2 = +0.14 y2 = -0.06 x3 = +0.08 y3 = +0.00 x4 = +0.30 y4 = +0.22 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) self.quad(x3, y3, x4, y4, y4, x4, y3, x3) self.extrude(x1, y1, x2, y2) self.extrude(x2, y2, y2, x2) self.extrude(y2, x2, y1, x1) self.extrude(y1, x1, x1, y1) self.extrude(x3, y3, x4, y4) self.extrude(x4, y4, y4, x4) self.extrude(y4, x4, y3, x3) NumSectors = 200 for i in range(NumSectors): angle1 = (i * 2 * math.pi) / NumSectors x5 = 0.30 * math.sin(angle1) y5 = 0.30 * math.cos(angle1) x6 = 0.20 * math.sin(angle1) y6 = 0.20 * math.cos(angle1) angle2 = ((i + 1) * 2 * math.pi) / NumSectors x7 = 0.20 * math.sin(angle2) y7 = 0.20 * math.cos(angle2) x8 = 0.30 * math.sin(angle2) y8 = 0.30 * math.cos(angle2) self.quad(x5, y5, x6, y6, x7, y7, x8, y8) self.extrude(x6, y6, x7, y7) self.extrude(x8, y8, x5, y5) self.gl.glEnd() self.gl.glEndList() return genList def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): self.setColor(self.trolltechGreen) self.gl.glVertex3d(x1, y1, -0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x3, y3, -0.05) self.gl.glVertex3d(x4, y4, -0.05) self.gl.glVertex3d(x4, y4, +0.05) self.gl.glVertex3d(x3, y3, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x1, y1, +0.05) def extrude(self, x1, y1, x2, y2): self.setColor(self.trolltechGreen.darker(250 + int(100 * x1))) self.gl.glVertex3d(x1, y1, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x1, y1, -0.05) def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def setClearColor(self, c): self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
class MapWidget(QWidget): def __init__(self, mapper: MapReceiver, settings=None): QWidget.__init__(self) self.mapper = mapper self.tile_size = 256 self.tile_drawn = [] self.lat = 56.842963648401295 self.lon = 60.6005859375 self.zoom = 15 self.delta = QPoint(0, 0) self.to_rerender = False self.load_settings(settings) self.trammer = TransportReceiver() self.drag_start = None self.current_pos = None def load_settings(self, settings): if settings is None: return self.lat = settings['lat'] self.lon = settings['lon'] def get_settings(self): return { 'lat': self.lat, 'lon': self.lon } def paintEvent(self, e): zoom = 15 painter = QPainter() painter.begin(self) try: if self.to_rerender: self.rerender(painter) else: self.draw_tiles_from_corner(painter, self.lat, self.lon, zoom) self.draw_trams(painter) except Exception as e: print(e) painter.end() def draw_tiles_from_corner(self, painter: QPainter, x, y, zoom): geom = self.geometry() corner_x, corner_y = self.mapper.coords_to_tile(x, y, zoom) row_number = 0 for row in range(geom.top() - self.tile_size, geom.height(), self.tile_size): col_number = 0 for column in range(geom.left() - self.tile_size, geom.right(), self.tile_size): target_rect = QRect(column, row, self.tile_size, self.tile_size) tile_rect = QRect(0, 0, self.tile_size, self.tile_size) res_x = corner_x + col_number res_y = corner_y + row_number tile = self.mapper.get_tile_from_numbers(res_x, res_y, zoom) tile.corner = target_rect.topLeft() self.tile_drawn.append(tile) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) tile.widget_x = target_rect.x() tile.widget_y = target_rect.y() col_number += 1 row_number += 1 def rerender(self, painter: QPainter): for tile in self.tile_drawn: tile.widget_x += self.delta.x() tile.widget_y += self.delta.y() target_rect = QRectF(tile.widget_x, tile.widget_y, self.tile_size, self.tile_size) tile_rect = QRectF(0, 0, self.tile_size, self.tile_size) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) self.fill_perimeter(painter) self.clear_tiles() def fill_perimeter(self, painter): self.fill_top_row(painter) self.fill_bottom_row(painter) self.fill_left_column(painter) self.fill_right_column(painter) def fill_top_row(self, painter: QPainter): top_tile = min(self.get_tiles_on_screen(), key=lambda tile: tile.widget_y) if top_tile.widget_y > -self.tile_size: row = top_tile.widget_y - self.tile_size col_number = 0 res_row = top_tile.y - 1 for column in range(int(top_tile.widget_x), self.geometry().width() + 1, self.tile_size): res_col = top_tile.x + col_number tile = self.mapper.get_tile_from_numbers(res_col, res_row, self.zoom) target_rect = QRectF(column, row, self.tile_size, self.tile_size) tile_rect = QRectF(0, 0, self.tile_size, self.tile_size) self.tile_drawn.append(tile) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) tile.widget_x = target_rect.x() tile.widget_y = target_rect.y() col_number += 1 def fill_bottom_row(self, painter: QPainter): bottom_tile = max(self.get_tiles_on_screen(), key=lambda cur_tile: cur_tile.widget_y) if bottom_tile.widget_y < self.geometry().height(): row = bottom_tile.widget_y + self.tile_size col_number = 0 res_row = bottom_tile.y + 1 for column in range(int(bottom_tile.widget_x), self.geometry().width() + 1, self.tile_size): res_col = bottom_tile.x + col_number tile = self.mapper.get_tile_from_numbers(res_col, res_row, self.zoom) target_rect = QRectF(column, row, self.tile_size, self.tile_size) tile_rect = QRectF(0, 0, self.tile_size, self.tile_size) self.tile_drawn.append(tile) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) tile.widget_x = target_rect.x() tile.widget_y = target_rect.y() col_number += 1 def fill_left_column(self, painter: QPainter): left_tile = min(self.get_tiles_on_screen(), key=lambda tile: tile.widget_x) if left_tile.widget_x > -self.tile_size: column = left_tile.widget_x - self.tile_size row_number = 0 res_col = left_tile.x - 1 for row in range(int(left_tile.widget_y), self.geometry().height() + 1, self.tile_size): res_row = left_tile.y + row_number tile = self.mapper.get_tile_from_numbers(res_col, res_row, self.zoom) target_rect = QRectF(column, row, self.tile_size, self.tile_size) tile_rect = QRectF(0, 0, self.tile_size, self.tile_size) self.tile_drawn.append(tile) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) tile.widget_x = target_rect.x() tile.widget_y = target_rect.y() row_number += 1 def fill_right_column(self, painter: QPainter): right_tile = max(self.get_tiles_on_screen(), key=lambda tile: tile.widget_x) if right_tile.widget_x < self.geometry().width() + 256: column = right_tile.widget_x + self.tile_size row_number = 0 res_col = right_tile.x + 1 for row in range(int(right_tile.widget_y), self.geometry().height() + 1, self.tile_size): res_row = right_tile.y + row_number tile = self.mapper.get_tile_from_numbers(res_col, res_row, self.zoom) target_rect = QRectF(column, row, self.tile_size, self.tile_size) tile_rect = QRectF(0, 0, self.tile_size, self.tile_size) self.tile_drawn.append(tile) painter.drawPixmap(target_rect, QPixmap(tile.path), tile_rect) tile.widget_x = target_rect.x() tile.widget_y = target_rect.y() row_number += 1 def clear_tiles(self): geom = self.geometry() bounds = QRect(-self.tile_size, -self.tile_size, geom.width() + self.tile_size, geom.height() + self.tile_size) tiles = [tile for tile in self.tile_drawn if self.fully_outside(QRect(tile.widget_x, tile.widget_y, self.tile_size, self.tile_size), bounds)] for tile in tiles: self.tile_drawn.remove(tile) def outside_bounds(self, rect: QRect, bounds: QRect): return rect.top() < bounds.top() or rect.bottom() > bounds.bottom() or rect.left() < bounds.left() or rect.right() > bounds.right() def fully_outside(self, rect: QRect, bounds: QRect): return rect.bottom() < bounds.top() or rect.right() < bounds.left() or rect.top() > bounds.bottom() or rect.left() > bounds.right() def get_tiles_on_screen(self): geom = self.geometry() return [tile for tile in self.tile_drawn if not self.outside_bounds(QRect(tile.widget_x, tile.widget_y, self.tile_size, self.tile_size), geom)] def point_is_outside(self, point: QPointF, bounds: QRectF): return point.x() < bounds.left() or point.x() > bounds.right() or point.y() < bounds.top() or point.y() > bounds.bottom() def draw_trams(self, painter: QPainter): trams = self.trammer.get_trams() last_tile = self.tile_drawn[-1] right_bottom = self.mapper.tile_too_coords(last_tile.x + 1, last_tile.y + 1, self.zoom) right_bottom = QPointF(right_bottom[1], right_bottom[0]) width = math.fabs(right_bottom.x() - self.lon) height = math.fabs(right_bottom.y() - self.lat) bounds = QRectF(self.lon, right_bottom.y(), width, height) for tram in trams: location = QPointF(tram.lon, tram.lat) if self.point_is_outside(location, bounds): continue coords = self.count_tram_tile_coords(tram) if coords is not None: x, y = coords painter.setBrush(QColor(255, 0, 0)) painter.drawEllipse(x, y, 10, 10) painter.drawText(x, y, tram.route) def count_tram_tile_coords(self, tram): tile = self.mapper.coords_to_tile(tram.lat, tram.lon, self.zoom) drawn_tile = self.find_tile(tile[0], tile[1]) if drawn_tile is None: return tile_lat, tile_lon = self.mapper.tile_too_coords(tile[0], tile[1], self.zoom) dy = self.mapper.get_distance((tile_lat, tile_lon), (tram.lat, tile_lon)) dx = self.mapper.get_distance((tile_lat, tile_lon), (tile_lat, tram.lon)) resolution = self.mapper.get_resolution(tram.lat, self.zoom) tile_dy = dy / resolution tile_dx = dx / resolution return drawn_tile.widget_x + tile_dx, drawn_tile.widget_y + tile_dy def find_tile(self, x, y): for tile in self.tile_drawn: if tile.x == x and tile.y == y: return tile return None def find_tile_by_drawn_coords(self, x, y): for tile in self.tile_drawn: if x - tile.widget_x <= 256 and y - tile.widget_y <= 256: return tile return None def mousePressEvent(self, event): self.drag_start = event.localPos() def mouseMoveEvent(self, event): self.current_pos = event.localPos() tile = self.find_tile_by_drawn_coords(self.current_pos.x(), self.current_pos.y()) if tile is None: return delta = self.current_pos - self.drag_start new_x, new_y = tile.x + delta.x() / 256, tile.y + delta.y() / 256 new_lat, new_lon = self.mapper.tile_too_coords(new_x, new_y, self.zoom) old_lat, old_lon = self.mapper.tile_too_coords(tile.x, tile.y, self.zoom) coords_delta = (new_lat - old_lat, new_lon - old_lon) self.lat -= coords_delta[0] self.lon -= coords_delta[1] self.drag_start = self.current_pos self.delta = delta self.to_rerender = True self.update()
class Window(QMainWindow): def __init__(self): super().__init__() top = 400 left = 400 width = 1200 height = 500 self.maximum_undo = 20 self.obj_type = 'wall' self.obj_width = 10 self.pix_per_meter = 10 self.bgc = Qt.white self.shift_pressed = False icon = "icon.png" self.setGeometry(top, left, width, height) self.setWindowTitle("Map Designer") self.setWindowIcon(QIcon(icon)) self.setFixedSize(width, height) self.hidden_obstacle_layer = QImage(1000, 500, QImage.Format_RGB32) self.hidden_obstacle_layer.fill(self.bgc) self.backup_hidden_obstacle = [] self.backup_hidden_obstacle.append(self.hidden_obstacle_layer) self.temp_hidden_obstacle_layer = self.hidden_obstacle_layer self.hidden_railing_brush = QBrush(Qt.SolidPattern) self.hidden_railing_brush.setColor(Qt.red) self.hidden_wall_brush = QBrush(Qt.SolidPattern) self.hidden_wall_brush.setColor(Qt.black) self.hidden_pillar_brush = QBrush(Qt.SolidPattern) self.hidden_pillar_brush.setColor(Qt.green) self.hidden_counter_brush = QBrush(Qt.SolidPattern) self.hidden_counter_brush.setColor(Qt.blue) self.hidden_destination_layer = QImage(1000, 500, QImage.Format_RGB32) self.hidden_destination_layer.fill(self.bgc) self.backup_hidden_destination = [] self.backup_hidden_destination.append(self.hidden_destination_layer) self.temp_hidden_destination_layer = self.hidden_destination_layer self.hidden_exit_brush = QBrush(Qt.SolidPattern) self.hidden_exit_brush.setColor(Qt.red) self.hidden_entry_brush = QBrush(Qt.SolidPattern) self.hidden_entry_brush.setColor(Qt.black) self.hidden_passage_brush = QBrush(Qt.SolidPattern) self.hidden_passage_brush.setColor(Qt.green) self.hidden_waiting_brush = QBrush(Qt.SolidPattern) self.hidden_waiting_brush.setColor(Qt.blue) self.hidden_pen = QPen() self.hidden_pen.setColor(self.bgc) self.left_layout = QHBoxLayout() self.left_zone = QWidget(self) self.left_zone.setLayout(self.left_layout) self.image = QImage(1000, 500, QImage.Format_RGB32) self.image.fill(self.bgc) self.image_label = QLabel(self) self.image_label.setGeometry(0, 0, 1000, 500) self.image_label.setPixmap(QPixmap.fromImage(self.image)) self.left_layout.addWidget(self.image_label) self.left_layout.setSpacing(0) self.left_layout.setContentsMargins(0, 0, 0, 0) self.left_layout.setStretch(0, 0) self.left_layout.setGeometry(QRect(QPoint(0, 0), QPoint(1000, 500))) self.splitter = QSplitter(self) self.splitter.setOrientation(Qt.Horizontal) self.splitter.setContentsMargins(0, 0, 0, 0) self.splitter.setFixedSize(1200, 500) self.splitter.setHandleWidth(0) self.splitter.addWidget(self.left_zone) self.backup_image = [] self.backup_image.append(self.image) self.draw_record = [] self.temp_image = QImage(1000, 500, QImage.Format_RGB32) self.temp_image.fill(self.bgc) self.drawing = False self.lastPoint = QPoint() # mainMenu = self.menuBar() # mainMenu.setNativeMenuBar(False) # fileMenu = mainMenu.addMenu("File") # brushMenu = mainMenu.addMenu("Brush Size") # brushColor = mainMenu.addMenu("Brush Color") # # saveAction = QAction("Save", self) # saveAction.setShortcut("Ctrl+S") # fileMenu.addAction(saveAction) # # clearAction = QAction("Clear", self) # clearAction.setShortcut("Ctrl+C") # fileMenu.addAction(clearAction) # # px3Action = QAction("3px", self) # px3Action.setShortcut("Ctrl+3") # brushMenu.addAction(px3Action) # # px5Action = QAction("5px", self) # px5Action.setShortcut("Ctrl+5") # brushMenu.addAction(px5Action) # # px9Action = QAction("9px", self) # px9Action.setShortcut("Ctrl+9") # brushMenu.addAction(px5Action) # # blackAction = QAction("Black", self) # blackAction.setShortcut("Ctrl+B") # brushColor.addAction(blackAction) # # whiteAction = QAction("White", self) # whiteAction.setShortcut("Ctrl+W") # brushColor.addAction(whiteAction) # #按钮控件 # # self.btn_obstacle = QPushButton(self) # self.btn_obstacle.setGeometry(1020, 40, 20, 20) # self.btn_obstacle.setText("■") # self.btn_obstacle.setStyleSheet("QPushButton{color: black; padding-bottom: 2px;}" # "QPushButton:hover{background-color: darkgrey}") # # self.btn_dest = QPushButton(self) # self.btn_dest.setGeometry(1020, 80, 20, 20) # self.btn_dest.setText("■") # self.btn_dest.setStyleSheet("color: green; padding-bottom: 2px") #绘制选项 self.right_layout = QVBoxLayout() self.right_zone = QWidget(self) self.right_zone.setLayout(self.right_layout) self.splitter.addWidget(self.right_zone) #self.right_layout.addWidget(self.image_label) #0.坐标显示区 self.right_layout.addStretch() self.coordinates_label = QLabel(self) self.coordinates_label.setText("当前坐标(m): ") self.coordinates_label.setFont(QFont("Noto Sans CJK SC")) self.right_layout.addWidget(self.coordinates_label) self.coordinates_disp = QLabel(self) self.coordinates_disp.setText("坐标: x = 0.0, \ty = 0.0") self.coordinates_disp.setFont(QFont("Noto Sans CJK SC")) self.right_layout.addWidget(self.coordinates_disp) #1. 绘制障碍物标题 self.right_layout.addStretch() self.obstacle_label = QLabel(self) self.obstacle_label.setText("绘制障碍物: ") self.obstacle_label.setFont(QFont("Noto Sans CJK SC")) #self.obstacle_label.setGeometry(1010, 40, 100, 30) self.right_layout.addWidget(self.obstacle_label) self.obstacle_pen = QPen(Qt.SolidLine) self.obstacle_pen.setColor(Qt.black) #1.1 绘制护栏 #1.1.1 护栏选择框 self.select_railing = QRadioButton(self) self.select_railing.setText("护栏. ") self.select_railing.setFont(QFont("Noto Sans CJK SC")) self.select_railing.toggled.connect(self.drawTypeChange) self.right_layout.addWidget(self.select_railing) #self.select_railing.setGeometry(1030, 65, 60, 30) #1.1.2 护栏笔刷 self.railing_brush = QBrush(Qt.BDiagPattern) self.railing_brush.setColor(Qt.darkGray) self.railing_width = 0.5 # 1.2.1 墙体选择框 self.wall_box = QHBoxLayout() self.select_wall = QRadioButton(self) self.select_wall.setText("墙体, ") self.select_wall.setFont(QFont("Noto Sans CJK SC")) self.select_wall.toggled.connect(self.drawTypeChange) #self.select_wall.setGeometry(1030, 90, 60, 30) self.wall_box.addWidget(self.select_wall) # 1.2.2 墙体笔刷 self.wall_brush = QBrush(Qt.Dense6Pattern) self.wall_brush.setColor(Qt.darkGray) self.wall_width = 1 #1.2.3 墙体宽度标签 self.wall_width_label = QLabel(self) self.wall_width_label.setText("宽度(m): ") self.wall_width_label.setFont(QFont("Noto Sans CJK SC")) #self.wall_width_label.setGeometry(1090, 90, 60, 30) self.wall_box.addWidget(self.wall_width_label) # 1.2.3 墙体宽度输入框 self.wall_width_input = QLineEdit(self) self.wall_width_input.setText("1") #self.wall_width_input.setGeometry(1140, 95, 30, 20) self.wall_width_input.setAlignment(Qt.AlignRight) self.wall_box.addWidget(self.wall_width_input) self.wall_width_input.textChanged.connect(self.widthChange) self.right_layout.addLayout(self.wall_box) # 1.3.1 立柱选择框 self.pillar_box = QHBoxLayout() self.select_pillar = QRadioButton(self) self.select_pillar.setText("立柱, ") self.select_pillar.setFont(QFont("Noto Sans CJK SC")) self.select_pillar.toggled.connect(self.drawTypeChange) #self.select_pillar.setGeometry(1030, 90, 60, 30) self.pillar_box.addWidget(self.select_pillar) # 1.3.2 立柱笔刷 self.pillar_brush = QBrush(Qt.Dense4Pattern) self.pillar_brush.setColor(Qt.darkGray) self.pillar_width = 1 # 1.3.3 立柱宽度标签 self.pillar_width_label = QLabel(self) self.pillar_width_label.setText("宽度(m): ") self.pillar_width_label.setFont(QFont("Noto Sans CJK SC")) # self.wall_width_label.setGeometry(1090, 90, 60, 30) self.pillar_box.addWidget(self.pillar_width_label) # 1.3.3 立柱宽度输入框 self.pillar_width_input = QLineEdit(self) self.pillar_width_input.setText("1") # self.wall_width_input.setGeometry(1140, 95, 30, 20) self.pillar_width_input.setAlignment(Qt.AlignRight) self.pillar_box.addWidget(self.pillar_width_input) self.pillar_width_input.textChanged.connect(self.widthChange) self.right_layout.addLayout(self.pillar_box) # 1.4.1 柜台选择框 #self.counter_box = QHBoxLayout() self.select_counter = QRadioButton(self) self.select_counter.setText("柜台. ") self.select_counter.setFont(QFont("Noto Sans CJK SC")) self.select_counter.toggled.connect(self.drawTypeChange) #self.select_counter.setGeometry(1030, 90, 60, 30) self.right_layout.addWidget(self.select_counter) #self.counter_box.addWidget(self.select_counter) # 1.4.2 柜台笔刷 self.counter_brush = QBrush(Qt.HorPattern) self.counter_brush.setColor(Qt.darkGray) self.counter_width = 1 # # 1.4.3 柜台宽度标签 # self.counter_width_label = QLabel(self) # self.counter_width_label.setText("宽度(m): ") # self.counter_width_label.setFont(QFont("Noto Sans CJK SC")) # # self.wall_width_label.setGeometry(1090, 90, 60, 30) # self.counter_box.addWidget(self.counter_width_label) # # 1.4.3 柜台宽度输入框 # self.counter_width_input = QLineEdit(self) # self.counter_width_input.setText("1") # # self.wall_width_input.setGeometry(1140, 95, 30, 20) # self.counter_width_input.setAlignment(Qt.AlignRight) # self.counter_box.addWidget(self.counter_width_input) # self.counter_width_input.textChanged.connect(self.widthChange) #self.right_layout.addLayout(self.counter_box) # 2. 绘制障碍物标题 self.right_layout.addStretch() self.destination_label = QLabel(self) self.destination_label.setText("绘制出入口及休息区: ") self.destination_label.setFont(QFont("Noto Sans CJK SC")) # self.obstacle_label.setGeometry(1010, 40, 100, 30) self.right_layout.addWidget(self.destination_label) self.destination_pen = QPen(Qt.DashDotDotLine) self.destination_pen.setColor(Qt.lightGray) # 2.1 绘制出口 # 2.1.1 出口选择框 self.select_exit = QRadioButton(self) self.select_exit.setText("出口. ") self.select_exit.setFont(QFont("Noto Sans CJK SC")) self.select_exit.toggled.connect(self.drawTypeChange) self.right_layout.addWidget(self.select_exit) # self.select_railing.setGeometry(1030, 65, 60, 30) # 2.1.2 出口笔刷 self.exit_brush = QBrush(Qt.BDiagPattern) color = QColor(0, 255, 0, 130) self.exit_brush.setColor(color) self.exit_width = 2 # 2.2 绘制入口 # 2.2.1 入口选择框 self.select_entry = QRadioButton(self) self.select_entry.setText("入口. ") self.select_entry.setFont(QFont("Noto Sans CJK SC")) self.select_entry.toggled.connect(self.drawTypeChange) self.right_layout.addWidget(self.select_entry) # self.select_railing.setGeometry(1030, 65, 60, 30) # 2.2.2 入口笔刷 self.entry_brush = QBrush(Qt.DiagCrossPattern) color = QColor(0, 255, 0, 130) self.entry_brush.setColor(color) self.entry_width = 2 # 2.3 绘制出入口 # 2.3.1 出入口选择框 self.select_passage = QRadioButton(self) self.select_passage.setText("出入口. ") self.select_passage.setFont(QFont("Noto Sans CJK SC")) self.select_passage.toggled.connect(self.drawTypeChange) self.right_layout.addWidget(self.select_passage) # self.select_railing.setGeometry(1030, 65, 60, 30) # 2.3.2 出入口笔刷 self.passage_brush = QBrush(Qt.Dense6Pattern) color = QColor(0, 255, 0, 120) self.passage_brush.setColor(color) self.passage_width = 2 # 2.4 绘制休息区 # 2.4.1 休息区选择框 self.select_waiting = QRadioButton(self) self.select_waiting.setText("休息区. ") self.select_waiting.setFont(QFont("Noto Sans CJK SC")) self.select_waiting.toggled.connect(self.drawTypeChange) self.right_layout.addWidget(self.select_waiting) # self.select_railing.setGeometry(1030, 65, 60, 30) # 2.4.2 休息区笔刷 self.waiting_brush = QBrush(Qt.SolidPattern) color = QColor(0, 255, 0, 25) self.waiting_brush.setColor(color) self.right_layout.addStretch() # 3. 保存图片按键 self.save_button = QPushButton(self) self.save_button.setText("保存地图") self.save_button.setFont(QFont("Noto Sans CJK SC")) self.save_button.clicked.connect(self.saveMap) self.right_layout.addWidget(self.save_button) self.right_layout.addStretch() self.right_layout.addStretch() self.right_layout.addStretch() self.brush = self.railing_brush self.pen = self.obstacle_pen self.draw_type = "railing" self.width = self.railing_width self.setCentralWidget(self.splitter) self.setCentralWidget(self.splitter) self.splitter.setMouseTracking(True) self.setMouseTracking(True) self.image_label.setMouseTracking(True) self.image_label.installEventFilter(self) self.select_railing.setChecked(True) self.update() def saveMap(self): timenow = datetime.datetime.now() timestamp = datetime.datetime.strftime(timenow, '%Y-%m-%d_%H_%M_%S') filename = "./Maps/map_" + timestamp print(filename) pixmap = QPixmap.fromImage(self.image) pixmap.save(filename + "_map.bmp") pixmap1 = QPixmap.fromImage(self.hidden_obstacle_layer) pixmap1.save(filename + "_obs.bmp") pixmap2 = QPixmap.fromImage(self.hidden_destination_layer) pixmap2.save(filename + "_des.bmp") def widthChange(self): self.wall_width = int(self.wall_width_input.text()) self.pillar_width = int(self.pillar_width_input.text()) def drawTypeChange(self): if self.select_railing.isChecked(): #print("railing") self.brush = self.railing_brush self.draw_type = "railing" self.width = self.railing_width self.pen = self.obstacle_pen elif self.select_wall.isChecked(): #print("wall") self.brush = self.wall_brush self.draw_type = "wall" self.width = self.wall_width self.pen = self.obstacle_pen elif self.select_pillar.isChecked(): #print("pillar") self.brush = self.pillar_brush self.draw_type = "pillar" self.width = self.pillar_width self.pen = self.obstacle_pen elif self.select_counter.isChecked(): #print("counter") self.brush = self.counter_brush self.draw_type = "counter" self.width = self.counter_width self.pen = self.obstacle_pen elif self.select_exit.isChecked(): # print("exit") self.brush = self.exit_brush self.draw_type = "exit" self.width = self.exit_width self.pen = self.destination_pen elif self.select_entry.isChecked(): # print("entry") self.brush = self.entry_brush self.draw_type = "entry" self.width = self.entry_width self.pen = self.destination_pen elif self.select_passage.isChecked(): # print("passage") self.brush = self.passage_brush self.draw_type = "passage" self.width = self.passage_width self.pen = self.destination_pen elif self.select_waiting.isChecked(): # print("waiting") self.brush = self.waiting_brush self.draw_type = "waiting" self.pen = self.destination_pen def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = True self.startPoint = event.pos() self.lastPoint = event.pos() self.temp_image = self.image.copy() if self.draw_type == "railing" or self.draw_type == "wall" or self.draw_type == "pillar" or self.draw_type == "counter": self.temp_hidden_obstacle_layer = self.hidden_obstacle_layer.copy( ) else: self.temp_hidden_destination_layer = self.hidden_destination_layer.copy( ) self.draw_record.insert(0, self.draw_type) if self.draw_record.__len__() > self.maximum_undo + 2: self.draw_record.pop() #print(self.startPoint) if self.draw_type == "pillar": self.image = self.temp_image.copy() painter = QPainter(self.image) painter.setPen(self.obstacle_pen) painter.setBrush(self.pillar_brush) start = QPoint( self.startPoint.x() - (self.pillar_width * self.pix_per_meter) / 2 - 1, self.startPoint.y() - (self.pillar_width * self.pix_per_meter) / 2 - 1) end = QPoint( self.startPoint.x() + (self.pillar_width * self.pix_per_meter) / 2 - 1, self.startPoint.y() + (self.pillar_width * self.pix_per_meter) / 2 - 1) rect = QRect(start, end) painter.drawEllipse(rect) self.backup_image.insert(0, self.image) if self.backup_image.__len__() > self.maximum_undo + 2: self.backup_image.pop() ## self.hidden_obstacle_layer = self.temp_hidden_obstacle_layer.copy( ) painter1 = QPainter(self.hidden_obstacle_layer) painter1.setPen(self.hidden_pen) painter1.setBrush(self.hidden_pillar_brush) painter1.drawEllipse(rect) self.backup_hidden_obstacle.insert(0, self.hidden_obstacle_layer) if self.backup_hidden_obstacle.__len__( ) > self.maximum_undo + 2: self.backup_hidden_obstacle.pop() self.drawing = False self.update() def eventFilter(self, Object, event): if event.type() == QEvent.MouseMove: x = event.x() y = event.y() if 0 <= x < 1000 and 0 <= y < 500: x = x / 10.0 y = y / 10.0 message = "坐标: x = " + str(float( '%.1f' % x)) + ", \ty = " + str(float('%.1f' % y)) self.coordinates_disp.setText(message) return QWidget.eventFilter(self, Object, event) def mouseMoveEvent(self, event): # x = event.x() # y = event.y() # #if 0 <= x < 1000 and 0 <= y < 500: # x = x / 10.0 # y = y / 10.0 # message = "坐标: x = " + str(float('%.1f' % x)) + ", y = " + str(float('%.1f' % y)) # self.coordinates_disp.setText(message) if (event.buttons() and Qt.LeftButton) and self.drawing: self.lastPoint = event.pos() self.image = self.temp_image.copy() painter = QPainter(self.image) painter.setBrush(self.brush) painter.setPen(self.pen) if self.draw_type == "railing" or self.draw_type == "wall" or self.draw_type == "pillar" or self.draw_type == "counter": self.hidden_obstacle_layer = self.temp_hidden_obstacle_layer.copy( ) painter1 = QPainter(self.hidden_obstacle_layer) if self.draw_type == "railing": painter1.setBrush(self.hidden_railing_brush) elif self.draw_type == "wall": painter1.setBrush(self.hidden_wall_brush) elif self.draw_type == "pillar": painter1.setBrush(self.hidden_pillar_brush) elif self.draw_type == "counter": painter1.setBrush(self.hidden_counter_brush) painter1.setPen(self.hidden_pen) else: self.hidden_destination_layer = self.temp_hidden_destination_layer.copy( ) painter1 = QPainter(self.hidden_destination_layer) if self.draw_type == "exit": painter1.setBrush(self.hidden_exit_brush) elif self.draw_type == "entry": painter1.setBrush(self.hidden_entry_brush) elif self.draw_type == "passage": painter1.setBrush(self.hidden_passage_brush) elif self.draw_type == "waiting": painter1.setBrush(self.hidden_waiting_brush) painter1.setPen(self.hidden_pen) w = self.width * self.pix_per_meter startx = self.startPoint.x() starty = self.startPoint.y() endx = self.lastPoint.x() endy = self.lastPoint.y() if self.shift_pressed == False and self.draw_type != "waiting": degree, length = self.get_degree(self.startPoint, self.lastPoint) painter.translate(self.startPoint) painter.rotate(degree) painter1.translate(self.startPoint) painter1.rotate(degree) start = QPoint(0, 0) end = QPoint(length, w) # if self.draw_type == "counter": # if abs(starty - endy) >= abs(startx - endx): # print("no shift, ver pattern") # temp_brush = self.brush # temp_brush.setStyle(Qt.HorPattern) # painter.setBrush(temp_brush) # else: # print("no shift, hor pattern") # temp_brush = self.brush # temp_brush.setStyle(Qt.HorPattern) # painter.setBrush(temp_brush) painter.drawRect(QRect(start, end)) painter1.drawRect(QRect(start, end)) elif self.shift_pressed == True and self.draw_type != "waiting": if abs(starty - endy) >= abs(startx - endx): if self.draw_type == "counter": temp_brush = self.brush temp_brush.setStyle(Qt.VerPattern) painter.setBrush(temp_brush) if startx < endx: painter.drawRect( QRect(QPoint(startx, starty), QPoint(startx + w, endy))) painter1.drawRect( QRect(QPoint(startx, starty), QPoint(startx + w, endy))) else: painter.drawRect( QRect(QPoint(startx, starty), QPoint(startx - w - 2, endy))) painter1.drawRect( QRect(QPoint(startx, starty), QPoint(startx - w - 2, endy))) else: if self.draw_type == "counter": temp_brush = self.brush temp_brush.setStyle(Qt.HorPattern) painter.setBrush(temp_brush) if starty < endy: painter.drawRect( QRect(QPoint(startx, starty), QPoint(endx, starty + w))) painter1.drawRect( QRect(QPoint(startx, starty), QPoint(endx, starty + w))) else: painter.drawRect( QRect(QPoint(startx, starty), QPoint(endx, starty - w - 2))) painter1.drawRect( QRect(QPoint(startx, starty), QPoint(endx, starty - w - 2))) else: painter.drawRect(QRect(self.startPoint, self.lastPoint)) painter1.drawRect(QRect(self.startPoint, self.lastPoint)) def get_degree(self, start, end): startx = start.x() starty = start.y() endx = end.x() endy = end.y() if endx >= startx: if endx == startx: if endy > starty: degree = 90 else: degree = 270 else: degree = math.atan( (endy - starty + 0.0) / (endx - startx + 0.0)) degree = (degree / 3.14) * 180 else: degree = math.atan((endy - starty + 0.0) / (startx - endx + 0.0)) degree = (degree / 3.14) * 180 degree = 180 - degree length = math.sqrt((startx - endx) * (startx - endx) + (starty - endy) * (starty - endy)) return degree, length def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: if self.draw_type != "pillar": self.drawing = False self.backup_image.insert(0, self.image) if self.backup_image.__len__() > self.maximum_undo + 2: self.backup_image.pop() if self.draw_type == "railing" or self.draw_type == "wall" or self.draw_type == "pillar" or self.draw_type == "counter": self.backup_hidden_obstacle.insert( 0, self.hidden_obstacle_layer) if self.backup_hidden_obstacle.__len__( ) > self.maximum_undo + 2: self.backup_hidden_obstacle.pop() else: self.backup_hidden_destination.insert( 0, self.hidden_destination_layer) if self.backup_hidden_destination.__len__( ) > self.maximum_undo + 2: self.backup_hidden_destination.pop() def keyPressEvent(self, event): if event.key() == Qt.Key_Z: self.undo() elif event.modifiers() == Qt.ShiftModifier: self.shift_pressed = True elif event.key() == Qt.Key_1: self.wall_width_input.setText("1") self.wall_width = 1 self.pillar_width_input.setText("1") self.pillar_width = 1 elif event.key() == Qt.Key_2: self.wall_width_input.setText("2") self.wall_width = 2 self.pillar_width_input.setText("2") self.pillar_width = 2 elif event.key() == Qt.Key_3: self.wall_width_input.setText("3") self.wall_width = 3 self.pillar_width_input.setText("3") self.pillar_width = 3 elif event.key() == Qt.Key_4: self.wall_width_input.setText("4") self.wall_width = 4 self.pillar_width_input.setText("4") self.pillar_width = 4 elif event.key() == Qt.Key_5: self.wall_width_input.setText("5") self.wall_width = 5 self.pillar_width_input.setText("5") self.pillar_width = 5 elif event.key() == Qt.Key_6: self.wall_width_input.setText("6") self.wall_width = 6 self.pillar_width_input.setText("6") self.pillar_width = 6 elif event.key() == Qt.Key_7: self.wall_width_input.setText("7") self.wall_width = 7 self.pillar_width_input.setText("7") self.pillar_width = 7 elif event.key() == Qt.Key_8: self.wall_width_input.setText("8") self.wall_width = 8 self.pillar_width_input.setText("8") self.pillar_width = 8 elif event.key() == Qt.Key_9: self.wall_width_input.setText("9") self.wall_width = 9 self.pillar_width_input.setText("9") self.pillar_width = 9 elif event.key() == Qt.Key_0: self.wall_width_input.setText("10") self.wall_width = 10 self.pillar_width_input.setText("10") self.pillar_width = 10 self.drawTypeChange() def undo(self): if self.backup_image.__len__() > 1: #print(self.backup_image.__len__()) self.image = self.backup_image[1] self.backup_image.pop(0) self.update() if self.draw_record[0] == "railing" or self.draw_record[ 0] == "wall" or self.draw_record[ 0] == "pillar" or self.draw_record[0] == "counter": if self.backup_hidden_obstacle.__len__() > 1: print(self.backup_hidden_obstacle.__len__()) self.hidden_obstacle_layer = self.backup_hidden_obstacle[1] self.backup_hidden_obstacle.pop(0) self.update() else: if self.backup_hidden_destination.__len__() > 1: print(self.backup_hidden_destination.__len__()) self.hidden_destination_layer = self.backup_hidden_destination[ 1] self.backup_hidden_destination.pop(0) self.update() self.draw_record.pop(0) def keyReleaseEvent(self, event): if event.key() == Qt.Key_Shift: self.shift_pressed = False def paintEvent(self, event): self.image_label.setPixmap(QPixmap.fromImage(self.image))
class Settings(object): l = logging.getLogger('Settings') def __init__(self, fileName = 'shadow.ini'): self.fileName = fileName self.tzIdx = 0 self.mainWindowSize = QSize(1200, 700) self.mainWindowPos = QPoint(240, 200) def load(self): self.l.debug('Loading local settings from {}'.format(self.fileName)) config = configparser.ConfigParser() config.read(self.fileName) if config.has_section('common'): commonSettings = config['common'] self.tzIdx = int(commonSettings.get('tz', 0)) # load main window position and size if config.has_section('mainWindow'): windowSettings = config['mainWindow'] # read position pos = windowSettings.get('pos', '{},{}'.format(self.mainWindowPos.x(), self.mainWindowPos.y())).split(',') self.mainWindowPos = QPoint(int(pos[0]), int(pos[1])) # read size size = windowSettings.get('size', '{},{}'.format(self.mainWindowSize.width(), self.mainWindowSize.height())).split(',') self.mainWindowSize = QSize(int(size[0]), int(size[1])) def dump(self, channel): self.l.debug('Saving local settings ...') config = configparser.ConfigParser() config.add_section('common') config.set('common', 'tz', str(self.tzIdx)) config.add_section('mainWindow') config.set('mainWindow', 'pos', '{},{}'.format(self.mainWindowPos.x(), self.mainWindowPos.y())) config.set('mainWindow', 'size', '{},{}'.format(self.mainWindowSize.width(), self.mainWindowSize.height())) config.write(channel) def save(self): with open(self.fileName, 'w') as configfile: self.dump(configfile) def setMainWindowPos(self, pos): self.mainWindowPos = pos def setMainWindowSize(self, size): self.mainWindowSize = size def getMainWindowPos(self): return self.mainWindowPos def getMainWindowSize(self): return self.mainWindowSize def getTzIndex(self): return self.tzIdx def setTzIdx(self, idx): self.tzIdx = idx
class ImgViewer(QWidget, Ui_ImgViewerWindow): def __init__(self, parentWindow): super(ImgViewer, self).__init__() self.ui = Ui_ImgViewerWindow() self.ui.setupUi(self) self.parentWindow = parentWindow self.setWindowTitle('loading file, please wait ....') self.ui.left_PushButton.setFlat(True) self.ui.right_PushButton.setFlat(True) self.ui.left_PushButton.clicked.connect(self.previousImg) self.ui.right_PushButton.clicked.connect(self.nextImg) self.left_click = False self.flipRGB = False def setFileList(self, filelist, YUVFormat, W, H, startframe, totalframe): # 获取该格式的解码函数 decoder = YUVdecoder_dict.get(YUVFormat) if decoder is None: # 未能成功获取则返回无法解码 return False # 成功获取解码器则准备解码 # 定义空列表 self.img_list = [] self.ui.imgViewer.setText('') self.filelist = [] # 遍历文件列表 for filename in filelist: try: # 使用获取的解码函数进行解码得到RGB的原始帧列表 frame_RGB_list = decoder(filename, W, H, startframe, totalframe) except Exception as e: continue # 定义img列表用来保存每一帧的QPixmap img_RGB_list = [] # 将原始帧转换到QPixmap并保存到img列表 for img in frame_RGB_list: # 提取图像的通道和尺寸,用于将OpenCV下的image转换成Qimage height, width, channel = img.shape bytesPerline = 3 * width qImg = QImage(img.data, width, height, bytesPerline, QImage.Format_RGB888).rgbSwapped() img_RGB_list.append(qImg) # img_RGB_list以及文件名存入列表 self.img_list.append(img_RGB_list) self.filelist.append(os.path.split(filename)[1]) #设置显示第一个YUV文件的第一帧图像 self.currentImg_RGB_list = self.img_list[0] self.currentImg = self.currentImg_RGB_list[0] self.setWindowTitle(self.filelist[0] + '-' + str(0)) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.point = QPoint(0, 0) return True def reciveimgdata(self, img_RGB_list, filename): if not img_RGB_list == []: # img_RGB_list以及文件名存入列表 self.img_list.append(img_RGB_list) self.filelist.append(os.path.split(filename)[1]) if len(self.img_list) == 1: # 设置显示第一个YUV文件的第一帧图像 self.ui.imgViewer.setText('') self.currentImg_RGB_list = self.img_list[0] self.currentImg = self.currentImg_RGB_list[0] self.setWindowTitle(self.filelist[0] + '-' + str(0)) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.point = QPoint(0, 0) self.repaint() self.decode_thread_finsh.append(self.decode_thread.pop(0)) if len(self.decode_thread) > 0: self.decode_thread[0].start() else: if len(self.img_list) == 0: QMessageBox.critical(self.parentWindow, 'Error', 'unknow error!!', QMessageBox.Ok) self.close() def setFileList_multithreading(self, filelist, YUVFormat, W, H, startframe, totalframe): # 获取该格式的解码函数 decoder = YUVdecoder_dict.get(YUVFormat) if decoder is None: # 未能成功获取则返回无法解码 return False # 定义空列表 self.img_list = [] self.filelist = [] self.decode_thread = [] self.decode_thread_finsh = [] # 遍历文件列表 for filename in filelist: decodeThread = YUVDecodeThread(self, filename, YUVFormat, W, H, startframe, totalframe) decodeThread.finsh_signal.connect(self.reciveimgdata) self.decode_thread.append(decodeThread) self.decode_thread[0].start() return True def closeEvent(self, event): self.parentWindow.show() event.accept() def draw_img(self, painter): painter.drawPixmap(self.point, QPixmap.fromImage(self.scaled_img)) def paintEvent(self, e): if not len(self.img_list) == 0: painter = QPainter() painter.begin(self) self.draw_img(painter) painter.end() def mouseMoveEvent(self, e): if not len(self.img_list) == 0: if self.left_click: self._endPos = e.pos() - self._startPos self.point = self.point + self._endPos self._startPos = e.pos() self.repaint() def mousePressEvent(self, e): if not len(self.img_list) == 0: if e.button() == Qt.LeftButton: self.left_click = True self._startPos = e.pos() def mouseReleaseEvent(self, e): if not len(self.img_list) == 0: if e.button() == Qt.LeftButton: self.left_click = False elif e.button() == Qt.RightButton: self.point = QPoint(0, 0) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.repaint() elif e.button() == Qt.MiddleButton: self.scaled_img = self.currentImg.scaled( self.currentImg.width(), self.scaled_img.height()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.point = QPoint(0, 0) self.repaint() def mouseDoubleClickEvent(self, event): if not len(self.img_list) == 0: if event.buttons() == Qt.LeftButton: list_index = self.img_list.index(self.currentImg_RGB_list) img_RGB_list = self.img_list[list_index] img_index = img_RGB_list.index(self.currentImg) savefile_name = QFileDialog.getSaveFileName( self, '保存文件', self.filelist[list_index].replace('.yuv', '-') + str(img_index) + '.png', 'Image files(*.png)') if savefile_name[0]: self.currentImg.save(savefile_name[0]) elif event.buttons() == Qt.RightButton: self.flipRGB = False if self.flipRGB else True self.point = QPoint(0, 0) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.repaint() def wheelEvent(self, e): if not len(self.img_list) == 0: if e.angleDelta().y() > 0: # 放大图片 if not self.scaled_img.width( ) == 0 and not self.scaled_img.height() == 0: setpsize_x = self.scaled_img.width() / 16 setpsize_y = self.scaled_img.height() / 16 #缩放可能导致比例不精确 self.scaled_img = self.currentImg.scaled( self.scaled_img.width() + setpsize_x, self.scaled_img.height() + setpsize_y) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() new_w = e.x() - (self.scaled_img.width() * (e.x() - self.point.x())) / ( self.scaled_img.width() - setpsize_x) new_h = e.y() - (self.scaled_img.height() * (e.y() - self.point.y())) / ( self.scaled_img.height() - setpsize_y) self.point = QPoint(new_w, new_h) self.repaint() elif e.angleDelta().y() < 0: # 缩小图片 if self.scaled_img.width() > 25 and self.scaled_img.width( ) > 25: setpsize_x = self.scaled_img.width() / 16 setpsize_y = self.scaled_img.height() / 16 #缩放可能导致比例不精确 self.scaled_img = self.currentImg.scaled( self.scaled_img.width() - setpsize_x, self.scaled_img.height() - setpsize_y) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() new_w = e.x() - (self.scaled_img.width() * (e.x() - self.point.x())) / ( self.scaled_img.width() + setpsize_x) new_h = e.y() - (self.scaled_img.height() * (e.y() - self.point.y())) / ( self.scaled_img.height() + setpsize_y) self.point = QPoint(new_w, new_h) self.repaint() def resizeEvent(self, e): if not len(self.img_list) == 0: if self.parent is not None: self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.point = QPoint(0, 0) self.update() def previousImg(self): if not len(self.img_list) == 0: #得到当前显示的文件序号 list_index = self.img_list.index(self.currentImg_RGB_list) img_RGB_list = self.img_list[list_index] #得到当前显示的图像是文件的帧序号 img_index = img_RGB_list.index(self.currentImg) #判断当前是否是第一帧 if img_index == 0: #如果当前是第一帧,则判断当前是否是第一个文件 if list_index == 0: #如果是第一个文件则文件序号更新代到最后一个序号 list_index = len(self.img_list) - 1 else: #否则文件序号更新到前一个文件序号 list_index -= 1 #更新帧序号为文件的最后一帧序号 img_index = len(self.img_list[list_index]) - 1 else: #否则更新帧序号为前一帧序号,此时文件序号不用更新 img_index -= 1 #序号更新完成,代入序号配置当前显示的页面 self.setWindowTitle(self.filelist[list_index] + '-' + str(img_index)) self.currentImg_RGB_list = self.img_list[list_index] self.currentImg = self.currentImg_RGB_list[img_index] self.point = QPoint(0, 0) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.repaint() def nextImg(self): if not len(self.img_list) == 0: # 得到当前显示的文件序号 list_index = self.img_list.index(self.currentImg_RGB_list) img_RGB_list = self.img_list[list_index] # 得到当前显示的图像是文件的帧序号 img_index = img_RGB_list.index(self.currentImg) # 判断当前是否是最后一帧 if img_index == len(img_RGB_list) - 1: # 如果当前是最后一帧,则判断当前是否是最后一个文件 if list_index == len(self.img_list) - 1: # 如果是最后一个文件则文件序号更新代到第一个序号 list_index = 0 else: # 否则文件序号更新到后一个文件序号 list_index += 1 # 更新帧序号为文件的第一帧序号 img_index = 0 else: # 否则更新帧序号为后一帧序号,此时文件序号不用更新 img_index += 1 # 序号更新完成,代入序号配置当前显示的页面 self.setWindowTitle(self.filelist[list_index] + '-' + str(img_index)) self.currentImg_RGB_list = self.img_list[list_index] self.currentImg = self.currentImg_RGB_list[img_index] self.point = QPoint(0, 0) self.scaled_img = self.currentImg.scaled(self.size()) if self.flipRGB: self.scaled_img = self.scaled_img.rgbSwapped() self.repaint()
def paintEvent(self, event): painter = QPainter(self) painter.setPen(self.pen) painter.setBrush(self.brush) if self.antialiased: painter.setRenderHint(QPainter.Antialiasing) angle_step = 360 / self.n_states painter.save() #Save_1. Save the state of the system (push matrix) painter.translate(self.dist_center.x(), self.dist_center.y()) # go to the center of the render area painter.rotate(-180) #to start painting from the left side of the circle (clockwise) #center of the circumference where through we are going to paint our states x = self.dist_radius * math.cos(0) y = self.dist_radius * math.sin(0) for h in range(self.n_states): rot = angle_step * h # each state is equidistant from the others. We paint them in circles painter.save() #Save_2 painter.rotate(rot) #now our system is pointing to the next state to be drawn painter.translate(x,y) #now our origin is in the center of the next state to be drawn #if the state is active, fill it green if self.machine.getState(h).isActive(): painter.setBrush(self.greenGradientBrush) painter.drawEllipse(QPoint(0,0), self.state_radius, self.state_radius) #draw the new state #global position of transformed coordinates (before any transformation, origin at top-left corner) gx = painter.worldTransform().map(QPoint(0,0)).x() gy = painter.worldTransform().map(QPoint(0,0)).y() self.machine.getState(h).setPos(gx, gy) #store the center of the state without any transformation applied # text transformation. Our origin is still in the center of the current state painter.save() #Save_3 painter.rotate(180) #making the text go vertical painter.rotate(-rot) #undoing the rotation made for painting the state. No the text is horizontal font = painter.font(); font.setPixelSize(self.state_radius*.4); painter.setFont(font); rect = QRect(-self.state_radius, -self.state_radius, self.state_radius*2, self.state_radius*2) painter.drawText(rect, Qt.AlignCenter, self.machine.getState(h).getName()); painter.restore() #Restore_3 #end text transformation painter.restore() #Restore_2 painter.restore() #Restore_1. Restore the state of the system (pop matrix) #drawing transitions. Line between states painter.save() # Save_4 pptv = QTransform() #Define a new transformation. Needed to rotate the system along other axis than Z pptv.translate(0, self.height()) #We are now at the bottom-left corner of the screen pptv.rotate(-180, Qt.XAxis) #Rotate along the X-axis so now we are in a typical cartesian system. painter.setTransform(pptv) #Apply the transformation states = self.machine.getStates() for state in states: transitions = state.getTransitions() for transition in transitions: #get the center of the origin and destination states in our current system state orig = QPoint(state.getPos()[0], state.getPos()[1]) end = QPoint(self.machine.getState(transition.getStateEnd()).getPos()[0], self.machine.getState(transition.getStateEnd()).getPos()[1]) # get those coordinates without transformation orig2 = QPoint(painter.worldTransform().map(orig)) end2 = QPoint(painter.worldTransform().map(end)) #get the angle between states centers and the horizon angle = math.atan2(end2.y() - orig2.y(), end2.x() - orig2.x()) #get the coordinates of the starting point of the transition (it starts in the bound of the state, not in the center) newX = self.state_radius * math.cos(angle) + orig2.x() newY = self.state_radius * math.sin(angle) + orig2.y() #now the transition starts at the border, not in the center orig2.setX(newX) orig2.setY(newY) #same for the destination state angle2 = math.atan2(orig2.y() - end2.y(), orig2.x() - end2.x()) newX2 = self.state_radius * math.cos(angle2) + end2.x() newY2 = self.state_radius * math.sin(angle2) + end2.y() end2.setX(newX2) end2.setY(newY2) #draw the line between the origin and destination states painter.drawLine(orig2, end2) #get the start and the end of the transition untransformed init = QPoint(painter.worldTransform().map(orig2)) end = QPoint(painter.worldTransform().map(end2)) #store that info transition.setOrig(init.x(), init.y()) transition.setDest(end.x(), end.y()) transition.setAngle(angle) painter.restore() #Restore_4 #Appliying style to the transitions painter.setPen(QPen(QColor(Qt.gray), 3)) for state in self.machine.getStates(): for transition in state.getTransitions(): #get the start and end coordinates of the transition i = QPoint(transition.getOrig()[0], transition.getOrig()[1]) o = QPoint(transition.getDest()[0], transition.getDest()[1]) painter.drawPolyline(i, o) #Drawing the arrow at the end of the transition painter.save() #Save_5 painter.setPen(QPen(QColor(Qt.gray), 2)) painter.translate(transition.getDest()[0],transition.getDest()[1]) #Go to the end of the transition painter.rotate(90 - transition.getAngle()*180/math.pi) #Rotate to point in the direction of the transition #coordinates of the arrow (triangle) a = QPoint(0,0) b = QPoint(-5,10) c = QPoint(5,10) #coordinates of the arrow untransformed a1 = painter.worldTransform().map(a) b1 = painter.worldTransform().map(b) c1 = painter.worldTransform().map(c) #Drawin the actual arrow pointer = QPolygon([a,b,c]) painter.drawPolygon(pointer) painter.restore() #Restore_5 #For the animation of the transition painter.save() #Save_6 if transition.isActive(): #if the current transition is the active one the wave function will be running, so it's updating the canvas painter.setPen(QPen(QColor(Qt.green), 3)) painter.drawPolyline(i,o) painter.setPen(QPen(QColor(Qt.gray), 3)) painter.drawPolyline(self.poly(self.pts)) #Draw the arrow in the active state (red arrow) painter.setBrush(QBrush(QColor(255, 0, 0))) painter.setPen(QPen(QColor(Qt.red), 2)) pointer = QPolygon([a1,b1,c1]) painter.drawPolygon(pointer) #Ball that follows the line animation for x, y in self.pts: painter.drawEllipse(QRectF(self.pts[0][0] - 4, self.pts[0][1] - 4, 8, 8)) painter.restore() #Restore_6 #Painting the text of the transition painter.save() #Save_7 pptv = QTransform() painter.setPen(QPen(QColor(Qt.black), 3)) #get the middle point of the transition middleX = (transition.getOrig()[0] + transition.getDest()[0]) /2 middleY = (transition.getOrig()[1] + transition.getDest()[1]) /2 pptv.translate(middleX, middleY) #translate to that point painter.setTransform(pptv) #apply the transformation font = painter.font(); font.setPixelSize(self.state_radius*.2); painter.setFont(font); rect = QRect(-self.state_radius, -self.state_radius, self.state_radius*2, self.state_radius*2) name = str(transition.getId())+ '. ' + transition.getName() painter.drawText(rect, Qt.AlignCenter, name) painter.restore() #Restore_7 #paint the actual canvas painter.setPen(self.palette().dark().color()) painter.setBrush(Qt.NoBrush) painter.drawRect(QRect(0, 0, self.width() - 1, self.height() - 1))
def screenToTileCoords(self, x, y): p = RenderParams(self.map()) if (p.staggerX): if p.staggerEven: x -= p.tileWidth else: x -= p.sideOffsetX else: if p.staggerEven: y -= p.tileHeight else: y -= p.sideOffsetY # Start with the coordinates of a grid-aligned tile lenx = p.tileWidth + p.sideLengthX leny = p.tileHeight + p.sideLengthY referencePoint = QPoint(math.floor(x / lenx), math.floor(y / leny)) # Relative x and y position on the base square of the grid-aligned tile rel = QVector2D(x - referencePoint.x() * lenx, y - referencePoint.y() * leny) # Adjust the reference point to the correct tile coordinates if p.staggerX: staggerAxisIndex = referencePoint.x() else: staggerAxisIndex = referencePoint.y() staggerAxisIndex *= 2 if (p.staggerEven): staggerAxisIndex += 1 if p.staggerX: referencePoint.setX(staggerAxisIndex) else: referencePoint.setY(staggerAxisIndex) # Determine the nearest hexagon tile by the distance to the center centers = [0, 0, 0, 0] if (p.staggerX): left = int(p.sideLengthX / 2) centerX = left + p.columnWidth centerY = int(p.tileHeight / 2) centers[0] = QVector2D(left, centerY) centers[1] = QVector2D(centerX, centerY - p.rowHeight) centers[2] = QVector2D(centerX, centerY + p.rowHeight) centers[3] = QVector2D(centerX + p.columnWidth, centerY) else: top = int(p.sideLengthY / 2) centerX = int(p.tileWidth / 2) centerY = top + p.rowHeight centers[0] = QVector2D(centerX, top) centers[1] = QVector2D(centerX - p.columnWidth, centerY) centers[2] = QVector2D(centerX + p.columnWidth, centerY) centers[3] = QVector2D(centerX, centerY + p.rowHeight) nearest = 0 minDist = 1.7976931348623157e+308 for i in range(4): center = centers[i] dc = (center - rel).lengthSquared() if (dc < minDist): minDist = dc nearest = i offsetsStaggerX = [ QPoint(0, 0), QPoint(+1, -1), QPoint(+1, 0), QPoint(+2, 0), ] offsetsStaggerY = [ QPoint(0, 0), QPoint(-1, +1), QPoint(0, +1), QPoint(0, +2), ] if p.staggerX: offsets = offsetsStaggerX else: offsets = offsetsStaggerY return QPointF(referencePoint + offsets[nearest])
def _incline_line(self, path: QtGui.QPainterPath, point1: QtCore.QPoint, point2: QtCore.QPoint, span_left: list, span_right: list): #绘制站间的斜线 #TODO 暂未考虑直接跨过无定义区域的情况 width = self.graphWidget.scene.width() - \ self.graphWidget.margins["left"] - self.graphWidget.margins["right"] if point1.inRange and point2.inRange: if point1.x() <= point2.x(): path.lineTo(point2) else: # 跨界运行线 dx = point2.x() - point1.x() + width dy = point2.y() - point1.y() ax = width + self.graphWidget.margins["left"] - point1.x() h = ax * dy / dx span_right.append(point1.y() + h) span_left.append(point1.y() + h) path.lineTo(self.graphWidget.margins["left"] + width, point1.y() + h) path.moveTo(self.graphWidget.margins["left"], point1.y() + h) path.lineTo(point2) elif not point1.inRange and not point2.inRange: return elif point1.inRange: #右侧点越界 dx = point2.x() - point1.x() + width dy = point2.y() - point1.y() ax = width + self.graphWidget.margins["left"] - point1.x() h = ax * dy / dx span_right.append(point1.y() + h) path.lineTo(self.graphWidget.margins["left"] + width, point1.y() + h) else: #左侧点越界 dx = point2.x() - point1.x() + width dy = point2.y() - point1.y() ax = width + self.graphWidget.margins["left"] - point1.x() h = ax * dy / dx span_left.append(point1.y() + h) path.moveTo(self.graphWidget.margins["left"], point1.y() + h) path.lineTo(point2)
class Example(QWidget): overlay: QImage #Overlay(Накладываем) Picture on Window timer: QTimer #Timet init painter: QPainter Colors: list arr_points: list DeltaX: int DeltaY: int SelfHeight: int LastAngle: int Size: list LastMousePosition: QPoint def __init__(self): super().__init__() self.initUI() def keyPressEvent(self, event): if event.key() == 16777216: self.FileSaving(FILE_NAME) sys.exit() #Programm Closing def GetStationPopularity(self, station_name, trends_object): kw_list = station_name trends_object.build_payload(kw_list, cat=0, timeframe='today 5-y', geo='', gprop='') interest = trends_object.interest_over_time() return interest.mean() #plt.plot(interest[station_name]) #plt.show() def mousePressEvent(self, event): mousePoint = event.pos() self.LastMousePosition = mousePoint if event.button() == 2: WindowW = self.frameGeometry().width() # WindowSize WindowH = self.frameGeometry().height() # WindowSize imgH = self.overlay.height() # Original Picture Size imgW = self.overlay.width() # Original Picture Size img = self.overlay.scaledToHeight(self.SelfHeight, Qt.FastTransformation) #AdjX = (WindowW-img.width())/2 ResultX = imgW * (mousePoint.x() - self.DeltaX) / img.width() ResultY = imgH / 100 * ((mousePoint.y() - self.DeltaY) / (self.SelfHeight / 100)) #eraser = 7 self.painter.drawEllipse(QPoint(ResultX, ResultY), RADIUS, RADIUS) #self.painter.eraseRect(QRect(QPoint(ResultX-RADIUS/2-eraser, ResultY-RADIUS/2-eraser), QPoint(ResultX+radius/2+eraser, ResultY+radius/2+eraser))) self.arr_points.append((ResultX, ResultY)) #print([(round(x[0]), round(x[1])) for x in self.arr_points]) self.update() #Redraw def FileSaving(self, fileName: str): with open(fileName, 'w') as f: for item in self.arr_points: f.write(';'.join(str(x) for x in item) + '\n') f.close() def NameReading(self, fileName: str): with open(fileName, 'r') as f: names = f.read().split('\n') f.close() #print(names) return names def FileDrawing(self, fileName: str): penLine = QPen(QColor(Qt.red)) penLine.setWidth(10) #my_file = Path('!StationsLine12.txt') #print(my_file.isfile()) for n in range(1): penEllipse = QPen(self.Colors[int(n / 2)]) penEllipse.setWidth(5) data = [] path = fileName + str(n / 2 + 1) + '.txt' my_file = Path(path) #print(os.listdir()) if my_file.is_file(): with open(fileName + str(n / 2 + 1) + '.txt', 'r') as f: data = f.read().split('\n') f.close() lastX = None lastY = None Point1 = None Point2 = None Startlen = None x = 0 y = 0 i = 0 #print(self.NameReading('!Stations.txt')) for line in data: x, y = line.split(';') #if lastX is not None or lastY is not None: self.painter.setPen(penLine) #Point1 = QPoint(lastX, lastY) #Point2 = QPoint(float(x), float(y)) #self.painter.drawLine(Point1, Point2) self.painter.setPen(penEllipse) penLine = QPen(QColor(Qt.red)) self.painter.setBrush(QColor(Qt.white)) self.painter.drawEllipse( float(x) - RADIUS / 100 * self.Size[i], float(y) - RADIUS / 100 * self.Size[i], (RADIUS / 100 * self.Size[i]) * 2, (RADIUS / 100 * self.Size[i]) * 2) i += 1 def mouseReleaseEvent(self, event): self.point = None def closeEvent(self, event): #self.FileSaving(FILE_NAME) sys.exit() #Programm Closing def initUI(self): self.Colors = [ QColor(228, 37, 24), #1 QColor(75, 175, 79), #2 QColor(5, 114, 185), #3 QColor(36, 188, 239), #4 QColor(146, 82, 51), #5 QColor(239, 128, 39), #6 QColor(148, 63, 144), #7 QColor(255, 209, 30), #8 QColor(173, 172, 172), #9 QColor(185, 206, 31), #10 QColor(134, 204, 206), #11 QColor(186, 200, 232), #12 QColor(68, 143, 201), #13 QColor(232, 68, 57), #14 ] self.pytrends = TrendReq(hl='en-US', tz=360) stationsName = self.NameReading('!Stations.txt') #print(stationsName[0:5]) self.Size = self.GetStationPopularity(stationsName[0:5], self.pytrends) #print(self.Size) print(list(self.Size)) self.showMaximized() #self.showNormal() self.arr_points = [] self.LastAngle = 0 self.timer = QTimer() #Timer init self.timer.timeout.connect(self.update) # Timer init self.setWindowTitle('Moscow Metro Map Poppularity') # Title self.point = None self.DeltaX = 0 self.DeltaY = 0 self.SelfHeight = self.frameGeometry().height() self.LastMousePosition = QPoint(0, 0) self.overlay = QImage() self.overlay.load('Moscow Metro Map Stations Popularity\\MainMap.bmp') pen = QPen(QColor(Qt.red)) pen.setWidth(5) self.painter = QPainter(self.overlay) self.painter.setPen(pen) self.painter.Antialiasing = True self.timer.start(1000 / 50) #50 кадров в секунду self.FileDrawing(FILE_NAME) def paintEvent(self, event): painter = QPainter() painter.begin(self) #windowsWidth = self.frameGeometry().width() windowsHeight = self.frameGeometry().height() img = self.overlay.scaledToHeight(self.SelfHeight, 0) painter.drawImage(self.DeltaX, self.DeltaY, img) painter.end() del painter def mouseMoveEvent(self, event): CurentPos = event.pos() self.DeltaX -= self.LastMousePosition.x() - CurentPos.x() self.DeltaY -= self.LastMousePosition.y() - CurentPos.y() #self.LastMousePosition = mousePoint self.LastMousePosition = event.pos() def wheelEvent(self, event): #print(str(event.angleDelta())) self.SelfHeight += (event.angleDelta().y()) / 10 self.LastAngle = event.angleDelta().y() def resizeEvent(self, event): self.SelfHeight = self.frameGeometry().height()
class GLWidget(QOpenGLWidget): def __init__(self, parent=None): super(GLWidget, self).__init__(parent) midnight = QTime(0, 0, 0) random.seed(midnight.secsTo(QTime.currentTime())) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.image = QImage() self.bubbles = [] self.lastPos = QPoint() self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) self.animationTimer = QTimer() self.animationTimer.setSingleShot(False) self.animationTimer.timeout.connect(self.animate) self.animationTimer.start(25) self.setAutoFillBackground(False) self.setMinimumSize(200, 200) self.setWindowTitle("Overpainting a Scene") def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle def initializeGL(self): self.gl = self.context().versionFunctions() self.gl.initializeOpenGLFunctions() self.object = self.makeObject() def mousePressEvent(self, event): self.lastPos = event.pos() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() def paintEvent(self, event): self.makeCurrent() self.gl.glMatrixMode(self.gl.GL_MODELVIEW) self.gl.glPushMatrix() self.setClearColor(self.trolltechPurple.darker()) self.gl.glShadeModel(self.gl.GL_SMOOTH) self.gl.glEnable(self.gl.GL_DEPTH_TEST) #self.gl.glEnable(self.gl.GL_CULL_FACE) self.gl.glEnable(self.gl.GL_LIGHTING) self.gl.glEnable(self.gl.GL_LIGHT0) self.gl.glEnable(self.gl.GL_MULTISAMPLE) self.gl.glLightfv(self.gl.GL_LIGHT0, self.gl.GL_POSITION, (0.5, 5.0, 7.0, 1.0)) self.setupViewport(self.width(), self.height()) self.gl.glClear( self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.gl.glLoadIdentity() self.gl.glTranslated(0.0, 0.0, -10.0) self.gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) self.gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) self.gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) self.gl.glCallList(self.object) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) self.gl.glPopMatrix() painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) for bubble in self.bubbles: if bubble.rect().intersects(QRectF(event.rect())): bubble.drawBubble(painter) self.drawInstructions(painter) painter.end() def resizeGL(self, width, height): self.setupViewport(width, height) def showEvent(self, event): self.createBubbles(20 - len(self.bubbles)) def sizeHint(self): return QSize(400, 400) def makeObject(self): list = self.gl.glGenLists(1) self.gl.glNewList(list, self.gl.GL_COMPILE) self.gl.glEnable(self.gl.GL_NORMALIZE) self.gl.glBegin(self.gl.GL_QUADS) self.gl.glMaterialfv(self.gl.GL_FRONT, self.gl.GL_DIFFUSE, (self.trolltechGreen.red()/255.0, self.trolltechGreen.green()/255.0, self.trolltechGreen.blue()/255.0, 1.0)) x1 = +0.06 y1 = -0.14 x2 = +0.14 y2 = -0.06 x3 = +0.08 y3 = +0.00 x4 = +0.30 y4 = +0.22 self.quad(x1, y1, x2, y2, y2, x2, y1, x1) self.quad(x3, y3, x4, y4, y4, x4, y3, x3) self.extrude(x1, y1, x2, y2) self.extrude(x2, y2, y2, x2) self.extrude(y2, x2, y1, x1) self.extrude(y1, x1, x1, y1) self.extrude(x3, y3, x4, y4) self.extrude(x4, y4, y4, x4) self.extrude(y4, x4, y3, x3) NumSectors = 200 for i in range(NumSectors): angle1 = (i * 2 * math.pi) / NumSectors x5 = 0.30 * math.sin(angle1) y5 = 0.30 * math.cos(angle1) x6 = 0.20 * math.sin(angle1) y6 = 0.20 * math.cos(angle1) angle2 = ((i + 1) * 2 * math.pi) / NumSectors x7 = 0.20 * math.sin(angle2) y7 = 0.20 * math.cos(angle2) x8 = 0.30 * math.sin(angle2) y8 = 0.30 * math.cos(angle2) self.quad(x5, y5, x6, y6, x7, y7, x8, y8) self.extrude(x6, y6, x7, y7) self.extrude(x8, y8, x5, y5) self.gl.glEnd() self.gl.glEndList() return list def quad(self, x1, y1, x2, y2, x3, y3, x4, y4): self.gl.glNormal3d(0.0, 0.0, -1.0) self.gl.glVertex3d(x1, y1, -0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x3, y3, -0.05) self.gl.glVertex3d(x4, y4, -0.05) self.gl.glNormal3d(0.0, 0.0, 1.0) self.gl.glVertex3d(x4, y4, +0.05) self.gl.glVertex3d(x3, y3, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x1, y1, +0.05) def extrude(self, x1, y1, x2, y2): self.setColor(self.trolltechGreen.darker(250 + int(100 * x1))) self.gl.glNormal3d((x1 + x2)/2.0, (y1 + y2)/2.0, 0.0) self.gl.glVertex3d(x1, y1, +0.05) self.gl.glVertex3d(x2, y2, +0.05) self.gl.glVertex3d(x2, y2, -0.05) self.gl.glVertex3d(x1, y1, -0.05) def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def createBubbles(self, number): for i in range(number): position = QPointF(self.width()*(0.1 + 0.8*random.random()), self.height()*(0.1 + 0.8*random.random())) radius = min(self.width(), self.height())*(0.0125 + 0.0875*random.random()) velocity = QPointF(self.width()*0.0125*(-0.5 + random.random()), self.height()*0.0125*(-0.5 + random.random())) self.bubbles.append(Bubble(position, radius, velocity)) def animate(self): for bubble in self.bubbles: bubble.move(self.rect()) self.update() def setupViewport(self, width, height): side = min(width, height) self.gl.glViewport((width - side) // 2, (height - side) // 2, side, side) self.gl.glMatrixMode(self.gl.GL_PROJECTION) self.gl.glLoadIdentity() self.gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0) self.gl.glMatrixMode(self.gl.GL_MODELVIEW) def drawInstructions(self, painter): text = "Click and drag with the left mouse button to rotate the Qt " \ "logo." metrics = QFontMetrics(self.font()) border = max(4, metrics.leading()) rect = metrics.boundingRect(0, 0, self.width() - 2*border, int(self.height()*0.125), Qt.AlignCenter | Qt.TextWordWrap, text) painter.setRenderHint(QPainter.TextAntialiasing) painter.fillRect(QRect(0, 0, self.width(), rect.height() + 2*border), QColor(0, 0, 0, 127)) painter.setPen(Qt.white) painter.fillRect(QRect(0, 0, self.width(), rect.height() + 2*border), QColor(0, 0, 0, 127)) painter.drawText((self.width() - rect.width())/2, border, rect.width(), rect.height(), Qt.AlignCenter | Qt.TextWordWrap, text) def setClearColor(self, c): self.gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): self.gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF())
class GLWidget(QOpenGLWidget): xRotationChanged = pyqtSignal(int) yRotationChanged = pyqtSignal(int) zRotationChanged = pyqtSignal(int) def __init__(self, parent=None): super(GLWidget, self).__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.object = 0 self.xRot = 0 self.yRot = 0 self.zRot = 0 self.translateX = 0.0 self.translateY = 0.0 self.zoom = -15.0 self.ctlPressed = False self.matrix = Matrix(5, 5, 5) self.lastPos = QPoint() self.selectedX = 0 self.selectedY = 0 self.selectedZ = 4 self.trolltechGreen = QColor.fromCmykF(0.40, 0.0, 1.0, 0.0) self.trolltechPurple = QColor.fromCmykF(0.39, 0.39, 0.0, 0.0) self.Black = QColor.fromCmykF(0.0, 0.0, 0.0, 0.0, 0.0) self.selectedColor = self.trolltechGreen def getOpenglInfo(self): info = """ Vendor: {0} Renderer: {1} OpenGL Version: {2} Shader Version: {3} """.format(gl.glGetString(gl.GL_VENDOR), gl.glGetString(gl.GL_RENDERER), gl.glGetString(gl.GL_VERSION), gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION)) return info def minimumSizeHint(self): return QSize(50, 50) def sizeHint(self): return QSize(800, 600) def setXRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.xRot: self.xRot = angle self.xRotationChanged.emit(angle) self.update() def setYRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.yRot: self.yRot = angle self.yRotationChanged.emit(angle) self.update() def setZRotation(self, angle): angle = self.normalizeAngle(angle) if angle != self.zRot: self.zRot = angle self.zRotationChanged.emit(angle) self.update() def initializeGL(self): print(self.getOpenglInfo()) self.setClearColor(self.trolltechPurple.darker()) self.object = self.makeObject() gl.glShadeModel(gl.GL_FLAT) gl.glEnable(gl.GL_DEPTH_TEST) gl.glEnable(gl.GL_CULL_FACE) gl.glCullFace(gl.GL_FRONT) def paintGL(self): gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT) gl.glLoadIdentity() gl.glTranslatef(self.translateX, self.translateY, self.zoom) gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0) gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0) gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0) gl.glCallList(self.object) def resizeGL(self, width, height): side = min(width, height) if side < 0: return gl.glMatrixMode(gl.GL_PROJECTION) gl.glLoadIdentity() glu.gluPerspective(45, width / height, 1, 100.0) gl.glMatrixMode(gl.GL_MODELVIEW) def mousePressEvent(self, event): self.lastPos = event.pos() if event.buttons() & Qt.MiddleButton: self.resetView() self.updateGL() def mouseMoveEvent(self, event): dx = event.x() - self.lastPos.x() dy = event.y() - self.lastPos.y() if not self.ctlPressed: if event.buttons() & Qt.LeftButton: self.setXRotation(self.xRot + 8 * dy) self.setYRotation(self.yRot + 8 * dx) elif event.buttons() & Qt.RightButton: self.setXRotation(self.xRot + 8 * dy) self.setZRotation(self.zRot + 8 * dx) self.lastPos = event.pos() else: if event.buttons() & Qt.LeftButton: self.translateX += dx / 100 self.translateY += -dy / 100 self.update() self.lastPos = event.pos() def wheelEvent(self, event): numdegrees = event.angleDelta() / 8 numdegrees = numdegrees / 15 if -200 <= self.zoom + numdegrees.y() <= 0: self.zoom += numdegrees.y() self.update() def keyPressEvent(self, event): if event.key() == Qt.Key_Shift: self.ctlPressed = True elif event.key() == Qt.Key_Left and self.selectedX > 0: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedX -= 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key( ) == Qt.Key_Right and self.selectedX < self.matrix.width - 1: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedX += 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key() == Qt.Key_Minus and self.selectedY > 0: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedY -= 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key( ) == Qt.Key_Plus and self.selectedY < self.matrix.height - 1: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedY += 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key() == Qt.Key_Up and self.selectedZ > 0: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedZ -= 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key( ) == Qt.Key_Down and self.selectedZ < self.matrix.depth - 1: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.selectedZ += 1 self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].select() self.updateGL() elif event.key() == Qt.Key_F5: self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].color = self.selectedColor self.matrix.blocks[self.selectedX, self.selectedY, self.selectedZ].activate() self.updateGL() def keyReleaseEvent(self, event): if event.key() == Qt.Key_Shift: self.ctlPressed = False def makeObject(self): genList = gl.glGenLists(1) gl.glNewList(genList, gl.GL_COMPILE) self.matrix.paint() gl.glEndList() return genList def normalizeAngle(self, angle): while angle < 0: angle += 360 * 16 while angle > 360 * 16: angle -= 360 * 16 return angle def setClearColor(self, c): gl.glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setColor(self, c): gl.glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF()) def setMatrixSize(self, x, y, z): self.matrix = Matrix(x, y, z) self.updateGL() def resetView(self): self.xRot = 0 self.yRot = 0 self.zRot = 0 self.translateX = 0.0 self.translateY = 0.0 self.zoom = -15.0 self.updateGL() def updateGL(self): self.object = self.makeObject() self.paintGL() self.update() def setSelectedColor(self, color): self.selectedColor = color