def _coordinate_transform(self, input: QRectF, output: QRectF): rx, ry = output.width() / input.width(), output.height( ) / input.height() t = QTransform.fromTranslate(-input.left(), -input.top()) t *= QTransform.fromScale(rx, ry) t *= QTransform.fromTranslate(output.left(), output.top()) return t
def set_scale(self, sx, sy, px, py): m = QTransform.fromTranslate(-px, -py) m = QTransform.fromScale(sx, sy) * m m = QTransform.fromTranslate(px, py) * m m = self._tmove * m self._tmove = m
def ParseTransformAttrib(s): # where s is an SVG transform attribute such as "translate(-2,1) matrix(0 1 2 3 4 5)" # return a list of QTransforms xforms = [] s = s.lower() while s: s = re.sub(r'^\s+,?\s+', '', s) # remove leading WS,WS m = re.match(r'\s*(\w+)\s*\(((\s*[0-9e.+-]+\s*,?)+)\)', s) # match identifier(numbers) clause if m: values = SplitFloatValues(m.group(2)) if m.group(1) == 'translate': if len(values) == 1: values.append(0) xforms.append(QTransform.fromTranslate(*values)) elif m.group(1) == 'scale': if len(values) == 1: values.append(values[0]) xforms.append(QTransform.fromScale(*values)) elif m.group(1) == 'rotate': xforms.append(QTransform().rotate( values[0])) # TODO: handle cx,cy values elif m.group(1) == 'matrix': logger.trace('matrix({}): m.group(2) = {}', values, m.group(2)) xforms.append( QTransform(values[0], values[1], 0, values[2], values[3], 0, values[4], values[5], 1)) # TODO: handle skewX and skewY else: logger.warning('unrecognized transform: {}', m.group()) s = s[m.end() + 1:] else: if s: logger.warning('unparsed transform: {}', s) break return xforms
def ParseTransformAttrib(s): # where s is an SVG transform attribute such as "translate(-2,1) matrix(0 1 2 3 4 5)" # return a list of QTransforms xforms = [] s = s.lower() while s: s = re.sub(r'^\s+,?\s+', '', s) # remove leading WS,WS m = re.match(r'\s*(\w+)\s*\(((\s*[0-9e.+-]+\s*,?)+)\)', s) # match identifier(numbers) clause if m: values = SplitFloatValues(m.group(2)) if m.group(1) == 'translate': if len(values) == 1: values.append(0) xforms.append( QTransform.fromTranslate(*values) ) elif m.group(1) == 'scale': if len(values) == 1: values.append(values[0]) xforms.append( QTransform.fromScale(*values) ) elif m.group(1) == 'rotate': xforms.append( QTransform().rotate(values[0]) ) # TODO: handle cx,cy values elif m.group(1) == 'matrix': logger.trace('matrix({}): m.group(2) = {}', values, m.group(2)) xforms.append( QTransform( values[0], values[1], 0 , values[2], values[3], 0 , values[4], values[5], 1) ) # TODO: handle skewX and skewY else: logger.warning('unrecognized transform: {}', m.group()) s = s[m.end()+1:] else: if s: logger.warning('unparsed transform: {}', s) break return xforms
def _newAxes(self): """Given self._rotation and self._swapped, calculates and sets the appropriate data2scene transformation. """ # TODO: this function works, but it is not elegant. There must # be a simpler way to calculate the appropriate transformation. w, h = self.dataShape assert self._rotation in range(0, 4) # unlike self._rotation, the local variable 'rotation' # indicates how many times to rotate clockwise after swapping # axes. # t1 : do axis swap t1 = QTransform() if self._swapped: t1 = QTransform(0, 1, 0, 1, 0, 0, 0, 0, 1) h, w = w, h # t2 : do rotation t2 = QTransform() t2.rotate(self._rotation * 90) # t3: shift to re-center rot2trans = {0: (0, 0), 1: (h, 0), 2: (w, h), 3: (0, w)} trans = rot2trans[self._rotation] t3 = QTransform.fromTranslate(*trans) self.data2scene = t1 * t2 * t3 if self._tileProvider: self._tileProvider.axesSwapped = self._swapped self.axesChanged.emit(self._rotation, self._swapped)
def _prepare_drawing_cache(self, config: "ExtraDrawConfig"): """ 生成一个矩阵用以将painter的坐标系从UI坐标系调整为drawer坐标系 这样painter中的x和y轴就正好对应数据的x和y了 """ # 从UI坐标系到drawer坐标系的转化矩阵的构造顺序恰好相反,假设目前为drawer坐标系 # 将drawer坐标转化为UI坐标 drawer_area = QRectF( config.begin, config.y_low, max(config.end - config.begin, 1), max(config.y_high - config.y_low, 1), ) plot_area = self.plot_area() if plot_area.width() <= 0 or plot_area.height() <= 0: raise NoVisualAreaError() # 应用这个坐标转化 transform = self._coordinate_transform(drawer_area, plot_area) # 去除padding对上下翻转的影响 transform *= QTransform.fromTranslate(0, -plot_area.top()) # 在UI坐标系中上下翻转图像 transform *= QTransform.fromTranslate(0, -plot_area.height()) transform *= QTransform().rotate(180, Qt.XAxis) # 恢复padding transform *= QTransform.fromTranslate(0, plot_area.top()) # 保存一些中间变量 drawing_cache = DrawingCache() drawing_cache.drawer_transform = transform drawing_cache.ui_transform = transform.inverted()[0] drawing_cache.drawer_area = drawer_area # drawing_cache.drawer_area_width = drawer_area.width() # drawing_cache.drawer_area_height = drawer_area.height() drawing_cache.plot_area = plot_area # drawing_cache.plot_area_width = plot_area.width() # drawing_cache.plot_area_height = plot_area.height() drawing_cache.p2d_w = drawer_area.width() / plot_area.width() drawing_cache.p2d_h = drawer_area.height() / plot_area.height() config.drawing_cache = drawing_cache
def _fetch_tile_layer(self, timestamp, ims, transform, tile_nr, stack_id, ims_req, cache): """ Fetch a single tile from a layer (ImageSource). Parameters ---------- timestamp The timestamp at which ims_req was created ims The layer (image source) we're fetching from transform The transform to apply to the fetched data, before storing it in the cache tile_nr The ID of the fetched tile stack_id The stack ID of the tile we're fetching (e.g. which T-slice and Z-slice this tile belongs to) ims_req A request object (e.g. GrayscaleImageRequest) with a wait() method that produces an item of the appropriate type for the layer (i.e. either a QImage or a QGraphicsItem) cache The value of self._cache at the time the ims_req was created. (The cache can be replaced occasionally. See TileProvider._onSizeChanged().) """ try: try: with cache: layerTimestamp = cache.layerTimestamp(stack_id, ims, tile_nr) except KeyError: # May not be a timestamp yet (especially when prefetching) layerTimestamp = 0 tile_rect = QRectF(self.tiling.imageRects[tile_nr]) if timestamp > layerTimestamp: img = ims_req.wait() if isinstance(img, QImage): img = img.transformed(transform) elif isinstance(img, QGraphicsItem): # FIXME: It *seems* like applying the same transform to QImages and QGraphicsItems # makes sense here, but for some strange reason it isn't right. # For QGraphicsItems, it seems obvious that this is the correct transform. # I do not understand the formula that produces 'transform', which is used for QImage tiles. img.setTransform(QTransform.fromTranslate(tile_rect.left(), tile_rect.top()), combine=True) img.setTransform(self.tiling.data2scene, combine=True) else: assert False, "Unexpected image type: {}".format(type(img)) with cache: try: cache.updateTileIfNecessary(stack_id, ims, tile_nr, timestamp, img) except KeyError: pass if stack_id == self._current_stack_id and cache is self._cache: self.sceneRectChanged.emit(tile_rect) except BaseException: logger.debug("Failed to fetch layer tile", exc_info=True)
def _fetch_tile_layer(self, timestamp, ims, transform, tile_nr, stack_id, ims_req, cache): """ Fetch a single tile from a layer (ImageSource). Parameters ---------- timestamp The timestamp at which ims_req was created ims The layer (image source) we're fetching from transform The transform to apply to the fetched data, before storing it in the cache tile_nr The ID of the fetched tile stack_id The stack ID of the tile we're fetching (e.g. which T-slice and Z-slice this tile belongs to) ims_req A request object (e.g. GrayscaleImageRequest) with a wait() method that produces an item of the appropriate type for the layer (i.e. either a QImage or a QGraphicsItem) cache The value of self._cache at the time the ims_req was created. (The cache can be replaced occasionally. See TileProvider._onSizeChanged().) """ try: try: with cache: layerTimestamp = cache.layerTimestamp(stack_id, ims, tile_nr) except KeyError: # May not be a timestamp yet (especially when prefetching) layerTimestamp = 0 tile_rect = QRectF(self.tiling.imageRects[tile_nr]) if timestamp > layerTimestamp: img = ims_req.wait() if isinstance(img, QImage): img = img.transformed(transform) elif isinstance(img, QGraphicsItem): # FIXME: It *seems* like applying the same transform to QImages and QGraphicsItems # makes sense here, but for some strange reason it isn't right. # For QGraphicsItems, it seems obvious that this is the correct transform. # I do not understand the formula that produces 'transform', which is used for QImage tiles. img.setTransform(QTransform.fromTranslate(tile_rect.left(), tile_rect.top()), combine=True) img.setTransform(self.tiling.data2scene, combine=True) else: assert False, "Unexpected image type: {}".format(type(img)) with cache: try: cache.updateTileIfNecessary(stack_id, ims, tile_nr, timestamp, img) except KeyError: pass if stack_id == self._current_stack_id and cache is self._cache: self.sceneRectChanged.emit(tile_rect) except BaseException: sys.excepthook(*sys.exc_info())
def timerEvent(self, event): axelDistance = 54.0 wheelsAngleRads = (self.wheelsAngle * math.pi) / 180 turnDistance = math.cos(wheelsAngleRads) * axelDistance * 2 turnRateRads = wheelsAngleRads / turnDistance turnRate = (turnRateRads * 180) / math.pi rotation = self.speed * turnRate self.setTransform(QTransform().rotate(rotation), True) self.setTransform(QTransform.fromTranslate(0, -self.speed), True) self.update()
def objectTransform(object, renderer): transform = QTransform() if (object.rotation() != 0): pos = renderer.pixelToScreenCoords_(object.position()) transform = rotateAt(pos, object.rotation()) offset = object.objectGroup().offset() if not offset.isNull(): transform *= QTransform.fromTranslate(offset.x(), offset.y()) return transform
def __init__(self, scene, width, height): self.width = width self.height = height self.cells = [[Cell() for j in range(self.width)] for i in range(self.height)] for i in range(self.height): for j in range(self.width): self.cells[i][j].setTransform( QTransform.fromTranslate(8 * j, 8 * i)) scene.addItem(self.cells[i][j])
def __init__(self, scene, length, color=0xFFFFFEFF, value=0): self.length = length self.color = color self.digits = [] for i in range(length): digit = Digit(value % 10, self.color) digit.setTransform( QTransform.fromTranslate((length - i - 1) * 8, 0)) scene.addItem(digit) self.digits.insert(0, digit) value //= 10
def update_transform(self): if self.transformChanged: translation = QTransform() translation = translation.fromTranslate(self.worldPosition[0], self.worldPosition[1]) scale = QTransform() scale = scale.fromScale(self.worldScale[0], self.worldScale[1]) rot = QTransform() rot = rot.rotate(self.worldRotation) self.worldTransform = scale * rot * translation self.transformChanged = False self.update_aabb() return
def initScene(self): self.setSceneRect(0, 0, 256, 240) bgImage = QPixmap(resource_path('./assets/boardLayout.png')) self.image = self.addPixmap(bgImage) self.board = Board(self, 10, 20) self.board.translate(12 * 8, 6 * 8) self.top = Number(self, 6) self.top.translate(24 * 8, 5 * 8) self.score = Number(self, 6) self.score.translate(24 * 8, 8 * 8) self.lines = Number(self, 3) self.lines.translate(19 * 8, 3 * 8) self.level = Number(self, 2, value=18) self.level.translate(26 * 8, 21 * 8) self.stats = [] for i in range(7): statNum = Number(self, 3, 0xFFB53120) statNum.translate(6 * 8, (12 + 2 * i) * 8) self.stats.append(statNum) self.statsPieces = PaletteItem( QPixmap(resource_path(f'./assets/pieceStats.png'))) self.statsPieces.setTransform(QTransform.fromTranslate(24, 88)) self.addItem(self.statsPieces) self.previewCoords = [(204, 119), (204, 119), (204, 119), (208, 119), (204, 119), (204, 119), (208, 123)] self.previewType = 0 self.preview = Piece(self.previewType, 0, 255) self.addItem(self.preview) self.preview.updateOffset(*self.previewCoords[self.previewType]) self.cursor = CursorItem(1) self.addItem(self.cursor) self.cursor.setVisible(False) self.cellState = 1 self.transparentDraw = False self.drawMode = False self.lastMousePos = None self.actionBuffer = ActionBuffer() self.actionGroup = []
def setZoom(self, zoom): self._zoom = zoom if zoom >= 1.0: self._zoom = 1.0 elif zoom <= 0.1: self._zoom = 0.1 transform = self.transform() new_transform = QTransform.fromTranslate(transform.dx(), transform.dy()) new_transform.scale(self._zoom, self._zoom) self.setTransform(new_transform) self.scene().setZoom(self._zoom)
def compute_SMBR(geom): area = float("inf") angle = 0 width = float("inf") height = float("inf") if (geom is None): return QgsGeometry() hull = geom.convexHull() if (hull.isEmpty()): return QgsGeometry() x = hull.asPolygon() vertexId = 0 pt0 = x[0][vertexId] pt1 = pt0 prevAngle = 0.0 size = len(x[0]) for vertexId in range(0, size - 0): pt2 = x[0][vertexId] currentAngle = lineAngle(pt1.x(), pt1.y(), pt2.x(), pt2.y()) rotateAngle = 180.0 / math.pi * (currentAngle - prevAngle) prevAngle = currentAngle t = QTransform.fromTranslate(pt0.x(), pt0.y()) t.rotate(rotateAngle) t.translate(-pt0.x(), -pt0.y()) hull.transform(t) bounds = hull.boundingBox() currentArea = bounds.width() * bounds.height() if (currentArea < area): minRect = bounds area = currentArea angle = 180.0 / math.pi * currentAngle width = bounds.width() height = bounds.height() pt2 = pt1 minBounds = QgsGeometry.fromRect(minRect) minBounds.rotate(angle, QgsPointXY(pt0.x(), pt0.y())) if (angle > 180.0): angle = math.fmod(angle, 180.0) return minBounds, area, angle, width, height
def paintEvent(self, _): """ 重写绘制事件,参考 qfusionstyle.cpp 中的 CE_ProgressBarContents 绘制方法 """ option = QStyleOptionProgressBar() self.initStyleOption(option) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.translate(0.5, 0.5) vertical = option.orientation == Qt.Vertical # 是否垂直 inverted = option.invertedAppearance # 是否反转 # 是否显示动画 indeterminate = (option.minimum == option.maximum) or ( option.minimum < option.progress < option.maximum) rect = option.rect if vertical: rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()) # 翻转宽度和高度 m = QTransform.fromTranslate(rect.height(), 0) m.rotate(90.0) painter.setTransform(m, True) maxWidth = rect.width() progress = max(option.progress, option.minimum) totalSteps = max(1, option.maximum - option.minimum) progressSteps = progress - option.minimum progressBarWidth = int(progressSteps * maxWidth / totalSteps) width = progressBarWidth # 已进行的进度宽度 radius = max(1, (min(width, self.width() if vertical else self.height()) // 4) if self._radius is None else self._radius) reverse = (not vertical and option.direction == Qt.RightToLeft) or vertical if inverted: reverse = not reverse # 绘制范围 path = QPainterPath() if not reverse: progressBar = QRectF(rect.left(), rect.top(), width, rect.height()) else: progressBar = QRectF(rect.right() - width, rect.top(), width, rect.height()) # 切割范围 path.addRoundedRect(progressBar, radius, radius) painter.setClipPath(path) # 绘制背景颜色 painter.setPen(Qt.NoPen) painter.setBrush(self._color) painter.drawRoundedRect(progressBar, radius, radius) if not indeterminate: if self._animation: self._animation.stop() self._animation = None else: # 叠加颜色覆盖后出现类似线条间隔的效果 color = self._color.lighter(320) color.setAlpha(80) painter.setPen(QPen(color, self._lineWidth)) if self._animation: step = int(self._animation.animationStep() % self._lineWidth) else: step = 0 self._animation = QProgressStyleAnimation(self._fps, self) self._animation.start() # 动画斜线绘制 startX = int(progressBar.left() - rect.height() - self._lineWidth) endX = int(rect.right() + self._lineWidth) if (not inverted and not vertical) or (inverted and vertical): lines = [ QLineF(x + step, progressBar.bottom(), x + rect.height() + step, progressBar.top()) for x in range(startX, endX, self._lineWidth) ] else: lines = [ QLineF(x - step, progressBar.bottom(), x + rect.height() - step, progressBar.top()) for x in range(startX, endX, self._lineWidth) ] painter.drawLines(lines)
def _translate(rectsrc, rectdest, offset: QPoint) -> QTransform: srcfct = rectsrc.width() / rectsrc.height() destfct = rectdest.width() / rectdest.height() shiftx = rectdest.width() * max((1 - srcfct / destfct) / 2, 0) shifty = rectdest.height() * max((1 - destfct / srcfct) / 2, 0) return QTransform.fromTranslate(offset.x() + shiftx, offset.y() + shifty)
def reset_tmove(self): self._tmove = QTransform.fromTranslate(0, 0)
def update_translate(self, dx, dy): self._tmove = QTransform.fromTranslate(dx, dy)
def modelMatrix(self, center, width): return QTransform.fromScale(width / 239, width / 239) * QTransform.fromTranslate( -center.x(), -center.y())